diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index ead3be7fd529b..78de37fc8a05f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1574,6 +1574,7 @@ supported_targets! { ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), ("wasm32-unknown-unknown", wasm32_unknown_unknown), ("wasm32-wasi", wasm32_wasi), + ("wasm32-wasi-preview1", wasm32_wasi_preview1), ("wasm32-wasi-preview2", wasm32_wasi_preview2), ("wasm32-wasi-preview1-threads", wasm32_wasi_preview1_threads), ("wasm64-unknown-unknown", wasm64_unknown_unknown), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasi.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasi.rs index 6dbcb01ea4360..575fb64942716 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasi.rs @@ -1,119 +1,11 @@ -//! The `wasm32-wasi` target is a new and still (as of April 2019) an -//! experimental target. The definition in this file is likely to be tweaked -//! over time and shouldn't be relied on too much. +//! NB: This target is in the process of being renamed to +//! `wasm32-wasi-preview1`. For more information see: //! -//! The `wasi` 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 -//! filesystem access, network access, etc. -//! -//! You can see more about the proposal at . -//! -//! 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 -//! 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` 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` 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` and is configured with the `wasm32-wasi` 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` 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! +//! * https://github.com/rust-lang/compiler-team/issues/607 +//! * https://github.com/rust-lang/compiler-team/issues/695 -use crate::spec::crt_objects; -use crate::spec::LinkSelfContainedDefault; -use crate::spec::{base, Cc, LinkerFlavor, Target}; +use crate::spec::Target; pub fn target() -> Target { - let mut options = base::wasm::options(); - - options.os = "wasi".into(); - options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), &["--target=wasm32-wasi"]); - - 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(); - - 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, - } + super::wasm32_wasi_preview1::target() } diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1.rs new file mode 100644 index 0000000000000..ffc45a9fd9bfc --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1.rs @@ -0,0 +1,57 @@ +//! The `wasm32-wasi-preview1` enables compiling to WebAssembly using the first +//! version of the WASI standard, called "preview1". This version of the +//! standard was never formally specified and WASI has since evolved to a +//! "preview2". This target in rustc uses the previous version of the proposal. +//! +//! This target uses the syscalls defined at +//! . +//! +//! Note that this target was historically called `wasm32-wasi` originally and +//! was since renamed to `wasm32-wasi-preview1` after the preview2 target was +//! introduced. + +use crate::spec::crt_objects; +use crate::spec::LinkSelfContainedDefault; +use crate::spec::{base, Cc, LinkerFlavor, Target}; + +pub fn target() -> Target { + let mut options = base::wasm::options(); + + options.os = "wasi".into(); + options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), &["--target=wasm32-wasi"]); + + 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(); + + 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, + } +} diff --git a/config.example.toml b/config.example.toml index a5ef4022d39d5..5a0d963690f2b 100644 --- a/config.example.toml +++ b/config.example.toml @@ -816,9 +816,9 @@ # The full path to the musl libdir. #musl-libdir = musl-root/lib -# The root location of the `wasm32-wasi` sysroot. Only used for the -# `wasm32-wasi` target. If you are building wasm32-wasi target, make sure to -# create a `[target.wasm32-wasi]` section and move this field there. +# The root location of the `wasm32-wasi-preview1` sysroot. Only used for WASI +# related targets. Make sure to create a `[target.wasm32-wasi-preview1]` +# section and move this field there (or equivalent for the target being built). #wasi-root = (path) # Used in testing for configuring where the QEMU images are located, you diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 5f1fec74bed54..76b20c71cb2f6 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -112,6 +112,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 ENV TARGETS=$TARGETS,wasm32-wasi-preview1-threads ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,x86_64-pc-solaris @@ -135,7 +136,8 @@ ENV TARGETS=$TARGETS,x86_64-unknown-uefi RUN ln -s /usr/include/x86_64-linux-gnu/asm /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.wasi-root=/wasm32-wasi-preview1 \ + --set target.wasm32-wasi-preview1.wasi-root=/wasm32-wasi-preview1 \ --set target.wasm32-wasi-preview1-threads.wasi-root=/wasm32-wasi-preview1-threads \ --musl-root-armv7=/musl-armv7 diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh index 4b0d360686f12..45cce1d8b5279 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh @@ -15,7 +15,7 @@ make -j$(nproc) \ CC="$bin/clang" \ NM="$bin/llvm-nm" \ AR="$bin/llvm-ar" \ - INSTALL_DIR=/wasm32-wasi \ + INSTALL_DIR=/wasm32-wasi-preview1 \ install cd .. diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index fb751b7229eb4..da3562010553b 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -190,7 +190,8 @@ target | std | notes [`thumbv8m.main-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | WebAssembly -`wasm32-wasi` | ✓ | WebAssembly with WASI +`wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename][wasi-rename]) +[`wasm32-wasi-preview1`](platform-support/wasm32-wasi-preview1.md) | ✓ | WebAssembly with WASI [`wasm32-wasi-preview1-threads`](platform-support/wasm32-wasi-preview1-threads.md) | ✓ | | WebAssembly with WASI Preview 1 and threads `x86_64-apple-ios` | ✓ | 64-bit x86 iOS [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX @@ -204,6 +205,7 @@ target | std | notes [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | * | 64-bit UEFI [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue]. +[wasi-rename]: https://github.com/rust-lang/compiler-team/issues/607 [Fortanix ABI]: https://edp.fortanix.com/ diff --git a/src/doc/rustc/src/platform-support/wasm32-wasi-preview1.md b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1.md new file mode 100644 index 0000000000000..ec1578453349c --- /dev/null +++ b/src/doc/rustc/src/platform-support/wasm32-wasi-preview1.md @@ -0,0 +1,119 @@ +# `wasm32-wasi-preview1` + +**Tier: 2** + +The `wasm32-wasi-preview1` target is a WebAssembly compilation target which +assumes that the [WASI Preview1] set of "syscalls" are available for use in the +standard library. Historically this target in the Rust compiler was one of the +first for WebAssembly where Rust and C code are explicitly intended to +interoperate as well. + +There's a bit of history to the target and current development which is also +worth explaining before going much further. Historically this target was +originally called `wasm32-wasi` in both rustc and Clang. This was first added +to Rust in 2019. In the intervening years leading up to 2024 the WASI standard +continued to be developed and was eventually "rebased" on top of the [Component +Model]. This was a large change to the WASI specification and was released as +0.2.0 ("preview 2" colloquially) in January 2024. The previous target's name in +rustc, `wasm32-wasi`, was then renamed to `wasm32-wasi-preview1`, to avoid +confusion with this new target to be added to rustc as `wasm32-wasi-preview2`. +Some more context can be found in these MCPs: + +* [Rename wasm32-wasi target to wasm32-wasi-preview1](https://github.com/rust-lang/compiler-team/issues/607) +* [Smooth the renaming transition of wasm32-wasi](https://github.com/rust-lang/compiler-team/issues/695) + +At this point the `wasm32-wasi-preview1` target is intended for historical +compatibility with the first version of the WASI standard. As of now (January +2024) the 0.2.0 target of WASI ("preview2") is relatively new. The state of +WASI will likely change in few years after which point this documentation will +probably receive another update. + +[WASI Preview1]: https://github.com/WebAssembly/WASI/tree/main/legacy/preview1 +[Component Model]: https://github.com/webassembly/component-model + +Today the `wasm32-wasi-preview1` target will generate core WebAssembly modules +which will import functions from the `wasi_snapshot_preview1` module for +OS-related functionality (e.g. printing). + +## Target maintainers + +When this target was added to the compiler platform-specific documentation here +was not maintained at that time. This means that the list below is not +exhaustive and there are more interested parties in this target. That being +said since when this document was last updated those interested in maintaining +this target are: + +- Alex Crichton, https://github.com/alexcrichton + +## Requirements + +This target is cross-compiled. The target includes support for `std` itself, +but not all of the standard library works. For example spawning a thread will +always return an error (see the `wasm32-wasi-preview1-threads` target for +example). Another example is that spawning a process will always return an +error. Operations such as opening a file, however, will be implemented by +calling WASI-defined APIs. + +The WASI targets for Rust are explicitly intended to interoperate with other +languages compiled to WebAssembly, for example C/C++. Any ABI differences or +mismatches are considered bugs that need to be fixed. + +By default the WASI targets in Rust ship in rustup with a precompiled copy of +[`wasi-libc`] meaning that a WebAssembly-targetting-Clang is not required to +use the WASI targets from Rust. If there is no actual interoperation with C +then `rustup target add wasm32-wasi` is all that's needed to get started with +WASI. + +Note that this behavior can be controlled with `-Clinker` and +`-Clink-self-contained`, however. By specifying `clang` as a linker and +disabling the `link-self-contained` option an external version of `libc.a` can +be used instead. + +[`wasi-libc`]: https://github.com/WebAssembly/wasi-libc + +## Building the target + +To build this target a compiled version of [`wasi-libc`] is required to be +present at build time. This can be installed through +[`wasi-sdk`](https://github.com/WebAssembly/wasi-sdk) as well. This is the +configured with: + +```toml +[target.wasm32-wasi-preview1] +wasi-root = ".../wasi-libc/sysroot" +``` + +Additionally users will need to enable LLD when building Rust from source as +LLVM's `wasm-ld` driver for LLD is required when linking WebAssembly code +together. + +## Building Rust programs + +The `wasm32-wasi-preview1` target is shipped with rustup so users can install +the target with: + +```text +rustup target add wasm32-wasi-preview1 +``` + +> **Note**: the `wasm32-wasi-preview1` target is new and may only be available +> on nightly by the time you're reading this. If `wasm32-wasi-preview` isn't +> available on stable Rust then `wasm32-wasi` should be available instead. + +Rust programs can be built for that target: + +```text +rustc --target wasm32-wasi-preview1 your-code.rs +``` + +## Cross-compilation + +This target can be cross-compiled from any hosts. + +## Testing + +Currently the WASI target is not tested in rust-lang/rust CI. This means that +tests in the repository are not guaranteed to pass. This is theoretically +possibly by installing a standalone WebAssembly runtime and using it as a +"runner" for all tests, but there are various failures that will need to be +waded through to adjust tests to work on the WASI target. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 1ef8cf7de3cd5..2f19cbf8c89b6 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -145,6 +145,7 @@ static TARGETS: &[&str] = &[ "wasm32-unknown-emscripten", "wasm32-unknown-unknown", "wasm32-wasi", + "wasm32-wasi-preview1", "wasm32-wasi-preview1-threads", "x86_64-apple-darwin", "x86_64-apple-ios", diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c859e8acadebd..2af43ef9b5173 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -526,6 +526,10 @@ fn wasm_special() { ("wasm32-wasi", "wasm32", true), ("wasm32-wasi", "wasm32-bare", false), ("wasm32-wasi", "wasi", true), + ("wasm32-wasi-preview1", "emscripten", false), + ("wasm32-wasi-preview1", "wasm32", true), + ("wasm32-wasi-preview1", "wasm32-bare", false), + ("wasm32-wasi-preview1", "wasi", true), ("wasm64-unknown-unknown", "emscripten", false), ("wasm64-unknown-unknown", "wasm32", false), ("wasm64-unknown-unknown", "wasm32-bare", false), diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs index 6d87fd1912b09..d14bdf387bf28 100644 --- a/tests/assembly/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly/stack-protector/stack-protector-target-support.rs @@ -149,7 +149,7 @@ // [r71] needs-llvm-components: webassembly // [r72] compile-flags:--target wasm32-unknown-unknown // [r72] needs-llvm-components: webassembly -// [r73] compile-flags:--target wasm32-wasi +// [r73] compile-flags:--target wasm32-wasi-preview1 // [r73] needs-llvm-components: webassembly // [r74] compile-flags:--target wasm32-wasi-preview1-threads // [r74] needs-llvm-components: webassembly @@ -179,7 +179,6 @@ // compile-flags: -C opt-level=2 #![crate_type = "lib"] - #![feature(no_core, lang_items)] #![crate_type = "lib"] #![no_core] diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index dee0fa9f4a410..bd168f2a3172a 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -483,6 +483,9 @@ // revisions: wasm32_wasi // [wasm32_wasi] compile-flags: --target wasm32-wasi // [wasm32_wasi] needs-llvm-components: webassembly +// revisions: wasm32_wasi_preview1 +// [wasm32_wasi_preview1] compile-flags: --target wasm32-wasi-preview1 +// [wasm32_wasi_preview1] needs-llvm-components: webassembly // revisions: wasm32_wasi_preview1_threads // [wasm32_wasi_preview1_threads] compile-flags: --target wasm32-wasi-preview1-threads // [wasm32_wasi_preview1_threads] needs-llvm-components: webassembly diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index c6bba7186da71..56c770e566617 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -44,7 +44,7 @@ //[wasm] compile-flags: --target wasm32-unknown-unknown //[wasm] needs-llvm-components: webassembly // revisions: wasi -//[wasi] compile-flags: --target wasm32-wasi +//[wasi] compile-flags: --target wasm32-wasi-preview1 //[wasi] needs-llvm-components: webassembly // revisions: bpf //[bpf] compile-flags: --target bpfeb-unknown-none