Emitting ES6 Module for `wasm32-unknown-emscripten`

I'm using wasm32-unknown-emscripten to compile some code that's being run in the browser. I want to integrate it into a standard React codebase with bundling. To do so, I want rustc to emit ESM. I know emscripten has the EXPORT_ES6 setting. Is there an equivalent for rustc?

Most people compile to wasm32-unknown-unknown and use wasm-bindgen (typically via wasm-pack) to generate the JavaScript glue code and *.d.ts files for embedding in a web app. I'd suggest having a read through of the Rust and WebAssembly book because it has a nice real-world tutorial.

Last I heard, the wasm32-unknown-emscripten backend isn't really being maintained.

1 Like

Yeah, the Emscripten backend is basically unmaintained, unsupported, and more importantly, broken in not-so-subtle ways. I'd strongly recommend against using it, because you'll likely run into blocking bugs with it.

2 Likes

Thanks for the response! Yeah I'd love to use wasm32-unknown-unknown, but it doesn't play nice compiling my C code to WASM. For full context, I'm compiling a codebase with a tree-sitter parser as a dependency. This requires compiling the parser's C code, which blows up with the following error:

  cargo:warning=In file included from src/lib.c:8:
  cargo:warning=In file included from src/./alloc.c:1:
  cargo:warning=In file included from src/alloc.h:4:
  cargo:warning=include/tree_sitter/api.h:8:10: fatal error: 'stdio.h' file not found
  cargo:warning=#include <stdio.h>
  cargo:warning=         ^~~~~~~~~
  cargo:warning=1 error generated.
  exit status: 1

Full output here.

If I had to guess, I need to link a standard library, which I've tried with wasm-stdlib-hack but that didn't work for me. I'm not an expert in C so I might have done this incorrectly though.

Truth be told, I'm a little mystified as to how emscripten gets it to work. I suppose emscripten comes with its own stdlib implementation?

Yep. Emscripten comes with its own implementation of a lot of C system libraries and I believe they use their own patched version of Clang.

1 Like

Yep, any cross-compiling toolchain has to supply its own implementation of the library, for the trivial reason that the platform it is emitting code for isn't the same as the one it is being compiled on.

wasm32-unknown-unknown is a "bare metal" target in that it provides no system libraries, just a computational model, if you wish. In case you want OS interop, you'll need to use the wasm32-wasi target, which provides the standard library. The unknown target, in contrast, can only assume that you provide any external functions.

As for interop with C: last time I checked (a couple months ago), this was simply not possible. Basically, the WASM emitted by rustc (on the two supported targets) is ABI-incompatible with emscripten-generated WASM, so most of the FFI calls will simply receive/return garbage or otherwise do the wrong thing.

As for interop with C: last time I checked (a couple months ago), this was simply not possible. Basically, the WASM emitted by rustc (on the two supported targets) is ABI-incompatible with emscripten-generated WASM, so most of the FFI calls will simply receive/return garbage or otherwise do the wrong thing.

Yeah I saw that too. Rather unfortunate. Do you think the same is true if I compile the C via Clang's WASM backend instead of via emscripten?

I'm not sure about that, but AFAIK Emscripten is already based on the Clang/LLVM ecosystem, so I would expect them to share ABIs (and thus ABI incompatibility with Rust).

The abi incompatibility is caused by rustc itself. When adding wasm support we forgot to add some code to lower the function signatures the way we have to according to the C abi for wasm. This resulted in the default LLVM lowering being used, which isn't documented afaik. Clang did add the right code, so it is abi compatible with the official C abi. Unfortunately we can't do the same as wasm-bindgen depends on the broken abi.

1 Like

The abi incompatibility is caused by rustc itself. When adding wasm support we forgot to add some code to lower the function signatures the way we have to according to the C abi for wasm. This resulted in the default LLVM lowering being used, which isn't documented afaik. Clang did add the right code, so it is abi compatible with the official C abi. Unfortunately we can't do the same as wasm-bindgen depends on the broken abi.

Darn, that's too bad. Do you have any references for this issue? Perhaps there's some way to create an alternate target? I'd love to help with this issue as it seems pretty important for making WebAssembly a true multi-language target.

Thanks for the help everyone!

Note that only wasm32-unknown-unknown uses the wrong abi. wasm32-unknown-emscripten amd wasm32-wasi both use the correct C abi.

1 Like