zwasm-sdk provides safe, idiomatic Rust bindings to the zwasm WebAssembly runtime.
A recent stable Rust compiler is recommended. (Rust 2021 edition)
- Requires Zig 0.16.0 in your PATH (used to build the zwasm C library)
- Supported platforms: Linux (x86_64, aarch64), macOS (x86_64, aarch64)
The zwasm C library is built from the vendored submodule and linked statically, so no shared library has to be installed on the machine that runs your binary.
Building it needs no network: zwasm's root package declares no dependencies, so
zig build static-lib fetches nothing even on a cold Zig cache.
Cross-compiling works through cargo-zigbuild:
cargo zigbuild --target <triple> builds the C library for that target rather
than for the build host. CI covers aarch64-unknown-linux-musl and
x86_64-unknown-linux-musl.
A glibc version on the target — --target x86_64-unknown-linux-gnu.2.28 — is
honoured with cargo-zigbuild 0.23.4 or later, which exports the resolved target
for build scripts to read. On older versions the C library is built for
whatever glibc Zig defaults to, while the link step targets the version asked
for.
ZWASM_ZIG_TARGET overrides the target handed to Zig outright, for anything
-Dtarget accepts — a glibc floor, CPU features, an ABI variant. It takes
precedence over everything above, and is the way to reach a floor below Zig's
default without cargo-zigbuild.
| zwasm-sdk | zwasm-sys | zwasm C API |
|---|---|---|
| 0.3.x | 0.3.x | 2.7.x |
| 0.2.x | 0.2.x | 2.6.x |
| 0.1.x | 0.1.x | 1.11.x |
zwasm 2.0 replaced the custom C API with the standard wasm-c-api, so 0.2 is a full rewrite with no path from 0.1. See CHANGELOG.md.
Add this to your Cargo.toml:
[dependencies]
zwasm-sdk = "0.3"use zwasm_sdk::{Engine, Instance, Module, Store, Val};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let wasm = std::fs::read("your_module.wasm")?;
let engine = Engine::new()?;
let mut store = Store::new(&engine)?;
let module = Module::new(&mut store, &wasm)?;
let instance = Instance::new(&mut store, &module, &[])?;
let add = instance
.get_func(&mut store, "add")
.ok_or("no export named add")?;
let mut results = [Val::I32(0)];
add.call(&mut store, &[Val::I32(10), Val::I32(32)], &mut results)?;
println!("results = {results:?}");
Ok(())
}Engine, Store, Module, Instance and Func mirror the wasm-c-api object model. Each one frees its C counterpart on drop.
Build a WasiConfig and install it on the store before instantiating. The store takes ownership of the config, so it is passed by value.
use zwasm_sdk::{Engine, Store, WasiConfig};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = Engine::new()?;
let mut store = Store::new(&engine)?;
let mut wasi = WasiConfig::new()?;
wasi.set_args(&["prog", "--flag"])?;
wasi.set_envs(&[("KEY", "VALUE")])?;
wasi.preopen_dir("/host/dir", "/")?;
wasi.inherit_stdio();
store.set_wasi(wasi);
Ok(())
}Imports of wasi_snapshot_preview1.* then resolve against that host. WASI 0.1 is supported; the Component Model and WASI 0.2 surfaces of zwasm are not wrapped yet.
All FFI unsafety is encapsulated. A host function is a Rust closure through Func::new, which takes its signature as ValType lists; the closure sees its arguments and not the caller's memory, because zwasm's callback carries no instance to resolve an export against. Func::new_host remains for an embedder that already has an extern "C" callback, and is the one unsafe entry point left.
Engine is neither Send nor Sync, and neither is Store or anything derived from it. zwasm's engine is single-threaded per process rather than per store: its stores share process-global state, so keeping a store on one thread is necessary rather than sufficient.
Five engine events can be observed — compiles, instantiations, traps, fuel exhaustion and memory growth — through Engine::set_compile_hook and its four siblings. A hook fires in the middle of the operation it reports, so it must not call back into the engine, and it reports an event rather than a duration: zwasm's core carries no clock.
For low-level access, see zwasm-sys.
MIT License. See LICENSE for details.
Contributions, bug reports, and feature requests are welcome! See CONTRIBUTING.md for details.