Add wasm32-wasi-threads target + WASI threads
This commit is contained in:
parent
f9f674f2bc
commit
5697f1620d
@ -1403,6 +1403,7 @@ fn $module() {
|
||||
("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
|
||||
("wasm32-unknown-unknown", wasm32_unknown_unknown),
|
||||
("wasm32-wasi", wasm32_wasi),
|
||||
("wasm32-wasi-preview1-threads", wasm32_wasi_preview1_threads),
|
||||
("wasm64-unknown-unknown", wasm64_unknown_unknown),
|
||||
|
||||
("thumbv6m-none-eabi", thumbv6m_none_eabi),
|
||||
|
134
compiler/rustc_target/src/spec/wasm32_wasi_preview1_threads.rs
Normal file
134
compiler/rustc_target/src/spec/wasm32_wasi_preview1_threads.rs
Normal file
@ -0,0 +1,134 @@
|
||||
//! The `wasm32-wasi-preview1-threads` target is a new and still (as of July 2023) an
|
||||
//! experimental target. The definition in this file is likely to be tweaked
|
||||
//! over time and shouldn't be relied on too much.
|
||||
//!
|
||||
//! The `wasi-threads` target is a proposal to define a standardized set of syscalls
|
||||
//! that WebAssembly files can interoperate with. This set of syscalls is
|
||||
//! intended to empower WebAssembly binaries with native capabilities such as
|
||||
//! threads, filesystem access, network access, etc.
|
||||
//!
|
||||
//! You can see more about the proposal at <https://github.com/WebAssembly/wasi-threads>.
|
||||
//!
|
||||
//! The Rust target definition here is interesting in a few ways. We want to
|
||||
//! serve two use cases here with this target:
|
||||
//!
|
||||
//! * First, we want Rust usage of the target to be as hassle-free as possible,
|
||||
//! ideally avoiding the need to configure and install a local wasm32-wasi-preview1-threads
|
||||
//! toolchain.
|
||||
//!
|
||||
//! * Second, one of the primary use cases of LLVM's new wasm backend and the
|
||||
//! wasm support in LLD is that any compiled language can interoperate with
|
||||
//! any other. To that the `wasm32-wasi-preview1-threads` target is the first with a viable C
|
||||
//! standard library and sysroot common definition, so we want Rust and C/C++
|
||||
//! code to interoperate when compiled to `wasm32-unknown-unknown`.
|
||||
//!
|
||||
//! You'll note, however, that the two goals above are somewhat at odds with one
|
||||
//! another. To attempt to solve both use cases in one go we define a target
|
||||
//! that (ab)uses the `crt-static` target feature to indicate which one you're
|
||||
//! in.
|
||||
//!
|
||||
//! ## No interop with C required
|
||||
//!
|
||||
//! By default the `crt-static` target feature is enabled, and when enabled
|
||||
//! this means that the bundled version of `libc.a` found in `liblibc.rlib`
|
||||
//! is used. This isn't intended really for interoperation with a C because it
|
||||
//! may be the case that Rust's bundled C library is incompatible with a
|
||||
//! foreign-compiled C library. In this use case, though, we use `rust-lld` and
|
||||
//! some copied crt startup object files to ensure that you can download the
|
||||
//! wasi target for Rust and you're off to the races, no further configuration
|
||||
//! necessary.
|
||||
//!
|
||||
//! All in all, by default, no external dependencies are required. You can
|
||||
//! compile `wasm32-wasi-preview1-threads` binaries straight out of the box. You can't, however,
|
||||
//! reliably interoperate with C code in this mode (yet).
|
||||
//!
|
||||
//! ## Interop with C required
|
||||
//!
|
||||
//! For the second goal we repurpose the `target-feature` flag, meaning that
|
||||
//! you'll need to do a few things to have C/Rust code interoperate.
|
||||
//!
|
||||
//! 1. All Rust code needs to be compiled with `-C target-feature=-crt-static`,
|
||||
//! indicating that the bundled C standard library in the Rust sysroot will
|
||||
//! not be used.
|
||||
//!
|
||||
//! 2. If you're using rustc to build a linked artifact then you'll need to
|
||||
//! specify `-C linker` to a `clang` binary that supports
|
||||
//! `wasm32-wasi-preview1-threads` and is configured with the `wasm32-wasi-preview1-threads` sysroot. This
|
||||
//! will cause Rust code to be linked against the libc.a that the specified
|
||||
//! `clang` provides.
|
||||
//!
|
||||
//! 3. If you're building a staticlib and integrating Rust code elsewhere, then
|
||||
//! compiling with `-C target-feature=-crt-static` is all you need to do.
|
||||
//!
|
||||
//! You can configure the linker via Cargo using the
|
||||
//! `CARGO_TARGET_WASM32_WASI_LINKER` env var. Be sure to also set
|
||||
//! `CC_wasm32-wasi-preview1-threads` if any crates in the dependency graph are using the `cc`
|
||||
//! crate.
|
||||
//!
|
||||
//! ## Remember, this is all in flux
|
||||
//!
|
||||
//! The wasi target is **very** new in its specification. It's likely going to
|
||||
//! be a long effort to get it standardized and stable. We'll be following it as
|
||||
//! best we can with this target. Don't start relying on too much here unless
|
||||
//! you know what you're getting in to!
|
||||
|
||||
use super::crt_objects::{self, LinkSelfContainedDefault};
|
||||
use super::{wasm_base, Cc, LinkerFlavor, Target};
|
||||
|
||||
pub fn target() -> Target {
|
||||
let mut options = wasm_base::options();
|
||||
|
||||
options.os = "wasi".into();
|
||||
|
||||
options.add_pre_link_args(
|
||||
LinkerFlavor::WasmLld(Cc::No),
|
||||
&["--import-memory", "--export-memory", "--shared-memory"],
|
||||
);
|
||||
options.add_pre_link_args(
|
||||
LinkerFlavor::WasmLld(Cc::Yes),
|
||||
&[
|
||||
"--target=wasm32-wasi-threads",
|
||||
"-Wl,--import-memory",
|
||||
"-Wl,--export-memory,",
|
||||
"-Wl,--shared-memory",
|
||||
],
|
||||
);
|
||||
|
||||
options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
|
||||
options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained();
|
||||
|
||||
// FIXME: Figure out cases in which WASM needs to link with a native toolchain.
|
||||
options.link_self_contained = LinkSelfContainedDefault::True;
|
||||
|
||||
// Right now this is a bit of a workaround but we're currently saying that
|
||||
// the target by default has a static crt which we're taking as a signal
|
||||
// for "use the bundled crt". If that's turned off then the system's crt
|
||||
// will be used, but this means that default usage of this target doesn't
|
||||
// need an external compiler but it's still interoperable with an external
|
||||
// compiler if configured correctly.
|
||||
options.crt_static_default = true;
|
||||
options.crt_static_respected = true;
|
||||
|
||||
// Allow `+crt-static` to create a "cdylib" output which is just a wasm file
|
||||
// without a main function.
|
||||
options.crt_static_allows_dylibs = true;
|
||||
|
||||
// WASI's `sys::args::init` function ignores its arguments; instead,
|
||||
// `args::args()` makes the WASI API calls itself.
|
||||
options.main_needs_argc_argv = false;
|
||||
|
||||
// And, WASI mangles the name of "main" to distinguish between different
|
||||
// signatures.
|
||||
options.entry_name = "__main_void".into();
|
||||
|
||||
options.singlethread = false;
|
||||
options.features = "+atomics,+bulk-memory,+mutable-globals".into();
|
||||
|
||||
Target {
|
||||
llvm_target: "wasm32-wasi".into(),
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
|
||||
arch: "wasm32".into(),
|
||||
options,
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public
|
||||
[target.'cfg(target_os = "hermit")'.dependencies]
|
||||
hermit-abi = { version = "0.3.2", features = ['rustc-dep-of-std'], public = true }
|
||||
|
||||
[target.wasm32-wasi.dependencies]
|
||||
[target.'cfg(target_os = "wasi")'.dependencies]
|
||||
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
|
||||
|
||||
[features]
|
||||
|
@ -29,8 +29,7 @@
|
||||
#[path = "../wasm/atomics/futex.rs"]
|
||||
pub mod futex;
|
||||
pub mod io;
|
||||
#[path = "../unsupported/locks/mod.rs"]
|
||||
pub mod locks;
|
||||
|
||||
pub mod net;
|
||||
pub mod os;
|
||||
#[path = "../unix/os_str.rs"]
|
||||
@ -47,14 +46,27 @@
|
||||
pub mod thread_local_dtor;
|
||||
#[path = "../unsupported/thread_local_key.rs"]
|
||||
pub mod thread_local_key;
|
||||
#[path = "../unsupported/thread_parking.rs"]
|
||||
pub mod thread_parking;
|
||||
pub mod time;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(target_feature = "atomics"))] {
|
||||
if #[cfg(target_feature = "atomics")] {
|
||||
#[path = "../unix/locks"]
|
||||
pub mod locks {
|
||||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
mod futex_condvar;
|
||||
mod futex_mutex;
|
||||
mod futex_rwlock;
|
||||
pub(crate) use futex_condvar::Condvar;
|
||||
pub(crate) use futex_mutex::Mutex;
|
||||
pub(crate) use futex_rwlock::RwLock;
|
||||
}
|
||||
} else {
|
||||
#[path = "../unsupported/locks/mod.rs"]
|
||||
pub mod locks;
|
||||
#[path = "../unsupported/once.rs"]
|
||||
pub mod once;
|
||||
#[path = "../unsupported/thread_parking.rs"]
|
||||
pub mod thread_parking;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +224,11 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn page_size() -> usize {
|
||||
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
||||
}
|
||||
|
||||
pub fn temp_dir() -> PathBuf {
|
||||
panic!("no filesystem on wasm")
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
@ -7,14 +5,116 @@
|
||||
use crate::sys::unsupported;
|
||||
use crate::time::Duration;
|
||||
|
||||
pub struct Thread(!);
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_feature = "atomics")] {
|
||||
use crate::cmp;
|
||||
use crate::ptr;
|
||||
use crate::sys::os;
|
||||
// Add a few symbols not in upstream `libc` just yet.
|
||||
mod libc {
|
||||
pub use crate::ffi;
|
||||
pub use crate::mem;
|
||||
pub use libc::*;
|
||||
|
||||
// defined in wasi-libc
|
||||
// https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108
|
||||
#[repr(C)]
|
||||
union pthread_attr_union {
|
||||
__i: [ffi::c_int; if mem::size_of::<ffi::c_int>() == 8 { 14 } else { 9 }],
|
||||
__vi: [ffi::c_int; if mem::size_of::<ffi::c_int>() == 8 { 14 } else { 9 }],
|
||||
__s: [ffi::c_ulong; if mem::size_of::<ffi::c_int>() == 8 { 7 } else { 9 }],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct pthread_attr_t {
|
||||
__u: pthread_attr_union,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pthread_t = *mut ffi::c_void;
|
||||
|
||||
extern "C" {
|
||||
pub fn pthread_create(
|
||||
native: *mut pthread_t,
|
||||
attr: *const pthread_attr_t,
|
||||
f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void,
|
||||
value: *mut ffi::c_void,
|
||||
) -> ffi::c_int;
|
||||
pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int;
|
||||
pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int;
|
||||
pub fn pthread_attr_setstacksize(
|
||||
attr: *mut pthread_attr_t,
|
||||
stack_size: libc::size_t,
|
||||
) -> ffi::c_int;
|
||||
pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Thread {
|
||||
id: libc::pthread_t,
|
||||
}
|
||||
} else {
|
||||
pub struct Thread(!);
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
|
||||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
unsupported()
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_feature = "atomics")] {
|
||||
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let p = Box::into_raw(Box::new(p));
|
||||
let mut native: libc::pthread_t = mem::zeroed();
|
||||
let mut attr: libc::pthread_attr_t = mem::zeroed();
|
||||
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
|
||||
|
||||
let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
|
||||
|
||||
match libc::pthread_attr_setstacksize(&mut attr, stack_size) {
|
||||
0 => {}
|
||||
n => {
|
||||
assert_eq!(n, libc::EINVAL);
|
||||
// EINVAL means |stack_size| is either too small or not a
|
||||
// multiple of the system page size. Because it's definitely
|
||||
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
|
||||
// Round up to the nearest page and try again.
|
||||
let page_size = os::page_size();
|
||||
let stack_size =
|
||||
(stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
|
||||
assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
|
||||
}
|
||||
};
|
||||
|
||||
let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
|
||||
// Note: if the thread creation fails and this assert fails, then p will
|
||||
// be leaked. However, an alternative design could cause double-free
|
||||
// which is clearly worse.
|
||||
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
|
||||
|
||||
return if ret != 0 {
|
||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||
// safe to reconstruct the box so that it gets deallocated.
|
||||
drop(Box::from_raw(p));
|
||||
Err(io::Error::from_raw_os_error(ret))
|
||||
} else {
|
||||
Ok(Thread { id: native })
|
||||
};
|
||||
|
||||
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
|
||||
unsafe {
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
unsupported()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
@ -62,7 +162,19 @@ pub fn sleep(dur: Duration) {
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
self.0
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_feature = "atomics")] {
|
||||
unsafe {
|
||||
let ret = libc::pthread_join(self.id, ptr::null_mut());
|
||||
mem::forget(self);
|
||||
if ret != 0 {
|
||||
rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,13 +287,14 @@ fn copy_self_contained_objects(
|
||||
let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained);
|
||||
target_deps.push((libunwind_path, DependencyType::TargetSelfContained));
|
||||
}
|
||||
} else if target.ends_with("-wasi") {
|
||||
} else if target.contains("-wasi") {
|
||||
let srcdir = builder
|
||||
.wasi_root(target)
|
||||
.unwrap_or_else(|| {
|
||||
panic!("Target {:?} does not have a \"wasi-root\" key", target.triple)
|
||||
})
|
||||
.join("lib/wasm32-wasi");
|
||||
.join("lib")
|
||||
.join(target.to_string().replace("-preview1", ""));
|
||||
for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] {
|
||||
copy_and_stamp(
|
||||
builder,
|
||||
@ -393,9 +394,13 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
|
||||
}
|
||||
}
|
||||
|
||||
if target.ends_with("-wasi") {
|
||||
if target.contains("-wasi") {
|
||||
if let Some(p) = builder.wasi_root(target) {
|
||||
let root = format!("native={}/lib/wasm32-wasi", p.to_str().unwrap());
|
||||
let root = format!(
|
||||
"native={}/lib/{}",
|
||||
p.to_str().unwrap(),
|
||||
target.to_string().replace("-preview1", "")
|
||||
);
|
||||
cargo.rustflag("-L").rustflag(&root);
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,9 @@ RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
|
||||
COPY host-x86_64/dist-various-2/build-wasi-toolchain.sh /tmp/
|
||||
RUN /tmp/build-wasi-toolchain.sh
|
||||
|
||||
COPY host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh /tmp/
|
||||
RUN /tmp/build-wasi-threads-toolchain.sh
|
||||
|
||||
COPY scripts/freebsd-toolchain.sh /tmp/
|
||||
RUN /tmp/freebsd-toolchain.sh i686
|
||||
|
||||
@ -114,6 +117,7 @@ ENV TARGETS=x86_64-unknown-fuchsia
|
||||
ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
|
||||
ENV TARGETS=$TARGETS,wasm32-unknown-unknown
|
||||
ENV TARGETS=$TARGETS,wasm32-wasi
|
||||
ENV TARGETS=$TARGETS,wasm32-wasi-preview1-threads
|
||||
ENV TARGETS=$TARGETS,sparcv9-sun-solaris
|
||||
ENV TARGETS=$TARGETS,x86_64-pc-solaris
|
||||
ENV TARGETS=$TARGETS,x86_64-sun-solaris
|
||||
@ -136,6 +140,7 @@ RUN ln -s /usr/include/asm-generic /usr/local/include/asm
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \
|
||||
--set target.wasm32-wasi.wasi-root=/wasm32-wasi \
|
||||
--set target.wasm32-wasi-preview1-threads.wasi-root=/wasm32-wasi-preview1-threads \
|
||||
--musl-root-armv7=/musl-armv7
|
||||
|
||||
ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
|
||||
|
24
src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh
Executable file
24
src/ci/docker/host-x86_64/dist-various-2/build-wasi-threads-toolchain.sh
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.4/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz
|
||||
curl https://ci-mirrors.rust-lang.org/rustc/2023-05-17-clang%2Bllvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz | \
|
||||
tar xJf -
|
||||
bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin"
|
||||
|
||||
git clone https://github.com/WebAssembly/wasi-libc
|
||||
|
||||
cd wasi-libc
|
||||
git reset --hard 7018e24d8fe248596819d2e884761676f3542a04
|
||||
make -j$(nproc) \
|
||||
CC="$bin/clang" \
|
||||
NM="$bin/llvm-nm" \
|
||||
AR="$bin/llvm-ar" \
|
||||
THREAD_MODEL=posix \
|
||||
INSTALL_DIR=/wasm32-wasi-preview1-threads \
|
||||
install
|
||||
|
||||
cd ..
|
||||
rm -rf wasi-libc
|
||||
rm -rf clang+llvm*
|
@ -2,10 +2,10 @@
|
||||
|
||||
set -ex
|
||||
|
||||
# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.6/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
curl https://ci-mirrors.rust-lang.org/rustc/2022-12-06-clang%2Bllvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04.tar.xz | \
|
||||
# Originally from https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.4/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz
|
||||
curl https://ci-mirrors.rust-lang.org/rustc/2023-05-17-clang%2Bllvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz | \
|
||||
tar xJf -
|
||||
bin="$PWD/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin"
|
||||
bin="$PWD/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04/bin"
|
||||
|
||||
git clone https://github.com/WebAssembly/wasi-libc
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
- [\*-unknown-netbsd\*](platform-support/netbsd.md)
|
||||
- [*-unknown-openbsd](platform-support/openbsd.md)
|
||||
- [\*-unknown-uefi](platform-support/unknown-uefi.md)
|
||||
- [wasm32-wasi-preview1-threads](platform-support/wasm32-wasi-preview1-threads.md)
|
||||
- [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
|
||||
- [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
|
||||
- [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
|
||||
|
@ -318,6 +318,7 @@ target | std | host | notes
|
||||
`thumbv7a-pc-windows-msvc` | ? | |
|
||||
`thumbv7a-uwp-windows-msvc` | ✓ | |
|
||||
`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, MUSL
|
||||
[`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads
|
||||
[`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly
|
||||
`x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64
|
||||
[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS
|
||||
|
@ -0,0 +1,139 @@
|
||||
# `wasm32-wasi-preview1-threads`
|
||||
|
||||
**Tier: 3**
|
||||
|
||||
The `wasm32-wasi-preview1-threads` target is a new and still (as of July 2023) an
|
||||
experimental target. This target is an extension to `wasm32-wasi-preview1` target,
|
||||
originally known as `wasm32-wasi`. It extends the original target with a
|
||||
standardized set of syscalls that are intended to empower WebAssembly binaries with
|
||||
native multi threading capabilities.
|
||||
|
||||
[wasi-threads]: https://github.com/WebAssembly/wasi-threads
|
||||
[threads]: https://github.com/WebAssembly/threads
|
||||
|
||||
|
||||
## Target maintainers
|
||||
|
||||
- Georgii Rylov, https://github.com/g0djan
|
||||
- Alex Crichton, https://github.com/alexcrichton
|
||||
- Andrew Brown, https://github.com/abrown
|
||||
- Marcin Kolny, https://github.com/loganek
|
||||
|
||||
## Requirements
|
||||
|
||||
This target is cross-compiled. The target supports `std` fully.
|
||||
|
||||
The Rust target definition here is interesting in a few ways. We want to
|
||||
serve two use cases here with this target:
|
||||
* First, we want Rust usage of the target to be as hassle-free as possible,
|
||||
ideally avoiding the need to configure and install a local wasm32-wasi-preview1-threads
|
||||
toolchain.
|
||||
* Second, one of the primary use cases of LLVM's new wasm backend and the
|
||||
wasm support in LLD is that any compiled language can interoperate with
|
||||
any other. The `wasm32-wasi-preview1-threads` target is the first with a viable C
|
||||
standard library and sysroot common definition, so we want Rust and C/C++
|
||||
code to interoperate when compiled to `wasm32-unknown-unknown`.
|
||||
|
||||
|
||||
You'll note, however, that the two goals above are somewhat at odds with one
|
||||
another. To attempt to solve both use cases in one go we define a target
|
||||
that (ab)uses the `crt-static` target feature to indicate which one you're
|
||||
in.
|
||||
### No interop with C required
|
||||
By default the `crt-static` target feature is enabled, and when enabled
|
||||
this means that the bundled version of `libc.a` found in `liblibc.rlib`
|
||||
is used. This isn't intended really for interoperation with a C because it
|
||||
may be the case that Rust's bundled C library is incompatible with a
|
||||
foreign-compiled C library. In this use case, though, we use `rust-lld` and
|
||||
some copied crt startup object files to ensure that you can download the
|
||||
wasi target for Rust and you're off to the races, no further configuration
|
||||
necessary.
|
||||
All in all, by default, no external dependencies are required. You can
|
||||
compile `wasm32-wasi-preview1-threads` binaries straight out of the box. You can't, however,
|
||||
reliably interoperate with C code in this mode (yet).
|
||||
### Interop with C required
|
||||
For the second goal we repurpose the `target-feature` flag, meaning that
|
||||
you'll need to do a few things to have C/Rust code interoperate.
|
||||
1. All Rust code needs to be compiled with `-C target-feature=-crt-static`,
|
||||
indicating that the bundled C standard library in the Rust sysroot will
|
||||
not be used.
|
||||
2. If you're using rustc to build a linked artifact then you'll need to
|
||||
specify `-C linker` to a `clang` binary that supports
|
||||
`wasm32-wasi-preview1-threads` and is configured with the `wasm32-wasi-preview1-threads` sysroot. This
|
||||
will cause Rust code to be linked against the libc.a that the specified
|
||||
`clang` provides.
|
||||
3. If you're building a staticlib and integrating Rust code elsewhere, then
|
||||
compiling with `-C target-feature=-crt-static` is all you need to do.
|
||||
|
||||
All in all, by default, no external dependencies are required. You can
|
||||
compile `wasm32-wasi-preview1-threads` binaries straight out of the box. You can't, however,
|
||||
reliably interoperate with C code in this mode (yet).
|
||||
|
||||
|
||||
This target is not a stable target. This means that there are not many engines
|
||||
which implement the `wasi-threads` feature and if they do they're likely behind a
|
||||
flag, for example:
|
||||
|
||||
* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads`
|
||||
|
||||
Also note that at this time the `wasm32-wasi-preview1-threads` target assumes the
|
||||
presence of other merged wasm proposals such as (with their LLVM feature flags):
|
||||
|
||||
* [Bulk memory] - `+bulk-memory`
|
||||
* Mutable imported globals - `+mutable-globals`
|
||||
* Atomics - `+atomics`
|
||||
|
||||
[Bulk memory]: https://github.com/WebAssembly/spec/blob/main/proposals/bulk-memory-operations/Overview.md
|
||||
|
||||
LLVM 16 is required for this target. The reason is related to linker flags: prior to LLVM 16, --import-memory and --export-memory were not allowed together. The reason both are needed is an artifact of how WASI currently does things; see https://github.com/WebAssembly/WASI/issues/502 for more details.
|
||||
|
||||
The target intends to match the corresponding Clang target for its `"C"` ABI.
|
||||
|
||||
> **Note**: due to the relatively early-days nature of this target when working
|
||||
> with this target you may encounter LLVM bugs. If an assertion hit or a bug is
|
||||
> found it's recommended to open an issue either with rust-lang/rust or ideally
|
||||
> with LLVM itself.
|
||||
|
||||
## Building the target
|
||||
|
||||
Users need to install or built wasi-sdk since release 20.0
|
||||
https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-20
|
||||
and specify path to *wasi-root* `.cargo/config.toml`
|
||||
|
||||
```toml
|
||||
[target.wasm32-wasi-preview1-threads]
|
||||
wasi-root = ".../wasi-libc/sysroot"
|
||||
```
|
||||
|
||||
After that users can build this by adding it to the `target` list in
|
||||
`config.toml`, or with `-Zbuild-std`.
|
||||
|
||||
## Building Rust programs
|
||||
|
||||
Since it is Tier 3, rust doesn't ship pre-compiled artifacts for this target.
|
||||
|
||||
Specify `wasi-root` as explained in the previous section and then use the `build-std`
|
||||
nightly cargo feature to build the standard library:
|
||||
```shell
|
||||
cargo +nightly build --target=wasm32-wasi-preview1-threads -Zbuild-std
|
||||
```
|
||||
|
||||
## Cross-compilation
|
||||
|
||||
This target can be cross-compiled from any hosts.
|
||||
|
||||
## Testing
|
||||
|
||||
Currently testing is not well supported for `wasm32-wasi-preview1-threads` and the
|
||||
Rust project doesn't run any tests for this target. However the UI testsuite can be run
|
||||
manually following this instructions:
|
||||
|
||||
0. Ensure [wamr](https://github.com/bytecodealliance/wasm-micro-runtime), [wasmtime](https://github.com/bytecodealliance/wasmtime)
|
||||
or another engine that supports `wasi-threads` is installed and can be found in the `$PATH` env variable.
|
||||
1. Clone master branch.
|
||||
2. Apply such [a change](https://github.com/g0djan/rust/compare/godjan/wasi-threads...g0djan:rust:godjan/wasi-run-ui-tests?expand=1) with an engine from the step 1.
|
||||
3. Run `./x.py test --target wasm32-wasi-preview1-threads tests/ui` and save the list of failed tests.
|
||||
4. Checkout branch with your changes.
|
||||
5. Apply such [a change](https://github.com/g0djan/rust/compare/godjan/wasi-threads...g0djan:rust:godjan/wasi-run-ui-tests?expand=1) with an engine from the step 1.
|
||||
6. Run `./x.py test --target wasm32-wasi-preview1-threads tests/ui` and save the list of failed tests.
|
||||
7. For both lists of failed tests run `cat list | sort > sorted_list` and compare it with `diff sorted_list1 sorted_list2`.
|
@ -139,6 +139,7 @@
|
||||
"wasm32-unknown-emscripten",
|
||||
"wasm32-unknown-unknown",
|
||||
"wasm32-wasi",
|
||||
"wasm32-wasi-preview1-threads",
|
||||
"x86_64-apple-darwin",
|
||||
"x86_64-apple-ios",
|
||||
"x86_64-fortanix-unknown-sgx",
|
||||
|
@ -152,28 +152,30 @@
|
||||
// [r72] needs-llvm-components: webassembly
|
||||
// [r73] compile-flags:--target wasm32-wasi
|
||||
// [r73] needs-llvm-components: webassembly
|
||||
// [r74] compile-flags:--target x86_64-apple-ios
|
||||
// [r74] needs-llvm-components: x86
|
||||
// [r75] compile-flags:--target x86_64-fortanix-unknown-sgx
|
||||
// [r74] compile-flags:--target wasm32-wasi-preview1-threads
|
||||
// [r74] needs-llvm-components: webassembly
|
||||
// [r75] compile-flags:--target x86_64-apple-ios
|
||||
// [r75] needs-llvm-components: x86
|
||||
// [r76] compile-flags:--target x86_64-unknown-fuchsia
|
||||
// [r76] compile-flags:--target x86_64-fortanix-unknown-sgx
|
||||
// [r76] needs-llvm-components: x86
|
||||
// [r77] compile-flags:--target x86_64-linux-android
|
||||
// [r77] compile-flags:--target x86_64-unknown-fuchsia
|
||||
// [r77] needs-llvm-components: x86
|
||||
// [r78] compile-flags:--target x86_64-sun-solaris
|
||||
// [r78] compile-flags:--target x86_64-linux-android
|
||||
// [r78] needs-llvm-components: x86
|
||||
// [r79] compile-flags:--target x86_64-unknown-freebsd
|
||||
// [r79] compile-flags:--target x86_64-sun-solaris
|
||||
// [r79] needs-llvm-components: x86
|
||||
// [r80] compile-flags:--target x86_64-unknown-illumos
|
||||
// [r80] compile-flags:--target x86_64-unknown-freebsd
|
||||
// [r80] needs-llvm-components: x86
|
||||
// [r81] compile-flags:--target x86_64-unknown-linux-gnux32
|
||||
// [r81] compile-flags:--target x86_64-unknown-illumos
|
||||
// [r81] needs-llvm-components: x86
|
||||
// [r82] compile-flags:--target x86_64-unknown-linux-musl
|
||||
// [r82] compile-flags:--target x86_64-unknown-linux-gnux32
|
||||
// [r82] needs-llvm-components: x86
|
||||
// [r83] compile-flags:--target x86_64-unknown-netbsd
|
||||
// [r83] compile-flags:--target x86_64-unknown-linux-musl
|
||||
// [r83] needs-llvm-components: x86
|
||||
// [r84] compile-flags: --target x86_64-unknown-redox
|
||||
// [r84] compile-flags:--target x86_64-unknown-netbsd
|
||||
// [r84] needs-llvm-components: x86
|
||||
// [r85] compile-flags: --target x86_64-unknown-redox
|
||||
// [r85] needs-llvm-components: x86
|
||||
// compile-flags: -Z stack-protector=all
|
||||
// compile-flags: -C opt-level=2
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user