Skip to content

feat(napi): build a native binary for Windows on ARM - #82

Merged
jamesyong-42 merged 2 commits into
mainfrom
feat/windows-arm64-native
Jul 26, 2026
Merged

feat(napi): build a native binary for Windows on ARM#82
jamesyong-42 merged 2 commits into
mainfrom
feat/windows-arm64-native

Conversation

@jamesyong-42

Copy link
Copy Markdown
Member

Why

aarch64-pc-windows-msvc was the one platform in the loader with no binary behind it. index.js has always had a win32-arm64-msvc branch, so every Windows-on-ARM install walked it, found nothing, and fell back to the TypeScript ingest path.

Graceful, but it's the slow path — and it's the same population that just hit the unshipped parse worker in #81, which compounded into sequential TypeScript parsing.

What

  • aarch64-pc-windows-msvc added to napi.targets
  • Cross-compiled from windows-latest, mirroring how aarch64-linux is built on ubuntu-latest
  • Smoke-tested on windows-11-arm, GitHub's hosted ARM Windows runner (free for public repos), so the binary is require()-loaded on real hardware rather than shipped on faith — keeping the invariant napi-build.yml states for itself
  • Platform package + release-please version entry, matching the other five

The loader needs no change: napi generates branches for every known platform regardless of which targets are built, so win32-arm64-msvc was already wired.

Verification

rusqlite's bundled feature compiles SQLite from C, so this needs an MSVC toolset targeting ARM64 — not just Rust std for the target. That can't be checked locally (my box has no ARM64 cl.exe; the build fails with failed to find tool "cl.exe"), so this PR carries a temporary probe workflow that cross-compiles and then loads the result on real ARM64 hardware.

napi-build.yml couldn't be used for this: it's workflow_dispatch-only and its publish job has no condition, so dispatching it to test a build would also attempt an npm publish. And release.yml dispatches it with no inputs, so adding a publish input would silently stop releases from publishing.

The probe is deleted before merge — it exists to produce evidence, not to ship.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LQt9EvHYXCd2U4ZJMfMm4E

aarch64-pc-windows-msvc was the one platform in the loader with no binary
behind it: index.js has always had a `win32-arm64-msvc` branch, so every
Windows-on-ARM install walked it, found nothing, and fell back to the
TypeScript ingest path. Graceful, but it is the slow path, and it is the
same population that just hit the unshipped parse worker.

Cross-compiled from windows-latest, mirroring how aarch64-linux is built
on ubuntu-latest, then require()-loaded on windows-11-arm — GitHub's
hosted ARM Windows runner, free for public repos — so the binary is
verified on real hardware rather than shipped on faith. That keeps the
invariant napi-build.yml states for itself: every published binary is
loaded on a matching host before publish.

Also registers the platform package and its release-please version entry,
matching the other five. Those packages are not published today (the main
package fat-bundles every binary) but are kept version-synced.

Includes a temporary pull_request-triggered probe workflow to prove the
cross-compile works on the runner image, since rusqlite's bundled SQLite
needs an MSVC toolset targeting ARM64 and that cannot be checked locally.
It is removed in the next commit.

Claude-Session: https://claude.ai/code/session_01LQt9EvHYXCd2U4ZJMfMm4E
It existed to answer one question that could not be settled locally:
whether windows-latest can cross-compile aarch64-pc-windows-msvc,
including rusqlite's bundled SQLite, which needs an MSVC toolset
targeting ARM64 rather than just the Rust std for that target.

Both halves passed on the previous commit:

  Compiling rusqlite v0.31.0
  Finished `release` profile [optimized] target(s) in 1m 35s
  spaghetti.win32-arm64-msvc.node   4544512 bytes

  Loaded OK on win32 arm64 - nativeVersion = 0.5.21

The cross-compile is 3m33s on windows-latest and the load check is 1m10s
on windows-11-arm, so the equivalent legs now in napi-build.yml cost the
release about the same as the existing windows-x64 pair.

Claude-Session: https://claude.ai/code/session_01LQt9EvHYXCd2U4ZJMfMm4E
@jamesyong-42
jamesyong-42 merged commit 0e9a741 into main Jul 26, 2026
6 checks passed
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