Wasm32-unknown-unknown vs wasm32-wasi

What is the relation between wasm32-unknown-unknown and wasm32-wasi ? [ rustc_target::spec::wasm32_wasi - Rust ]

Context: I am trying to build rusqlite to wasm. On target wasm32-unknown-unknown, I am getting error: rust-lld: error: unknown file type: sqlite3.o

Googling around, Can't build for wasm target · Issue #827 · rusqlite/rusqlite · GitHub seems to reply there is a difference between wasm32-unknown-unknown and wasm32-wasi.

1 Like

Sure there is! WASI is an extended WASM environment specification, which tries to emulate a full OS, including system calls and functionality related to file system, networking, and so forth. In contrast, wasm32-unknown-unknown is a bare metal-like target (hence the unknowns in the target triple — those would specify the OS), which doesn't provide much functionality outside of pure computation.

Ignoring the fact rusqlite fails to buildon wasm32-unknown-unknown and claims to build on wasm32-wasi:

In practice, if I am writing a Rust/wasm32 app and having it run on Chrome browser, what are the practical tradeoffs of wasm32-unknown-unknown vs wasm32-wasi ? [Until today, I did not even realize wasm32-wasi was a real target -- I thought it was some yet to be implemented spec].

The only difference is that wasm32-wasi target won't work there due to the lack of the necessary system API, AFAIK.

1 Like

Browsers of today typically don't support WASI, so requiring WASI APIs will mean that your code won't run in a browser. If you are targeting the web, your best bet is to stick to wasm32-unknown.

Edit: after a bit of googling, it became apparent to me that there are multiple WASI polyfill projects that try to make browsers support WASI interfaces. I'm not sure how mature/reliable they are, though.

1 Like

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).

6 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.