WASM: compile for wasm32, and fix trunk's binary selection on aarch64 #17

Merged
fabi merged 5 commits from fix/clippy-lints-wasm into main 2026-09-08 20:09:44 +00:00
Owner

Makes cargo check --target wasm32-unknown-unknown compile, and fixes the step after it
so the job's remaining failure is a real one rather than a known-wrong binary download.

Refs #11. Not marked Closes deliberately — see What this does not do.

The three commits

9f6321d fix(formats) — drop the unused normal tokio dependency
a7af8a4 fix(wasm) — the two --cfg flags, in a wasm-scoped .cargo/config.toml
90365b1 ci(wasm)trunk-action v0.5.0 → v0.5.1 for aarch64

#11 was written around the getrandom error alone. It turned out to be three stacked
blockers
, each invisible until the previous was gone:

  1. getrandom 0.3 refuses wasm32-unknown-unknown without --cfg getrandom_backend="wasm_js"
    and the crate's wasm_js feature — its own error is explicit that either alone is
    insufficient. It is not a direct dependency; it arrives through ahash.
  2. sylpheed-formats declared tokio as a normal dependency it never used as one,
    pulling tokio/fullnetmio, which does not build for wasm32.
  3. bevy_egui needs --cfg web_sys_unstable_apis.

Ordering

The tokio removal is first and separate, because it is the one change that touches
another crate, and because the reverse order would leave an intermediate commit still
failing on mio. Verified: at 9f6321d alone, cargo check --workspace exits 0 and the
wasm check fails with 0 mio errors, 2 getrandom errors — the tokio removal really
does clear mio, and every commit builds.

Verification

Confirmed on two machines, two architectures, two toolchains:

