You mark your function as #[no_mangle]
(don't apply symbol mangling so I can refer to it using the same name) and extern "C"
(defines the calling convention).
Here's a Cargo.toml
:
# Cargo.toml
[package]
name = "temp"
version = "0.1.0"
authors = ["Michael-F-Bryan <michaelfbryan@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[lib]
crate-type = ["cdylib", "staticlib"]
And my code:
// src/lib.rs
#[no_mangle]
pub extern "C" fn add(left: i32, right: i32) -> i32 {
left + right
}
I then compile it using cargo
.
$ cargo build --target wasm32-unknown-unknown --release
Compiling temp v0.1.0 (/tmp/temp)
Finished dev [optimized] target(s) in 0.16s
$ ls target/wasm32-unknown-unknown/release/
build deps examples incremental libtemp.a libtemp.d temp.d temp.wasm
We can convert the temp.wasm
to a human-readable form using the tools from WABT.
$ wasm2wat target/wasm32-unknown-unknown/release/temp.wasm
(module
(type (;0;) (func (param i32 i32) (result i32)))
(func $add (type 0) (param i32 i32) (result i32)
local.get 1
local.get 0
i32.add)
(table (;0;) 1 1 funcref)
(memory (;0;) 16)
(global (;0;) (mut i32) (i32.const 1048576))
(global (;1;) i32 (i32.const 1048576))
(global (;2;) i32 (i32.const 1048576))
(export "memory" (memory 0))
(export "add" (func $add))
(export "__data_end" (global 1))
(export "__heap_base" (global 2)))
And you can see there's a func
called $add
which takes two i32
s and returns an i32
, and the (export "add" (func $add))
expression says the $add
function is publicly accessible.
The wasm-bindgen tool automates a lot of the extern "C"
code and sets things up so you can pass more complex types to/from WebAssembly because a function can only use integers and floats as parameters or return values.