|
| 1 | +# `wasm32-unknown-unknown` |
| 2 | + |
| 3 | +**Tier: 2** |
| 4 | + |
| 5 | +The `wasm32-unknown-unknown` target is a WebAssembly compilation target which |
| 6 | +does not import any functions from the host for the standard library. This is |
| 7 | +the "minimal" WebAssembly in the sense of making the fewest assumptions about |
| 8 | +the host environment. This target is often used when compiling to the web or |
| 9 | +JavaScript environments as there is no standard for what functions can be |
| 10 | +imported on the web. This target can also be useful for creating minimal or |
| 11 | +bare-bones WebAssembly binaries. |
| 12 | + |
| 13 | +The `wasm32-unknown-unknown` target has support for the Rust standard library |
| 14 | +but many parts of the standard library do not work and return errors. For |
| 15 | +example `println!` does nothing, `std::fs` always return errors, and |
| 16 | +`std::thread::spawn` will panic. There is no means by which this can be |
| 17 | +overridden. For a WebAssembly target that more fully supports the standard |
| 18 | +library see the [`wasm32-wasip1`](./wasm32-wasip1.md) or |
| 19 | +[`wasm32-wasip2`](./wasm32-wasip2.md) targets. |
| 20 | + |
| 21 | +The `wasm32-unknown-unknown` target has full support for the `core` and `alloc` |
| 22 | +crates. It additionally supports the `HashMap` type in the `std` crate, although |
| 23 | +hash maps are not randomized like they are on other platforms. |
| 24 | + |
| 25 | +One existing user of this target (please feel free to edit and expand this list |
| 26 | +too) is the [`wasm-bindgen` project](https://github.com/rustwasm/wasm-bindgen) |
| 27 | +which facilitates Rust code interoperating with JavaScript code. Note, though, |
| 28 | +that not all uses of `wasm32-unknown-unknown` are using JavaScript and the web. |
| 29 | + |
| 30 | +## Target maintainers |
| 31 | + |
| 32 | +When this target was added to the compiler platform-specific documentation here |
| 33 | +was not maintained at that time. This means that the list below is not |
| 34 | +exhaustive and there are more interested parties in this target. That being |
| 35 | +said since when this document was last updated those interested in maintaining |
| 36 | +this target are: |
| 37 | + |
| 38 | +- Alex Crichton, https://github.com/alexcrichton |
| 39 | + |
| 40 | +## Requirements |
| 41 | + |
| 42 | +This target is cross-compiled. The target includes support for `std` itself, |
| 43 | +but as mentioned above many pieces of functionality that require an operating |
| 44 | +system do not work and will return errors. |
| 45 | + |
| 46 | +This target currently has no equivalent in C/C++. There is no C/C++ toolchain |
| 47 | +for this target. While interop is theoretically possible it's recommended to |
| 48 | +instead use one of: |
| 49 | + |
| 50 | +* `wasm32-unknown-emscripten` - for web-based use cases the Emscripten |
| 51 | + toolchain is typically chosen for running C/C++. |
| 52 | +* [`wasm32-wasip1`](./wasm32-wasip1.md) - the wasi-sdk toolchain is used to |
| 53 | + compile C/C++ on this target and can interop with Rust code. WASI works on |
| 54 | + the web so far as there's no blocker, but an implementation of WASI APIs |
| 55 | + must be either chosen or reimplemented. |
| 56 | + |
| 57 | +This target has no build requirements beyond what's in-tree in the Rust |
| 58 | +repository. Linking binaries requires LLD to be enabled for the `wasm-ld` |
| 59 | +driver. This target uses the `dlmalloc` crate as the default global allocator. |
| 60 | + |
| 61 | +## Building the target |
| 62 | + |
| 63 | +Building this target can be done by: |
| 64 | + |
| 65 | +* Configure the `wasm32-unknown-unknown` target to get built. |
| 66 | +* Configure LLD to be built. |
| 67 | +* Ensure the `WebAssembly` target backend is not disabled in LLVM. |
| 68 | + |
| 69 | +These are all controlled through `config.toml` options. It should be possible |
| 70 | +to build this target on any platform. |
| 71 | + |
| 72 | +## Building Rust programs |
| 73 | + |
| 74 | +Rust programs can be compiled by adding this target via rustup: |
| 75 | + |
| 76 | +```sh |
| 77 | +$ rustup target add wasm32-unknown-unknown |
| 78 | +``` |
| 79 | + |
| 80 | +and then compiling with the target: |
| 81 | + |
| 82 | +```sh |
| 83 | +$ rustc foo.rs --target wasm32-unknown-unknown |
| 84 | +$ file foo.wasm |
| 85 | +``` |
| 86 | + |
| 87 | +## Cross-compilation |
| 88 | + |
| 89 | +This target can be cross-compiled from any host. |
| 90 | + |
| 91 | +## Testing |
| 92 | + |
| 93 | +This target is not tested in CI for the rust-lang/rust repository. Many tests |
| 94 | +must be disabled to run on this target and failures are non-obvious because |
| 95 | +`println!` doesn't work in the standard library. It's recommended to test the |
| 96 | +`wasm32-wasip1` target instead for WebAssembly compatibility. |
| 97 | + |
| 98 | +## Conditionally compiling code |
| 99 | + |
| 100 | +It's recommended to conditionally compile code for this target with: |
| 101 | + |
| 102 | +```text |
| 103 | +#[cfg(all(target_family = "wasm", target_os = "unknown"))] |
| 104 | +``` |
| 105 | + |
| 106 | +Note that there is no way to tell via `#[cfg]` whether code will be running on |
| 107 | +the web or not. |
| 108 | + |
| 109 | +## Enabled WebAssembly features |
| 110 | + |
| 111 | +WebAssembly is an evolving standard which adds new features such as new |
| 112 | +instructions over time. This target's default set of supported WebAssembly |
| 113 | +features will additionally change over time. The `wasm32-unknown-unknown` target |
| 114 | +inherits the default settings of LLVM which typically matches the default |
| 115 | +settings of Emscripten as well. |
| 116 | + |
| 117 | +Changes to WebAssembly go through a [proposals process][proposals] but reaching |
| 118 | +the final stage (stage 5) does not automatically mean that the feature will be |
| 119 | +enabled in LLVM and Rust by default. At this time the general guidance is that |
| 120 | +features must be present in most engines for a "good chunk of time" before |
| 121 | +they're enabled in LLVM by default. There is currently no exact number of |
| 122 | +months or engines that are required to enable features by default. |
| 123 | + |
| 124 | +[proposals]: https://github.com/WebAssembly/proposals |
| 125 | + |
| 126 | +As of the time of this writing the proposals that are enabled by default (the |
| 127 | +`generic` CPU in LLVM terminology) are: |
| 128 | + |
| 129 | +* `multivalue` |
| 130 | +* `mutable-globals` |
| 131 | +* `reference-types` |
| 132 | +* `sign-ext` |
| 133 | + |
| 134 | +If you're compiling WebAssembly code for an engine that does not support a |
| 135 | +feature in LLVM's default feature set then the feature must be disabled at |
| 136 | +compile time. Note, though, that enabled features may be used in the standard |
| 137 | +library or precompiled libraries shipped via rustup. This means that not only |
| 138 | +does your own code need to be compiled with the correct set of flags but the |
| 139 | +Rust standard library additionally must be recompiled. |
| 140 | + |
| 141 | +Compiling all code for the initial release of WebAssembly looks like: |
| 142 | + |
| 143 | +```sh |
| 144 | +$ export RUSTFLAGS=-Ctarget-cpu=mvp |
| 145 | +$ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown |
| 146 | +``` |
| 147 | + |
| 148 | +Here the `mvp` "cpu" is a placeholder in LLVM for disabling all supported |
| 149 | +features by default. Cargo's `-Zbuild-std` feature, a Nightly Rust feature, is |
| 150 | +then used to recompile the standard library in addition to your own code. This |
| 151 | +will produce a binary that uses only the original WebAssembly features by |
| 152 | +default and no proposals since its inception. |
| 153 | + |
| 154 | +To enable individual features it can be done with `-Ctarget-feature=+foo`. |
| 155 | +Available features for Rust code itself are documented in the [reference] and |
| 156 | +can also be found through: |
| 157 | + |
| 158 | +```sh |
| 159 | +$ rustc -Ctarget-feature=help --target wasm32-unknown-unknown |
| 160 | +``` |
| 161 | + |
| 162 | +You'll need to consult your WebAssembly engine's documentation to learn more |
| 163 | +about the supported WebAssembly features the engine has. |
| 164 | + |
| 165 | +[reference]: https://doc.rust-lang.org/reference/attributes/codegen.html#wasm32-or-wasm64 |
| 166 | + |
| 167 | +Note that it is still possible for Rust crates and libraries to enable |
| 168 | +WebAssembly features on a per-function level. This means that the build |
| 169 | +command above may not be sufficient to disable all WebAssembly features. If the |
| 170 | +final binary still has SIMD instructions, for example, the function in question |
| 171 | +will need to be found and the crate in question will likely contain something |
| 172 | +like: |
| 173 | + |
| 174 | +```rust,ignore (not-always-compiled-to-wasm) |
| 175 | +#[target_feature(enable = "simd128")] |
| 176 | +fn foo() { |
| 177 | + // ... |
| 178 | +} |
| 179 | +``` |
| 180 | + |
| 181 | +In this situation there is no compiler flag to disable emission of SIMD |
| 182 | +instructions and the crate must instead be modified to not include this function |
| 183 | +at compile time either by default or through a Cargo feature. For crate authors |
| 184 | +it's recommended to avoid `#[target_feature(enable = "...")]` except where |
| 185 | +necessary and instead use: |
| 186 | + |
| 187 | +```rust,ignore (not-always-compiled-to-wasm) |
| 188 | +#[cfg(target_feature = "simd128")] |
| 189 | +fn foo() { |
| 190 | + // ... |
| 191 | +} |
| 192 | +``` |
| 193 | + |
| 194 | +That is to say instead of enabling target features it's recommended to |
| 195 | +conditionally compile code instead. This is notably different to the way native |
| 196 | +platforms such as x86\_64 work, and this is due to the fact that WebAssembly |
| 197 | +binaries must only contain code the engine understands. Native binaries work so |
| 198 | +long as the CPU doesn't execute unknown code dynamically at runtime. |
0 commit comments