Fixing Rust's WebAssembly Targets

Currently the Rust WebAssembly ecosystem is a rather fractured. We have three WebAssembly targets: wasm32-unknown-unknown, wasm32-unknown-emscripten, wasm32-wasi.

Going down the list, wasm32-unknown-unknown is the best supported by tooling. It has wasm-bindgen and wasm-pack, and can be used to build Wasm programs that run in the browser with relative ease. However, it has an ABI incompatibility with C compiled to WebAssembly.. This effectively limits the target to pure Rust codebases, which is rather unfortunate.

Next, wasm32-unknown-emscripten seems to work well, but is not well maintained and emits outdated JavaScript. The general sentiment seems to be that it is a legacy target, since emscripten has been superseded by a direct LLVM target.

Finally, there's wasm32-wasi. This target does not have the ABI incompatibility. However, it also does not work with wasm-bindgen or wasm-pack. Furthermore, it uses WASI, which means that to run a program in the browser, you need a WASI implementation, such as wasmer-js. These implementations are not very mature and in my view, should not be required to run a program.

In summary, the Rust WebAssembly targets all have significant issues. I'd like to propose a couple ideas for solving these issues:

  • Fix the wasm32-unknown-unknown ABI incompatibility. It seems that this is blocked on updating wasm-bindgen. If it's possible to update wasm-bindgen and fix this ABI incompatibility without breaking anything, then I'd say this is the best option.
  • Introduce a wasm32-unknown-browser target. If we cannot fix the ABI incompatibility, I would choose this as the second option. Perhaps this would be too specialized, but it would be nice to have a target that is expected to be executable in the browser without any special functionality.

Basically, I want to run my Rust + C codebase in the browser without tearing my hair out. Currently that's not possible.

wasm isn't an app it's a library. You will always need something more.
wasm32-unknown-unknown already fills the role of in the browser. If you don't want wasm-bindgen you can write your own javascript. It has the property of not requiring any import functions.

All of std rust isn't supported by wasm32-unknown-unknown (io, println in particular) the same holds for c. The general intent is that you will write code in Rust and only use c of existing libraries. But the c libraries mostly have the same problem that they use io.

For the trivial c code you link, your free to contribute a fix. There is no internal ABI for (or baring) rust + c being used together just a lack of manpower.

It sounds like you want a VM in browser rather than bespoke code. emscripten is the closest but even that requires code modifications beyond the trivial cases.

Thanks for the response. There are plenty of C libraries that don't use IO that would be feasible to run in WebAssembly if it were not for this ABI incompatibility. This isn't like std Rust where you can build a program with std, even if it may not run as you wish. This incompatibility means that even building Rust with C is not always feasible.

I don't want a VM in the browser and I'm not sure where I said this. In fact something like wasm32-wasi is effectively a VM. What I want is a target that is barebones enough to run in the browser without a polyfill. Basically I want wasm32-unknown-unknown but that works with C.

As for contributing, it appears that it's a question of appetite and standardization. The actual work seems fairly trivial (flipping a few configs). I'd love to contribute to this process. Part of the reason I made this post was to see if someone could point me in a direction on how to get this accomplished.

Have you seen Tracking issue for the unstable "wasm" ABI · Issue #83788 · rust-lang/rust · GitHub?

From my viewpoint (without reading too much, so maybe said elsewhere;) the developers created technical debt in allowing extern "C" {} to be used to define(/map) wasm imported function. A possible fix without massive breakage (IMO) have this block still as wasm import but also C linkage compatible and add another for wasm api exclusive.

General lang contributing (Not something I've done.) I know there are also teams too for wasm (and other areas.)

Yeah I've looked at that. Doesn't seem to be much movement there. I'm not even sure what the next steps are supposed to be. A joint meeting with the clang people to determine an ABI specification? I'd love to figure this out.

1 Like

That is literally what Tracking issue for the unstable "wasm" ABI · Issue #83788 · rust-lang/rust · GitHub linked by @cole-miller is about. It is still a massive breaking change as wasm-bindgen breaks, but it may be possible to first introduce extern "wasm", then switch wasm-bindgen and a couple of years later make rustc use the correct C abi for extern "C".

1 Like

There is already a C abi specified: tool-conventions/ at main · WebAssembly/tool-conventions · GitHub The issue is that switching to it breaks wasm-bindgen and thus can't be done until wasm-bindgen is no longer broken by it.

Perhaps I'm misinterpreting that thread, but it appears from what Alex is saying that there isn't a set in stone ABI that clang has actually agreed to:

Personally I think this is more of a "what is C going to do" problem for stabilization. I don't think Rust is in the position to blaze a trail here when C/C++ otherwise can't access it. One of the main purposes of this ABI is to give access to the ability to define a multi-return function in WebAssembly, but C/C++ have no corresponding mechanism to do that. Until C/C++ figure out how they're going to return multiple values then multi-return is unlikely to be used in the wasm ecosystem so stabilizing this wouldn't provide much benefit. Additionally if this were stabilized and then C/C++ picked a different way to use multi-return then that would be yet-another ABI that Rust would have to implement.

Basically, if I understand correctly, we have this ABI, but there hasn't been a buy-in as to it actually being a standard that both clang and Rust agree to adopt. The blocker is not necessarily wasm-bindgen, as Alex expresses that he is willing to change wasm-bindgen to use a wasm ABI and not a C ABI.