Add Windows ARM64 build and release support#6486
Conversation
|
I'm Bonk, and I've done a quick review of your PR. This PR adds Windows ARM64 build, test, and release support across the Bazel build system, Rust toolchain, NPM distribution, and CI workflows. The Bazel, Rust, npm, and test workflow changes all look correct. Issues found (ranked by severity): 1. [HIGH]
|
|
I've posted a review comment on PR #6486. Here's a summary: The PR adds Windows ARM64 support across the build system, Rust toolchain, npm packages, and CI workflows. The Bazel, Rust, npm, and test workflow changes are all correct. One high-severity issue found: The The fix is to replace |
|
My understanding is that lots of effort would be needed to properly support an arm64 Windows build – see #4062 for some prior work. Would need to be developed on an actual arm64 machine, not something an LLM can do alone. A good alternative to explore would be to cross-compiling from x64 Windows (still won't be trivial). |
db49ad2 to
61c282d
Compare
Merging this PR will improve performance by 14.58%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | Encode_ASCII_32[TextEncoder][0/0/32] |
3.1 ms | 2.7 ms | +14.58% |
Comparing add-windows-arm64-support (193ca0e) with main (1f30941)
Footnotes
-
129 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
|
Ah I see ,thanks for the info @fhanau (tagged you in the internal thread as well). lemme do a couple of iterations here and see how far I can get before I complete give up (inevitably) |
Status updateWe've been iterating through blockers on the
Current blocker: Bazel 9.0.1 toolchain detectionBecause of blocker #3, we're currently running the x64 Bazel binary under emulation. This works for Bazel itself, but
This is a fundamental limitation of using x64 Bazel on an ARM64 host — the toolchain auto-detection picks up the wrong architecture. Path forwardBazel 9.0.2 (bazelbuild/bazel#28967) fixes the ARM64 Windows JNI bug. RC1 is expected April 6 and the release on April 8. Once we bump
The prior attempt at this (PR #4062 by @fhanau) hit several of these same blockers when the upstream ecosystem wasn't ready. Since then, This PR is ready to pick back up once Bazel 9.0.2 drops. |
|
converting to draft so we can revisit this next week after bazel 9.0.2 is out |
|
The generated output of |
31dffa2 to
6bd6bf6
Compare
Add end-to-end support for building, testing, and releasing workerd on Windows ARM64 (aarch64-pc-windows-msvc). This enables `npm install workerd` to work natively on Windows ARM64 devices (e.g. Snapdragon laptops) via the new @cloudflare/workerd-windows-arm64 package. Bazel build system: - Define arm64_windows-clang-cl platform in BUILD.bazel - Add build:windows_arm64 config overriding the toolchain and execution platform from x64 to ARM64 - Add build:release_windows_arm64 composing release_windows + windows_arm64 - Add build:ci-windows-arm64 for CI release builds Rust toolchain: - Register aarch64-pc-windows-msvc in RUST_TARGET_TRIPLES so rules_rust downloads and configures a Rust toolchain for the new target - Add the triple to supported_platform_triples in crates_vendor so the Cargo dependency graph resolves for Windows ARM64 - Add win_arm64 config_setting_group and wire cargo-bazel to use the x64 binary under WoW64 emulation (no native ARM64 build available) Host tools: - Add @bazel_tools//src/conditions:windows_arm64 entries to wasm-tools and clang-tidy selects, falling back to x64 binaries under emulation NPM distribution: - Create npm/workerd-windows-arm64/ package (os: win32, cpu: arm64) - Add "win32 arm64 LE" to knownPackages in node-platform.ts - Add @cloudflare/workerd-windows-arm64 to optionalDependencies in the workerd meta-package and build-shim-package.mjs CI/CD: - Add windows-arm64 build matrix entry in release.yml using the windows-11-arm GitHub Actions runner - Add windows-arm64 upload-artifacts entry for release asset publishing and npm per-arch package publishing - Add windows-arm64 to test.yml matrix (debug builds excluded, matching the x64 Windows exclusion for disk space reasons) Note: the @local_config_cc toolchain name for ARM64 Windows is auto-generated by Bazel based on what it discovers on the host. If the first CI run fails with a toolchain resolution error, query @local_config_cc//:all on the runner to find the correct label. Made-with: Cursor
aspect_rules_js uses yq to parse pnpm lockfiles during repository setup.
It resolves the yq binary via @yq_{platform}, where {platform} is detected
from the host. On Windows ARM64, this becomes @yq_windows_arm64, which
doesn't exist in yq.bzl 0.3.2 (the version transitively pulled in by
aspect_rules_js 3.0.3).
yq.bzl 0.3.5 includes Windows ARM64 yq binaries, so we override the
transitive version with a direct bazel_dep in the root MODULE.bazel.
This was the primary blocker identified in the prior Windows ARM64 attempt
(PR #4062). The other blockers from that attempt have since been resolved:
- rules_nodejs 6.7.3 (already used) includes windows_arm64 Node.js
toolchain support (merged in 6.5.0, fix in 6.6.1)
- bazel_lib 3.2.2 (already used) includes windows_arm64 binaries for
copy_to_directory, coreutils, expand_template, and zstd
- The setup-runner action already enables developer mode on Windows via
reg add, which also runs on ARM64 runners
Made-with: Cursor
The script derives Git's bash.exe location by stripping known git.exe suffixes from the path returned by `where git.exe`. It handled \cmd\git.exe and \mingw64\bin\git.exe but not \bin\git.exe, which is the path returned on ARM64 Windows runners. Also fix the `for` loop to use `goto` instead of `break` (which doesn't exit batch for-loops) so only the first result from `where` is used. Made-with: Cursor
Bazel 9.0.2rc1 is now available with the fix for the ARM64 Windows JNI DLL mismatch (bazelbuild/bazel#28941, PR #29012). This allows native ARM64 Bazel to run correctly, which means the toolchain auto-detection will find the ARM64 clang-cl toolchain instead of x64 MSVC. Replace the BAZELISK_FORMAT_URL workaround (which forced x64 Bazel and caused toolchain misdetection) with USE_BAZEL_VERSION=9.0.2rc1 scoped to ARM64 Windows only. Other platforms continue using 9.0.1 from .bazelversion. Made-with: Cursor
The vendored crate definitions in deps/rust/crates/defs.bzl were generated without the aarch64-pc-windows-msvc triple, causing Rust crates like windows_sys, mio, socket2, and termcolor to fail to resolve their Windows-specific dependencies on ARM64. Add the triple to the cfg(windows), cfg(any(target_arch = "aarch64")), cfg(not(all(target_arch = "arm"))) conditions and as a literal triple mapping. A proper crates_vendor --repin should be done once the googlesource auth issue is resolved for local development. Made-with: Cursor
aspect_rules_esbuild 0.25.1 doesn't include Windows ARM64 in its platform list despite esbuild shipping native win32-arm64 binaries. This caused 911 targets to fail toolchain resolution on ARM64 Windows. Add a patch that: - Adds win32-arm64 to _PLATFORMS in toolchains_repo.bzl - Adds the npm integrity hash for @esbuild/win32-arm64@0.19.9 to versions.bzl Made-with: Cursor
The oci_load and multirun targets in images/ were missing target_compatible_with constraints, causing toolchain resolution failures on Windows (both x64 and ARM64). The oci_image target already had the Linux constraint but the load/multirun targets that depend on it did not. Made-with: Cursor
The windows-11-arm runner has 4 vCPUs (vs 16 for windows-2025-16core), so tests need longer timeouts. Four tests were timing out at the default limits (3s/15s/60s/240s for small/medium/large/enormous). Increase to 15s/60s/240s/240s to match the slower hardware. Made-with: Cursor
098d766 to
d0b90bc
Compare
clang-cl on ARM64 Windows doesn't automatically link the compiler-rt builtins library, causing undefined symbol errors for 128-bit integer operations like __udivti3 (used by V8's bigint division). The library is available in the LLVM lib path but needs to be linked explicitly. Made-with: Cursor
Update: Windows ARM64 CI is fully green 🎉Since the last status update, we've cleared all remaining blockers. The Blockers resolved since last update
What's left before mergingThe PR description has a full checklist, but the key items are:
cc @fhanau — turns out the ecosystem has come far enough since #4062 that this was achievable with targeted patches. Happy to discuss any of the changes. |
danlapid
left a comment
There was a problem hiding this comment.
Great work! This might become useful in the future!
At present, I am more interested to learn if window for arm's x64 emulation can run workerd well enough.
If it can, I am not convinced this is worth the maintenance burden.
|
@danlapid I'm running a patched workderd on my Windows ARM X-Elite notebook since almost a year now. although it should be said that im not rly using it much other than local nextjs on workers dev. |
Hi, I've been running workerd under emulation with my Snapdragon X Elite X1E78100 for ~6 months with no issues. I've gone ahead and opened #6882 in hopes we can merge that while we wait for this PR |
Summary
Adds end-to-end support for building, testing, and releasing workerd on Windows ARM64 (
aarch64-pc-windows-msvc). This enablesnpm install workerdto work natively on Windows ARM64 devices (e.g. Snapdragon laptops) via the new@cloudflare/workerd-windows-arm64package.Customer request: https://chat.google.com/room/AAAAAzbdxGI/mmu50RiTETE/mmu50RiTETE?cls=10
Builds on prior work in #4062 by @fhanau. Several upstream blockers from that attempt have since been resolved (rules_nodejs, bazel_lib, yq all gained ARM64 Windows support), making this possible now.
What changed
Build system scaffolding
arm64_windows-clang-clBazel platform,build:windows_arm64/release_windows_arm64/ci-windows-arm64configsaarch64-pc-windows-msvcadded toRUST_TARGET_TRIPLES,supported_platform_triples, and vendored crate platform mappingswasm-tools,clang-tidy):windows_arm64select entries using x64 binaries under emulationUpstream dependency patches
Three Bazel rulesets needed patching for ARM64 Windows — the upstream binaries exist but the Bazel rules don't register the platform:
yq.bzl0.3.5aspect_rules_jspulls 0.3.2 transitively (nowindows_arm64)archive_overrideto force 0.3.5aspect_rules_js3.0.3use_repolist missingyq_windows_arm64aspect_rules_esbuild0.25.1_PLATFORMSmissingwin32-arm64Runner/toolchain fixes
USE_BAZEL_VERSION=9.0.2rc1on ARM64 Windows only until.bazelversionis bumped globally.clang_rt.builtins-aarch64.lib, causing__udivti3undefined symbol in V8. Added explicit--linkopt.\bin\git.exeon ARM64 runners (not\cmd\git.exe). Fixed bash path derivation.windows-11-armrunner has 4 vCPUs (vs 16 on x64). Increased test timeouts accordingly.NPM distribution
@cloudflare/workerd-windows-arm64package (os: win32,cpu: arm64)optionalDependencies, and build script all updatedCI/CD
release.ymlusingwindows-11-armGitHub Actions runnertest.yml(debug builds excluded).exeextension handling generalized from== 'windows-64'tocontains(matrix.arch, 'windows')Pre-existing fix
images/) now havetarget_compatible_with = ["@platforms//os:linux"]— they were missing this and would fail on any Windows platform, not just ARM64.Before merging
USE_BAZEL_VERSIONfrom9.0.2rc1to9.0.2final once released (or bump.bazelversionglobally and remove the override). Tracked at bazelbuild/bazel#28967.deps/rust/crates/were edited manually. Runbazel run //deps/rust:crates_vendor -- --repinto validate/regenerate them properly.aspect_rules_js,aspect_rules_esbuild, andyq.bzlcould be contributed upstream to reduce our maintenance burden.Test plan
windows-arm64test matrix entry (windows-11-armrunner)bazel build //...succeeds (2545/2545 targets)bazel test //...passes (with adjusted timeouts)workerd --versionruns on an actual Windows ARM64 device@cloudflare/workerd-windows-arm64npm package installs correctly