Problem
aws-lc-sys v0.37.0 produces unresolved external symbol errors for __builtin_bswap32, __builtin_bswap64, and __builtin_bswap16 when building on Windows CI runners (Blacksmith blacksmith-4vcpu-windows-2025). This blocks all Windows desktop release builds.
Branch: release-build-fixes
Error (identical across 20+ CI runs):
libaws_lc_sys-f3cfa6bd59120afa.rlib(5e7b0e08b07b6019-bcm.o) : error LNK2019: unresolved external symbol __builtin_bswap32 referenced in function CRYPTO_bswap4
libaws_lc_sys-f3cfa6bd59120afa.rlib(5e7b0e08b07b6019-bcm.o) : error LNK2019: unresolved external symbol __builtin_bswap64 referenced in function CRYPTO_bswap8
libaws_lc_sys-f3cfa6bd59120afa.rlib(aa3883b9c76e19d7-cbb.o) : error LNK2019: unresolved external symbol __builtin_bswap16 referenced in function CRYPTO_bswap2
C:\runner\_work\spacedrive\spacedrive\target\release\deps\iroh_relay-f3f13ac3990b19b7.dll : fatal error LNK1120: 3 unresolved externals
The linker is MSVC's link.exe. The affected crates are iroh-relay and rustls-platform-verifier, both linking against aws_lc_sys.
Root Cause Analysis
aws-lc-sys has a compiler feature detection step in its build script (cc_builder.rs line ~732):
if self.compiler_check("builtin_swap_check", Vec::<&'static str>::new()) {
cc_build.define("AWS_LC_BUILTIN_SWAP_SUPPORTED", Some("1"));
}
This test compiles builtin_swap_check.c which uses __builtin_bswap16/32/64. If the detected compiler supports these GCC builtins, it defines AWS_LC_BUILTIN_SWAP_SUPPORTED, causing the actual C source (crypto/internal.h) to use __builtin_bswap* instead of MSVC's _byteswap_ulong.
The problem is a compiler mismatch: aws-lc-sys uses the cc crate to detect the compiler (which finds clang-cl from the LLVM installation we install for bindgen), so the builtin check passes. But the actual CMake build uses the Visual Studio generator which compiles with MSVC cl.exe. MSVC treats __builtin_bswap* as regular extern function calls → unresolved at link time.
Critically, the cc crate does not respect CMAKE_C_COMPILER — it only checks CC, CC_<target>, and TARGET_CC environment variables. We spent many iterations setting CMAKE_C_COMPILER before discovering this.
Why LLVM is Installed
We install LLVM 15 via KyleMayes/install-llvm-action@v2 specifically for bindgen, which needs libclang.dll. The install-llvm-action adds C:\Program Files\LLVM\bin to PATH via core.addPath(), which makes clang-cl.exe discoverable to the cc crate.
Everything We Tried
All attempts on the release-build-fixes branch, each taking ~20 min to validate:
Attempt 1: Remove lld-link from xtask linker detection
- Removed
lld-link from xtask/src/system.rs get_best_linker()
- Result: Same error, just with
link.exe instead of lld-link (this was a linker issue, not the root cause)
Attempt 2: Install NASM
- Added
ilammy/setup-nasm@v1 for Windows in release.yml
- Theory: NASM would let aws-lc-sys use assembly instead of C fallbacks
- Result: Same error — NASM doesn't eliminate C compilation for bswap code paths
Attempt 3: Set CC=cl and CXX=cl on tauri-action build step
- Added
CC: cl and CXX: cl env vars to the build step
- Result: Same error — suspected cargo cache restoring old artifact
Attempt 4: Bust cargo cache (stable-cache-v2)
- Changed Swatinem/rust-cache
shared-key from stable-cache to stable-cache-v2
- Result: Same error
Attempt 5: Add CMAKE_C_COMPILER and CMAKE_CXX_COMPILER
- Added these env vars to the build step
- Result: Same error — aws-lc-sys ignores these (uses
cc crate, not cmake env vars)
Attempt 6: Set CC=cl via GITHUB_ENV in setup-system
- Set
CC=cl, CXX=cl, CMAKE_C_COMPILER=cl, CMAKE_CXX_COMPILER=cl via $GITHUB_ENV
- Result: NEW error:
ToolNotFound: failed to find tool "cl" — the cc crate can't find cl via simple PATH lookup; its built-in MSVC detection requires CC to NOT be set
Attempt 7: Remove LLVM from PATH with sed
- Tried removing LLVM bin from PATH using sed in a bash step, set LIBCLANG_PATH for bindgen
- Result: Same original error — GITHUB_PATH entries (from
core.addPath()) are always prepended to PATH at every step, overriding GITHUB_ENV changes
Attempt 8: Rename clang executables
- Physically renamed
clang.exe, clang++.exe, clang-cl.exe to .bak in LLVM bin
- Set LIBCLANG_PATH for bindgen, didn't set CC/CXX
- Result: Same error — cache from v2 may have been poisoned
Attempt 9: Cache bust to v3 + verification step
- Bumped shared-key to
stable-cache-v3
- Added verification step that fails if
Get-Command clang still finds clang
- Result: Same error
Attempt 10: Delete ALL .exe files from LLVM\bin
- Instead of renaming 3 specific files, deleted every
.exe in C:\Program Files\LLVM\bin
- Also removed LLVM CMake config directory
- Also checked for VS-bundled Clang at multiple VS installation paths
- Set
CMAKE_C_COMPILER to cl.exe full path via vswhere
- Bumped cache to v4
- Result: Same error —
CMAKE_C_COMPILER is irrelevant because aws-lc-sys uses the cc crate
Attempt 11: Set CC to cl.exe full path via vswhere
- Used vswhere to find cl.exe absolute path
- Set
CC, CXX, CMAKE_C_COMPILER, CMAKE_CXX_COMPILER via GITHUB_ENV
- Bumped cache to v5
- Result: Same error — still happening, the CC env var via GITHUB_ENV may not be reaching the build step, or the
cc crate's behavior with full paths needs investigation
What We Know For Sure
- The
.rlib hash f3cfa6bd59120afa is a cargo metadata hash (deterministic, not cache-dependent)
- The error persists through fresh caches (v2 through v5), confirming it's freshly compiled each time
- The
cc crate ignores CMAKE_C_COMPILER — only reads CC/CC_<target>/TARGET_CC
- aws-lc-sys's
builtin_swap_check creates a mismatch between compiler detection (cc crate → finds clang-cl) and actual compilation (CMake Visual Studio generator → uses MSVC cl.exe)
iroh already uses ring (not aws-lc-rs), but aws-lc-rs is still pulled in by other transitive deps (tokio-rustls defaults, sqlx, etc.)
Potential Solutions (Not Yet Tried)
-
Remove aws-lc-rs from the dependency tree entirely — switch all rustls consumers to use ring instead. Complex due to transitive dependency feature unification (tokio-rustls, sqlx, etc. all enable aws-lc-rs by default).
-
Don't install full LLVM — download only libclang.dll for bindgen instead of the full LLVM toolchain. Eliminates clang-cl from the system entirely.
-
Investigate why CC env var via GITHUB_ENV isn't reaching the build — the tauri-action might have its own env handling that overrides GITHUB_ENV.
-
Set CC directly on the tauri-action build step — instead of via GITHUB_ENV in an earlier step, set it in the env: block of the build step itself using vswhere output.
-
File upstream issue on aws-lc-rs — the compiler detection mismatch between cc crate and cmake builder is arguably a bug in aws-lc-sys.
Related Upstream Issues
Problem
aws-lc-sysv0.37.0 produces unresolved external symbol errors for__builtin_bswap32,__builtin_bswap64, and__builtin_bswap16when building on Windows CI runners (Blacksmithblacksmith-4vcpu-windows-2025). This blocks all Windows desktop release builds.Branch:
release-build-fixesError (identical across 20+ CI runs):
The linker is MSVC's
link.exe. The affected crates areiroh-relayandrustls-platform-verifier, both linking againstaws_lc_sys.Root Cause Analysis
aws-lc-syshas a compiler feature detection step in its build script (cc_builder.rsline ~732):This test compiles
builtin_swap_check.cwhich uses__builtin_bswap16/32/64. If the detected compiler supports these GCC builtins, it definesAWS_LC_BUILTIN_SWAP_SUPPORTED, causing the actual C source (crypto/internal.h) to use__builtin_bswap*instead of MSVC's_byteswap_ulong.The problem is a compiler mismatch: aws-lc-sys uses the
cccrate to detect the compiler (which findsclang-clfrom the LLVM installation we install for bindgen), so the builtin check passes. But the actual CMake build uses the Visual Studio generator which compiles with MSVCcl.exe. MSVC treats__builtin_bswap*as regular extern function calls → unresolved at link time.Critically, the
cccrate does not respectCMAKE_C_COMPILER— it only checksCC,CC_<target>, andTARGET_CCenvironment variables. We spent many iterations settingCMAKE_C_COMPILERbefore discovering this.Why LLVM is Installed
We install LLVM 15 via
KyleMayes/install-llvm-action@v2specifically forbindgen, which needslibclang.dll. Theinstall-llvm-actionaddsC:\Program Files\LLVM\binto PATH viacore.addPath(), which makesclang-cl.exediscoverable to thecccrate.Everything We Tried
All attempts on the
release-build-fixesbranch, each taking ~20 min to validate:Attempt 1: Remove lld-link from xtask linker detection
lld-linkfromxtask/src/system.rsget_best_linker()link.exeinstead oflld-link(this was a linker issue, not the root cause)Attempt 2: Install NASM
ilammy/setup-nasm@v1for Windows in release.ymlAttempt 3: Set CC=cl and CXX=cl on tauri-action build step
CC: clandCXX: clenv vars to the build stepAttempt 4: Bust cargo cache (stable-cache-v2)
shared-keyfromstable-cachetostable-cache-v2Attempt 5: Add CMAKE_C_COMPILER and CMAKE_CXX_COMPILER
cccrate, not cmake env vars)Attempt 6: Set CC=cl via GITHUB_ENV in setup-system
CC=cl,CXX=cl,CMAKE_C_COMPILER=cl,CMAKE_CXX_COMPILER=clvia$GITHUB_ENVToolNotFound: failed to find tool "cl"— thecccrate can't findclvia simple PATH lookup; its built-in MSVC detection requires CC to NOT be setAttempt 7: Remove LLVM from PATH with sed
core.addPath()) are always prepended to PATH at every step, overriding GITHUB_ENV changesAttempt 8: Rename clang executables
clang.exe,clang++.exe,clang-cl.exeto.bakin LLVM binAttempt 9: Cache bust to v3 + verification step
stable-cache-v3Get-Command clangstill finds clangAttempt 10: Delete ALL .exe files from LLVM\bin
.exeinC:\Program Files\LLVM\binCMAKE_C_COMPILERto cl.exe full path via vswhereCMAKE_C_COMPILERis irrelevant because aws-lc-sys uses thecccrateAttempt 11: Set CC to cl.exe full path via vswhere
CC,CXX,CMAKE_C_COMPILER,CMAKE_CXX_COMPILERvia GITHUB_ENVcccrate's behavior with full paths needs investigationWhat We Know For Sure
.rlibhashf3cfa6bd59120afais a cargo metadata hash (deterministic, not cache-dependent)cccrate ignoresCMAKE_C_COMPILER— only readsCC/CC_<target>/TARGET_CCbuiltin_swap_checkcreates a mismatch between compiler detection (cc crate → finds clang-cl) and actual compilation (CMake Visual Studio generator → uses MSVC cl.exe)irohalready usesring(notaws-lc-rs), butaws-lc-rsis still pulled in by other transitive deps (tokio-rustlsdefaults,sqlx, etc.)Potential Solutions (Not Yet Tried)
Remove aws-lc-rs from the dependency tree entirely — switch all rustls consumers to use
ringinstead. Complex due to transitive dependency feature unification (tokio-rustls, sqlx, etc. all enable aws-lc-rs by default).Don't install full LLVM — download only
libclang.dllfor bindgen instead of the full LLVM toolchain. Eliminates clang-cl from the system entirely.Investigate why CC env var via GITHUB_ENV isn't reaching the build — the tauri-action might have its own env handling that overrides GITHUB_ENV.
Set CC directly on the tauri-action build step — instead of via GITHUB_ENV in an earlier step, set it in the
env:block of the build step itself using vswhere output.File upstream issue on aws-lc-rs — the compiler detection mismatch between cc crate and cmake builder is arguably a bug in aws-lc-sys.
Related Upstream Issues