From bcc09e99134ba4b19869890f2c7026ca25d9a440 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 30 Sep 2025 13:40:27 -0700 Subject: [PATCH] Add a new `wasm32-wasip3` target to Rust This commit adds a new tier 3 target to rustc, `wasm32-wasip3`. This follows in the footsteps of the previous `wasm32-wasip2` target and is used to represent binding to the WASIp3 set of APIs managed by the WASI subgroup to the WebAssembly Community Group. As of now the WASIp3 set of APIs are not finalized nor standardized. They're in the process of doing so and the current trajectory is to have the APIs published in December of this year. The goal here is to get the wheels turning in Rust to have the target in a more-ready-than-nonexistent state by the time this happens in December. For now the `wasm32-wasip3` target looks exactly the same as `wasm32-wasip2` except that `target_env = "p3"` is specified. This indicates to crates in the ecosystem that WASIp3 APIs should be used, such as the [`wasip3` crate]. Over time this target will evolve as implementation in guest toolchains progress, notably: * The standard library will use WASIp3 APIs natively once they're finalized in the WASI subgroup. * Support through `wasi-libc` will be updated to use WASIp3 natively which Rust will then transitively use. * Longer-term, features such as cooperative multithreading will be added to the WASIp3-track of targets to enable using `std::thread`, for example, on this target. These changes are all expected to be non-breaking changes for users of this target. Runtimes supporting WASIp3, currently Wasmtime and Jco, support WASIp2 APIs as well and will work with components whether or not they import WASIp2, both WASIp2 and WASIp3, or just WASIp3 APIs. This means that changing the internal implementation details of libstd over time is expected to be a non-breaking change. [`wasip3` crate]: https://crates.io/crates/wasip3 --- compiler/rustc_target/src/spec/mod.rs | 1 + .../src/spec/targets/wasm32_wasip3.rs | 20 +++++ library/std/Cargo.toml | 5 ++ library/std/src/os/mod.rs | 2 +- library/std/src/sys/args/mod.rs | 2 +- library/std/src/sys/net/connection/mod.rs | 2 +- .../std/src/sys/net/connection/socket/mod.rs | 2 +- library/std/src/sys/pal/mod.rs | 2 +- library/std/src/sys/random/mod.rs | 4 +- library/std/src/sys/stdio/mod.rs | 2 +- library/std/src/sys/thread/mod.rs | 4 +- src/bootstrap/src/core/build_steps/compile.rs | 10 +++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../src/platform-support/wasm32-wasip3.md | 83 +++++++++++++++++++ 15 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs create mode 100644 src/doc/rustc/src/platform-support/wasm32-wasip3.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4a82a8bd888e6..e4b44e8b686c1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1624,6 +1624,7 @@ supported_targets! { ("wasm32v1-none", wasm32v1_none), ("wasm32-wasip1", wasm32_wasip1), ("wasm32-wasip2", wasm32_wasip2), + ("wasm32-wasip3", wasm32_wasip3), ("wasm32-wasip1-threads", wasm32_wasip1_threads), ("wasm32-wali-linux-musl", wasm32_wali_linux_musl), ("wasm64-unknown-unknown", wasm64_unknown_unknown), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs new file mode 100644 index 0000000000000..e3d5e6542c263 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs @@ -0,0 +1,20 @@ +//! The `wasm32-wasip3` target is the next in the chain of `wasm32-wasip1`, then +//! `wasm32-wasip2`, then WASIp3. The main feature of WASIp3 is native async +//! support in the component model itself. +//! +//! Like `wasm32-wasip2` this target produces a component by default. Support +//! for `wasm32-wasip3` is very early as of the time of this writing so +//! components produced will still import WASIp2 APIs, but that's ok since it's +//! all component-model-level imports anyway. Over time the imports of the +//! standard library will change to WASIp3. + +use crate::spec::Target; + +pub(crate) fn target() -> Target { + // As of now WASIp3 is a lightly edited wasip2 target, so start with that + // and this may grow over time as more features are supported. + let mut target = super::wasm32_wasip2::target(); + target.llvm_target = "wasm32-wasip3".into(); + target.options.env = "p3".into(); + target +} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 888914a2f772e..779b07ce240a6 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -85,6 +85,11 @@ wasip2 = { version = '0.14.4', features = [ 'rustc-dep-of-std', ], default-features = false, package = 'wasi' } +[target.'cfg(all(target_os = "wasi", target_env = "p3"))'.dependencies] +wasip2 = { version = '0.14.4', features = [ + 'rustc-dep-of-std', +], default-features = false, package = 'wasi' } + [target.'cfg(target_os = "uefi")'.dependencies] r-efi = { version = "5.2.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "2.0.0", features = ['rustc-dep-of-std'] } diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 96d9bfae8ca32..fd7a11433af1b 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -103,7 +103,7 @@ pub mod linux; all(target_vendor = "fortanix", target_env = "sgx") ) )))] -#[cfg(any(target_os = "wasi", doc))] +#[cfg(any(target_os = "wasi", any(target_env = "p1", target_env = "p2"), doc))] pub mod wasi; #[cfg(any(all(target_os = "wasi", target_env = "p2"), doc))] diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index e11e8e5430f06..75c59da721e19 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -36,7 +36,7 @@ cfg_select! { mod wasip1; pub use wasip1::*; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::*; } diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs index 7f9636a8ccfd6..41e7159f909ae 100644 --- a/library/std/src/sys/net/connection/mod.rs +++ b/library/std/src/sys/net/connection/mod.rs @@ -3,7 +3,7 @@ cfg_select! { all(target_family = "unix", not(target_os = "l4re")), target_os = "windows", target_os = "hermit", - all(target_os = "wasi", target_env = "p2"), + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")), target_os = "solid_asp3", ) => { mod socket; diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 1dd06e97bbabd..e59d01bdd9bb1 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -25,7 +25,7 @@ cfg_select! { mod unix; pub use unix::*; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::*; } diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index dd5e83ee570b6..9e964540a87c1 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -49,7 +49,7 @@ cfg_select! { mod vexos; pub use self::vexos::*; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use self::wasip2::*; } diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 3c5a4c82a9f1e..ec81d89a0f3af 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -90,7 +90,7 @@ cfg_select! { mod wasip1; pub use wasip1::fill_bytes; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::{fill_bytes, hashmap_random_keys}; } @@ -115,7 +115,7 @@ cfg_select! { target_os = "linux", target_os = "android", all(target_family = "wasm", target_os = "unknown"), - all(target_os = "wasi", target_env = "p2"), + all(target_os = "wasi", not(target_env = "p1")), target_os = "xous", target_os = "vexos", )))] diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs index 404ac87792696..660317e3ea844 100644 --- a/library/std/src/sys/stdio/mod.rs +++ b/library/std/src/sys/stdio/mod.rs @@ -37,7 +37,7 @@ cfg_select! { mod wasip1; pub use wasip1::*; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::*; } diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs index 3bd83dd760ac9..a20b2a3ddd8ce 100644 --- a/library/std/src/sys/thread/mod.rs +++ b/library/std/src/sys/thread/mod.rs @@ -99,7 +99,7 @@ cfg_select! { #[cfg(not(target_feature = "atomics"))] pub use unsupported::{Thread, available_parallelism}; } - all(target_os = "wasi", target_env = "p2") => { + all(target_os = "wasi", any(target_env = "p2", target_env = "p3")) => { mod wasip2; pub use wasip2::{sleep, sleep_until}; #[expect(dead_code)] @@ -146,7 +146,7 @@ cfg_select! { target_os = "hurd", target_os = "fuchsia", target_os = "vxworks", - all(target_os = "wasi", target_env = "p2"), + all(target_os = "wasi", not(target_env = "p1")), )))] pub fn sleep_until(deadline: crate::time::Instant) { use crate::time::Instant; diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 96b4e15433f7e..715f7abe9477f 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -430,6 +430,16 @@ fn copy_self_contained_objects( target.triple ) }); + + // wasm32-wasip3 doesn't exist in wasi-libc yet, so instead use libs + // from the wasm32-wasip2 target. Once wasi-libc supports wasip3 this + // should be deleted and the native objects should be used. + let srcdir = if target == "wasm32-wasip3" { + assert!(!srcdir.exists(), "wasip3 support is in wasi-libc, this should be updated now"); + builder.wasi_libdir(TargetSelection::from_user("wasm32-wasip2")).unwrap() + } else { + srcdir + }; for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] { copy_and_stamp( builder, diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 67882bb38132a..1965a1b25498b 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -132,6 +132,7 @@ - [wasm32-wasip1](platform-support/wasm32-wasip1.md) - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md) - [wasm32-wasip2](platform-support/wasm32-wasip2.md) + - [wasm32-wasip3](platform-support/wasm32-wasip3.md) - [wasm32-wali-linux-musl](platform-support/wasm32-wali-linux.md) - [wasm32-unknown-emscripten](platform-support/wasm32-unknown-emscripten.md) - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d0b6ed51bc163..c23d7563aedb5 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -198,6 +198,7 @@ target | std | notes [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASIp1 [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads [`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ | WebAssembly with WASIp2 +[`wasm32-wasip3`](platform-support/wasm32-wasip3.md) | ✓ | WebAssembly with WASIp3 [`wasm32v1-none`](platform-support/wasm32v1-none.md) | * | WebAssembly limited to 1.0 features and no imports [`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS [`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on x86_64 diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip3.md b/src/doc/rustc/src/platform-support/wasm32-wasip3.md new file mode 100644 index 0000000000000..e8063a1bdcfed --- /dev/null +++ b/src/doc/rustc/src/platform-support/wasm32-wasip3.md @@ -0,0 +1,83 @@ +# `wasm32-wasip3` + +**Tier: 3** + +The `wasm32-wasip3` target is the next stage of evolution of the +[`wasm32-wasip2`](./wasm32-wasip2.md) target. The `wasm32-wasip3` target enables +the Rust standard library to use WASIp3 APIs to implement various pieces of +functionality. WASIp3 brings native async support over WASIp2, which integrates +well with Rust's `async` ecosystem. + +> **Note**: As of 2025-10-01 WASIp3 has not yet been approved by the WASI +> subgroup of the WebAssembly Community Group. Development is expected to +> conclude in late 2025 or early 2026. Until then the Rust standard library +> won't actually use WASIp3 APIs on the `wasm32-wasip3` target as they are not +> yet stable and would reduce the stability of this target. Once WASIp3 is +> approved, however, the standard library will update to use WASIp3 natively. + +> **Note**: This target does not yet build as of 2025-10-01 due to and update +> needed in the `libc` crate. Using it will require a `[patch]` for now. + +> **Note**: Until the standard library is fully migrated to use the `wasip3` +> crate then components produced for `wasm32-wasip3` may import WASIp2 APIs. +> This is considered a transitionary phase until fully support of libstd is +> implemented. + +## Target maintainers + +[@alexcrichton](https://github.com/alexcrichton) + +## Requirements + +This target is cross-compiled. The target supports `std` fully. + +## Platform requirements + +The WebAssembly runtime should support both WASIp2 and WASIp3. Runtimes also +are required to support components since this target outputs a component as +opposed to a core wasm module. Two example runtimes for WASIp3 are [Wasmtime] +and [Jco]. + +[Wasmtime]: https://wasmtime.dev/ +[Jco]: https://github.com/bytecodealliance/jco + +## Building the target + +To build this target first acquire a copy of +[`wasi-sdk`](https://github.com/WebAssembly/wasi-sdk/). At this time version 22 +is the minimum needed. + +Next configure the `WASI_SDK_PATH` environment variable to point to where this +is installed. For example: + +```text +export WASI_SDK_PATH=/path/to/wasi-sdk-22.0 +``` + +Next be sure to enable LLD when building Rust from source as LLVM's `wasm-ld` +driver for LLD is required when linking WebAssembly code together. Rust's build +system will automatically pick up any necessary binaries and programs from +`WASI_SDK_PATH`. + +## Testing + +This target is not tested in CI at this time. Locally it can be tested with a +`wasmtime` binary in `PATH` like so: + +```text +./x.py test --target wasm32-wasip3 tests/ui +``` + +## Conditionally compiling code + +It's recommended to conditionally compile code for this target with: + +```text +#[cfg(all(target_os = "wasi", target_env = "p3"))] +``` + +## Enabled WebAssembly features + +The default set of WebAssembly features enabled for compilation is currently the +same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the +documentation there for more information.