Skip to content

Commit 61c282d

Browse files
committed
Add Windows ARM64 build and release support
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
1 parent 862a428 commit 61c282d

13 files changed

Lines changed: 75 additions & 7 deletions

File tree

.bazelrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,12 @@ build:windows --enable_runfiles
346346
build:windows --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl
347347
build:windows --extra_execution_platforms=//:x64_windows-clang-cl
348348

349+
# Windows ARM64 overrides: use the ARM64 platform instead of x64. The toolchain name is
350+
# auto-generated by local_config_cc – if this doesn't match what Bazel detects on the ARM64
351+
# runner, query @local_config_cc//:all to find the correct name.
352+
build:windows_arm64 --extra_toolchains=@local_config_cc//:cc-toolchain-arm64_windows-clang-cl
353+
build:windows_arm64 --extra_execution_platforms=//:arm64_windows-clang-cl
354+
349355
# The Windows fastbuild bazel configuration is broken in that it necessarily generates PDB debug
350356
# information while the Linux and macOS toolchains only compile with debug information in the dbg
351357
# configuration or when requested with the -g flag. This causes huge increases in compile time and
@@ -435,6 +441,9 @@ build:release_windows --per_file_copt="src/workerd/server/container-client"@/cla
435441
# Work around Windows test failures in rpc-related tests
436442
build:release_windows --per_file_copt=src/workerd/io/worker-interface@/clang:-fno-inline
437443

444+
build:release_windows_arm64 --config=release_windows
445+
build:release_windows_arm64 --config=windows_arm64
446+
438447
build:windows --cxxopt='/std:c++23preview' --host_cxxopt='/std:c++23preview'
439448
build:windows --copt='/D_CRT_USE_BUILTIN_OFFSETOF' --host_copt='/D_CRT_USE_BUILTIN_OFFSETOF'
440449
build:windows --copt='/DWIN32_LEAN_AND_MEAN' --host_copt='/DWIN32_LEAN_AND_MEAN'

.github/workflows/release.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ jobs:
104104
image: windows-2025-16core
105105
bazel-config: release_windows
106106
target-arch: X64
107+
- title: windows-arm64
108+
os-name: Windows
109+
image: windows-11-arm
110+
bazel-config: release_windows_arm64
111+
target-arch: ARM64
107112
name: build (${{ matrix.title }})
108113
uses: './.github/workflows/_bazel.yml'
109114
with:
@@ -129,8 +134,6 @@ jobs:
129134
strategy:
130135
matrix:
131136
arch: [linux-64, darwin-64, windows-64]
132-
# This variable itself is unused, but allows us to set up two macOS builds. arm64 builds for
133-
# other platforms will be supported later, then we'll list both architectures here.
134137
cpu: [X64]
135138
include:
136139
- arch: linux-64
@@ -145,6 +148,9 @@ jobs:
145148
cpu: ARM64
146149
- arch: windows-64
147150
name: Windows-X64
151+
- arch: windows-arm64
152+
name: Windows-ARM64
153+
cpu: ARM64
148154
steps:
149155
- name: Checkout Repo
150156
uses: actions/checkout@v6
@@ -157,15 +163,15 @@ jobs:
157163
name: ${{ matrix.name }}-binary
158164
path: /tmp
159165
# Set execute permissions before compressing the binary
160-
- if: matrix.arch != 'windows-64'
166+
- if: ${{ !contains(matrix.arch, 'windows') }}
161167
run: chmod +x /tmp/workerd
162168
- name: Compress release binary
163169
run: |
164170
# As of release v1.20230404.0 the Linux x64 binary after debug_strip is 65.8 MB,
165171
# 21.0 MB with gzip and 17.3 MB with brotli -9. Use gzip as a widely supported format
166172
# which still produces an acceptable compressed size.
167-
gzip -9N -k /tmp/workerd${{ matrix.arch == 'windows-64' && '.exe' || '' }}
168-
- run: mv /tmp/workerd${{ matrix.arch == 'windows-64' && '.exe' || '' }}.gz /tmp/workerd-${{ matrix.arch }}.gz
173+
gzip -9N -k /tmp/workerd${{ contains(matrix.arch, 'windows') && '.exe' || '' }}
174+
- run: mv /tmp/workerd${{ contains(matrix.arch, 'windows') && '.exe' || '' }}.gz /tmp/workerd-${{ matrix.arch }}.gz
169175
# Upload compressed release binaries – one set of artifacts is sufficient with gzip being
170176
# widely supported
171177
- name: Upload Release Assets
@@ -190,7 +196,7 @@ jobs:
190196
WORKERD_VERSION: ${{ needs.version.outputs.version }}
191197
LATEST_COMPATIBILITY_DATE: ${{ needs.version.outputs.date }}
192198
- run: mkdir npm/workerd-${{ matrix.arch }}/bin
193-
- run: cp /tmp/workerd${{ matrix.arch == 'windows-64' && '.exe' || '' }} npm/workerd-${{ matrix.arch }}/bin/workerd${{ matrix.arch == 'windows-64' && '.exe' || '' }}
199+
- run: cp /tmp/workerd${{ contains(matrix.arch, 'windows') && '.exe' || '' }} npm/workerd-${{ matrix.arch }}/bin/workerd${{ contains(matrix.arch, 'windows') && '.exe' || '' }}
194200
- run: echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > npm/workerd-${{ matrix.arch }}/.npmrc
195201
- run: cd npm/workerd-${{ matrix.arch }} && npm publish --access public --tag ${{ startsWith(needs.version.outputs.version, '0') && 'beta' || 'latest'}}
196202
env:

