Repository navigation
worker-build: let explicit wasm-opt args control wasm names - #1091
Conversation
8d76709 to
7f337a8
Compare
With `strip = true`, rust-lld drops the `name` and `target_features` sections. Profiles lose function names, and wasm-bindgen fails on catch imports without `target_features`. Release and profiling builds now link via `cargo rustc` with `--keep-section` for both. `--no-preserve-wasm-names` drops names to save size.
7f337a8 to
2e5a28c
Compare
|
Thanks for looking into this one! In general I would actually advise against using Towards fixing this issue I've posted wasm-bindgen/wasm-bindgen#5382 which fixes the original issue and also emits a warning that makes it clear that strip = true is not the way. With that context, we can then reframe this PR as changing the wasm-opt options when running wasm-opt after the wasm bindgen step, and wasm-opt can then be customized for build types further as needed. Hopefully that framing helps? Happy to discuss further. |
|
Thanks @guybedford for the reply! I edited the PR to remove the link-time approach and instead decide to keep the name section during the |
guybedford
left a comment
There was a problem hiding this comment.
Thanks for reworking this, and to your question: yes, I think the profile's wasm-opt args are the right home for it rather than a new CLI flag.
Some background on how the tools interact here. Release builds already keep names today, because worker-build always appends --debuginfo to the wasm-opt invocation. So what this PR really adds is the opt-out for size, which is the legitimate reason people reach for strip = true (on examples/router it's 162KB -> 118KB).
The catch is that binaryen reads the name section into its IR as function names, and -g writes them back out at the end. --strip-debug only removes the custom section, and the IR names survive, so today this config still emits names because of the appended --debuginfo:
[package.metadata.wasm-pack.profile.release]
wasm-opt = ["-O", "--strip-debug"]If worker-build just skips --debuginfo when the profile's args contain --strip-debug, that config does what it says. Then no new flag is needed, it's set per profile in Cargo.toml right where strip = true used to live, and the --profiling check goes away. It also avoids the flag silently doing nothing whenever wasm-opt doesn't run (--dev, --no-opt, wasm-opt = false, --emscripten).
With that, the logic is just argument construction, so it can be covered by unit tests in cargo test -p worker-build, and the script and CI step can go. The READMEs would then document the profile recipe instead of the flag. The PR title and description also still describe the earlier link-time approach, so those need updating too.
| } | ||
| // Keep the Wasm names section | ||
| args.push("--debuginfo".into()); | ||
| if !self.remove_name_section { |
There was a problem hiding this comment.
Something like:
// Keep the Wasm names section unless the profile strips debug info
if !args.iter().any(|arg| arg == "--strip-debug") {
args.push("--debuginfo".into());
}Pulling the arg construction out into a small function would make it easy to unit test: the default wasm-opt = true gets --debuginfo, and ["-O", "--strip-debug"] doesn't.
| @@ -0,0 +1,81 @@ | |||
| // Checks that a Wasm module's `name` section holds function names from each given crate, or with | |||
There was a problem hiding this comment.
I'd rather not add test scripts under .github. With the profile approach the unit tests cover the behaviour worker-build owns, and what -g / --strip-debug do is binaryen's contract, so I think this script and the CI step can be dropped.
worker-build always appended `--debuginfo` to wasm-opt, so a profile with `wasm-opt = ["-O", "--strip-debug"]` still kept the `name` section. Skip `--debuginfo` when the profile strips debug info, so size-sensitive Workers can drop names without `strip = true`.
2224826 to
79f7f0e
Compare
guybedford
left a comment
There was a problem hiding this comment.
Thanks for the update, this is very close. Having looked at it again, I think matching on --strip-debug is the wrong shape, and that's on me since I suggested it last round. It means worker-build has to understand wasm-opt flags, and exact matching already misses aliases like --strip.
A simpler rule is that explicit args give the user full control over the invocation:
wasm-opt = trueresolves to-O --debuginfo, so names are kept by default.wasm-opt = [...]is passed through as written, plus only the required--enable-*features. worker-build never appends-g.
Then dropping names is just leaving out -g, which is already how binaryen behaves. --strip, --strip-debug and any future flags work with no parsing, and there's nothing for worker-build to keep in sync. Users with explicit args today would need to add -g to keep names, so that's worth a line in the PR description.
Could you also update the Leptos template while you're here? templates/leptos/Cargo.toml still has strip = true in [profile.release], which is exactly what the new README advises against, and new projects get it from cargo generate. I'd remove it so the template uses the default. Note that the profile is shared with the cargo leptos build --release client build, so it's worth checking that the client bundle size doesn't regress.
| ] { | ||
| args.push(format!("--enable-{feature}")); | ||
| } | ||
| // Keep the Wasm names section unless the profile strips debug info |
There was a problem hiding this comment.
With the explicit-args rule, this condition goes away. --debuginfo can move into the wasm-opt = true default in CargoWasmPackProfile::wasm_opt_args in manifest.rs:
CargoWasmPackProfileWasmOpt::Enabled(true) => Some(vec!["-O".to_string(), "--debuginfo".to_string()]),and this function only appends the features. The tests then cover true -> -O --debuginfo plus features, and explicit args -> passed through plus features with no --debuginfo.
|
|
||
| ```toml | ||
| [package.metadata.wasm-pack.profile.release] | ||
| wasm-opt = ["-O", "--strip-debug"] |
There was a problem hiding this comment.
With that change, the recipe here becomes "explicit wasm-opt args don't keep names unless they include -g", for example:
[package.metadata.wasm-pack.profile.release]
# names dropped
wasm-opt = ["-O"]
# names kept
# wasm-opt = ["-O", "-g"]The last sentence on line 33 also repeats the intro and can be dropped.
Matching on `--strip-debug` meant worker-build had to understand wasm-opt flags, and missed aliases like `--strip`. Instead, explicit args now give the user full control: `wasm-opt = true` resolves to `-O --debuginfo`, while `wasm-opt = [...]` is passed through as written plus only the required `--enable-*` features. Dropping names is just leaving out `-g`. Profiles with explicit args need to add `-g` to keep names. Also remove `strip = true` from the Leptos template, so new projects keep names in the Worker.
worker-build always appends
--debuginfoto the wasm-opt invocation, which keeps the Wasmnamesection so that CPU profiles and stack traces show Rust function names. That is the right default, but it leaves no working way to drop names for a size-sensitive Worker: whatever the profile's wasm-opt args say, the appended--debuginfowrites the names back out. So users reach forstrip = true, which removes every custom section at link time (see wasm-bindgen/wasm-bindgen#5382).Explicit wasm-opt args now give the user full control over the invocation:
wasm-opt = trueresolves to-O --debuginfo, so names are kept by default.wasm-opt = [...]is passed through as written, plus only the required--enable-*features. worker-build never appends-g.Dropping names is just leaving out
-g, which is how binaryen already behaves, so--strip,--strip-debugand any future flags work without worker-build parsing them. Withwasm-opt = ["-O"],examples/routergoes from 162KB to 118KB. Profiles that already set explicitwasm-optargs currently keep names only because worker-build appends--debuginfo, so they need to add-gto keep them, e.g.wasm-opt = ["-O", "-g"]. The READMEs document this in place ofstrip = true.This also removes
strip = truefrom the Leptos template, so new Leptos projects keep names in the Worker.