Skip to content

Commit ef32456

Browse files
committed
Auto merge of #119616 - rylev:wasm32-wasi-preview2, r=petrochenkov,m-ou-se
Add a new `wasm32-wasi-preview2` target This is the initial implementation of the MCP rust-lang/compiler-team#694 creating a new tier 3 target `wasm32-wasi-preview2`. That MCP has been seconded and will most likely be approved in a little over a week from now. For more information on the need for this target, please read the [MCP](rust-lang/compiler-team#694). There is one aspect of this PR that will become insta-stable once these changes reach a stable compiler: * A new `target_family` named `wasi` is introduced. This target family incorporates all wasi targets including `wasm32-wasi` and its derivative `wasm32-wasi-preview1-threads`. The difference between `target_family = wasi` and `target_os = wasi` will become much clearer when `wasm32-wasi` is renamed to `wasm32-wasi-preview1` and the `target_os` becomes `wasm32-wasi-preview1`. You can read about this target rename in [this MCP](rust-lang/compiler-team#695) which has also been seconded and will hopefully be officially approved soon. Additional technical details include: * Both `std::sys::wasi_preview2` and `std::os::wasi_preview2` have been created and mostly use `#[path]` annotations on their submodules to reach into the existing `wasi` (soon to be `wasi_preview1`) modules. Over time the differences between `wasi_preview1` and `wasi_preview2` will grow and most like all `#[path]` based module aliases will fall away. * Building `wasi-preview2` relies on a [`wasi-sdk`](https://github.com/WebAssembly/wasi-sdk) in the same way that `wasi-preview1` does (one must include a `wasi-root` path in the `Config.toml` pointing to sysroot included in the wasi-sdk). The target should build against [wasi-sdk v21](https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-21) without modifications. However, the wasi-sdk itself is growing [preview2 support](WebAssembly/wasi-sdk#370) so this might shift rapidly. We will be following along quickly to make sure that building the target remains possible as the wasi-sdk changes. * This requires a [patch to libc](https://github.com/rylev/rust-libc/tree/wasm32-wasi-preview2) that we'll need to land in conjunction with this change. Until that patch lands the target won't actually build.
2 parents 1e4f9e3 + 5e9bed7 commit ef32456

File tree

17 files changed

+331
-128
lines changed

17 files changed

