Skip to content

worker-build --emscripten - #1061

Open
guybedford wants to merge 13 commits into
mainfrom
gbedford/worker-build-emscripten
Open

worker-build --emscripten#1061
guybedford wants to merge 13 commits into
mainfrom
gbedford/worker-build-emscripten

Conversation

@guybedford

Copy link
Copy Markdown
Collaborator

This adds worker-build --emscripten, building Workers for wasm32-unknown-emscripten so crates that need a libc, epoll sockets or blocking calls (stock Tokio net, etc.) run unmodified, parking through JSPI.

  • worker-build installs the pinned emsdk release (6.0.9) into its cache directory and applies the patches under worker-build/patches/emscripten/ to the frontend: the marker-based -sWASM_BINDGEN backport (Unify wasm-bindgen output under -sWASM_BINDGEN with marker-based detection emscripten-core/emscripten#27208) and NODERAWSOCKETS DNS (Real DNS resolution for getaddrinfo under -sNODERAWSOCKETS emscripten-core/emscripten#27693). Each is dropped as the pin moves past it. EMSCRIPTEN / EMSDK env vars override for local toolchain work.
  • rustc drives emcc as the linker for a bin target (cdylib cannot link on emscripten); emcc runs wasm-bindgen post-link, and the output is collected into the standard build/index.js + wasm shape, so wrangler config only changes the build command (plus the new_module_registry compat flag for import.meta.url). Codegen and link flags go through RUSTFLAGS, as --panic-unwind does.
  • worker::init becomes a private start function (its public init export collided with Emscripten's own) and no longer registers the abort reinit hook on emscripten, where Emscripten owns instantiation.
  • Rust-side dependency patches (tokio, mio, libc, wasm-streams) stay user-side; the emscripten-tcp example documents the [patch.crates-io] block.

--release builds work with the released wasm-bindgen CLI. Debuginfo builds need a CLI with wasm-bindgen/wasm-bindgen#5328 (DWARF that survives the exnref translation) until 0.2.129; the submodule is updated to include it along with wasm-bindgen/wasm-bindgen#5332.

Tested: the emscripten-tcp example (worker types + tokio::net::TcpStream under JSPI) builds with --dev and --release and serves /?host=example.com under wrangler dev; CI adds an Emscripten example job running both builds and that smoke test. Unit tests cover the patch applier.

Build Workers for wasm32-unknown-emscripten through a worker-build
provisioned toolchain: the pinned emsdk release is installed into the
cache directory and the frontend patched with backports the Rust link
needs (marker-based -sWASM_BINDGEN, NODERAWSOCKETS DNS). rustc drives
emcc as the linker for a bin target, emcc runs wasm-bindgen post-link,
and the output is collected into the standard build/index.js shape.

The worker crate's start function becomes private, since its public
init export collided with Emscripten's own.
The exnref translation failure on debug builds was wasm-bindgen 0.2.128's
--keep-debug output (walrus 0.27.1 .debug_loc), fixed on main by #5328,
not binaryen on the linked module. The CLI floor already covers it.
The worker crate no longer registers the abort reinit hook on
wasm32-unknown-emscripten, so the released wasm-bindgen CLI builds
--emscripten --release; only debuginfo builds still need #5328. Export
and wasm import detection now handle emcc's minified release output.
The runtime serves the whole cloudflare: namespace (cloudflare:node,
cloudflare:test, ...), not only the three that were listed, and a
wasm-bindgen module import of one of them must reach the output as an
import rather than fail to resolve in esbuild.
Backport the JSPI lifecycle hooks, REENTRANT_JSPI fiber stacks and epoll
listener API to the 6.0.9 frontend, and take Binaryen from a release
carrying the jspi-hooks pass (WebAssembly/binaryen#9102). The release
sysroot stamp is dropped after patching so emcc installs the new
headers.
wasm-bindgen/wasm-bindgen#5333 instruments jspi exports and suspending
imports with emscripten's fiber hooks, so under -sREENTRANT_JSPI each
fetch activation runs on its own stack. The example takes wasm-bindgen
from the submodule until it is released.
Pass --cfg tokio_jspi_hooks so Tokio's emscripten port registers the JSPI
lifecycle hooks, and move the example to that Tokio branch. Concurrent
fetch activations each drive their own runtime.
The runtime exposes RPC on a Durable Object class only when it derives
from cloudflare:workers' DurableObject; the wasm-bindgen classes are
plain, so splice its prototype in.
On wasm32-unknown-emscripten the handler wrappers are #[wasm_bindgen(jspi)]
exports suspending on the handler future, so each activation is its own
fiber. The wrappers are left for rustc to expand: expanding both cfg
variants in the proc macro deduplicated their export descriptors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant