From e65a48efd9b711281c70667c5392de70a9e1f7c3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 1 Aug 2024 11:59:47 -0700 Subject: [PATCH] Document WebAssembly target feature expectations This commit is a result of the discussion on #128475 and incorporates parts of #109807 as well. This is all done as a new page of documentation for the `wasm32-unknown-unknown` target which previously did not exist. This new page goes into details about the preexisting target and additionally documents the expectations for WebAssembly features and code generation. The tl;dr is that LLVM will enable features over time after most engines have had support for awhile. Compiling without features requires `-Ctarget-cpu=mvp` to rustc plus `-Zbuild-std` to Cargo. Closes #109807 Closes #128475 --- src/doc/rustc/src/platform-support.md | 2 +- .../wasm32-unknown-unknown.md | 154 ++++++++++++++++++ .../src/platform-support/wasm32-wasip1.md | 7 + .../src/platform-support/wasm32-wasip2.md | 7 + 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index cbb338f481172..1fb7d2d150385 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -190,7 +190,7 @@ target | std | notes [`thumbv8m.main-none-eabi`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline [`thumbv8m.main-none-eabihf`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten -`wasm32-unknown-unknown` | ✓ | WebAssembly +[`wasm32-unknown-unknown`](platform-support/wasm32-unknown-unknown.md) | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename]) [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md new file mode 100644 index 0000000000000..03126eaa50cbb --- /dev/null +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md @@ -0,0 +1,154 @@ +# `wasm32-unknown-unknown` + +**Tier: 2** + +The `wasm32-unknown-unknown` target is a WebAssembly compilation target which +does not import any functions from the host for the standard library. This is +the "minimal" WebAssembly in the sense of making the fewest assumptions about +the host environment. This target is often used when compiling to the web or +JavaScript environments as there is not standard for what functions can be +imported on the web. This target can also be useful for creating minimal or +bare-bones WebAssembly binaries. + +The `wasm32-unknown-unknown` target has support for the Rust standard library +but many parts of the standard library do not work and return errors. For +example `println!` does nothing, `std::fs` always return errors, and +`std::thread::spawn` will panic. There is no means by which this can be +overridden. For a WebAssembly target that more fully supports the standard +library see the [`wasm32-wasip1`](./wasm32-wasip1.md) or +[`wasm32-wasip2`](./wasm32-wasip2.md) targets. + +The `wasm32-unknown-unknown` target has full support for the `core` and `alloc` +crates. It additionally supports the `HashMap` type in the `std` crate, although +hash maps are not randomized like they are on other platforms. + +One existing user of this target (please feel free to edit and expand this list +too) is the [`wasm-bindgen` project](https://github.com/rustwasm/wasm-bindgen) +which facilitates Rust code interoperating with JavaScript code. Note, though, +that not all uses of `wasm32-unknown-unknown` are using JavaScript and the web. + +## 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 as mentioned above many pieces of functionality that require an operating +system do not work and will return errors. + +This target currently has no equivalent in C/C++. There is no C/C++ toolchain +for this target. While interop is theoretically possible it's recommended to +instead use one of: + +* `wasm32-unknown-emscripten` - for web-based use cases the Emscripten + toolchain is typically chosen for running C/C++. +* [`wasm32-wasip1`](./wasm32-wasip1.md) - the wasi-sdk toolchain is used to + compile C/C++ on this target and can interop with Rust code. WASI works on + the web so far as there's no blocker, but an implementation of WASI APIs + must be either chosen or reimplemented. + +This target has no build requirements beyond what's in-tree in the Rust +repository. Linking binaries requires LLD to be enabled for the `wasm-ld` +driver. This target uses the `dlmalloc` crate as the default global allocator. + +## Building the target + +Building this target can be done by: + +* Configure the `wasm32-unknown-unknown` target to get built. +* Configure LLD to be built. +* Ensure the `WebAssembly` target backend is not disabled in LLVM. + +These are all controlled through `config.toml` options. It should be possible +to build this target on any platform. + +## Building Rust programs + +Rust programs can be compiled by adding this target via rustup: + +```sh +$ rustup target add wasm32-unknown-unknown +``` + +and then compiling with the target: + +```sh +$ rustc foo.rs --target wasm32-unknown-unknown +$ file foo.wasm +``` + +## Cross-compilation + +This target can be cross-compiled from any hosts. + +## Testing + +This target is not tested in CI for the rust-lang/rust repository. Many tests +must be disabled to run on this target and failures are non-obvious because +println doesn't work in the standard library. It's recommended to test the +`wasm32-wasip1` target instead for WebAssembly compatibility. + +## Conditionally compiling code + +It's recommended to conditionally compile code for this target with: + +```text +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +``` + +Note that there is no way to tell via `#[cfg]` whether code will be running on +the web or not. + +## Enabled WebAssembly features + +WebAssembly is an evolving standard which adds new features such as new +instructions over time. This target's default set of supported WebAssembly +features will additionally change over time. The `wasm32-unknown-unknown` target +inherits the default settings of LLVM which typically matches the default +settings of Emscripten as well. + +Changes to WebAssembly go through a [proposals process][proposals] but reaching +the final stage (stage 5) does not automatically mean that the feature will be +enabled in LLVM and Rust by default. At this time the general guidance is that +features must be present in most engines for a "good chunk of time" before +they're enabled in LLVM by default. There is currently not exact number of +months or engines that are required to enable features by default. + +[proposals]: https://github.com/WebAssembly/proposals + +If you're compiling WebAssembly code for an engine that does not support a +feature in LLVM's default feature set then the feature must be disabled at +compile time. Note, though, that enabled features may be used in the standard +library or precompiled libraries shipped via rustup. This means that not only +does your own code need to be compiled with the correct set of flags but the +Rust standard library additionally must be recompiled. + +Compiling all code for the initial release of WebAssembly looks like: + +```sh +$ export RUSTFLAG=-Ctarget-cpu=mvp +$ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown +``` + +Here the `mvp` "cpu" is a placeholder in LLVM for disabling all supported +features by default. Cargo's `-Zbuild-std` feature, a Nightly Rust feature, is +then used to recompile the standard library in addition to your own code. This +will produce a binary that uses only the original WebAssembly features by +default and no proposals since its inception. + +To enable individual features it can be done with `-Ctarget-feature=+foo`. +Available features can be found through: + +```sh +$ rustc -Ctarget-feature=help --target wasm32-unknown-unknown +``` + +You'll need to consult your WebAssembly engine's documentation to learn more +about the supported WebAssembly features the engine has. diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1.md b/src/doc/rustc/src/platform-support/wasm32-wasip1.md index fb70bbdc2b403..7a7cac9aeeb1e 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1.md @@ -132,3 +132,10 @@ It's recommended to conditionally compile code for this target with: Note that the `target_env = "p1"` condition first appeared in Rust 1.80. Prior to Rust 1.80 the `target_env` condition was not set. + +## Enabled WebAssembly features + +The default set of WebAssembly features enabled for compilation is currently the +same across all WebAssembly targets. For more information on WebAssembly +features see the documentation for +[`wasm32-unknown-unknokwn`](./wasm32-unknown-unknown.md) diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip2.md b/src/doc/rustc/src/platform-support/wasm32-wasip2.md index 1e53fbc178e2e..e4ef65bcfec55 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip2.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip2.md @@ -61,3 +61,10 @@ It's recommended to conditionally compile code for this target with: ```text #[cfg(all(target_os = "wasi", target_env = "p2"))] ``` + +## Enabled WebAssembly features + +The default set of WebAssembly features enabled for compilation is currently the +same across all WebAssembly targets. For more information on WebAssembly +features see the documentation for +[`wasm32-unknown-unknokwn`](./wasm32-unknown-unknown.md)