+331
-128
lines changed

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,7 @@ symbols! {
18811881
vtable_align,
18821882
vtable_size,
18831883
warn,
1884+
wasip2,
18841885
wasm_abi,
18851886
wasm_import_module,
18861887
wasm_target_feature,

compiler/rustc_target/src/spec/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,7 @@ supported_targets! {
15751575
("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
15761576
("wasm32-unknown-unknown", wasm32_unknown_unknown),
15771577
("wasm32-wasi", wasm32_wasi),
1578+
("wasm32-wasip2", wasm32_wasip2),
15781579
("wasm32-wasi-preview1-threads", wasm32_wasi_preview1_threads),
15791580
("wasm64-unknown-unknown", wasm64_unknown_unknown),
15801581

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//! The `wasm32-wasip2` target is the next evolution of the
2+
//! wasm32-wasi target. While the wasi specification is still under
3+
//! active development, the {review 2 iteration is considered an "island
4+
//! of stability" that should allow users to rely on it indefinitely.
5+
//!
6+
//! The `wasi` target is a proposal to define a standardized set of WebAssembly
7+
//! component imports that allow it to interoperate with the host system in a
8+
//! standardized way. This set of imports is intended to empower WebAssembly
9+
//! binaries with host capabilities such as filesystem access, network access, etc.
10+
//!
11+
//! Wasi Preview 2 relies on the WebAssembly component model which is an extension of
12+
//! the core WebAssembly specification which allows interoperability between WebAssembly
13+
//! modules (known as "components") through high-level, shared-nothing APIs instead of the
14+
//! low-level, shared-everything linear memory model of the core WebAssembly specification.
15+
//!
16+
//! You can see more about wasi at <https://wasi.dev> and the component model at
17+
//! <https://github.com/WebAssembly/component-model>.
18+
19+
use crate::spec::crt_objects;
20+
use crate::spec::LinkSelfContainedDefault;
21+
use crate::spec::{base, Target};
22+
23+
pub fn target() -> Target {
24+
let mut options = base::wasm::options();
25+
26+
options.os = "wasi".into();
27+
options.env = "p2".into();
28+
options.linker = Some("wasm-component-ld".into());
29+
30+
options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
31+
options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained();
32+
33+
// FIXME: Figure out cases in which WASM needs to link with a native toolchain.
34+
options.link_self_contained = LinkSelfContainedDefault::True;
35+
36+
// Right now this is a bit of a workaround but we're currently saying that
37+
// the target by default has a static crt which we're taking as a signal
38+
// for "use the bundled crt". If that's turned off then the system's crt
39+
// will be used, but this means that default usage of this target doesn't
40+
// need an external compiler but it's still interoperable with an external
41+
// compiler if configured correctly.
42+
options.crt_static_default = true;
43+
options.crt_static_respected = true;
44+
45+
// Allow `+crt-static` to create a "cdylib" output which is just a wasm file
46+
// without a main function.
47+
options.crt_static_allows_dylibs = true;
48+
49+
// WASI's `sys::args::init` function ignores its arguments; instead,
50+
// `args::args()` makes the WASI API calls itself.
51+
options.main_needs_argc_argv = false;
52+
53+
// And, WASI mangles the name of "main" to distinguish between different
54+
// signatures.
55+
options.entry_name = "__main_void".into();
56+
57+
Target {
58+
llvm_target: "wasm32-unknown-unknown".into(),
59+
pointer_width: 32,
60+
data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
61+
arch: "wasm32".into(),
62+
options,
63+
}
64+
}

library/std/src/os/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ pub mod linux;
8585
#[cfg(any(target_os = "wasi", doc))]
8686
pub mod wasi;
8787

88+
#[cfg(any(all(target_os = "wasi", target_env = "p2"), doc))]
89+
pub mod wasip2;
90+
8891
// windows
8992
#[cfg(not(all(
9093
doc,

library/std/src/os/wasi/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
//! [`OsStr`]: crate::ffi::OsStr
2929
//! [`OsString`]: crate::ffi::OsString
3030
31-
#![stable(feature = "rust1", since = "1.0.0")]
31+
#![cfg_attr(not(target_env = "p2"), stable(feature = "rust1", since = "1.0.0"))]
32+
#![cfg_attr(target_env = "p2", unstable(feature = "wasip2", issue = "none"))]
3233
#![deny(unsafe_op_in_unsafe_fn)]
3334
#![doc(cfg(target_os = "wasi"))]
3435

library/std/src/os/wasip2/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//! Platform-specific extensions to `std` for Preview 2 of the WebAssembly System Interface (WASI).
2+
//!
3+
//! This module is currently empty, but will be filled over time as wasi-libc support for WASI Preview 2 is stabilized.
4+
5+
#![stable(feature = "raw_ext", since = "1.1.0")]

library/std/src/sys/pal/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ cfg_if::cfg_if! {
4040
} else if #[cfg(target_os = "wasi")] {
4141
mod wasi;
4242
pub use self::wasi::*;
43+
} else if #[cfg(all(target_os = "wasi", target_env = "p2"))] {
44+
mod wasip2;
45+
pub use self::wasip2::*;
4346
} else if #[cfg(target_family = "wasm")] {
4447
mod wasm;
4548
pub use self::wasm::*;
+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use crate::io as std_io;
2+
use crate::mem;
3+
4+
#[inline]
5+
pub fn is_interrupted(errno: i32) -> bool {
6+
errno == wasi::ERRNO_INTR.raw().into()
7+
}
8+
9+
pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
10+
use std_io::ErrorKind;
11+
12+
let Ok(errno) = u16::try_from(errno) else {
13+
return ErrorKind::Uncategorized;
14+
};
15+
16+
macro_rules! match_errno {
17+
($($($errno:ident)|+ => $errkind:ident),*, _ => $wildcard:ident $(,)?) => {
18+
match errno {
19+
$(e if $(e == ::wasi::$errno.raw())||+ => ErrorKind::$errkind),*,
20+
_ => ErrorKind::$wildcard,
21+
}
22+
};
23+
}
24+
25+
match_errno! {
26+
ERRNO_2BIG => ArgumentListTooLong,
27+
ERRNO_ACCES => PermissionDenied,
28+
ERRNO_ADDRINUSE => AddrInUse,
29+
ERRNO_ADDRNOTAVAIL => AddrNotAvailable,
30+
ERRNO_AFNOSUPPORT => Unsupported,
31+
ERRNO_AGAIN => WouldBlock,
32+
// ALREADY => "connection already in progress",
33+
// BADF => "bad file descriptor",
34+
// BADMSG => "bad message",
35+
ERRNO_BUSY => ResourceBusy,
36+
// CANCELED => "operation canceled",
37+
// CHILD => "no child processes",
38+
ERRNO_CONNABORTED => ConnectionAborted,
39+
ERRNO_CONNREFUSED => ConnectionRefused,
40+
ERRNO_CONNRESET => ConnectionReset,
41+
ERRNO_DEADLK => Deadlock,
42+
// DESTADDRREQ => "destination address required",
43+
ERRNO_DOM => InvalidInput,
44+
// DQUOT => /* reserved */,
45+
ERRNO_EXIST => AlreadyExists,
46+
// FAULT => "bad address",
47+
ERRNO_FBIG => FileTooLarge,
48+
ERRNO_HOSTUNREACH => HostUnreachable,
49+
// IDRM => "identifier removed",
50+
// ILSEQ => "illegal byte sequence",
51+
// INPROGRESS => "operation in progress",
52+
ERRNO_INTR => Interrupted,
53+
ERRNO_INVAL => InvalidInput,
54+
ERRNO_IO => Uncategorized,
55+
// ISCONN => "socket is connected",
56+
ERRNO_ISDIR => IsADirectory,
57+
ERRNO_LOOP => FilesystemLoop,
58+
// MFILE => "file descriptor value too large",
59+
ERRNO_MLINK => TooManyLinks,
60+
// MSGSIZE => "message too large",
61+
// MULTIHOP => /* reserved */,
62+
ERRNO_NAMETOOLONG => InvalidFilename,
63+
ERRNO_NETDOWN => NetworkDown,
64+
// NETRESET => "connection aborted by network",
65+
ERRNO_NETUNREACH => NetworkUnreachable,
66+
// NFILE => "too many files open in system",
67+
// NOBUFS => "no buffer space available",
68+
ERRNO_NODEV => NotFound,
69+
ERRNO_NOENT => NotFound,
70+
// NOEXEC => "executable file format error",
71+
// NOLCK => "no locks available",
72+
// NOLINK => /* reserved */,
73+
ERRNO_NOMEM => OutOfMemory,
74+
// NOMSG => "no message of the desired type",
75+
// NOPROTOOPT => "protocol not available",
76+
ERRNO_NOSPC => StorageFull,
77+
ERRNO_NOSYS => Unsupported,
78+
ERRNO_NOTCONN => NotConnected,
79+
ERRNO_NOTDIR => NotADirectory,
80+
ERRNO_NOTEMPTY => DirectoryNotEmpty,
81+
// NOTRECOVERABLE => "state not recoverable",
82+
// NOTSOCK => "not a socket",
83+
ERRNO_NOTSUP => Unsupported,
84+
// NOTTY => "inappropriate I/O control operation",
85+
ERRNO_NXIO => NotFound,
86+
// OVERFLOW => "value too large to be stored in data type",
87+
// OWNERDEAD => "previous owner died",
88+
ERRNO_PERM => PermissionDenied,
89+
ERRNO_PIPE => BrokenPipe,
90+
// PROTO => "protocol error",
91+
ERRNO_PROTONOSUPPORT => Unsupported,
92+
// PROTOTYPE => "protocol wrong type for socket",
93+
// RANGE => "result too large",
94+
ERRNO_ROFS => ReadOnlyFilesystem,
95+
ERRNO_SPIPE => NotSeekable,
96+
ERRNO_SRCH => NotFound,
97+
// STALE => /* reserved */,
98+
ERRNO_TIMEDOUT => TimedOut,
99+
ERRNO_TXTBSY => ResourceBusy,
100+
ERRNO_XDEV => CrossesDevices,
101+
ERRNO_NOTCAPABLE => PermissionDenied,
102+
_ => Uncategorized,
103+
}
104+
}
105+
106+
pub fn abort_internal() -> ! {
107+
unsafe { libc::abort() }
108+
}
109+
110+
pub fn hashmap_random_keys() -> (u64, u64) {
111+
let mut ret = (0u64, 0u64);
112+
unsafe {
113+
let base = &mut ret as *mut (u64, u64) as *mut u8;
114+
let len = mem::size_of_val(&ret);
115+
wasi::random_get(base, len).expect("random_get failure");
116+
}
117+
return ret;
118+
}
119+
120+
#[inline]
121+
pub(crate) fn err2io(err: wasi::Errno) -> std_io::Error {
122+
std_io::Error::from_raw_os_error(err.raw().into())
123+
}

