Keith's PR #1827 changes (for review) - #6
Closed
AttilaTheFun wants to merge 8 commits into
Closed
Conversation
Add `swift.android_sdk`, which downloads the swift.org Android Swift SDK bundle
and defines a Swift toolchain targeting {aarch64,x86_64}-unknown-linux-android.
`swift_binary(linkshared = True)` produces a JNI lib<name>.so whose entry points
are written entirely in Swift; examples/cross_compilation builds one.
rules_swift does not fetch or manage the Android NDK. C/C++ compilation and
linking go through a separately registered Android C++ cc toolchain (e.g.
@androidndk//:all from hermetic_android_toolchains), and the Swift toolchain
reads that toolchain's sysroot at analysis time. Register one alongside the
Swift toolchain.
A few NDK-integration details handled in the Swift toolchain rule:
- rules_android_ndk's CcToolchainInfo.sysroot reports the clang dir, not the
sysroot, so we derive the sysroot from the toolchain's files.
- The Swift link action drives the NDK clang directly and bypasses the cc
toolchain's sysroot/runtime-lib link features, so for Android we add --sysroot
and stage libc++_shared.so (which the NDK clang links by default) into the
link ourselves.
- select_android_runtime_lib selects libc++_shared.so from the resolved cc
toolchain for APK packaging.
Verified end to end: //examples/cross_compilation:libSwiftJNI.so builds a real
aarch64 Android .so linked through @androidndk, and a downstream app packages it
into a working APK alongside libc++_shared.so.
…Swift) The cross_compilation example previously built only the JNI .so and documented (in prose) how a downstream module would package it into an APK. Replace that recipe with a real, building android_binary that runs on a device/emulator and shows the Swift greeting on screen — a far more compelling demonstration of integrating Swift into an Android app. It's packaged the real-world way, with rules_android (android_binary) and rules_kotlin (kt_android_library). The one rules_swift-specific detail: the swift_binary(linkshared) .so arrives via DefaultInfo (not CcInfo), so it's wrapped in a cc_library to feed android_binary's per-ABI native split; libc++ is selected via select_android_runtime_lib the same way. rules_android/rules_kotlin/rules_java/rules_jvm_external are all dev_dependency deps (with a pinned Maven lock and the hermetic @AndroidSDK), so consumers of rules_swift are unaffected. CI builds the APK via a build_test under --config=android_example (scoped flags; the rest of the build is untouched). Claude-Session: https://claude.ai/code/session_01SmG1kqA3qB4WsLGU2xavuJ
Toolchain: - Keep file_prefix_map enabled for Android (hermetic working-dir remap) instead of disabling it; the worker only requires DEVELOPER_DIR for the Apple developer-dir remap, so guard that remap on DEVELOPER_DIR being set (a cross compile on a macOS host has none). Fixes non-hermetic debug info. - Extract the Android link logic into _swift_android_linkopts_cc_info keyed on os == "android"; drop the redundant -lm (the clang driver links libm anyway; -lstdc++ stays, since it selects the shared libc++_shared.so the SDK intends). - Rename the SDK repo's host_swiftc attr to paired_swiftc. - Trim verbose comments/docs across the toolchain and extensions; simplify the clang-only error message. Example (//examples/cross_compilation/android_app): - Consolidate the Swift sources, Kotlin app, and BUILD into android_app/. - Build the .so as a dep of android_binary (its native split configures it for Android) instead of a hand-written platform transition; use the platforms rules_android exposes (@rules_android//:arm64-v8a) rather than a custom one. - Drop the manual tags; mark the Android-only targets target_compatible_with os:android so the //examples/... wildcard skips them on a host and the example runs in the normal macOS CI job. Remove the dedicated cross-compilation task. - Split the example's dev dependencies into android_app/android.MODULE.bazel, include()d from the root MODULE; move the Maven lock out of the repo root; link rules_android#485 for the maven.install requirement. - Set the rules_android flags (android_platforms + hermetic JDK) globally rather than behind a --config. Claude-Session: https://claude.ai/code/session_01SmG1kqA3qB4WsLGU2xavuJ
Per review, guard the Android cross-compile on CI without a device. Analysis tests (//test:android, macOS) assert the action command lines: - the Swift compile targets aarch64-linux-android, - the link runs the NDK clang for the Android target against the NDK sysroot and links libc++ as the shared libc++_shared.so, and - libc++_shared.so is staged into the link. Artifact tests on the example (run via build_test) cover what a build can't see: - android_so_abi_check runs the NDK llvm-readelf on the built .so to assert it is an AArch64 ELF that lists libc++_shared.so in NEEDED and exports the @_cdecl JNI entry point in .dynsym; - android_apk_contents_check asserts the APK packages both .so files under lib/arm64-v8a/ and the dexed Kotlin. Claude-Session: https://claude.ai/code/session_01SmG1kqA3qB4WsLGU2xavuJ
Adds //examples/cross_compilation/android_app:run, which installs the example APK on a connected device/emulator and launches it — booting a hermetic emulator first if nothing is connected, so the example runs with nothing preinstalled (no Android Studio, no device). adb comes from @AndroidSDK; the emulator + AOSP system image are downloaded by a dev module extension (emulator.bzl). macOS/arm64 only, to keep the delta small. Demonstrates what zero-setup 'bazel run' support would cost for the example. Claude-Session: https://claude.ai/code/session_01SmG1kqA3qB4WsLGU2xavuJ
Explains why -lstdc++ is needed: the Android cc toolchain links libc++ statically by default, so the shared libc++_shared.so must be forced. Claude-Session: https://claude.ai/code/session_01SmG1kqA3qB4WsLGU2xavuJ
Fixes the gazelle-up-to-date CI check. Uses the correct @rules_cc//cc:find_cc_toolchain_bzl label (gazelle's auto-generated find_cc_toolchain doesn't exist), matching swift/toolchains/BUILD. Claude-Session: https://claude.ai/code/session_01SmG1kqA3qB4WsLGU2xavuJ
Keith's Android implementation (bazelbuild#1827) as a single commit representing the delta against the prior android-support work: static libc++ (dropping the shared libc++_shared.so packaging and select_android_runtime_lib), validation moved into test/ test rules with a fixture APK, and all Android module wiring consolidated into android.MODULE.bazel.
AttilaTheFun
force-pushed
the
android-keith-review
branch
from
June 30, 2026 23:00
18a051e to
56ee71b
Compare
AttilaTheFun
force-pushed
the
android-support
branch
from
July 2, 2026 22:47
07dca6c to
1f7611c
Compare
Owner
Author
|
Superseded: keith pushed this delta directly and bazelbuild#1818 has merged upstream. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Keith's changes from his fork (bazelbuild#1827 / the gist) applied on
top of our
android-supporttip, so the delta is reviewable here. Squashed intoone commit because the upstream history is noisy.
The headline change: static libc++ instead of shared
libc++_shared.so— hedrops
-lstdc++, re-adds--exclude-libs,ALL+-export-dynamic, deletesselect_android_runtime_liband the example'slibcxxtargets. JNI symbols stayexported via
-export-dynamic+ rules_android_ndk's--undefined-glob.Other notable moves:
test/test rules (android_so_abi_test/android_apk_contents_test) against a self-contained fixture APK; usesllvm-nm+llvm-readelf, generalized needed/not-needed lists.MODULE.bazelis now entirely Android-free — all wiring moved intoandroid.MODULE.bazel(+ a newrules_android_ndkdep/override).DEVELOPER_DIRguard (back to unconditional).swift_sdk_linker_inputs; addedarmv7; enabled the exampleon Linux CI; hardened
run.sh's boot check; trimmed docs.Things to confirm with keith (see
~/Downloads/keith_pr1827_changes.mdfor thefull writeup):
DEVELOPER_DIRrevert — relies on it being set (CI-only) or genuinelyunneeded?
register_toolchains("@androidndk//:all")appears twice inandroid.MODULE.bazel— looks accidental.