Enable arm64_32-apple-watchos (Apple Watch SE2 / Series 4-8) build#97
Enable arm64_32-apple-watchos (Apple Watch SE2 / Series 4-8) build#97matthargett wants to merge 1 commit into
Conversation
|
Thanks @matthargett for the Apple Watch SE / S4-S8 ILP32 enablement — the wasm-benchmark / pure-interpreter / App-Store-eligible use case is great motivation, and I've read through the diff carefully. The strategy makes sense: work around To ship cleanly on
#98 has been verified end-to-end on Mac aarch64 (7/7 Commit Gate + bench-quick) and Ubuntu x86_64 (6/6 Commit Gate). Once CI is green it will be squash-merged with If anything about the cleanup direction looks off — different error name, different gating predicate, anything — please drop a note here, on #98, or in a new issue / discussion. Happy to iterate, and thanks again for the contribution! 🙇 |
…wasm#98) Adds support for `zig build static-lib -Dtarget=aarch64-watchos-ilp32 -Djit=false` (Apple Watch SE / SE2 / Series 4-8, ILP32 ABI). zwasm's `-Djit=false` mode is the right fit for App-Store-eligible WatchKit apps where `MAP_JIT` is forbidden outside JavaScriptCore. Strategy (per D139): work around Zig 0.16's `std.Io.Threaded` not compiling under ILP32 (u64 → usize narrowing) via comptime gates that keep 64-bit consumers byte-identical. - `build.zig` — `single_threaded = true` on `lib_static_mod` gated to `target.result.ptrBitWidth() < 64` - `src/c_api.zig` — `pub const panic = std.debug.no_panic` on ILP32, default elsewhere; same gating for `std_options` - `src/types.zig` — refuse `loadCore` with `error.MissingIo` when WASI or `timeout_ms` is requested on ILP32 without an explicit `config.io` - `src/guard.zig` — `GUARD_SIZE` / `TOTAL_RESERVATION` set to 0 placeholders on ILP32 (comptime overflow otherwise; guarded paths predicated on `jitSupported()` which is false for watchos) - `src/memory.zig`, `src/vm.zig` — explicit `@intCast(usize)` on `effective: u64` after the bounds check (no-op on 64-bit, narrowing on ILP32) - `.github/workflows/ci.yml` — build-only smoke job for `aarch64-watchos-ilp32` on `macos-latest` - `.dev/decisions.md` (D139), `.dev/checklist.md` (W55) — support matrix, alternatives, open follow-ups (Zig 0.16 `.a` packing bug) Verified: Mac aarch64 Commit Gate 7/7 (incl. bench-quick), Ubuntu x86_64 Commit Gate 6/6, full CI 11/11 across macOS / Ubuntu / Windows + ILP32 smoke. Closes clojurewasm#97. Co-authored-by: Matt Hargett <plaztiksyke@gmail.com>
Summary
Makes `zig build static-lib -Dtarget=aarch64-watchos-ilp32 -Djit=false` produce a working `libzwasm.a` for the Apple Watch SE / SE2 / S4-S8 device class (the ILP32 ABI: 32-bit pointers, aarch64 instructions). All changes are gated on `@sizeOf(usize) < 8` (ILP32) so they are comptime no-ops on every 64-bit target.
Zig 0.16 spells the triple `aarch64-watchos-ilp32` — the legacy `arm64_32-` arch was removed in ziglang/zig#20820. The build was previously broken on ILP32 with five categories of errors; this PR fixes each in the minimum way that preserves behaviour on every other target.
Why
I run a 6-runtime pure-interpreter comparison (rebeckerspecialties/wasm-benchmark) targeting Apple's full first-party platform set (macOS, iOS, watchOS, tvOS). Apple Watch SE2 (S8 / Cortex-A53-derivative) ships as ILP32 — wasm-eligible since iOS 18 + watchOS 11, and one of the most common consumer-facing wasm-runtime deployment scenarios where pure interpretation is mandatory (App Store doesn't allow MAP_JIT outside of JavaScriptCore). zwasm's `-Djit=false` mode is a perfect fit for this; the missing piece was the ILP32 build itself.
Diff shape (5 changes, ~115 LOC net)
Verified
Known Zig 0.16 quirk (separate)
`zig build static-lib` for `aarch64-watchos-ilp32` correctly generates the `.o` but doesn't pack it into the `.a` (the resulting archive is 88 bytes, just the SYMDEF). Our build script works around this with `ar rcs` post-build. Probably a Zig bug to file separately, not in scope for this PR.
Environment