library/std/src/sys/pal/wasi/mod.rs

+9-123
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@
1414
//! compiling for wasm. That way it's a compile time error for something that's
1515
//! guaranteed to be a runtime error!
1616
17-
use crate::io as std_io;
18-
use crate::mem;
19-
2017
#[path = "../unix/alloc.rs"]
2118
pub mod alloc;
2219
pub mod args;
@@ -57,123 +54,12 @@ cfg_if::cfg_if! {
5754
mod common;
5855
pub use common::*;
5956

60-
#[inline]
61-
pub fn is_interrupted(errno: i32) -> bool {
62-
errno == wasi::ERRNO_INTR.raw().into()
63-
}
64-
65-
pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
66-
use std_io::ErrorKind;
67-
68-
let Ok(errno) = u16::try_from(errno) else {
69-
return ErrorKind::Uncategorized;
70-
};
71-
72-
macro_rules! match_errno {
73-
($($($errno:ident)|+ => $errkind:ident),*, _ => $wildcard:ident $(,)?) => {
74-
match errno {
75-
$(e if $(e == ::wasi::$errno.raw())||+ => ErrorKind::$errkind),*,
76-
_ => ErrorKind::$wildcard,
77-
}
78-
};
79-
}
80-
81-
match_errno! {
82-
ERRNO_2BIG => ArgumentListTooLong,
83-
ERRNO_ACCES => PermissionDenied,
84-
ERRNO_ADDRINUSE => AddrInUse,
85-
ERRNO_ADDRNOTAVAIL => AddrNotAvailable,
86-
ERRNO_AFNOSUPPORT => Unsupported,
87-
ERRNO_AGAIN => WouldBlock,
88-
// ALREADY => "connection already in progress",
89-
// BADF => "bad file descriptor",
90-
// BADMSG => "bad message",
91-
ERRNO_BUSY => ResourceBusy,
92-
// CANCELED => "operation canceled",
93-
// CHILD => "no child processes",
94-
ERRNO_CONNABORTED => ConnectionAborted,
95-
ERRNO_CONNREFUSED => ConnectionRefused,
96-
ERRNO_CONNRESET => ConnectionReset,
97-
ERRNO_DEADLK => Deadlock,
98-
// DESTADDRREQ => "destination address required",
99-
ERRNO_DOM => InvalidInput,
100-
// DQUOT => /* reserved */,
101-
ERRNO_EXIST => AlreadyExists,
102-
// FAULT => "bad address",
103-
ERRNO_FBIG => FileTooLarge,
104-
ERRNO_HOSTUNREACH => HostUnreachable,
105-
// IDRM => "identifier removed",
106-
// ILSEQ => "illegal byte sequence",
107-
// INPROGRESS => "operation in progress",
108-
ERRNO_INTR => Interrupted,
109-
ERRNO_INVAL => InvalidInput,
110-
ERRNO_IO => Uncategorized,
111-
// ISCONN => "socket is connected",
112-
ERRNO_ISDIR => IsADirectory,
113-
ERRNO_LOOP => FilesystemLoop,
114-
// MFILE => "file descriptor value too large",
115-
ERRNO_MLINK => TooManyLinks,
116-
// MSGSIZE => "message too large",
117-
// MULTIHOP => /* reserved */,
118-
ERRNO_NAMETOOLONG => InvalidFilename,
119-
ERRNO_NETDOWN => NetworkDown,
120-
// NETRESET => "connection aborted by network",
121-
ERRNO_NETUNREACH => NetworkUnreachable,
122-
// NFILE => "too many files open in system",
123-
// NOBUFS => "no buffer space available",
124-
ERRNO_NODEV => NotFound,
125-
ERRNO_NOENT => NotFound,
126-
// NOEXEC => "executable file format error",
127-
// NOLCK => "no locks available",
128-
// NOLINK => /* reserved */,
129-
ERRNO_NOMEM => OutOfMemory,
130-
// NOMSG => "no message of the desired type",
131-
// NOPROTOOPT => "protocol not available",
132-
ERRNO_NOSPC => StorageFull,
133-
ERRNO_NOSYS => Unsupported,
134-
ERRNO_NOTCONN => NotConnected,
135-
ERRNO_NOTDIR => NotADirectory,
136-
ERRNO_NOTEMPTY => DirectoryNotEmpty,
137-
// NOTRECOVERABLE => "state not recoverable",
138-
// NOTSOCK => "not a socket",
139-
ERRNO_NOTSUP => Unsupported,
140-
// NOTTY => "inappropriate I/O control operation",
141-
ERRNO_NXIO => NotFound,
142-
// OVERFLOW => "value too large to be stored in data type",
143-
// OWNERDEAD => "previous owner died",
144-
ERRNO_PERM => PermissionDenied,
145-
ERRNO_PIPE => BrokenPipe,
146-
// PROTO => "protocol error",
147-
ERRNO_PROTONOSUPPORT => Unsupported,
148-
// PROTOTYPE => "protocol wrong type for socket",
149-
// RANGE => "result too large",
150-
ERRNO_ROFS => ReadOnlyFilesystem,
151-
ERRNO_SPIPE => NotSeekable,
152-
ERRNO_SRCH => NotFound,
153-
// STALE => /* reserved */,
154-
ERRNO_TIMEDOUT => TimedOut,
155-
ERRNO_TXTBSY => ResourceBusy,
156-
ERRNO_XDEV => CrossesDevices,
157-
ERRNO_NOTCAPABLE => PermissionDenied,
158-
_ => Uncategorized,
159-
}
160-
}
161-
162-
pub fn abort_internal() -> ! {
163-
unsafe { libc::abort() }
164-
}
165-
166-
pub fn hashmap_random_keys() -> (u64, u64) {
167-
let mut ret = (0u64, 0u64);
168-
unsafe {
169-
let base = core::ptr::addr_of_mut!(ret) as *mut u8;
170-
let len = mem::size_of_val(&ret);
171-
wasi::random_get(base, len).expect("random_get failure");
172-
}
173-
return ret;
174-
}
175-
176-
#[inline]
177-
fn err2io(err: wasi::Errno) -> std_io::Error {
178-
std_io::Error::from_raw_os_error(err.raw().into())
179-
}
57+
mod helpers;
58+
// These exports are listed individually to work around Rust's glob import
59+
// conflict rules. If we glob export `helpers` and `common` together, then
60+
// the compiler complains about conflicts.
61+
pub use helpers::abort_internal;
62+
pub use helpers::decode_error_kind;
63+
use helpers::err2io;
64+
pub use helpers::hashmap_random_keys;
65+
pub use helpers::is_interrupted;

0 commit comments

Comments
 (0)