Skip to content

Commit 31ecf34

Browse files
committed
Add the wasm32-wasi-preview2 target
Signed-off-by: Ryan Levick <me@ryanlevick.com>
1 parent 8b94152 commit 31ecf34

File tree

18 files changed

+334
-130
lines changed

18 files changed

+334
-130
lines changed

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1792,6 +1792,7 @@ symbols! {
17921792
warn,
17931793
wasm_abi,
17941794
wasm_import_module,
1795+
wasm_preview2,
17951796
wasm_target_feature,
17961797
while_let,
17971798
windows,

compiler/rustc_target/src/spec/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,7 @@ supported_targets! {
15741574
("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
15751575
("wasm32-unknown-unknown", wasm32_unknown_unknown),
15761576
("wasm32-wasi", wasm32_wasi),
1577+
("wasm32-wasi-preview2", wasm32_wasi_preview2),
15771578
("wasm32-wasi-preview1-threads", wasm32_wasi_preview1_threads),
15781579
("wasm64-unknown-unknown", wasm64_unknown_unknown),
15791580

compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1_threads.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@
7272
//! best we can with this target. Don't start relying on too much here unless
7373
//! you know what you're getting in to!
7474
75-
use crate::spec::{base, crt_objects, Cc, LinkSelfContainedDefault, LinkerFlavor, Target};
75+
use crate::spec::{base, crt_objects, cvs, Cc, LinkSelfContainedDefault, LinkerFlavor, Target};
7676

7777
pub fn target() -> Target {
7878
let mut options = base::wasm::options();
7979

80+
options.families = cvs!["wasm", "wasi"];
8081
options.os = "wasi".into();
8182

8283
options.add_pre_link_args(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//! The `wasm32-wasi-preview2` 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 = "preview2".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 = "preview2"), doc))]
89+
pub mod wasi_preview2;
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 = "preview2"), stable(feature = "rust1", since = "1.0.0"))]
32+
#![cfg_attr(target_env = "preview2", unstable(feature = "wasm_preview2", issue = "none"))]
3233
#![deny(unsafe_op_in_unsafe_fn)]
3334
#![doc(cfg(target_os = "wasi"))]
3435

+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 = "preview2"))] {
44+
mod wasi_preview2;
45+
pub use self::wasi_preview2::*;
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;
@@ -72,123 +69,12 @@ cfg_if::cfg_if! {
7269
mod common;
7370
pub use common::*;
7471

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

0 commit comments

Comments
 (0)