This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
62 lines
2.7 KiB
Rust
62 lines
2.7 KiB
Rust
//! A "bare wasm" target representing a WebAssembly output that makes zero
|
|
//! assumptions about its environment.
|
|
//!
|
|
//! The `wasm32-unknown-unknown` target is intended to encapsulate use cases
|
|
//! that do not rely on any imported functionality. The binaries generated are
|
|
//! entirely self-contained by default when using the standard library. Although
|
|
//! the standard library is available, most of it returns an error immediately
|
|
//! (e.g. trying to create a TCP stream or something like that).
|
|
//!
|
|
//! This target is more or less managed by the Rust and WebAssembly Working
|
|
//! Group nowadays at <https://github.com/rustwasm>.
|
|
|
|
use super::wasm_base;
|
|
use super::{LinkerFlavor, LldFlavor, Target};
|
|
use crate::spec::abi::Abi;
|
|
|
|
pub fn target() -> Target {
|
|
let mut options = wasm_base::options();
|
|
options.os = "unknown".to_string();
|
|
options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
|
|
|
|
// This is a default for backwards-compatibility with the original
|
|
// definition of this target oh-so-long-ago. Once the "wasm" ABI is
|
|
// stable and the wasm-bindgen project has switched to using it then there's
|
|
// no need for this and it can be removed.
|
|
//
|
|
// Currently this is the reason that this target's ABI is mismatched with
|
|
// clang's ABI. This means that, in the limit, you can't merge C and Rust
|
|
// code on this target due to this ABI mismatch.
|
|
options.default_adjusted_cabi = Some(Abi::Wasm);
|
|
|
|
let clang_args = options.pre_link_args.entry(LinkerFlavor::Gcc).or_default();
|
|
|
|
// Make sure clang uses LLD as its linker and is configured appropriately
|
|
// otherwise
|
|
clang_args.push("--target=wasm32-unknown-unknown".to_string());
|
|
|
|
// For now this target just never has an entry symbol no matter the output
|
|
// type, so unconditionally pass this.
|
|
clang_args.push("-Wl,--no-entry".to_string());
|
|
|
|
// Rust really needs a way for users to specify exports and imports in
|
|
// the source code. --export-dynamic isn't the right tool for this job,
|
|
// however it does have the side effect of automatically exporting a lot
|
|
// of symbols, which approximates what people want when compiling for
|
|
// wasm32-unknown-unknown expect, so use it for now.
|
|
clang_args.push("-Wl,--export-dynamic".to_string());
|
|
|
|
// Add the flags to wasm-ld's args too.
|
|
let lld_args = options.pre_link_args.entry(LinkerFlavor::Lld(LldFlavor::Wasm)).or_default();
|
|
lld_args.push("--no-entry".to_string());
|
|
lld_args.push("--export-dynamic".to_string());
|
|
|
|
Target {
|
|
llvm_target: "wasm32-unknown-unknown".to_string(),
|
|
pointer_width: 32,
|
|
data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
|
|
arch: "wasm32".to_string(),
|
|
options,
|
|
}
|
|
}
|