wasm32-wasi-preview1-threads
Tier: 2
The wasm32-wasi-preview1-threads
target is a new and still (as of July 2023) an
experimental target. This target is an extension to wasm32-wasi-preview1
target,
originally known as wasm32-wasi
. It extends the original target with a
standardized set of syscalls that are intended to empower WebAssembly binaries with
native multi threading capabilities.
Target maintainers
- Georgii Rylov, https://github.com/g0djan
- Alex Crichton, https://github.com/alexcrichton
- Andrew Brown, https://github.com/abrown
- Marcin Kolny, https://github.com/loganek
Requirements
This target is cross-compiled. The target supports std
fully.
The Rust target definition here is interesting in a few ways. We want to serve two use cases here with this target:
- First, we want Rust usage of the target to be as hassle-free as possible, ideally avoiding the need to configure and install a local wasm32-wasi-preview1-threads toolchain.
- Second, one of the primary use cases of LLVM's new wasm backend and the
wasm support in LLD is that any compiled language can interoperate with
any other. The
wasm32-wasi-preview1-threads
target is the first with a viable C standard library and sysroot common definition, so we want Rust and C/C++ code to interoperate when compiled towasm32-unknown-unknown
.
You'll note, however, that the two goals above are somewhat at odds with one
another. To attempt to solve both use cases in one go we define a target
that (ab)uses the crt-static
target feature to indicate which one you're
in.
No interop with C required
By default the crt-static
target feature is enabled, and when enabled
this means that the bundled version of libc.a
found in liblibc.rlib
is used. This isn't intended really for interoperation with a C because it
may be the case that Rust's bundled C library is incompatible with a
foreign-compiled C library. In this use case, though, we use rust-lld
and
some copied crt startup object files to ensure that you can download the
wasi target for Rust and you're off to the races, no further configuration
necessary.
All in all, by default, no external dependencies are required. You can
compile wasm32-wasi-preview1-threads
binaries straight out of the box. You can't, however,
reliably interoperate with C code in this mode (yet).
Interop with C required
For the second goal we repurpose the target-feature
flag, meaning that
you'll need to do a few things to have C/Rust code interoperate.
- All Rust code needs to be compiled with
-C target-feature=-crt-static
, indicating that the bundled C standard library in the Rust sysroot will not be used. - If you're using rustc to build a linked artifact then you'll need to
specify
-C linker
to aclang
binary that supportswasm32-wasi-preview1-threads
and is configured with thewasm32-wasi-preview1-threads
sysroot. This will cause Rust code to be linked against the libc.a that the specifiedclang
provides. - If you're building a staticlib and integrating Rust code elsewhere, then
compiling with
-C target-feature=-crt-static
is all you need to do.
All in all, by default, no external dependencies are required. You can
compile wasm32-wasi-preview1-threads
binaries straight out of the box. You can't, however,
reliably interoperate with C code in this mode (yet).
Also note that at this time the wasm32-wasi-preview1-threads
target assumes the
presence of other merged wasm proposals such as (with their LLVM feature flags):
- Bulk memory -
+bulk-memory
- Mutable imported globals -
+mutable-globals
- Atomics -
+atomics
LLVM 16 is required for this target. The reason is related to linker flags: prior to LLVM 16, --import-memory and --export-memory were not allowed together. The reason both are needed is an artifact of how WASI currently does things; see https://github.com/WebAssembly/WASI/issues/502 for more details.
The target intends to match the corresponding Clang target for its "C"
ABI.
Note: due to the relatively early-days nature of this target when working with this target you may encounter LLVM bugs. If an assertion hit or a bug is found it's recommended to open an issue either with rust-lang/rust or ideally with LLVM itself.
Platform requirements
The runtime should support the same set of APIs as any other supported wasi target for interacting with the host environment through the WASI standard. The runtime also should have implementation of wasi-threads proposal.
This target is not a stable target. This means that there are a few engines
which implement the wasi-threads
feature and if they do they're likely behind a
flag, for example:
- Wasmtime -
--wasm-features=threads --wasi-modules=experimental-wasi-threads
- WAMR - needs to be built with WAMR_BUILD_LIB_WASI_THREADS=1
Building the target
Users need to install or built wasi-sdk since release 20.0
https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-20
and specify path to wasi-root .cargo/config.toml
[target.wasm32-wasi-preview1-threads]
wasi-root = ".../wasi-libc/sysroot"
After that users can build this by adding it to the target
list in
config.toml
, or with -Zbuild-std
.
Building Rust programs
From Rust Nightly 1.71.1 (2023-08-03) on the artifacts are shipped pre-compiled:
rustup target add wasm32-wasi-preview1-threads --toolchain nightly
Rust programs can be built for that target:
rustc --target wasm32-wasi-preview1-threads your-code.rs
Cross-compilation
This target can be cross-compiled from any hosts.
Testing
Currently testing is not well supported for wasm32-wasi-preview1-threads
and the
Rust project doesn't run any tests for this target. However the UI testsuite can be run
manually following this instructions:
- Ensure wamr, wasmtime
or another engine that supports
wasi-threads
is installed and can be found in the$PATH
env variable. - Clone master branch.
- Apply such a change with an engine from the step 1.
- Run
./x.py test --target wasm32-wasi-preview1-threads tests/ui
and save the list of failed tests. - Checkout branch with your changes.
- Apply such a change with an engine from the step 1.
- Run
./x.py test --target wasm32-wasi-preview1-threads tests/ui
and save the list of failed tests. - For both lists of failed tests run
cat list | sort > sorted_list
and compare it withdiff sorted_list1 sorted_list2
.