Hello, WASM!
Getting Setup
Install the Nightly Compiler
$ rustup install nightly
This will allow us to use some experimental rust features.
Install the wasm32-unknown-unknown
Target
$ rustup target add wasm32-unknown-unknown --toolchain nightly
This will allow us to actually compile to Web Assembly, specifically for the nightly compiler we just installed
Install Wasm-Bindgen’s CLI tool
$ cargo install wasm-bindgen-cli
This will install a cli application wasm-bindgen
, this is going to read our .wasm
file and generate a javascript file for us.
Now that our environment can handle building a wasm project, let's get something working. We are going to use the same lib.rs
file that we were using before but we need to update a few things about our project.
first we can delete the main.rs file, you don't have to but it might trip you up.
Once we have done that we need to update our Cargo.toml
file with some new information. It is going to look like this.
Cargo.toml
[package]
name = "hello_world"
version = "0.1.0"
authors = ["robert masen <r@robertmasen.pizza>"]
[dependencies]
wasm-bindgen = "0.2"
[lib]
crate-type = ["cdylib"]
First we added a dependency wasm-bindgen = "0.2"
, this will make a bunch of glue code available to us.
The other thing we changed was adding a [lib]
section and including the line crate-type = ["cdylib"]
, this will tell cargo that we want to create a "C Dynamic Library" this will make sure our library is consumable from languages other than Rust. Now that we have our configuration right, lets dig back into the code. We really just need to make a few small changes to our existing lib.rs
file.
lib.rs
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn generate_greeting() -> String {
"Hello, world!".to_string()
}
#[wasm_bindgen]
pub fn generate_custom_greeting(name: &str) -> String {
format!("Hello, {}!", name);
}
First we added a new line to the top of the file (#![feature(...)]
), this is turning on a few custom features that are not normally enabled in rust.
-
proc_macro
: This enables procedural macros, a special kind of rust code we will be using -
wasm_custom_section
: This tells the compiler to add a non-standard section to our.wasm
file -
wasm_import_module
: This instructs the compiler to include functionality from another wasm module
After that, we define our need for the external library extern crate wasm_bindgen;
and then import everything in that library's prelude module with use wasm-bindgen::prelude::*;
. This makes everything we need from that library available to us.
We also need to annotate the functions with the #[wasm_bindgen]
procedural macro. If you are familiar with attributes in C# or decorators in TypeScript and Python, it is the same concept, if you are not this will just add a bunch of that glue code I was referring to earlier.
With those changes, we can now build our wasm module. We are going to use the new stuff we added with our rustup
and cargo
commands earlier.
$ cargo +nightly build --target wasm32-unknown-unknown
Notice that we put +nightly
in there, this is shorthand for telling cargo
to use the nightly compiler instead of the stable one
The first time you run this it will might take a little while.
Once that is complete you would have a .wasm
file in the ./target/wasm32-unknown-unknown/debug/
folder.
The next step is to generate our bindings. We can use that wasm-bindgen
command line tool we installed like so.
$ wasm-bindgen ./target/wasm32-unknown-unknown/debug/hello_world.wasm --out-dir .
hello_world_bg.wasm
and hello_world.js
.
lets take a look at the .js
file.