Rollup merge of #128511 - alexcrichton:doc-wasm-features, r=jieyouxu
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 #119811 Closes #128475
This commit is contained in:
commit
440076db48
@ -81,6 +81,7 @@
|
|||||||
- [wasm32-wasip1](platform-support/wasm32-wasip1.md)
|
- [wasm32-wasip1](platform-support/wasm32-wasip1.md)
|
||||||
- [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md)
|
- [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md)
|
||||||
- [wasm32-wasip2](platform-support/wasm32-wasip2.md)
|
- [wasm32-wasip2](platform-support/wasm32-wasip2.md)
|
||||||
|
- [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md)
|
||||||
- [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
|
- [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
|
||||||
- [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
|
- [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
|
||||||
- [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
|
- [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
|
||||||
|
@ -192,7 +192,7 @@ target | std | notes
|
|||||||
[`thumbv8m.main-none-eabi`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline
|
[`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
|
[`thumbv8m.main-none-eabihf`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline, hardfloat
|
||||||
`wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten
|
`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-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename])
|
||||||
[`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI
|
[`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
|
[`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads
|
||||||
|
198
src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
Normal file
198
src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
# `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 no 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 host.
|
||||||
|
|
||||||
|
## 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 no exact number of
|
||||||
|
months or engines that are required to enable features by default.
|
||||||
|
|
||||||
|
[proposals]: https://github.com/WebAssembly/proposals
|
||||||
|
|
||||||
|
As of the time of this writing the proposals that are enabled by default (the
|
||||||
|
`generic` CPU in LLVM terminology) are:
|
||||||
|
|
||||||
|
* `multivalue`
|
||||||
|
* `mutable-globals`
|
||||||
|
* `reference-types`
|
||||||
|
* `sign-ext`
|
||||||
|
|
||||||
|
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 RUSTFLAGS=-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 for Rust code itself are documented in the [reference] and
|
||||||
|
can also 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.
|
||||||
|
|
||||||
|
[reference]: https://doc.rust-lang.org/reference/attributes/codegen.html#wasm32-or-wasm64
|
||||||
|
|
||||||
|
Note that it is still possible for Rust crates and libraries to enable
|
||||||
|
WebAssembly features on a per-function level. This means that the build
|
||||||
|
command above may not be sufficient to disable all WebAssembly features. If the
|
||||||
|
final binary still has SIMD instructions, for example, the function in question
|
||||||
|
will need to be found and the crate in question will likely contain something
|
||||||
|
like:
|
||||||
|
|
||||||
|
```rust,ignore (not-always-compiled-to-wasm)
|
||||||
|
#[target_feature(enable = "simd128")]
|
||||||
|
fn foo() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this situation there is no compiler flag to disable emission of SIMD
|
||||||
|
instructions and the crate must instead be modified to not include this function
|
||||||
|
at compile time either by default or through a Cargo feature. For crate authors
|
||||||
|
it's recommended to avoid `#[target_feature(enable = "...")]` except where
|
||||||
|
necessary and instead use:
|
||||||
|
|
||||||
|
```rust,ignore (not-always-compiled-to-wasm)
|
||||||
|
#[cfg(target_feature = "simd128")]
|
||||||
|
fn foo() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That is to say instead of enabling target features it's recommended to
|
||||||
|
conditionally compile code instead. This is notably different to the way native
|
||||||
|
platforms such as x86\_64 work, and this is due to the fact that WebAssembly
|
||||||
|
binaries must only contain code the engine understands. Native binaries work so
|
||||||
|
long as the CPU doesn't execute unknown code dynamically at runtime.
|
@ -162,3 +162,17 @@ It's recommended to conditionally compile code for this target with:
|
|||||||
Prior to Rust 1.80 the `target_env = "p1"` key was not set. Currently the
|
Prior to Rust 1.80 the `target_env = "p1"` key was not set. Currently the
|
||||||
`target_feature = "atomics"` is Nightly-only. Note that the precise `#[cfg]`
|
`target_feature = "atomics"` is Nightly-only. Note that the precise `#[cfg]`
|
||||||
necessary to detect this target may change as the target becomes more stable.
|
necessary to detect this target may change as the target becomes more stable.
|
||||||
|
|
||||||
|
## Enabled WebAssembly features
|
||||||
|
|
||||||
|
The default set of WebAssembly features enabled for compilation includes two
|
||||||
|
more features in addition to that which
|
||||||
|
[`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md) enables:
|
||||||
|
|
||||||
|
* `bulk-memory`
|
||||||
|
* `atomics`
|
||||||
|
|
||||||
|
For more information about features see the documentation for
|
||||||
|
[`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md), but note that the
|
||||||
|
`mvp` CPU in LLVM does not support this target as it's required that
|
||||||
|
`bulk-memory`, `atomics`, and `mutable-globals` are all enabled.
|
||||||
|
@ -132,3 +132,9 @@ 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
|
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.
|
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 as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the
|
||||||
|
documentation there for more information.
|
||||||
|
@ -61,3 +61,9 @@ It's recommended to conditionally compile code for this target with:
|
|||||||
```text
|
```text
|
||||||
#[cfg(all(target_os = "wasi", target_env = "p2"))]
|
#[cfg(all(target_os = "wasi", target_env = "p2"))]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Enabled WebAssembly features
|
||||||
|
|
||||||
|
The default set of WebAssembly features enabled for compilation is currently the
|
||||||
|
same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the
|
||||||
|
documentation there for more information.
|
||||||
|
Loading…
Reference in New Issue
Block a user