Skip to content

Latest commit

 

History

History
194 lines (145 loc) · 5.22 KB

01 - Hello DevWorld.md

File metadata and controls

194 lines (145 loc) · 5.22 KB

01 - Hello DevWorld

Overview

  • Create a static library in Rust
  • Define a function that prints to screen
  • Test it from Rust

Instructions

Create a new library project and give it a name. In these notes we will use the meaningless name anvil, so the resulting static library will called libanvil.a.

$ cd ~/code
$ cargo new --lib anvil
     Created library `anvil` package
$

Open Cargo.toml and add a [lib] section to select the output formats:

[package]
name = "anvil"
version = "0.1.0"
authors = ["Thomas Karpiniec <tom.karpiniec@outlook.com>"]
edition = "2018"

[lib]
crate-type = ["lib", "staticlib"]

[dependencies]

Open src/lib.rs and delete the generated test. Add a function like this one:

#[no_mangle]
pub extern "C" fn hello_devworld() {
    println!("Hello, /dev/world 2019!");
}

Inside the anvil project directory, make sure it compiles:

$ cargo build
   Compiling anvil v0.1.0 (/Users/tk/code/anvil)
    Finished dev [unoptimized + debuginfo] target(s) in 0.36s

Check that you can see both the rust library and the static library in the target subdirectory:

$ ls -l target/debug/lib*
-rw-r--r--  2 tk  staff  4416376 24 Aug 11:05 target/debug/libanvil.a
-rw-r--r--  1 tk  staff       78 24 Aug 11:05 target/debug/libanvil.d
-rw-r--r--  2 tk  staff    18520 24 Aug 11:05 target/debug/libanvil.rlib

Check that your function is being exported from the static library. This means it can be used from C (and Swift)!

$ nm target/debug/libanvil.a | grep hello
0000000000000000 T _hello_devworld

Next, let's provide a way to test the library function by calling it from a normal Rust application. Inside the anvil directory, manually create a new directory and a file inside it: examples/testanvil.rs.

$ mkdir examples
$ cd examples
$ touch testanvil.rs

Your project folder should now be laid out like this:

├── Cargo.lock
├── Cargo.toml
├── examples
│   └── testanvil.rs
├── src
│   └── lib.rs
...

Open testanvil.rs and enter the following Rust program:

use anvil::*;

fn main() {
    hello_devworld();
}

You can now use this test program to call into your anvil library.

$ cargo run --example testanvil
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/examples/testanvil`
Hello, /dev/world 2019!

Exercises

1. An experiment with crates

Searching on https://crates.io for something interesting we might spot the crate ferris-says.

Let's make our function more exciting. Open Cargo.toml and add a reference to this crate underneath [dependencies].

[dependencies]
ferris-says = "0.1"

Change src/lib.rs to use this new crate:

use std::io::{stdout, BufWriter};

#[no_mangle]
pub extern "C" fn hello_devworld() {
    let phrase = b"Hello, /dev/world/2019!";
    let stdout = stdout();
    let mut writer = BufWriter::new(stdout.lock());
    ferris_says::say(phrase, 30, &mut writer).unwrap();
}

Now we get a more interesting printout.

$ cargo run --example testanvil
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/examples/testanvil`
    ----------------------------------
    | Hello, /dev/world/2019!        |
    ----------------------------------
                \
                 \
                     _~^~^~_
                 \) /  o o  \ (/
                   '_   -   _'
                   / '-----' \

2. Test the library from C

If you don't feel like going all the way to Swift yet, you can try out the library from an ordinary C program.

We need to make sure we link in all the required system libraries to support our library and its use of the Rust standard library. Run this command to see what flags you will need - note that this may vary from system to system.

$ cargo rustc -- --print native-static-libs
   Compiling anvil v0.1.0 (/Users/tk/code/anvil)
note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.

note: native-static-libs: -lSystem -lresolv -lc -lm

    Finished dev [unoptimized + debuginfo] target(s) in 0.71s

Create a new folder out of the way, and copy over your compiled static library.

$ mkdir ~/code/hello_c
$ cd ~/code/hello_c
$ cp ~/code/anvil/target/debug/libanvil.a .
$ touch hello.c

Edit hello.c and fill in a program that calls the library function. We don't have an anvil.h header yet (that comes later!) so we'll need to declare the function prototype ourselves.

extern void hello_devworld();

int main(int argc, char *argv[]) {
	hello_devworld();
    return 0;
}

Compile and run it:

$ cc hello.c libanvil.a -lSystem -lresolv -lc -lm -o hello
$ ./hello
    ----------------------------------
    | Hello, /dev/world/2019!        |
    ----------------------------------
                \
                 \
                     _~^~^~_
                 \) /  o o  \ (/
                   '_   -   _'
                   / '-----' \