swift-flake: skip host cc-wrapper flags for every non-host -target (not just wasm32); Android bridge back to plain swiftc #41

Merged
founder merged 2 commits from claude/cranky-wu-a15bdd into main 2026-08-16 09:33:35 +00:00
Owner

Problem

Packages/swift-flake/build/wrapper.sh (the cc-wrapper-derived swiftc/swift wrapper that build.nix installs into both the swift-flake swift toolchain and the Android skip-swift-toolchain-6.2.3) only exempted -target wasm32* from host-flag injection. Every other non-host -target on Linux still sourced the clang-wrapper/bintools add-flags.sh + add-hardening.sh, synthesized the glibc SDKROOT/COMPILER_PATH, and appended -L<glibc>/lib, -B<glibc>/lib, -idirafter <glibc-dev>/include, -nostdlibinc, -resource-dir=<clang-wrapper>/resource-root, -Xlinker -dynamic-linker=<x86_64 ld.so> and the glibc/gcc -L dirs. That is what broke the Android bridge link (Build (Android) red 2026-06-19..08-16; #37 works around it by driving the unwrapped swift-driver).

Change

  • build.nix: substitute @defaultTarget@ = targetPlatform.config (the same value nixpkgs' cc-wrapper uses for its own defaultTarget; suffixSalt is derived from it).
  • wrapper.sh: replace isWasmTarget with isCrossTarget = "the last Swift -target/--target= is not the wrapper's host triple", after canonicalizing arm64-aarch64-, -apple-macosx/-apple-macos-apple-darwin and stripping OS versions (macosx14.0, android35). A cross target keeps the driver-mode / PATH / LD_LIBRARY_PATH / frontend plumbing and skips: SDKROOT + COMPILER_PATH/LIBRARY_PATH setup, bintools+cc add-flags.sh, add-hardening.sh, the link-flag / dynamic-linker injection, host -march-style flags, and the add-local-cc-cflags-before.sh hook (which for a cross target only printed cc-wrapper's multi-target warning). Values of pass-through flags (-Xcc -target …) are not mistaken for the Swift target; SwiftPM helpers (swift-build & co., whose --target is a module name and which compile host + cross code in one run) always count as host — the swiftc calls they spawn come back through the wrapper and are classified individually. Host builds (no -target, or the host -target) are unchanged. NIX_DEBUG>=1 prints the decision.
  • Scripts/build-android-bridge.sh: back to the plain wrapped swiftc (so Build (Android) exercises the wrapper's cross path like the wasm lane does); the per-ABI ELF-machine verification from #37 stays.

This changes the hash of every Swift toolchain derivation built from build.nix, so the web/wasm lane, lately macro plugin, KaiOS core and the Android skip toolchain rebuild once.

Verification (forge, x86_64-linux, this branch)

  • nix build .#web-container: rebuilt swift (6.3.2) → KaiOS core (host module emit + -target wasm32-unknown-wasip1 sidecar), swift-syntax-host (swift build --target SwiftCompilerPlugin through the helper wrapper), lately-macro-plugin (host link), lately-web-core (9.8 MB lately-core.wasm), site, image — all green.
  • nix develop .#android --command Scripts/build-android-bridge.sh with the rebuilt skip-swift-toolchain-6.2.3 and the plain wrapped swiftc: both ABIs link, llvm-readelf shows AArch64 / X86-64, libc++_shared.so in NEEDED and staged; wrapper NIX_DEBUG dump for both *-linux-android35 targets: cross=1, extra flags = --driver-mode=swiftc only, zero glibc/gcc/dynamic-linker paths in the whole log.
  • Host unchanged: old (main, f8h44vy7…-swift) vs new (g4vwlk5q…-swift) NIX_DEBUG=1 flag dumps for swiftc hello.swift inside a gcc stdenv env (NIX_CC set), with and without an explicit -target x86_64-unknown-linux-gnu, are identical apart from the new debug line and temp/output names; both binaries link and run. Bare invocations without NIX_CC fail identically old vs new (missing required module 'SwiftGlibc', pre-existing).
  • 42-case unit test of the triple detection/canonicalization (Linux + both Darwin defaultTarget spellings, -Xcc -target, last--target-wins, helper --target <module>).

Follow-up in flight: Build: Android workflow dispatch on this branch (Namespace runner) to cover the full bazel → prepare-skip-core → bridge → APK lane with the rebuilt toolchain.

🤖 Generated with Claude Code

## Problem `Packages/swift-flake/build/wrapper.sh` (the cc-wrapper-derived `swiftc`/`swift` wrapper that `build.nix` installs into both the swift-flake `swift` toolchain and the Android `skip-swift-toolchain-6.2.3`) only exempted `-target wasm32*` from host-flag injection. Every other non-host `-target` on Linux still sourced the clang-wrapper/bintools `add-flags.sh` + `add-hardening.sh`, synthesized the glibc `SDKROOT`/`COMPILER_PATH`, and appended `-L<glibc>/lib`, `-B<glibc>/lib`, `-idirafter <glibc-dev>/include`, `-nostdlibinc`, `-resource-dir=<clang-wrapper>/resource-root`, `-Xlinker -dynamic-linker=<x86_64 ld.so>` and the glibc/gcc `-L` dirs. That is what broke the Android bridge link (Build (Android) red 2026-06-19..08-16; #37 works around it by driving the unwrapped swift-driver). ## Change - **`build.nix`**: substitute `@defaultTarget@` = `targetPlatform.config` (the same value nixpkgs' cc-wrapper uses for its own `defaultTarget`; `suffixSalt` is derived from it). - **`wrapper.sh`**: replace `isWasmTarget` with `isCrossTarget` = "the last Swift `-target`/`--target=` is not the wrapper's host triple", after canonicalizing `arm64-`→`aarch64-`, `-apple-macosx`/`-apple-macos`→`-apple-darwin` and stripping OS versions (`macosx14.0`, `android35`). A cross target keeps the driver-mode / PATH / LD_LIBRARY_PATH / frontend plumbing and skips: SDKROOT + COMPILER_PATH/LIBRARY_PATH setup, bintools+cc `add-flags.sh`, `add-hardening.sh`, the link-flag / dynamic-linker injection, host `-march`-style flags, and the `add-local-cc-cflags-before.sh` hook (which for a cross target only printed cc-wrapper's multi-target warning). Values of pass-through flags (`-Xcc -target …`) are not mistaken for the Swift target; SwiftPM helpers (`swift-build` & co., whose `--target` is a module name and which compile host + cross code in one run) always count as host — the swiftc calls they spawn come back through the wrapper and are classified individually. Host builds (no `-target`, or the host `-target`) are unchanged. `NIX_DEBUG>=1` prints the decision. - **`Scripts/build-android-bridge.sh`**: back to the plain wrapped `swiftc` (so Build (Android) exercises the wrapper's cross path like the wasm lane does); the per-ABI ELF-machine verification from #37 stays. This changes the hash of every Swift toolchain derivation built from `build.nix`, so the web/wasm lane, lately macro plugin, KaiOS core and the Android skip toolchain rebuild once. ## Verification (forge, x86_64-linux, this branch) - `nix build .#web-container`: rebuilt `swift` (6.3.2) → KaiOS core (host module emit + `-target wasm32-unknown-wasip1` sidecar), `swift-syntax-host` (`swift build --target SwiftCompilerPlugin` through the helper wrapper), `lately-macro-plugin` (host link), `lately-web-core` (9.8 MB `lately-core.wasm`), site, image — all green. - `nix develop .#android --command Scripts/build-android-bridge.sh` with the rebuilt `skip-swift-toolchain-6.2.3` and the plain wrapped `swiftc`: both ABIs link, `llvm-readelf` shows AArch64 / X86-64, `libc++_shared.so` in NEEDED and staged; wrapper `NIX_DEBUG` dump for both `*-linux-android35` targets: `cross=1`, extra flags = `--driver-mode=swiftc` only, zero glibc/gcc/dynamic-linker paths in the whole log. - Host unchanged: old (main, `f8h44vy7…-swift`) vs new (`g4vwlk5q…-swift`) `NIX_DEBUG=1` flag dumps for `swiftc hello.swift` inside a gcc stdenv env (`NIX_CC` set), with and without an explicit `-target x86_64-unknown-linux-gnu`, are identical apart from the new debug line and temp/output names; both binaries link and run. Bare invocations without `NIX_CC` fail identically old vs new (`missing required module 'SwiftGlibc'`, pre-existing). - 42-case unit test of the triple detection/canonicalization (Linux + both Darwin `defaultTarget` spellings, `-Xcc -target`, last-`-target`-wins, helper `--target <module>`). Follow-up in flight: `Build: Android` workflow dispatch on this branch (Namespace runner) to cover the full bazel → prepare-skip-core → bridge → APK lane with the rebuilt toolchain. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The swiftc/swift wrapper (a cc-wrapper derivative) only exempted
`-target wasm32*` from host-flag injection. Any other cross target on Linux
still sourced the clang-wrapper/bintools add-flags.sh, add-hardening.sh and
the local-cc-cflags hook, synthesized the glibc SDKROOT/COMPILER_PATH, and
appended `-L<glibc>/lib`, `-B<glibc>/lib`, `-idirafter <glibc-dev>/include`,
`-nostdlibinc`, `-resource-dir=<clang-wrapper>/resource-root`,
`-Xlinker -dynamic-linker=<x86_64 ld.so>` and the glibc/gcc `-L` dirs. For
the Android bridge swift-driver handed those `-L` dirs to the NDK clang ahead
of the Android sysroot, `-lc` resolved to x86_64 glibc's libc.so linker
script and lld flipped to elf64-x86-64 (Build (Android) red 2026-06-19 ..
08-16; PR #37 works around it by driving the unwrapped swift-driver).

Generalize the exemption: build.nix now substitutes `@defaultTarget@`
(targetPlatform.config, the same value nixpkgs' cc-wrapper uses), and the
wrapper compares the last Swift `-target`/`--target=` against it after
canonicalizing arm64->aarch64, macosx/macos->darwin and stripping OS
versions. Anything that is not the host triple (wasm32, *-linux-android*,
*-linux-musl, other Darwin platforms) is a cross target: it keeps the
driver-mode/PATH/LD_LIBRARY_PATH/frontend plumbing but skips the SDKROOT and
COMPILER_PATH setup, add-flags, hardening, link-flag/dynamic-linker
injection, the host `-march`-style flags and the local-cc-cflags hook (which
for a cross target only printed cc-wrapper's multi-target warning). Values
of pass-through flags (`-Xcc -target ...`) are not mistaken for the Swift
target, and SwiftPM's helpers (whose `--target` is a module name and which
compile host and cross code in one run) always count as host. Host builds
with no `-target` or the host `-target` are unchanged. NIX_DEBUG>=1 now
prints the detected target and the decision.

Note: this changes the hash of every Swift toolchain derivation built from
build.nix (swift-flake `swift`, the Android skip-swift-toolchain), so the
web/wasm lane, the lately macro plugin, the KaiOS core and the Android bridge
all rebuild once.
android: link the Swift bridge with the plain wrapped swiftc again; keep the ELF check
Some checks failed
Build: Linux / Build (Linux x86_64) (pull_request) Has started running
Build: Apple / Check (SwiftLint) (pull_request) Successful in 1m2s
Build: Linux / Build (keystore-forge x86_64) (pull_request) Has been cancelled
Build: Apple / Build (visionOS) (pull_request) Has been cancelled
Build: Apple / Build (iOS) (pull_request) Has been cancelled
Build: Apple / Build (macOS) (pull_request) Has been cancelled
c0e93912d6
With the swift-flake wrapper now treating every non-host -target as a cross
target, the Android bridge no longer needs to sidestep it by driving the
unwrapped swift-driver (PR #37): `${toolchain}/usr/bin/swiftc` injects
nothing host-specific for aarch64/x86_64-unknown-linux-android35, so go back
to it and let Build (Android) exercise the wrapper's cross path like the
web/wasm lane does. verify_artifact_machine stays: it is what turns a future
host-flag leak into a loud per-ABI failure instead of a host-machine .so.

Verified on the forge (x86_64-linux) via `nix develop .#android` with the
rebuilt skip-swift-toolchain-6.2.3: both ABIs link (AArch64 / X86-64,
libc++_shared.so in NEEDED and staged), and the wrapper's NIX_DEBUG dump
shows only `--driver-mode=swiftc` added, no glibc/gcc/dynamic-linker paths.
founder force-pushed claude/cranky-wu-a15bdd from c0e93912d6
Some checks failed
Build: Linux / Build (Linux x86_64) (pull_request) Has started running
Build: Apple / Check (SwiftLint) (pull_request) Successful in 1m2s
Build: Linux / Build (keystore-forge x86_64) (pull_request) Has been cancelled
Build: Apple / Build (visionOS) (pull_request) Has been cancelled
Build: Apple / Build (iOS) (pull_request) Has been cancelled
Build: Apple / Build (macOS) (pull_request) Has been cancelled
to 0b3fe1c193
Some checks failed
Build: Apple / Check (SwiftLint) (pull_request) Successful in 17s
Build: Apple / Build (visionOS) (pull_request) Successful in 23s
Build: Apple / Build (iOS) (pull_request) Successful in 1m18s
Build: Apple / Build (macOS) (pull_request) Successful in 2m39s
Build: Linux / Build (Linux x86_64) (pull_request) Failing after 12m29s
Build: Linux / Build (keystore-forge x86_64) (pull_request) Has been skipped
2026-08-16 08:28:32 +00:00
Compare
founder force-pushed claude/cranky-wu-a15bdd from 0b3fe1c193
Some checks failed
Build: Apple / Check (SwiftLint) (pull_request) Successful in 17s
Build: Apple / Build (visionOS) (pull_request) Successful in 23s
Build: Apple / Build (iOS) (pull_request) Successful in 1m18s
Build: Apple / Build (macOS) (pull_request) Successful in 2m39s
Build: Linux / Build (Linux x86_64) (pull_request) Failing after 12m29s
Build: Linux / Build (keystore-forge x86_64) (pull_request) Has been skipped
to 9cc18a4bb2
Some checks failed
Build: Apple / Check (SwiftLint) (pull_request) Successful in 17s
Build: Linux / Build (Linux x86_64) (pull_request) Has been cancelled
Build: Linux / Build (keystore-forge x86_64) (pull_request) Has been cancelled
Build: Apple / Build (macOS) (pull_request) Has been cancelled
Build: Apple / Build (visionOS) (pull_request) Has been cancelled
Build: Apple / Build (iOS) (pull_request) Has been cancelled
2026-08-16 09:33:03 +00:00
Compare
founder force-pushed claude/cranky-wu-a15bdd from 9cc18a4bb2
Some checks failed
Build: Apple / Check (SwiftLint) (pull_request) Successful in 17s
Build: Linux / Build (Linux x86_64) (pull_request) Has been cancelled
Build: Linux / Build (keystore-forge x86_64) (pull_request) Has been cancelled
Build: Apple / Build (macOS) (pull_request) Has been cancelled
Build: Apple / Build (visionOS) (pull_request) Has been cancelled
Build: Apple / Build (iOS) (pull_request) Has been cancelled
to 180a43ef55
Some checks failed
Release: If Needed / Check (Release Needed) (push) Successful in 6s
Build: Apple / Check (SwiftLint) (pull_request) Successful in 19s
Build: Apple / Check (SwiftLint) (push) Successful in 16s
Build: Apple / Build (iOS) (pull_request) Successful in 27s
Build: Apple / Build (visionOS) (pull_request) Successful in 23s
Build: Apple / Build (visionOS) (push) Successful in 26s
Build: Apple / Build (iOS) (push) Successful in 1m17s
Build: Apple / Build (macOS) (pull_request) Successful in 1m48s
Build: Linux / Build (Linux x86_64) (pull_request) Has started running
Build: Linux / Build (Linux x86_64) (push) Has started running
Build: Apple / Build (macOS) (push) Successful in 1m51s
Deploy: API / Deploy (API) (push) Successful in 3m6s
Deploy: Web / Deploy (Web) (push) Successful in 4m53s
Build: Linux / Build (keystore-forge x86_64) (push) Has been cancelled
Build: Linux / Build (keystore-forge x86_64) (pull_request) Has been cancelled
2026-08-16 09:33:30 +00:00
Compare
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
key-store/key.store!41
No description provided.