Conversation
44c1fe0 to
2b701d6
Compare
0d4f858 to
502cbd5
Compare
3a49676 to
a34257b
Compare
Replace the `web` Cargo feature with target-based detection using a new `wasm32-unknown-js-web` custom target spec with `"os": "web"`. The `web` cfg_alias in all build.rs files now checks `target_os = "web"` instead of `feature = "web"`, so zero Rust source files need changes. - Create wasm32-unknown-js-web.json target spec with threading support, shared-memory link args, and `"os": "web"` for cfg detection - Update web/.cargo/config.toml to use the new target with json-target-spec - Change the `web` cfg_alias in 9 build.rs files from `all(target_arch = "wasm32", feature = "web")` to `target_os = "web"` - Remove `web` feature from 8 crate Cargo.toml files, moving web-only dependencies to `[target.'cfg(target_os = "web")'.dependencies]` sections - Remove `"web"` feature references from web/@linera/client/Cargo.toml - Remove wasm32-unknown-unknown from web/rust-toolchain.toml targets
Follow-up fixes to the custom web target:
- Rename wasm32-unknown-js-web → wasm32-web-unknown so that
target-lexicon (used by wasmer/cranelift) can parse the target name.
target-lexicon has no custom OS support, so "web" goes in the vendor
position.
- Use "env": "web" + "os": "unknown" in the target spec instead of
"os": "web". std has no platform implementation for target_os="web"
and fails to compile with build-std.
- Switch all build.rs aliases and Cargo.toml target sections from
target_os = "web" to target_env = "web" accordingly.
- Add -Zunstable-options to web rustflags (required by rustc to load
custom target specs).
- Remove explicit --target from build.bash; let web/.cargo/config.toml
handle it.
KNOWN BLOCKER: The web build still fails because wasmer-types v4.4.0
(upstream, depended on by linera-wasmer) cannot compile when using ANY
custom target with build-std. This is a cargo bug where build-std
dependency resolution for custom targets causes indexmap v2.x (from
std's deps) to shadow indexmap v1.x (used by wasmer-types), resulting
in generic arity mismatches. The same wasmer-types code compiles fine
for the built-in wasm32-unknown-unknown target with identical flags.
Possible workarounds:
- Use wasm32-unknown-unknown as target + env var/rustflag for web
detection (avoids build-std custom target bug entirely)
- Patch/fork wasmer-types to use indexmap 2.x
- File a cargo bug report for build-std + custom target dep resolution
Point wasmer git deps to wasmer-types-indexmap2 branch, which includes wasmer-types as a workspace member with indexmap 2 (fixing build-std conflicts with the custom wasm32-web-unknown target). Enable dynamic-linking in the target spec so cdylib crate type is supported.
502cbd5 to
cf2df1b
Compare
| ruzstd.workspace = true | ||
| tracing-web = { optional = true, workspace = true } | ||
|
|
||
| [target.'cfg(target_env = "web")'.dependencies] |
There was a problem hiding this comment.
Some of these are Web-specific (e.g. kywasmtime) and some are JS-specific (e.g. getrandom/js).
There was a problem hiding this comment.
Remember we loosely also support (i.e. it's broken right now, but currently isn't too much work to fix) NodeJS, so not every JS environment is a Web environment.
There was a problem hiding this comment.
Shouldn't this be wasm32-unknown-js-web? Target triples are architecture-vendor-os-env.
There was a problem hiding this comment.
(Not that JS is exactly an OS — but I reckon it's close enough for the analogy. Vendors would be for specific browsers I suppose, or maybe specific Wasm interpreters where they're incompatible.)
There was a problem hiding this comment.
I can't remember now which crate it was but there was an issue where, when using the target triple, the crate failed to compile b/c it didn't recognize js as the os. So Claude, after analysing its code (and some trial and error) ended up with this
There was a problem hiding this comment.
Ah, yes. It was in the commit message:
- Rename wasm32-unknown-js-web → wasm32-web-unknown so that
target-lexicon(used by wasmer/cranelift) can parse the target name.
target-lexiconhas no custom OS support, so "web" goes in the vendor
position.- Use "env": "web" + "os": "unknown" in the target spec instead of
"os": "web". std has no platform implementation for target_os="web"
and fails to compile with build-std.
There was a problem hiding this comment.
I think the env here is unknown. The vendor in this triple is web, not the env. This is semantic nonsense, though, and Cranelift shouldn't be pulled in on the Web, so I suggest fixing it by working out why Cranelift is aware of this target at all.
For the latter, indeed the os has to be unknown so as to pull in dlmalloc according to the relevant Cargo.toml, but there's no need to mess with the vendor instead of keeping the web env.
There was a problem hiding this comment.
rust-lang/rust#153686 to allow us to use wasm32-unknown-js-web, which I think should otherwise work.
There was a problem hiding this comment.
Dependencies are:
linera-web → enables wasmer feature on linera-execution → pulls in linera-wasmer → depends on wasmer-types → depends on target-lexicon
So wasmer-types unconditionally depends on target-lexicon and uses Triple for parsing target triples. When compiled for the web target, target-lexicon tries to parse the target name during compilation.
This can be fixed by either:
- Changing
wasmer-typesto pull intarget-lexiconoptionally (upstream change) - Waiting for your PR to rust-lang
- keeping the current hack
The custom wasm32-web-unknown target spec was created by adding
web-specific customizations (env, threading, shared memory) but
did not carry over the default pre-link-args that the built-in
wasm32-unknown-unknown target provides. These flags are:
-z stack-size=1048576 Allocate 1MB stack (without this, the
wasm binary has no stack, causing
"memory access out of bounds" on any
non-trivial function call)
--stack-first Place stack at the start of linear memory
--allow-undefined Allow undefined symbols (JS imports)
--no-demangle Don't demangle symbols in diagnostics
--no-entry No entry point required (library build)
These can be verified by running:
rustc +nightly -Z unstable-options --print target-spec-json \
--target wasm32-unknown-unknown
The threading flags (--shared-memory, --import-memory, TLS exports)
were already present — they were migrated from the previous
`-C link-args=...` in web/.cargo/config.toml which were added when
Rust 1.92 stopped auto-enabling shared memory for +atomics.
The wasm32-web-unknown target links with --shared-memory, causing wasm-bindgen to create WebAssembly.Memory backed by SharedArrayBuffer. Modern browsers restrict SharedArrayBuffer to cross-origin isolated contexts, requiring COOP/COEP HTTP headers on the serving page. Add the required headers to vitest's dev server config and document the cross-origin isolation requirement in the @linera/client README.
Motivation
Replace the
webCargo feature flag with a custom wasm target (wasm32-web-unknown)that uses
target_env = "web"for cfg detection. This eliminates the need to passfeatures = ["web"]through the entire dependency tree and makes web-specific codeselection automatic based on the compilation target.
Proposal
wasm32-web-unknown.jsonthat extendswasm32-unknown-unknownwith"env": "web", threading support (+atomics,--shared-memory), and TLS exports.cfg(feature = "web")checks withcfg(target_env = "web")viacfg_aliasesin each crate'sbuild.rs.webfeature from all Cargo.toml files.wasmer-typeswith indexmap 2 to resolve abuild-stddependencyconflict with custom targets.
wasm32-unknown-unknownlinker flags (-z stack-size=1048576,--stack-first,--allow-undefined,--no-entry) to the custom target spec,which are not inherited when defining a custom target from scratch.
SharedArrayBuffersupportrequired by the atomics-enabled wasm build.
Note on target naming: The target is named
wasm32-web-unknown(withwebinthe vendor position) as a workaround for
target-lexicon(used bywasmer-types)not being able to parse custom OS values. The semantically correct name would be
wasm32-unknown-js-web(arch-vendor-os-env); an upstream Rust PR(rust-lang/rust#153686) has been filed to enable this.
Test Plan
cd web && pnpm -r run cipasses all 5 tests (2 signer + 3 client integration),lint, clippy, and typedoc generation.
Release Plan
Links
std: includedlmallocfor all non-wasi Wasm targets rust-lang/rust#153686