Wasm32-unknown-unknown vs wasm32-wasi

The best way to think of wasm32-unknown-unknown vs wasm32-wasi is by analogy with no_std.

When you compile a Rust program to wasm32-unknown-unknown it has no way to access things your OS/kernel would normally provide (the target OS is literally unknown). That means trying to access things like environment variables, std::process::Command, and the file system will always fail (or return empty values).

On the other hand, when you compile to wasm32-wasi the compiler will get access to all the functions defined by WASI. These are things like read() and so on. The Rust standard library then wraps those functions to provide the same interface we already know (i.e. std::fs::File and friends).

When you try to load a wasm32-wasi binary in the browser, you will need to provide your own implementation for these functions otherwise you'll probably run into "missing import" errors. Normally you'll use a library like @wasmer/wasi that implements these functions for you. They may be implemented by stubbing the functions out and erroring unconditionally, or using some sort of "virtual filesystem" (e.g. an object mapping paths to the bytes making up a file).

I normally try to avoid WASI if I can because it expands the interface between guest and host. A lot of the C programs you compile to WebAssembly will require it though, because they tend to use libc functions a lot more (e.g. when reading data, a Rust library might use some R: Read, whereas a C library might want a File* or call fopen() internally).

9 Likes