Built and verified 2026-04-20 on a Snapdragon X Elite (X1E80100), Windows 11 25H2 (build 26200), 64 GB RAM. The wheel and its build recipe are in this repo; every claim below is either read out of the shipped wheel or reproducible from the scripts here.
grpcio publishes no win_arm64 wheel on PyPI — for any Python version, at any patch level. On native Windows ARM64 the fallback is a from-source build inside pip install grpcio, which unpacks the vendored src/ and third_party/ tree from the sdist, invokes its bespoke setup.py, and takes roughly 45–60 minutes end-to-end when it works at all. Downstream reports of "unable to install grpcio" on ARM64 have been open on the pip tracker for over two years — the referenced tracking issue is pypa/pip#39362. This repo publishes a native grpcio-1.80.0-cp312-cp312-win_arm64.whl (4,489,895 bytes, sha256 in §9) built from the official 1.80.0 source tarball with the MSVC ARM64 toolchain, Python 3.12 ARM64, and Cython 3.1.1. The wheel is self-contained — its native extension cygrpc.cp312-win_arm64.pyd imports only Windows system DLLs and python312.dll, so no delvewheel repair, no msvcp140 mangling, no bundled runtime is required. pip install it and it works. The recipe here looks small; the four failed attempts that came before the working one (§§5–7, timeline in §8) are what makes it non-obvious.
# 1. ARM64 CPython 3.12 venv (the wheel is cp312-only)
<path-to-arm64-python-3.12>\python.exe -m venv .venv-arm64
# 2. Verify the wheel against the sha256 in §9 and install it:
# 4,489,895 bytes, sha256 1bd2fe31fae074ef469789e0a74226f4a360512de64aa2a7cf7000c363f597c8
.venv-arm64\Scripts\python -m pip install .\grpcio-1.80.0-cp312-cp312-win_arm64.whl
# 3. Smoke it — starts an in-process insecure server and opens a client channel to it
.venv-arm64\Scripts\python smoke_grpcio.py # expect: GRPCIO_SMOKE_OKThe wheel's only runtime requirement is typing-extensions~=4.12; pip install will pull it. If you plan to use the grpc-tools protoc plugin (for python -m grpc_tools.protoc), install it separately with pip install grpcio-tools>=1.80.0 — this repo does not ship a tools wheel.
| Item | Value |
|---|---|
| CPU | Snapdragon X Elite (X1E80100), 12 Oryon cores |
| OS / RAM | Windows 11 25H2 (build 26200) ARM64, 64 GB |
| Python | CPython 3.12 ARM64, isolated venv at C:\Users\you\.venv-arm64 |
| Compiler | VS 2022 Build Tools, MSVC ARM64 (VC\Tools\MSVC\<ver>\bin\HostARM64\arm64\cl.exe), Windows SDK 10.0.26100.0 ucrt/arm64 |
| Build tools | Cython 3.1.1, setuptools 82.0.1 (from the wheel's WHEEL metadata), build 1.3.x, wheel 0.29+ |
| Source | grpcio 1.80.0 sdist from PyPI (grpcio-1.80.0.tar.gz, unpacked in-place — the sdist bundles all C/C++ third-party sources it needs; no separate git submodule update is required for the sdist path) |
| Runtime dep | typing-extensions~=4.12 (the only wheel-declared requirement) |
Native binary evidence, read from the shipped wheel:
$ python -c "import pefile; pe = pefile.PE('cygrpc.cp312-win_arm64.pyd', fast_load=True); \
pe.parse_data_directories(directories=[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_IMPORT']]); \
print(hex(pe.FILE_HEADER.Machine)); \
[print(e.dll.decode()) for e in pe.DIRECTORY_ENTRY_IMPORT]"
0xaa64 # IMAGE_FILE_MACHINE_ARM64
ADVAPI32.dll # crypto/keys/registry — Windows-shipped
bcrypt.dll # BCrypt* — Windows-shipped
dbghelp.dll # crash diagnostics — Windows-shipped
WS2_32.dll # winsock — Windows-shipped
CRYPT32.dll # cert store — Windows-shipped
python312.dll # the venv's own interpreter
KERNEL32.dll # Win32 base — Windows-shipped
No msvcp140.dll, no vcruntime140*.dll, no third-party runtime — the extension links its C++ runtime statically (as grpcio's setup.py has done on Windows for years) and only touches system-provided DLLs at load time. This is why the wheel needs no delvewheel repair step.
grpcio's setup.py is not CMake-driven; it does everything through setuptools with a large C/C++ extension declaration and a handful of environment variables. The relevant ones for a native ARM64 build:
| Variable | Value | Why |
|---|---|---|
GRPC_PYTHON_BUILD_WITH_CYTHON |
1 |
Force the Cython path — the same one grpc's own CI uses. Without it, setup.py may try to use a pregenerated .c fallback, which is not maintained for every platform variant. |
GRPC_PYTHON_BUILD_WITH_SYSTEMD |
0 |
Linux-only feature; leave off on Windows. |
Everything else the build needs — OpenSSL, BoringSSL, c-ares, zlib, upb, abseil, re2, protobuf — is either statically linked from the vendored sources in src/ and third_party/ of the sdist or omitted entirely (protoc/tools live in the separate grpcio-tools package). The sdist is deliberately self-contained for exactly this reason: distros without git-submodule access can still build.
The MSVC toolchain has to be the native ARM64 one, not the cross-compiler. Enter it before invoking Python:
> vcvarsall.bat arm64
[vcvarsall.bat] Environment initialized for: 'arm64'
> where cl.exe
C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\<ver>\bin\HostARM64\arm64\cl.exe
If where cl.exe returns a HostX64\x64\cl.exe path, the ARM64 build will silently emit x86_64 objects and the wheel will fail to load at import time. build_grpcio_wheel.bat in this repo fails fast if the HostARM64\arm64 substring is missing.
Wheel stage (build_grpcio_wheel.bat in this repo, run inside vcvarsall arm64):
| Setting | Value | Why |
|---|---|---|
where cl.exe gate |
must contain HostARM64\\arm64 |
Prevents a silent x64-object build from a wrong vcvarsall (§2). |
GRPC_PYTHON_BUILD_WITH_CYTHON |
1 |
Force the Cython path (grpc CI parity). |
GRPC_PYTHON_BUILD_WITH_SYSTEMD |
0 |
Linux-only feature. |
| Cython | 3.1.1 |
Pinned to the version in grpcio 1.80.0's own requirements.txt — 3.2.x has generated-code diffs the setup expects Cython 3.1 for. |
| setuptools | >=77.0.1 |
grpcio 1.80.0 declares this floor. The wheel's WHEEL metadata records the version actually used: setuptools (82.0.1). |
| build backend | python -m build --wheel --no-isolation --outdir wheels |
--no-isolation uses the deps we just pinned in the venv rather than a fresh PEP-517 sandbox, so the Cython version is deterministic. |
| Output dir | %OUT% (default %BASE%\wheels) |
The wheel lands here as grpcio-1.80.0-cp312-cp312-win_arm64.whl. |
No CMake stage, no delvewheel repair, no --with-mangle — grpcio's Windows link line is already static-CRT and system-DLL-only. Verified after the fact by dumping the .pyd's imports (§1).
Same pitfall as the Windows_ARM64_PyArrow build: PowerShell's Start-Process cmd.exe -RedirectStandardOutput ... -RedirectStandardError ... runs cmd without a console, and vcvarsall.bat / vsdevcmd.bat spawn powershell.exe grandchildren that die mid-init in that mode — silently, with zero bytes in either redirected stream. The fix is to launch a wrapper .bat that redirects internally, and let PowerShell only detach it:
powershell Start-Process cmd.exe `
-ArgumentList '/c','C:\path\to\Windows_ARM64_grpcio\run_grpcio_build.bat' `
-WindowStyle Hiddenrun_grpcio_build.bat does call vcvarsall.bat arm64 first, then call build_grpcio_wheel.bat > out.log 2> err.log — the redirects run inside the (hidden) console cmd owns, so the grandchildren survive.
Watch grpcio_build.out.log for the two markers:
VCVARS_INITIALIZED rc=0— the vcvarsall arm64 call succeeded and theHostARM64\arm64\cl.exegate passed.GRPCIO_WHEEL_BUILD_OK—python -m buildfinished and the wheel landed in%OUT%.
The first attempt, run as plain pip install grpcio --no-binary :all: into an isolated PEP-517 build environment, died in the dependency install phase — grpcio's own compile never started. Cython 3.1.1 had no win_arm64 wheel on PyPI at the time, so pip's isolated build env tried to build cython from source. Its Cython.Compiler.Parsing extension compile failed under MSVC ARM64, and pip cascaded:
Building wheel for cython (pyproject.toml): finished with status 'error'
ERROR: Failed building wheel for cython
Failed to build cython
error: failed-wheel-build-for-install
ERROR: Failed to build 'grpcio' when installing build dependencies for grpcio
Attempt #2 responded with --no-build-isolation, but the base venv did not have setuptools' build backend importable, and pip crashed 11 minutes in with:
pip._vendor.pyproject_hooks._impl.BackendUnavailable: Cannot import 'setuptools.build_meta'
The fix that stuck: pre-install cython==3.1.1, setuptools>=77.0.1, wheel>=0.29, and build>=1.3.0 in the venv itself, then use --no-build-isolation so pip runs the build in the venv you already primed — no isolated env, no on-the-fly cython source build. That is exactly the sequence build_grpcio_wheel.bat runs before invoking python -m build.
With the build environment fixed, attempt #3 got into grpcio's own C compile — and died several thousand translation units in with:
C1083: Cannot open compiler generated file: '': Invalid argument
MSVC's C1083 '' (empty filename) is the diagnostic-that-isn't: cl.exe fails to open its own generated output file and cannot even echo which file. The failing /Fo argument in the surrounding command was one of the deepest paths in grpcio's tree:
/Fopyb\temp.win-arm64-cpython-312\Release\src\core\ext\upb-gen\envoy\extensions\
grpc_service\call_credentials\access_token\v3\access_token_credentials.upb_minitable.obj
The relative path is 165 characters. Attempt #3 ran with pip's default cwd of C:\Users\<you>\AppData\Local\Temp\pip-install-<rand>\grpcio_<hash>\ (~94 chars) — the combined path with a separator lands at 260 characters, right at Windows' MAX_PATH limit (which reserves one byte for the null terminator, leaving 259 usable). Under MAX_PATH pressure Windows returns ERROR_INVALID_NAME, which MSVC surfaces as C1083 with the filename it never got to write.
Partial fix (§7 has the rest): set TMP=C:\t before launching pip so pip's ephemeral extraction lives under a 4-char root instead of a 30-char one. This alone is not enough; §7 explains why.
Attempt #4 launched with TMP=C:\t in effect; pip's cwd became C:\t\pip-install-9wbvo1vc\grpcio_884f6a543d8b433fa7bb290c66bc2ca3\ (65 chars). Every translation unit compiled — the log ran to 26.5 MB, larger than any prior attempt — and the failure shifted to link time:
LINK : fatal error LNK1181: cannot open input file
'pyb\temp.win-arm64-cpython-312\Release\src\core\ext\upb-gen\envoy\extensions\
load_balancing_policies\client_side_weighted_round_robin\v3\
client_side_weighted_round_robin.upb_minitable.obj'
The .obj was written correctly by cl.exe — the on-disk file survives in the build tree. What broke was link.exe's re-open of it via the response file: the relative path is 187 characters, and the pip-install cwd (65 chars) plus a separator plus that path lands at 253 characters — a hair under the 259 usable bytes MAX_PATH gives you, with no headroom for whatever the linker's response-file expansion adds when it opens each input. LNK1181 with a truncated filename in the diagnostic is the fingerprint.
Fix that stuck: stop letting pip pick the working directory. Download the sdist manually, unpack it under a short root, and run pip wheel . from inside the unpacked tree so pip has no pip-install-<rand>\grpcio_<hash>\ layer to add:
mkdir C:\t\grpcio-1.80.0
tar -xzf grpcio-1.80.0.tar.gz -C C:\t
cd C:\t\grpcio-1.80.0
python -m pip wheel . --no-build-isolation --wheel-dir C:\t\wheelsThat drops the build-tree cwd from 65 characters (attempt #4) to ~20, which is what put attempt #5 over the finish line. build_grpcio_wheel.bat in this repo assumes you have already unpacked the sdist into %SRC% and does the same python -m build --wheel . from that dir.
All times UTC, 2026-04-19 → 2026-04-20:
| # | Started | Log | Died at | Outcome |
|---|---|---|---|---|
| 1 | 04-19 16:09 | 761 KB | pip build-dep install (cython source build under isolation) | Failed |
| 2 | 04-19 16:20 | 12.6 KB | pip PEP-517 backend load (Cannot import 'setuptools.build_meta') |
Failed |
| 3 | 04-19 17:30 | 3.3 MB | cl.exe compile — C1083 '' on upb-gen access_token .obj |
Failed |
| 4 | 04-19 23:03 | 26.5 MB | link.exe — LNK1181 on upb-gen client_side_weighted_round_robin .obj |
Failed |
| 5 | 04-20 08:18 | 26.4 MB | — | Successfully built grpcio — sha256 in §9 |
Elapsed from first attempt to working wheel: 16 hours 9 minutes across five attempts. The three fixes that shifted the failure surface were, in order: pre-install cython 3.1.1 + setuptools 77.0.1+ in the venv and pass --no-build-isolation (fixed #1 and #2); set TMP=C:\t to shorten pip's ephemeral root (fixed #3); manually unpack the sdist and pip wheel . from the unpacked tree so pip cannot introduce a pip-install-<rand>\grpcio_<hash>\ subdirectory (fixed #4).
- File:
grpcio-1.80.0-cp312-cp312-win_arm64.whl - Size: 4,489,895 bytes (4.28 MiB)
- sha256:
1bd2fe31fae074ef469789e0a74226f4a360512de64aa2a7cf7000c363f597c8 - Wheel tag:
cp312-cp312-win_arm64(CPython 3.12, ARM64 only) - Metadata generator:
setuptools (82.0.1)(fromgrpcio-1.80.0.dist-info/WHEEL) - Wheel-declared runtime dep:
typing-extensions~=4.12 - Optional extra:
protobuf→grpcio-tools>=1.80.0 - Files in the wheel: 65 total. The native extension is
grpc/_cython/cygrpc.cp312-win_arm64.pyd(10,488,320 bytes, ARM64, imports listed in §1). Root CA bundlegrpc/_cython/_credentials/roots.pem(264,440 bytes) is shipped verbatim from the source tree. Everything else is Python source and metadata.
Verify the sha256 before installing:
Get-FileHash -Algorithm SHA256 .\grpcio-1.80.0-cp312-cp312-win_arm64.whl
# Hash should be: 1BD2FE31FAE074EF469789E0A74226F4A360512DE64AA2A7CF7000C363F597C8smoke_grpcio.py starts an in-process insecure server, opens a client channel, waits for READY, then tears both down. It exercises: .pyd import (cygrpc.cp312-win_arm64.pyd loads and its DLL imports resolve), gRPC core initialization, add_insecure_port(0) (kernel-assigned port via ws2_32.dll), server startup, channel connectivity state machine, clean shutdown.
Expected output shape:
python: 3.12.<x> win32
grpc: 1.80.0
cygrpc module: <venv>\Lib\site-packages\grpc\_cython\cygrpc.cp312-win_arm64.pyd
server: listening on 127.0.0.1:<port>
channel state: 0
channel state: 2
channel state: 3
GRPCIO_SMOKE_OK
(0/2/3 are the C enum values for IDLE / CONNECTING / READY in the grpc_connectivity_state enum — the READY transition is what proves the client half of the stack works too.)
If the .pyd fails to load, you will see ImportError naming the missing DLL — with the imports enumerated in §1, the only realistic cause is a broken CPython install or an antivirus that quarantined the .pyd.
- cp312-only wheel. Built against CPython 3.12 ABI. Python 3.11 and 3.13 need their own builds — run
build_grpcio_wheel.batinside the corresponding ARM64 venv (update%PYEXE%to point at it; the Cython 3.1.1 pin is fine across cp3.10–cp3.13). - Windows ARM64 only. Wheel tag is
win_arm64; it will not install on x86_64 or any other platform. - Must build from a short absolute path. grpcio's upb-gen tree has 190+ char relative paths that put MAX_PATH within reach; do not run the build out of
%USERPROFILE%\...\Temp\or let pip pick the cwd via apip install --no-binaryon the package name. Unpack the sdist under a short root (e.g.C:\t\grpcio-1.80.0\) andpip wheel .from inside it, exactly asbuild_grpcio_wheel.batdoes. §§6–7 have the failure modes both halves of that rule prevent. - grpcio 1.80.0. This is not the latest grpcio — the current release is higher by several minor versions as of the read date. The recipe should port forward without change (grpcio's Windows setup.py path is stable), but each new minor may bring vendored-dep bumps that need re-verification.
- No grpcio-tools. This repo ships only
grpcio.grpcio-tools(protoc + the Python plugin) is a separate build and is not included; if you needpython -m grpc_tools.protoc, it will also need a from-source native build on ARM64 (or use an x86_64-emulated Python for the codegen step only). - MSVC ARM64 toolchain required. Build assumes VS 2022 Build Tools with the native ARM64 compiler and a recent Windows 11 ARM64 SDK. Cross-compiling from an x64 host is a different exercise this recipe does not cover.
- One machine, one day. The wheel was built on a single Snapdragon X Elite session; re-run
smoke_grpcio.pyand your own workload on your hardware to validate.
Everything above is produced by the two .bat scripts and one smoke script in this repo. On your own ARM64 box:
-
Toolchain: VS 2022 Build Tools with the MSVC C++ ARM64 component and a Windows 11 ARM64 SDK. Verify the compiler after
vcvarsall.bat arm64—where cl.exemust report aHostARM64\arm64\cl.exepath. Also install an ARM64 CPython 3.12. -
Source: download the official grpcio 1.80.0 sdist from PyPI —
# Bare-metal download; verify against PyPI's own file listing Invoke-WebRequest -Uri "https://files.pythonhosted.org/packages/source/g/grpcio/grpcio-1.80.0.tar.gz" ` -OutFile grpcio-1.80.0.tar.gz tar -xzf grpcio-1.80.0.tar.gz # unpacks to .\grpcio-1.80.0\
The sdist bundles all
src/andthird_party/sources it needs; no separate git clone or submodule update is required. -
Build deps in the venv (versions from grpcio 1.80.0's own
requirements.txtplus PEP 517 build):cython==3.1.1,setuptools>=77.0.1,wheel>=0.29,build>=1.3.0,typing-extensions==4.12.2. -
Edit placeholders.
build_grpcio_wheel.batandrun_grpcio_build.batuseC:\Users\you\...placeholders at the top (BASE,SRC,OUT,PYEXE,VCVARSALL). Point them at your own directories and the ARM64 Python 3.12 venv before launching. -
Wheel stage: launch the pattern-B wrapper — never
Start-Processwith stream redirection (§4):powershell Start-Process cmd.exe -ArgumentList '/c', ` 'C:\Users\you\GitHub_Repos\Windows_ARM64_grpcio\run_grpcio_build.bat' ` -WindowStyle Hidden
Watch
grpcio_build.out.logforVCVARS_INITIALIZED rc=0, thenGRPCIO_WHEEL_BUILD_OK. Wall-clock on the build machine was 45–50 minutes end-to-end at-j8(attempt #5 in §8: 07:31 sdist read → 08:18 wheel written). grpcio's setup.py builds a large number of small C/C++ translation units serially in stretches, so the parallelism win is smaller than a CMake+Ninja build like Arrow's. -
Install and verify per the step-by-step instructions above:
pip installthe wheel, thensmoke_grpcio.py→GRPCIO_SMOKE_OK.
PolyForm Noncommercial 1.0.0 — see LICENSE. Required Notice: Copyright 2026 LucRoot (info@lucasroot.com). This repo redistributes a wheel built from grpcio 1.80.0 sources; grpcio itself remains Apache-2.0 (its LICENSE ships inside the wheel at grpcio-1.80.0.dist-info/licenses/LICENSE).
Author: Dr. Lucas Root, Ph.D. — info@lucasroot.com