wasm32-unknown-emscripten

Tier: 2

The wasm32-unknown-emscripten target is a WebAssembly compilation target which uses the Emscripten compiler toolchain. Emscripten is a C/C++ toolchain designed to make it as easy as possible to port C/C++ code written for Linux to run on the web or in other JavaScript runtimes such as Node. It thus provides POSIX-compatible (musl) libc and libstd implementations and many Linux APIs, access to the OpenGL and SDL APIs, and the ability to run arbitrary JavaScript code, all based on web APIs using JS glue code. With the wasm32-unknown-emscripten target, Rust code can interoperate with Emscripten's ecosystem, C/C++ and JS code, and web APIs.

One existing user of this target is the pyodide project which provides a Python runtime in WebAssembly using Emscripten and compiles Python extension modules written in Rust to the wasm32-unknown-emscripten target.

If you want to generate a standalone WebAssembly binary that does not require access to the web APIs or the Rust standard library, the wasm32-unknown-unknown target may be better suited for you. However, wasm32-unknown-unknown does not (easily) support interop with C/C++ code. Please refer to the wasm-bindgen crate in case you want to interoperate with JavaScript with this target.

Like Emscripten, the WASI targets wasm32-wasip1 and wasm32-wasip2 also provide access to the host environment, support interop with C/C++ (and other languages), and support most of the Rust standard library. While the WASI targets are portable across different hosts (web and non-web), WASI has no standard way of accessing web APIs, whereas Emscripten has the ability to run arbitrary JS from WASM and access many web APIs. If you are only targeting the web and need to access web APIs, the wasm32-unknown-emscripten target may be preferable.

Target maintainers

  • Hood Chatham, https://github.com/hoodmane
  • Juniper Tyree, https://github.com/juntyr

Requirements

This target is cross-compiled. The Emscripten compiler toolchain emcc must be installed to link WASM binaries for this target. You can install emcc using:

git clone https://github.com/emscripten-core/emsdk.git --depth 1
./emsdk/emsdk install 3.1.68
./emsdk/emsdk activate 3.1.68
source ./emsdk/emsdk_env.sh

Please refer to https://emscripten.org/docs/getting_started/downloads.html for further details and instructions.

Building the target

Building this target can be done by:

  • Configure the wasm32-unknown-emscripten target to get built.
  • Ensure the WebAssembly target backend is not disabled in LLVM.

These are all controlled through config.toml options. It should be possible to build this target on any platform. A minimal example configuration would be:

[llvm]
targets = "WebAssembly"

[build]
build-stage = 1
target = ["wasm32-unknown-emscripten"]

Building Rust programs

Rust programs can be compiled by adding this target via rustup:

$ rustup target add wasm32-unknown-emscripten

and then compiling with the target:

$ rustc foo.rs --target wasm32-unknown-emscripten
$ file foo.wasm

Cross-compilation

This target can be cross-compiled from any host.

Emscripten ABI Compatibility

The Emscripten compiler toolchain does not follow a semantic versioning scheme that clearly indicates when breaking changes to the ABI can be made. Additionally, Emscripten offers many different ABIs even for a single version of Emscripten depending on the linker flags used, e.g. -fexceptions and -sWASM_BIGINT. If the ABIs mismatch, your code may exhibit undefined behaviour.

To ensure that the ABIs of your Rust code, of the Rust standard library, and of other code compiled for Emscripten all match, you should rebuild the Rust standard library with your local Emscripten version and settings using:

cargo +nightly -Zbuild-std build

If you still want to use the pre-compiled std from rustup, you should ensure that your local Emscripten matches the version used by Rust and be careful about any -C link-args that you compiled your Rust code with.

Testing

This target is not extensively tested in CI for the rust-lang/rust repository. It can be tested locally, for example, with:

./x.py test --target wasm32-unknown-emscripten --skip src/tools/linkchecker

To run these tests, both emcc and node need to be in your $PATH. You can install node, for example, using nvm by following the instructions at https://github.com/nvm-sh/nvm#install--update-script.

If you need to test WebAssembly compatibility in general, it is recommended to test the wasm32-wasip1 target instead.

Conditionally compiling code

It's recommended to conditionally compile code for this target with:

#[cfg(target_os = "emscripten")]

It may sometimes be necessary to conditionally compile code for WASM targets which do not use emscripten, which can be achieved with:

#[cfg(all(target_family = "wasm", not(target_os = "emscripten)))]

Enabled WebAssembly features

WebAssembly is an evolving standard which adds new features such as new instructions over time. This target's default set of supported WebAssembly features will additionally change over time. The wasm32-unknown-emscripten target inherits the default settings of LLVM which typically, but not necessarily, matches the default settings of Emscripten as well. At link time, emcc configures the linker to use Emscripten's settings.

Please refer to the wasm32-unknown-unknown target's documentation on which WebAssembly features Rust enables by default, how features can be disabled, and how Rust code can be conditionally compiled based on which features are enabled.

Note that Rust code compiled for wasm32-unknown-emscripten currently enables -fexceptions (JS exceptions) by default unless the Rust code is compiled with -Cpanic=abort. -fwasm-exceptions (WASM exceptions) is not yet currently supported, see https://github.com/rust-lang/rust/issues/112195.

Please refer to the Emscripten ABI compatibility section to ensure that the features that are enabled do not cause an ABI mismatch between your Rust code, the pre-compiled Rust standard library, and other code compiled for Emscripten.