.github/workflows/test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ jobs:
3737
{ name: linux-arm, arch: ARM64, image: ubuntu-22.04-arm-16core },
3838
{ name: macOS, arch: ARM64, image: macos-15-xlarge, use_lld: true },
3939
{ name: windows, arch: X64, image: windows-2025-16core },
40+
{ name: windows-arm64, arch: ARM64, image: windows-11-arm },
4041
]
4142
config: [
4243
# Default build: no suffix or additional bazel arguments
@@ -57,6 +58,8 @@ jobs:
5758
exclude:
5859
- os: { name: windows, arch: X64, image: windows-2025-16core }
5960
config: { suffix: -debug }
61+
- os: { name: windows-arm64, arch: ARM64, image: windows-11-arm }
62+
config: { suffix: -debug }
6063
# due to resource constraints, exclude the macOS and x64 Linux debug runners for now.
6164
# linux-asan and arm64 linux-debug should provide sufficient coverage for building in the
6265
# debug configuration.

BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ platform(
6262
],
6363
)
6464

65+
platform(
66+
name = "arm64_windows-clang-cl",
67+
constraint_values = [
68+
"@platforms//cpu:aarch64",
69+
"@platforms//os:windows",
70+
"@bazel_tools//tools/cpp:clang-cl",
71+
],
72+
)
73+
6574
# Used for cross-compilation
6675
platform(
6776
name = "macOS_x86",

RELEASE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ The primary distribution channel for `workerd` right now is through `npm`. We us
88

99
## Cutting Releases
1010

11-
This is pretty simple, and completely automatic—every time the date in [release-version.txt](src/workerd/io/release-version.txt) changes, a new release is generated, along with the built binaries for `linux-64`, `linux-arm64`, `darwin-64`, `darwin-arm64` and `windows-64`. The types will also be generated and published automatically. This is governed by the [release.yml](.github/workflows/release.yml) GitHub Action.
11+
This is pretty simple, and completely automatic—every time the date in [release-version.txt](src/workerd/io/release-version.txt) changes, a new release is generated, along with the built binaries for `linux-64`, `linux-arm64`, `darwin-64`, `darwin-arm64`, `windows-64` and `windows-arm64`. The types will also be generated and published automatically. This is governed by the [release.yml](.github/workflows/release.yml) GitHub Action.

build/ci.bazelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,15 @@ test:ci-macOS --spawn_strategy=local
8888
build:ci-windows --config=release_windows
8989
build:ci-windows-debug --config=debug
9090

91+
build:ci-windows-arm64 --config=release_windows_arm64
92+
9193
# Some tests (like Python import tests) take a long time to run, especially when debug is enabled
9294
# For that reason, we only run them in the default configuration for each platform to minimize
9395
# effect on CI pipeline runtime.
9496
test:ci-linux --test_size_filters=
9597
test:ci-macOS --test_size_filters=
9698
test:ci-windows --test_size_filters=
99+
test:ci-windows-arm64 --test_size_filters=
97100

98101
# Run container tests on Linux CI
99102
test:ci-linux --test_tag_filters=-off-by-default,-requires-fuzzilli

build/deps/rust.MODULE.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ RUST_TARGET_TRIPLES = [
88
"x86_64-apple-darwin",
99
# Add support for macOS rosetta
1010
"aarch64-unknown-linux-gnu",
11+
# Add support for Windows ARM64
12+
"aarch64-pc-windows-msvc",
1113
]
1214

1315
# rules_rust
@@ -36,6 +38,7 @@ rust.toolchain(
3638
"x86_64-pc-windows-msvc": ["-Ctarget-feature=+sse4.2"],
3739
"aarch64-unknown-linux-gnu": ["-Ctarget-feature=+crc"],
3840
# No options needed for aarch64-apple-darwin: CRC feature is enabled by default.
41+
# No options needed for aarch64-pc-windows-msvc: CRC feature is enabled by default on ARM64.
3942
},
4043
extra_target_triples = RUST_TARGET_TRIPLES,
4144
rustfmt_version = RUST_NIGHTLY_VERSION,

deps/rust/BUILD.bazel

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,22 @@ selects.config_setting_group(
4545
],
4646
)
4747

