Compiling Rust to WebAssembly for non-Web embedding

Created Last updated

After learning about Common WebAssembly, I wanted to experiment with Life, a server-side WebAssembly VM built in Go.

I quite like the idea of WebAssembly in non-Web environments, as an universal scripting interface.

For now, I am using Lua for this use-case. But the idea of being able to use any language to interact with Blobstash sounds appealing to me.

I struggled to find information about compiling to WebAssembly without all the web stuff enabled, that's why I am sharing my notes.

Setup

This requires Rust nightly:

$ rustup toolchain install nightly
$ rustup default nightly

And the WebAssembly target:

$ rustup target add wasm32-unknown-unknown

New project

Create a new library (not a binary package):

$ cargo new cwatest --lib

I will re-use the example script from Life.

  • The extern block is for external imports, in this context, these are defined in Go
  • #[no_mangle] will ensure our "exported" function will stay called app_main

In src/lib.rs:

extern "C" {
    fn __life_log(msg: *const u8, len: usize);
}

#[no_mangle]
pub extern "C" fn app_main() -> i32 {
    let message = "This is being called outside of WebAssembly!".as_bytes();

    unsafe {
        __life_log(message.as_ptr(), message.len());
    }

    return 0;
}

Compiling to WebAssembly

In Cargo.toml, the crate type needs to be changed to cdylib (this will setup C interopability):

[lib]
crate-type =["cdylib"]

Then, the library needs to be cross-compiled as WebAssembly:

$ cargo build --target wasm32-unknown-unknown --release
# You can find the wasm file at target/wasm32-unknown-unknown/release/cwatest.wasm 

That's it, the resulting wasm file is ready for consumption with server-side runtimes like life or wasmer.