Hi everyone,
I was working on a bare-metal kernel AetherKernel for the Raspberry Pi 4 (Cortex-A72) using Embedded Swift. Since the natural target for a bare-metal AArch64 kernel is aarch64-none-none-elf, I hit a blocker: the toolchain does not build or ship libswift_Concurrency.a for this triple.
To get the concurrency runtime onto the board, I'm using a workaround: I target arm64-apple-none-macho instead (same AArch64 ISA, Mach-O container), -force_load its concurrency library, and post-process the Mach-O binary into a flat kernel8.img. This works great—async/await and a custom SerialExecutor run successfully on the hardware—but it means compiling a non-Apple bare-metal kernel through an Apple-platform triple purely to obtain the _Concurrency archive.
The Build System Root Cause
During the Swift 6.4 cycle, several updates have expanded non-Darwin embedded concurrency support:
- Commit f161a60e1213 extended the macOS-host arch filter in
stdlib/public/Concurrency/CMakeLists.txtto add ARMv8-M targets (armv8m.main|armv8.1m.main). - Commit 01ac09a1792e fixed SDK macro handling for non-Darwin embedded targets.
This indicates that _Concurrency is actively being brought up across the embedded target matrix. However, the ELF spelling of ARM64 (aarch64) appears to have been missed.
Looking at the build configuration in release/6.4.x (verified at commit 9140a9cd4ec5):
First, aarch64-none-none-elf is defined as a first-class embedded stdlib target in stdlib/public/CMakeLists.txt:
if("AArch64" IN_LIST LLVM_TARGETS_TO_BUILD)
list(APPEND EMBEDDED_STDLIB_TARGET_TRIPLES
"aarch64 aarch64-none-none-elf aarch64-none-none-elf"
)
endif()
Second, in stdlib/public/Concurrency/CMakeLists.txt, the macOS-host architecture filter drops it during the loop over EMBEDDED_STDLIB_TARGET_TRIPLES (line 322):
elseif (SWIFT_HOST_VARIANT STREQUAL "macosx")
if(NOT "${mod}" MATCHES "x86_64|arm64|arm64e|armv7|armv7m|armv7em|armv8m.main|armv8.1m.main")
continue() # line 324 — mod="aarch64-none-none-elf" matches nothing here
endif()
arm64-apple-none-macho matches arm64 and builds, but aarch64-none-none-elf matches nothing (since arm64 is not a substring of aarch64) and gets skipped. The Linux-host path (lines 318-321) also skips it.
Third, the CPU-define branch (line 337) only matches arm64 and misses aarch64:
elseif("${arch}" MATCHES "arm64")
list(APPEND extra_c_compile_flags -DTARGET_CPU_ARM64=1)
Proposed Fix
Since the architecturally identical Mach-O triple already compiles and runs this runtime on bare metal, there doesn't seem to be an architectural blocker.
The fix appears to be adjusting two lines in stdlib/public/Concurrency/CMakeLists.txt:
- Add
aarch64to the host arch filter:"x86_64|aarch64|arm64|..." - Update the CPU define:
elseif("${arch}" MATCHES "arm64|aarch64")
Is this omission intentional, or is it an oversight? If it's the latter, I'd be happy to open a pull request to resolve this. I'd also appreciate any guidance on how the working group prefers build-configuration changes like this to be verified/tested in the compiler repo.
Thanks!