48+
selects.config_setting_group(
49+
name = "win_arm64",
50+
match_all = [
51+
"@platforms//os:windows",
52+
"@platforms//cpu:aarch64",
53+
],
54+
)
55+
4856
CARGO_BAZEL = select({
4957
":linux_x64": "@cargo_bazel_linux_x64//file:downloaded",
5058
":linux_arm64": "@cargo_bazel_linux_arm64//file:downloaded",
5159
":macos_x64": "@cargo_bazel_macos_x64//file:downloaded",
5260
":macos_arm64": "@cargo_bazel_macos_arm64//file:downloaded",
5361
":win_x64": "@cargo_bazel_win_x64//file:downloaded.exe",
62+
# x64 cargo-bazel runs under emulation on Windows ARM64
63+
":win_arm64": "@cargo_bazel_win_x64//file:downloaded.exe",
5464
})
5565

5666
# Generates a repository containing all the crates we reference from our
@@ -82,6 +92,7 @@ crates_vendor(
8292
"aarch64-unknown-linux-gnu",
8393
"x86_64-unknown-linux-gnu",
8494
"x86_64-pc-windows-msvc",
95+
"aarch64-pc-windows-msvc",
8596
],
8697
)
8798

npm/lib/node-platform.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const knownPackages: Record<string, string> = {
1717
"darwin x64 LE": "@cloudflare/workerd-darwin-64",
1818
"linux arm64 LE": "@cloudflare/workerd-linux-arm64",
1919
"linux x64 LE": "@cloudflare/workerd-linux-64",
20+
"win32 arm64 LE": "@cloudflare/workerd-windows-arm64",
2021
"win32 x64 LE": "@cloudflare/workerd-windows-64",
2122
};
2223

npm/scripts/build-shim-package.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function buildNeutralLib() {
1717
'@cloudflare/workerd-darwin-64': process.env.WORKERD_VERSION,
1818
'@cloudflare/workerd-linux-arm64': process.env.WORKERD_VERSION,
1919
'@cloudflare/workerd-linux-64': process.env.WORKERD_VERSION,
20+
'@cloudflare/workerd-windows-arm64': process.env.WORKERD_VERSION,
2021
'@cloudflare/workerd-windows-64': process.env.WORKERD_VERSION,
2122
};
2223
fs.writeFileSync(pjPath, JSON.stringify(package_json, null, 2) + '\n');

0 commit comments

Comments
 (0)