aarch64 · rustc 1.98.1 (the runner's) x86_64 · rustc 1.90.0
wasm check exit 0, 163 s from scratch, cache cleared exit 0, zero errors, 38 s
negative control at parent exit 101, the exact getrandom error
native cargo check --workspace exit 0 exit 0

Each blocker is confirmed separately, not by the aggregate exit code: in the passing
run bevy_egui compiles and neither mio nor tokio appears in the wasm graph at all;
in the failing control bevy_egui is never reached, which is what "stacked" means.

The trunk bump was read out of the two bundled dist/index.js files rather than the
release notes. v0.5.0 switches on platform alonecase 'linux': arch = 'x86_64-unknown-linux-gnu' — and never consults architecture, so on this aarch64 runner
it fetches an x86_64 binary. v0.5.1 adds process.arch with 'x64' → 'x86_64',
'arm64' → 'aarch64', and core.setFailed otherwise. It also moves the download host
thedodd/trunktrunk-rs/trunk (trunk moved repositories), and swaps io.mv for
io.cp, which is what avoids EXDEV on a self-hosted runner whose /tmp is a separate
filesystem — ours. Note EXDEV appears zero times in either bundle; that fix is
visible only as the primitive swap.

What this does not do

It is not known to turn the job green. Every check above concerns compiling, and
selecting and fetching trunk. The step after — trunk build --release — has never
executed in this repository on any architecture
, so there is no basis to predict it.
Read that log fresh. #11 should close on a green job, not on this merge.

Provenance

Authored by sylph-pi, which found and verified all three blockers. The commit split,
the cross-architecture A/B, and the trunk-version check were done on the desktop. Neither
agent could complete it alone: the Pi holds write:issue but is read-only on the repo,
the desktop holds write:repository but cannot file issues.

Makes `cargo check --target wasm32-unknown-unknown` compile, and fixes the step after it so the job's remaining failure is a real one rather than a known-wrong binary download. `Refs #11`. Not marked `Closes` deliberately — see **What this does not do**. ## The three commits | | | |---|---| | `9f6321d` | **`fix(formats)`** — drop the unused normal `tokio` dependency | | `a7af8a4` | **`fix(wasm)`** — the two `--cfg` flags, in a wasm-scoped `.cargo/config.toml` | | `90365b1` | **`ci(wasm)`** — `trunk-action` v0.5.0 → v0.5.1 for aarch64 | `#11` was written around the getrandom error alone. It turned out to be **three stacked blockers**, each invisible until the previous was gone: 1. `getrandom` 0.3 refuses `wasm32-unknown-unknown` without `--cfg getrandom_backend="wasm_js"` **and** the crate's `wasm_js` feature — its own error is explicit that either alone is insufficient. It is not a direct dependency; it arrives through `ahash`. 2. `sylpheed-formats` declared `tokio` as a **normal** dependency it never used as one, pulling `tokio/full` → `net` → `mio`, which does not build for wasm32. 3. `bevy_egui` needs `--cfg web_sys_unstable_apis`. ## Ordering The `tokio` removal is **first and separate**, because it is the one change that touches another crate, and because the reverse order would leave an intermediate commit still failing on `mio`. Verified: at `9f6321d` alone, `cargo check --workspace` exits 0 and the wasm check fails with **0 `mio` errors, 2 getrandom errors** — the tokio removal really does clear `mio`, and every commit builds. ## Verification Confirmed on two machines, two architectures, two toolchains: | | aarch64 · rustc 1.98.1 (the runner's) | x86_64 · rustc 1.90.0 | |---|---|---| | wasm check | exit 0, **163 s from scratch, cache cleared** | exit 0, zero errors, 38 s | | negative control at parent | — | **exit 101**, the exact getrandom error | | native `cargo check --workspace` | exit 0 | exit 0 | Each blocker is confirmed **separately**, not by the aggregate exit code: in the passing run `bevy_egui` compiles and neither `mio` nor `tokio` appears in the wasm graph at all; in the failing control `bevy_egui` is never reached, which is what "stacked" means. The trunk bump was read out of the two bundled `dist/index.js` files rather than the release notes. v0.5.0 switches on **platform alone** — `case 'linux': arch = 'x86_64-unknown-linux-gnu'` — and never consults architecture, so on this aarch64 runner it fetches an x86_64 binary. v0.5.1 adds `process.arch` with `'x64' → 'x86_64'`, `'arm64' → 'aarch64'`, and `core.setFailed` otherwise. It also moves the download host `thedodd/trunk` → `trunk-rs/trunk` (trunk moved repositories), and swaps `io.mv` for `io.cp`, which is what avoids `EXDEV` on a self-hosted runner whose `/tmp` is a separate filesystem — ours. Note `EXDEV` appears **zero times** in either bundle; that fix is visible only as the primitive swap. ## What this does not do **It is not known to turn the job green.** Every check above concerns *compiling*, and *selecting and fetching* trunk. The step after — **`trunk build --release` — has never executed in this repository on any architecture**, so there is no basis to predict it. Read that log fresh. `#11` should close on a green job, not on this merge. ## Provenance Authored by `sylph-pi`, which found and verified all three blockers. The commit split, the cross-architecture A/B, and the trunk-version check were done on the desktop. Neither agent could complete it alone: the Pi holds `write:issue` but is read-only on the repo, the desktop holds `write:repository` but cannot file issues.
fabi added 3 commits 2026-09-07 19:59:20 +00:00
`sylpheed-formats` declared `tokio` as a normal dependency and never used
it as one. All four references in its `src/` are inside a `mod tests` --
three runtime builders in ship.rs (539, 566, 690; `mod tests` at 498) and
one `#[tokio::test]` in xiso.rs (182; `mod tests` at 179) -- and tokio was
ALREADY present in `[dev-dependencies]`, so the tests keep compiling
unchanged.

The unused normal dependency pulled `tokio/full`, whose `net` feature
drags in `mio`, which does not build for wasm32:

  error: This wasm target is unsupported by mio.

Removing it is right on its own terms; the WASM job is merely what exposed
it. Native is unaffected -- `cargo check --workspace` exits 0 on x86_64.

This is separated from the CI configuration it was found through because
it is the one change here that touches another crate, and #11 is
`state/proposed` around the getrandom error alone. It is ordered first so
that every commit builds: the reverse order would leave an intermediate
commit still failing the wasm check on `mio`.

WARNING: this does NOT reach `sylpheed-export`, which builds
`sylpheed-formats` from the git pin `formats-pin-2026-09-01` (`1cd5b8b1`,
contained in `auto/frame-blend-draw-path` only) rather than the workspace
path crate. The dependency is not gone tree-wide until that pin resolves,
so anyone later adding `-p sylpheed-export` to the WASM job will hit `mio`
with this fix apparently already applied.

Refs #11

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
With the `mio` subtree gone (previous commit), two blockers remain. Each
was invisible until the one before it was cleared, which is why #11 was
written around only the first.

1. getrandom 0.3 refuses wasm32-unknown-unknown without being told which
   backend to use. It needs `--cfg getrandom_backend="wasm_js"` AND the
   crate's `wasm_js` feature; its own error is explicit that either alone
   is insufficient. Nothing here depends on getrandom directly -- it
   arrives through `ahash`, in `sylpheed-viewer` only -- so the feature
   half is declared there purely to switch it on.

2. error: bevy_egui uses unstable APIs to support clipboard on web.
   Needs `--cfg web_sys_unstable_apis`.

Both cfgs live in /.cargo/config.toml scoped to the wasm target, so native
builds are untouched.

Verified on aarch64 / rustc 1.98.1 -- the runner's toolchain -- from
scratch with the cache cleared: exit 0 in 163s. Independently reproduced
on x86_64 / rustc 1.90.0 as a controlled A/B against the parent, both
running the job's exact invocation:

  with this branch                        exit 0, zero errors, 38s
  same command at 885b4d4                 exit 101, the getrandom error

The control also shows `bevy_egui` is never reached when getrandom fails,
and the passing case contains no `mio` and no `tokio` in the wasm graph at
all -- so each blocker is confirmed separately rather than by the
aggregate exit code.

This does NOT make the WASM job green, and the next failure is already
identified rather than left to be discovered. `Install Trunk` uses
`jetli/trunk-action@v0.5.0`, whose bundled `dist/index.js` contains the
string `x86_64-unknown-linux-gnu` exactly once and `aarch64` not at all,
while calling `os.arch()` five times with no mapping for it. On this
aarch64 runner it will fetch an x86_64 binary. Upstream trunk does ship
`trunk-aarch64-unknown-linux-gnu.tar.gz`, so the asset exists and only the
action's selection is wrong -- but replacing the install step means
picking a version to pin and an install method, which is a decision, not a
fix. Left for #11 to decide.

Refs #11

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ci(wasm): bump trunk-action v0.5.0 -> v0.5.1 for aarch64
Some checks failed
CI / Native — linux (pull_request) Successful in 32m20s
CI / WASM — Web (pull_request) Failing after 22m17s
CI / Formatting (pull_request) Failing after 50s
90365b1751
`Install Trunk` has never run to completion here, because the two steps
before it always failed first. With those cleared it becomes reachable,
and on this runner v0.5.0 would fetch the wrong binary.

v0.5.0 switches on PLATFORM alone and never consults the architecture:

  case 'linux': arch = 'x86_64-unknown-linux-gnu'; break;

v0.5.1 reads it and maps it, failing loudly rather than wrongly:

  const arch = process.env['ARCH'] || process.arch;
  case 'x64':   targetArch = 'x86_64';  break;
  case 'arm64': targetArch = 'aarch64'; break;
  default: core.setFailed(`Unsupported architecture: ${arch}`); return;

Node reports `arm64` here, so it resolves to `aarch64`, and upstream does
publish trunk-aarch64-unknown-linux-gnu.tar.gz. There is also an `ARCH`
env override if the mapping is ever wrong.

Read out of the two bundled dist/index.js files, not the release notes.
Counts moved as predicted: `x86_64-unknown-linux-gnu` 1 -> 0, `aarch64`
0 -> 1, `os.arch()` 5 -> 5. Confirmed independently on both machines.

Two further changes the bump carries, neither of them about architecture:

  * the download host moves thedodd/trunk -> trunk-rs/trunk. Trunk moved
    repositories and v0.5.0 still points at the old one -- arguably the
    more durable half of the fix.
  * `io.mv` 1 -> 0 and `io.cp` 2 -> 3. A cross-filesystem move throws
    EXDEV; a copy does not. This is the fix for self-hosted runners whose
    /tmp is a separate filesystem, which is ours. NOTE: the string EXDEV
    appears zero times in either bundle, so this cannot be found by
    grepping for the error it prevents -- it is visible only as the
    primitive swap.

STILL UNVERIFIED: whether `trunk build --release` then succeeds. Everything
above concerns selecting and fetching the binary. The step after it has
never run in this repository's history, on any architecture, so there is no
basis to predict it. Expect to read that log fresh.

Refs #11

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fabi added 1 commit 2026-09-08 17:00:40 +00:00
fix(wasm): select the bin target, so trunk emits a real bundle
Some checks failed
CI / Native — linux (pull_request) Successful in 32m46s
CI / WASM — Web (pull_request) Failing after 23m39s
CI / Formatting (pull_request) Failing after 48s
7285a566dd
`trunk build --release` reached the asset pipeline for the first time and
failed there:

  found more than one target artifact: ["sylpheed_viewer", "sylpheed-viewer"]

The crate declares both a [[bin]] `sylpheed-viewer` (src/main.rs) and a
[lib] `sylpheed_viewer` cdylib (src/lib.rs), and the index.html link named
neither, so trunk refused to guess.

Trunk's error offers two ways out and THEY ARE NOT EQUIVALENT. Measured,
both exiting 0:

  data-target-name="sylpheed_viewer"   1_478 bytes,        1 app symbol
  data-bin="sylpheed-viewer"          21_298_268 bytes, 2_998 app symbols

Selecting the lib "succeeds" while linking nothing, because there is no
wasm entry point in it -- no wasm-bindgen dependency, no import, no
`#[wasm_bindgen(start)]`. The linker drops the whole app and trunk emits an
empty module. That would have turned this job GREEN on a bundle that cannot
start, which is worse than the red it replaced.

`main()` is a valid wasm entry: it calls `sylpheed_viewer::run()` and its
only native-specific code is already `#[cfg(not(target_arch = "wasm32"))]`.
With the bin selected, trunk injects a real init -- `import init`, an
integrity-checked module preload, `__wbindgen_start`, and the
`TrunkApplicationStarted` event.

The lib.rs docs claimed this file was the WASM entry point "called from
`wasm_bindgen` init on the web". Nothing ever called it. That comment is
what made the lib look like the right target, so it is corrected here
rather than left to mislead the next reader.

Verified locally with trunk 0.21.7 on x86_64. The exit code does not
distinguish these two cases -- only the artifact does.

Refs #11
fabi added 1 commit 2026-09-08 18:03:32 +00:00
ci(wasm): drop the artifact upload, which cannot work on Gitea
Some checks failed
CI / Native — linux (pull_request) Successful in 31m52s
CI / WASM — Web (pull_request) Successful in 29m40s
CI / Formatting (pull_request) Failing after 46s
a364813df6
With the build fixed, `trunk build --release` succeeds and the job then
died on its last step:

  ::error:: @actions/artifact v2.0.0+, upload-artifact@v4+ and
            download-artifact@v4+ are not currently supported on GHES.

Gitea presents as GHES and the action aborts by design -- go-gitea/gitea
#31256 and #36024. Same class as the trunk-action bug this branch already
fixes: an action written for GitHub's hosted fleet, on a runner that is not
it.

Dropped rather than downgraded, because nothing consumes the artifact.
`web-dist` had exactly one reference in the repository -- the line that
produced it. There is no `download-artifact`, no deploy step, and no second
workflow. It was failing the job for no benefit.

The two ways to keep it are recorded in the file rather than here, because
choosing between them needs a fact this run does not provide (the runner's
node version) or a supply-chain decision (a third-party action).

What now runs end to end on aarch64, from scratch:

  Install Trunk             ok   (v0.5.1, the arch fix, on the real runner)
  cargo check wasm32        ok
  trunk build --release     ok   10m 56s, 3 files in dist/

Refs #11

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fabi merged commit b0729d5cc9 into main 2026-09-08 20:09:44 +00:00
Sign in to join this conversation.