Skip to content

Commit 25d3cd2

Browse files
committed
Add the wasm32-wasi-preview2 target
Signed-off-by: Ryan Levick <me@ryanlevick.com>
1 parent 16fadb3 commit 25d3cd2

File tree

18 files changed

+334
-131
lines changed

18 files changed

+334
-131
lines changed

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,7 @@ symbols! {
17891789
warn,
17901790
wasm_abi,
17911791
wasm_import_module,
1792+
wasm_preview2,
17921793
wasm_target_feature,
17931794
while_let,
17941795
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;
@@ -76,123 +73,12 @@ cfg_if::cfg_if! {
7673
mod common;
7774
pub use common::*;
7875

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

0 commit comments

Comments
 (0)