Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_target/src/spec/targets/wasm32_wasip3.rs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question (somewhat off-topic): what are the long term plans for the wasm32-wasip* set of targets? Or are the WASIpN more like "profiles" in terms of which WASI APIs are available?

Copy link
Member

@yoshuawuyts yoshuawuyts Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't say that the WASI targets are quite like profiles. For today's meeting between T-Lang and the Wasmtime team (unrelated to this PR), Alex wrote the following about the WASI versions. I thought it was really good, so I'll paste it here in full:


Appendix C: WASI Versions

To expand on the glossary terms above:

  • WASIp1 - no longer in development. Completely unrelated to the component model. Completely custom ABI and type system used to define APIs, and most APIs looked more-or-less like a C signature.
  • WASIp2 - first release of WASI "rebased" on the Component Model. All APIs defined in terms of WIT using component model types (e.g. record, string, etc). Functionality-wise WASIp2 is a superset of WASIp1 and notably includes support for TCP/UDP sockets. This more-or-less conicided with the first "release" of the component model itself, although the component model doesn't have an official release cadence. In lieu of that WASI versions have been used to introduce component model features. Regardless this is why Rust's wasm32-wasip2 target, for example, produces a component instead of a core module as output.
  • WASIp3 - next in-development version of WASI, not currently released/stamped. Major feature over WASIp2 is native async support in the component model itself, reflected in WIT as async functions for example. Additionally there are two new types in WIT, future<T> and stream<T>. Functionality remains the same as WASIp2 except that doing async operations is "much nicer" in terms of how languages integrate. Semantically it's now possible to invoke concurrent computations within a single component if it's exported as an async function in WIT.

Notably WASIp1 is incompatible with WASIp{2,3} due to how its APIs are defined. The core-level ABI and types of WASIp1 are incompatible with the component model and WASIp{2,3}. For WASIp{2,3}, however, the underyling format is "just a component" which means that a component can simultaneously import, and export WASIp2 and WASIp3 APIs. This means that all development of WASIp3-as-a-standard has been using the wasm32-wasip2 Rust target, for example. WASIp3 does not mean that WASIp2 is gone and inaccessible, but rather WASIp3 means that there's access to more functions. Idiomatically a true WASIp3 target wouldn't use WASIp2 at all, and that's the end goal, but this is not a requirement in the transition period from WASIp2 to WASIp3.


The plan is to eventually drive WASI to a 1.0 status, at which point we'll be able to drop the "preview" suffix. From a maintenance perspective WASIp2, WASIp3, and the eventual WASI 1.0 will share most of their infrastructure in the compiler, with most of the differences being in the stdlib. This should make them relatively easy to maintain as a set. This is different for WASI 0.1, which is different enough from the other targets that it needs to be maintained as its own target.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, that makes sense and is helpful context. Thanks.

Original file line number Diff line number Diff line change
@@ -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
}
5 changes: 5 additions & 0 deletions library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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'] }
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/os/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
}
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/net/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/net/connection/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
}
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/pal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
}
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/sys/random/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
}
Expand All @@ -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",
)))]
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/sys/stdio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
}
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/sys/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/doc/rustc/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/doc/rustc/src/platform-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
83 changes: 83 additions & 0 deletions src/doc/rustc/src/platform-support/wasm32-wasip3.md
Original file line number Diff line number Diff line change
@@ -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.
Loading