Skip to content

Carry the Android API level into Swift's target triple#1857

Closed
AttilaTheFun wants to merge 1 commit into
bazelbuild:mainfrom
AttilaTheFun:android-api-level-triple
Closed

Carry the Android API level into Swift's target triple#1857
AttilaTheFun wants to merge 1 commit into
bazelbuild:mainfrom
AttilaTheFun:android-api-level-triple

Conversation

@AttilaTheFun

Copy link
Copy Markdown
Contributor

The NDK cc toolchain reports a level-less target_gnu_system_name (aarch64-linux-android), so Swift compiles with an availability floor below the SDK's actual minimum. Concretely, cross-compiling swift-log for Android fails with:

error: 'stdout' is only available in Android 23 or newer

even though the Swift Android SDK bundle itself declares aarch64-unknown-linux-android28 in its swift-sdk.json.

This PR:

  • adds an optional target_system_name attribute to swift_toolchain that overrides the cc-toolchain-derived triple, and
  • has the generated Android SDK toolchains pass the bundle's own triple, read from swift-sdk.json's targetTriples (API level included). The wasm toolchain generation is unchanged (empty override).

Verified by cross-compiling swift-log / swift-nio / grpc-swift-2 (via rules_swift_package_manager) for aarch64 Android and running a plaintext HTTP/2 gRPC round trip against a host server from the Android emulator:

greeter-client: Hey Universal UI! [seq=1 tags=grpc-swift-2,nio-http2]

@AttilaTheFun
AttilaTheFun marked this pull request as ready for review July 14, 2026 14:12
@AttilaTheFun
AttilaTheFun force-pushed the android-api-level-triple branch from 2727792 to f26da8d Compare July 14, 2026 14:28
The NDK cc toolchain reports a level-less target_gnu_system_name
(aarch64-linux-android), so Swift compiles with an availability floor
below the SDK's actual minimum - e.g. swift-log fails to build because
'stdout' is 'only available in Android 23 or newer', even though the
Swift Android SDK bundle itself declares aarch64-unknown-linux-android28.

- swift_toolchain gains an optional target_system_name attribute that
  overrides the cc-toolchain-derived triple.
- The generated Android SDK toolchains pass the bundle's own triple,
  read from swift-sdk.json's targetTriples (API level included).

Verified by cross-compiling swift-log / swift-nio / grpc-swift-2 for
aarch64 Android and running a gRPC round trip on-device.
@AttilaTheFun
AttilaTheFun force-pushed the android-api-level-triple branch from f26da8d to 5e26876 Compare July 14, 2026 15:08
@keith

keith commented Jul 14, 2026

Copy link
Copy Markdown
Member

is it safe for us to derive this versus trying to match what is setup by the user in their NDK toolchain setup?

@AttilaTheFun

AttilaTheFun commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

The Swift Android SDK bundle ships a per-API-level stdlib and declares the whole ladder it supports. For 6.3.2 that's <arch>-unknown-linux-android{28…36} for each arch (one swift-resources/.../swift-<arch> variant per level), with 28 as the floor. The prebuilt runtime won't load below it, so a Swift-on-Android binary can't target lower than 28 regardless of how the NDK is set up.

_sdk_triple_for_arch currently picks the lowest supported level (28). Two reasons it's safe in the narrow sense:

  1. It's the safe minimum. A binary built for min-28 runs on any device ≥28, and 28 is the lowest the SDK permits, so the derived value can never be wrong-low.
  2. It only fills a gap. The Swift target is target_triples.parse(ctx.var.get("CC_TARGET_TRIPLE") or target_system_name). Tf the NDK cc toolchain hands Swift an API-level-bearing triple via CC_TARGET_TRIPLE, that already wins and the derived value is never consulted. The bundle value only kicks in when the cc side gives Swift a level-less triple (aarch64-linux-android), which is exactly the case that was flooring availability and breaking swift-log.

But you're right that "derive" and "match the user's NDK" can diverge:

  • If a user configures their NDK for, say, minSdk 30, clang links --target=…android30 while Swift (falling back to the bundle floor) would compile at android28. That's safe over-conservative availability, and a min-28 binary is compatible with a min-30 app, but it isn't matching, and Swift would refuse APIs newer than 28 that the user might expect to have.
  • The attr is ctx.attr.target_system_name or cc_toolchain.target_gnu_system_name, so if a toolchain ever did report a level-bearing target_gnu_system_name, the derived attr would override it downward. Today the NDK's is level-less so it's not an issue right now though.

If you'd prefer we track the user's level rather than the bundle floor, the clean version is: take the API level the NDK is already configured with (the same min-sdk that drives clang's --target), select the bundle triple for that level (the bundle covers 28–36, so any in-range choice resolves), fall back to the floor only when the level is genuinely unknown, and never override a cc triple that already carries a level. That moves the value from "lowest the SDK supports" to "whatever the NDK is targeting," which I think is the behavior you're after.

@AttilaTheFun

Copy link
Copy Markdown
Contributor Author

Opened #1858 as an alternative that implements the "match the NDK's level" behavior I described above: an api_level knob on swift.android_sdk that selects the bundle triple for that level (falling back to the SDK's lowest supported level when unset), plus a rule that Swift never overrides a cc triple already carrying an API level.

This PR (#1857) keeps the simpler "always use the bundle floor" approach. They're behavior-identical for the common level-less NDK today; #1858 adds the knob + the don't-override guard. Happy to land whichever you prefer — I'll close the other.

@keith

keith commented Jul 15, 2026

Copy link
Copy Markdown
Member

#1859

@keith keith closed this Jul 15, 2026
@AttilaTheFun
AttilaTheFun deleted the android-api-level-triple branch July 16, 2026 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants