add wasm-bindgen support#23493
add wasm-bindgen support#23493walkingeyerobot wants to merge 82 commits intoemscripten-core:mainfrom
Conversation
Does rustc then read the wasm to find those function names, and pass those names to In general if we need to read metadata-type info from the wasm, then we have a minimal parser in tools/webassembly.py. If we need something more complex, a binaryen pass is an option. |
|
wasm-bindgen itself is two pieces: a library that allows you to annotate your rust code marking things to be exported, and a tool that consumes a .wasm file and reads those annotations to produce a companion js file. rustc knows about those function names because wasm-bindgen as a library provided the annotations. If rustc invokes the linker itself, it's able to pass that information along. However, because we need to also build C++, we're only using rustc to compile and not drive the whole process, so we need to have it output that information elsewhere. One (very naive) possibility is to have rustc invoke a fake linker that just writes the |
Export all C symbols, except perhaps those from system libraries.
Automatically infer what symbols to export for wasm-bindgen
…arget
`WorkerPool::spawn` calls `wasm_bindgen::module()` to forward the
current Wasm module handle to a newly-spawned Web Worker. That
intrinsic is only supported by wasm-bindgen-cli's OutputMode::{Web,
NoModules, Node, Module} (see `wasm-bindgen-cli-support/src/js/mod.rs`
`Intrinsic::Module`, which bails out for Bundler and Emscripten).
An emscripten fork with `-sWASM_BINDGEN` integration (e.g. the
`walkingeyerobot/emscripten` draft upstream of
emscripten-core/emscripten#23493) inserts the
`__wasm_bindgen_emscripten_marker` custom section, which forces
wasm-bindgen-cli into `OutputMode::Emscripten` unconditionally. In that
mode the `__wbindgen_module` intrinsic bails, so post-link fails with:
failed to generates bindings for import of
`__wbindgen_placeholder__::__wbg___wbindgen_module_<hash>`
This happens even when the caller never spawns a worker — the mere
reference in the dep graph is enough. Web Workers aren't usable from
the emscripten target regardless (single-threaded model), so fall back
to a null module handle when `target_os = "emscripten"`. Any runtime
call to `spawn` would have failed on that target anyway; this just
keeps the import out of the wasm so wasm-bindgen post-link can complete.
Verified on `wasm32-unknown-emscripten` with wasm-bindgen-cli 0.2.118 +
the walkingeyerobot emscripten fork: `cargo build --release --bin
nobodywho_flutter_web --target wasm32-unknown-emscripten` now produces
a ~15 MB .wasm + matching JS glue that loads and instantiates in Node.
…arget
`WorkerPool::spawn` calls `wasm_bindgen::module()` to forward the
current Wasm module handle to a newly-spawned Web Worker. That
intrinsic is only supported by wasm-bindgen-cli's OutputMode::{Web,
NoModules, Node, Module} (see `wasm-bindgen-cli-support/src/js/mod.rs`
`Intrinsic::Module`, which bails out for Bundler and Emscripten).
An emscripten fork with `-sWASM_BINDGEN` integration (e.g. the
`walkingeyerobot/emscripten` draft upstream of
emscripten-core/emscripten#23493) inserts the
`__wasm_bindgen_emscripten_marker` custom section, which forces
wasm-bindgen-cli into `OutputMode::Emscripten` unconditionally. In that
mode the `__wbindgen_module` intrinsic bails, so post-link fails with:
failed to generates bindings for import of
`__wbindgen_placeholder__::__wbg___wbindgen_module_<hash>`
This happens even when the caller never spawns a worker — the mere
reference in the dep graph is enough. Web Workers aren't usable from
the emscripten target regardless (single-threaded model), so fall back
to a null module handle when `target_os = "emscripten"`. Any runtime
call to `spawn` would have failed on that target anyway; this just
keeps the import out of the wasm so wasm-bindgen post-link can complete.
Verified on `wasm32-unknown-emscripten` with wasm-bindgen-cli 0.2.118 +
the walkingeyerobot emscripten fork: `cargo build --release --bin
nobodywho_flutter_web --target wasm32-unknown-emscripten` now produces
a ~15 MB .wasm + matching JS glue that loads and instantiates in Node.
|
I believe this is ready for review! :D |
This is an early draft PR for the purposes of gathering feedback early. There are also pending changes to wasm-bindgen.
How this works:
wasm32-unknown-emscripteninto a.afile..afile.wasm-ldto link the C++ and Rust into a.wasmfile..wasmfile, producing a new.wasmfile, alibrary.jsfile, and apre.jsfile..js, integrating the wasm-bindgen.jsfiles.You can see a demo more easily at https://github.com/walkingeyerobot/cxx-rust-demo.
library_wbg.jsandpre.jsare approximately what will be produced by wasm-bindgen for consumption by Emscripten.Some TODOs:
wasm-ldso they're not removed in the final.wasmbut that may not necessarily be present after wasm-bindgen processes the.wasm. wasm-bindgen at compile time puts the information it needs to generate JS inside the.wasmfile itself in the form of_describefunctions. These functions are then removed after JS generation..jsfiles produced by wasm-bindgen. This shouldn't be that hard; I just haven't gotten around to it yet. This would simplify the code for both Emscripten and wasm-bindgen.-unknownand-emscriptenthat I'll have to fix.I'm mostly looking for feedback on the first point about exported symbols and about the general addition of
-sWASM_BINDGENto Emscripten. Again, this is very early, but it's a pretty big feature, so I thought it best to start discussions now.cc @daxpedda, who I've been working with on the wasm-bindgen side.