Those of you following Rust’s WebAssembly support probably know that I landed a pair of PRs in the last couple weeks that added a new rustc target, wasm32-experimental-emscripten. In this post I will explain first how this target is different from the older WebAssembly rustc target, wasm32-unknown-emscripten, and second what needs to be done next to move WebAssembly support in rustc forward.
Current WebAssembly Support
Rust has supported WebAssembly for a while now through the target wasm32-unknown-emscripten. This target works by having rustc produce LLVM bitcode files from Rust source files, then passing those bitcode files to Emscripten. Emscripten links the bitcode files with libc bitcode files it has produced, compiles the resulting bitcode to WebAssembly, then adds the JavaScript glue that emulates a file system, POSIX system calls, and other functionality necessary to make the WebAssembly usable. The way Emscripten compiles the bitcode to WebAssembly is by first compiling to asm.js using the Fastcomp JSBackend, then using the asm2wasm tool to compile the asm.js to WebAssembly.
The new wasm32-experimental-emscripten target does the exact same thing as the old target, except that it tells Emscripten to use the new WebAssembly LLVM backend to compile the bitcode to WebAssembly instead of using the JSBackend and going through asm.js. This is useful because in the future the WebAssembly LLVM backend will the official, best supported, most up-to-date path from LLVM bitcode to WebAssembly. It is also a big step toward cutting Rust’s dependency on Fastcomp, which currently forces us to update Rust’s fork of LLVM in lockstep with Emscripten’s fork.
Future WebAssembly Support
Emscripten is a large dependency, and as LLVM tool support for WebAssembly matures, Emscripten will no longer be the best way to support compilation to WebAssembly. Tip of tree LLVM and lld already support emitting and linking WebAssembly object files, so my next step locally will be to create another rustc target that emits WebAssembly object files directly and invokes lld to link them. @vadimcn has been experimenting with this locally, so with luck it won’t take me too long to get this new Emscripten-free target producing #[no_std] binaries. That leaves the question of how to supply all of the runtime functionality that Emscripten provides, but the short-term plan there is to borrow as much as necessary and possible from Emscripten and figure out what is left from there.
In order to upstream these changes, a couple things will need to happen.
-
lld will need to be added to the source tree. For the foreseeable future, whatever “cc” happens to be on the host system will not be able to link WebAssembly objects, so we need to explicitly depend on the LLVM linker. I asked @alexcrichton about this and he said we would need to do some planning and preparation for this change.
-
Rust’s LLVM will need to be upgraded. The current one is too old to be able to emit WebAssembly object files. Unfortunately since WebAssembly support is a work in progress, Rust’s LLVM will not need to be updated just once, but potentially many times. One undesirable workaround would be to cherry pick all of the WebAssembly-specific changes to Rust’s fork, but otherwise we will have to do full updates. These will be tied to Emscripten’s LLVM updates as long as we still want to support asm.js and there is no wasm2asm tool. Hopefully @kripken can suggest a path forward for this.
How can we make this happen in an orderly fashion? Please discuss!