From 6c1b007b215b2b76af3c246b41f49fc29459faf2 Mon Sep 17 00:00:00 2001 From: Logan Shire Date: Wed, 24 Jun 2026 20:25:07 -0400 Subject: [PATCH 1/8] Support cross-compiling to Android with a Swift SDK 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.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. --- .bazelci/presubmit.yml | 14 ++ .bazelrc | 6 + MODULE.bazel | 46 +++- doc/standalone_toolchain.md | 103 ++++++++ examples/cross_compilation/BUILD.bazel | 45 ++++ examples/cross_compilation/README.md | 55 +++++ .../Sources/Greeter/Greeter.swift | 14 ++ .../Sources/SwiftJNI/SwiftJNI.swift | 24 ++ .../android_app/AndroidManifest.xml | 19 ++ .../cross_compilation/android_app/README.md | 127 ++++++++++ .../java/com/example/swiftjni/MainActivity.kt | 15 ++ .../java/com/example/swiftjni/NativeBridge.kt | 19 ++ swift/extensions.bzl | 130 ++++++++++ swift/internal/extensions/BUILD.bazel.tpl | 48 ++++ .../extensions/swift_sdk_releases.bzl | 23 +- swift/internal/extensions/swift_sdks.bzl | 230 ++++++++++-------- swift/internal/extensions/toolchains.bzl | 47 +++- swift/toolchains/BUILD | 7 + swift/toolchains/android_runtime_lib.bzl | 47 ++++ swift/toolchains/swift_toolchain.bzl | 46 +++- 20 files changed, 943 insertions(+), 122 deletions(-) create mode 100644 examples/cross_compilation/BUILD.bazel create mode 100644 examples/cross_compilation/README.md create mode 100644 examples/cross_compilation/Sources/Greeter/Greeter.swift create mode 100644 examples/cross_compilation/Sources/SwiftJNI/SwiftJNI.swift create mode 100644 examples/cross_compilation/android_app/AndroidManifest.xml create mode 100644 examples/cross_compilation/android_app/README.md create mode 100644 examples/cross_compilation/android_app/java/com/example/swiftjni/MainActivity.kt create mode 100644 examples/cross_compilation/android_app/java/com/example/swiftjni/NativeBridge.kt create mode 100644 swift/toolchains/android_runtime_lib.bzl diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 5626e8a51..aa84b9019 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -62,6 +62,20 @@ tasks: bazel: last_green <<: *mac_common + macos_cross_compilation: + name: "Cross-compilation (Android)" + platform: macos_arm64 + xcode_version: "26.2" + bazel: latest + # The //examples/cross_compilation targets are tagged `manual` (they fetch + # the Swift SDK bundle and the NDK), so they are excluded from the + # `//examples/...` wildcard the other tasks build. List them explicitly here + # so the Swift-SDK cross-compilation toolchains are exercised in CI. + # Build-only: the trivial JNI library exercises the link path, while runtime + # behavior is covered downstream by real consumers. + build_targets: + - "//examples/cross_compilation:libSwiftJNI.so" + macos_latest_shell_scripts: name: "macOS shell tests" platform: macos_arm64 diff --git a/.bazelrc b/.bazelrc index 0f9e3bf81..8a9de7fd6 100644 --- a/.bazelrc +++ b/.bazelrc @@ -22,6 +22,12 @@ build --worker_sandboxing build --enable_platform_specific_config +# Accept the Android NDK/SDK licenses for hermetic_android_toolchains' @androidndk +# (the Android cc toolchain used by //examples/cross_compilation). Only consulted +# when those repositories are fetched. +common --repo_env=ACCEPTED_ANDROID_NDK_LICENSE_VERSION=r27c +common --repo_env=ACCEPTED_ANDROID_SDK_LICENSE_VERSION=35 + common:linux --repo_env=CC=clang build:linux --cxxopt='-std=c++17' --host_cxxopt='-std=c++17' common:linux --//test:apple_build_tests=False diff --git a/MODULE.bazel b/MODULE.bazel index 30e9a8029..ad2d25029 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -82,7 +82,10 @@ use_repo(system_sdk, "system_sdk") swift = use_extension("//swift:extensions.bzl", "swift", dev_dependency = True) swift.toolchain( name = "swift_toolchain", - swift_version = "6.3", + swift_version = "6.3.2", +) +swift.android_sdk( + toolchain_name = "swift_toolchain", ) use_repo( swift, @@ -110,6 +113,47 @@ register_toolchains( dev_dependency = True, ) +register_toolchains( + # Android Swift SDK toolchains used by //examples/cross_compilation. As with + # the embedded toolchains above, we register only the host platforms used by + # CI rather than `@swift_toolchain//:all`, because rules_swift cannot yet + # auto-select a Linux distribution and `:all` would make the host/exec + # toolchain ambiguous across distros. A consumer that builds on a single host + # platform can simply register `@swift_toolchain//:all`. The Android C/C++ + # toolchain comes from `@androidndk//:all` (registered below), not here. + "@swift_toolchain//:swift_toolchain_android_aarch64_ubuntu22.04", + "@swift_toolchain//:swift_toolchain_android_aarch64_ubuntu22.04-aarch64", + "@swift_toolchain//:swift_toolchain_android_aarch64_xcode", + "@swift_toolchain//:swift_toolchain_android_x86_64_ubuntu22.04", + "@swift_toolchain//:swift_toolchain_android_x86_64_ubuntu22.04-aarch64", + "@swift_toolchain//:swift_toolchain_android_x86_64_xcode", + dev_dependency = True, +) + +# The Android C/C++ cc toolchains for the cross-compile. rules_swift's Swift +# Android toolchain links through these and reads the sysroot from them. +bazel_dep(name = "hermetic_android_toolchains", version = "0.1.1", dev_dependency = True) + +android_ndk = use_extension( + "@hermetic_android_toolchains//:extensions.bzl", + "android", + dev_dependency = True, +) +android_ndk.sdk( + build_tools_version = "35.0.0", + version = "35", +) +android_ndk.ndk( + api_level = 28, + version = "r27c", +) +use_repo(android_ndk, "androidndk") + +register_toolchains( + "@androidndk//:all", + dev_dependency = True, +) + # Dev dependencies bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.5.0", dev_dependency = True) bazel_dep(name = "gazelle", version = "0.46.0", dev_dependency = True) diff --git a/doc/standalone_toolchain.md b/doc/standalone_toolchain.md index 7e96e51cf..61adc1848 100644 --- a/doc/standalone_toolchain.md +++ b/doc/standalone_toolchain.md @@ -146,6 +146,109 @@ bazel run @rules_swift//tools/swift-releases -- list \ main-snapshot-2024-08-01 --platform xcode --platform ubuntu22.04 ``` +## Cross-compiling to Android with a Swift SDK + +swift.org publishes "Swift SDK" artifact bundles (the bundles consumed by +`swift sdk install`) that let the host compiler cross-compile for platforms it +cannot target by itself. The `swift` extension can download the Android SDK and +define matching Swift and C/C++ toolchains, so plain `swift_library` and +`swift_binary` targets build for `{aarch64,x86_64}-unknown-linux-android` under +`--platforms`. + +Add the `android_sdk` tag, referencing the `toolchain` tag by name (the Swift +module format is not stable across compiler versions, so the SDK is always +downloaded for exactly the toolchain's version): + +```bzl +swift.toolchain( + name = "swift_toolchain", + swift_version = "6.3.2", +) + +swift.android_sdk(toolchain_name = "swift_toolchain") + +# rules_swift provides only the Swift toolchain; register an Android C/C++ cc +# toolchain too (it also provides the sysroot the Swift compiler reads). For +# example, @androidndk//:all from hermetic_android_toolchains: +android = use_extension("@hermetic_android_toolchains//:extensions.bzl", "android") +android.sdk(version = "35", build_tools_version = "35.0.0") +android.ndk(version = "r27c", api_level = 28) +use_repo(android, "androidndk") + +register_toolchains( + "@swift_toolchain//:swift_toolchain_android_aarch64_xcode", + "@swift_toolchain//:swift_toolchain_android_x86_64_xcode", + "@androidndk//:all", +) +``` + +If you build on a single host platform you can register everything the +extension generates in one line instead of listing the matrix: + +```bzl +register_toolchains("@swift_toolchain//:all") +``` + +Avoid `:all` when you configure multiple Linux distributions, for the same +reason the standalone host toolchains are registered explicitly: rules_swift +cannot yet auto-select a distribution, so `:all` would make the host/exec +toolchain ambiguous across them. + +Then build with a platform carrying the matching constraints: + +```bzl +platform( + name = "android-aarch64", + constraint_values = [ + "@platforms//cpu:aarch64", + "@platforms//os:android", + ], +) +``` + +```sh +bazel build //my:binary --platforms=//:android-aarch64 +``` + +See `examples/cross_compilation` for a complete example, including building +through a platform transition. + +### JNI shared libraries + +A plain `swift_binary` links an ordinary executable. To produce a JNI library +loadable with `System.loadLibrary`, set `linkshared = True`: it produces +`lib.so`. Export functions with `@_cdecl`; the Android Swift SDK's +`Android` module provides the JNI types, so the entry points can be written +entirely in Swift. A `swift_binary(linkshared = True)` may depend on ordinary +`swift_library` targets (linked statically), so the JNI entry point and the +shared business logic stay in separate libraries. +`examples/cross_compilation/android_app` shows the Kotlin app that loads the JNI +library. + +Details worth knowing: + +* The Swift standard library is linked statically from the SDK. +* Android binaries link against the NDK's `libc++_shared.so`, which must be + packaged with the application. Select it from the registered Android cc + toolchain with `select_android_runtime_lib` from + `@rules_swift//swift/toolchains:android_runtime_lib.bzl` (build it under the + Android platform so the cc toolchain resolves). +* rules_swift does not fetch the Android NDK; the registered Android cc toolchain + (e.g. `@androidndk//:all`) provides clang, the linker, and the sysroot, and the + Swift toolchain reads that toolchain's sysroot at analysis time. +* Checksums for the SDK bundles are bundled for a curated list of releases (see + `swift/internal/extensions/swift_sdk_releases.bzl`); for other releases, pass + `sha256` explicitly. + +### Coexistence with `rules_apple` + +A common setup cross-compiles to Android *and* builds the same app's Apple +targets with `rules_apple`. The two resolve together cleanly: this line of +`rules_swift` is `compatibility_level = 3` (the same as released `rules_swift` +3.x), so a current `rules_apple` release works alongside it. Bazel keeps the +higher of each shared transitive dependency (`apple_support`, `rules_cc`), which +are backward compatible, so no extra pinning is required. + ## Using the extension from a non-root module The extension is intended for the root module — it fails if a non-root diff --git a/examples/cross_compilation/BUILD.bazel b/examples/cross_compilation/BUILD.bazel new file mode 100644 index 000000000..59dec2d43 --- /dev/null +++ b/examples/cross_compilation/BUILD.bazel @@ -0,0 +1,45 @@ +load("//examples/embedded:transition.bzl", "transition_binary") +load("//swift:swift.bzl", "swift_binary", "swift_library") + +package(default_visibility = ["//visibility:public"]) + +# The platform covered by the Android Swift SDK toolchain registered by this +# repository's dev `MODULE.bazel` (via the `swift` extension's `android_sdk` +# tag). Build the targets below with `--platforms` set to this. +platform( + name = "android-aarch64", + constraint_values = [ + "@platforms//cpu:aarch64", + "@platforms//os:android", + ], +) + +# A plain library dependency, compiled for whichever platform depends on it, +# demonstrating that a normal `swift_library` is reused unchanged across targets. +swift_library( + name = "Greeter", + srcs = ["Sources/Greeter/Greeter.swift"], + module_name = "Greeter", + tags = ["manual"], +) + +# --------------------------------------------------------------------------- +# Android: a JNI shared library, loaded by Kotlin via `System.loadLibrary`. +# --------------------------------------------------------------------------- + +# `linkshared` produces `libSwiftJNI.so`. The JNI entry point is written in +# Swift (it `import`s the SDK's `Android` module for the JNI types) and calls +# into the `Greeter` library. See `android_app/` for the APK that loads it. +swift_binary( + name = "SwiftJNI", + srcs = ["Sources/SwiftJNI/SwiftJNI.swift"], + linkshared = True, + tags = ["manual"], + deps = [":Greeter"], +) + +transition_binary( + name = "libSwiftJNI.so", + binary = ":SwiftJNI", + platform = ":android-aarch64", +) diff --git a/examples/cross_compilation/README.md b/examples/cross_compilation/README.md new file mode 100644 index 000000000..9ecdfd874 --- /dev/null +++ b/examples/cross_compilation/README.md @@ -0,0 +1,55 @@ +# Cross-compilation example (Android) + +Builds plain `swift_library` / `swift_binary` targets for Android using the +Swift SDK toolchain registered by this repository's `MODULE.bazel` (via the +`swift` extension's `android_sdk` tag). See `doc/standalone_toolchain.md` for the +toolchain setup. + +All targets are tagged `manual` because they download the Swift SDK bundle and +require the Android cc toolchain to be registered. + +### The Android C/C++ toolchain + +rules_swift provides only the Swift Android toolchain; C/C++ compilation and +linking (and the NDK sysroot the Swift compiler reads) come from a separately +registered Android cc toolchain. This example uses `@androidndk//:all` from +keith's +[`hermetic_android_toolchains`](https://github.com/keith/hermetic_android_toolchains), +wired in this repository's `MODULE.bazel`: + +```starlark +android = use_extension("@hermetic_android_toolchains//:extensions.bzl", "android") +android.sdk(version = "35", build_tools_version = "35.0.0") +android.ndk(version = "r27c", api_level = 28) +use_repo(android, "androidndk") +register_toolchains("@androidndk//:all") +``` + +Any rules_android_ndk-based Android cc toolchain works the same way. To package +the NDK's `libc++_shared.so` into an APK, use the `select_android_runtime_lib` +rule from `@rules_swift//swift/toolchains:android_runtime_lib.bzl` (it reads the +resolved cc toolchain); see `android_app/README.md`. + +## Targets + +| Target | Output | Demonstrates | +|---|---|---| +| `:Greeter` | `.swiftmodule` + `.a` | A normal `swift_library` reused across targets | +| `:libSwiftJNI.so` | `libSwiftJNI.so` | An Android **JNI shared library** (`swift_binary(linkshared)`) that calls `:Greeter` | + +```sh +# Android JNI shared library: +bazel build //examples/cross_compilation:libSwiftJNI.so +``` + +`:libSwiftJNI.so` builds `:SwiftJNI` under the `:android-aarch64` platform; you +can equivalently pass `--platforms=//examples/cross_compilation:android-aarch64` +on the command line. + +## Android app + +`android_app/` contains the Kotlin app (and a documented packaging recipe) that +loads `libSwiftJNI.so` and calls into it, completing the +Kotlin → Swift (JNI `.so`) → Swift library chain. Packaging an APK uses +`rules_android` + an Android SDK in the consuming module; see +`android_app/README.md`. diff --git a/examples/cross_compilation/Sources/Greeter/Greeter.swift b/examples/cross_compilation/Sources/Greeter/Greeter.swift new file mode 100644 index 000000000..7c065196a --- /dev/null +++ b/examples/cross_compilation/Sources/Greeter/Greeter.swift @@ -0,0 +1,14 @@ +/// A plain `swift_library` used as a normal dependency of the Android JNI +/// entry point. Nothing in here is platform-specific; it is compiled for +/// whichever platform the depending target is built for. +public struct Greeter { + private let subject: String + + public init(subject: String) { + self.subject = subject + } + + public func greeting() -> String { + return "Hello from Swift, \(subject)!" + } +} diff --git a/examples/cross_compilation/Sources/SwiftJNI/SwiftJNI.swift b/examples/cross_compilation/Sources/SwiftJNI/SwiftJNI.swift new file mode 100644 index 000000000..4b3336bd5 --- /dev/null +++ b/examples/cross_compilation/Sources/SwiftJNI/SwiftJNI.swift @@ -0,0 +1,24 @@ +import Android +import Greeter + +// The JNI entry point, written entirely in Swift. `import Android` provides the +// JNI types (`JNIEnv`, `jclass`, `jstring`, ...) from the Android Swift SDK, so +// no C shim is needed. `@_cdecl` gives the function the exact symbol name JNI +// looks up: `Java___`, with `.`/`_` escaped per the JNI +// spec. It is the Kotlin-callable native implementation of: +// +// package com.example.swiftjni +// class NativeBridge { external fun greetingFromSwift(): String } +// +// and it delegates to the `Greeter` `swift_library` (a normal dependency), +// completing the Kotlin -> Swift (JNI .so) -> Swift library call chain. +@_cdecl("Java_com_example_swiftjni_NativeBridge_greetingFromSwift") +public func greetingFromSwift( + _ env: UnsafeMutablePointer, + _ clazz: jclass +) -> jstring? { + let message = Greeter(subject: "Android").greeting() + return message.withCString { cString in + env.pointee!.pointee.NewStringUTF(env, cString) + } +} diff --git a/examples/cross_compilation/android_app/AndroidManifest.xml b/examples/cross_compilation/android_app/AndroidManifest.xml new file mode 100644 index 000000000..9fa94dbfb --- /dev/null +++ b/examples/cross_compilation/android_app/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/examples/cross_compilation/android_app/README.md b/examples/cross_compilation/android_app/README.md new file mode 100644 index 000000000..d779a7921 --- /dev/null +++ b/examples/cross_compilation/android_app/README.md @@ -0,0 +1,127 @@ +# Android app: Kotlin → Swift JNI `.so` → Swift library + +This directory shows the application half of the +Kotlin → Swift → Swift call chain that `rules_swift` enables: + +``` +MainActivity.kt ──► NativeBridge.greetingFromSwift() (Kotlin) + │ JNI (System.loadLibrary("SwiftJNI")) + ▼ + //examples/cross_compilation:SwiftJNI → libSwiftJNI.so (swift_binary, linkshared) + @_cdecl("Java_..._greetingFromSwift") in SwiftJNI.swift (Swift) + │ + ▼ + //examples/cross_compilation:Greeter (swift_library) +``` + +The `rules_swift` side — building `libSwiftJNI.so` from a `swift_binary` that +depends on a normal `swift_library`, and exposing the NDK's `libc++_shared.so` +at a host-independent label — is fully implemented and exercised by +`//examples/cross_compilation:libSwiftJNI.so`. + +Packaging that `.so` into an APK is the job of the Android rules +(`rules_android` + `rules_kotlin`) and a local Android SDK. Those are heavy +dependencies (`rules_android` pulls in `rules_go`, `gazelle`, Robolectric, and a +conflicting protobuf), so `rules_swift` deliberately does **not** depend on them; +the APK target lives in *your* module instead. The sources in this directory +(`NativeBridge.kt`, `MainActivity.kt`, `AndroidManifest.xml`) are complete and +ready to drop into such a module. + +## `MODULE.bazel` (in your app's module) + +```starlark +bazel_dep(name = "rules_swift", version = "...") # or git_override to this fork +bazel_dep(name = "rules_android", version = "0.7.3") +bazel_dep(name = "rules_kotlin", version = "2.3.20") + +swift = use_extension("@rules_swift//swift:extensions.bzl", "swift") +swift.toolchain(name = "swift_toolchain", swift_version = "6.3.2") +swift.android_sdk(toolchain_name = "swift_toolchain") +use_repo(swift, "swift_toolchain") + +# One line registers every Swift SDK toolchain (and the standalone host ones). +register_toolchains("@swift_toolchain//:all") + +android_sdk = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension") +use_repo(android_sdk, "androidsdk") +register_toolchains("@androidsdk//:all") +``` + +Set `ANDROID_HOME` to a local Android SDK (with `platforms;android-34` and a +recent `build-tools`). + +## `BUILD.bazel` (in your app's module) + +```starlark +load("@rules_android//android:rules.bzl", "android_binary") +load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") + +# Lay the Swift JNI library and the NDK C++ runtime out as jniLibs for the +# arm64-v8a ABI. `libSwiftJNI.so` is the swift_binary(linkshared) output; +# `select_android_runtime_lib` selects `libc++_shared.so` from the resolved +# Android cc toolchain (build it under the android platform). +load("@rules_swift//swift/toolchains:android_runtime_lib.bzl", "select_android_runtime_lib") + +select_android_runtime_lib( + name = "libcxx_shared", + triple = "aarch64-linux-android", +) + +genrule( + name = "jni_libs", + srcs = [ + "@rules_swift//examples/cross_compilation:libSwiftJNI.so", + ":libcxx_shared", + ], + outs = [ + "lib/arm64-v8a/libSwiftJNI.so", + "lib/arm64-v8a/libc++_shared.so", + ], + cmd = """ + srcs=($(SRCS)) + mkdir -p $(RULEDIR)/lib/arm64-v8a + cp "$${srcs[0]}" $(RULEDIR)/lib/arm64-v8a/libSwiftJNI.so + cp "$${srcs[1]}" $(RULEDIR)/lib/arm64-v8a/libc++_shared.so + """, +) + +kt_android_library( + name = "app_lib", + srcs = [ + "java/com/example/swiftjni/MainActivity.kt", + "java/com/example/swiftjni/NativeBridge.kt", + ], + manifest = "AndroidManifest.xml", +) + +android_binary( + name = "app", + manifest = "AndroidManifest.xml", + custom_package = "com.example.swiftjni", + # Bundle the native libraries laid out above. + resource_files = [], + deps = [":app_lib"], + # rules_android picks up `lib//*.so` produced by the genrule when it is + # provided as data; depending on your rules_android version you may instead + # place the .so files under `src/main/jniLibs//` or pass them through a + # `cc_library`/`android_library` `jni_libs` attribute. + data = [":jni_libs"], +) +``` + +> The exact mechanism for adding pre-built `.so`s to an `android_binary` varies +> by `rules_android` version; the constant is that `libSwiftJNI.so` and +> `libc++_shared.so` must land under `lib/arm64-v8a/` (and the corresponding +> directory for any other ABIs you build). Build the `.so` for `x86_64` with the +> `//examples/cross_compilation:android-x86_64`-equivalent platform and place it +> under `lib/x86_64/` to support the emulator. + +## Building + +```sh +# The rules_swift-side artifact (verified by this repo): +bazel build @rules_swift//examples/cross_compilation:libSwiftJNI.so + +# The APK (in your module, with the wiring above and ANDROID_HOME set): +bazel build //path/to/android_app:app +``` diff --git a/examples/cross_compilation/android_app/java/com/example/swiftjni/MainActivity.kt b/examples/cross_compilation/android_app/java/com/example/swiftjni/MainActivity.kt new file mode 100644 index 000000000..d1cb84bf0 --- /dev/null +++ b/examples/cross_compilation/android_app/java/com/example/swiftjni/MainActivity.kt @@ -0,0 +1,15 @@ +package com.example.swiftjni + +import android.app.Activity +import android.os.Bundle +import android.widget.TextView + +/** Displays the greeting computed by Swift, reached via JNI. */ +class MainActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val textView = TextView(this) + textView.text = NativeBridge.greetingFromSwift() + setContentView(textView) + } +} diff --git a/examples/cross_compilation/android_app/java/com/example/swiftjni/NativeBridge.kt b/examples/cross_compilation/android_app/java/com/example/swiftjni/NativeBridge.kt new file mode 100644 index 000000000..62c59afa0 --- /dev/null +++ b/examples/cross_compilation/android_app/java/com/example/swiftjni/NativeBridge.kt @@ -0,0 +1,19 @@ +package com.example.swiftjni + +/** + * Loads the Swift JNI shared library (`libSwiftJNI.so`, built by the + * `//examples/cross_compilation:SwiftJNI` `swift_binary(linkshared = True)`) + * and exposes its Swift entry point to Kotlin. + * + * The native method binds by name to the Swift `@_cdecl` function + * `Java_com_example_swiftjni_NativeBridge_greetingFromSwift`, which in turn + * calls the `Greeter` `swift_library` — completing the + * Kotlin -> Swift (in the `.so`) -> Swift library call chain. + */ +object NativeBridge { + init { + System.loadLibrary("SwiftJNI") + } + + external fun greetingFromSwift(): String +} diff --git a/swift/extensions.bzl b/swift/extensions.bzl index be6bbc0c1..738a6218d 100644 --- a/swift/extensions.bzl +++ b/swift/extensions.bzl @@ -18,8 +18,19 @@ load("@bazel_features//:features.bzl", "bazel_features") load("//swift/internal:repositories.bzl", "swift_rules_dependencies") load("//swift/internal/extensions:standalone_toolchain.bzl", _standalone_toolchain = "standalone_toolchain") load("//swift/internal/extensions:swift_releases.bzl", "SWIFT_RELEASES") +load( + "//swift/internal/extensions:swift_sdk_releases.bzl", + "SWIFT_SDK_RELEASES", + "swift_sdk_download_url", +) +load( + "//swift/internal/extensions:swift_sdks.bzl", + "ANDROID_ARCHS", + "swift_android_sdk_repository", +) load( "//swift/internal/extensions:toolchains.bzl", + _android_sdk_toolchains_for_platform = "android_sdk_toolchains_for_platform", _toolchains_for_platform = "toolchains_for_platform", _toolchains_repository = "toolchains_repository", ) @@ -40,6 +51,62 @@ def _non_module_deps_impl(module_ctx): non_module_deps = module_extension(implementation = _non_module_deps_impl) +def _setup_android_sdk(*, tag, toolchain_name, swift_version, platforms): + """Creates the repositories for a `swift.android_sdk` tag. + + Args: + tag: The `android_sdk` tag. + toolchain_name: The name of the `swift.toolchain` tag the SDK extends. + swift_version: The Swift release version of that toolchain. + platforms: The host platforms the toolchain was created for. + + Returns: + BUILD file content with the `toolchain` declarations to add to the + toolchains hub repository. + """ + sha256 = tag.sha256 + if not sha256: + if swift_version not in SWIFT_SDK_RELEASES: + fail("No known Android Swift SDK for version `{}`. Please choose one of {}, or provide the SDK's sha256.".format( + swift_version, + SWIFT_SDK_RELEASES.keys(), + )) + sha256 = SWIFT_SDK_RELEASES[swift_version]["android"] + + # The Swift Android toolchain compiles and links C/C++ through a separately + # registered Android C++ cc toolchain (e.g. `@androidndk//:all` from + # `hermetic_android_toolchains`) and reads that toolchain's sysroot at + # analysis time, so rules_swift does not fetch or manage the NDK itself. + build_file_content = "" + for platform in platforms: + repository_name = "{}_android_sdk_{}".format(toolchain_name, platform) + swift_android_sdk_repository( + name = repository_name, + host_swiftc = "@{}_{}//:usr/bin/swiftc".format(toolchain_name, platform), + sha256 = sha256, + swift_version = swift_version, + toolchain_repo = "{}_{}".format(toolchain_name, platform), + url = swift_sdk_download_url(swift_version, "android"), + ) + build_file_content += _android_sdk_toolchains_for_platform( + platform = platform, + sdk_repository = repository_name, + archs = ANDROID_ARCHS, + ) + return build_file_content + +def _sdk_tags_by_toolchain_name(tags, kind): + """Groups SDK tags by the toolchain they extend, rejecting duplicates.""" + tags_by_name = {} + for tag in tags: + if tag.toolchain_name in tags_by_name: + fail("Only one `{}` tag may be used per toolchain, got multiple for `{}`.".format( + kind, + tag.toolchain_name, + )) + tags_by_name[tag.toolchain_name] = tag + return tags_by_name + def _standalone_toolchain_impl(module_ctx): root_module = None for mod in module_ctx.modules: @@ -50,6 +117,22 @@ def _standalone_toolchain_impl(module_ctx): if not root_module: fail("Could not find a root module. This should never happen.") + android_sdk_tags = _sdk_tags_by_toolchain_name( + root_module.tags.android_sdk, + "android_sdk", + ) + + toolchain_names = [ + toolchain.name + for toolchain in root_module.tags.toolchain + ] + for toolchain_name in android_sdk_tags: + if toolchain_name not in toolchain_names: + fail("The `android_sdk` tag references unknown toolchain `{}`. Please use the name of a `toolchain` tag: {}".format( + toolchain_name, + toolchain_names, + )) + toolchains_build_file_content = "" for toolchain in root_module.tags.toolchain: if toolchain.swift_version and toolchain.swift_version_file: @@ -81,6 +164,16 @@ def _standalone_toolchain_impl(module_ctx): platform = platform, toolchain_repository = repository_name, ) + + platforms = [platform for platform, _ in swift_releases] + if toolchain.name in android_sdk_tags: + toolchains_build_file_content += _setup_android_sdk( + tag = android_sdk_tags[toolchain.name], + toolchain_name = toolchain.name, + swift_version = swift_version, + platforms = platforms, + ) + _toolchains_repository( name = toolchain.name, build_file_content = toolchains_build_file_content, @@ -94,6 +187,42 @@ def _standalone_toolchain_impl(module_ctx): **metadata_kwargs ) +_android_sdk = tag_class( + attrs = { + "sha256": attr.string( + doc = """\ +The expected SHA-256 of the SDK artifact bundle. May be omitted for Swift +versions known to this version of rules_swift. +""", + ), + "toolchain_name": attr.string( + doc = "The name of the `toolchain` tag to add this Swift SDK to.", + mandatory = True, + ), + }, + doc = """\ +Downloads the Android Swift SDK matching a `toolchain` tag's Swift version and +defines Swift toolchains targeting `aarch64-unknown-linux-android` and +`x86_64-unknown-linux-android`. + +C/C++ compilation and linking for those targets go through a separately +registered Android C++ cc toolchain, which also provides the sysroot the Swift +compiler reads. Register one alongside the Swift toolchains -- for example +`@androidndk//:all` from +[hermetic_android_toolchains](https://github.com/keith/hermetic_android_toolchains): + +```starlark +register_toolchains( + "@swift_toolchain//:swift_toolchain_android_aarch64_xcode", + "@androidndk//:all", +) +``` + +and build with a platform that has the `@platforms//os:android` and +`@platforms//cpu:aarch64` (or `x86_64`) constraints. +""", +) + _toolchain = tag_class(attrs = { "name": attr.string( doc = "Repository name of the generated toolchain", @@ -114,6 +243,7 @@ their hashes. For instance: swift = module_extension( implementation = _standalone_toolchain_impl, tag_classes = { + "android_sdk": _android_sdk, "toolchain": _toolchain, }, ) diff --git a/swift/internal/extensions/BUILD.bazel.tpl b/swift/internal/extensions/BUILD.bazel.tpl index 231ecbcb9..f0e9c8192 100644 --- a/swift/internal/extensions/BUILD.bazel.tpl +++ b/swift/internal/extensions/BUILD.bazel.tpl @@ -13,6 +13,54 @@ exports_files([ "usr/bin/llvm-objcopy", ]) +### Tools referenced by Swift SDK cross-compilation repositories. ### +# See swift/internal/extensions/swift_sdks.bzl. +exports_files([ + "usr/bin/clang", + "usr/bin/llvm-ar", + "usr/bin/swift-autolink-extract", + "usr/bin/swift-symbolgraph-extract", + "usr/bin/swiftc", +]) + +# The subset of the toolchain that Swift compile actions for a Swift SDK +# target need: the driver/frontend and their libraries, plus clang's builtin +# headers for the clang importer. The Swift standard library for the target +# comes from the SDK, not from here. +filegroup( + name = "swift_sdk_compiler_inputs", + srcs = glob( + [ + "usr/bin/swift*", + "usr/lib/clang/**", + "usr/lib/lib*.dylib", + "usr/lib/lib*.so*", + "usr/lib/swift/host/**", + "usr/lib/swift/linux/**", + "usr/lib/swift/macosx/**", + ], + allow_empty = True, + ), +) + +# The subset of the toolchain that link actions driven by this toolchain's +# clang need. +filegroup( + name = "swift_sdk_linker_inputs", + srcs = glob( + [ + "usr/bin/clang*", + "usr/bin/ld.lld", + "usr/bin/ld64.lld", + "usr/bin/lld", + "usr/bin/llvm-ar", + "usr/bin/wasm-ld", + "usr/lib/clang/**", + ], + allow_empty = True, + ), +) + filegroup( name = "files", srcs = glob( diff --git a/swift/internal/extensions/swift_sdk_releases.bzl b/swift/internal/extensions/swift_sdk_releases.bzl index 4a1c2e02f..92a7b89a8 100644 --- a/swift/internal/extensions/swift_sdk_releases.bzl +++ b/swift/internal/extensions/swift_sdk_releases.bzl @@ -1,26 +1,29 @@ -"""Swift SDK release version mappings. +"""Swift SDK and Android NDK release version mappings. -Checksums for the official "Swift SDK" artifact bundles published by swift.org -(the bundles installed by `swift sdk install`), used to cross-compile Swift to -platforms not covered by a host toolchain. +This module defines checksums for the artifacts needed to cross-compile Swift +for platforms that are not covered by a host toolchain, using the official +"Swift SDK" artifact bundles published by swift.org (the bundles installed by +`swift sdk install`). The Swift module format is not stable across compiler versions, so a Swift SDK -can only be used with the host toolchain from exactly the same release; the keys -of `SWIFT_SDK_RELEASES` therefore mirror the keys of `SWIFT_RELEASES` in +can only be used with the host toolchain from exactly the same release; the +keys of `SWIFT_SDK_RELEASES` therefore mirror the keys of `SWIFT_RELEASES` in `swift_releases.bzl`. Checksums are published in https://www.swift.org/api/v1/install/releases.json. """ -# Populated by the per-platform extensions (e.g. `wasm_sdk`, `android_sdk`), -# which add their SDK checksums under each supported Swift release. -SWIFT_SDK_RELEASES = {} +SWIFT_SDK_RELEASES = { + "6.3.2": { + "android": "939e933549d12d28f2e0bf71019d734d309859e9773c572657ce565a81f85d68", + }, +} def swift_sdk_download_url(swift_version, sdk): """Returns the download URL for a Swift SDK artifact bundle. Args: swift_version: The Swift release version (e.g. "6.3.2"). - sdk: The SDK kind (e.g. "wasm"). + sdk: The SDK kind (e.g. "android"). Returns: The URL of the `.artifactbundle.tar.gz` for the given release. diff --git a/swift/internal/extensions/swift_sdks.bzl b/swift/internal/extensions/swift_sdks.bzl index 12d36fc4b..41b14b315 100644 --- a/swift/internal/extensions/swift_sdks.bzl +++ b/swift/internal/extensions/swift_sdks.bzl @@ -1,11 +1,14 @@ -"""Shared building blocks for Swift SDK repository rules. +"""Shared building blocks for Swift SDK repository rules, plus the Android SDK +repository rule. A "Swift SDK" is an artifact bundle published by swift.org for cross-compiling Swift to a platform the host toolchain cannot target by itself (the bundles that -`swift sdk install` consumes). The per-platform extensions (e.g. `wasm_sdk`, -`android_sdk`) define repository rules that download such a bundle and generate -a `swift_toolchain` + rules_cc `cc_toolchain` for the target; this module holds -the helpers and BUILD-file templates they share. +`swift sdk install` consumes). The `android_sdk` extension defines a repository +rule that downloads such a bundle and generates a `swift_toolchain` targeting +`{aarch64,x86_64}-unknown-linux-android`; this module holds the helpers and +BUILD-file template it uses. C/C++ compilation and linking go through a +separately registered Android cc toolchain (e.g. `@androidndk//:all`), which also +provides the sysroot the Swift toolchain reads. Because the Swift module format is not stable across compiler versions, a Swift SDK must come from exactly the same release as the host toolchain it is paired @@ -16,89 +19,8 @@ with; the `swift` module extension enforces this by deriving both from the same # Files in the host toolchain that compile actions need: the driver/frontend # binaries, their libraries, and clang's builtin headers (used by the clang # importer when the Swift SDK's resource directory does not bundle them). -# buildifier: disable=unused-variable _HOST_COMPILER_INPUTS = "swift_sdk_compiler_inputs" -# Files in the host toolchain that link actions driven by its clang need. -# buildifier: disable=unused-variable -_HOST_LINKER_INPUTS = "swift_sdk_linker_inputs" - -# buildifier: disable=unused-variable -_CC_TOOLCHAIN_TEMPLATE = """ -cc_tool( - name = "clang", - src = "{clang}", - data = {clang_data}, - tags = ["manual"], -) - -cc_tool( - name = "ar", - src = "{ar}", - tags = ["manual"], -) - -cc_tool_map( - name = "cc_tools", - tags = ["manual"], - tools = {{ - "@rules_cc//cc/toolchains/actions:ar_actions": ":ar", - "@rules_cc//cc/toolchains/actions:assembly_actions": ":clang", - "@rules_cc//cc/toolchains/actions:c_compile": ":clang", - "@rules_cc//cc/toolchains/actions:cpp_compile_actions": ":clang", - "@rules_cc//cc/toolchains/actions:link_actions": ":clang", - }}, -) -""" - -# buildifier: disable=unused-variable -_CC_TOOLCHAIN_FOR_TARGET_TEMPLATE = """ -cc_args( - name = "cc_args_{suffix}", - actions = [ - "@rules_cc//cc/toolchains/actions:compile_actions", - "@rules_cc//cc/toolchains/actions:link_actions", - ], - args = {args}, -) - -cc_args( - name = "cc_link_args_{suffix}", - actions = [ - "@rules_cc//cc/toolchains/actions:link_actions", - ], - args = {link_args}, -) - -cc_make_variable( - name = "cc_target_triple_{suffix}", - value = "{triple}", - variable_name = "CC_TARGET_TRIPLE", -) - -cc_toolchain( - name = "cc_toolchain_{suffix}", - args = [ - ":cc_args_{suffix}", - ":cc_link_args_{suffix}", - ], - compiler = "clang", - enabled_features = [ - "@rules_cc//cc/toolchains/args/archiver_flags:feature", - "@rules_cc//cc/toolchains/args/libraries_to_link:feature", - "@rules_cc//cc/toolchains/args/link_flags:feature", - # Needed so `swift_binary(linkshared = True)` links a shared library - # (passes `-shared` for the dynamic_library link action). - "@rules_cc//cc/toolchains/args/shared_flag:feature", - ], - make_variables = [ - ":cc_target_triple_{suffix}", - ], - tool_map = ":cc_tools", -) -""" - -# buildifier: disable=unused-variable _SWIFT_TOOLCHAIN_TEMPLATE = """ swift_toolchain( name = "swift_toolchain_{suffix}", @@ -115,13 +37,7 @@ swift_toolchain( ) """ -# buildifier: disable=unused-variable _BUILD_HEADER_TEMPLATE = """\ -load("@rules_cc//cc/toolchains:args.bzl", "cc_args") -load("@rules_cc//cc/toolchains:make_variable.bzl", "cc_make_variable") -load("@rules_cc//cc/toolchains:tool.bzl", "cc_tool") -load("@rules_cc//cc/toolchains:tool_map.bzl", "cc_tool_map") -load("@rules_cc//cc/toolchains:toolchain.bzl", "cc_toolchain") load("@rules_swift//swift/toolchains:swift_toolchain.bzl", "swift_toolchain") load("@rules_swift//swift/toolchains:swift_tools.bzl", "swift_tools") @@ -141,7 +57,26 @@ swift_tools( ) """ -# buildifier: disable=unused-variable +def _execroot_relative_path(path): + """Returns the execution-root-relative path for an external repository path. + + Args: + path: An absolute `path` (or string) below the output base's + `external` directory. + + Returns: + The same path expressed relative to the execution root, suitable for + baking into command line flags. + """ + path_str = str(path) + + # buildifier: disable=external-path + if "/external/" not in path_str: + fail("Expected a path inside an external repository, got: " + path_str) + + # buildifier: disable=external-path + return "external/" + path_str.rsplit("/external/", 1)[1] + def _build_list(items, indent = " "): """Formats a list of strings as a multi-line BUILD file list literal.""" if not items: @@ -152,7 +87,6 @@ def _build_list(items, indent = " "): lines.append(indent + "]") return "\n".join(lines) -# buildifier: disable=unused-variable def _download_sdk_bundle(repository_ctx): """Downloads and extracts the Swift SDK artifact bundle for a repository. @@ -178,7 +112,6 @@ def _download_sdk_bundle(repository_ctx): )) return bundles[0] -# buildifier: disable=unused-variable def _common_attrs(): return { "sha256": attr.string( @@ -201,3 +134,110 @@ this SDK is paired with. mandatory = True, ), } + +# The architectures the Android Swift SDK provides resources for and that +# `@platforms//cpu` can express. (The SDK also supports armv7, which can be +# added on demand.) +ANDROID_ARCHS = ["aarch64", "x86_64"] + +def _swift_android_sdk_impl(repository_ctx): + bundle_dir = _download_sdk_bundle(repository_ctx) + toolchain_repo = repository_ctx.attr.toolchain_repo + + repo_root = "external/" + repository_ctx.name + sdk_dir_relative = bundle_dir + "/swift-android" + if not repository_ctx.path(sdk_dir_relative + "/swift-sdk.json").exists: + fail("The Android Swift SDK bundle has an unexpected layout; " + + "missing {}/{}/swift-sdk.json".format(repo_root, sdk_dir_relative)) + lib_dir = "{}/{}/swift-resources/usr/lib".format(repo_root, sdk_dir_relative) + + # The Android Swift SDK's resource directories do not bundle clang's + # builtin headers, so the clang importer must be pointed at the host + # toolchain's copy (which matches the clang embedded in swiftc). + host_usr = repository_ctx.path(repository_ctx.attr.host_swiftc).dirname.dirname + clang_versions = host_usr.get_child("lib", "clang").readdir() + if len(clang_versions) != 1: + fail("Expected exactly one clang version directory in the host " + + "toolchain, found: " + str(clang_versions)) + clang_builtin_headers = _execroot_relative_path( + clang_versions[0].get_child("include"), + ) + + build_content = _BUILD_HEADER_TEMPLATE.format( + bundle_dir = bundle_dir, + compiler_inputs = _build_list([ + ":sdk_files", + "@{}//:{}".format(toolchain_repo, _HOST_COMPILER_INPUTS), + ]), + toolchain_repo = toolchain_repo, + ) + + for arch in ANDROID_ARCHS: + resource_dir = "{}/swift_static-{}".format(lib_dir, arch) + + build_content += _SWIFT_TOOLCHAIN_TEMPLATE.format( + arch = arch, + copts = _build_list([ + "-resource-dir", + resource_dir, + "-Xcc", + "-I" + clang_builtin_headers, + ]), + features = _build_list([ + "swift.lld_gc_workaround", + "swift.module_map_no_private_headers", + "swift.use_autolink_extract", + "swift.use_module_wrap", + # The file prefix map would make the worker resolve the Xcode + # developer directory on macOS hosts, which this toolchain + # does not depend on. + "-swift.file_prefix_map", + ]), + linker_inputs = _build_list([":sdk_files"]), + # The runtime objects and libraries that `swiftc` adds when + # statically linking the stdlib for Android; see + # `swift_static-{arch}/android/static-stdlib-args.lnk` in the SDK. + # The 16 KiB max page size is required by Android 15+. We omit that + # file's `-Wl,--exclude-libs,ALL`: under Bazel a `swift_binary`'s + # `swift_library` deps are static archives, so it would demote their + # exported symbols (e.g. `@_cdecl("Java_…")` JNI entry points) to + # local and `System.loadLibrary` could not bind them. Pass a linker + # version script to hide the runtime symbols if desired. + linkopts = _build_list([ + "{}/android/{}/swiftrt.o".format(resource_dir, arch), + "-L{}/android".format(resource_dir), + "-ldl", + "-llog", + "-lm", + "-lstdc++", + "-Wl,-z,max-page-size=16384", + ]), + os = "android", + # Empty: the toolchain reads the sysroot from the resolved Android + # C++ cc toolchain (e.g. `@androidndk//:all`) at analysis time. + sdkroot = "", + suffix = arch, + swift_version = repository_ctx.attr.swift_version, + ) + + repository_ctx.file("BUILD.bazel", build_content) + +swift_android_sdk_repository = repository_rule( + attrs = _common_attrs() | { + "host_swiftc": attr.label( + doc = """\ +The host toolchain's `swiftc`, used to locate the clang builtin headers that +match the clang embedded in the Swift compiler. +""", + mandatory = True, + ), + }, + doc = """\ +Downloads the Android Swift SDK artifact bundle and defines Swift toolchains that +target `{aarch64,x86_64}-unknown-linux-android`. C/C++ compilation and linking go +through a separately-registered Android C++ cc toolchain (e.g. `@androidndk//:all` +from `hermetic_android_toolchains`); the Swift toolchain reads that toolchain's +sysroot at analysis time. +""", + implementation = _swift_android_sdk_impl, +) diff --git a/swift/internal/extensions/toolchains.bzl b/swift/internal/extensions/toolchains.bzl index f01f91c4c..f83e1387b 100644 --- a/swift/internal/extensions/toolchains.bzl +++ b/swift/internal/extensions/toolchains.bzl @@ -43,9 +43,10 @@ toolchain( """ -# buildifier: disable=unused-variable +# Just the Swift toolchain: Android's C/C++ toolchain is registered separately +# (e.g. `@androidndk//:all`). _SDK_TOOLCHAIN_PLATFORM = """ -# Swift SDK toolchains from repository: `{sdk_repository}` +# Swift SDK toolchain from repository: `{sdk_repository}` toolchain( name = "swift_toolchain_{target}_{platform}", exec_compatible_with = {exec_compatible_with}, @@ -54,15 +55,6 @@ toolchain( toolchain_type = "@rules_swift//toolchains:toolchain_type", visibility = ["//visibility:public"], ) - -toolchain( - name = "cc_toolchain_{target}_{platform}", - exec_compatible_with = {exec_compatible_with}, - target_compatible_with = {target_compatible_with}, - toolchain = "@{sdk_repository}//:cc_toolchain_{target_suffix}", - toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", - visibility = ["//visibility:public"], -) """ def _exec_compatible_with_for_platform(platform): @@ -83,6 +75,39 @@ def toolchains_for_platform(platform, toolchain_repository): toolchain_repository = toolchain_repository, ) +def android_sdk_toolchains_for_platform(platform, sdk_repository, archs): + """Returns Swift `toolchain` declarations for an Android Swift SDK. + + Only the Swift toolchain is declared; C/C++ compilation and linking for + Android targets use a separately registered cc toolchain (e.g. + `@androidndk//:all`). + + Args: + platform: The host platform name (e.g. "xcode" or "ubuntu22.04") whose + standalone toolchain the SDK is paired with. + sdk_repository: The name of the repository created by + `swift_android_sdk_repository`. + archs: The Android architectures ("aarch64", "x86_64") to declare + toolchains for. + + Returns: + BUILD file content declaring the Swift toolchains. + """ + content = "" + for arch in archs: + content += _SDK_TOOLCHAIN_PLATFORM.format( + exec_compatible_with = _exec_compatible_with_for_platform(platform), + platform = platform, + sdk_repository = sdk_repository, + target = "android_" + arch, + target_compatible_with = [ + "@platforms//os:android", + "@platforms//cpu:" + arch, + ], + target_suffix = arch, + ) + return content + def _toolchains_impl(repository_ctx): repository_ctx.file("BUILD.bazel", repository_ctx.attr.build_file_content) diff --git a/swift/toolchains/BUILD b/swift/toolchains/BUILD index 89d84641d..ef9f4f322 100644 --- a/swift/toolchains/BUILD +++ b/swift/toolchains/BUILD @@ -156,3 +156,10 @@ bzl_library( visibility = ["//visibility:public"], deps = ["//swift:providers"], ) + +bzl_library( + name = "android_runtime_lib", + srcs = ["android_runtime_lib.bzl"], + visibility = ["//visibility:public"], + deps = ["@rules_cc//cc:find_cc_toolchain_bzl"], +) diff --git a/swift/toolchains/android_runtime_lib.bzl b/swift/toolchains/android_runtime_lib.bzl new file mode 100644 index 000000000..9cc05626f --- /dev/null +++ b/swift/toolchains/android_runtime_lib.bzl @@ -0,0 +1,47 @@ +"""A rule that selects a single Android NDK runtime library from the toolchain. + +The Android NDK's shared C++ runtime (`libc++_shared.so`) must be packaged into +any APK that contains Swift (or other NDK C++) code. This rule selects it out of +the resolved C++ (cc) toolchain's files, so a consumer can reference it for APK +packaging without naming the NDK repository or build host. Build it for an +Android platform so the Android cc toolchain (e.g. `@androidndk//:all`) is +resolved. +""" + +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") + +def _select_android_runtime_lib_impl(ctx): + cc_toolchain = find_cc_toolchain(ctx) + suffix = "/usr/lib/{}/{}".format(ctx.attr.triple, ctx.attr.basename) + matches = [ + f + for f in cc_toolchain.all_files.to_list() + if f.path.endswith(suffix) + ] + if len(matches) != 1: + fail("Expected exactly one `{}` under `usr/lib/{}` in the Android cc toolchain, found: {}".format( + ctx.attr.basename, + ctx.attr.triple, + [f.path for f in matches], + )) + return [DefaultInfo(files = depset(matches))] + +select_android_runtime_lib = rule( + implementation = _select_android_runtime_lib_impl, + attrs = { + "basename": attr.string( + default = "libc++_shared.so", + doc = "The runtime library file name to select.", + ), + "triple": attr.string( + mandatory = True, + doc = "The Android target triple, e.g. `aarch64-linux-android`.", + ), + }, + toolchains = use_cc_toolchain(), + doc = """\ +Selects a single runtime library (by default `libc++_shared.so`) for an Android +target triple out of the resolved C++ toolchain's files, exposing it as a +one-file target for APK packaging. Build it for an Android platform. +""", +) diff --git a/swift/toolchains/swift_toolchain.bzl b/swift/toolchains/swift_toolchain.bzl index ab8845574..6ef716050 100644 --- a/swift/toolchains/swift_toolchain.bzl +++ b/swift/toolchains/swift_toolchain.bzl @@ -491,6 +491,23 @@ def _parse_target_system_name(*, arch, os, target_system_name): else: return "%s-unknown-%s" % (arch, os) +def _resolve_sdkroot(ctx, cc_toolchain): + """Returns the SDK root (sysroot) for `-sdk`. + + Prefers the explicit `sdkroot` attribute. Otherwise falls back to the + resolved cc toolchain's sysroot -- but rules_android_ndk's `@androidndk` + toolchain reports `sysroot` as the clang directory, not the NDK sysroot + swiftc needs, so for Android we derive the sysroot from the toolchain files. + """ + if ctx.attr.sdkroot: + return ctx.attr.sdkroot + if ctx.attr.os == "android": + for f in cc_toolchain.all_files.to_list(): + idx = f.path.find("/sysroot/") + if idx != -1: + return f.path[:idx] + "/sysroot" + return cc_toolchain.sysroot + def _swift_toolchain_impl(ctx): toolchain_root = ctx.attr.root cc_toolchain = find_cc_toolchain(ctx) @@ -503,12 +520,17 @@ def _swift_toolchain_impl(ctx): target_triples.parse(ctx.var.get("CC_TARGET_TRIPLE") or target_system_name), ) - if "clang" not in cc_toolchain.compiler: - fail("Swift requires the configured CC toolchain use clang. " + + # Swift can only link through an LLVM/clang cc toolchain, not gcc. Accept any + # toolchain whose compiler identifies as clang or LLVM (e.g. the Android NDK's + # `@androidndk//:all` reports `llvm-c++`). + if "clang" not in cc_toolchain.compiler and "llvm" not in cc_toolchain.compiler: + fail("Swift requires the configured CC toolchain use clang/LLVM. " + "Either use the locally installed LLVM by setting `CC=clang` in your environment " + "before invoking Bazel, or configure a Bazel LLVM CC toolchain. " + "The current CC toolchain is configured to use '{}'.".format(cc_toolchain.compiler)) + sdkroot = _resolve_sdkroot(ctx, cc_toolchain) + additional_rpaths = [] if ctx.attr.swift_tools: if ctx.attr.swift_executable: @@ -549,10 +571,24 @@ def _swift_toolchain_impl(ctx): # own `-L`/rpath and `swiftrt.o`); for a cross-compiled SDK target they # are at best wrong and at worst invalid (wasm-ld rejects `-pie`, and a # second `swiftrt.o` would conflict with the SDK's own). + linkopts = list(ctx.attr.linkopts) + linker_inputs = list(ctx.files.linker_inputs) + if ctx.attr.os == "android" and sdkroot: + # The Swift link action drives the NDK clang directly and does not go + # through the cc toolchain's sysroot/runtime-lib link features, so + # point clang at the sysroot and stage `libc++_shared.so` (which the + # NDK clang links by default) into the link ourselves. + linkopts.append("--sysroot=" + sdkroot) + libcxx_suffix = "/usr/lib/{}-linux-android/libc++_shared.so".format(ctx.attr.arch) + linker_inputs = linker_inputs + [ + f + for f in cc_toolchain.all_files.to_list() + if f.path.endswith(libcxx_suffix) + ] swift_linkopts_cc_info = _swift_sdk_linkopts_cc_info( ctx.label, - ctx.attr.linkopts, - ctx.files.linker_inputs, + linkopts, + linker_inputs, ) else: swift_linkopts_cc_info = _swift_unix_linkopts_cc_info( @@ -609,7 +645,7 @@ def _swift_toolchain_impl(ctx): os = ctx.attr.os, arch = ctx.attr.arch, target_triple = target_triple, - sdkroot = ctx.attr.sdkroot or cc_toolchain.sysroot, + sdkroot = sdkroot, xctest_version = ctx.attr.xctest_version, additional_swiftc_copts = ctx.attr.copts + swiftcopts, ) From 86683826e776889d36f72f91ea05631bca375551 Mon Sep 17 00:00:00 2001 From: Logan Shire Date: Wed, 24 Jun 2026 22:45:35 -0400 Subject: [PATCH 2/8] examples: add a runnable Android APK example (Kotlin -> Swift JNI -> Swift) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .bazelci/presubmit.yml | 9 +- .bazelrc | 11 + MODULE.bazel | 55 +- examples/cross_compilation/README.md | 15 +- .../cross_compilation/android_app/BUILD.bazel | 91 + .../cross_compilation/android_app/README.md | 138 +- rules_android_maven_install.json | 5426 +++++++++++++++++ 7 files changed, 5635 insertions(+), 110 deletions(-) create mode 100644 examples/cross_compilation/android_app/BUILD.bazel create mode 100755 rules_android_maven_install.json diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index aa84b9019..0750bc559 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -71,10 +71,15 @@ tasks: # the Swift SDK bundle and the NDK), so they are excluded from the # `//examples/...` wildcard the other tasks build. List them explicitly here # so the Swift-SDK cross-compilation toolchains are exercised in CI. - # Build-only: the trivial JNI library exercises the link path, while runtime - # behavior is covered downstream by real consumers. + # `--config=android_example` supplies the rules_android flags (arm64 + # --android_platforms + a hermetic JDK) the APK needs; it's harmless for the + # bare .so. The build_test asserts the runnable APK (Kotlin -> Swift JNI -> + # Swift library) assembles; runtime behavior is shown by `android_app/`. + build_flags: + - "--config=android_example" build_targets: - "//examples/cross_compilation:libSwiftJNI.so" + - "//examples/cross_compilation/android_app:app_build_test" macos_latest_shell_scripts: name: "macOS shell tests" diff --git a/.bazelrc b/.bazelrc index 8a9de7fd6..f7eaf8327 100644 --- a/.bazelrc +++ b/.bazelrc @@ -28,6 +28,17 @@ build --enable_platform_specific_config common --repo_env=ACCEPTED_ANDROID_NDK_LICENSE_VERSION=r27c common --repo_env=ACCEPTED_ANDROID_SDK_LICENSE_VERSION=35 +# Build the runnable APK example (//examples/cross_compilation/android_app) with +# `--config=android_example`. Scoped to a config (not applied globally) so the +# rest of the build is untouched: --android_platforms drives rules_android's +# per-ABI native split (the emulator is arm64), and the hermetic remote JDK runs +# rules_android's Java actions instead of requiring a host JDK. +common:android_example --android_platforms=@rules_android//:arm64-v8a +common:android_example --java_language_version=17 +common:android_example --java_runtime_version=remotejdk_17 +common:android_example --tool_java_language_version=17 +common:android_example --tool_java_runtime_version=remotejdk_17 + common:linux --repo_env=CC=clang build:linux --cxxopt='-std=c++17' --host_cxxopt='-std=c++17' common:linux --//test:apple_build_tests=False diff --git a/MODULE.bazel b/MODULE.bazel index ad2d25029..70ecc537e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -147,13 +147,66 @@ android_ndk.ndk( api_level = 28, version = "r27c", ) -use_repo(android_ndk, "androidndk") +use_repo(android_ndk, "androidndk", "androidsdk") register_toolchains( "@androidndk//:all", dev_dependency = True, ) +# A runnable APK example (//examples/cross_compilation/android_app) that loads +# the Swift JNI .so and shows the Swift greeting on screen. It uses rules_android +# + rules_kotlin — the real-world way Android apps are built. These are all +# dev-only (rules_android pulls in a Maven graph and is heavy), so they never +# affect rules_swift consumers; a consumer brings their own Android rules. +bazel_dep(name = "rules_android", version = "0.7.3", dev_dependency = True) +bazel_dep(name = "rules_java", version = "9.3.0", dev_dependency = True) +bazel_dep(name = "rules_kotlin", version = "2.2.2", dev_dependency = True) +bazel_dep(name = "rules_jvm_external", version = "7.0", dev_dependency = True) + +# rules_java's hermetic JDK + java tools for rules_android's Java actions. +rules_java_toolchains = use_extension( + "@rules_java//java:extensions.bzl", + "toolchains", + dev_dependency = True, +) +use_repo(rules_java_toolchains, "remote_java_tools") + +# rules_android's own Maven dependencies, pinned to a checked-in lock file: +# REPIN=1 bazel run @rules_android_maven//:pin +maven = use_extension( + "@rules_jvm_external//:extensions.bzl", + "maven", + dev_dependency = True, +) +maven.install( + name = "rules_android_maven", + aar_import_bzl_label = "@rules_android//rules:rules.bzl", + artifacts = [], + known_contributing_modules = ["rules_android"], + lock_file = "//:rules_android_maven_install.json", + repositories = [ + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], + use_starlark_android_rules = True, +) +use_repo(maven, "rules_android_maven") + +# Point rules_android at the hermetic @androidsdk created by the android_ndk.sdk +# tag above (instead of requiring a local $ANDROID_HOME). +rules_android_sdk = use_extension( + "@rules_android//rules/android_sdk_repository:rule.bzl", + "android_sdk_repository_extension", + dev_dependency = True, +) +override_repo(rules_android_sdk, "androidsdk") + +register_toolchains( + "@androidsdk//:all", + dev_dependency = True, +) + # Dev dependencies bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.5.0", dev_dependency = True) bazel_dep(name = "gazelle", version = "0.46.0", dev_dependency = True) diff --git a/examples/cross_compilation/README.md b/examples/cross_compilation/README.md index 9ecdfd874..f181c6619 100644 --- a/examples/cross_compilation/README.md +++ b/examples/cross_compilation/README.md @@ -48,8 +48,15 @@ on the command line. ## Android app -`android_app/` contains the Kotlin app (and a documented packaging recipe) that -loads `libSwiftJNI.so` and calls into it, completing the -Kotlin → Swift (JNI `.so`) → Swift library chain. Packaging an APK uses -`rules_android` + an Android SDK in the consuming module; see +`android_app/` is a complete, runnable APK that loads `libSwiftJNI.so`, calls +into it, and shows the Swift greeting on screen — completing the +Kotlin → Swift (JNI `.so`) → Swift library chain: + +```sh +bazel build --config=android_example \ + //examples/cross_compilation/android_app:app +``` + +It's packaged with `rules_android` + `rules_kotlin` (dev-only dependencies of +`rules_swift`) and the hermetic `@androidsdk` (no local SDK needed). See `android_app/README.md`. diff --git a/examples/cross_compilation/android_app/BUILD.bazel b/examples/cross_compilation/android_app/BUILD.bazel new file mode 100644 index 000000000..4495b86f2 --- /dev/null +++ b/examples/cross_compilation/android_app/BUILD.bazel @@ -0,0 +1,91 @@ +# A runnable Android APK that loads the Swift JNI .so and shows the Swift +# greeting on screen, completing the Kotlin -> Swift -> Swift call chain end to +# end. It is built with rules_android + rules_kotlin (the real-world way Android +# apps are packaged); those are dev-only dependencies of rules_swift (see the +# root MODULE.bazel), so consumers of rules_swift are unaffected. +# +# Build/run (the flags come from `--config=android_example` in //.bazelrc): +# +# bazel build --config=android_example \ +# //examples/cross_compilation/android_app:app +# +# Everything here is tagged `manual` (like the rest of //examples/cross_compilation, +# which fetches the Swift SDK bundle + the NDK) so it stays out of the +# `//examples/...` wildcard the other CI tasks build. + +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("@rules_android//rules:rules.bzl", "android_binary") +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") +load("//examples/embedded:transition.bzl", "transition_binary") +load("//swift/toolchains:android_runtime_lib.bzl", "select_android_runtime_lib") + +package(default_visibility = ["//visibility:private"]) + +# The NDK's shared C++ runtime, selected from the resolved Android cc toolchain +# (`@androidndk//:all`) and built for arm64 so it bundles into the APK alongside +# the Swift .so. (The NDK clang links libc++ dynamically, so the app must ship +# it; rules_swift's `select_android_runtime_lib` locates it in the cc toolchain.) +select_android_runtime_lib( + name = "libcxx_shared_lib", + tags = ["manual"], + triple = "aarch64-linux-android", +) + +transition_binary( + name = "libcxx_shared", + binary = ":libcxx_shared_lib", + platform = "//examples/cross_compilation:android-aarch64", + tags = ["manual"], +) + +# Wrap the prebuilt Swift JNI .so and libc++_shared.so as cc_libraries. A +# prebuilt .so in a cc_library's srcs becomes a CcInfo dynamic library, which +# `android_binary`'s per-ABI native split collects and packages under +# lib/arm64-v8a/. (`swift_binary(linkshared)` exposes its .so via DefaultInfo, +# not CcInfo, and `cc_import` isn't an allowed `android_binary.deps` rule, so the +# cc_library wrapper is the way in. The transitions keep the .so arm64 regardless +# of the split's configuration.) +cc_library( + name = "swift_jni_so", + srcs = ["//examples/cross_compilation:libSwiftJNI.so"], + tags = ["manual"], +) + +cc_library( + name = "libcxx_so", + srcs = [":libcxx_shared"], + tags = ["manual"], +) + +# The Kotlin host: MainActivity displays NativeBridge.greetingFromSwift(). +kt_android_library( + name = "app_lib", + srcs = [ + "java/com/example/swiftjni/MainActivity.kt", + "java/com/example/swiftjni/NativeBridge.kt", + ], + custom_package = "com.example.swiftjni", + manifest = "AndroidManifest.xml", + tags = ["manual"], +) + +# The assembled + signed APK. The two cc_library deps carry the native .so files. +android_binary( + name = "app", + manifest = "AndroidManifest.xml", + tags = ["manual"], + deps = [ + ":app_lib", + ":libcxx_so", + ":swift_jni_so", + ], +) + +# CI build coverage: asserts the APK assembles (exercises the full +# Swift .so -> rules_android packaging path). +build_test( + name = "app_build_test", + tags = ["manual"], + targets = [":app"], +) diff --git a/examples/cross_compilation/android_app/README.md b/examples/cross_compilation/android_app/README.md index d779a7921..741d47a96 100644 --- a/examples/cross_compilation/android_app/README.md +++ b/examples/cross_compilation/android_app/README.md @@ -1,7 +1,8 @@ # Android app: Kotlin → Swift JNI `.so` → Swift library -This directory shows the application half of the -Kotlin → Swift → Swift call chain that `rules_swift` enables: +A complete, runnable Android app that shows the greeting computed by Swift, +reached over JNI — the application half of the Kotlin → Swift → Swift call chain +that `rules_swift` enables: ``` MainActivity.kt ──► NativeBridge.greetingFromSwift() (Kotlin) @@ -14,114 +15,45 @@ MainActivity.kt ──► NativeBridge.greetingFromSwift() (Kotlin) //examples/cross_compilation:Greeter (swift_library) ``` -The `rules_swift` side — building `libSwiftJNI.so` from a `swift_binary` that -depends on a normal `swift_library`, and exposing the NDK's `libc++_shared.so` -at a host-independent label — is fully implemented and exercised by -`//examples/cross_compilation:libSwiftJNI.so`. +## Build & run -Packaging that `.so` into an APK is the job of the Android rules -(`rules_android` + `rules_kotlin`) and a local Android SDK. Those are heavy -dependencies (`rules_android` pulls in `rules_go`, `gazelle`, Robolectric, and a -conflicting protobuf), so `rules_swift` deliberately does **not** depend on them; -the APK target lives in *your* module instead. The sources in this directory -(`NativeBridge.kt`, `MainActivity.kt`, `AndroidManifest.xml`) are complete and -ready to drop into such a module. - -## `MODULE.bazel` (in your app's module) - -```starlark -bazel_dep(name = "rules_swift", version = "...") # or git_override to this fork -bazel_dep(name = "rules_android", version = "0.7.3") -bazel_dep(name = "rules_kotlin", version = "2.3.20") - -swift = use_extension("@rules_swift//swift:extensions.bzl", "swift") -swift.toolchain(name = "swift_toolchain", swift_version = "6.3.2") -swift.android_sdk(toolchain_name = "swift_toolchain") -use_repo(swift, "swift_toolchain") - -# One line registers every Swift SDK toolchain (and the standalone host ones). -register_toolchains("@swift_toolchain//:all") +```sh +# Build the APK (the flags live in //.bazelrc as `--config=android_example`): +bazel build --config=android_example \ + //examples/cross_compilation/android_app:app -android_sdk = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension") -use_repo(android_sdk, "androidsdk") -register_toolchains("@androidsdk//:all") +# Install on a connected device/emulator and launch: +adb install -r bazel-bin/examples/cross_compilation/android_app/app.apk +adb shell am start -n com.example.swiftjni/.MainActivity ``` -Set `ANDROID_HOME` to a local Android SDK (with `platforms;android-34` and a -recent `build-tools`). - -## `BUILD.bazel` (in your app's module) +The screen shows **“Hello from Swift, Android!”** — computed by the `Greeter` +`swift_library`, returned through the `@_cdecl` JNI entry point in +`libSwiftJNI.so`, and displayed by Kotlin. -```starlark -load("@rules_android//android:rules.bzl", "android_binary") -load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") +## How it's wired (`BUILD.bazel`) -# Lay the Swift JNI library and the NDK C++ runtime out as jniLibs for the -# arm64-v8a ABI. `libSwiftJNI.so` is the swift_binary(linkshared) output; -# `select_android_runtime_lib` selects `libc++_shared.so` from the resolved -# Android cc toolchain (build it under the android platform). -load("@rules_swift//swift/toolchains:android_runtime_lib.bzl", "select_android_runtime_lib") +The APK is built with `rules_android` (`android_binary`) and `rules_kotlin` +(`kt_android_library`) — the real-world way Android apps are packaged. The one +rules_swift-specific detail is getting the prebuilt Swift `.so` into the APK: -select_android_runtime_lib( - name = "libcxx_shared", - triple = "aarch64-linux-android", -) +- `swift_binary(linkshared = True)` exposes its `.so` via `DefaultInfo`, not + `CcInfo`, so it can't go straight into `android_binary.deps`. Wrapping it in a + `cc_library` (a prebuilt `.so` in `srcs` becomes a `CcInfo` dynamic library) + lets `android_binary`'s per-ABI native split collect it into `lib/arm64-v8a/`. +- `libc++_shared.so` (the NDK's C++ runtime, which the NDK clang links + dynamically) is selected from the resolved Android cc toolchain by + rules_swift's `select_android_runtime_lib` and packaged the same way. -genrule( - name = "jni_libs", - srcs = [ - "@rules_swift//examples/cross_compilation:libSwiftJNI.so", - ":libcxx_shared", - ], - outs = [ - "lib/arm64-v8a/libSwiftJNI.so", - "lib/arm64-v8a/libc++_shared.so", - ], - cmd = """ - srcs=($(SRCS)) - mkdir -p $(RULEDIR)/lib/arm64-v8a - cp "$${srcs[0]}" $(RULEDIR)/lib/arm64-v8a/libSwiftJNI.so - cp "$${srcs[1]}" $(RULEDIR)/lib/arm64-v8a/libc++_shared.so - """, -) +The example targets arm64 (`--android_platforms=@rules_android//:arm64-v8a`); +build the `.so` for another ABI and add a matching `cc_library` to support more. -kt_android_library( - name = "app_lib", - srcs = [ - "java/com/example/swiftjni/MainActivity.kt", - "java/com/example/swiftjni/NativeBridge.kt", - ], - manifest = "AndroidManifest.xml", -) +## Dev dependencies -android_binary( - name = "app", - manifest = "AndroidManifest.xml", - custom_package = "com.example.swiftjni", - # Bundle the native libraries laid out above. - resource_files = [], - deps = [":app_lib"], - # rules_android picks up `lib//*.so` produced by the genrule when it is - # provided as data; depending on your rules_android version you may instead - # place the .so files under `src/main/jniLibs//` or pass them through a - # `cc_library`/`android_library` `jni_libs` attribute. - data = [":jni_libs"], -) -``` - -> The exact mechanism for adding pre-built `.so`s to an `android_binary` varies -> by `rules_android` version; the constant is that `libSwiftJNI.so` and -> `libc++_shared.so` must land under `lib/arm64-v8a/` (and the corresponding -> directory for any other ABIs you build). Build the `.so` for `x86_64` with the -> `//examples/cross_compilation:android-x86_64`-equivalent platform and place it -> under `lib/x86_64/` to support the emulator. - -## Building - -```sh -# The rules_swift-side artifact (verified by this repo): -bazel build @rules_swift//examples/cross_compilation:libSwiftJNI.so - -# The APK (in your module, with the wiring above and ANDROID_HOME set): -bazel build //path/to/android_app:app -``` +`rules_android` + `rules_kotlin` (and their Maven graph) are **dev-only** +dependencies of `rules_swift` — see the root `MODULE.bazel` (all +`dev_dependency = True`) and the pinned `//:rules_android_maven_install.json`. +They never reach consumers of `rules_swift`; a consumer brings their own Android +rules. The Android SDK is the hermetic `@androidsdk` from +[`hermetic_android_toolchains`](https://github.com/keith/hermetic_android_toolchains) +(no local `$ANDROID_HOME` required). diff --git a/rules_android_maven_install.json b/rules_android_maven_install.json new file mode 100755 index 000000000..85698634a --- /dev/null +++ b/rules_android_maven_install.json @@ -0,0 +1,5426 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": { + "androidx.databinding:databinding-compiler": 783253192, + "androidx.privacysandbox.tools:tools": 260044968, + "androidx.privacysandbox.tools:tools-apigenerator": 1715129262, + "androidx.privacysandbox.tools:tools-apipackager": -825133791, + "androidx.test.ext:junit": -270978287, + "androidx.test:core": -678478071, + "com.android.tools.apkdeployer:apkdeployer": -1433133189, + "com.android.tools.build:aapt2-proto": 1126539235, + "com.android.tools.build:apksig": -1518382387, + "com.android.tools.build:apkzlib": 285298697, + "com.android.tools.build:bundletool": 1244320477, + "com.android.tools.build:gradle": -100479777, + "com.android.tools:desugar_jdk_libs_configuration": 1628685326, + "com.android.tools:desugar_jdk_libs_configuration_minimal": 1192686832, + "com.android.tools:desugar_jdk_libs_configuration_nio": 1800584355, + "com.android.tools:desugar_jdk_libs_minimal": 1591858937, + "com.android.tools:desugar_jdk_libs_nio": 1407847212, + "com.android.tools:r8": 1967354745, + "com.android:signflinger": 5110881, + "com.android:zipflinger": 1989593331, + "com.beust:jcommander": -1790778431, + "com.google.auto.service:auto-service": -1729498094, + "com.google.auto.service:auto-service-annotations": -843120535, + "com.google.auto.value:auto-value": 1146221104, + "com.google.auto.value:auto-value-annotations": -1101276935, + "com.google.auto:auto-common": -832702775, + "com.google.code.findbugs:jsr305": 495355163, + "com.google.errorprone:error_prone_annotations": -442228676, + "com.google.errorprone:error_prone_check_api": -462382627, + "com.google.errorprone:error_prone_core": -40568825, + "com.google.errorprone:error_prone_type_annotations": -256308857, + "com.google.flogger:flogger": -825712792, + "com.google.flogger:flogger-system-backend": 1522076251, + "com.google.guava:failureaccess": 1582410452, + "com.google.guava:guava": -1137009876, + "com.google.guava:guava-testlib": -724978605, + "com.google.jimfs:jimfs": -1004381565, + "com.google.testing.compile:compile-testing": 421834972, + "com.google.testparameterinjector:test-parameter-injector": -551082624, + "com.google.truth.extensions:truth-java8-extension": -1489436114, + "com.google.truth.extensions:truth-liteproto-extension": 103162706, + "com.google.truth.extensions:truth-proto-extension": -89782976, + "com.google.truth:truth": 2144119175, + "info.picocli:picocli": 1728074233, + "jakarta.inject:jakarta.inject-api": 190564362, + "junit:junit": -744267592, + "org.bouncycastle:bcprov-jdk18on": 1958694455, + "org.hamcrest:hamcrest-core": -1340662768, + "org.mockito:mockito-core": 2076415653, + "org.ow2.asm:asm": 905490297, + "org.ow2.asm:asm-commons": -1641575852, + "org.ow2.asm:asm-tree": 884936356, + "org.ow2.asm:asm-util": 820191240, + "org.robolectric:robolectric": 1809563374, + "repositories": 1670674627 + }, + "__RESOLVED_ARTIFACTS_HASH": { + "androidx.annotation:annotation": -71007237, + "androidx.annotation:annotation-experimental:aar": -693774503, + "androidx.annotation:annotation-jvm": 755298383, + "androidx.concurrent:concurrent-futures": 1877279226, + "androidx.databinding:databinding-common": -830969719, + "androidx.databinding:databinding-compiler": 1048151336, + "androidx.databinding:databinding-compiler-common": -1924832877, + "androidx.lifecycle:lifecycle-common": 132345499, + "androidx.privacysandbox.tools:tools": -915523372, + "androidx.privacysandbox.tools:tools-apigenerator": 12203445, + "androidx.privacysandbox.tools:tools-apipackager": -424316984, + "androidx.privacysandbox.tools:tools-core": 154923387, + "androidx.test.espresso:espresso-idling-resource:aar": -419264045, + "androidx.test.ext:junit:aar": -9314161, + "androidx.test.services:storage:aar": -2032638480, + "androidx.test:annotation:aar": 371275418, + "androidx.test:core:aar": 2057521073, + "androidx.test:monitor:aar": -918095258, + "androidx.tracing:tracing:aar": 1847043151, + "com.almworks.sqlite4java:sqlite4java": 1585971300, + "com.android.databinding:baseLibrary": 1346054104, + "com.android.tools.adblib:adblib": -1005989637, + "com.android.tools.adblib:adblib-tools": 135180617, + "com.android.tools.analytics-library:crash": 1974526916, + "com.android.tools.analytics-library:protos": 2027590314, + "com.android.tools.analytics-library:shared": -2090103599, + "com.android.tools.analytics-library:tracker": 469112493, + "com.android.tools.apkdeployer:apkdeployer": 1221767944, + "com.android.tools.apkparser:binary-resources": 422388365, + "com.android.tools.build.jetifier:jetifier-core": 1531128315, + "com.android.tools.build.jetifier:jetifier-processor": -2125786732, + "com.android.tools.build:aapt2-proto": 1879136903, + "com.android.tools.build:aaptcompiler": -1851935348, + "com.android.tools.build:apksig": -132861103, + "com.android.tools.build:apkzlib": -1156943369, + "com.android.tools.build:builder": -238368295, + "com.android.tools.build:builder-model": -428315610, + "com.android.tools.build:builder-test-api": 40026603, + "com.android.tools.build:bundletool": 492701178, + "com.android.tools.build:gradle": 1804224714, + "com.android.tools.build:gradle-api": -1037800157, + "com.android.tools.build:gradle-settings-api": -12563313, + "com.android.tools.build:manifest-merger": 521330918, + "com.android.tools.build:transform-api": -1603282576, + "com.android.tools.ddms:ddmlib": -344863490, + "com.android.tools.layoutlib:layoutlib-api": 1753594039, + "com.android.tools.lint:lint-model": -569778976, + "com.android.tools.lint:lint-typedef-remover": 1066906429, + "com.android.tools.utp:android-device-provider-ddmlib-proto": 713461290, + "com.android.tools.utp:android-device-provider-gradle-proto": -1641494983, + "com.android.tools.utp:android-device-provider-profile-proto": 1296661623, + "com.android.tools.utp:android-test-plugin-host-additional-test-output-proto": -1407329698, + "com.android.tools.utp:android-test-plugin-host-apk-installer-proto": 1942554268, + "com.android.tools.utp:android-test-plugin-host-coverage-proto": 1644803478, + "com.android.tools.utp:android-test-plugin-host-emulator-control-proto": -87253430, + "com.android.tools.utp:android-test-plugin-host-logcat-proto": -1752569609, + "com.android.tools.utp:android-test-plugin-host-retention-proto": 269565690, + "com.android.tools.utp:android-test-plugin-result-listener-gradle-proto": -462111362, + "com.android.tools:annotations": -474154037, + "com.android.tools:common": -97409, + "com.android.tools:desugar_jdk_libs_configuration": 70006298, + "com.android.tools:desugar_jdk_libs_configuration_minimal": -1204210384, + "com.android.tools:desugar_jdk_libs_configuration_nio": -1927002988, + "com.android.tools:desugar_jdk_libs_minimal": 2138982643, + "com.android.tools:desugar_jdk_libs_nio": 111027300, + "com.android.tools:dvlib": 1336874510, + "com.android.tools:r8": -647856975, + "com.android.tools:repository": 1486772552, + "com.android.tools:sdk-common": 1699346456, + "com.android.tools:sdklib": -212682908, + "com.android:signflinger": -1328005565, + "com.android:zipflinger": 1049675655, + "com.beust:jcommander": -2120169146, + "com.github.ben-manes.caffeine:caffeine": 485938992, + "com.github.kevinstern:software-and-algorithms": 2052480962, + "com.google.android:annotations": 2096496032, + "com.google.api.grpc:proto-google-common-protos": -1849982900, + "com.google.auto.service:auto-service": -1259184058, + "com.google.auto.service:auto-service-annotations": 262983930, + "com.google.auto.value:auto-value": 1110951021, + "com.google.auto.value:auto-value-annotations": 641018093, + "com.google.auto:auto-common": -1638517079, + "com.google.code.findbugs:jsr305": 870839855, + "com.google.code.gson:gson": -2085536727, + "com.google.crypto.tink:tink": 606277437, + "com.google.dagger:dagger": -657715774, + "com.google.errorprone:error_prone_annotation": 1981397787, + "com.google.errorprone:error_prone_annotations": 1146986774, + "com.google.errorprone:error_prone_check_api": -1269625186, + "com.google.errorprone:error_prone_core": 1998856892, + "com.google.errorprone:error_prone_type_annotations": -850168805, + "com.google.flatbuffers:flatbuffers-java": -165420746, + "com.google.flogger:flogger": -1346444653, + "com.google.flogger:flogger-system-backend": 1919472289, + "com.google.guava:failureaccess": -718864417, + "com.google.guava:guava": 2139131367, + "com.google.guava:guava-testlib": -1172786314, + "com.google.guava:listenablefuture": 1079558157, + "com.google.j2objc:j2objc-annotations": -404209759, + "com.google.jimfs:jimfs": -1122068596, + "com.google.protobuf:protobuf-java": 1668417350, + "com.google.protobuf:protobuf-java-util": -273222167, + "com.google.testing.compile:compile-testing": 626180405, + "com.google.testing.platform:core-proto": 527627836, + "com.google.testparameterinjector:test-parameter-injector": -1070902817, + "com.google.truth.extensions:truth-java8-extension": 1987726514, + "com.google.truth.extensions:truth-liteproto-extension": -1614796468, + "com.google.truth.extensions:truth-proto-extension": -1158956226, + "com.google.truth:truth": 183102370, + "com.googlecode.juniversalchardet:juniversalchardet": -1689124048, + "com.ibm.icu:icu4j": -2015640546, + "com.squareup:javapoet": 1976481703, + "com.squareup:javawriter": 1260780548, + "com.squareup:kotlinpoet": -1863489937, + "com.sun.activation:javax.activation": 833641300, + "com.sun.istack:istack-commons-runtime": -733848051, + "com.sun.xml.fastinfoset:FastInfoset": 705289510, + "commons-codec:commons-codec": 1434473311, + "commons-io:commons-io": -269079134, + "commons-logging:commons-logging": 1248790901, + "info.picocli:picocli": -1004002055, + "io.github.eisop:dataflow-errorprone": 1875600084, + "io.github.java-diff-utils:java-diff-utils": -1540151507, + "io.grpc:grpc-api": -1580416076, + "io.grpc:grpc-context": -334820686, + "io.grpc:grpc-core": 1920833048, + "io.grpc:grpc-netty": -1693506054, + "io.grpc:grpc-protobuf": -329749950, + "io.grpc:grpc-protobuf-lite": -330957716, + "io.grpc:grpc-stub": -1744060168, + "io.netty:netty-buffer": 2136790867, + "io.netty:netty-codec": -1507877204, + "io.netty:netty-codec-http": 1682650710, + "io.netty:netty-codec-http2": 1647321664, + "io.netty:netty-codec-socks": -252623028, + "io.netty:netty-common": -2052466401, + "io.netty:netty-handler": -1647291088, + "io.netty:netty-handler-proxy": 291809139, + "io.netty:netty-resolver": 293070298, + "io.netty:netty-transport": 651303654, + "io.netty:netty-transport-native-unix-common": 642832620, + "io.perfmark:perfmark-api": 159265143, + "jakarta.activation:jakarta.activation-api": 196614426, + "jakarta.inject:jakarta.inject-api": 188991469, + "jakarta.xml.bind:jakarta.xml.bind-api": 1749682402, + "javax.annotation:javax.annotation-api": -1009230154, + "javax.inject:javax.inject": 698155243, + "junit:junit": 1626373082, + "net.bytebuddy:byte-buddy": 1086524953, + "net.bytebuddy:byte-buddy-agent": 1999612366, + "net.java.dev.jna:jna": 1182309070, + "net.java.dev.jna:jna-platform": -1651247774, + "net.sf.jopt-simple:jopt-simple": -2071864669, + "net.sf.kxml:kxml2": 181311874, + "org.apache.commons:commons-compress": 2110676592, + "org.apache.httpcomponents:httpclient": -277175505, + "org.apache.httpcomponents:httpcore": 67453319, + "org.apache.httpcomponents:httpmime": 98069319, + "org.bitbucket.b_c:jose4j": 1753430613, + "org.bouncycastle:bcpkix-jdk18on": 1479399750, + "org.bouncycastle:bcprov-jdk18on": -1198463192, + "org.bouncycastle:bcutil-jdk18on": 812437278, + "org.checkerframework:checker-compat-qual": -1467964223, + "org.checkerframework:checker-qual": -1158206121, + "org.codehaus.mojo:animal-sniffer-annotations": -759588484, + "org.conscrypt:conscrypt-openjdk-uber": 742580967, + "org.glassfish.jaxb:jaxb-runtime": -1363105419, + "org.glassfish.jaxb:txw2": 1008506230, + "org.hamcrest:hamcrest": -820511133, + "org.hamcrest:hamcrest-core": 1709140352, + "org.jdom:jdom2": 2016421531, + "org.jetbrains.kotlin:kotlin-reflect": 60970917, + "org.jetbrains.kotlin:kotlin-stdlib": 661411577, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": 1378837705, + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": -914118602, + "org.jetbrains.kotlinx:kotlinx-coroutines-core": -1927043705, + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": 1392787226, + "org.jetbrains.kotlinx:kotlinx-metadata-jvm": 1569126537, + "org.jetbrains:annotations": -1663747638, + "org.jspecify:jspecify": 117231129, + "org.jvnet.staxex:stax-ex": -1540368555, + "org.mockito:mockito-core": -1129661008, + "org.objenesis:objenesis": 1798216877, + "org.ow2.asm:asm": -1101379267, + "org.ow2.asm:asm-analysis": -559036312, + "org.ow2.asm:asm-commons": 1034366166, + "org.ow2.asm:asm-tree": -1479389285, + "org.ow2.asm:asm-util": -824669353, + "org.pcollections:pcollections": -1523748864, + "org.robolectric:annotations": -405033800, + "org.robolectric:junit": -1693042492, + "org.robolectric:nativeruntime": 1143376221, + "org.robolectric:nativeruntime-dist-compat": 1467761799, + "org.robolectric:pluginapi": 816510301, + "org.robolectric:plugins-maven-dependency-resolver": 470940045, + "org.robolectric:resources": -1471446418, + "org.robolectric:robolectric": 621675227, + "org.robolectric:sandbox": -226824678, + "org.robolectric:shadowapi": 1558856404, + "org.robolectric:shadows-framework": -2013999441, + "org.robolectric:utils": -74197370, + "org.robolectric:utils-reflector": -1293968723, + "org.slf4j:slf4j-api": -801231047, + "org.tensorflow:tensorflow-lite-metadata": -1344642840, + "org.xerial:sqlite-jdbc": -1986691968, + "org.yaml:snakeyaml": 1733283626 + }, + "conflict_resolution": { + "com.android.tools.build:aapt2-proto:8.6.1-11315950": "com.android.tools.build:aapt2-proto:8.11.0-alpha10-12782657", + "com.android:zipflinger:8.7.0": "com.android:zipflinger:8.11.0-alpha10", + "com.google.guava:failureaccess:1.0.1": "com.google.guava:failureaccess:1.0.2", + "com.google.guava:guava:32.1.2-jre": "com.google.guava:guava:33.3.1-jre", + "com.google.testparameterinjector:test-parameter-injector:1.16": "com.google.testparameterinjector:test-parameter-injector:1.18", + "org.bouncycastle:bcprov-jdk18on:1.77": "org.bouncycastle:bcprov-jdk18on:1.79", + "org.ow2.asm:asm-commons:9.6": "org.ow2.asm:asm-commons:9.7.1", + "org.ow2.asm:asm-tree:9.6": "org.ow2.asm:asm-tree:9.7.1", + "org.ow2.asm:asm-util:9.6": "org.ow2.asm:asm-util:9.7.1", + "org.ow2.asm:asm:9.6": "org.ow2.asm:asm:9.7.1" + }, + "artifacts": { + "androidx.annotation:annotation": { + "shasums": { + "jar": "b11676837cad011a5285d6074418649107ef25eba17131517e9557ef8c9984ed" + }, + "version": "1.7.0-beta01" + }, + "androidx.annotation:annotation-experimental:aar": { + "shasums": { + "jar": "0157de61a2064047896a058080f3fd67ba57ad9a94857b3f7a363660243e3f90" + }, + "version": "1.1.0" + }, + "androidx.annotation:annotation-jvm": { + "shasums": { + "jar": "e36b8e4b8393a4adc74e3d4ab22ad5a36396f0cea2e40b5734eae14937dfd224" + }, + "version": "1.7.0-beta01" + }, + "androidx.concurrent:concurrent-futures": { + "shasums": { + "jar": "0ce067c514a0d1049d1bebdf709e344ed3266fe9744275682937cdcb13334e9e" + }, + "version": "1.1.0" + }, + "androidx.databinding:databinding-common": { + "shasums": { + "jar": "66cab82639dac0f6c2433464c093b074d608c4bb887ec38a9b8bc4ac98126732" + }, + "version": "8.7.0" + }, + "androidx.databinding:databinding-compiler": { + "shasums": { + "jar": "ec92b3db7362b04929b4415542e7b1791cac76b03465f36d7de61fdbcc6e22ca" + }, + "version": "8.7.0" + }, + "androidx.databinding:databinding-compiler-common": { + "shasums": { + "jar": "f4ccc0eafca4a47be5bf910209b986ac0921b6b5b52caa1bf4aa52900d244edd" + }, + "version": "8.7.0" + }, + "androidx.lifecycle:lifecycle-common": { + "shasums": { + "jar": "15848fb56db32f4c7cdc72b324003183d52a4884d6bf09be708ac7f587d139b5" + }, + "version": "2.3.1" + }, + "androidx.privacysandbox.tools:tools": { + "shasums": { + "jar": "83b78a665834bb554e8fb6cee1bc8fb81f0c55383f9fb44aedea44682393d4c8" + }, + "version": "1.0.0-alpha06" + }, + "androidx.privacysandbox.tools:tools-apigenerator": { + "shasums": { + "jar": "e37efef8a51df25d414aa6d3c5d4b7514ee98d83f3fc764f326fe96c646e0da0" + }, + "version": "1.0.0-alpha06" + }, + "androidx.privacysandbox.tools:tools-apipackager": { + "shasums": { + "jar": "bc5934f84730b7c4fe10d96e767beaf756197fc5bb7dc1c123ebf9d40a512d6c" + }, + "version": "1.0.0-alpha06" + }, + "androidx.privacysandbox.tools:tools-core": { + "shasums": { + "jar": "c2b88a261f38e0c3f09d46f8dc9daa0f562e26b3ebeffb4cb52903e4704f870a" + }, + "version": "1.0.0-alpha06" + }, + "androidx.test.espresso:espresso-idling-resource:aar": { + "shasums": { + "jar": "bc63a8780f1c707724e389f530cb2e1a6847da97f6a8114604c002aba2fd86ca" + }, + "version": "3.6.1" + }, + "androidx.test.ext:junit:aar": { + "shasums": { + "jar": "54362f0f2589d0d32fe8866bedd1471f63847a7e56f74b2cd6b71355eb134304" + }, + "version": "1.2.0-alpha01" + }, + "androidx.test.services:storage:aar": { + "shasums": { + "jar": "f6540dd19e7cb6fb5f075232c3c582fc04c6a6d25ec8c5fdfac2c35e18a673d0" + }, + "version": "1.5.0-alpha01" + }, + "androidx.test:annotation:aar": { + "shasums": { + "jar": "361dd1910ced2fb3a01c0ff9d1f318affb76466a9173b3648a4f2d3c6c2c2cdf" + }, + "version": "1.1.0-alpha01" + }, + "androidx.test:core:aar": { + "shasums": { + "jar": "404e752d20e4f1b8e1f5a31ea4bfa00ee777ecc39e9e81f837c7f3571ba21cf1" + }, + "version": "1.6.0-alpha01" + }, + "androidx.test:monitor:aar": { + "shasums": { + "jar": "868cc120d10d024b886fa157e1e1eaee0e6a8e5d55e7f765ef41d8fc0fea775b" + }, + "version": "1.7.2" + }, + "androidx.tracing:tracing:aar": { + "shasums": { + "jar": "5b78e2c618fc10b3d14decc01df76158f15954ad746aacf0607766721da081f6" + }, + "version": "1.1.0" + }, + "com.almworks.sqlite4java:sqlite4java": { + "shasums": { + "jar": "243a64470fda0e86a6fddeb0af4c7aa9426ce84e68cbfe18d75ee5da4b7e0b92" + }, + "version": "1.0.392" + }, + "com.android.databinding:baseLibrary": { + "shasums": { + "jar": "794113709dab21b06c262b3795e73cb708fbacae61715f34361e1af6237a1870" + }, + "version": "8.7.0" + }, + "com.android.tools.adblib:adblib": { + "shasums": { + "jar": "e135e7707bf51f21be1ed58e149f814ec17b36bbfda5bad067c3eae9e54aaa1f" + }, + "version": "8.11.0-alpha10" + }, + "com.android.tools.adblib:adblib-tools": { + "shasums": { + "jar": "96e5eb477c9885e63ed18a5b1e6fd7bcdf71d4248b4aef08a9ce5689a1ee697d" + }, + "version": "8.11.0-alpha10" + }, + "com.android.tools.analytics-library:crash": { + "shasums": { + "jar": "cca97ac29a1329bd310a3e832b6e57f46227e501aa529c00a63df217c5d7df41" + }, + "version": "31.7.0" + }, + "com.android.tools.analytics-library:protos": { + "shasums": { + "jar": "fe08d0175ddf6ee17463aa047a44024b07626b41676e693b2091cb4e227fa598" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools.analytics-library:shared": { + "shasums": { + "jar": "306355bafa0727ab1bffcab94ba4b607f8ce7b953c9ba20d58d72b325c1a8ce7" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools.analytics-library:tracker": { + "shasums": { + "jar": "e1f954973a4733f76027a5f96fa45472dc3cc22d27b1dc93f3fe6a46a75681be" + }, + "version": "31.7.0" + }, + "com.android.tools.apkdeployer:apkdeployer": { + "shasums": { + "jar": "a2f46e74e51fbc53291c77e7148ebc2fe7765510fad7f2b575a4314712f9e147" + }, + "version": "8.11.0-alpha10" + }, + "com.android.tools.apkparser:binary-resources": { + "shasums": { + "jar": "fb5bd78c9ba5124602358455045b53270ebf215ff80d42a59af9c5a2f21a906f" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools.build.jetifier:jetifier-core": { + "shasums": { + "jar": "26abb4a13927d9062169c504c9e94fe80e9ae3a4f7b5ab8875ab007536a91f5e" + }, + "version": "1.0.0-beta10" + }, + "com.android.tools.build.jetifier:jetifier-processor": { + "shasums": { + "jar": "c5067a7b928237a1271a5e9cb5710e9f80b4973293945bc51e3a4c864ea4bfed" + }, + "version": "1.0.0-beta10" + }, + "com.android.tools.build:aapt2-proto": { + "shasums": { + "jar": "8efcf192c2e54a1c1388b5f648280aa05773fc43e8e5d2a94051bc2380e107df" + }, + "version": "8.11.0-alpha10-12782657" + }, + "com.android.tools.build:aaptcompiler": { + "shasums": { + "jar": "ea4a886009444435f7a19fcaede1eaf180e8d85145f7c52a4ba87cbc356c563a" + }, + "version": "8.7.0" + }, + "com.android.tools.build:apksig": { + "shasums": { + "jar": "c070ed1394629d74641aa0906f60b2ffa1ee77e6366a1f93437f59717b1aeb89" + }, + "version": "8.7.0" + }, + "com.android.tools.build:apkzlib": { + "shasums": { + "jar": "1c1a67d6f4f186427ac166ebaa0dd867f595d5144fc925252b05ffb9d1a156b7" + }, + "version": "8.7.0" + }, + "com.android.tools.build:builder": { + "shasums": { + "jar": "89b5beb3396a8b4529bccc653b321a9cd968e25245be3b1c320189759abb6edf" + }, + "version": "8.7.0" + }, + "com.android.tools.build:builder-model": { + "shasums": { + "jar": "a96dc78cf39b4e569de90e8150b5efa66642d25908caf2890c603cc647a16c78" + }, + "version": "8.7.0" + }, + "com.android.tools.build:builder-test-api": { + "shasums": { + "jar": "c32506113d10a5196b5e3f869802722c8f228c123086c04852f866cdf78c050d" + }, + "version": "8.7.0" + }, + "com.android.tools.build:bundletool": { + "shasums": { + "jar": "80e02a1bc7063bed3d310c670f70f6de453d06c589ecb6dc05e0ac45fc9b2e50" + }, + "version": "1.18.2" + }, + "com.android.tools.build:gradle": { + "shasums": { + "jar": "1f56b870c409b61e79883aa4027a22c48cafc0cacd004f4def3f2dea1882faa5" + }, + "version": "8.7.0" + }, + "com.android.tools.build:gradle-api": { + "shasums": { + "jar": "09e441732c94c811b9f685d840edee4a986ee7b322e10abb6f0abdfd6c7c3382" + }, + "version": "8.7.0" + }, + "com.android.tools.build:gradle-settings-api": { + "shasums": { + "jar": "7ddfc77332dee3585243152238ff00ac47b1707a419c0f1448453a0498fb6836" + }, + "version": "8.7.0" + }, + "com.android.tools.build:manifest-merger": { + "shasums": { + "jar": "ab92276434e5a61e86c590e7b19f2de161778fa275fc08a8eec84081e2703bb3" + }, + "version": "31.7.0" + }, + "com.android.tools.build:transform-api": { + "shasums": { + "jar": "4de4a3d05e1c534c2db9e4588bf34082bb2bd232d8abb9727c430290ce225740" + }, + "version": "2.0.0-deprecated-use-gradle-api" + }, + "com.android.tools.ddms:ddmlib": { + "shasums": { + "jar": "839957f961100713ea0eed628a8684cc39aa479631c36249793e6df7e0cd63d8" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools.layoutlib:layoutlib-api": { + "shasums": { + "jar": "d06bc650247632a4a4e6596b87312019f45e900267c5476c47a5bfa6e3fd3132" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools.lint:lint-model": { + "shasums": { + "jar": "9f4c087a199174521d1bc7b8ff05ff1484f770f4518b7fd9f6dae6c261882dbd" + }, + "version": "31.7.0" + }, + "com.android.tools.lint:lint-typedef-remover": { + "shasums": { + "jar": "5b4f485215ca4d86ef2319fc398b5f2251e62f5446bc5fd0e00653648ddde318" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-device-provider-ddmlib-proto": { + "shasums": { + "jar": "da9f3f3dae26544c90668549584765d5854a87c425d2cfe577cd34d3600ea097" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-device-provider-gradle-proto": { + "shasums": { + "jar": "ad2342bb1d6f95563400a322493ea1c229cb93df3944f1261b7399f718494049" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-device-provider-profile-proto": { + "shasums": { + "jar": "10d100ced5d083714c1c68bbbb10bb375e8546f92ab0e4219c0e4a5ff298115e" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-test-plugin-host-additional-test-output-proto": { + "shasums": { + "jar": "38450694de6328c2c4cba696f9c04ecdd5ce6952355f68c3a22f9541d1d6546f" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-test-plugin-host-apk-installer-proto": { + "shasums": { + "jar": "543eb6c8d72b2ed7451f8e939d5d80890566f14bc26b7df9c8347506b258d7ae" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-test-plugin-host-coverage-proto": { + "shasums": { + "jar": "efb4d7014aaa7355246a07c2e437a2231fb252540ff1bce6872c88dc8da89d12" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-test-plugin-host-emulator-control-proto": { + "shasums": { + "jar": "aedec5ec4627d898cccdf42d8038db20eba4495753c53d1b0b378734491caf5f" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-test-plugin-host-logcat-proto": { + "shasums": { + "jar": "9129024bd8e38353bca3eb26dfd8e3628e058d57d6e9d8451ffc35f016751e63" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-test-plugin-host-retention-proto": { + "shasums": { + "jar": "3db8ed38ef49b694caea466ae22e3b36cedc9557b3589d0e07c0cdd83294591c" + }, + "version": "31.7.0" + }, + "com.android.tools.utp:android-test-plugin-result-listener-gradle-proto": { + "shasums": { + "jar": "cbdf71bca60e14c30e7b2cf4b90f0f0a3e8c138f7cadd874b0d9c0ae082e0274" + }, + "version": "31.7.0" + }, + "com.android.tools:annotations": { + "shasums": { + "jar": "3b4bb9620c17d19e5bd91ac1988080553573b4c3b739fdd92416f42f2daf3e78" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools:common": { + "shasums": { + "jar": "f93c8450118d7c9db3962d316794321dda3a890d10726a6b6a45d0899a05b8bc" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools:desugar_jdk_libs_configuration": { + "shasums": { + "jar": "7bc9051b3a1ec19806311dcb6aa9b9ba7ef9c22caa6f4810da55bde285fb7770" + }, + "version": "2.1.5" + }, + "com.android.tools:desugar_jdk_libs_configuration_minimal": { + "shasums": { + "jar": "09704d34fd1ef3937b504d53a0083fa5e0bb0f275c4241a0b6c2da56ac6f8a05" + }, + "version": "2.1.5" + }, + "com.android.tools:desugar_jdk_libs_configuration_nio": { + "shasums": { + "jar": "7db51661cd07d1fd5cf12769a75ba201910624bb3801c09363dd3cb28e31c51b" + }, + "version": "2.1.5" + }, + "com.android.tools:desugar_jdk_libs_minimal": { + "shasums": { + "jar": "d8044befae095781b9a80bf1faa92edc30382d75d437476784c1bf991598a976" + }, + "version": "2.1.5" + }, + "com.android.tools:desugar_jdk_libs_nio": { + "shasums": { + "jar": "d8044befae095781b9a80bf1faa92edc30382d75d437476784c1bf991598a976" + }, + "version": "2.1.5" + }, + "com.android.tools:dvlib": { + "shasums": { + "jar": "e3cf3fdc947788dee8d5baa76cb72a66571174bc4741edf0e3bab97a7ca90e1b" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools:r8": { + "shasums": { + "jar": "3b4de3053885da105e39c15212261d22653d6d1b5eb92323dd04ae913cc8286f" + }, + "version": "9.1.31" + }, + "com.android.tools:repository": { + "shasums": { + "jar": "095becb618937d1d2a4d77a921d70563ec9ffda05d62ec1aff6a9bae701d39da" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools:sdk-common": { + "shasums": { + "jar": "46f4645222d393c1131be1e66fdc0be0da4d7f2ab3c68a728308367f99f3bdf2" + }, + "version": "31.11.0-alpha10" + }, + "com.android.tools:sdklib": { + "shasums": { + "jar": "d2360450812c5b0a785d7ca4927d022fee557c45132a220ea87e6df2460c3790" + }, + "version": "31.11.0-alpha10" + }, + "com.android:signflinger": { + "shasums": { + "jar": "c1dca2c683634ee1a294298f9c7179578af6a86e080bdc40f961915bc5c8142f" + }, + "version": "8.7.0" + }, + "com.android:zipflinger": { + "shasums": { + "jar": "a6a68f03e8d9f8944688c36c6d16c253e81a625930af1d0eb5e592bd2b2da9e8" + }, + "version": "8.11.0-alpha10" + }, + "com.beust:jcommander": { + "shasums": { + "jar": "deeac157c8de6822878d85d0c7bc8467a19cc8484d37788f7804f039dde280b1" + }, + "version": "1.82" + }, + "com.github.ben-manes.caffeine:caffeine": { + "shasums": { + "jar": "8a9b54d3506a3b92ee46b217bcee79196b21ca6d52dc2967c686a205fb2f9c15" + }, + "version": "3.0.5" + }, + "com.github.kevinstern:software-and-algorithms": { + "shasums": { + "jar": "61ab82439cef37343b14f53154c461619375373a56b9338e895709fb54e0864c" + }, + "version": "1.0" + }, + "com.google.android:annotations": { + "shasums": { + "jar": "ba734e1e84c09d615af6a09d33034b4f0442f8772dec120efb376d86a565ae15" + }, + "version": "4.1.1.4" + }, + "com.google.api.grpc:proto-google-common-protos": { + "shasums": { + "jar": "4ef1fe0c327fc1521d1d753b0b1c4a875a54bd14ebded3afff0ca395320b6ea9" + }, + "version": "2.17.0" + }, + "com.google.auto.service:auto-service": { + "shasums": { + "jar": "1f48f451503e623daba7d9ed368cca0f81e1e3815653a4560113e12c0129ebd5" + }, + "version": "1.1.1" + }, + "com.google.auto.service:auto-service-annotations": { + "shasums": { + "jar": "16a76dd00a2650568447f5d6e3a9e2c809d9a42367d56b45215cfb89731f4d24" + }, + "version": "1.1.1" + }, + "com.google.auto.value:auto-value": { + "shasums": { + "jar": "aaf8d637bfed3c420436b9facf1b7a88d12c8785374e4202382783005319c2c3" + }, + "version": "1.11.0" + }, + "com.google.auto.value:auto-value-annotations": { + "shasums": { + "jar": "5a055ce4255333b3346e1a8703da5bf8ff049532286fdcd31712d624abe111dd" + }, + "version": "1.11.0" + }, + "com.google.auto:auto-common": { + "shasums": { + "jar": "f50b1ce8a41fad31a8a819c052f8ffa362ea0a3dbe9ef8f7c7dc9a36d4738a59" + }, + "version": "1.2.2" + }, + "com.google.code.findbugs:jsr305": { + "shasums": { + "jar": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" + }, + "version": "3.0.2" + }, + "com.google.code.gson:gson": { + "shasums": { + "jar": "57928d6e5a6edeb2abd3770a8f95ba44dce45f3b23b7a9dc2b309c581552a78b" + }, + "version": "2.11.0" + }, + "com.google.crypto.tink:tink": { + "shasums": { + "jar": "88970a456a08ba4c66b01b23e5846ca1095cc14e54cb48363e5d2e15a1307308" + }, + "version": "1.7.0" + }, + "com.google.dagger:dagger": { + "shasums": { + "jar": "f1dd23f8ae34a8e91366723991ead0d6499d1a3e9163ce550c200b02d76a872b" + }, + "version": "2.28.3" + }, + "com.google.errorprone:error_prone_annotation": { + "shasums": { + "jar": "99f8b53c75a50617d4f9bf45512eda82e7d8e9eb377471d822d3d4c4e034c510" + }, + "version": "2.34.0" + }, + "com.google.errorprone:error_prone_annotations": { + "shasums": { + "jar": "d9f3af3974fa64cd0f0f34238f40d9898abf7df19ca15849e1978f5beb818cb6" + }, + "version": "2.33.0" + }, + "com.google.errorprone:error_prone_check_api": { + "shasums": { + "jar": "77a1472108ccfb9dcd91ebc7d534453d7a6e8730296f691cb26a7dfb1bc6e8df" + }, + "version": "2.33.0" + }, + "com.google.errorprone:error_prone_core": { + "shasums": { + "jar": "fa9718dede454324b69ea4be67ea1b87ddf4642fd3f62ec022fe448c33ff8a64" + }, + "version": "2.33.0" + }, + "com.google.errorprone:error_prone_type_annotations": { + "shasums": { + "jar": "5811125e354ad7350d8a7756af67f6455773f4f4fba8faed096ae15551dbd372" + }, + "version": "2.33.0" + }, + "com.google.flatbuffers:flatbuffers-java": { + "shasums": { + "jar": "3f8c088b4dd04a9858721f2e162508c94db0dd86f961e306ee63ef2eda871bf7" + }, + "version": "1.12.0" + }, + "com.google.flogger:flogger": { + "shasums": { + "jar": "bebe7cd82be6c8d5208d6e960cd4344ea10672132ef06f5d4c71a48ab442b963" + }, + "version": "0.8" + }, + "com.google.flogger:flogger-system-backend": { + "shasums": { + "jar": "eb4428e483c5332381778d78c6a19da63b4fef3fa7e40f62dadabea0d7600cb4" + }, + "version": "0.8" + }, + "com.google.guava:failureaccess": { + "shasums": { + "jar": "8a8f81cf9b359e3f6dfa691a1e776985c061ef2f223c9b2c80753e1b458e8064" + }, + "version": "1.0.2" + }, + "com.google.guava:guava": { + "shasums": { + "jar": "4bf0e2c5af8e4525c96e8fde17a4f7307f97f8478f11c4c8e35a0e3298ae4e90" + }, + "version": "33.3.1-jre" + }, + "com.google.guava:guava-testlib": { + "shasums": { + "jar": "5ec141072658424f40cd30b91467f5ce63c0e617b91ec927df7256efdfd2d84a" + }, + "version": "33.2.1-jre" + }, + "com.google.guava:listenablefuture": { + "shasums": { + "jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" + }, + "version": "9999.0-empty-to-avoid-conflict-with-guava" + }, + "com.google.j2objc:j2objc-annotations": { + "shasums": { + "jar": "88241573467ddca44ffd4d74aa04c2bbfd11bf7c17e0c342c94c9de7a70a7c64" + }, + "version": "3.0.0" + }, + "com.google.jimfs:jimfs": { + "shasums": { + "jar": "de16d5c8489729a8512f1a02fbd81f58f89249b72066987da4cc5c87ecb9f72d" + }, + "version": "1.2" + }, + "com.google.protobuf:protobuf-java": { + "shasums": { + "jar": "707bccf406f4fc61b841d4700daa8d3e84db8ab499ef3481a060fa6a0f06e627" + }, + "version": "4.28.2" + }, + "com.google.protobuf:protobuf-java-util": { + "shasums": { + "jar": "c615f76879dc5c303e4df5b94a6afa39534058c7545db2d483fd95d9f63c8bfe" + }, + "version": "3.22.3" + }, + "com.google.testing.compile:compile-testing": { + "shasums": { + "jar": "92cfbee5ad356a403d36688ab7bae74be65db9a117478ace34ac3ab4d1f9feb9" + }, + "version": "0.18" + }, + "com.google.testing.platform:core-proto": { + "shasums": { + "jar": "6d8a8906774150f43a8fad08ca64e25c6070c39bd8a6fc13b2593f289242fe95" + }, + "version": "0.0.9-alpha02" + }, + "com.google.testparameterinjector:test-parameter-injector": { + "shasums": { + "jar": "e5a7c649c54c412049908247ca5e25fe6921d746849c6017a84dc6044237a4b4" + }, + "version": "1.18" + }, + "com.google.truth.extensions:truth-java8-extension": { + "shasums": { + "jar": "293f4e4c59ce48e8b68651321d2d9f2355534412b221369b2af8ff76e6acf381" + }, + "version": "1.4.0" + }, + "com.google.truth.extensions:truth-liteproto-extension": { + "shasums": { + "jar": "2445c955286b8bc58903a853d4b9166000c94e4b95aea6ac9da3e1fdc3e08f10" + }, + "version": "1.4.0" + }, + "com.google.truth.extensions:truth-proto-extension": { + "shasums": { + "jar": "99e6cede45cb1fe962e6ae4e95fb045df8038b01eee03eee362bb073e42f54fc" + }, + "version": "1.4.0" + }, + "com.google.truth:truth": { + "shasums": { + "jar": "235c28e96ee6701ab01cc852fb294cb0f34756f636a8154b9aef08fb1215bbc4" + }, + "version": "1.4.0" + }, + "com.googlecode.juniversalchardet:juniversalchardet": { + "shasums": { + "jar": "757bfe906193b8b651e79dc26cd67d6b55d0770a2cdfb0381591504f779d4a76" + }, + "version": "1.0.3" + }, + "com.ibm.icu:icu4j": { + "shasums": { + "jar": "543e43a91d1499e331c711a756f833d6fb8cc019f9c9913c0bdf4d53009932d5" + }, + "version": "75.1" + }, + "com.squareup:javapoet": { + "shasums": { + "jar": "20ef4b82e43ff7c652281a21313cf3b941092467add3fa73509c26f6969efdab" + }, + "version": "1.10.0" + }, + "com.squareup:javawriter": { + "shasums": { + "jar": "fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0" + }, + "version": "2.5.0" + }, + "com.squareup:kotlinpoet": { + "shasums": { + "jar": "102d5d8a289d961cd7f39204c264d272e4aad775e388d909f6050e14558aae9b" + }, + "version": "1.14.2" + }, + "com.sun.activation:javax.activation": { + "shasums": { + "jar": "993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce" + }, + "version": "1.2.0" + }, + "com.sun.istack:istack-commons-runtime": { + "shasums": { + "jar": "4ffabb06be454a05e4398e20c77fa2b6308d4b88dfbef7ca30a76b5b7d5505ef" + }, + "version": "3.0.8" + }, + "com.sun.xml.fastinfoset:FastInfoset": { + "shasums": { + "jar": "056f3a1e144409f21ed16afc26805f58e9a21f3fce1543c42d400719d250c511" + }, + "version": "1.2.16" + }, + "commons-codec:commons-codec": { + "shasums": { + "jar": "b3e9f6d63a790109bf0d056611fbed1cf69055826defeb9894a71369d246ed63" + }, + "version": "1.15" + }, + "commons-io:commons-io": { + "shasums": { + "jar": "671eaa39688dac2ffaa4645b3c9980ae2d0ea2471e4ae6a5da199cd15ae23666" + }, + "version": "2.13.0" + }, + "commons-logging:commons-logging": { + "shasums": { + "jar": "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636" + }, + "version": "1.2" + }, + "info.picocli:picocli": { + "shasums": { + "jar": "1964e89575b43aa177aa4e534946b25bde9f3a48a9675d61d9ef7c4ca83d94b4" + }, + "version": "4.7.4" + }, + "io.github.eisop:dataflow-errorprone": { + "shasums": { + "jar": "10434fba4e53f55fa9c76904cde414b918932548c9dfc4e2d634ac05ff7a7d10" + }, + "version": "3.41.0-eisop1" + }, + "io.github.java-diff-utils:java-diff-utils": { + "shasums": { + "jar": "9990a2039778f6b4cc94790141c2868864eacee0620c6c459451121a901cd5b5" + }, + "version": "4.12" + }, + "io.grpc:grpc-api": { + "shasums": { + "jar": "8d2c384299f84ee8aa7f670f00e7cb26b87e231cf3091474307b32b76910f71c" + }, + "version": "1.57.0" + }, + "io.grpc:grpc-context": { + "shasums": { + "jar": "953fcacd82f531e69b76e3834f5830bad4c22ae84144e058d71dc80a7430275d" + }, + "version": "1.57.0" + }, + "io.grpc:grpc-core": { + "shasums": { + "jar": "3bee48c73bc4c5b55bed79be0e484adf26ba56bebbe5798ddbf34714ef1e1cea" + }, + "version": "1.57.0" + }, + "io.grpc:grpc-netty": { + "shasums": { + "jar": "81d43f2d4ed18fa341bd840a3735f1403a70074a046e157e27f679b721b4c9ad" + }, + "version": "1.57.0" + }, + "io.grpc:grpc-protobuf": { + "shasums": { + "jar": "49f986d4eab12610fdba4a6890fca52d5eb653598916fdb863a366d5e28eecf7" + }, + "version": "1.57.0" + }, + "io.grpc:grpc-protobuf-lite": { + "shasums": { + "jar": "2c507c02d981b84a21763d44e09af4f279881dd3e25be3080f6361258607f198" + }, + "version": "1.57.0" + }, + "io.grpc:grpc-stub": { + "shasums": { + "jar": "6e6ee141539fa14d9fa479f7f511605544443c7e011e78e273cf9468aa183060" + }, + "version": "1.57.0" + }, + "io.netty:netty-buffer": { + "shasums": { + "jar": "007c7d9c378df02d390567d0d7ddf542ffddb021b7313dbf502392113ffabb08" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-codec": { + "shasums": { + "jar": "990c378168dc6364c6ff569701f4f2f122fffe8998b3e189eba4c4d868ed1084" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-codec-http": { + "shasums": { + "jar": "dacf78ce78ab2d29570325db4cd2451ea589639807de95881a0fa7155a9e6b55" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-codec-http2": { + "shasums": { + "jar": "d96cc09045a1341c6d47494352aa263b87b72fb1d2ea9eca161aa73820bfe8bb" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-codec-socks": { + "shasums": { + "jar": "0ea47b5ba23ca1da8eb9146c8fc755c1271414633b1e2be2ce1df764ba0fff2a" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-common": { + "shasums": { + "jar": "443bb316599fb16e3baeba2fb58881814d7ff0b7af176fe76e38071a6e86f8c0" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-handler": { + "shasums": { + "jar": "4e5f563ae14ed713381816d582f5fcfd0615aefb29203486cdfb782d8a00a02b" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-handler-proxy": { + "shasums": { + "jar": "2ac5f7fbefa0b73ef783889069344d5515505a14b2303be693c5002c486df2b4" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-resolver": { + "shasums": { + "jar": "e59770b66e81822e5d111ac4e544d7eb0c543e0a285f52628e53941acd8ed759" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-transport": { + "shasums": { + "jar": "a5a78019bc1cd43dbc3c7b7cdd3801912ca26d1f498fb560514fee497864ba96" + }, + "version": "4.1.93.Final" + }, + "io.netty:netty-transport-native-unix-common": { + "shasums": { + "jar": "774165a1c4dbaacb17f9c1ad666b3569a6a59715ae828e7c3d47703f479a53e7" + }, + "version": "4.1.93.Final" + }, + "io.perfmark:perfmark-api": { + "shasums": { + "jar": "b7d23e93a34537ce332708269a0d1404788a5b5e1949e82f5535fce51b3ea95b" + }, + "version": "0.26.0" + }, + "jakarta.activation:jakarta.activation-api": { + "shasums": { + "jar": "8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b" + }, + "version": "1.2.1" + }, + "jakarta.inject:jakarta.inject-api": { + "shasums": { + "jar": "f7dc98062fccf14126abb751b64fab12c312566e8cbdc8483598bffcea93af7c" + }, + "version": "2.0.1" + }, + "jakarta.xml.bind:jakarta.xml.bind-api": { + "shasums": { + "jar": "69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea" + }, + "version": "2.3.2" + }, + "javax.annotation:javax.annotation-api": { + "shasums": { + "jar": "e04ba5195bcd555dc95650f7cc614d151e4bcd52d29a10b8aa2197f3ab89ab9b" + }, + "version": "1.3.2" + }, + "javax.inject:javax.inject": { + "shasums": { + "jar": "91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff" + }, + "version": "1" + }, + "junit:junit": { + "shasums": { + "jar": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3" + }, + "version": "4.13.2" + }, + "net.bytebuddy:byte-buddy": { + "shasums": { + "jar": "e99761a526df0fefbbd3fe14436b0f953000cdfa5151dc63c0b18d37d9c46f1c" + }, + "version": "1.14.5" + }, + "net.bytebuddy:byte-buddy-agent": { + "shasums": { + "jar": "55f19862b870f5d85890ba5386b1b45e9bbc88d5fe1f819abe0c788b4929fa6b" + }, + "version": "1.14.5" + }, + "net.java.dev.jna:jna": { + "shasums": { + "jar": "5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf" + }, + "version": "5.6.0" + }, + "net.java.dev.jna:jna-platform": { + "shasums": { + "jar": "9ecea8bf2b1b39963939d18b70464eef60c508fed8820f9dcaba0c35518eabf7" + }, + "version": "5.6.0" + }, + "net.sf.jopt-simple:jopt-simple": { + "shasums": { + "jar": "26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5" + }, + "version": "4.9" + }, + "net.sf.kxml:kxml2": { + "shasums": { + "jar": "f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2" + }, + "version": "2.3.0" + }, + "org.apache.commons:commons-compress": { + "shasums": { + "jar": "6aecfd5459728a595601cfa07258d131972ffc39b492eb48bdd596577a2f244a" + }, + "version": "1.21" + }, + "org.apache.httpcomponents:httpclient": { + "shasums": { + "jar": "c8bc7e1c51a6d4ce72f40d2ebbabf1c4b68bfe76e732104b04381b493478e9d6" + }, + "version": "4.5.14" + }, + "org.apache.httpcomponents:httpcore": { + "shasums": { + "jar": "6c9b3dd142a09dc468e23ad39aad6f75a0f2b85125104469f026e52a474e464f" + }, + "version": "4.4.16" + }, + "org.apache.httpcomponents:httpmime": { + "shasums": { + "jar": "0b2b1102c18d3c7e05a77214b9b7501a6f6056174ae5604e0e256776eda7553e" + }, + "version": "4.5.6" + }, + "org.bitbucket.b_c:jose4j": { + "shasums": { + "jar": "808fb3166f3e67dad9811c331029ab1681242fd52b735bc3f33f281167fcc72e" + }, + "version": "0.9.5" + }, + "org.bouncycastle:bcpkix-jdk18on": { + "shasums": { + "jar": "3639a24ddf9ba4b7eba0659b44770e91eba816421888e571f285aadefe532cd6" + }, + "version": "1.79" + }, + "org.bouncycastle:bcprov-jdk18on": { + "shasums": { + "jar": "0d81ecc3124536b539bce9aa3fe9621b7f84c9cee371b635a5b31c78b79ab1da" + }, + "version": "1.79" + }, + "org.bouncycastle:bcutil-jdk18on": { + "shasums": { + "jar": "c70b88ada58938cbc2f005d40329054078bcfa1149e6ffc03e9242eb6ab21836" + }, + "version": "1.79" + }, + "org.checkerframework:checker-compat-qual": { + "shasums": { + "jar": "d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d" + }, + "version": "2.5.3" + }, + "org.checkerframework:checker-qual": { + "shasums": { + "jar": "3fbc2e98f05854c3df16df9abaa955b91b15b3ecac33623208ed6424640ef0f6" + }, + "version": "3.43.0" + }, + "org.codehaus.mojo:animal-sniffer-annotations": { + "shasums": { + "jar": "9ffe526bf43a6348e9d8b33b9cd6f580a7f5eed0cf055913007eda263de974d0" + }, + "version": "1.23" + }, + "org.conscrypt:conscrypt-openjdk-uber": { + "shasums": { + "jar": "eaf537d98e033d0f0451cd1b8cc74e02d7b55ec882da63c88060d806ba89c348" + }, + "version": "2.5.2" + }, + "org.glassfish.jaxb:jaxb-runtime": { + "shasums": { + "jar": "e6e0a1e89fb6ff786279e6a0082d5cef52dc2ebe67053d041800737652b4fd1b" + }, + "version": "2.3.2" + }, + "org.glassfish.jaxb:txw2": { + "shasums": { + "jar": "4a6a9f483388d461b81aa9a28c685b8b74c0597993bf1884b04eddbca95f48fe" + }, + "version": "2.3.2" + }, + "org.hamcrest:hamcrest": { + "shasums": { + "jar": "5e62846a89f05cd78cd9c1a553f340d002458380c320455dd1f8fc5497a8a1c1" + }, + "version": "2.2" + }, + "org.hamcrest:hamcrest-core": { + "shasums": { + "jar": "094f5d92b4b7d9c8a2bf53cc69d356243ae89c3499457bcb4b92f7ed3bf95879" + }, + "version": "2.2" + }, + "org.jdom:jdom2": { + "shasums": { + "jar": "1345f11ba606d15603d6740551a8c21947c0215640770ec67271fe78bea97cf5" + }, + "version": "2.0.6" + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "shasums": { + "jar": "419778f2b7a826bad6ee2ca1e4bdebe639ab306d2904fa3ef2a308ecfaab3811" + }, + "version": "2.1.20" + }, + "org.jetbrains.kotlin:kotlin-stdlib": { + "shasums": { + "jar": "1bcc74e8ce84e2c25eaafde10f1248349cce3062b6e36978cbeec610db1e930a" + }, + "version": "2.1.20" + }, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": { + "shasums": { + "jar": "5343bf795783932e5fa538b0bca05af810bb07213edb9baa770c784068f57867" + }, + "version": "2.1.20" + }, + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": { + "shasums": { + "jar": "ed22217b5dc0940a068d8be9440bbe2f7f9f51c466cdd1185e2385cdec19f238" + }, + "version": "2.1.20" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-core": { + "shasums": { + "jar": "7089c33c145865020760d3dbca5e4634133cc3dd7feb926e830f6de6ede28ac6" + }, + "version": "1.9.0" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": { + "shasums": { + "jar": "ad89c2892235e670f222d819cb3d81188143cb19a05b59df9889ae4269f5c70a" + }, + "version": "1.9.0" + }, + "org.jetbrains.kotlinx:kotlinx-metadata-jvm": { + "shasums": { + "jar": "8f5759b435fcbcfdf06c80295013ba953db4ec817b04d7809c61a739a483527b" + }, + "version": "0.6.2" + }, + "org.jetbrains:annotations": { + "shasums": { + "jar": "7b0f19724082cbfcbc66e5abea2b9bc92cf08a1ea11e191933ed43801eb3cd05" + }, + "version": "23.0.0" + }, + "org.jspecify:jspecify": { + "shasums": { + "jar": "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab" + }, + "version": "1.0.0" + }, + "org.jvnet.staxex:stax-ex": { + "shasums": { + "jar": "20522549056e9e50aa35ef0b445a2e47a53d06be0b0a9467d704e2483ffb049a" + }, + "version": "1.8.1" + }, + "org.mockito:mockito-core": { + "shasums": { + "jar": "b1689b06617ea01fd777bfaedbdde512faf083d639a049f79b388d5a4e96d2e5" + }, + "version": "5.4.0" + }, + "org.objenesis:objenesis": { + "shasums": { + "jar": "02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb" + }, + "version": "3.3" + }, + "org.ow2.asm:asm": { + "shasums": { + "jar": "8cadd43ac5eb6d09de05faecca38b917a040bb9139c7edeb4cc81c740b713281" + }, + "version": "9.7.1" + }, + "org.ow2.asm:asm-analysis": { + "shasums": { + "jar": "85b29371884ba31bb76edf22323c2c24e172c3267a67152eba3d1ccc2e041ef2" + }, + "version": "9.7.1" + }, + "org.ow2.asm:asm-commons": { + "shasums": { + "jar": "9a579b54d292ad9be171d4313fd4739c635592c2b5ac3a459bbd1049cddec6a0" + }, + "version": "9.7.1" + }, + "org.ow2.asm:asm-tree": { + "shasums": { + "jar": "9929881f59eb6b840e86d54570c77b59ce721d104e6dfd7a40978991c2d3b41f" + }, + "version": "9.7.1" + }, + "org.ow2.asm:asm-util": { + "shasums": { + "jar": "f885be71b5c90556f5f1ad1c4f9276b29b96057c497d46666fe4ddbec3cb43c6" + }, + "version": "9.7.1" + }, + "org.pcollections:pcollections": { + "shasums": { + "jar": "1f82766d7c3221930854033bebff5073ea46b43f27326074bbe15d148c18bfb3" + }, + "version": "4.0.1" + }, + "org.robolectric:annotations": { + "shasums": { + "jar": "463a5ad1386c31010bc9af00bfe19a1b758d8c2dedd8c19e5c75d29ab8abb9ba" + }, + "version": "4.14.1" + }, + "org.robolectric:junit": { + "shasums": { + "jar": "2cee817aadce3552706b09450ad1ea7ff5981924072d2adfe40ddad57d5fa123" + }, + "version": "4.14.1" + }, + "org.robolectric:nativeruntime": { + "shasums": { + "jar": "c07b66d315aec3272a7c64aa5f154b4194be2cc6030a733d16f2ee87330232a8" + }, + "version": "4.14.1" + }, + "org.robolectric:nativeruntime-dist-compat": { + "shasums": { + "jar": "2f4e879b00eed634d0e43353ecff80db4d5ce24b3b213d1e6053cb21b0ced10f" + }, + "version": "1.0.16" + }, + "org.robolectric:pluginapi": { + "shasums": { + "jar": "ad8b74238d59bce6631e29190c105dd0c4701e836a2631060678407f621c7b7a" + }, + "version": "4.14.1" + }, + "org.robolectric:plugins-maven-dependency-resolver": { + "shasums": { + "jar": "6c8dbc979db0780755e712acab9eeb9396811b2d4dc31a92a5b259f9876205ec" + }, + "version": "4.14.1" + }, + "org.robolectric:resources": { + "shasums": { + "jar": "54eb274a47dec9e74cc9b45b9e4335bb5d83857c63b2a49dd8d1993e6321f2c5" + }, + "version": "4.14.1" + }, + "org.robolectric:robolectric": { + "shasums": { + "jar": "e0a73d45bceb94a5a0352b66e2120ad4a4b222fe406079130893b6c79d4441d1" + }, + "version": "4.14.1" + }, + "org.robolectric:sandbox": { + "shasums": { + "jar": "de361f3de8c08d4488cf156683830f2bd43db1da85a5b136ad6d065b868d3bab" + }, + "version": "4.14.1" + }, + "org.robolectric:shadowapi": { + "shasums": { + "jar": "fd158863cee488475206ba1d23ff4c7d29be412eccd21b12d9416b0030aa582d" + }, + "version": "4.14.1" + }, + "org.robolectric:shadows-framework": { + "shasums": { + "jar": "f3cf7785eecf9b2e80fbb4caac4c42f63eeea3506e289581c04696a56a494622" + }, + "version": "4.14.1" + }, + "org.robolectric:utils": { + "shasums": { + "jar": "6884eec32c9c9b23d74250e30a5ba9c5ece48784f808feba98f119b215ab59d8" + }, + "version": "4.14.1" + }, + "org.robolectric:utils-reflector": { + "shasums": { + "jar": "eb8f52cdc24f59ae4cf13369c5bf990354c19c386e3e8f9f5d5cee04d836557b" + }, + "version": "4.14.1" + }, + "org.slf4j:slf4j-api": { + "shasums": { + "jar": "cdba07964d1bb40a0761485c6b1e8c2f8fd9eb1d19c53928ac0d7f9510105c57" + }, + "version": "1.7.30" + }, + "org.tensorflow:tensorflow-lite-metadata": { + "shasums": { + "jar": "2c2a264f842498c36d34d2a7b91342490d9a962862c85baac1acd54ec2fca6d9" + }, + "version": "0.1.0-rc2" + }, + "org.xerial:sqlite-jdbc": { + "shasums": { + "jar": "50524b16b649fb03f81df6e61dec69911b8849e6943c61b85faa24e49bfd98fc" + }, + "version": "3.43.0.0" + }, + "org.yaml:snakeyaml": { + "shasums": { + "jar": "63a76fe66b652360bd4c2c107e6f0258daa7d4bb492008ba8c26fcd230ff9146" + }, + "version": "2.3" + } + }, + "dependencies": { + "androidx.annotation:annotation": [ + "androidx.annotation:annotation-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.annotation:annotation-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.concurrent:concurrent-futures": [ + "androidx.annotation:annotation", + "com.google.guava:listenablefuture" + ], + "androidx.databinding:databinding-compiler": [ + "androidx.databinding:databinding-common", + "androidx.databinding:databinding-compiler-common", + "com.android.tools:annotations", + "com.google.auto:auto-common", + "com.google.code.gson:gson", + "com.google.guava:guava", + "com.googlecode.juniversalchardet:juniversalchardet", + "com.squareup:javapoet", + "commons-codec:commons-codec", + "commons-io:commons-io", + "org.glassfish.jaxb:jaxb-runtime", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "androidx.databinding:databinding-compiler-common": [ + "androidx.databinding:databinding-common", + "com.android.databinding:baseLibrary", + "com.android.tools.build.jetifier:jetifier-core", + "com.android.tools:annotations", + "com.google.code.gson:gson", + "com.google.guava:guava", + "com.googlecode.juniversalchardet:juniversalchardet", + "com.squareup:javapoet", + "commons-io:commons-io", + "org.glassfish.jaxb:jaxb-runtime", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "androidx.lifecycle:lifecycle-common": [ + "androidx.annotation:annotation" + ], + "androidx.privacysandbox.tools:tools": [ + "androidx.annotation:annotation", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.privacysandbox.tools:tools-apigenerator": [ + "androidx.privacysandbox.tools:tools", + "androidx.privacysandbox.tools:tools-core", + "com.squareup:kotlinpoet", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-metadata-jvm", + "org.ow2.asm:asm", + "org.ow2.asm:asm-commons" + ], + "androidx.privacysandbox.tools:tools-apipackager": [ + "androidx.privacysandbox.tools:tools", + "androidx.privacysandbox.tools:tools-core", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.ow2.asm:asm", + "org.ow2.asm:asm-commons" + ], + "androidx.privacysandbox.tools:tools-core": [ + "androidx.privacysandbox.tools:tools", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "com.squareup:kotlinpoet", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.test.ext:junit:aar": [ + "androidx.annotation:annotation", + "androidx.test.services:storage:aar", + "androidx.test:core:aar", + "androidx.test:monitor:aar", + "junit:junit" + ], + "androidx.test.services:storage:aar": [ + "androidx.annotation:annotation", + "androidx.test:annotation:aar", + "androidx.test:monitor:aar" + ], + "androidx.test:annotation:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar" + ], + "androidx.test:core:aar": [ + "androidx.annotation:annotation", + "androidx.concurrent:concurrent-futures", + "androidx.lifecycle:lifecycle-common", + "androidx.test.services:storage:aar", + "androidx.test:annotation:aar", + "androidx.test:monitor:aar", + "androidx.tracing:tracing:aar", + "com.google.guava:listenablefuture", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.test:monitor:aar": [ + "androidx.annotation:annotation", + "androidx.tracing:tracing:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.tracing:tracing:aar": [ + "androidx.annotation:annotation" + ], + "com.android.tools.adblib:adblib": [ + "com.google.protobuf:protobuf-java", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains.kotlinx:kotlinx-coroutines-core" + ], + "com.android.tools.adblib:adblib-tools": [ + "com.android.tools.adblib:adblib", + "com.google.protobuf:protobuf-java", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains.kotlinx:kotlinx-coroutines-core" + ], + "com.android.tools.analytics-library:crash": [ + "com.android.tools:annotations", + "com.google.guava:guava", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.apache.httpcomponents:httpmime" + ], + "com.android.tools.analytics-library:protos": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.analytics-library:shared": [ + "com.android.tools.analytics-library:protos", + "com.android.tools:annotations", + "com.android.tools:common", + "com.google.code.gson:gson", + "com.google.guava:guava", + "net.java.dev.jna:jna-platform", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.analytics-library:tracker": [ + "com.android.tools.analytics-library:protos", + "com.android.tools.analytics-library:shared", + "com.android.tools:annotations", + "com.android.tools:common", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.apkdeployer:apkdeployer": [ + "com.android.tools.adblib:adblib", + "com.android.tools.adblib:adblib-tools", + "com.android.tools.apkparser:binary-resources", + "com.android.tools.ddms:ddmlib", + "com.android.tools:annotations", + "com.android.tools:common", + "com.android.tools:r8", + "com.android.tools:sdk-common", + "com.android:zipflinger", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains:annotations", + "org.xerial:sqlite-jdbc" + ], + "com.android.tools.apkparser:binary-resources": [ + "com.android.tools:annotations", + "com.google.guava:guava" + ], + "com.android.tools.build.jetifier:jetifier-core": [ + "com.google.code.gson:gson", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.android.tools.build.jetifier:jetifier-processor": [ + "com.android.tools.build.jetifier:jetifier-core", + "org.jdom:jdom2", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.ow2.asm:asm", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-util" + ], + "com.android.tools.build:aapt2-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.build:aaptcompiler": [ + "com.android.tools.build:aapt2-proto", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools:common", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.build:apkzlib": [ + "com.android.tools.build:apksig", + "com.google.code.findbugs:jsr305", + "com.google.guava:guava", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on" + ], + "com.android.tools.build:builder": [ + "com.android.tools.analytics-library:protos", + "com.android.tools.analytics-library:tracker", + "com.android.tools.build:apksig", + "com.android.tools.build:apkzlib", + "com.android.tools.build:builder-model", + "com.android.tools.build:builder-test-api", + "com.android.tools.build:manifest-merger", + "com.android.tools.ddms:ddmlib", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools:common", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.android:signflinger", + "com.android:zipflinger", + "com.squareup:javawriter", + "commons-codec:commons-codec", + "javax.inject:javax.inject", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.ow2.asm:asm-commons" + ], + "com.android.tools.build:builder-model": [ + "com.android.tools:annotations", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.build:builder-test-api": [ + "com.android.tools.ddms:ddmlib", + "com.android.tools:annotations", + "com.android.tools:common", + "com.google.guava:guava" + ], + "com.android.tools.build:bundletool": [ + "com.android.tools.build:aapt2-proto", + "com.google.auto.value:auto-value-annotations", + "com.google.dagger:dagger", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "com.google.protobuf:protobuf-java-util", + "javax.inject:javax.inject", + "org.bitbucket.b_c:jose4j", + "org.slf4j:slf4j-api" + ], + "com.android.tools.build:gradle": [ + "androidx.databinding:databinding-common", + "androidx.databinding:databinding-compiler-common", + "com.android.databinding:baseLibrary", + "com.android.tools.analytics-library:crash", + "com.android.tools.analytics-library:shared", + "com.android.tools.build.jetifier:jetifier-core", + "com.android.tools.build.jetifier:jetifier-processor", + "com.android.tools.build:aapt2-proto", + "com.android.tools.build:aaptcompiler", + "com.android.tools.build:builder", + "com.android.tools.build:builder-model", + "com.android.tools.build:builder-test-api", + "com.android.tools.build:bundletool", + "com.android.tools.build:gradle-api", + "com.android.tools.build:gradle-settings-api", + "com.android.tools.build:transform-api", + "com.android.tools.ddms:ddmlib", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools.lint:lint-model", + "com.android.tools.lint:lint-typedef-remover", + "com.android.tools.utp:android-device-provider-ddmlib-proto", + "com.android.tools.utp:android-device-provider-gradle-proto", + "com.android.tools.utp:android-device-provider-profile-proto", + "com.android.tools.utp:android-test-plugin-host-additional-test-output-proto", + "com.android.tools.utp:android-test-plugin-host-apk-installer-proto", + "com.android.tools.utp:android-test-plugin-host-coverage-proto", + "com.android.tools.utp:android-test-plugin-host-emulator-control-proto", + "com.android.tools.utp:android-test-plugin-host-logcat-proto", + "com.android.tools.utp:android-test-plugin-host-retention-proto", + "com.android.tools.utp:android-test-plugin-result-listener-gradle-proto", + "com.android.tools:repository", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.google.code.gson:gson", + "com.google.crypto.tink:tink", + "com.google.flatbuffers:flatbuffers-java", + "com.google.protobuf:protobuf-java", + "com.google.protobuf:protobuf-java-util", + "com.google.testing.platform:core-proto", + "com.squareup:javapoet", + "commons-io:commons-io", + "io.grpc:grpc-core", + "io.grpc:grpc-netty", + "io.grpc:grpc-protobuf", + "io.grpc:grpc-stub", + "net.sf.jopt-simple:jopt-simple", + "org.apache.httpcomponents:httpmime", + "org.bouncycastle:bcpkix-jdk18on", + "org.glassfish.jaxb:jaxb-runtime", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-util", + "org.tensorflow:tensorflow-lite-metadata" + ], + "com.android.tools.build:gradle-api": [ + "com.android.tools.build:builder-test-api", + "com.google.guava:guava", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.ow2.asm:asm" + ], + "com.android.tools.build:gradle-settings-api": [ + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.build:manifest-merger": [ + "com.android.tools:common", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.google.code.gson:gson", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.ddms:ddmlib": [ + "com.android.tools:common", + "com.google.protobuf:protobuf-java", + "net.sf.kxml:kxml2", + "org.jetbrains:annotations" + ], + "com.android.tools.layoutlib:layoutlib-api": [ + "com.android.tools:annotations", + "com.android.tools:common", + "net.sf.kxml:kxml2", + "org.jetbrains:annotations" + ], + "com.android.tools.lint:lint-model": [ + "com.android.tools.build:builder-model", + "com.android.tools:common", + "com.android.tools:sdk-common", + "net.sf.kxml:kxml2", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.lint:lint-typedef-remover": [ + "com.android.tools:annotations", + "com.google.guava:guava", + "org.ow2.asm:asm" + ], + "com.android.tools.utp:android-device-provider-ddmlib-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.utp:android-device-provider-gradle-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.utp:android-device-provider-profile-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.utp:android-test-plugin-host-additional-test-output-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.utp:android-test-plugin-host-apk-installer-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.utp:android-test-plugin-host-coverage-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.utp:android-test-plugin-host-emulator-control-proto": [ + "com.google.protobuf:protobuf-java", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.utp:android-test-plugin-host-logcat-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.utp:android-test-plugin-host-retention-proto": [ + "com.google.protobuf:protobuf-java", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.utp:android-test-plugin-result-listener-gradle-proto": [ + "com.google.code.gson:gson", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "io.grpc:grpc-core", + "io.grpc:grpc-netty", + "io.grpc:grpc-protobuf", + "io.grpc:grpc-stub", + "javax.annotation:javax.annotation-api" + ], + "com.android.tools:common": [ + "com.android.tools:annotations", + "com.google.guava:guava", + "net.java.dev.jna:jna-platform", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools:desugar_jdk_libs_minimal": [ + "com.android.tools:desugar_jdk_libs_configuration_minimal" + ], + "com.android.tools:desugar_jdk_libs_nio": [ + "com.android.tools:desugar_jdk_libs_configuration_nio" + ], + "com.android.tools:dvlib": [ + "com.android.tools:common" + ], + "com.android.tools:repository": [ + "com.android.tools.analytics-library:shared", + "com.android.tools:common", + "com.google.jimfs:jimfs", + "com.sun.activation:javax.activation", + "org.apache.commons:commons-compress", + "org.glassfish.jaxb:jaxb-runtime", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools:sdk-common": [ + "com.android.tools.analytics-library:shared", + "com.android.tools.build:aapt2-proto", + "com.android.tools.ddms:ddmlib", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools:common", + "com.android.tools:sdklib", + "com.google.code.gson:gson", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "javax.inject:javax.inject", + "net.sf.kxml:kxml2", + "org.apache.commons:commons-compress", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on", + "org.glassfish.jaxb:jaxb-runtime", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools:sdklib": [ + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools:common", + "com.android.tools:dvlib", + "com.android.tools:repository", + "com.google.code.gson:gson", + "org.apache.commons:commons-compress", + "org.apache.httpcomponents:httpcore", + "org.apache.httpcomponents:httpmime", + "org.glassfish.jaxb:jaxb-runtime" + ], + "com.android:signflinger": [ + "com.android.tools.build:apksig", + "com.android.tools:annotations", + "com.android:zipflinger" + ], + "com.android:zipflinger": [ + "com.android.tools:annotations" + ], + "com.github.ben-manes.caffeine:caffeine": [ + "com.google.errorprone:error_prone_annotations", + "org.checkerframework:checker-qual" + ], + "com.google.api.grpc:proto-google-common-protos": [ + "com.google.protobuf:protobuf-java" + ], + "com.google.auto.service:auto-service": [ + "com.google.auto.service:auto-service-annotations", + "com.google.auto:auto-common", + "com.google.guava:guava" + ], + "com.google.auto:auto-common": [ + "com.google.guava:guava" + ], + "com.google.code.gson:gson": [ + "com.google.errorprone:error_prone_annotations" + ], + "com.google.crypto.tink:tink": [ + "com.google.code.gson:gson", + "com.google.protobuf:protobuf-java" + ], + "com.google.dagger:dagger": [ + "javax.inject:javax.inject" + ], + "com.google.errorprone:error_prone_annotation": [ + "com.google.guava:guava" + ], + "com.google.errorprone:error_prone_check_api": [ + "com.github.ben-manes.caffeine:caffeine", + "com.github.kevinstern:software-and-algorithms", + "com.google.auto.value:auto-value-annotations", + "com.google.errorprone:error_prone_annotation", + "com.google.errorprone:error_prone_annotations", + "io.github.eisop:dataflow-errorprone", + "io.github.java-diff-utils:java-diff-utils", + "javax.inject:javax.inject", + "org.jspecify:jspecify" + ], + "com.google.errorprone:error_prone_core": [ + "com.google.auto.service:auto-service-annotations", + "com.google.auto.value:auto-value-annotations", + "com.google.auto:auto-common", + "com.google.errorprone:error_prone_annotation", + "com.google.errorprone:error_prone_annotations", + "com.google.errorprone:error_prone_check_api", + "com.google.errorprone:error_prone_type_annotations", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "io.github.eisop:dataflow-errorprone", + "javax.inject:javax.inject", + "org.jspecify:jspecify", + "org.pcollections:pcollections" + ], + "com.google.flogger:flogger": [ + "org.checkerframework:checker-compat-qual" + ], + "com.google.flogger:flogger-system-backend": [ + "com.google.flogger:flogger", + "org.checkerframework:checker-compat-qual" + ], + "com.google.guava:guava": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "org.checkerframework:checker-qual" + ], + "com.google.guava:guava-testlib": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.j2objc:j2objc-annotations", + "junit:junit", + "org.checkerframework:checker-qual" + ], + "com.google.jimfs:jimfs": [ + "com.google.guava:guava" + ], + "com.google.protobuf:protobuf-java-util": [ + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.j2objc:j2objc-annotations", + "com.google.protobuf:protobuf-java" + ], + "com.google.testing.compile:compile-testing": [ + "com.google.auto.value:auto-value", + "com.google.auto:auto-common", + "com.google.guava:guava", + "com.google.truth:truth", + "junit:junit" + ], + "com.google.testparameterinjector:test-parameter-injector": [ + "com.google.auto.value:auto-value-annotations", + "com.google.code.findbugs:jsr305", + "com.google.guava:guava", + "junit:junit", + "org.yaml:snakeyaml" + ], + "com.google.truth.extensions:truth-java8-extension": [ + "com.google.truth:truth", + "org.checkerframework:checker-qual" + ], + "com.google.truth.extensions:truth-liteproto-extension": [ + "com.google.auto.value:auto-value-annotations", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.truth:truth", + "org.checkerframework:checker-qual" + ], + "com.google.truth.extensions:truth-proto-extension": [ + "com.google.auto.value:auto-value-annotations", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "com.google.truth.extensions:truth-liteproto-extension", + "com.google.truth:truth", + "org.checkerframework:checker-qual" + ], + "com.google.truth:truth": [ + "com.google.auto.value:auto-value-annotations", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "junit:junit", + "org.checkerframework:checker-qual", + "org.ow2.asm:asm" + ], + "com.squareup:kotlinpoet": [ + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.sun.istack:istack-commons-runtime": [ + "jakarta.activation:jakarta.activation-api" + ], + "io.grpc:grpc-api": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava" + ], + "io.grpc:grpc-context": [ + "io.grpc:grpc-api" + ], + "io.grpc:grpc-core": [ + "com.google.android:annotations", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "io.grpc:grpc-api", + "io.grpc:grpc-context", + "io.perfmark:perfmark-api", + "org.codehaus.mojo:animal-sniffer-annotations" + ], + "io.grpc:grpc-netty": [ + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "io.grpc:grpc-core", + "io.netty:netty-codec-http2", + "io.netty:netty-handler-proxy", + "io.netty:netty-transport-native-unix-common", + "io.perfmark:perfmark-api" + ], + "io.grpc:grpc-protobuf": [ + "com.google.api.grpc:proto-google-common-protos", + "com.google.code.findbugs:jsr305", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "io.grpc:grpc-api", + "io.grpc:grpc-protobuf-lite" + ], + "io.grpc:grpc-protobuf-lite": [ + "com.google.code.findbugs:jsr305", + "com.google.guava:guava", + "io.grpc:grpc-api" + ], + "io.grpc:grpc-stub": [ + "com.google.errorprone:error_prone_annotations", + "com.google.guava:guava", + "io.grpc:grpc-api" + ], + "io.netty:netty-buffer": [ + "io.netty:netty-common" + ], + "io.netty:netty-codec": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-http": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-http2": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-transport" + ], + "io.netty:netty-codec-socks": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-handler": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-common", + "io.netty:netty-resolver", + "io.netty:netty-transport", + "io.netty:netty-transport-native-unix-common" + ], + "io.netty:netty-handler-proxy": [ + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-codec-socks", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "io.netty:netty-resolver": [ + "io.netty:netty-common" + ], + "io.netty:netty-transport": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-resolver" + ], + "io.netty:netty-transport-native-unix-common": [ + "io.netty:netty-buffer", + "io.netty:netty-common", + "io.netty:netty-transport" + ], + "jakarta.xml.bind:jakarta.xml.bind-api": [ + "jakarta.activation:jakarta.activation-api" + ], + "junit:junit": [ + "org.hamcrest:hamcrest-core" + ], + "net.java.dev.jna:jna-platform": [ + "net.java.dev.jna:jna" + ], + "org.apache.httpcomponents:httpclient": [ + "commons-codec:commons-codec", + "commons-logging:commons-logging", + "org.apache.httpcomponents:httpcore" + ], + "org.apache.httpcomponents:httpmime": [ + "org.apache.httpcomponents:httpclient" + ], + "org.bouncycastle:bcpkix-jdk18on": [ + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on" + ], + "org.bouncycastle:bcutil-jdk18on": [ + "org.bouncycastle:bcprov-jdk18on" + ], + "org.glassfish.jaxb:jaxb-runtime": [ + "com.sun.istack:istack-commons-runtime", + "com.sun.xml.fastinfoset:FastInfoset", + "jakarta.activation:jakarta.activation-api", + "jakarta.xml.bind:jakarta.xml.bind-api", + "org.glassfish.jaxb:txw2", + "org.jvnet.staxex:stax-ex" + ], + "org.hamcrest:hamcrest-core": [ + "org.hamcrest:hamcrest" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core": [ + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlinx:kotlinx-metadata-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jvnet.staxex:stax-ex": [ + "jakarta.activation:jakarta.activation-api", + "jakarta.xml.bind:jakarta.xml.bind-api" + ], + "org.mockito:mockito-core": [ + "net.bytebuddy:byte-buddy", + "net.bytebuddy:byte-buddy-agent", + "org.objenesis:objenesis" + ], + "org.ow2.asm:asm-analysis": [ + "org.ow2.asm:asm-tree" + ], + "org.ow2.asm:asm-commons": [ + "org.ow2.asm:asm", + "org.ow2.asm:asm-tree" + ], + "org.ow2.asm:asm-tree": [ + "org.ow2.asm:asm" + ], + "org.ow2.asm:asm-util": [ + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-tree" + ], + "org.robolectric:junit": [ + "org.robolectric:annotations", + "org.robolectric:pluginapi", + "org.robolectric:sandbox", + "org.robolectric:shadowapi", + "org.robolectric:utils-reflector" + ], + "org.robolectric:nativeruntime": [ + "com.google.guava:guava", + "org.robolectric:nativeruntime-dist-compat", + "org.robolectric:shadowapi", + "org.robolectric:utils", + "org.robolectric:utils-reflector" + ], + "org.robolectric:pluginapi": [ + "com.google.guava:guava", + "org.robolectric:annotations" + ], + "org.robolectric:plugins-maven-dependency-resolver": [ + "com.google.auto.value:auto-value-annotations", + "com.google.guava:guava", + "org.robolectric:pluginapi", + "org.robolectric:utils" + ], + "org.robolectric:resources": [ + "com.google.auto.value:auto-value-annotations", + "com.google.guava:guava", + "org.robolectric:annotations", + "org.robolectric:pluginapi", + "org.robolectric:utils" + ], + "org.robolectric:robolectric": [ + "androidx.test.espresso:espresso-idling-resource:aar", + "androidx.test:monitor:aar", + "com.google.testparameterinjector:test-parameter-injector", + "javax.annotation:javax.annotation-api", + "javax.inject:javax.inject", + "org.bouncycastle:bcprov-jdk18on", + "org.conscrypt:conscrypt-openjdk-uber", + "org.robolectric:annotations", + "org.robolectric:junit", + "org.robolectric:pluginapi", + "org.robolectric:plugins-maven-dependency-resolver", + "org.robolectric:resources", + "org.robolectric:sandbox", + "org.robolectric:shadows-framework", + "org.robolectric:utils", + "org.robolectric:utils-reflector", + "org.yaml:snakeyaml" + ], + "org.robolectric:sandbox": [ + "com.google.guava:guava", + "javax.annotation:javax.annotation-api", + "javax.inject:javax.inject", + "org.ow2.asm:asm", + "org.ow2.asm:asm-commons", + "org.robolectric:annotations", + "org.robolectric:shadowapi", + "org.robolectric:utils", + "org.robolectric:utils-reflector" + ], + "org.robolectric:shadowapi": [ + "org.robolectric:annotations", + "org.robolectric:utils" + ], + "org.robolectric:shadows-framework": [ + "androidx.test:monitor:aar", + "com.almworks.sqlite4java:sqlite4java", + "com.google.auto.value:auto-value-annotations", + "com.google.errorprone:error_prone_annotation", + "com.ibm.icu:icu4j", + "org.robolectric:annotations", + "org.robolectric:nativeruntime", + "org.robolectric:pluginapi", + "org.robolectric:resources", + "org.robolectric:sandbox", + "org.robolectric:shadowapi", + "org.robolectric:utils", + "org.robolectric:utils-reflector" + ], + "org.robolectric:utils": [ + "com.google.errorprone:error_prone_annotation", + "javax.annotation:javax.annotation-api", + "javax.inject:javax.inject", + "org.robolectric:annotations", + "org.robolectric:pluginapi" + ], + "org.robolectric:utils-reflector": [ + "org.ow2.asm:asm", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-util", + "org.robolectric:utils" + ], + "org.tensorflow:tensorflow-lite-metadata": [ + "com.google.flatbuffers:flatbuffers-java", + "org.checkerframework:checker-qual" + ] + }, + "packages": { + "androidx.annotation:annotation-jvm": [ + "androidx.annotation" + ], + "androidx.concurrent:concurrent-futures": [ + "androidx.concurrent.futures" + ], + "androidx.databinding:databinding-common": [ + "androidx.databinding" + ], + "androidx.databinding:databinding-compiler": [ + "android.databinding.annotationprocessor", + "android.databinding.tool", + "android.databinding.tool.expr", + "android.databinding.tool.reflection", + "android.databinding.tool.reflection.annotation", + "android.databinding.tool.solver", + "android.databinding.tool.store", + "android.databinding.tool.util", + "android.databinding.tool.writer" + ], + "androidx.databinding:databinding-compiler-common": [ + "android.databinding.internal.org.antlr.v4.runtime", + "android.databinding.internal.org.antlr.v4.runtime.atn", + "android.databinding.internal.org.antlr.v4.runtime.dfa", + "android.databinding.internal.org.antlr.v4.runtime.misc", + "android.databinding.internal.org.antlr.v4.runtime.tree", + "android.databinding.internal.org.antlr.v4.runtime.tree.pattern", + "android.databinding.internal.org.antlr.v4.runtime.tree.xpath", + "android.databinding.parser", + "android.databinding.tool", + "android.databinding.tool.expr", + "android.databinding.tool.ext", + "android.databinding.tool.processing", + "android.databinding.tool.processing.scopes", + "android.databinding.tool.store", + "android.databinding.tool.util", + "android.databinding.tool.writer" + ], + "androidx.lifecycle:lifecycle-common": [ + "androidx.lifecycle" + ], + "androidx.privacysandbox.tools:tools": [ + "androidx.privacysandbox.tools", + "androidx.privacysandbox.tools.internal" + ], + "androidx.privacysandbox.tools:tools-apigenerator": [ + "androidx.privacysandbox.tools.apigenerator", + "androidx.privacysandbox.tools.apigenerator.parser" + ], + "androidx.privacysandbox.tools:tools-apipackager": [ + "androidx.privacysandbox.tools.apipackager" + ], + "androidx.privacysandbox.tools:tools-core": [ + "androidx.privacysandbox.tools.core", + "androidx.privacysandbox.tools.core.generator", + "androidx.privacysandbox.tools.core.generator.poet", + "androidx.privacysandbox.tools.core.model", + "androidx.privacysandbox.tools.core.proto", + "androidx.privacysandbox.tools.core.validator" + ], + "com.almworks.sqlite4java:sqlite4java": [ + "com.almworks.sqlite4java", + "javolution.util.stripped" + ], + "com.android.databinding:baseLibrary": [ + "android.databinding" + ], + "com.android.tools.adblib:adblib": [ + "com.android.adblib", + "com.android.adblib.impl", + "com.android.adblib.impl.channels", + "com.android.adblib.impl.services", + "com.android.adblib.testing", + "com.android.adblib.utils", + "com.android.server.adb.protos" + ], + "com.android.tools.adblib:adblib-tools": [ + "com.android.adblib.tools", + "com.android.adblib.tools.debugging", + "com.android.adblib.tools.debugging.impl", + "com.android.adblib.tools.debugging.packets", + "com.android.adblib.tools.debugging.packets.ddms", + "com.android.adblib.tools.debugging.packets.ddms.chunks", + "com.android.adblib.tools.debugging.packets.impl", + "com.android.adblib.tools.debugging.processinventory", + "com.android.adblib.tools.debugging.processinventory.impl", + "com.android.adblib.tools.debugging.processinventory.protos", + "com.android.adblib.tools.debugging.processinventory.server", + "com.android.adblib.tools.debugging.utils", + "com.android.adblib.tools.impl", + "com.android.adblib.tools.tcpserver", + "com.android.adblib.tools.tcpserver.impl" + ], + "com.android.tools.analytics-library:crash": [ + "com.android.tools.analytics.crash" + ], + "com.android.tools.analytics-library:protos": [ + "com.android.tools.build.gradle.internal.profile", + "com.google.wireless.android.play.playlog.proto", + "com.google.wireless.android.sdk.stats" + ], + "com.android.tools.analytics-library:shared": [ + "com.android.tools.analytics" + ], + "com.android.tools.analytics-library:tracker": [ + "com.android.tools.analytics" + ], + "com.android.tools.apkdeployer:apkdeployer": [ + "com.android.tools.deploy.proto", + "com.android.tools.deployer", + "com.android.tools.deployer.model", + "com.android.tools.deployer.model.component", + "com.android.tools.deployer.tasks", + "com.android.tools.idea.protobuf", + "com.android.tools.idea.protobuf.compiler", + "com.android.tools.idea.protobuf.util", + "com.android.tools.manifest.parser", + "com.android.tools.manifest.parser.components", + "com.android.tools.tracer" + ], + "com.android.tools.apkparser:binary-resources": [ + "com.google.devrel.gmscore.tools.apk.arsc" + ], + "com.android.tools.build.jetifier:jetifier-core": [ + "com.android.tools.build.jetifier.core", + "com.android.tools.build.jetifier.core.config", + "com.android.tools.build.jetifier.core.pom", + "com.android.tools.build.jetifier.core.proguard", + "com.android.tools.build.jetifier.core.rule", + "com.android.tools.build.jetifier.core.type", + "com.android.tools.build.jetifier.core.utils" + ], + "com.android.tools.build.jetifier:jetifier-processor": [ + "com.android.tools.build.jetifier.processor", + "com.android.tools.build.jetifier.processor.archive", + "com.android.tools.build.jetifier.processor.com.android.tools.build.jetifier.processor.transform.java", + "com.android.tools.build.jetifier.processor.transform", + "com.android.tools.build.jetifier.processor.transform.bytecode", + "com.android.tools.build.jetifier.processor.transform.bytecode.asm", + "com.android.tools.build.jetifier.processor.transform.metainf", + "com.android.tools.build.jetifier.processor.transform.pom", + "com.android.tools.build.jetifier.processor.transform.proguard", + "com.android.tools.build.jetifier.processor.transform.proguard.patterns", + "com.android.tools.build.jetifier.processor.transform.resource", + "com.android.tools.build.jetifier.processor.type" + ], + "com.android.tools.build:aapt2-proto": [ + "android.aapt.pb.internal", + "com.android.aapt" + ], + "com.android.tools.build:aaptcompiler": [ + "com.android.aaptcompiler", + "com.android.aaptcompiler.android", + "com.android.aaptcompiler.buffer", + "com.android.aaptcompiler.proto" + ], + "com.android.tools.build:apksig": [ + "com.android.apksig", + "com.android.apksig.apk", + "com.android.apksig.internal.apk", + "com.android.apksig.internal.apk.stamp", + "com.android.apksig.internal.apk.v1", + "com.android.apksig.internal.apk.v2", + "com.android.apksig.internal.apk.v3", + "com.android.apksig.internal.apk.v4", + "com.android.apksig.internal.asn1", + "com.android.apksig.internal.asn1.ber", + "com.android.apksig.internal.jar", + "com.android.apksig.internal.oid", + "com.android.apksig.internal.pkcs7", + "com.android.apksig.internal.util", + "com.android.apksig.internal.x509", + "com.android.apksig.internal.zip", + "com.android.apksig.kms", + "com.android.apksig.util", + "com.android.apksig.zip" + ], + "com.android.tools.build:apkzlib": [ + "com.android.tools.build.apkzlib.bytestorage", + "com.android.tools.build.apkzlib.sign", + "com.android.tools.build.apkzlib.utils", + "com.android.tools.build.apkzlib.zfile", + "com.android.tools.build.apkzlib.zip", + "com.android.tools.build.apkzlib.zip.compress", + "com.android.tools.build.apkzlib.zip.utils" + ], + "com.android.tools.build:builder": [ + "com.android.builder.compiling", + "com.android.builder.core", + "com.android.builder.dependency", + "com.android.builder.dependency.level2", + "com.android.builder.dexing", + "com.android.builder.dexing.r8", + "com.android.builder.errors", + "com.android.builder.files", + "com.android.builder.internal", + "com.android.builder.internal.aapt", + "com.android.builder.internal.aapt.v2", + "com.android.builder.internal.compiler", + "com.android.builder.internal.incremental", + "com.android.builder.internal.packaging", + "com.android.builder.merge", + "com.android.builder.multidex", + "com.android.builder.packaging", + "com.android.builder.png", + "com.android.builder.profile", + "com.android.builder.sdk", + "com.android.builder.signing", + "com.android.builder.symbols", + "com.android.builder.tasks", + "com.android.builder.testing", + "com.android.builder.utils", + "com.android.tools.r8", + "com.android.tools.r8.androidapi", + "com.android.tools.r8.compatproguard", + "com.android.tools.r8.dex", + "com.android.tools.r8.diagnostic", + "com.android.tools.r8.diagnostic.internal", + "com.android.tools.r8.errors", + "com.android.tools.r8.experimental.graphinfo", + "com.android.tools.r8.graph", + "com.android.tools.r8.graph.proto", + "com.android.tools.r8.inspector", + "com.android.tools.r8.internal", + "com.android.tools.r8.ir.desugar.desugaredlibrary.lint", + "com.android.tools.r8.ir.desugar.varhandle", + "com.android.tools.r8.ir.optimize", + "com.android.tools.r8.ir.optimize.inliner", + "com.android.tools.r8.kotlin", + "com.android.tools.r8.metadata", + "com.android.tools.r8.naming", + "com.android.tools.r8.naming.mappinginformation", + "com.android.tools.r8.origin", + "com.android.tools.r8.position", + "com.android.tools.r8.profile.art", + "com.android.tools.r8.profile.art.diagnostic", + "com.android.tools.r8.references", + "com.android.tools.r8.relocated.keepanno.proto", + "com.android.tools.r8.relocator", + "com.android.tools.r8.retrace", + "com.android.tools.r8.shaking", + "com.android.tools.r8.startup", + "com.android.tools.r8.startup.diagnostic", + "com.android.tools.r8.synthesis", + "com.android.tools.r8.threading", + "com.android.tools.r8.threading.providers.blocking", + "com.android.tools.r8.threading.providers.singlethreaded", + "com.android.tools.r8.tracereferences", + "com.android.tools.r8.utils", + "com.android.tools.r8.utils.positions" + ], + "com.android.tools.build:builder-model": [ + "com.android.build", + "com.android.builder.model", + "com.android.builder.model.level2", + "com.android.builder.model.v2", + "com.android.builder.model.v2.dsl", + "com.android.builder.model.v2.ide", + "com.android.builder.model.v2.models", + "com.android.builder.model.v2.models.ndk" + ], + "com.android.tools.build:builder-test-api": [ + "com.android.builder.testing.api" + ], + "com.android.tools.build:bundletool": [ + "com.android.bundle", + "com.android.tools.build.bundletool", + "com.android.tools.build.bundletool.androidtools", + "com.android.tools.build.bundletool.archive", + "com.android.tools.build.bundletool.commands", + "com.android.tools.build.bundletool.device", + "com.android.tools.build.bundletool.device.activitymanager", + "com.android.tools.build.bundletool.flags", + "com.android.tools.build.bundletool.io", + "com.android.tools.build.bundletool.mergers", + "com.android.tools.build.bundletool.model", + "com.android.tools.build.bundletool.model.exceptions", + "com.android.tools.build.bundletool.model.manifestelements", + "com.android.tools.build.bundletool.model.targeting", + "com.android.tools.build.bundletool.model.utils", + "com.android.tools.build.bundletool.model.utils.files", + "com.android.tools.build.bundletool.model.utils.xmlproto", + "com.android.tools.build.bundletool.model.version", + "com.android.tools.build.bundletool.optimizations", + "com.android.tools.build.bundletool.preprocessors", + "com.android.tools.build.bundletool.sdkmodule", + "com.android.tools.build.bundletool.shards", + "com.android.tools.build.bundletool.size", + "com.android.tools.build.bundletool.splitters", + "com.android.tools.build.bundletool.transparency", + "com.android.tools.build.bundletool.validation", + "com.android.tools.build.bundletool.xml", + "shadow.bundletool.com.android", + "shadow.bundletool.com.android.annotations", + "shadow.bundletool.com.android.annotations.concurrency", + "shadow.bundletool.com.android.apex", + "shadow.bundletool.com.android.apksig", + "shadow.bundletool.com.android.apksig.apk", + "shadow.bundletool.com.android.apksig.internal.apk", + "shadow.bundletool.com.android.apksig.internal.apk.stamp", + "shadow.bundletool.com.android.apksig.internal.apk.v1", + "shadow.bundletool.com.android.apksig.internal.apk.v2", + "shadow.bundletool.com.android.apksig.internal.apk.v3", + "shadow.bundletool.com.android.apksig.internal.apk.v4", + "shadow.bundletool.com.android.apksig.internal.asn1", + "shadow.bundletool.com.android.apksig.internal.asn1.ber", + "shadow.bundletool.com.android.apksig.internal.jar", + "shadow.bundletool.com.android.apksig.internal.oid", + "shadow.bundletool.com.android.apksig.internal.pkcs7", + "shadow.bundletool.com.android.apksig.internal.util", + "shadow.bundletool.com.android.apksig.internal.x509", + "shadow.bundletool.com.android.apksig.internal.zip", + "shadow.bundletool.com.android.apksig.util", + "shadow.bundletool.com.android.apksig.zip", + "shadow.bundletool.com.android.commands.am", + "shadow.bundletool.com.android.ddmlib", + "shadow.bundletool.com.android.ddmlib.clientmanager", + "shadow.bundletool.com.android.ddmlib.idevicemanager", + "shadow.bundletool.com.android.ddmlib.internal", + "shadow.bundletool.com.android.ddmlib.internal.commands", + "shadow.bundletool.com.android.ddmlib.internal.jdwp", + "shadow.bundletool.com.android.ddmlib.internal.jdwp.chunkhandler", + "shadow.bundletool.com.android.ddmlib.internal.jdwp.interceptor", + "shadow.bundletool.com.android.ddmlib.jdwp", + "shadow.bundletool.com.android.ddmlib.jdwp.packets", + "shadow.bundletool.com.android.ddmlib.log", + "shadow.bundletool.com.android.ddmlib.logcat", + "shadow.bundletool.com.android.ddmlib.testrunner", + "shadow.bundletool.com.android.ddmlib.utils", + "shadow.bundletool.com.android.ide.common.blame", + "shadow.bundletool.com.android.incfs.install", + "shadow.bundletool.com.android.incfs.install.adb.ddmlib", + "shadow.bundletool.com.android.io", + "shadow.bundletool.com.android.prefs", + "shadow.bundletool.com.android.resources", + "shadow.bundletool.com.android.sdklib", + "shadow.bundletool.com.android.server.adb.protos", + "shadow.bundletool.com.android.support", + "shadow.bundletool.com.android.testing.utils", + "shadow.bundletool.com.android.tools.proguard", + "shadow.bundletool.com.android.tools.r8", + "shadow.bundletool.com.android.tools.r8.code", + "shadow.bundletool.com.android.tools.r8.compatproguard", + "shadow.bundletool.com.android.tools.r8.dex", + "shadow.bundletool.com.android.tools.r8.dexsplitter", + "shadow.bundletool.com.android.tools.r8.diagnostic", + "shadow.bundletool.com.android.tools.r8.diagnostic.internal", + "shadow.bundletool.com.android.tools.r8.errors", + "shadow.bundletool.com.android.tools.r8.experimental.graphinfo", + "shadow.bundletool.com.android.tools.r8.graph", + "shadow.bundletool.com.android.tools.r8.graph.proto", + "shadow.bundletool.com.android.tools.r8.inspector", + "shadow.bundletool.com.android.tools.r8.internal", + "shadow.bundletool.com.android.tools.r8.ir.optimize", + "shadow.bundletool.com.android.tools.r8.ir.optimize.info", + "shadow.bundletool.com.android.tools.r8.ir.optimize.string", + "shadow.bundletool.com.android.tools.r8.ir.regalloc", + "shadow.bundletool.com.android.tools.r8.jetbrains.kotlin", + "shadow.bundletool.com.android.tools.r8.jetbrains.kotlinx.metadata.jvm", + "shadow.bundletool.com.android.tools.r8.naming", + "shadow.bundletool.com.android.tools.r8.naming.mappinginformation", + "shadow.bundletool.com.android.tools.r8.optimize.argumentpropagation.codescanner", + "shadow.bundletool.com.android.tools.r8.origin", + "shadow.bundletool.com.android.tools.r8.position", + "shadow.bundletool.com.android.tools.r8.references", + "shadow.bundletool.com.android.tools.r8.relocator", + "shadow.bundletool.com.android.tools.r8.retrace", + "shadow.bundletool.com.android.tools.r8.shaking", + "shadow.bundletool.com.android.tools.r8.synthesis", + "shadow.bundletool.com.android.tools.r8.tracereferences", + "shadow.bundletool.com.android.tools.r8.utils", + "shadow.bundletool.com.android.utils", + "shadow.bundletool.com.android.utils.concurrency", + "shadow.bundletool.com.android.utils.cxx", + "shadow.bundletool.com.android.utils.cxx.collections", + "shadow.bundletool.com.android.utils.cxx.io", + "shadow.bundletool.com.android.utils.cxx.ninja", + "shadow.bundletool.com.android.utils.cxx.os", + "shadow.bundletool.com.android.utils.cxx.process", + "shadow.bundletool.com.android.utils.reflection", + "shadow.bundletool.com.android.utils.sleep", + "shadow.bundletool.com.android.utils.time", + "shadow.bundletool.com.android.xml", + "shadow.bundletool.com.android.xml.sax", + "shadow.bundletool.com.android.zipflinger" + ], + "com.android.tools.build:gradle": [ + "com.android.build.api.artifact.impl", + "com.android.build.api.component.analytics", + "com.android.build.api.component.impl", + "com.android.build.api.component.impl.features", + "com.android.build.api.extension.impl", + "com.android.build.api.variant", + "com.android.build.api.variant.impl", + "com.android.build.gradle", + "com.android.build.gradle.api", + "com.android.build.gradle.external.cmake", + "com.android.build.gradle.external.cmake.server", + "com.android.build.gradle.external.cmake.server.receiver", + "com.android.build.gradle.external.gnumake", + "com.android.build.gradle.internal", + "com.android.build.gradle.internal.aapt", + "com.android.build.gradle.internal.annotations", + "com.android.build.gradle.internal.api", + "com.android.build.gradle.internal.api.artifact", + "com.android.build.gradle.internal.attributes", + "com.android.build.gradle.internal.attribution", + "com.android.build.gradle.internal.caching", + "com.android.build.gradle.internal.component", + "com.android.build.gradle.internal.component.features", + "com.android.build.gradle.internal.component.legacy", + "com.android.build.gradle.internal.core", + "com.android.build.gradle.internal.core.dsl", + "com.android.build.gradle.internal.core.dsl.features", + "com.android.build.gradle.internal.core.dsl.impl", + "com.android.build.gradle.internal.core.dsl.impl.features", + "com.android.build.gradle.internal.coverage", + "com.android.build.gradle.internal.crash", + "com.android.build.gradle.internal.cxx.attribution", + "com.android.build.gradle.internal.cxx.build", + "com.android.build.gradle.internal.cxx.caching", + "com.android.build.gradle.internal.cxx.cmake", + "com.android.build.gradle.internal.cxx.collections", + "com.android.build.gradle.internal.cxx.configure", + "com.android.build.gradle.internal.cxx.gradle.generator", + "com.android.build.gradle.internal.cxx.hashing", + "com.android.build.gradle.internal.cxx.io", + "com.android.build.gradle.internal.cxx.json", + "com.android.build.gradle.internal.cxx.logging", + "com.android.build.gradle.internal.cxx.model", + "com.android.build.gradle.internal.cxx.ninja", + "com.android.build.gradle.internal.cxx.prefab", + "com.android.build.gradle.internal.cxx.process", + "com.android.build.gradle.internal.cxx.settings", + "com.android.build.gradle.internal.cxx.string", + "com.android.build.gradle.internal.cxx.stripping", + "com.android.build.gradle.internal.cxx.timing", + "com.android.build.gradle.internal.databinding", + "com.android.build.gradle.internal.dependency", + "com.android.build.gradle.internal.dexing", + "com.android.build.gradle.internal.dsl", + "com.android.build.gradle.internal.dsl.decorator", + "com.android.build.gradle.internal.dsl.decorator.annotation", + "com.android.build.gradle.internal.errors", + "com.android.build.gradle.internal.feature", + "com.android.build.gradle.internal.fusedlibrary", + "com.android.build.gradle.internal.generators", + "com.android.build.gradle.internal.ide", + "com.android.build.gradle.internal.ide.dependencies", + "com.android.build.gradle.internal.ide.kmp", + "com.android.build.gradle.internal.ide.kmp.resolvers", + "com.android.build.gradle.internal.ide.kmp.serialization", + "com.android.build.gradle.internal.ide.level2", + "com.android.build.gradle.internal.ide.proto", + "com.android.build.gradle.internal.ide.v2", + "com.android.build.gradle.internal.incremental", + "com.android.build.gradle.internal.instrumentation", + "com.android.build.gradle.internal.lint", + "com.android.build.gradle.internal.manifest", + "com.android.build.gradle.internal.matcher", + "com.android.build.gradle.internal.model", + "com.android.build.gradle.internal.multiplatform", + "com.android.build.gradle.internal.ndk", + "com.android.build.gradle.internal.packaging", + "com.android.build.gradle.internal.plugins", + "com.android.build.gradle.internal.privaysandboxsdk", + "com.android.build.gradle.internal.process", + "com.android.build.gradle.internal.profile", + "com.android.build.gradle.internal.publishing", + "com.android.build.gradle.internal.r8", + "com.android.build.gradle.internal.res", + "com.android.build.gradle.internal.res.namespaced", + "com.android.build.gradle.internal.scope", + "com.android.build.gradle.internal.services", + "com.android.build.gradle.internal.signing", + "com.android.build.gradle.internal.tasks", + "com.android.build.gradle.internal.tasks.databinding", + "com.android.build.gradle.internal.tasks.factory", + "com.android.build.gradle.internal.tasks.factory.features", + "com.android.build.gradle.internal.tasks.featuresplit", + "com.android.build.gradle.internal.tasks.manifest", + "com.android.build.gradle.internal.tasks.mlkit", + "com.android.build.gradle.internal.tasks.mlkit.codegen", + "com.android.build.gradle.internal.tasks.mlkit.codegen.codeinjector", + "com.android.build.gradle.internal.tasks.mlkit.codegen.codeinjector.codeblock", + "com.android.build.gradle.internal.tasks.mlkit.codegen.codeinjector.codeblock.processor", + "com.android.build.gradle.internal.tasks.mlkit.codegen.codeinjector.fields", + "com.android.build.gradle.internal.tasks.mlkit.codegen.codeinjector.innerclass", + "com.android.build.gradle.internal.tasks.mlkit.codegen.codeinjector.methods", + "com.android.build.gradle.internal.test", + "com.android.build.gradle.internal.test.report", + "com.android.build.gradle.internal.testFixtures", + "com.android.build.gradle.internal.testing", + "com.android.build.gradle.internal.testing.utp", + "com.android.build.gradle.internal.testing.utp.worker", + "com.android.build.gradle.internal.transforms", + "com.android.build.gradle.internal.utils", + "com.android.build.gradle.internal.variant", + "com.android.build.gradle.internal.workeractions", + "com.android.build.gradle.options", + "com.android.build.gradle.tasks", + "com.android.build.gradle.tasks.factory", + "com.android.build.shrinker", + "com.android.build.shrinker.gatherer", + "com.android.build.shrinker.graph", + "com.android.build.shrinker.obfuscation", + "com.android.build.shrinker.usages", + "com.android.buildanalyzer.common", + "com.android.builder.core", + "com.android.builder.model.proto.ide", + "com.android.kotlin.multiplatform.ide.models.serialization", + "com.android.kotlin.multiplatform.models", + "com.android.tools.build.libraries.metadata", + "com.android.tools.idea.insights.proto", + "com.android.tools.mlkit", + "com.android.tools.profgen" + ], + "com.android.tools.build:gradle-api": [ + "com.android.build.api", + "com.android.build.api.artifact", + "com.android.build.api.attributes", + "com.android.build.api.component", + "com.android.build.api.dsl", + "com.android.build.api.instrumentation", + "com.android.build.api.instrumentation.manageddevice", + "com.android.build.api.transform", + "com.android.build.api.variant", + "com.android.build.gradle", + "com.android.build.gradle.api" + ], + "com.android.tools.build:gradle-settings-api": [ + "com.android.build.api.dsl", + "com.android.build.gradle" + ], + "com.android.tools.build:manifest-merger": [ + "com.android.manifmerger" + ], + "com.android.tools.ddms:ddmlib": [ + "com.android.commands.am", + "com.android.ddmlib", + "com.android.ddmlib.clientmanager", + "com.android.ddmlib.idevicemanager", + "com.android.ddmlib.internal", + "com.android.ddmlib.internal.commands", + "com.android.ddmlib.internal.jdwp", + "com.android.ddmlib.internal.jdwp.chunkhandler", + "com.android.ddmlib.internal.jdwp.interceptor", + "com.android.ddmlib.jdwp", + "com.android.ddmlib.jdwp.packets", + "com.android.ddmlib.log", + "com.android.ddmlib.logcat", + "com.android.ddmlib.testrunner", + "com.android.ddmlib.utils", + "com.android.incfs.install", + "com.android.incfs.install.adb.ddmlib", + "com.android.server.adb.protos" + ], + "com.android.tools.layoutlib:layoutlib-api": [ + "com.android.ide.common.rendering.api", + "com.android.resources" + ], + "com.android.tools.lint:lint-model": [ + "com.android.tools.lint.model" + ], + "com.android.tools.lint:lint-typedef-remover": [ + "com.android.tools.lint.typedefs" + ], + "com.android.tools.utp:android-device-provider-ddmlib-proto": [ + "com.android.tools.utp.plugins.deviceprovider.ddmlib.proto" + ], + "com.android.tools.utp:android-device-provider-gradle-proto": [ + "com.android.tools.utp.plugins.deviceprovider.gradle.proto" + ], + "com.android.tools.utp:android-device-provider-profile-proto": [ + "com.android.tools.utp.plugins.deviceprovider.profile.proto" + ], + "com.android.tools.utp:android-test-plugin-host-additional-test-output-proto": [ + "com.android.tools.utp.plugins.host.additionaltestoutput.proto" + ], + "com.android.tools.utp:android-test-plugin-host-apk-installer-proto": [ + "com.android.tools.utp.plugins.host.apkinstaller.proto" + ], + "com.android.tools.utp:android-test-plugin-host-coverage-proto": [ + "com.android.tools.utp.plugins.host.coverage.proto" + ], + "com.android.tools.utp:android-test-plugin-host-emulator-control-proto": [ + "com.android.tools.utp.plugins.host.emulatorcontrol.proto" + ], + "com.android.tools.utp:android-test-plugin-host-logcat-proto": [ + "com.android.tools.utp.plugins.host.logcat.proto" + ], + "com.android.tools.utp:android-test-plugin-host-retention-proto": [ + "com.android.tools.utp.plugins.host.icebox.proto" + ], + "com.android.tools.utp:android-test-plugin-result-listener-gradle-proto": [ + "com.android.tools.utp.plugins.result.listener.gradle.proto" + ], + "com.android.tools:annotations": [ + "com.android.annotations", + "com.android.annotations.concurrency" + ], + "com.android.tools:common": [ + "com.android", + "com.android.ide.common.blame", + "com.android.io", + "com.android.prefs", + "com.android.resources", + "com.android.sdklib", + "com.android.support", + "com.android.testing.utils", + "com.android.tools.proguard", + "com.android.utils", + "com.android.utils.cache", + "com.android.utils.concurrency", + "com.android.utils.cxx", + "com.android.utils.cxx.collections", + "com.android.utils.cxx.io", + "com.android.utils.cxx.ninja", + "com.android.utils.cxx.os", + "com.android.utils.cxx.process", + "com.android.utils.function", + "com.android.utils.reflection", + "com.android.utils.sleep", + "com.android.utils.text", + "com.android.xml", + "com.android.xml.sax" + ], + "com.android.tools:desugar_jdk_libs_configuration": [ + "java.adapter", + "java.nio.channels", + "java.nio.file", + "java.nio.file.attribute", + "java.time", + "java.util", + "java.util.stream" + ], + "com.android.tools:desugar_jdk_libs_configuration_minimal": [ + "java.adapter", + "java.nio.channels", + "java.nio.file", + "java.nio.file.attribute", + "java.time", + "java.util", + "java.util.stream" + ], + "com.android.tools:desugar_jdk_libs_configuration_nio": [ + "java.adapter", + "java.nio.channels", + "java.nio.file", + "java.nio.file.attribute", + "java.time", + "java.util", + "java.util.stream" + ], + "com.android.tools:desugar_jdk_libs_minimal": [ + "desugar.sun.nio.fs", + "java.io", + "java.lang", + "java.lang.annotation", + "java.net", + "java.nio.channels", + "java.nio.charset", + "java.nio.charset.spi", + "java.nio.file", + "java.nio.file.attribute", + "java.nio.file.spi", + "java.time", + "java.time.chrono", + "java.time.format", + "java.time.temporal", + "java.time.zone", + "java.util", + "java.util.concurrent", + "java.util.concurrent.atomic", + "java.util.function", + "java.util.stream", + "jdk.internal.util", + "libcore.api", + "libcore.content.type", + "libcore.util", + "sun.misc", + "sun.nio", + "sun.nio.ch", + "sun.nio.cs", + "sun.nio.fs", + "sun.security.action", + "sun.util" + ], + "com.android.tools:desugar_jdk_libs_nio": [ + "desugar.sun.nio.fs", + "java.io", + "java.lang", + "java.lang.annotation", + "java.net", + "java.nio.channels", + "java.nio.charset", + "java.nio.charset.spi", + "java.nio.file", + "java.nio.file.attribute", + "java.nio.file.spi", + "java.time", + "java.time.chrono", + "java.time.format", + "java.time.temporal", + "java.time.zone", + "java.util", + "java.util.concurrent", + "java.util.concurrent.atomic", + "java.util.function", + "java.util.stream", + "jdk.internal.util", + "libcore.api", + "libcore.content.type", + "libcore.util", + "sun.misc", + "sun.nio", + "sun.nio.ch", + "sun.nio.cs", + "sun.nio.fs", + "sun.security.action", + "sun.util" + ], + "com.android.tools:dvlib": [ + "com.android.dvlib" + ], + "com.android.tools:r8": [ + "com.android.tools.r8", + "com.android.tools.r8.androidapi", + "com.android.tools.r8.assistant.postprocessing", + "com.android.tools.r8.assistant.runtime", + "com.android.tools.r8.compatproguard", + "com.android.tools.r8.dex", + "com.android.tools.r8.diagnostic", + "com.android.tools.r8.diagnostic.internal", + "com.android.tools.r8.errors", + "com.android.tools.r8.experimental.graphinfo", + "com.android.tools.r8.graph", + "com.android.tools.r8.graph.proto", + "com.android.tools.r8.inspector", + "com.android.tools.r8.internal", + "com.android.tools.r8.ir.analysis.value", + "com.android.tools.r8.ir.desugar.desugaredlibrary.lint", + "com.android.tools.r8.ir.desugar.varhandle", + "com.android.tools.r8.ir.optimize", + "com.android.tools.r8.ir.optimize.inliner", + "com.android.tools.r8.it.unimi.dsi.fastutil.ints", + "com.android.tools.r8.it.unimi.dsi.fastutil.longs", + "com.android.tools.r8.it.unimi.dsi.fastutil.objects", + "com.android.tools.r8.kotlin", + "com.android.tools.r8.libanalyzer", + "com.android.tools.r8.metadata", + "com.android.tools.r8.naming", + "com.android.tools.r8.naming.mappinginformation", + "com.android.tools.r8.origin", + "com.android.tools.r8.position", + "com.android.tools.r8.processkeeprules", + "com.android.tools.r8.profile.art", + "com.android.tools.r8.profile.art.diagnostic", + "com.android.tools.r8.references", + "com.android.tools.r8.relocated.keepanno.proto", + "com.android.tools.r8.relocator", + "com.android.tools.r8.retrace", + "com.android.tools.r8.shaking", + "com.android.tools.r8.startup", + "com.android.tools.r8.startup.diagnostic", + "com.android.tools.r8.synthesis", + "com.android.tools.r8.threading", + "com.android.tools.r8.threading.providers.blocking", + "com.android.tools.r8.threading.providers.singlethreaded", + "com.android.tools.r8.tracereferences", + "com.android.tools.r8.utils", + "com.android.tools.r8.utils.positions" + ], + "com.android.tools:repository": [ + "com.android.repository", + "com.android.repository.api", + "com.android.repository.impl.downloader", + "com.android.repository.impl.generated.generic.v1", + "com.android.repository.impl.generated.generic.v2", + "com.android.repository.impl.generated.v1", + "com.android.repository.impl.generated.v2", + "com.android.repository.impl.installer", + "com.android.repository.impl.manager", + "com.android.repository.impl.meta", + "com.android.repository.impl.sources", + "com.android.repository.impl.sources.generated.v1", + "com.android.repository.io", + "com.android.repository.util" + ], + "com.android.tools:sdk-common": [ + "com.android.ide.common.blame", + "com.android.ide.common.blame.parser", + "com.android.ide.common.blame.parser.aapt", + "com.android.ide.common.blame.parser.util", + "com.android.ide.common.build", + "com.android.ide.common.caching", + "com.android.ide.common.fonts", + "com.android.ide.common.gradle", + "com.android.ide.common.internal", + "com.android.ide.common.pagealign", + "com.android.ide.common.process", + "com.android.ide.common.rendering", + "com.android.ide.common.repository", + "com.android.ide.common.resources", + "com.android.ide.common.resources.configuration", + "com.android.ide.common.resources.escape.string", + "com.android.ide.common.resources.escape.xml", + "com.android.ide.common.resources.sampledata", + "com.android.ide.common.resources.usage", + "com.android.ide.common.sdk", + "com.android.ide.common.signing", + "com.android.ide.common.symbols", + "com.android.ide.common.util", + "com.android.ide.common.vectordrawable", + "com.android.ide.common.workers", + "com.android.ide.common.xml", + "com.android.instantapp.provision", + "com.android.instantapp.run", + "com.android.instantapp.sdk", + "com.android.instantapp.utils", + "com.android.projectmodel", + "wireless.android.instantapps.sdk" + ], + "com.android.tools:sdklib": [ + "com.android.sdklib", + "com.android.sdklib.devices", + "com.android.sdklib.internal.avd", + "com.android.sdklib.internal.build", + "com.android.sdklib.internal.project", + "com.android.sdklib.repository", + "com.android.sdklib.repository.generated.addon.v1", + "com.android.sdklib.repository.generated.addon.v2", + "com.android.sdklib.repository.generated.addon.v3", + "com.android.sdklib.repository.generated.common.v1", + "com.android.sdklib.repository.generated.common.v2", + "com.android.sdklib.repository.generated.common.v3", + "com.android.sdklib.repository.generated.repository.v1", + "com.android.sdklib.repository.generated.repository.v2", + "com.android.sdklib.repository.generated.repository.v3", + "com.android.sdklib.repository.generated.sysimg.v1", + "com.android.sdklib.repository.generated.sysimg.v2", + "com.android.sdklib.repository.generated.sysimg.v3", + "com.android.sdklib.repository.generated.sysimg.v4", + "com.android.sdklib.repository.installer", + "com.android.sdklib.repository.legacy", + "com.android.sdklib.repository.legacy.descriptors", + "com.android.sdklib.repository.legacy.io", + "com.android.sdklib.repository.legacy.local", + "com.android.sdklib.repository.legacy.remote", + "com.android.sdklib.repository.legacy.remote.internal", + "com.android.sdklib.repository.legacy.remote.internal.archives", + "com.android.sdklib.repository.legacy.remote.internal.packages", + "com.android.sdklib.repository.legacy.remote.internal.sources", + "com.android.sdklib.repository.meta", + "com.android.sdklib.repository.sources", + "com.android.sdklib.repository.sources.generated.v1", + "com.android.sdklib.repository.sources.generated.v2", + "com.android.sdklib.repository.sources.generated.v3", + "com.android.sdklib.repository.sources.generated.v4", + "com.android.sdklib.repository.sources.generated.v5", + "com.android.sdklib.repository.sources.generated.v6", + "com.android.sdklib.repository.targets", + "com.android.sdklib.tool", + "com.android.sdklib.tool.sdkmanager", + "com.android.sdklib.util" + ], + "com.android:signflinger": [ + "com.android.signflinger" + ], + "com.android:zipflinger": [ + "com.android.zipflinger" + ], + "com.beust:jcommander": [ + "com.beust.ah", + "com.beust.jcommander", + "com.beust.jcommander.converters", + "com.beust.jcommander.defaultprovider", + "com.beust.jcommander.internal", + "com.beust.jcommander.parser", + "com.beust.jcommander.validators" + ], + "com.github.ben-manes.caffeine:caffeine": [ + "com.github.benmanes.caffeine.cache", + "com.github.benmanes.caffeine.cache.stats" + ], + "com.github.kevinstern:software-and-algorithms": [ + "blogspot.software_and_algorithms.stern_library.data_structure", + "blogspot.software_and_algorithms.stern_library.geometry", + "blogspot.software_and_algorithms.stern_library.optimization", + "blogspot.software_and_algorithms.stern_library.string" + ], + "com.google.android:annotations": [ + "android.annotation" + ], + "com.google.api.grpc:proto-google-common-protos": [ + "com.google.api", + "com.google.cloud", + "com.google.cloud.audit", + "com.google.cloud.location", + "com.google.geo.type", + "com.google.logging.type", + "com.google.longrunning", + "com.google.rpc", + "com.google.rpc.context", + "com.google.type" + ], + "com.google.auto.service:auto-service": [ + "com.google.auto.service.processor" + ], + "com.google.auto.service:auto-service-annotations": [ + "com.google.auto.service" + ], + "com.google.auto.value:auto-value": [ + "autovalue.shaded.com.google.auto.common", + "autovalue.shaded.com.google.auto.service", + "autovalue.shaded.com.google.common.annotations", + "autovalue.shaded.com.google.common.base", + "autovalue.shaded.com.google.common.cache", + "autovalue.shaded.com.google.common.collect", + "autovalue.shaded.com.google.common.escape", + "autovalue.shaded.com.google.common.eventbus", + "autovalue.shaded.com.google.common.graph", + "autovalue.shaded.com.google.common.hash", + "autovalue.shaded.com.google.common.html", + "autovalue.shaded.com.google.common.io", + "autovalue.shaded.com.google.common.math", + "autovalue.shaded.com.google.common.net", + "autovalue.shaded.com.google.common.primitives", + "autovalue.shaded.com.google.common.reflect", + "autovalue.shaded.com.google.common.util.concurrent", + "autovalue.shaded.com.google.common.xml", + "autovalue.shaded.com.google.errorprone.annotations", + "autovalue.shaded.com.google.errorprone.annotations.concurrent", + "autovalue.shaded.com.google.escapevelocity", + "autovalue.shaded.com.google.j2objc.annotations", + "autovalue.shaded.com.squareup.javapoet", + "autovalue.shaded.net.ltgt.gradle.incap", + "autovalue.shaded.org.checkerframework.checker.nullness.qual", + "autovalue.shaded.org.checkerframework.framework.qual", + "autovalue.shaded.org.objectweb.asm", + "com.google.auto.value.extension", + "com.google.auto.value.extension.memoized.processor", + "com.google.auto.value.extension.serializable.processor", + "com.google.auto.value.extension.serializable.serializer", + "com.google.auto.value.extension.serializable.serializer.impl", + "com.google.auto.value.extension.serializable.serializer.interfaces", + "com.google.auto.value.extension.serializable.serializer.runtime", + "com.google.auto.value.extension.toprettystring.processor", + "com.google.auto.value.processor" + ], + "com.google.auto.value:auto-value-annotations": [ + "com.google.auto.value", + "com.google.auto.value.extension.memoized", + "com.google.auto.value.extension.serializable", + "com.google.auto.value.extension.toprettystring" + ], + "com.google.auto:auto-common": [ + "com.google.auto.common" + ], + "com.google.code.findbugs:jsr305": [ + "javax.annotation", + "javax.annotation.concurrent", + "javax.annotation.meta" + ], + "com.google.code.gson:gson": [ + "com.google.gson", + "com.google.gson.annotations", + "com.google.gson.internal", + "com.google.gson.internal.bind", + "com.google.gson.internal.bind.util", + "com.google.gson.internal.reflect", + "com.google.gson.internal.sql", + "com.google.gson.reflect", + "com.google.gson.stream" + ], + "com.google.crypto.tink:tink": [ + "com.google.crypto.tink", + "com.google.crypto.tink.aead", + "com.google.crypto.tink.aead.internal", + "com.google.crypto.tink.aead.subtle", + "com.google.crypto.tink.annotations", + "com.google.crypto.tink.config", + "com.google.crypto.tink.config.internal", + "com.google.crypto.tink.daead", + "com.google.crypto.tink.hybrid", + "com.google.crypto.tink.hybrid.internal", + "com.google.crypto.tink.hybrid.subtle", + "com.google.crypto.tink.internal", + "com.google.crypto.tink.jwt", + "com.google.crypto.tink.mac", + "com.google.crypto.tink.mac.internal", + "com.google.crypto.tink.monitoring", + "com.google.crypto.tink.prf", + "com.google.crypto.tink.proto", + "com.google.crypto.tink.signature", + "com.google.crypto.tink.signature.internal", + "com.google.crypto.tink.streamingaead", + "com.google.crypto.tink.subtle", + "com.google.crypto.tink.subtle.prf", + "com.google.crypto.tink.tinkkey", + "com.google.crypto.tink.tinkkey.internal", + "com.google.crypto.tink.util" + ], + "com.google.dagger:dagger": [ + "dagger", + "dagger.internal", + "dagger.multibindings" + ], + "com.google.errorprone:error_prone_annotation": [ + "com.google.errorprone" + ], + "com.google.errorprone:error_prone_annotations": [ + "com.google.errorprone.annotations", + "com.google.errorprone.annotations.concurrent" + ], + "com.google.errorprone:error_prone_check_api": [ + "com.google.errorprone", + "com.google.errorprone.apply", + "com.google.errorprone.bugpatterns", + "com.google.errorprone.dataflow", + "com.google.errorprone.dataflow.nullnesspropagation", + "com.google.errorprone.dataflow.nullnesspropagation.inference", + "com.google.errorprone.fixes", + "com.google.errorprone.matchers", + "com.google.errorprone.matchers.method", + "com.google.errorprone.names", + "com.google.errorprone.predicates", + "com.google.errorprone.predicates.type", + "com.google.errorprone.scanner", + "com.google.errorprone.suppliers", + "com.google.errorprone.util" + ], + "com.google.errorprone:error_prone_core": [ + "com.google.errorprone", + "com.google.errorprone.bugpatterns", + "com.google.errorprone.bugpatterns.android", + "com.google.errorprone.bugpatterns.apidiff", + "com.google.errorprone.bugpatterns.argumentselectiondefects", + "com.google.errorprone.bugpatterns.checkreturnvalue", + "com.google.errorprone.bugpatterns.collectionincompatibletype", + "com.google.errorprone.bugpatterns.flogger", + "com.google.errorprone.bugpatterns.formatstring", + "com.google.errorprone.bugpatterns.inject", + "com.google.errorprone.bugpatterns.inject.dagger", + "com.google.errorprone.bugpatterns.inject.guice", + "com.google.errorprone.bugpatterns.inlineme", + "com.google.errorprone.bugpatterns.javadoc", + "com.google.errorprone.bugpatterns.nullness", + "com.google.errorprone.bugpatterns.overloading", + "com.google.errorprone.bugpatterns.threadsafety", + "com.google.errorprone.bugpatterns.time", + "com.google.errorprone.refaster", + "com.google.errorprone.refaster.annotation", + "com.google.errorprone.scanner" + ], + "com.google.errorprone:error_prone_type_annotations": [ + "com.google.errorprone.annotations" + ], + "com.google.flatbuffers:flatbuffers-java": [ + "com.google.flatbuffers" + ], + "com.google.flogger:flogger": [ + "com.google.common.flogger", + "com.google.common.flogger.backend", + "com.google.common.flogger.context", + "com.google.common.flogger.parameter", + "com.google.common.flogger.parser", + "com.google.common.flogger.util" + ], + "com.google.flogger:flogger-system-backend": [ + "com.google.common.flogger.backend.system" + ], + "com.google.guava:failureaccess": [ + "com.google.common.util.concurrent.internal" + ], + "com.google.guava:guava": [ + "com.google.common.annotations", + "com.google.common.base", + "com.google.common.base.internal", + "com.google.common.cache", + "com.google.common.collect", + "com.google.common.escape", + "com.google.common.eventbus", + "com.google.common.graph", + "com.google.common.hash", + "com.google.common.html", + "com.google.common.io", + "com.google.common.math", + "com.google.common.net", + "com.google.common.primitives", + "com.google.common.reflect", + "com.google.common.util.concurrent", + "com.google.common.xml", + "com.google.thirdparty.publicsuffix" + ], + "com.google.guava:guava-testlib": [ + "com.google.common.collect.testing", + "com.google.common.collect.testing.features", + "com.google.common.collect.testing.google", + "com.google.common.collect.testing.suites", + "com.google.common.collect.testing.testers", + "com.google.common.escape.testing", + "com.google.common.testing", + "com.google.common.util.concurrent.testing" + ], + "com.google.j2objc:j2objc-annotations": [ + "com.google.j2objc.annotations" + ], + "com.google.jimfs:jimfs": [ + "com.google.common.jimfs" + ], + "com.google.protobuf:protobuf-java": [ + "com.google.protobuf", + "com.google.protobuf.compiler" + ], + "com.google.protobuf:protobuf-java-util": [ + "com.google.protobuf.util" + ], + "com.google.testing.compile:compile-testing": [ + "com.google.testing.compile" + ], + "com.google.testing.platform:core-proto": [ + "com.google.testing.platform.core.telemetry.proto", + "com.google.testing.platform.plugin.android.proto", + "com.google.testing.platform.proto.api.config", + "com.google.testing.platform.proto.api.core", + "com.google.testing.platform.proto.api.service" + ], + "com.google.testparameterinjector:test-parameter-injector": [ + "com.google.testing.junit.testparameterinjector" + ], + "com.google.truth.extensions:truth-liteproto-extension": [ + "com.google.common.truth.extensions.proto" + ], + "com.google.truth.extensions:truth-proto-extension": [ + "com.google.common.truth.extensions.proto" + ], + "com.google.truth:truth": [ + "com.google.common.truth" + ], + "com.googlecode.juniversalchardet:juniversalchardet": [ + "org.mozilla.universalchardet", + "org.mozilla.universalchardet.prober", + "org.mozilla.universalchardet.prober.contextanalysis", + "org.mozilla.universalchardet.prober.distributionanalysis", + "org.mozilla.universalchardet.prober.sequence", + "org.mozilla.universalchardet.prober.statemachine" + ], + "com.ibm.icu:icu4j": [ + "com.ibm.icu.impl", + "com.ibm.icu.impl.breakiter", + "com.ibm.icu.impl.coll", + "com.ibm.icu.impl.data", + "com.ibm.icu.impl.duration", + "com.ibm.icu.impl.duration.impl", + "com.ibm.icu.impl.locale", + "com.ibm.icu.impl.number", + "com.ibm.icu.impl.number.parse", + "com.ibm.icu.impl.number.range", + "com.ibm.icu.impl.personname", + "com.ibm.icu.impl.text", + "com.ibm.icu.impl.units", + "com.ibm.icu.lang", + "com.ibm.icu.math", + "com.ibm.icu.message2", + "com.ibm.icu.number", + "com.ibm.icu.text", + "com.ibm.icu.util" + ], + "com.squareup:javapoet": [ + "com.squareup.javapoet" + ], + "com.squareup:javawriter": [ + "com.squareup.javawriter" + ], + "com.squareup:kotlinpoet": [ + "com.squareup.kotlinpoet", + "com.squareup.kotlinpoet.jvm", + "com.squareup.kotlinpoet.tags" + ], + "com.sun.activation:javax.activation": [ + "com.sun.activation.registries", + "com.sun.activation.viewers", + "javax.activation" + ], + "com.sun.istack:istack-commons-runtime": [ + "com.sun.istack", + "com.sun.istack.localization", + "com.sun.istack.logging" + ], + "com.sun.xml.fastinfoset:FastInfoset": [ + "com.sun.xml.fastinfoset", + "com.sun.xml.fastinfoset.algorithm", + "com.sun.xml.fastinfoset.alphabet", + "com.sun.xml.fastinfoset.dom", + "com.sun.xml.fastinfoset.org.apache.xerces.util", + "com.sun.xml.fastinfoset.sax", + "com.sun.xml.fastinfoset.stax", + "com.sun.xml.fastinfoset.stax.events", + "com.sun.xml.fastinfoset.stax.factory", + "com.sun.xml.fastinfoset.stax.util", + "com.sun.xml.fastinfoset.tools", + "com.sun.xml.fastinfoset.util", + "com.sun.xml.fastinfoset.vocab", + "org.jvnet.fastinfoset", + "org.jvnet.fastinfoset.sax", + "org.jvnet.fastinfoset.sax.helpers", + "org.jvnet.fastinfoset.stax" + ], + "commons-codec:commons-codec": [ + "org.apache.commons.codec", + "org.apache.commons.codec.binary", + "org.apache.commons.codec.cli", + "org.apache.commons.codec.digest", + "org.apache.commons.codec.language", + "org.apache.commons.codec.language.bm", + "org.apache.commons.codec.net" + ], + "commons-io:commons-io": [ + "org.apache.commons.io", + "org.apache.commons.io.build", + "org.apache.commons.io.charset", + "org.apache.commons.io.comparator", + "org.apache.commons.io.file", + "org.apache.commons.io.file.attribute", + "org.apache.commons.io.file.spi", + "org.apache.commons.io.filefilter", + "org.apache.commons.io.function", + "org.apache.commons.io.input", + "org.apache.commons.io.input.buffer", + "org.apache.commons.io.monitor", + "org.apache.commons.io.output", + "org.apache.commons.io.serialization" + ], + "commons-logging:commons-logging": [ + "org.apache.commons.logging", + "org.apache.commons.logging.impl" + ], + "info.picocli:picocli": [ + "picocli" + ], + "io.github.eisop:dataflow-errorprone": [ + "org.checkerframework.dataflow.qual", + "org.checkerframework.errorprone.checker.builder.qual", + "org.checkerframework.errorprone.checker.calledmethods.qual", + "org.checkerframework.errorprone.checker.compilermsgs.qual", + "org.checkerframework.errorprone.checker.fenum.qual", + "org.checkerframework.errorprone.checker.formatter.qual", + "org.checkerframework.errorprone.checker.guieffect.qual", + "org.checkerframework.errorprone.checker.i18n.qual", + "org.checkerframework.errorprone.checker.i18nformatter.qual", + "org.checkerframework.errorprone.checker.index.qual", + "org.checkerframework.errorprone.checker.initialization.qual", + "org.checkerframework.errorprone.checker.interning.qual", + "org.checkerframework.errorprone.checker.lock.qual", + "org.checkerframework.errorprone.checker.mustcall.qual", + "org.checkerframework.errorprone.checker.nullness.qual", + "org.checkerframework.errorprone.checker.optional.qual", + "org.checkerframework.errorprone.checker.propkey.qual", + "org.checkerframework.errorprone.checker.regex.qual", + "org.checkerframework.errorprone.checker.signature.qual", + "org.checkerframework.errorprone.checker.signedness.qual", + "org.checkerframework.errorprone.checker.tainting.qual", + "org.checkerframework.errorprone.checker.units.qual", + "org.checkerframework.errorprone.com.google.common.annotations", + "org.checkerframework.errorprone.com.google.common.base", + "org.checkerframework.errorprone.com.google.common.base.internal", + "org.checkerframework.errorprone.com.google.common.cache", + "org.checkerframework.errorprone.com.google.common.collect", + "org.checkerframework.errorprone.com.google.common.escape", + "org.checkerframework.errorprone.com.google.common.eventbus", + "org.checkerframework.errorprone.com.google.common.graph", + "org.checkerframework.errorprone.com.google.common.hash", + "org.checkerframework.errorprone.com.google.common.html", + "org.checkerframework.errorprone.com.google.common.io", + "org.checkerframework.errorprone.com.google.common.math", + "org.checkerframework.errorprone.com.google.common.net", + "org.checkerframework.errorprone.com.google.common.primitives", + "org.checkerframework.errorprone.com.google.common.reflect", + "org.checkerframework.errorprone.com.google.common.util.concurrent", + "org.checkerframework.errorprone.com.google.common.xml", + "org.checkerframework.errorprone.com.google.errorprone.annotations", + "org.checkerframework.errorprone.com.google.errorprone.annotations.concurrent", + "org.checkerframework.errorprone.com.google.thirdparty.publicsuffix", + "org.checkerframework.errorprone.common.aliasing.qual", + "org.checkerframework.errorprone.common.initializedfields.qual", + "org.checkerframework.errorprone.common.reflection.qual", + "org.checkerframework.errorprone.common.returnsreceiver.qual", + "org.checkerframework.errorprone.common.subtyping.qual", + "org.checkerframework.errorprone.common.util.report.qual", + "org.checkerframework.errorprone.common.value.qual", + "org.checkerframework.errorprone.dataflow.analysis", + "org.checkerframework.errorprone.dataflow.busyexpr", + "org.checkerframework.errorprone.dataflow.cfg", + "org.checkerframework.errorprone.dataflow.cfg.block", + "org.checkerframework.errorprone.dataflow.cfg.builder", + "org.checkerframework.errorprone.dataflow.cfg.node", + "org.checkerframework.errorprone.dataflow.cfg.playground", + "org.checkerframework.errorprone.dataflow.cfg.visualize", + "org.checkerframework.errorprone.dataflow.constantpropagation", + "org.checkerframework.errorprone.dataflow.expression", + "org.checkerframework.errorprone.dataflow.livevariable", + "org.checkerframework.errorprone.dataflow.reachingdef", + "org.checkerframework.errorprone.dataflow.util", + "org.checkerframework.errorprone.framework.qual", + "org.checkerframework.errorprone.javacutil", + "org.checkerframework.errorprone.javacutil.trees", + "org.checkerframework.errorprone.org.plumelib.reflection", + "org.checkerframework.errorprone.org.plumelib.util" + ], + "io.github.java-diff-utils:java-diff-utils": [ + "com.github.difflib", + "com.github.difflib.algorithm", + "com.github.difflib.algorithm.myers", + "com.github.difflib.patch", + "com.github.difflib.text", + "com.github.difflib.unifieddiff" + ], + "io.grpc:grpc-api": [ + "io.grpc" + ], + "io.grpc:grpc-core": [ + "io.grpc.inprocess", + "io.grpc.internal", + "io.grpc.util" + ], + "io.grpc:grpc-netty": [ + "io.grpc.netty" + ], + "io.grpc:grpc-protobuf": [ + "io.grpc.protobuf" + ], + "io.grpc:grpc-protobuf-lite": [ + "io.grpc.protobuf.lite" + ], + "io.grpc:grpc-stub": [ + "io.grpc.stub", + "io.grpc.stub.annotations" + ], + "io.netty:netty-buffer": [ + "io.netty.buffer", + "io.netty.buffer.search" + ], + "io.netty:netty-codec": [ + "io.netty.handler.codec", + "io.netty.handler.codec.base64", + "io.netty.handler.codec.bytes", + "io.netty.handler.codec.compression", + "io.netty.handler.codec.json", + "io.netty.handler.codec.marshalling", + "io.netty.handler.codec.protobuf", + "io.netty.handler.codec.serialization", + "io.netty.handler.codec.string", + "io.netty.handler.codec.xml" + ], + "io.netty:netty-codec-http": [ + "io.netty.handler.codec.http", + "io.netty.handler.codec.http.cookie", + "io.netty.handler.codec.http.cors", + "io.netty.handler.codec.http.multipart", + "io.netty.handler.codec.http.websocketx", + "io.netty.handler.codec.http.websocketx.extensions", + "io.netty.handler.codec.http.websocketx.extensions.compression", + "io.netty.handler.codec.rtsp", + "io.netty.handler.codec.spdy" + ], + "io.netty:netty-codec-http2": [ + "io.netty.handler.codec.http2" + ], + "io.netty:netty-codec-socks": [ + "io.netty.handler.codec.socks", + "io.netty.handler.codec.socksx", + "io.netty.handler.codec.socksx.v4", + "io.netty.handler.codec.socksx.v5" + ], + "io.netty:netty-common": [ + "io.netty.util", + "io.netty.util.collection", + "io.netty.util.concurrent", + "io.netty.util.internal", + "io.netty.util.internal.logging", + "io.netty.util.internal.shaded.org.jctools.queues", + "io.netty.util.internal.shaded.org.jctools.queues.atomic", + "io.netty.util.internal.shaded.org.jctools.util", + "io.netty.util.internal.svm" + ], + "io.netty:netty-handler": [ + "io.netty.handler.address", + "io.netty.handler.flow", + "io.netty.handler.flush", + "io.netty.handler.ipfilter", + "io.netty.handler.logging", + "io.netty.handler.pcap", + "io.netty.handler.ssl", + "io.netty.handler.ssl.ocsp", + "io.netty.handler.ssl.util", + "io.netty.handler.stream", + "io.netty.handler.timeout", + "io.netty.handler.traffic" + ], + "io.netty:netty-handler-proxy": [ + "io.netty.handler.proxy" + ], + "io.netty:netty-resolver": [ + "io.netty.resolver" + ], + "io.netty:netty-transport": [ + "io.netty.bootstrap", + "io.netty.channel", + "io.netty.channel.embedded", + "io.netty.channel.group", + "io.netty.channel.internal", + "io.netty.channel.local", + "io.netty.channel.nio", + "io.netty.channel.oio", + "io.netty.channel.pool", + "io.netty.channel.socket", + "io.netty.channel.socket.nio", + "io.netty.channel.socket.oio" + ], + "io.netty:netty-transport-native-unix-common": [ + "io.netty.channel.unix" + ], + "io.perfmark:perfmark-api": [ + "io.perfmark" + ], + "jakarta.activation:jakarta.activation-api": [ + "javax.activation" + ], + "jakarta.inject:jakarta.inject-api": [ + "jakarta.inject" + ], + "jakarta.xml.bind:jakarta.xml.bind-api": [ + "javax.xml.bind", + "javax.xml.bind.annotation", + "javax.xml.bind.annotation.adapters", + "javax.xml.bind.attachment", + "javax.xml.bind.helpers", + "javax.xml.bind.util" + ], + "javax.annotation:javax.annotation-api": [ + "javax.annotation", + "javax.annotation.security", + "javax.annotation.sql" + ], + "javax.inject:javax.inject": [ + "javax.inject" + ], + "junit:junit": [ + "junit.extensions", + "junit.framework", + "junit.runner", + "junit.textui", + "org.junit", + "org.junit.experimental", + "org.junit.experimental.categories", + "org.junit.experimental.max", + "org.junit.experimental.results", + "org.junit.experimental.runners", + "org.junit.experimental.theories", + "org.junit.experimental.theories.internal", + "org.junit.experimental.theories.suppliers", + "org.junit.function", + "org.junit.internal", + "org.junit.internal.builders", + "org.junit.internal.management", + "org.junit.internal.matchers", + "org.junit.internal.requests", + "org.junit.internal.runners", + "org.junit.internal.runners.model", + "org.junit.internal.runners.rules", + "org.junit.internal.runners.statements", + "org.junit.matchers", + "org.junit.rules", + "org.junit.runner", + "org.junit.runner.manipulation", + "org.junit.runner.notification", + "org.junit.runners", + "org.junit.runners.model", + "org.junit.runners.parameterized", + "org.junit.validator" + ], + "net.bytebuddy:byte-buddy": [ + "net.bytebuddy", + "net.bytebuddy.agent.builder", + "net.bytebuddy.asm", + "net.bytebuddy.build", + "net.bytebuddy.description", + "net.bytebuddy.description.annotation", + "net.bytebuddy.description.enumeration", + "net.bytebuddy.description.field", + "net.bytebuddy.description.method", + "net.bytebuddy.description.modifier", + "net.bytebuddy.description.type", + "net.bytebuddy.dynamic", + "net.bytebuddy.dynamic.loading", + "net.bytebuddy.dynamic.scaffold", + "net.bytebuddy.dynamic.scaffold.inline", + "net.bytebuddy.dynamic.scaffold.subclass", + "net.bytebuddy.implementation", + "net.bytebuddy.implementation.attribute", + "net.bytebuddy.implementation.auxiliary", + "net.bytebuddy.implementation.bind", + "net.bytebuddy.implementation.bind.annotation", + "net.bytebuddy.implementation.bytecode", + "net.bytebuddy.implementation.bytecode.assign", + "net.bytebuddy.implementation.bytecode.assign.primitive", + "net.bytebuddy.implementation.bytecode.assign.reference", + "net.bytebuddy.implementation.bytecode.collection", + "net.bytebuddy.implementation.bytecode.constant", + "net.bytebuddy.implementation.bytecode.member", + "net.bytebuddy.jar.asm", + "net.bytebuddy.jar.asm.commons", + "net.bytebuddy.jar.asm.signature", + "net.bytebuddy.matcher", + "net.bytebuddy.pool", + "net.bytebuddy.utility", + "net.bytebuddy.utility.dispatcher", + "net.bytebuddy.utility.nullability", + "net.bytebuddy.utility.privilege", + "net.bytebuddy.utility.visitor" + ], + "net.bytebuddy:byte-buddy-agent": [ + "net.bytebuddy.agent", + "net.bytebuddy.agent.utility.nullability" + ], + "net.java.dev.jna:jna": [ + "com.sun.jna", + "com.sun.jna.internal", + "com.sun.jna.ptr", + "com.sun.jna.win32" + ], + "net.java.dev.jna:jna-platform": [ + "com.sun.jna.platform", + "com.sun.jna.platform.dnd", + "com.sun.jna.platform.linux", + "com.sun.jna.platform.mac", + "com.sun.jna.platform.unix", + "com.sun.jna.platform.unix.solaris", + "com.sun.jna.platform.win32", + "com.sun.jna.platform.win32.COM", + "com.sun.jna.platform.win32.COM.tlb", + "com.sun.jna.platform.win32.COM.tlb.imp", + "com.sun.jna.platform.win32.COM.util", + "com.sun.jna.platform.win32.COM.util.annotation", + "com.sun.jna.platform.wince" + ], + "net.sf.jopt-simple:jopt-simple": [ + "joptsimple", + "joptsimple.internal", + "joptsimple.util" + ], + "net.sf.kxml:kxml2": [ + "org.kxml2.io", + "org.kxml2.kdom", + "org.kxml2.wap", + "org.kxml2.wap.syncml", + "org.kxml2.wap.wml", + "org.kxml2.wap.wv", + "org.xmlpull.v1" + ], + "org.apache.commons:commons-compress": [ + "org.apache.commons.compress", + "org.apache.commons.compress.archivers", + "org.apache.commons.compress.archivers.ar", + "org.apache.commons.compress.archivers.arj", + "org.apache.commons.compress.archivers.cpio", + "org.apache.commons.compress.archivers.dump", + "org.apache.commons.compress.archivers.examples", + "org.apache.commons.compress.archivers.jar", + "org.apache.commons.compress.archivers.sevenz", + "org.apache.commons.compress.archivers.tar", + "org.apache.commons.compress.archivers.zip", + "org.apache.commons.compress.changes", + "org.apache.commons.compress.compressors", + "org.apache.commons.compress.compressors.brotli", + "org.apache.commons.compress.compressors.bzip2", + "org.apache.commons.compress.compressors.deflate", + "org.apache.commons.compress.compressors.deflate64", + "org.apache.commons.compress.compressors.gzip", + "org.apache.commons.compress.compressors.lz4", + "org.apache.commons.compress.compressors.lz77support", + "org.apache.commons.compress.compressors.lzma", + "org.apache.commons.compress.compressors.lzw", + "org.apache.commons.compress.compressors.pack200", + "org.apache.commons.compress.compressors.snappy", + "org.apache.commons.compress.compressors.xz", + "org.apache.commons.compress.compressors.z", + "org.apache.commons.compress.compressors.zstandard", + "org.apache.commons.compress.harmony.archive.internal.nls", + "org.apache.commons.compress.harmony.pack200", + "org.apache.commons.compress.harmony.unpack200", + "org.apache.commons.compress.harmony.unpack200.bytecode", + "org.apache.commons.compress.harmony.unpack200.bytecode.forms", + "org.apache.commons.compress.java.util.jar", + "org.apache.commons.compress.parallel", + "org.apache.commons.compress.utils" + ], + "org.apache.httpcomponents:httpclient": [ + "org.apache.http.auth", + "org.apache.http.auth.params", + "org.apache.http.client", + "org.apache.http.client.config", + "org.apache.http.client.entity", + "org.apache.http.client.methods", + "org.apache.http.client.params", + "org.apache.http.client.protocol", + "org.apache.http.client.utils", + "org.apache.http.conn", + "org.apache.http.conn.params", + "org.apache.http.conn.routing", + "org.apache.http.conn.scheme", + "org.apache.http.conn.socket", + "org.apache.http.conn.ssl", + "org.apache.http.conn.util", + "org.apache.http.cookie", + "org.apache.http.cookie.params", + "org.apache.http.impl.auth", + "org.apache.http.impl.client", + "org.apache.http.impl.conn", + "org.apache.http.impl.conn.tsccm", + "org.apache.http.impl.cookie", + "org.apache.http.impl.execchain" + ], + "org.apache.httpcomponents:httpcore": [ + "org.apache.http", + "org.apache.http.annotation", + "org.apache.http.concurrent", + "org.apache.http.config", + "org.apache.http.entity", + "org.apache.http.impl", + "org.apache.http.impl.bootstrap", + "org.apache.http.impl.entity", + "org.apache.http.impl.io", + "org.apache.http.impl.pool", + "org.apache.http.io", + "org.apache.http.message", + "org.apache.http.params", + "org.apache.http.pool", + "org.apache.http.protocol", + "org.apache.http.ssl", + "org.apache.http.util" + ], + "org.apache.httpcomponents:httpmime": [ + "org.apache.http.entity.mime", + "org.apache.http.entity.mime.content" + ], + "org.bitbucket.b_c:jose4j": [ + "org.jose4j.base64url", + "org.jose4j.base64url.internal.apache.commons.codec.binary", + "org.jose4j.http", + "org.jose4j.jca", + "org.jose4j.json", + "org.jose4j.json.internal.json_simple", + "org.jose4j.json.internal.json_simple.parser", + "org.jose4j.jwa", + "org.jose4j.jwe", + "org.jose4j.jwe.kdf", + "org.jose4j.jwk", + "org.jose4j.jws", + "org.jose4j.jwt", + "org.jose4j.jwt.consumer", + "org.jose4j.jwx", + "org.jose4j.keys", + "org.jose4j.keys.resolvers", + "org.jose4j.lang", + "org.jose4j.mac", + "org.jose4j.zip" + ], + "org.bouncycastle:bcpkix-jdk18on": [ + "org.bouncycastle.cert", + "org.bouncycastle.cert.bc", + "org.bouncycastle.cert.cmp", + "org.bouncycastle.cert.crmf", + "org.bouncycastle.cert.crmf.bc", + "org.bouncycastle.cert.crmf.jcajce", + "org.bouncycastle.cert.dane", + "org.bouncycastle.cert.dane.fetcher", + "org.bouncycastle.cert.jcajce", + "org.bouncycastle.cert.ocsp", + "org.bouncycastle.cert.ocsp.jcajce", + "org.bouncycastle.cert.path", + "org.bouncycastle.cert.path.validations", + "org.bouncycastle.cert.selector", + "org.bouncycastle.cert.selector.jcajce", + "org.bouncycastle.cmc", + "org.bouncycastle.cms", + "org.bouncycastle.cms.bc", + "org.bouncycastle.cms.jcajce", + "org.bouncycastle.dvcs", + "org.bouncycastle.eac", + "org.bouncycastle.eac.jcajce", + "org.bouncycastle.eac.operator", + "org.bouncycastle.eac.operator.jcajce", + "org.bouncycastle.est", + "org.bouncycastle.est.jcajce", + "org.bouncycastle.its", + "org.bouncycastle.its.bc", + "org.bouncycastle.its.jcajce", + "org.bouncycastle.its.operator", + "org.bouncycastle.mime", + "org.bouncycastle.mime.encoding", + "org.bouncycastle.mime.smime", + "org.bouncycastle.mozilla", + "org.bouncycastle.mozilla.jcajce", + "org.bouncycastle.openssl", + "org.bouncycastle.openssl.bc", + "org.bouncycastle.openssl.jcajce", + "org.bouncycastle.operator", + "org.bouncycastle.operator.bc", + "org.bouncycastle.operator.jcajce", + "org.bouncycastle.pkcs", + "org.bouncycastle.pkcs.bc", + "org.bouncycastle.pkcs.jcajce", + "org.bouncycastle.pkix", + "org.bouncycastle.pkix.jcajce", + "org.bouncycastle.pkix.util", + "org.bouncycastle.pkix.util.filter", + "org.bouncycastle.tsp", + "org.bouncycastle.tsp.cms", + "org.bouncycastle.tsp.ers", + "org.bouncycastle.voms" + ], + "org.bouncycastle:bcprov-jdk18on": [ + "org.bouncycastle", + "org.bouncycastle.asn1", + "org.bouncycastle.asn1.anssi", + "org.bouncycastle.asn1.bc", + "org.bouncycastle.asn1.cryptopro", + "org.bouncycastle.asn1.gm", + "org.bouncycastle.asn1.nist", + "org.bouncycastle.asn1.ocsp", + "org.bouncycastle.asn1.pkcs", + "org.bouncycastle.asn1.sec", + "org.bouncycastle.asn1.teletrust", + "org.bouncycastle.asn1.ua", + "org.bouncycastle.asn1.util", + "org.bouncycastle.asn1.x500", + "org.bouncycastle.asn1.x500.style", + "org.bouncycastle.asn1.x509", + "org.bouncycastle.asn1.x509.qualified", + "org.bouncycastle.asn1.x509.sigi", + "org.bouncycastle.asn1.x9", + "org.bouncycastle.crypto", + "org.bouncycastle.crypto.agreement", + "org.bouncycastle.crypto.agreement.jpake", + "org.bouncycastle.crypto.agreement.kdf", + "org.bouncycastle.crypto.agreement.srp", + "org.bouncycastle.crypto.commitments", + "org.bouncycastle.crypto.constraints", + "org.bouncycastle.crypto.digests", + "org.bouncycastle.crypto.ec", + "org.bouncycastle.crypto.encodings", + "org.bouncycastle.crypto.engines", + "org.bouncycastle.crypto.examples", + "org.bouncycastle.crypto.fpe", + "org.bouncycastle.crypto.generators", + "org.bouncycastle.crypto.hpke", + "org.bouncycastle.crypto.io", + "org.bouncycastle.crypto.kems", + "org.bouncycastle.crypto.macs", + "org.bouncycastle.crypto.modes", + "org.bouncycastle.crypto.modes.gcm", + "org.bouncycastle.crypto.modes.kgcm", + "org.bouncycastle.crypto.paddings", + "org.bouncycastle.crypto.params", + "org.bouncycastle.crypto.parsers", + "org.bouncycastle.crypto.prng", + "org.bouncycastle.crypto.prng.drbg", + "org.bouncycastle.crypto.signers", + "org.bouncycastle.crypto.tls", + "org.bouncycastle.crypto.util", + "org.bouncycastle.i18n", + "org.bouncycastle.i18n.filter", + "org.bouncycastle.iana", + "org.bouncycastle.internal.asn1.bsi", + "org.bouncycastle.internal.asn1.cms", + "org.bouncycastle.internal.asn1.cryptlib", + "org.bouncycastle.internal.asn1.eac", + "org.bouncycastle.internal.asn1.edec", + "org.bouncycastle.internal.asn1.gnu", + "org.bouncycastle.internal.asn1.iana", + "org.bouncycastle.internal.asn1.isara", + "org.bouncycastle.internal.asn1.isismtt", + "org.bouncycastle.internal.asn1.iso", + "org.bouncycastle.internal.asn1.kisa", + "org.bouncycastle.internal.asn1.microsoft", + "org.bouncycastle.internal.asn1.misc", + "org.bouncycastle.internal.asn1.nsri", + "org.bouncycastle.internal.asn1.ntt", + "org.bouncycastle.internal.asn1.oiw", + "org.bouncycastle.internal.asn1.rosstandart", + "org.bouncycastle.jcajce", + "org.bouncycastle.jcajce.interfaces", + "org.bouncycastle.jcajce.io", + "org.bouncycastle.jcajce.provider.asymmetric", + "org.bouncycastle.jcajce.provider.asymmetric.compositesignatures", + "org.bouncycastle.jcajce.provider.asymmetric.dh", + "org.bouncycastle.jcajce.provider.asymmetric.dsa", + "org.bouncycastle.jcajce.provider.asymmetric.dstu", + "org.bouncycastle.jcajce.provider.asymmetric.ec", + "org.bouncycastle.jcajce.provider.asymmetric.ecgost", + "org.bouncycastle.jcajce.provider.asymmetric.ecgost12", + "org.bouncycastle.jcajce.provider.asymmetric.edec", + "org.bouncycastle.jcajce.provider.asymmetric.elgamal", + "org.bouncycastle.jcajce.provider.asymmetric.gost", + "org.bouncycastle.jcajce.provider.asymmetric.ies", + "org.bouncycastle.jcajce.provider.asymmetric.mldsa", + "org.bouncycastle.jcajce.provider.asymmetric.mlkem", + "org.bouncycastle.jcajce.provider.asymmetric.rsa", + "org.bouncycastle.jcajce.provider.asymmetric.slhdsa", + "org.bouncycastle.jcajce.provider.asymmetric.util", + "org.bouncycastle.jcajce.provider.asymmetric.x509", + "org.bouncycastle.jcajce.provider.config", + "org.bouncycastle.jcajce.provider.digest", + "org.bouncycastle.jcajce.provider.drbg", + "org.bouncycastle.jcajce.provider.keystore", + "org.bouncycastle.jcajce.provider.keystore.bc", + "org.bouncycastle.jcajce.provider.keystore.bcfks", + "org.bouncycastle.jcajce.provider.keystore.pkcs12", + "org.bouncycastle.jcajce.provider.keystore.util", + "org.bouncycastle.jcajce.provider.symmetric", + "org.bouncycastle.jcajce.provider.symmetric.util", + "org.bouncycastle.jcajce.provider.util", + "org.bouncycastle.jcajce.spec", + "org.bouncycastle.jcajce.util", + "org.bouncycastle.jce", + "org.bouncycastle.jce.exception", + "org.bouncycastle.jce.interfaces", + "org.bouncycastle.jce.netscape", + "org.bouncycastle.jce.provider", + "org.bouncycastle.jce.spec", + "org.bouncycastle.math", + "org.bouncycastle.math.ec", + "org.bouncycastle.math.ec.custom.djb", + "org.bouncycastle.math.ec.custom.gm", + "org.bouncycastle.math.ec.custom.sec", + "org.bouncycastle.math.ec.endo", + "org.bouncycastle.math.ec.rfc7748", + "org.bouncycastle.math.ec.rfc8032", + "org.bouncycastle.math.ec.tools", + "org.bouncycastle.math.field", + "org.bouncycastle.math.raw", + "org.bouncycastle.pqc.asn1", + "org.bouncycastle.pqc.crypto", + "org.bouncycastle.pqc.crypto.bike", + "org.bouncycastle.pqc.crypto.cmce", + "org.bouncycastle.pqc.crypto.crystals.dilithium", + "org.bouncycastle.pqc.crypto.falcon", + "org.bouncycastle.pqc.crypto.frodo", + "org.bouncycastle.pqc.crypto.gemss", + "org.bouncycastle.pqc.crypto.hqc", + "org.bouncycastle.pqc.crypto.lms", + "org.bouncycastle.pqc.crypto.mldsa", + "org.bouncycastle.pqc.crypto.mlkem", + "org.bouncycastle.pqc.crypto.newhope", + "org.bouncycastle.pqc.crypto.ntru", + "org.bouncycastle.pqc.crypto.ntruprime", + "org.bouncycastle.pqc.crypto.picnic", + "org.bouncycastle.pqc.crypto.rainbow", + "org.bouncycastle.pqc.crypto.saber", + "org.bouncycastle.pqc.crypto.slhdsa", + "org.bouncycastle.pqc.crypto.sphincs", + "org.bouncycastle.pqc.crypto.sphincsplus", + "org.bouncycastle.pqc.crypto.util", + "org.bouncycastle.pqc.crypto.xmss", + "org.bouncycastle.pqc.crypto.xwing", + "org.bouncycastle.pqc.jcajce.interfaces", + "org.bouncycastle.pqc.jcajce.provider", + "org.bouncycastle.pqc.jcajce.provider.bike", + "org.bouncycastle.pqc.jcajce.provider.cmce", + "org.bouncycastle.pqc.jcajce.provider.dilithium", + "org.bouncycastle.pqc.jcajce.provider.falcon", + "org.bouncycastle.pqc.jcajce.provider.frodo", + "org.bouncycastle.pqc.jcajce.provider.gmss", + "org.bouncycastle.pqc.jcajce.provider.hqc", + "org.bouncycastle.pqc.jcajce.provider.kyber", + "org.bouncycastle.pqc.jcajce.provider.lms", + "org.bouncycastle.pqc.jcajce.provider.mceliece", + "org.bouncycastle.pqc.jcajce.provider.newhope", + "org.bouncycastle.pqc.jcajce.provider.ntru", + "org.bouncycastle.pqc.jcajce.provider.ntruprime", + "org.bouncycastle.pqc.jcajce.provider.picnic", + "org.bouncycastle.pqc.jcajce.provider.rainbow", + "org.bouncycastle.pqc.jcajce.provider.saber", + "org.bouncycastle.pqc.jcajce.provider.sphincs", + "org.bouncycastle.pqc.jcajce.provider.sphincsplus", + "org.bouncycastle.pqc.jcajce.provider.util", + "org.bouncycastle.pqc.jcajce.provider.xmss", + "org.bouncycastle.pqc.jcajce.spec", + "org.bouncycastle.pqc.legacy.crypto.gmss", + "org.bouncycastle.pqc.legacy.crypto.gmss.util", + "org.bouncycastle.pqc.legacy.crypto.mceliece", + "org.bouncycastle.pqc.legacy.crypto.ntru", + "org.bouncycastle.pqc.legacy.crypto.qtesla", + "org.bouncycastle.pqc.legacy.crypto.rainbow", + "org.bouncycastle.pqc.legacy.crypto.rainbow.util", + "org.bouncycastle.pqc.legacy.math.linearalgebra", + "org.bouncycastle.pqc.legacy.math.ntru.euclid", + "org.bouncycastle.pqc.legacy.math.ntru.polynomial", + "org.bouncycastle.pqc.legacy.math.ntru.util", + "org.bouncycastle.pqc.math.ntru", + "org.bouncycastle.pqc.math.ntru.parameters", + "org.bouncycastle.util", + "org.bouncycastle.util.encoders", + "org.bouncycastle.util.io", + "org.bouncycastle.util.io.pem", + "org.bouncycastle.util.test", + "org.bouncycastle.x509", + "org.bouncycastle.x509.extension", + "org.bouncycastle.x509.util" + ], + "org.bouncycastle:bcutil-jdk18on": [ + "org.bouncycastle.asn1.bsi", + "org.bouncycastle.asn1.cmc", + "org.bouncycastle.asn1.cmp", + "org.bouncycastle.asn1.cms", + "org.bouncycastle.asn1.cms.ecc", + "org.bouncycastle.asn1.crmf", + "org.bouncycastle.asn1.cryptlib", + "org.bouncycastle.asn1.dvcs", + "org.bouncycastle.asn1.eac", + "org.bouncycastle.asn1.edec", + "org.bouncycastle.asn1.esf", + "org.bouncycastle.asn1.ess", + "org.bouncycastle.asn1.est", + "org.bouncycastle.asn1.gnu", + "org.bouncycastle.asn1.iana", + "org.bouncycastle.asn1.icao", + "org.bouncycastle.asn1.isara", + "org.bouncycastle.asn1.isismtt", + "org.bouncycastle.asn1.isismtt.ocsp", + "org.bouncycastle.asn1.isismtt.x509", + "org.bouncycastle.asn1.iso", + "org.bouncycastle.asn1.kisa", + "org.bouncycastle.asn1.microsoft", + "org.bouncycastle.asn1.misc", + "org.bouncycastle.asn1.mozilla", + "org.bouncycastle.asn1.nsri", + "org.bouncycastle.asn1.ntt", + "org.bouncycastle.asn1.oiw", + "org.bouncycastle.asn1.rosstandart", + "org.bouncycastle.asn1.smime", + "org.bouncycastle.asn1.tsp", + "org.bouncycastle.oer", + "org.bouncycastle.oer.its", + "org.bouncycastle.oer.its.etsi102941", + "org.bouncycastle.oer.its.etsi102941.basetypes", + "org.bouncycastle.oer.its.etsi103097", + "org.bouncycastle.oer.its.etsi103097.extension", + "org.bouncycastle.oer.its.ieee1609dot2", + "org.bouncycastle.oer.its.ieee1609dot2.basetypes", + "org.bouncycastle.oer.its.ieee1609dot2dot1", + "org.bouncycastle.oer.its.template.etsi102941", + "org.bouncycastle.oer.its.template.etsi102941.basetypes", + "org.bouncycastle.oer.its.template.etsi103097", + "org.bouncycastle.oer.its.template.etsi103097.extension", + "org.bouncycastle.oer.its.template.ieee1609dot2", + "org.bouncycastle.oer.its.template.ieee1609dot2.basetypes", + "org.bouncycastle.oer.its.template.ieee1609dot2dot1" + ], + "org.checkerframework:checker-compat-qual": [ + "org.checkerframework.checker.nullness.compatqual" + ], + "org.checkerframework:checker-qual": [ + "org.checkerframework.checker.builder.qual", + "org.checkerframework.checker.calledmethods.qual", + "org.checkerframework.checker.compilermsgs.qual", + "org.checkerframework.checker.fenum.qual", + "org.checkerframework.checker.formatter.qual", + "org.checkerframework.checker.guieffect.qual", + "org.checkerframework.checker.i18n.qual", + "org.checkerframework.checker.i18nformatter.qual", + "org.checkerframework.checker.index.qual", + "org.checkerframework.checker.initialization.qual", + "org.checkerframework.checker.interning.qual", + "org.checkerframework.checker.lock.qual", + "org.checkerframework.checker.mustcall.qual", + "org.checkerframework.checker.nullness.qual", + "org.checkerframework.checker.optional.qual", + "org.checkerframework.checker.propkey.qual", + "org.checkerframework.checker.regex.qual", + "org.checkerframework.checker.signature.qual", + "org.checkerframework.checker.signedness.qual", + "org.checkerframework.checker.tainting.qual", + "org.checkerframework.checker.units.qual", + "org.checkerframework.common.aliasing.qual", + "org.checkerframework.common.initializedfields.qual", + "org.checkerframework.common.reflection.qual", + "org.checkerframework.common.returnsreceiver.qual", + "org.checkerframework.common.subtyping.qual", + "org.checkerframework.common.util.count.report.qual", + "org.checkerframework.common.value.qual", + "org.checkerframework.dataflow.qual", + "org.checkerframework.framework.qual" + ], + "org.codehaus.mojo:animal-sniffer-annotations": [ + "org.codehaus.mojo.animal_sniffer" + ], + "org.conscrypt:conscrypt-openjdk-uber": [ + "org.conscrypt", + "org.conscrypt.ct", + "org.conscrypt.io" + ], + "org.glassfish.jaxb:jaxb-runtime": [ + "com.sun.xml.bind", + "com.sun.xml.bind.annotation", + "com.sun.xml.bind.api", + "com.sun.xml.bind.api.impl", + "com.sun.xml.bind.marshaller", + "com.sun.xml.bind.unmarshaller", + "com.sun.xml.bind.util", + "com.sun.xml.bind.v2", + "com.sun.xml.bind.v2.bytecode", + "com.sun.xml.bind.v2.model.annotation", + "com.sun.xml.bind.v2.model.core", + "com.sun.xml.bind.v2.model.impl", + "com.sun.xml.bind.v2.model.nav", + "com.sun.xml.bind.v2.model.runtime", + "com.sun.xml.bind.v2.model.util", + "com.sun.xml.bind.v2.runtime", + "com.sun.xml.bind.v2.runtime.output", + "com.sun.xml.bind.v2.runtime.property", + "com.sun.xml.bind.v2.runtime.reflect", + "com.sun.xml.bind.v2.runtime.reflect.opt", + "com.sun.xml.bind.v2.runtime.unmarshaller", + "com.sun.xml.bind.v2.schemagen", + "com.sun.xml.bind.v2.schemagen.episode", + "com.sun.xml.bind.v2.schemagen.xmlschema", + "com.sun.xml.bind.v2.util" + ], + "org.glassfish.jaxb:txw2": [ + "com.sun.xml.txw2", + "com.sun.xml.txw2.annotation", + "com.sun.xml.txw2.output" + ], + "org.hamcrest:hamcrest": [ + "org.hamcrest", + "org.hamcrest.beans", + "org.hamcrest.collection", + "org.hamcrest.comparator", + "org.hamcrest.core", + "org.hamcrest.internal", + "org.hamcrest.io", + "org.hamcrest.number", + "org.hamcrest.object", + "org.hamcrest.text", + "org.hamcrest.xml" + ], + "org.hamcrest:hamcrest-core": [ + "org.hamcrest.core.deprecated" + ], + "org.jdom:jdom2": [ + "org.jdom2", + "org.jdom2.adapters", + "org.jdom2.filter", + "org.jdom2.input", + "org.jdom2.input.sax", + "org.jdom2.input.stax", + "org.jdom2.internal", + "org.jdom2.located", + "org.jdom2.output", + "org.jdom2.output.support", + "org.jdom2.transform", + "org.jdom2.util", + "org.jdom2.xpath", + "org.jdom2.xpath.jaxen", + "org.jdom2.xpath.util" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "kotlin.reflect.full", + "kotlin.reflect.jvm", + "kotlin.reflect.jvm.internal", + "kotlin.reflect.jvm.internal.calls", + "kotlin.reflect.jvm.internal.impl", + "kotlin.reflect.jvm.internal.impl.builtins", + "kotlin.reflect.jvm.internal.impl.builtins.functions", + "kotlin.reflect.jvm.internal.impl.builtins.jvm", + "kotlin.reflect.jvm.internal.impl.descriptors", + "kotlin.reflect.jvm.internal.impl.descriptors.annotations", + "kotlin.reflect.jvm.internal.impl.descriptors.deserialization", + "kotlin.reflect.jvm.internal.impl.descriptors.impl", + "kotlin.reflect.jvm.internal.impl.descriptors.java", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.components", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.structure", + "kotlin.reflect.jvm.internal.impl.incremental", + "kotlin.reflect.jvm.internal.impl.incremental.components", + "kotlin.reflect.jvm.internal.impl.load.java", + "kotlin.reflect.jvm.internal.impl.load.java.components", + "kotlin.reflect.jvm.internal.impl.load.java.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.types", + "kotlin.reflect.jvm.internal.impl.load.java.sources", + "kotlin.reflect.jvm.internal.impl.load.java.structure", + "kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement", + "kotlin.reflect.jvm.internal.impl.load.kotlin", + "kotlin.reflect.jvm.internal.impl.load.kotlin.header", + "kotlin.reflect.jvm.internal.impl.metadata", + "kotlin.reflect.jvm.internal.impl.metadata.builtins", + "kotlin.reflect.jvm.internal.impl.metadata.deserialization", + "kotlin.reflect.jvm.internal.impl.metadata.jvm", + "kotlin.reflect.jvm.internal.impl.metadata.jvm.deserialization", + "kotlin.reflect.jvm.internal.impl.name", + "kotlin.reflect.jvm.internal.impl.platform", + "kotlin.reflect.jvm.internal.impl.protobuf", + "kotlin.reflect.jvm.internal.impl.renderer", + "kotlin.reflect.jvm.internal.impl.resolve", + "kotlin.reflect.jvm.internal.impl.resolve.calls.inference", + "kotlin.reflect.jvm.internal.impl.resolve.constants", + "kotlin.reflect.jvm.internal.impl.resolve.deprecation", + "kotlin.reflect.jvm.internal.impl.resolve.descriptorUtil", + "kotlin.reflect.jvm.internal.impl.resolve.jvm", + "kotlin.reflect.jvm.internal.impl.resolve.sam", + "kotlin.reflect.jvm.internal.impl.resolve.scopes", + "kotlin.reflect.jvm.internal.impl.resolve.scopes.receivers", + "kotlin.reflect.jvm.internal.impl.serialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors", + "kotlin.reflect.jvm.internal.impl.storage", + "kotlin.reflect.jvm.internal.impl.types", + "kotlin.reflect.jvm.internal.impl.types.checker", + "kotlin.reflect.jvm.internal.impl.types.error", + "kotlin.reflect.jvm.internal.impl.types.extensions", + "kotlin.reflect.jvm.internal.impl.types.model", + "kotlin.reflect.jvm.internal.impl.types.typeUtil", + "kotlin.reflect.jvm.internal.impl.types.typesApproximation", + "kotlin.reflect.jvm.internal.impl.util", + "kotlin.reflect.jvm.internal.impl.util.capitalizeDecapitalize", + "kotlin.reflect.jvm.internal.impl.util.collectionUtils", + "kotlin.reflect.jvm.internal.impl.utils", + "kotlin.reflect.jvm.internal.impl.utils.addToStdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "kotlin", + "kotlin.annotation", + "kotlin.collections", + "kotlin.collections.builders", + "kotlin.collections.jdk8", + "kotlin.collections.unsigned", + "kotlin.comparisons", + "kotlin.concurrent", + "kotlin.concurrent.atomics", + "kotlin.concurrent.internal", + "kotlin.contracts", + "kotlin.coroutines", + "kotlin.coroutines.cancellation", + "kotlin.coroutines.intrinsics", + "kotlin.coroutines.jvm.internal", + "kotlin.enums", + "kotlin.experimental", + "kotlin.internal", + "kotlin.internal.jdk7", + "kotlin.internal.jdk8", + "kotlin.io", + "kotlin.io.encoding", + "kotlin.io.path", + "kotlin.jdk7", + "kotlin.js", + "kotlin.jvm", + "kotlin.jvm.functions", + "kotlin.jvm.internal", + "kotlin.jvm.internal.markers", + "kotlin.jvm.internal.unsafe", + "kotlin.jvm.jdk8", + "kotlin.jvm.optionals", + "kotlin.math", + "kotlin.properties", + "kotlin.random", + "kotlin.random.jdk8", + "kotlin.ranges", + "kotlin.reflect", + "kotlin.sequences", + "kotlin.streams.jdk8", + "kotlin.system", + "kotlin.text", + "kotlin.text.jdk8", + "kotlin.time", + "kotlin.time.jdk8", + "kotlin.uuid" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": [ + "_COROUTINE", + "kotlinx.coroutines", + "kotlinx.coroutines.channels", + "kotlinx.coroutines.debug", + "kotlinx.coroutines.debug.internal", + "kotlinx.coroutines.flow", + "kotlinx.coroutines.flow.internal", + "kotlinx.coroutines.future", + "kotlinx.coroutines.internal", + "kotlinx.coroutines.intrinsics", + "kotlinx.coroutines.scheduling", + "kotlinx.coroutines.selects", + "kotlinx.coroutines.stream", + "kotlinx.coroutines.sync", + "kotlinx.coroutines.time" + ], + "org.jetbrains.kotlinx:kotlinx-metadata-jvm": [ + "kotlinx.metadata", + "kotlinx.metadata.internal", + "kotlinx.metadata.internal.common", + "kotlinx.metadata.internal.extensions", + "kotlinx.metadata.internal.metadata", + "kotlinx.metadata.internal.metadata.builtins", + "kotlinx.metadata.internal.metadata.deserialization", + "kotlinx.metadata.internal.metadata.jvm", + "kotlinx.metadata.internal.metadata.jvm.deserialization", + "kotlinx.metadata.internal.metadata.jvm.serialization", + "kotlinx.metadata.internal.metadata.serialization", + "kotlinx.metadata.internal.protobuf", + "kotlinx.metadata.jvm", + "kotlinx.metadata.jvm.internal" + ], + "org.jetbrains:annotations": [ + "org.intellij.lang.annotations", + "org.jetbrains.annotations" + ], + "org.jspecify:jspecify": [ + "org.jspecify.annotations" + ], + "org.jvnet.staxex:stax-ex": [ + "org.jvnet.staxex", + "org.jvnet.staxex.util" + ], + "org.mockito:mockito-core": [ + "org.mockito", + "org.mockito.codegen", + "org.mockito.configuration", + "org.mockito.creation.instance", + "org.mockito.exceptions.base", + "org.mockito.exceptions.misusing", + "org.mockito.exceptions.stacktrace", + "org.mockito.exceptions.verification", + "org.mockito.exceptions.verification.junit", + "org.mockito.exceptions.verification.opentest4j", + "org.mockito.hamcrest", + "org.mockito.internal", + "org.mockito.internal.configuration", + "org.mockito.internal.configuration.injection", + "org.mockito.internal.configuration.injection.filter", + "org.mockito.internal.configuration.injection.scanner", + "org.mockito.internal.configuration.plugins", + "org.mockito.internal.creation", + "org.mockito.internal.creation.bytebuddy", + "org.mockito.internal.creation.instance", + "org.mockito.internal.creation.proxy", + "org.mockito.internal.creation.settings", + "org.mockito.internal.creation.util", + "org.mockito.internal.debugging", + "org.mockito.internal.exceptions", + "org.mockito.internal.exceptions.stacktrace", + "org.mockito.internal.exceptions.util", + "org.mockito.internal.framework", + "org.mockito.internal.hamcrest", + "org.mockito.internal.handler", + "org.mockito.internal.invocation", + "org.mockito.internal.invocation.finder", + "org.mockito.internal.invocation.mockref", + "org.mockito.internal.junit", + "org.mockito.internal.listeners", + "org.mockito.internal.matchers", + "org.mockito.internal.matchers.apachecommons", + "org.mockito.internal.matchers.text", + "org.mockito.internal.progress", + "org.mockito.internal.reporting", + "org.mockito.internal.runners", + "org.mockito.internal.runners.util", + "org.mockito.internal.session", + "org.mockito.internal.stubbing", + "org.mockito.internal.stubbing.answers", + "org.mockito.internal.stubbing.defaultanswers", + "org.mockito.internal.util", + "org.mockito.internal.util.collections", + "org.mockito.internal.util.concurrent", + "org.mockito.internal.util.io", + "org.mockito.internal.util.reflection", + "org.mockito.internal.verification", + "org.mockito.internal.verification.api", + "org.mockito.internal.verification.argumentmatching", + "org.mockito.internal.verification.checkers", + "org.mockito.invocation", + "org.mockito.junit", + "org.mockito.listeners", + "org.mockito.mock", + "org.mockito.plugins", + "org.mockito.quality", + "org.mockito.session", + "org.mockito.stubbing", + "org.mockito.verification" + ], + "org.objenesis:objenesis": [ + "org.objenesis", + "org.objenesis.instantiator", + "org.objenesis.instantiator.android", + "org.objenesis.instantiator.annotations", + "org.objenesis.instantiator.basic", + "org.objenesis.instantiator.gcj", + "org.objenesis.instantiator.perc", + "org.objenesis.instantiator.sun", + "org.objenesis.instantiator.util", + "org.objenesis.strategy" + ], + "org.ow2.asm:asm": [ + "org.objectweb.asm", + "org.objectweb.asm.signature" + ], + "org.ow2.asm:asm-analysis": [ + "org.objectweb.asm.tree.analysis" + ], + "org.ow2.asm:asm-commons": [ + "org.objectweb.asm.commons" + ], + "org.ow2.asm:asm-tree": [ + "org.objectweb.asm.tree" + ], + "org.ow2.asm:asm-util": [ + "org.objectweb.asm.util" + ], + "org.pcollections:pcollections": [ + "org.pcollections" + ], + "org.robolectric:annotations": [ + "org.robolectric.annotation", + "org.robolectric.annotation.experimental", + "org.robolectric.annotation.internal", + "org.robolectric.shadow.api", + "org.robolectric.versioning" + ], + "org.robolectric:junit": [ + "org.robolectric.internal" + ], + "org.robolectric:nativeruntime": [ + "org.robolectric.nativeruntime" + ], + "org.robolectric:pluginapi": [ + "org.robolectric.internal.dependency", + "org.robolectric.pluginapi", + "org.robolectric.pluginapi.config", + "org.robolectric.pluginapi.perf" + ], + "org.robolectric:plugins-maven-dependency-resolver": [ + "org.robolectric", + "org.robolectric.internal.dependency" + ], + "org.robolectric:resources": [ + "org.robolectric", + "org.robolectric.manifest", + "org.robolectric.res", + "org.robolectric.res.android", + "org.robolectric.res.builder" + ], + "org.robolectric:robolectric": [ + "org.robolectric", + "org.robolectric.android", + "org.robolectric.android.internal", + "org.robolectric.internal", + "org.robolectric.internal.dependency", + "org.robolectric.junit.rules", + "org.robolectric.plugins", + "org.robolectric.plugins.config" + ], + "org.robolectric:sandbox": [ + "org.robolectric.config", + "org.robolectric.fakes", + "org.robolectric.interceptors", + "org.robolectric.internal.bytecode", + "org.robolectric.sandbox", + "org.robolectric.util" + ], + "org.robolectric:shadowapi": [ + "org.robolectric.annotation.internal", + "org.robolectric.config", + "org.robolectric.internal", + "org.robolectric.shadow.api", + "org.robolectric.util" + ], + "org.robolectric:shadows-framework": [ + "android.webkit", + "org.robolectric", + "org.robolectric.android", + "org.robolectric.android.controller", + "org.robolectric.android.internal", + "org.robolectric.android.util.concurrent", + "org.robolectric.fakes", + "org.robolectric.shadows", + "org.robolectric.shadows.util" + ], + "org.robolectric:utils": [ + "org.robolectric", + "org.robolectric.util", + "org.robolectric.util.inject" + ], + "org.robolectric:utils-reflector": [ + "org.robolectric.util.reflector" + ], + "org.slf4j:slf4j-api": [ + "org.slf4j", + "org.slf4j.event", + "org.slf4j.helpers", + "org.slf4j.spi" + ], + "org.tensorflow:tensorflow-lite-metadata": [ + "org.tensorflow.lite.schema", + "org.tensorflow.lite.support.metadata", + "org.tensorflow.lite.support.metadata.schema" + ], + "org.xerial:sqlite-jdbc": [ + "org.sqlite", + "org.sqlite.core", + "org.sqlite.date", + "org.sqlite.javax", + "org.sqlite.jdbc3", + "org.sqlite.jdbc4", + "org.sqlite.nativeimage", + "org.sqlite.util" + ], + "org.yaml:snakeyaml": [ + "org.yaml.snakeyaml", + "org.yaml.snakeyaml.comments", + "org.yaml.snakeyaml.composer", + "org.yaml.snakeyaml.constructor", + "org.yaml.snakeyaml.emitter", + "org.yaml.snakeyaml.env", + "org.yaml.snakeyaml.error", + "org.yaml.snakeyaml.events", + "org.yaml.snakeyaml.extensions.compactnotation", + "org.yaml.snakeyaml.external.biz.base64Coder", + "org.yaml.snakeyaml.external.com.google.gdata.util.common.base", + "org.yaml.snakeyaml.inspector", + "org.yaml.snakeyaml.internal", + "org.yaml.snakeyaml.introspector", + "org.yaml.snakeyaml.nodes", + "org.yaml.snakeyaml.parser", + "org.yaml.snakeyaml.reader", + "org.yaml.snakeyaml.representer", + "org.yaml.snakeyaml.resolver", + "org.yaml.snakeyaml.scanner", + "org.yaml.snakeyaml.serializer", + "org.yaml.snakeyaml.tokens", + "org.yaml.snakeyaml.util" + ] + }, + "repositories": { + "https://maven.google.com/": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.annotation:annotation-jvm", + "androidx.concurrent:concurrent-futures", + "androidx.databinding:databinding-common", + "androidx.databinding:databinding-compiler", + "androidx.databinding:databinding-compiler-common", + "androidx.lifecycle:lifecycle-common", + "androidx.privacysandbox.tools:tools", + "androidx.privacysandbox.tools:tools-apigenerator", + "androidx.privacysandbox.tools:tools-apipackager", + "androidx.privacysandbox.tools:tools-core", + "androidx.test.espresso:espresso-idling-resource:aar", + "androidx.test.ext:junit:aar", + "androidx.test.services:storage:aar", + "androidx.test:annotation:aar", + "androidx.test:core:aar", + "androidx.test:monitor:aar", + "androidx.tracing:tracing:aar", + "com.almworks.sqlite4java:sqlite4java", + "com.android.databinding:baseLibrary", + "com.android.tools.adblib:adblib", + "com.android.tools.adblib:adblib-tools", + "com.android.tools.analytics-library:crash", + "com.android.tools.analytics-library:protos", + "com.android.tools.analytics-library:shared", + "com.android.tools.analytics-library:tracker", + "com.android.tools.apkdeployer:apkdeployer", + "com.android.tools.apkparser:binary-resources", + "com.android.tools.build.jetifier:jetifier-core", + "com.android.tools.build.jetifier:jetifier-processor", + "com.android.tools.build:aapt2-proto", + "com.android.tools.build:aaptcompiler", + "com.android.tools.build:apksig", + "com.android.tools.build:apkzlib", + "com.android.tools.build:builder", + "com.android.tools.build:builder-model", + "com.android.tools.build:builder-test-api", + "com.android.tools.build:bundletool", + "com.android.tools.build:gradle", + "com.android.tools.build:gradle-api", + "com.android.tools.build:gradle-settings-api", + "com.android.tools.build:manifest-merger", + "com.android.tools.build:transform-api", + "com.android.tools.ddms:ddmlib", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools.lint:lint-model", + "com.android.tools.lint:lint-typedef-remover", + "com.android.tools.utp:android-device-provider-ddmlib-proto", + "com.android.tools.utp:android-device-provider-gradle-proto", + "com.android.tools.utp:android-device-provider-profile-proto", + "com.android.tools.utp:android-test-plugin-host-additional-test-output-proto", + "com.android.tools.utp:android-test-plugin-host-apk-installer-proto", + "com.android.tools.utp:android-test-plugin-host-coverage-proto", + "com.android.tools.utp:android-test-plugin-host-emulator-control-proto", + "com.android.tools.utp:android-test-plugin-host-logcat-proto", + "com.android.tools.utp:android-test-plugin-host-retention-proto", + "com.android.tools.utp:android-test-plugin-result-listener-gradle-proto", + "com.android.tools:annotations", + "com.android.tools:common", + "com.android.tools:desugar_jdk_libs_configuration", + "com.android.tools:desugar_jdk_libs_configuration_minimal", + "com.android.tools:desugar_jdk_libs_configuration_nio", + "com.android.tools:desugar_jdk_libs_minimal", + "com.android.tools:desugar_jdk_libs_nio", + "com.android.tools:dvlib", + "com.android.tools:r8", + "com.android.tools:repository", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.android:signflinger", + "com.android:zipflinger", + "com.beust:jcommander", + "com.github.ben-manes.caffeine:caffeine", + "com.github.kevinstern:software-and-algorithms", + "com.google.android:annotations", + "com.google.api.grpc:proto-google-common-protos", + "com.google.auto.service:auto-service", + "com.google.auto.service:auto-service-annotations", + "com.google.auto.value:auto-value", + "com.google.auto.value:auto-value-annotations", + "com.google.auto:auto-common", + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.crypto.tink:tink", + "com.google.dagger:dagger", + "com.google.errorprone:error_prone_annotation", + "com.google.errorprone:error_prone_annotations", + "com.google.errorprone:error_prone_check_api", + "com.google.errorprone:error_prone_core", + "com.google.errorprone:error_prone_type_annotations", + "com.google.flatbuffers:flatbuffers-java", + "com.google.flogger:flogger", + "com.google.flogger:flogger-system-backend", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.guava:guava-testlib", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "com.google.jimfs:jimfs", + "com.google.protobuf:protobuf-java", + "com.google.protobuf:protobuf-java-util", + "com.google.testing.compile:compile-testing", + "com.google.testing.platform:core-proto", + "com.google.testparameterinjector:test-parameter-injector", + "com.google.truth.extensions:truth-java8-extension", + "com.google.truth.extensions:truth-liteproto-extension", + "com.google.truth.extensions:truth-proto-extension", + "com.google.truth:truth", + "com.googlecode.juniversalchardet:juniversalchardet", + "com.ibm.icu:icu4j", + "com.squareup:javapoet", + "com.squareup:javawriter", + "com.squareup:kotlinpoet", + "com.sun.activation:javax.activation", + "com.sun.istack:istack-commons-runtime", + "com.sun.xml.fastinfoset:FastInfoset", + "commons-codec:commons-codec", + "commons-io:commons-io", + "commons-logging:commons-logging", + "info.picocli:picocli", + "io.github.eisop:dataflow-errorprone", + "io.github.java-diff-utils:java-diff-utils", + "io.grpc:grpc-api", + "io.grpc:grpc-context", + "io.grpc:grpc-core", + "io.grpc:grpc-netty", + "io.grpc:grpc-protobuf", + "io.grpc:grpc-protobuf-lite", + "io.grpc:grpc-stub", + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-codec-http2", + "io.netty:netty-codec-socks", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-handler-proxy", + "io.netty:netty-resolver", + "io.netty:netty-transport", + "io.netty:netty-transport-native-unix-common", + "io.perfmark:perfmark-api", + "jakarta.activation:jakarta.activation-api", + "jakarta.inject:jakarta.inject-api", + "jakarta.xml.bind:jakarta.xml.bind-api", + "javax.annotation:javax.annotation-api", + "javax.inject:javax.inject", + "junit:junit", + "net.bytebuddy:byte-buddy", + "net.bytebuddy:byte-buddy-agent", + "net.java.dev.jna:jna", + "net.java.dev.jna:jna-platform", + "net.sf.jopt-simple:jopt-simple", + "net.sf.kxml:kxml2", + "org.apache.commons:commons-compress", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.apache.httpcomponents:httpmime", + "org.bitbucket.b_c:jose4j", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on", + "org.checkerframework:checker-compat-qual", + "org.checkerframework:checker-qual", + "org.codehaus.mojo:animal-sniffer-annotations", + "org.conscrypt:conscrypt-openjdk-uber", + "org.glassfish.jaxb:jaxb-runtime", + "org.glassfish.jaxb:txw2", + "org.hamcrest:hamcrest", + "org.hamcrest:hamcrest-core", + "org.jdom:jdom2", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", + "org.jetbrains.kotlinx:kotlinx-metadata-jvm", + "org.jetbrains:annotations", + "org.jspecify:jspecify", + "org.jvnet.staxex:stax-ex", + "org.mockito:mockito-core", + "org.objenesis:objenesis", + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-tree", + "org.ow2.asm:asm-util", + "org.pcollections:pcollections", + "org.robolectric:annotations", + "org.robolectric:junit", + "org.robolectric:nativeruntime", + "org.robolectric:nativeruntime-dist-compat", + "org.robolectric:pluginapi", + "org.robolectric:plugins-maven-dependency-resolver", + "org.robolectric:resources", + "org.robolectric:robolectric", + "org.robolectric:sandbox", + "org.robolectric:shadowapi", + "org.robolectric:shadows-framework", + "org.robolectric:utils", + "org.robolectric:utils-reflector", + "org.slf4j:slf4j-api", + "org.tensorflow:tensorflow-lite-metadata", + "org.xerial:sqlite-jdbc", + "org.yaml:snakeyaml" + ], + "https://repo1.maven.org/maven2/": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.annotation:annotation-jvm", + "androidx.concurrent:concurrent-futures", + "androidx.databinding:databinding-common", + "androidx.databinding:databinding-compiler", + "androidx.databinding:databinding-compiler-common", + "androidx.lifecycle:lifecycle-common", + "androidx.privacysandbox.tools:tools", + "androidx.privacysandbox.tools:tools-apigenerator", + "androidx.privacysandbox.tools:tools-apipackager", + "androidx.privacysandbox.tools:tools-core", + "androidx.test.espresso:espresso-idling-resource:aar", + "androidx.test.ext:junit:aar", + "androidx.test.services:storage:aar", + "androidx.test:annotation:aar", + "androidx.test:core:aar", + "androidx.test:monitor:aar", + "androidx.tracing:tracing:aar", + "com.almworks.sqlite4java:sqlite4java", + "com.android.databinding:baseLibrary", + "com.android.tools.adblib:adblib", + "com.android.tools.adblib:adblib-tools", + "com.android.tools.analytics-library:crash", + "com.android.tools.analytics-library:protos", + "com.android.tools.analytics-library:shared", + "com.android.tools.analytics-library:tracker", + "com.android.tools.apkdeployer:apkdeployer", + "com.android.tools.apkparser:binary-resources", + "com.android.tools.build.jetifier:jetifier-core", + "com.android.tools.build.jetifier:jetifier-processor", + "com.android.tools.build:aapt2-proto", + "com.android.tools.build:aaptcompiler", + "com.android.tools.build:apksig", + "com.android.tools.build:apkzlib", + "com.android.tools.build:builder", + "com.android.tools.build:builder-model", + "com.android.tools.build:builder-test-api", + "com.android.tools.build:bundletool", + "com.android.tools.build:gradle", + "com.android.tools.build:gradle-api", + "com.android.tools.build:gradle-settings-api", + "com.android.tools.build:manifest-merger", + "com.android.tools.build:transform-api", + "com.android.tools.ddms:ddmlib", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools.lint:lint-model", + "com.android.tools.lint:lint-typedef-remover", + "com.android.tools.utp:android-device-provider-ddmlib-proto", + "com.android.tools.utp:android-device-provider-gradle-proto", + "com.android.tools.utp:android-device-provider-profile-proto", + "com.android.tools.utp:android-test-plugin-host-additional-test-output-proto", + "com.android.tools.utp:android-test-plugin-host-apk-installer-proto", + "com.android.tools.utp:android-test-plugin-host-coverage-proto", + "com.android.tools.utp:android-test-plugin-host-emulator-control-proto", + "com.android.tools.utp:android-test-plugin-host-logcat-proto", + "com.android.tools.utp:android-test-plugin-host-retention-proto", + "com.android.tools.utp:android-test-plugin-result-listener-gradle-proto", + "com.android.tools:annotations", + "com.android.tools:common", + "com.android.tools:desugar_jdk_libs_configuration", + "com.android.tools:desugar_jdk_libs_configuration_minimal", + "com.android.tools:desugar_jdk_libs_configuration_nio", + "com.android.tools:desugar_jdk_libs_minimal", + "com.android.tools:desugar_jdk_libs_nio", + "com.android.tools:dvlib", + "com.android.tools:r8", + "com.android.tools:repository", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.android:signflinger", + "com.android:zipflinger", + "com.beust:jcommander", + "com.github.ben-manes.caffeine:caffeine", + "com.github.kevinstern:software-and-algorithms", + "com.google.android:annotations", + "com.google.api.grpc:proto-google-common-protos", + "com.google.auto.service:auto-service", + "com.google.auto.service:auto-service-annotations", + "com.google.auto.value:auto-value", + "com.google.auto.value:auto-value-annotations", + "com.google.auto:auto-common", + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.crypto.tink:tink", + "com.google.dagger:dagger", + "com.google.errorprone:error_prone_annotation", + "com.google.errorprone:error_prone_annotations", + "com.google.errorprone:error_prone_check_api", + "com.google.errorprone:error_prone_core", + "com.google.errorprone:error_prone_type_annotations", + "com.google.flatbuffers:flatbuffers-java", + "com.google.flogger:flogger", + "com.google.flogger:flogger-system-backend", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.guava:guava-testlib", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "com.google.jimfs:jimfs", + "com.google.protobuf:protobuf-java", + "com.google.protobuf:protobuf-java-util", + "com.google.testing.compile:compile-testing", + "com.google.testing.platform:core-proto", + "com.google.testparameterinjector:test-parameter-injector", + "com.google.truth.extensions:truth-java8-extension", + "com.google.truth.extensions:truth-liteproto-extension", + "com.google.truth.extensions:truth-proto-extension", + "com.google.truth:truth", + "com.googlecode.juniversalchardet:juniversalchardet", + "com.ibm.icu:icu4j", + "com.squareup:javapoet", + "com.squareup:javawriter", + "com.squareup:kotlinpoet", + "com.sun.activation:javax.activation", + "com.sun.istack:istack-commons-runtime", + "com.sun.xml.fastinfoset:FastInfoset", + "commons-codec:commons-codec", + "commons-io:commons-io", + "commons-logging:commons-logging", + "info.picocli:picocli", + "io.github.eisop:dataflow-errorprone", + "io.github.java-diff-utils:java-diff-utils", + "io.grpc:grpc-api", + "io.grpc:grpc-context", + "io.grpc:grpc-core", + "io.grpc:grpc-netty", + "io.grpc:grpc-protobuf", + "io.grpc:grpc-protobuf-lite", + "io.grpc:grpc-stub", + "io.netty:netty-buffer", + "io.netty:netty-codec", + "io.netty:netty-codec-http", + "io.netty:netty-codec-http2", + "io.netty:netty-codec-socks", + "io.netty:netty-common", + "io.netty:netty-handler", + "io.netty:netty-handler-proxy", + "io.netty:netty-resolver", + "io.netty:netty-transport", + "io.netty:netty-transport-native-unix-common", + "io.perfmark:perfmark-api", + "jakarta.activation:jakarta.activation-api", + "jakarta.inject:jakarta.inject-api", + "jakarta.xml.bind:jakarta.xml.bind-api", + "javax.annotation:javax.annotation-api", + "javax.inject:javax.inject", + "junit:junit", + "net.bytebuddy:byte-buddy", + "net.bytebuddy:byte-buddy-agent", + "net.java.dev.jna:jna", + "net.java.dev.jna:jna-platform", + "net.sf.jopt-simple:jopt-simple", + "net.sf.kxml:kxml2", + "org.apache.commons:commons-compress", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.apache.httpcomponents:httpmime", + "org.bitbucket.b_c:jose4j", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on", + "org.checkerframework:checker-compat-qual", + "org.checkerframework:checker-qual", + "org.codehaus.mojo:animal-sniffer-annotations", + "org.conscrypt:conscrypt-openjdk-uber", + "org.glassfish.jaxb:jaxb-runtime", + "org.glassfish.jaxb:txw2", + "org.hamcrest:hamcrest", + "org.hamcrest:hamcrest-core", + "org.jdom:jdom2", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", + "org.jetbrains.kotlinx:kotlinx-metadata-jvm", + "org.jetbrains:annotations", + "org.jspecify:jspecify", + "org.jvnet.staxex:stax-ex", + "org.mockito:mockito-core", + "org.objenesis:objenesis", + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-tree", + "org.ow2.asm:asm-util", + "org.pcollections:pcollections", + "org.robolectric:annotations", + "org.robolectric:junit", + "org.robolectric:nativeruntime", + "org.robolectric:nativeruntime-dist-compat", + "org.robolectric:pluginapi", + "org.robolectric:plugins-maven-dependency-resolver", + "org.robolectric:resources", + "org.robolectric:robolectric", + "org.robolectric:sandbox", + "org.robolectric:shadowapi", + "org.robolectric:shadows-framework", + "org.robolectric:utils", + "org.robolectric:utils-reflector", + "org.slf4j:slf4j-api", + "org.tensorflow:tensorflow-lite-metadata", + "org.xerial:sqlite-jdbc", + "org.yaml:snakeyaml" + ] + }, + "services": { + "androidx.databinding:databinding-compiler": { + "javax.annotation.processing.Processor": [ + "android.databinding.annotationprocessor.ProcessDataBinding" + ] + }, + "com.android.tools.build:builder": { + "com.android.tools.r8.internal.OU": [ + "com.android.tools.r8.internal.fK" + ] + }, + "com.android.tools.build:bundletool": { + "com.android.tools.r8.internal.WE": [ + "com.android.tools.r8.internal.cx" + ] + }, + "com.android.tools.build:gradle": { + "com.android.build.api.variant.BuiltArtifactsLoader": [ + "com.android.build.api.variant.impl.BuiltArtifactsLoaderImpl" + ] + }, + "com.android.tools:r8": { + "com.android.tools.r8.internal.lj2": [ + "com.android.tools.r8.internal.gv1" + ] + }, + "com.google.auto.service:auto-service": { + "javax.annotation.processing.Processor": [ + "com.google.auto.service.processor.AutoServiceProcessor" + ] + }, + "com.google.auto.value:auto-value": { + "com.google.auto.value.extension.AutoValueExtension": [ + "com.google.auto.value.extension.memoized.processor.MemoizeExtension", + "com.google.auto.value.extension.serializable.processor.SerializableAutoValueExtension", + "com.google.auto.value.extension.toprettystring.processor.ToPrettyStringExtension" + ], + "com.google.auto.value.extension.serializable.serializer.interfaces.SerializerExtension": [ + "com.google.auto.value.extension.serializable.serializer.impl.ImmutableListSerializerExtension", + "com.google.auto.value.extension.serializable.serializer.impl.ImmutableMapSerializerExtension", + "com.google.auto.value.extension.serializable.serializer.impl.OptionalSerializerExtension" + ], + "javax.annotation.processing.Processor": [ + "com.google.auto.value.extension.memoized.processor.MemoizedValidator", + "com.google.auto.value.extension.toprettystring.processor.ToPrettyStringValidator", + "com.google.auto.value.processor.AutoAnnotationProcessor", + "com.google.auto.value.processor.AutoBuilderProcessor", + "com.google.auto.value.processor.AutoOneOfProcessor", + "com.google.auto.value.processor.AutoValueBuilderProcessor", + "com.google.auto.value.processor.AutoValueProcessor" + ] + }, + "com.google.errorprone:error_prone_core": { + "com.sun.source.util.Plugin": [ + "com.google.errorprone.ErrorProneJavacPlugin" + ] + }, + "com.google.jimfs:jimfs": { + "java.nio.file.spi.FileSystemProvider": [ + "com.google.common.jimfs.SystemJimfsFileSystemProvider" + ] + }, + "io.grpc:grpc-core": { + "io.grpc.LoadBalancerProvider": [ + "io.grpc.internal.PickFirstLoadBalancerProvider", + "io.grpc.util.OutlierDetectionLoadBalancerProvider", + "io.grpc.util.SecretRoundRobinLoadBalancerProvider$Provider" + ], + "io.grpc.NameResolverProvider": [ + "io.grpc.internal.DnsNameResolverProvider" + ] + }, + "io.grpc:grpc-netty": { + "io.grpc.ManagedChannelProvider": [ + "io.grpc.netty.NettyChannelProvider", + "io.grpc.netty.UdsNettyChannelProvider" + ], + "io.grpc.NameResolverProvider": [ + "io.grpc.netty.UdsNameResolverProvider" + ], + "io.grpc.ServerProvider": [ + "io.grpc.netty.NettyServerProvider" + ] + }, + "io.netty:netty-common": { + "reactor.blockhound.integration.BlockHoundIntegration": [ + "io.netty.util.internal.Hidden$NettyBlockHoundIntegration" + ] + }, + "net.sf.kxml:kxml2": { + "org.xmlpull.v1.XmlPullParserFactory": [ + "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer" + ] + }, + "org.bouncycastle:bcprov-jdk18on": { + "java.security.Provider": [ + "org.bouncycastle.jce.provider.BouncyCastleProvider", + "org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider" + ] + }, + "org.glassfish.jaxb:jaxb-runtime": { + "javax.xml.bind.JAXBContext": [ + "com.sun.xml.bind.v2.ContextFactory" + ] + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader": [ + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins.BuiltInsLoaderImpl" + ], + "kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition": [ + "kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.FieldOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.JavaIncompatibilityRulesOverridabilityCondition" + ] + }, + "org.jetbrains.kotlinx:kotlinx-metadata-jvm": { + "kotlinx.metadata.internal.extensions.MetadataExtensions": [ + "kotlinx.metadata.jvm.internal.JvmMetadataExtensions" + ] + }, + "org.robolectric:nativeruntime": { + "org.robolectric.pluginapi.NativeRuntimeLoader": [ + "org.robolectric.nativeruntime.DefaultNativeRuntimeLoader" + ] + }, + "org.robolectric:robolectric": { + "androidx.test.internal.platform.ThreadChecker": [ + "org.robolectric.android.internal.RobolectricThreadChecker" + ], + "androidx.test.internal.platform.app.ActivityInvoker": [ + "org.robolectric.android.internal.LocalActivityInvoker" + ], + "androidx.test.internal.platform.content.PermissionGranter": [ + "org.robolectric.android.internal.LocalPermissionGranter" + ], + "androidx.test.internal.platform.os.ControlledLooper": [ + "org.robolectric.android.internal.LocalControlledLooper" + ], + "androidx.test.platform.ui.UiController": [ + "org.robolectric.android.internal.LocalUiController" + ], + "org.robolectric.internal.dependency.DependencyResolver": [ + "org.robolectric.plugins.LegacyDependencyResolver" + ], + "org.robolectric.pluginapi.SdkPicker": [ + "org.robolectric.plugins.DefaultSdkPicker" + ], + "org.robolectric.pluginapi.SdkProvider": [ + "org.robolectric.plugins.DefaultSdkProvider" + ], + "org.robolectric.pluginapi.config.ConfigurationStrategy": [ + "org.robolectric.plugins.HierarchicalConfigurationStrategy" + ], + "org.robolectric.pluginapi.config.Configurer": [ + "org.robolectric.plugins.ConfigConfigurer", + "org.robolectric.plugins.ConscryptModeConfigurer", + "org.robolectric.plugins.GetInstallerPackageNameModeConfigurer", + "org.robolectric.plugins.GraphicsModeConfigurer", + "org.robolectric.plugins.LazyApplicationConfigurer", + "org.robolectric.plugins.LooperModeConfigurer", + "org.robolectric.plugins.ResourcesModeConfigurer", + "org.robolectric.plugins.SQLiteModeConfigurer", + "org.robolectric.plugins.TextLayoutModeConfigurer" + ], + "org.robolectric.pluginapi.config.GlobalConfigProvider": [ + "org.robolectric.RobolectricTestRunner$DeprecatedTestRunnerDefaultConfigProvider" + ] + }, + "org.robolectric:sandbox": { + "org.robolectric.internal.bytecode.ClassHandler": [ + "org.robolectric.internal.bytecode.ShadowWrangler" + ], + "org.robolectric.internal.bytecode.ClassInstrumentor$Decorator": [ + "org.robolectric.internal.bytecode.ShadowDecorator" + ] + }, + "org.robolectric:shadows-framework": { + "org.robolectric.internal.ShadowProvider": [ + "org.robolectric.Shadows" + ] + }, + "org.xerial:sqlite-jdbc": { + "java.sql.Driver": [ + "org.sqlite.JDBC" + ] + } + }, + "version": "3" +} From f505befc5f786b6177c065f96b70e362808d6472 Mon Sep 17 00:00:00 2001 From: Logan Shire Date: Thu, 25 Jun 2026 16:34:11 -0400 Subject: [PATCH 3/8] Address review feedback 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 --- .bazelci/presubmit.yml | 23 +--- .bazelrc | 18 +-- MODULE.bazel | 58 +-------- doc/standalone_toolchain.md | 22 +--- examples/cross_compilation/BUILD.bazel | 45 ------- examples/cross_compilation/README.md | 68 ++-------- .../Sources/Greeter/Greeter.swift | 14 -- .../Sources/SwiftJNI/SwiftJNI.swift | 24 ---- .../cross_compilation/android_app/BUILD.bazel | 122 ++++++++---------- .../cross_compilation/android_app/README.md | 33 ++--- .../android_app/Sources/Greeter/Greeter.swift | 11 ++ .../Sources/SwiftJNI/SwiftJNI.swift | 16 +++ .../android_app/android.MODULE.bazel | 68 ++++++++++ .../java/com/example/swiftjni/NativeBridge.kt | 5 +- .../rules_android_maven_install.json | 0 swift/extensions.bzl | 25 +--- swift/internal/extensions/swift_sdks.bzl | 38 +++--- swift/internal/extensions/toolchains.bzl | 10 +- swift/toolchains/android_runtime_lib.bzl | 12 +- swift/toolchains/swift_toolchain.bzl | 66 ++++++---- tools/worker/swift_runner.cc | 16 ++- 21 files changed, 272 insertions(+), 422 deletions(-) delete mode 100644 examples/cross_compilation/BUILD.bazel delete mode 100644 examples/cross_compilation/Sources/Greeter/Greeter.swift delete mode 100644 examples/cross_compilation/Sources/SwiftJNI/SwiftJNI.swift create mode 100644 examples/cross_compilation/android_app/Sources/Greeter/Greeter.swift create mode 100644 examples/cross_compilation/android_app/Sources/SwiftJNI/SwiftJNI.swift create mode 100644 examples/cross_compilation/android_app/android.MODULE.bazel rename rules_android_maven_install.json => examples/cross_compilation/android_app/rules_android_maven_install.json (100%) diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 0750bc559..8e5f32e9d 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -26,11 +26,15 @@ x_defaults: build_targets: - "//examples/..." - "-//examples/apple/..." + # The Android APK example is exercised on macOS (see //examples/... + # below); it needs the hermetic Android SDK/NDK and is skipped here. + - "-//examples/cross_compilation/..." test_flags: *linux_flags test_targets: - "//examples/..." - "//test/..." - "-//examples/apple/..." + - "-//examples/cross_compilation/..." # The following tests require Swift >5.8. - "-//test:const_values_empty_const_values_multiple_files" - "-//test:const_values_empty_const_values_single_file" @@ -62,25 +66,6 @@ tasks: bazel: last_green <<: *mac_common - macos_cross_compilation: - name: "Cross-compilation (Android)" - platform: macos_arm64 - xcode_version: "26.2" - bazel: latest - # The //examples/cross_compilation targets are tagged `manual` (they fetch - # the Swift SDK bundle and the NDK), so they are excluded from the - # `//examples/...` wildcard the other tasks build. List them explicitly here - # so the Swift-SDK cross-compilation toolchains are exercised in CI. - # `--config=android_example` supplies the rules_android flags (arm64 - # --android_platforms + a hermetic JDK) the APK needs; it's harmless for the - # bare .so. The build_test asserts the runnable APK (Kotlin -> Swift JNI -> - # Swift library) assembles; runtime behavior is shown by `android_app/`. - build_flags: - - "--config=android_example" - build_targets: - - "//examples/cross_compilation:libSwiftJNI.so" - - "//examples/cross_compilation/android_app:app_build_test" - macos_latest_shell_scripts: name: "macOS shell tests" platform: macos_arm64 diff --git a/.bazelrc b/.bazelrc index f7eaf8327..35388d8b9 100644 --- a/.bazelrc +++ b/.bazelrc @@ -22,22 +22,14 @@ build --worker_sandboxing build --enable_platform_specific_config -# Accept the Android NDK/SDK licenses for hermetic_android_toolchains' @androidndk -# (the Android cc toolchain used by //examples/cross_compilation). Only consulted -# when those repositories are fetched. common --repo_env=ACCEPTED_ANDROID_NDK_LICENSE_VERSION=r27c common --repo_env=ACCEPTED_ANDROID_SDK_LICENSE_VERSION=35 -# Build the runnable APK example (//examples/cross_compilation/android_app) with -# `--config=android_example`. Scoped to a config (not applied globally) so the -# rest of the build is untouched: --android_platforms drives rules_android's -# per-ABI native split (the emulator is arm64), and the hermetic remote JDK runs -# rules_android's Java actions instead of requiring a host JDK. -common:android_example --android_platforms=@rules_android//:arm64-v8a -common:android_example --java_language_version=17 -common:android_example --java_runtime_version=remotejdk_17 -common:android_example --tool_java_language_version=17 -common:android_example --tool_java_runtime_version=remotejdk_17 +common --android_platforms=@rules_android//:arm64-v8a +common --java_language_version=17 +common --java_runtime_version=remotejdk_17 +common --tool_java_language_version=17 +common --tool_java_runtime_version=remotejdk_17 common:linux --repo_env=CC=clang build:linux --cxxopt='-std=c++17' --host_cxxopt='-std=c++17' diff --git a/MODULE.bazel b/MODULE.bazel index 70ecc537e..970a4b845 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -147,65 +147,17 @@ android_ndk.ndk( api_level = 28, version = "r27c", ) -use_repo(android_ndk, "androidndk", "androidsdk") +use_repo(android_ndk, "androidndk") register_toolchains( "@androidndk//:all", dev_dependency = True, ) -# A runnable APK example (//examples/cross_compilation/android_app) that loads -# the Swift JNI .so and shows the Swift greeting on screen. It uses rules_android -# + rules_kotlin — the real-world way Android apps are built. These are all -# dev-only (rules_android pulls in a Maven graph and is heavy), so they never -# affect rules_swift consumers; a consumer brings their own Android rules. -bazel_dep(name = "rules_android", version = "0.7.3", dev_dependency = True) -bazel_dep(name = "rules_java", version = "9.3.0", dev_dependency = True) -bazel_dep(name = "rules_kotlin", version = "2.2.2", dev_dependency = True) -bazel_dep(name = "rules_jvm_external", version = "7.0", dev_dependency = True) - -# rules_java's hermetic JDK + java tools for rules_android's Java actions. -rules_java_toolchains = use_extension( - "@rules_java//java:extensions.bzl", - "toolchains", - dev_dependency = True, -) -use_repo(rules_java_toolchains, "remote_java_tools") - -# rules_android's own Maven dependencies, pinned to a checked-in lock file: -# REPIN=1 bazel run @rules_android_maven//:pin -maven = use_extension( - "@rules_jvm_external//:extensions.bzl", - "maven", - dev_dependency = True, -) -maven.install( - name = "rules_android_maven", - aar_import_bzl_label = "@rules_android//rules:rules.bzl", - artifacts = [], - known_contributing_modules = ["rules_android"], - lock_file = "//:rules_android_maven_install.json", - repositories = [ - "https://maven.google.com", - "https://repo1.maven.org/maven2", - ], - use_starlark_android_rules = True, -) -use_repo(maven, "rules_android_maven") - -# Point rules_android at the hermetic @androidsdk created by the android_ndk.sdk -# tag above (instead of requiring a local $ANDROID_HOME). -rules_android_sdk = use_extension( - "@rules_android//rules/android_sdk_repository:rule.bzl", - "android_sdk_repository_extension", - dev_dependency = True, -) -override_repo(rules_android_sdk, "androidsdk") - -register_toolchains( - "@androidsdk//:all", - dev_dependency = True, -) +# Dev dependencies for the runnable APK example (rules_android + rules_kotlin and +# their Maven graph). Split into its own segment to keep the heavy, example-only +# dependencies out of the root module; it references `android_ndk` defined above. +include("//examples/cross_compilation/android_app:android.MODULE.bazel") # Dev dependencies bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.5.0", dev_dependency = True) diff --git a/doc/standalone_toolchain.md b/doc/standalone_toolchain.md index 61adc1848..cfe873ce0 100644 --- a/doc/standalone_toolchain.md +++ b/doc/standalone_toolchain.md @@ -194,24 +194,14 @@ reason the standalone host toolchains are registered explicitly: rules_swift cannot yet auto-select a distribution, so `:all` would make the host/exec toolchain ambiguous across them. -Then build with a platform carrying the matching constraints: - -```bzl -platform( - name = "android-aarch64", - constraint_values = [ - "@platforms//cpu:aarch64", - "@platforms//os:android", - ], -) -``` +Then build with a platform carrying the matching constraints — for Android, use +the ones `rules_android` already exposes: ```sh -bazel build //my:binary --platforms=//:android-aarch64 +bazel build //my:binary --platforms=@rules_android//:arm64-v8a ``` -See `examples/cross_compilation` for a complete example, including building -through a platform transition. +See `examples/cross_compilation/android_app` for a complete, runnable example. ### JNI shared libraries @@ -245,9 +235,7 @@ Details worth knowing: A common setup cross-compiles to Android *and* builds the same app's Apple targets with `rules_apple`. The two resolve together cleanly: this line of `rules_swift` is `compatibility_level = 3` (the same as released `rules_swift` -3.x), so a current `rules_apple` release works alongside it. Bazel keeps the -higher of each shared transitive dependency (`apple_support`, `rules_cc`), which -are backward compatible, so no extra pinning is required. +3.x), so a current `rules_apple` release works alongside it. ## Using the extension from a non-root module diff --git a/examples/cross_compilation/BUILD.bazel b/examples/cross_compilation/BUILD.bazel deleted file mode 100644 index 59dec2d43..000000000 --- a/examples/cross_compilation/BUILD.bazel +++ /dev/null @@ -1,45 +0,0 @@ -load("//examples/embedded:transition.bzl", "transition_binary") -load("//swift:swift.bzl", "swift_binary", "swift_library") - -package(default_visibility = ["//visibility:public"]) - -# The platform covered by the Android Swift SDK toolchain registered by this -# repository's dev `MODULE.bazel` (via the `swift` extension's `android_sdk` -# tag). Build the targets below with `--platforms` set to this. -platform( - name = "android-aarch64", - constraint_values = [ - "@platforms//cpu:aarch64", - "@platforms//os:android", - ], -) - -# A plain library dependency, compiled for whichever platform depends on it, -# demonstrating that a normal `swift_library` is reused unchanged across targets. -swift_library( - name = "Greeter", - srcs = ["Sources/Greeter/Greeter.swift"], - module_name = "Greeter", - tags = ["manual"], -) - -# --------------------------------------------------------------------------- -# Android: a JNI shared library, loaded by Kotlin via `System.loadLibrary`. -# --------------------------------------------------------------------------- - -# `linkshared` produces `libSwiftJNI.so`. The JNI entry point is written in -# Swift (it `import`s the SDK's `Android` module for the JNI types) and calls -# into the `Greeter` library. See `android_app/` for the APK that loads it. -swift_binary( - name = "SwiftJNI", - srcs = ["Sources/SwiftJNI/SwiftJNI.swift"], - linkshared = True, - tags = ["manual"], - deps = [":Greeter"], -) - -transition_binary( - name = "libSwiftJNI.so", - binary = ":SwiftJNI", - platform = ":android-aarch64", -) diff --git a/examples/cross_compilation/README.md b/examples/cross_compilation/README.md index f181c6619..a666a3cfc 100644 --- a/examples/cross_compilation/README.md +++ b/examples/cross_compilation/README.md @@ -1,62 +1,10 @@ # Cross-compilation example (Android) -Builds plain `swift_library` / `swift_binary` targets for Android using the -Swift SDK toolchain registered by this repository's `MODULE.bazel` (via the -`swift` extension's `android_sdk` tag). See `doc/standalone_toolchain.md` for the -toolchain setup. - -All targets are tagged `manual` because they download the Swift SDK bundle and -require the Android cc toolchain to be registered. - -### The Android C/C++ toolchain - -rules_swift provides only the Swift Android toolchain; C/C++ compilation and -linking (and the NDK sysroot the Swift compiler reads) come from a separately -registered Android cc toolchain. This example uses `@androidndk//:all` from -keith's -[`hermetic_android_toolchains`](https://github.com/keith/hermetic_android_toolchains), -wired in this repository's `MODULE.bazel`: - -```starlark -android = use_extension("@hermetic_android_toolchains//:extensions.bzl", "android") -android.sdk(version = "35", build_tools_version = "35.0.0") -android.ndk(version = "r27c", api_level = 28) -use_repo(android, "androidndk") -register_toolchains("@androidndk//:all") -``` - -Any rules_android_ndk-based Android cc toolchain works the same way. To package -the NDK's `libc++_shared.so` into an APK, use the `select_android_runtime_lib` -rule from `@rules_swift//swift/toolchains:android_runtime_lib.bzl` (it reads the -resolved cc toolchain); see `android_app/README.md`. - -## Targets - -| Target | Output | Demonstrates | -|---|---|---| -| `:Greeter` | `.swiftmodule` + `.a` | A normal `swift_library` reused across targets | -| `:libSwiftJNI.so` | `libSwiftJNI.so` | An Android **JNI shared library** (`swift_binary(linkshared)`) that calls `:Greeter` | - -```sh -# Android JNI shared library: -bazel build //examples/cross_compilation:libSwiftJNI.so -``` - -`:libSwiftJNI.so` builds `:SwiftJNI` under the `:android-aarch64` platform; you -can equivalently pass `--platforms=//examples/cross_compilation:android-aarch64` -on the command line. - -## Android app - -`android_app/` is a complete, runnable APK that loads `libSwiftJNI.so`, calls -into it, and shows the Swift greeting on screen — completing the -Kotlin → Swift (JNI `.so`) → Swift library chain: - -```sh -bazel build --config=android_example \ - //examples/cross_compilation/android_app:app -``` - -It's packaged with `rules_android` + `rules_kotlin` (dev-only dependencies of -`rules_swift`) and the hermetic `@androidsdk` (no local SDK needed). See -`android_app/README.md`. +A complete, runnable Android app that cross-compiles Swift to Android and runs it +through the JNI, built with the Swift SDK toolchain registered by this +repository's `MODULE.bazel` (via the `swift` extension's `android_sdk` tag). See +`doc/standalone_toolchain.md` for the toolchain setup. + +Everything lives in [`android_app/`](android_app) — the Swift sources, the Kotlin +app, and the `BUILD.bazel` that packages them into an APK with `rules_android` + +`rules_kotlin`. See [`android_app/README.md`](android_app/README.md). diff --git a/examples/cross_compilation/Sources/Greeter/Greeter.swift b/examples/cross_compilation/Sources/Greeter/Greeter.swift deleted file mode 100644 index 7c065196a..000000000 --- a/examples/cross_compilation/Sources/Greeter/Greeter.swift +++ /dev/null @@ -1,14 +0,0 @@ -/// A plain `swift_library` used as a normal dependency of the Android JNI -/// entry point. Nothing in here is platform-specific; it is compiled for -/// whichever platform the depending target is built for. -public struct Greeter { - private let subject: String - - public init(subject: String) { - self.subject = subject - } - - public func greeting() -> String { - return "Hello from Swift, \(subject)!" - } -} diff --git a/examples/cross_compilation/Sources/SwiftJNI/SwiftJNI.swift b/examples/cross_compilation/Sources/SwiftJNI/SwiftJNI.swift deleted file mode 100644 index 4b3336bd5..000000000 --- a/examples/cross_compilation/Sources/SwiftJNI/SwiftJNI.swift +++ /dev/null @@ -1,24 +0,0 @@ -import Android -import Greeter - -// The JNI entry point, written entirely in Swift. `import Android` provides the -// JNI types (`JNIEnv`, `jclass`, `jstring`, ...) from the Android Swift SDK, so -// no C shim is needed. `@_cdecl` gives the function the exact symbol name JNI -// looks up: `Java___`, with `.`/`_` escaped per the JNI -// spec. It is the Kotlin-callable native implementation of: -// -// package com.example.swiftjni -// class NativeBridge { external fun greetingFromSwift(): String } -// -// and it delegates to the `Greeter` `swift_library` (a normal dependency), -// completing the Kotlin -> Swift (JNI .so) -> Swift library call chain. -@_cdecl("Java_com_example_swiftjni_NativeBridge_greetingFromSwift") -public func greetingFromSwift( - _ env: UnsafeMutablePointer, - _ clazz: jclass -) -> jstring? { - let message = Greeter(subject: "Android").greeting() - return message.withCString { cString in - env.pointee!.pointee.NewStringUTF(env, cString) - } -} diff --git a/examples/cross_compilation/android_app/BUILD.bazel b/examples/cross_compilation/android_app/BUILD.bazel index 4495b86f2..7077dfe35 100644 --- a/examples/cross_compilation/android_app/BUILD.bazel +++ b/examples/cross_compilation/android_app/BUILD.bazel @@ -1,64 +1,31 @@ -# A runnable Android APK that loads the Swift JNI .so and shows the Swift -# greeting on screen, completing the Kotlin -> Swift -> Swift call chain end to -# end. It is built with rules_android + rules_kotlin (the real-world way Android -# apps are packaged); those are dev-only dependencies of rules_swift (see the -# root MODULE.bazel), so consumers of rules_swift are unaffected. +# A runnable Android app that runs Swift code through the JNI. # -# Build/run (the flags come from `--config=android_example` in //.bazelrc): +# bazel build //examples/cross_compilation/android_app:app +# adb install -r bazel-bin/examples/cross_compilation/android_app/app.apk +# adb shell am start -n com.example.swiftjni/.MainActivity # -# bazel build --config=android_example \ -# //examples/cross_compilation/android_app:app -# -# Everything here is tagged `manual` (like the rest of //examples/cross_compilation, -# which fetches the Swift SDK bundle + the NDK) so it stays out of the -# `//examples/...` wildcard the other CI tasks build. +# The call chain: MainActivity.kt -> NativeBridge.greetingFromSwift() (Kotlin, +# JNI) -> libSwiftJNI.so (swift_binary, @_cdecl) -> Greeter (swift_library). load("@bazel_skylib//rules:build_test.bzl", "build_test") load("@rules_android//rules:rules.bzl", "android_binary") load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") -load("//examples/embedded:transition.bzl", "transition_binary") +load("//swift:swift.bzl", "swift_binary", "swift_library") load("//swift/toolchains:android_runtime_lib.bzl", "select_android_runtime_lib") -package(default_visibility = ["//visibility:private"]) - -# The NDK's shared C++ runtime, selected from the resolved Android cc toolchain -# (`@androidndk//:all`) and built for arm64 so it bundles into the APK alongside -# the Swift .so. (The NDK clang links libc++ dynamically, so the app must ship -# it; rules_swift's `select_android_runtime_lib` locates it in the cc toolchain.) -select_android_runtime_lib( - name = "libcxx_shared_lib", - tags = ["manual"], - triple = "aarch64-linux-android", -) - -transition_binary( - name = "libcxx_shared", - binary = ":libcxx_shared_lib", - platform = "//examples/cross_compilation:android-aarch64", - tags = ["manual"], -) - -# Wrap the prebuilt Swift JNI .so and libc++_shared.so as cc_libraries. A -# prebuilt .so in a cc_library's srcs becomes a CcInfo dynamic library, which -# `android_binary`'s per-ABI native split collects and packages under -# lib/arm64-v8a/. (`swift_binary(linkshared)` exposes its .so via DefaultInfo, -# not CcInfo, and `cc_import` isn't an allowed `android_binary.deps` rule, so the -# cc_library wrapper is the way in. The transitions keep the .so arm64 regardless -# of the split's configuration.) -cc_library( - name = "swift_jni_so", - srcs = ["//examples/cross_compilation:libSwiftJNI.so"], - tags = ["manual"], -) +package(default_visibility = ["//visibility:public"]) -cc_library( - name = "libcxx_so", - srcs = [":libcxx_shared"], - tags = ["manual"], +android_binary( + name = "app", + manifest = "AndroidManifest.xml", + deps = [ + ":app_lib", + ":libcxx", + ":swift_jni", + ], ) -# The Kotlin host: MainActivity displays NativeBridge.greetingFromSwift(). kt_android_library( name = "app_lib", srcs = [ @@ -67,25 +34,50 @@ kt_android_library( ], custom_package = "com.example.swiftjni", manifest = "AndroidManifest.xml", - tags = ["manual"], ) -# The assembled + signed APK. The two cc_library deps carry the native .so files. -android_binary( - name = "app", - manifest = "AndroidManifest.xml", - tags = ["manual"], - deps = [ - ":app_lib", - ":libcxx_so", - ":swift_jni_so", - ], -) - -# CI build coverage: asserts the APK assembles (exercises the full -# Swift .so -> rules_android packaging path). build_test( name = "app_build_test", - tags = ["manual"], targets = [":app"], ) + +# The Swift JNI library and the NDK C++ runtime it loads, packaged into the APK +# by android_binary's per-ABI native split. A prebuilt .so in a cc_library's +# srcs becomes the CcInfo dynamic library the split collects. These only build +# for Android (the split configures them from --android_platforms), so the +# //examples/... wildcard skips them on a non-Android host. +cc_library( + name = "swift_jni", + srcs = [":SwiftJNI"], + target_compatible_with = ["@platforms//os:android"], +) + +cc_library( + name = "libcxx", + srcs = [":libcxx_shared"], + target_compatible_with = ["@platforms//os:android"], +) + +select_android_runtime_lib( + name = "libcxx_shared", + target_compatible_with = ["@platforms//os:android"], + triple = "aarch64-linux-android", +) + +# `linkshared` produces `libSwiftJNI.so`. The JNI entry point is written in +# Swift (it `import`s the SDK's `Android` module for the JNI types) and calls +# into the `Greeter` library. +swift_binary( + name = "SwiftJNI", + srcs = ["Sources/SwiftJNI/SwiftJNI.swift"], + linkshared = True, + target_compatible_with = ["@platforms//os:android"], + deps = [":Greeter"], +) + +# A plain library dependency, compiled for whichever platform depends on it. +swift_library( + name = "Greeter", + srcs = ["Sources/Greeter/Greeter.swift"], + module_name = "Greeter", +) diff --git a/examples/cross_compilation/android_app/README.md b/examples/cross_compilation/android_app/README.md index 741d47a96..60b69e6e9 100644 --- a/examples/cross_compilation/android_app/README.md +++ b/examples/cross_compilation/android_app/README.md @@ -1,35 +1,31 @@ # Android app: Kotlin → Swift JNI `.so` → Swift library A complete, runnable Android app that shows the greeting computed by Swift, -reached over JNI — the application half of the Kotlin → Swift → Swift call chain -that `rules_swift` enables: +reached over JNI: ``` MainActivity.kt ──► NativeBridge.greetingFromSwift() (Kotlin) │ JNI (System.loadLibrary("SwiftJNI")) ▼ - //examples/cross_compilation:SwiftJNI → libSwiftJNI.so (swift_binary, linkshared) - @_cdecl("Java_..._greetingFromSwift") in SwiftJNI.swift (Swift) + :SwiftJNI → libSwiftJNI.so (swift_binary, linkshared) + @_cdecl("Java_..._greetingFromSwift") in Sources/SwiftJNI/SwiftJNI.swift │ ▼ - //examples/cross_compilation:Greeter (swift_library) + :Greeter (swift_library) ``` ## Build & run ```sh -# Build the APK (the flags live in //.bazelrc as `--config=android_example`): -bazel build --config=android_example \ - //examples/cross_compilation/android_app:app - -# Install on a connected device/emulator and launch: +bazel build //examples/cross_compilation/android_app:app adb install -r bazel-bin/examples/cross_compilation/android_app/app.apk adb shell am start -n com.example.swiftjni/.MainActivity ``` The screen shows **“Hello from Swift, Android!”** — computed by the `Greeter` `swift_library`, returned through the `@_cdecl` JNI entry point in -`libSwiftJNI.so`, and displayed by Kotlin. +`libSwiftJNI.so`, and displayed by Kotlin. (`//.bazelrc` sets +`--android_platforms=@rules_android//:arm64-v8a` and a hermetic JDK.) ## How it's wired (`BUILD.bazel`) @@ -41,19 +37,18 @@ rules_swift-specific detail is getting the prebuilt Swift `.so` into the APK: `CcInfo`, so it can't go straight into `android_binary.deps`. Wrapping it in a `cc_library` (a prebuilt `.so` in `srcs` becomes a `CcInfo` dynamic library) lets `android_binary`'s per-ABI native split collect it into `lib/arm64-v8a/`. -- `libc++_shared.so` (the NDK's C++ runtime, which the NDK clang links + The split configures the wrapped `swift_binary` for Android, so no explicit + platform transition is needed. +- `libc++_shared.so` (the NDK's C++ runtime, which the Swift SDK links dynamically) is selected from the resolved Android cc toolchain by rules_swift's `select_android_runtime_lib` and packaged the same way. -The example targets arm64 (`--android_platforms=@rules_android//:arm64-v8a`); -build the `.so` for another ABI and add a matching `cc_library` to support more. - ## Dev dependencies `rules_android` + `rules_kotlin` (and their Maven graph) are **dev-only** -dependencies of `rules_swift` — see the root `MODULE.bazel` (all -`dev_dependency = True`) and the pinned `//:rules_android_maven_install.json`. -They never reach consumers of `rules_swift`; a consumer brings their own Android -rules. The Android SDK is the hermetic `@androidsdk` from +dependencies of `rules_swift`, kept in [`android.MODULE.bazel`](android.MODULE.bazel) +(`include()`d from the root `MODULE.bazel`) with a pinned Maven lock. They never +reach consumers of `rules_swift`; a consumer brings their own Android rules. The +Android SDK is the hermetic `@androidsdk` from [`hermetic_android_toolchains`](https://github.com/keith/hermetic_android_toolchains) (no local `$ANDROID_HOME` required). diff --git a/examples/cross_compilation/android_app/Sources/Greeter/Greeter.swift b/examples/cross_compilation/android_app/Sources/Greeter/Greeter.swift new file mode 100644 index 000000000..349660d4b --- /dev/null +++ b/examples/cross_compilation/android_app/Sources/Greeter/Greeter.swift @@ -0,0 +1,11 @@ +public struct Greeter { + private let subject: String + + public init(subject: String) { + self.subject = subject + } + + public func greeting() -> String { + return "Hello from Swift, \(subject)!" + } +} diff --git a/examples/cross_compilation/android_app/Sources/SwiftJNI/SwiftJNI.swift b/examples/cross_compilation/android_app/Sources/SwiftJNI/SwiftJNI.swift new file mode 100644 index 000000000..031f06e87 --- /dev/null +++ b/examples/cross_compilation/android_app/Sources/SwiftJNI/SwiftJNI.swift @@ -0,0 +1,16 @@ +import Android +import Greeter + +// The JNI entry point, written entirely in Swift: `import Android` provides the +// JNI types, and `@_cdecl` gives the function the `Java___` +// symbol name that `NativeBridge.greetingFromSwift()` binds to. +@_cdecl("Java_com_example_swiftjni_NativeBridge_greetingFromSwift") +public func greetingFromSwift( + _ env: UnsafeMutablePointer, + _ clazz: jclass +) -> jstring? { + let message = Greeter(subject: "Android").greeting() + return message.withCString { cString in + env.pointee!.pointee.NewStringUTF(env, cString) + } +} diff --git a/examples/cross_compilation/android_app/android.MODULE.bazel b/examples/cross_compilation/android_app/android.MODULE.bazel new file mode 100644 index 000000000..a860cb7ea --- /dev/null +++ b/examples/cross_compilation/android_app/android.MODULE.bazel @@ -0,0 +1,68 @@ +# Dev dependencies for the runnable APK example (//examples/cross_compilation/ +# android_app), included from the root MODULE.bazel. rules_android + rules_kotlin +# package the APK the real-world way; they pull in a Maven graph and are heavy, +# so they're kept out of the root module and are all dev_dependency. Consumers of +# rules_swift never see them; a consumer brings their own Android rules. +# +# `android_ndk` (the hermetic_android_toolchains extension) and `@androidndk` are +# defined in the root module above this include(). + +bazel_dep(name = "rules_android", version = "0.7.3", dev_dependency = True) +bazel_dep(name = "rules_java", version = "9.3.0", dev_dependency = True) +bazel_dep(name = "rules_kotlin", version = "2.2.2", dev_dependency = True) +bazel_dep(name = "rules_jvm_external", version = "7.0", dev_dependency = True) + +# rules_java's hermetic JDK + java tools for rules_android's Java actions. +rules_java_toolchains = use_extension( + "@rules_java//java:extensions.bzl", + "toolchains", + dev_dependency = True, +) +use_repo(rules_java_toolchains, "remote_java_tools") + +# rules_android's own Maven dependencies, pinned to a checked-in lock file: +# REPIN=1 bazel run @rules_android_maven//:pin +# rules_android requiring a consumer-side maven.install is a known wart; see +# https://github.com/bazelbuild/rules_android/issues/485. +maven = use_extension( + "@rules_jvm_external//:extensions.bzl", + "maven", + dev_dependency = True, +) +maven.install( + name = "rules_android_maven", + aar_import_bzl_label = "@rules_android//rules:rules.bzl", + artifacts = [], + known_contributing_modules = ["rules_android"], + lock_file = "//examples/cross_compilation/android_app:rules_android_maven_install.json", + repositories = [ + "https://maven.google.com", + "https://repo1.maven.org/maven2", + ], + use_starlark_android_rules = True, +) +use_repo(maven, "rules_android_maven") + +# Point rules_android at the hermetic @androidsdk created by the android_ndk.sdk +# tag in the root module (instead of requiring a local $ANDROID_HOME). The +# extension proxy is re-declared here because include() segments don't share +# names with the root module; this resolves to the same extension usage. +android_ndk = use_extension( + "@hermetic_android_toolchains//:extensions.bzl", + "android", + dev_dependency = True, +) +use_repo(android_ndk, "androidsdk") + +rules_android_sdk = use_extension( + "@rules_android//rules/android_sdk_repository:rule.bzl", + "android_sdk_repository_extension", + dev_dependency = True, +) + +override_repo(rules_android_sdk, "androidsdk") + +register_toolchains( + "@androidsdk//:all", + dev_dependency = True, +) diff --git a/examples/cross_compilation/android_app/java/com/example/swiftjni/NativeBridge.kt b/examples/cross_compilation/android_app/java/com/example/swiftjni/NativeBridge.kt index 62c59afa0..3aecc6a4f 100644 --- a/examples/cross_compilation/android_app/java/com/example/swiftjni/NativeBridge.kt +++ b/examples/cross_compilation/android_app/java/com/example/swiftjni/NativeBridge.kt @@ -1,9 +1,8 @@ package com.example.swiftjni /** - * Loads the Swift JNI shared library (`libSwiftJNI.so`, built by the - * `//examples/cross_compilation:SwiftJNI` `swift_binary(linkshared = True)`) - * and exposes its Swift entry point to Kotlin. + * Loads the Swift JNI shared library (`libSwiftJNI.so`, built by the `:SwiftJNI` + * `swift_binary(linkshared = True)`) and exposes its Swift entry point to Kotlin. * * The native method binds by name to the Swift `@_cdecl` function * `Java_com_example_swiftjni_NativeBridge_greetingFromSwift`, which in turn diff --git a/rules_android_maven_install.json b/examples/cross_compilation/android_app/rules_android_maven_install.json similarity index 100% rename from rules_android_maven_install.json rename to examples/cross_compilation/android_app/rules_android_maven_install.json diff --git a/swift/extensions.bzl b/swift/extensions.bzl index 738a6218d..409cf7b72 100644 --- a/swift/extensions.bzl +++ b/swift/extensions.bzl @@ -73,16 +73,12 @@ def _setup_android_sdk(*, tag, toolchain_name, swift_version, platforms): )) sha256 = SWIFT_SDK_RELEASES[swift_version]["android"] - # The Swift Android toolchain compiles and links C/C++ through a separately - # registered Android C++ cc toolchain (e.g. `@androidndk//:all` from - # `hermetic_android_toolchains`) and reads that toolchain's sysroot at - # analysis time, so rules_swift does not fetch or manage the NDK itself. build_file_content = "" for platform in platforms: repository_name = "{}_android_sdk_{}".format(toolchain_name, platform) swift_android_sdk_repository( name = repository_name, - host_swiftc = "@{}_{}//:usr/bin/swiftc".format(toolchain_name, platform), + paired_swiftc = "@{}_{}//:usr/bin/swiftc".format(toolchain_name, platform), sha256 = sha256, swift_version = swift_version, toolchain_repo = "{}_{}".format(toolchain_name, platform), @@ -202,24 +198,7 @@ versions known to this version of rules_swift. }, doc = """\ Downloads the Android Swift SDK matching a `toolchain` tag's Swift version and -defines Swift toolchains targeting `aarch64-unknown-linux-android` and -`x86_64-unknown-linux-android`. - -C/C++ compilation and linking for those targets go through a separately -registered Android C++ cc toolchain, which also provides the sysroot the Swift -compiler reads. Register one alongside the Swift toolchains -- for example -`@androidndk//:all` from -[hermetic_android_toolchains](https://github.com/keith/hermetic_android_toolchains): - -```starlark -register_toolchains( - "@swift_toolchain//:swift_toolchain_android_aarch64_xcode", - "@androidndk//:all", -) -``` - -and build with a platform that has the `@platforms//os:android` and -`@platforms//cpu:aarch64` (or `x86_64`) constraints. +defines Swift toolchains targeting Android. """, ) diff --git a/swift/internal/extensions/swift_sdks.bzl b/swift/internal/extensions/swift_sdks.bzl index 41b14b315..8a53009fa 100644 --- a/swift/internal/extensions/swift_sdks.bzl +++ b/swift/internal/extensions/swift_sdks.bzl @@ -154,8 +154,8 @@ def _swift_android_sdk_impl(repository_ctx): # The Android Swift SDK's resource directories do not bundle clang's # builtin headers, so the clang importer must be pointed at the host # toolchain's copy (which matches the clang embedded in swiftc). - host_usr = repository_ctx.path(repository_ctx.attr.host_swiftc).dirname.dirname - clang_versions = host_usr.get_child("lib", "clang").readdir() + paired_usr = repository_ctx.path(repository_ctx.attr.paired_swiftc).dirname.dirname + clang_versions = paired_usr.get_child("lib", "clang").readdir() if len(clang_versions) != 1: fail("Expected exactly one clang version directory in the host " + "toolchain, found: " + str(clang_versions)) @@ -188,27 +188,22 @@ def _swift_android_sdk_impl(repository_ctx): "swift.module_map_no_private_headers", "swift.use_autolink_extract", "swift.use_module_wrap", - # The file prefix map would make the worker resolve the Xcode - # developer directory on macOS hosts, which this toolchain - # does not depend on. - "-swift.file_prefix_map", ]), linker_inputs = _build_list([":sdk_files"]), - # The runtime objects and libraries that `swiftc` adds when - # statically linking the stdlib for Android; see - # `swift_static-{arch}/android/static-stdlib-args.lnk` in the SDK. - # The 16 KiB max page size is required by Android 15+. We omit that - # file's `-Wl,--exclude-libs,ALL`: under Bazel a `swift_binary`'s - # `swift_library` deps are static archives, so it would demote their - # exported symbols (e.g. `@_cdecl("Java_…")` JNI entry points) to - # local and `System.loadLibrary` could not bind them. Pass a linker - # version script to hide the runtime symbols if desired. + # The Swift runtime objects/libraries from the SDK's + # `swift_static-{arch}/android/static-stdlib-args.lnk`. We drop that + # file's `-Wl,--exclude-libs,ALL` (it would demote a depended-on + # `swift_library`'s `@_cdecl` JNI exports to local) and add the 16 KiB + # max page size required by Android 15+. linkopts = _build_list([ "{}/android/{}/swiftrt.o".format(resource_dir, arch), "-L{}/android".format(resource_dir), "-ldl", "-llog", - "-lm", + # libc++ as the shared `libc++_shared.so` (the SDK's intended + # linkage; dropping this statically links libc++ instead, which + # the NDK discourages for a JNI library). It must be packaged + # into the APK; see `select_android_runtime_lib`. "-lstdc++", "-Wl,-z,max-page-size=16384", ]), @@ -224,20 +219,17 @@ def _swift_android_sdk_impl(repository_ctx): swift_android_sdk_repository = repository_rule( attrs = _common_attrs() | { - "host_swiftc": attr.label( + "paired_swiftc": attr.label( doc = """\ -The host toolchain's `swiftc`, used to locate the clang builtin headers that -match the clang embedded in the Swift compiler. +The `swiftc` of the standalone toolchain this SDK is paired with, used to locate +the clang builtin headers that match the clang embedded in the Swift compiler. """, mandatory = True, ), }, doc = """\ Downloads the Android Swift SDK artifact bundle and defines Swift toolchains that -target `{aarch64,x86_64}-unknown-linux-android`. C/C++ compilation and linking go -through a separately-registered Android C++ cc toolchain (e.g. `@androidndk//:all` -from `hermetic_android_toolchains`); the Swift toolchain reads that toolchain's -sysroot at analysis time. +target Android. """, implementation = _swift_android_sdk_impl, ) diff --git a/swift/internal/extensions/toolchains.bzl b/swift/internal/extensions/toolchains.bzl index f83e1387b..c520f1942 100644 --- a/swift/internal/extensions/toolchains.bzl +++ b/swift/internal/extensions/toolchains.bzl @@ -43,8 +43,6 @@ toolchain( """ -# Just the Swift toolchain: Android's C/C++ toolchain is registered separately -# (e.g. `@androidndk//:all`). _SDK_TOOLCHAIN_PLATFORM = """ # Swift SDK toolchain from repository: `{sdk_repository}` toolchain( @@ -78,16 +76,12 @@ def toolchains_for_platform(platform, toolchain_repository): def android_sdk_toolchains_for_platform(platform, sdk_repository, archs): """Returns Swift `toolchain` declarations for an Android Swift SDK. - Only the Swift toolchain is declared; C/C++ compilation and linking for - Android targets use a separately registered cc toolchain (e.g. - `@androidndk//:all`). - Args: - platform: The host platform name (e.g. "xcode" or "ubuntu22.04") whose + platform: The platform name (e.g. "xcode" or "ubuntu22.04") whose standalone toolchain the SDK is paired with. sdk_repository: The name of the repository created by `swift_android_sdk_repository`. - archs: The Android architectures ("aarch64", "x86_64") to declare + archs: The Android architectures (e.g. aarch64) to declare toolchains for. Returns: diff --git a/swift/toolchains/android_runtime_lib.bzl b/swift/toolchains/android_runtime_lib.bzl index 9cc05626f..ca5161e88 100644 --- a/swift/toolchains/android_runtime_lib.bzl +++ b/swift/toolchains/android_runtime_lib.bzl @@ -1,11 +1,11 @@ """A rule that selects a single Android NDK runtime library from the toolchain. -The Android NDK's shared C++ runtime (`libc++_shared.so`) must be packaged into -any APK that contains Swift (or other NDK C++) code. This rule selects it out of -the resolved C++ (cc) toolchain's files, so a consumer can reference it for APK -packaging without naming the NDK repository or build host. Build it for an -Android platform so the Android cc toolchain (e.g. `@androidndk//:all`) is -resolved. +The Swift Android SDK links the NDK's C++ runtime dynamically, so any APK with a +Swift JNI library must also package `libc++_shared.so` (unlike normal NDK C++, +which can statically link libc++). This rule selects it out of the resolved C++ +(cc) toolchain's files, so a consumer can reference it for APK packaging without +naming the NDK repository or build host. Build it for an Android platform so the +Android cc toolchain (e.g. `@androidndk//:all`) is resolved. """ load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") diff --git a/swift/toolchains/swift_toolchain.bzl b/swift/toolchains/swift_toolchain.bzl index 6ef716050..f2a83765b 100644 --- a/swift/toolchains/swift_toolchain.bzl +++ b/swift/toolchains/swift_toolchain.bzl @@ -474,6 +474,35 @@ def _swift_sdk_linkopts_cc_info( ), ) +def _swift_android_linkopts_cc_info(ctx, cc_toolchain, sdkroot): + """Returns a `CcInfo` with the Android Swift runtime link flags. + + The binary link runs through `cc_common.link` with the resolved Android cc + toolchain, but rules_android_ndk's toolchain reports its sysroot as the clang + directory and exposes an empty `dynamic_runtime_lib`, so the real sysroot is + never passed and `libc++_shared.so` (which the NDK clang links by default) is + never staged. Add both ourselves, on top of the SDK's `linkopts`/`linker_inputs`. + + Args: + ctx: The toolchain rule context. + cc_toolchain: The resolved Android C++ `CcToolchainInfo`. + sdkroot: The Android sysroot derived from the cc toolchain. + + Returns: + A `CcInfo` propagating the Android runtime link flags and inputs. + """ + linkopts = list(ctx.attr.linkopts) + linker_inputs = list(ctx.files.linker_inputs) + if sdkroot: + linkopts.append("--sysroot=" + sdkroot) + libcxx_suffix = "/usr/lib/{}-linux-android/libc++_shared.so".format(ctx.attr.arch) + linker_inputs = linker_inputs + [ + f + for f in cc_toolchain.all_files.to_list() + if f.path.endswith(libcxx_suffix) + ] + return _swift_sdk_linkopts_cc_info(ctx.label, linkopts, linker_inputs) + def _entry_point_linkopts_provider(*, entry_point_name): """Returns linkopts to customize the entry point of a binary.""" return struct( @@ -520,11 +549,8 @@ def _swift_toolchain_impl(ctx): target_triples.parse(ctx.var.get("CC_TARGET_TRIPLE") or target_system_name), ) - # Swift can only link through an LLVM/clang cc toolchain, not gcc. Accept any - # toolchain whose compiler identifies as clang or LLVM (e.g. the Android NDK's - # `@androidndk//:all` reports `llvm-c++`). if "clang" not in cc_toolchain.compiler and "llvm" not in cc_toolchain.compiler: - fail("Swift requires the configured CC toolchain use clang/LLVM. " + + fail("Swift requires the configured CC toolchain use clang. " + "Either use the locally installed LLVM by setting `CC=clang` in your environment " + "before invoking Bazel, or configure a Bazel LLVM CC toolchain. " + "The current CC toolchain is configured to use '{}'.".format(cc_toolchain.compiler)) @@ -562,33 +588,21 @@ def _swift_toolchain_impl(ctx): ) elif ctx.attr.os == "none": swift_linkopts_cc_info = CcInfo() + elif ctx.attr.os == "android": + swift_linkopts_cc_info = _swift_android_linkopts_cc_info(ctx, cc_toolchain, sdkroot) elif ctx.attr.linkopts or ctx.attr.linker_inputs: # A toolchain whose Swift runtime comes from a Swift SDK (e.g. - # WebAssembly or Android) provides the *complete* set of runtime link - # flags via `linkopts`/`linker_inputs`, replacing — not adding to — the - # defaults computed below. Those defaults are specific to a Linux *host* - # toolchain (`-pie`, `-static-libgcc`, `-lrt`, and the host toolchain's - # own `-L`/rpath and `swiftrt.o`); for a cross-compiled SDK target they - # are at best wrong and at worst invalid (wasm-ld rejects `-pie`, and a + # WebAssembly) provides the *complete* set of runtime link flags via + # `linkopts`/`linker_inputs`, replacing — not adding to — the defaults + # computed below. Those defaults are specific to a Linux *host* toolchain + # (`-pie`, `-static-libgcc`, `-lrt`, and the host toolchain's own + # `-L`/rpath and `swiftrt.o`); for a cross-compiled SDK target they are + # at best wrong and at worst invalid (wasm-ld rejects `-pie`, and a # second `swiftrt.o` would conflict with the SDK's own). - linkopts = list(ctx.attr.linkopts) - linker_inputs = list(ctx.files.linker_inputs) - if ctx.attr.os == "android" and sdkroot: - # The Swift link action drives the NDK clang directly and does not go - # through the cc toolchain's sysroot/runtime-lib link features, so - # point clang at the sysroot and stage `libc++_shared.so` (which the - # NDK clang links by default) into the link ourselves. - linkopts.append("--sysroot=" + sdkroot) - libcxx_suffix = "/usr/lib/{}-linux-android/libc++_shared.so".format(ctx.attr.arch) - linker_inputs = linker_inputs + [ - f - for f in cc_toolchain.all_files.to_list() - if f.path.endswith(libcxx_suffix) - ] swift_linkopts_cc_info = _swift_sdk_linkopts_cc_info( ctx.label, - linkopts, - linker_inputs, + list(ctx.attr.linkopts), + list(ctx.files.linker_inputs), ) else: swift_linkopts_cc_info = _swift_unix_linkopts_cc_info( diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc index 89ee3952a..9e8e91a61 100644 --- a/tools/worker/swift_runner.cc +++ b/tools/worker/swift_runner.cc @@ -587,10 +587,18 @@ bool SwiftRunner::ProcessArgument( consumer(std::filesystem::current_path().string() + "=" + new_path); #if __APPLE__ - std::string developer_dir = "__BAZEL_XCODE_DEVELOPER_DIR__"; - if (bazel_placeholder_substitutions_.Apply(developer_dir)) { - consumer(flag); - consumer(developer_dir + "=/PLACEHOLDER_DEVELOPER_DIR"); + // The developer-directory remap only applies to toolchains that use the + // Apple developer directory. A cross-compile (e.g. to Android) running on a + // macOS host has no DEVELOPER_DIR; skip the remap rather than hard-failing, + // keeping the working-directory remap above so file_prefix_map stays + // hermetic for those targets. + const char* developer_dir_env = std::getenv("DEVELOPER_DIR"); + if (developer_dir_env != nullptr && developer_dir_env[0] != '\0') { + std::string developer_dir = "__BAZEL_XCODE_DEVELOPER_DIR__"; + if (bazel_placeholder_substitutions_.Apply(developer_dir)) { + consumer(flag); + consumer(developer_dir + "=/PLACEHOLDER_DEVELOPER_DIR"); + } } #endif }; From 976886227160c83b8f87d17e5270c3fc86184ace Mon Sep 17 00:00:00 2001 From: Logan Shire Date: Thu, 25 Jun 2026 20:22:12 -0400 Subject: [PATCH 4/8] examples: add Android toolchain analysis + artifact tests 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 --- .../cross_compilation/android_app/BUILD.bazel | 33 +++++ .../android_app/validation.bzl | 137 ++++++++++++++++++ test/BUILD | 3 + test/android_tests.bzl | 80 ++++++++++ test/fixtures/android/BUILD | 28 ++++ test/fixtures/android/jni.swift | 11 ++ 6 files changed, 292 insertions(+) create mode 100644 examples/cross_compilation/android_app/validation.bzl create mode 100644 test/android_tests.bzl create mode 100644 test/fixtures/android/BUILD create mode 100644 test/fixtures/android/jni.swift diff --git a/examples/cross_compilation/android_app/BUILD.bazel b/examples/cross_compilation/android_app/BUILD.bazel index 7077dfe35..e55dcb840 100644 --- a/examples/cross_compilation/android_app/BUILD.bazel +++ b/examples/cross_compilation/android_app/BUILD.bazel @@ -13,6 +13,7 @@ load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") load("//swift:swift.bzl", "swift_binary", "swift_library") load("//swift/toolchains:android_runtime_lib.bzl", "select_android_runtime_lib") +load(":validation.bzl", "android_apk_contents_check", "android_so_abi_check") package(default_visibility = ["//visibility:public"]) @@ -41,6 +42,38 @@ build_test( targets = [":app"], ) +# Assert the built JNI .so is a correct AArch64 ELF that exports the @_cdecl +# entry point and links libc++_shared.so (run via build_test below). +android_so_abi_check( + name = "swift_jni_abi", + jni_symbol = "Java_com_example_swiftjni_NativeBridge_greetingFromSwift", + shared_library = ":SwiftJNI", + tags = ["manual"], +) + +build_test( + name = "swift_jni_abi_test", + targets = [":swift_jni_abi"], +) + +# Assert the APK actually packages the Swift .so, the NDK C++ runtime, and the +# dexed Kotlin (run via build_test below). +android_apk_contents_check( + name = "apk_contents", + apk = ":app.apk", + expected_entries = [ + "lib/arm64-v8a/libSwiftJNI.so", + "lib/arm64-v8a/libc++_shared.so", + "classes.dex", + ], + tags = ["manual"], +) + +build_test( + name = "apk_contents_test", + targets = [":apk_contents"], +) + # The Swift JNI library and the NDK C++ runtime it loads, packaged into the APK # by android_binary's per-ABI native split. A prebuilt .so in a cc_library's # srcs becomes the CcInfo dynamic library the split collects. These only build diff --git a/examples/cross_compilation/android_app/validation.bzl b/examples/cross_compilation/android_app/validation.bzl new file mode 100644 index 000000000..1972126ff --- /dev/null +++ b/examples/cross_compilation/android_app/validation.bzl @@ -0,0 +1,137 @@ +"""Validates the built Android JNI `.so` with the NDK's `llvm-readelf`. + +The assertions run at build time (so the NDK `llvm-readelf` is reached through the +resolved Android cc toolchain) and are surfaced as a test with `build_test`. They +guard the things a `build_test` alone can't see: that the JNI entry point is +actually exported in the dynamic symbol table, that the `.so` is an AArch64 ELF, +and that it links `libc++_shared.so` dynamically (so the APK must ship it). +""" + +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") + +# Incoming transition so the rule (and its `.so` dep) resolve for Android, which +# makes `find_cc_toolchain` return the NDK toolchain whose files include +# `llvm-readelf`. +def _android_transition_impl(_settings, _attr): + return {"//command_line_option:platforms": "@rules_android//:arm64-v8a"} + +_android_transition = transition( + implementation = _android_transition_impl, + inputs = [], + outputs = ["//command_line_option:platforms"], +) + +def _android_so_abi_check_impl(ctx): + cc_toolchain = find_cc_toolchain(ctx) + readelf = None + for f in cc_toolchain.all_files.to_list(): + if f.basename == "llvm-readelf": + readelf = f + break + if not readelf: + fail("llvm-readelf was not found in the resolved Android cc toolchain.") + + so = ctx.file.shared_library + marker = ctx.actions.declare_file(ctx.label.name + ".ok") + command = """ +set -u +header=$('{readelf}' -h '{so}') +case "$header" in + *AArch64*) ;; + *) echo 'error: {so} is not an AArch64 ELF' >&2; exit 1 ;; +esac +dynamic=$('{readelf}' -d '{so}') +case "$dynamic" in + *libc++_shared.so*) ;; + *) echo 'error: {so} does not list libc++_shared.so in NEEDED' >&2; exit 1 ;; +esac +dynsyms=$('{readelf}' --dyn-syms '{so}') +case "$dynsyms" in + *{sym}*) ;; + *) echo 'error: JNI symbol {sym} is not exported in the .dynsym of {so}' >&2; exit 1 ;; +esac +touch '{marker}' +""".format( + readelf = readelf.path, + so = so.path, + sym = ctx.attr.jni_symbol, + marker = marker.path, + ) + ctx.actions.run_shell( + inputs = depset([so], transitive = [cc_toolchain.all_files]), + outputs = [marker], + command = command, + mnemonic = "AndroidSoAbiCheck", + progress_message = "Validating Android JNI .so %s" % so.short_path, + ) + return [DefaultInfo(files = depset([marker]))] + +android_so_abi_check = rule( + implementation = _android_so_abi_check_impl, + cfg = _android_transition, + attrs = { + "shared_library": attr.label( + allow_single_file = True, + mandatory = True, + doc = "The `swift_binary(linkshared = True)` JNI library to inspect.", + ), + "jni_symbol": attr.string( + mandatory = True, + doc = "The `@_cdecl` JNI entry point expected in the `.so`'s `.dynsym`.", + ), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + }, + toolchains = use_cc_toolchain(), +) + +def _android_apk_contents_check_impl(ctx): + apk = ctx.file.apk + marker = ctx.actions.declare_file(ctx.label.name + ".ok") + checks = "\n".join([ + """case "$listing" in + *'{entry}'*) ;; + *) echo 'error: APK is missing {entry}' >&2; exit 1 ;; +esac""".format(entry = entry) + for entry in ctx.attr.expected_entries + ]) + ctx.actions.run_shell( + inputs = [apk], + outputs = [marker], + tools = [ctx.executable._zipper], + command = """ +set -u +listing=$('{zipper}' v '{apk}') +{checks} +touch '{marker}' +""".format( + zipper = ctx.executable._zipper.path, + apk = apk.path, + checks = checks, + marker = marker.path, + ), + mnemonic = "AndroidApkContentsCheck", + progress_message = "Validating APK contents of %s" % apk.short_path, + ) + return [DefaultInfo(files = depset([marker]))] + +android_apk_contents_check = rule( + implementation = _android_apk_contents_check_impl, + attrs = { + "apk": attr.label( + allow_single_file = [".apk"], + mandatory = True, + doc = "The APK whose entries to assert.", + ), + "expected_entries": attr.string_list( + mandatory = True, + doc = "Zip entry paths that must be present in the APK.", + ), + "_zipper": attr.label( + default = "@bazel_tools//tools/zip:zipper", + executable = True, + cfg = "exec", + ), + }, +) diff --git a/test/BUILD b/test/BUILD index 97b43f2bb..7c6c97493 100644 --- a/test/BUILD +++ b/test/BUILD @@ -1,5 +1,6 @@ load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") load(":additional_linker_inputs_tests.bzl", "additional_linker_inputs_test_suite") +load(":android_tests.bzl", "android_test_suite") load(":aspect_tests.bzl", "aspect_tests") load(":ast_file_tests.bzl", "ast_file_test_suite") load(":bzl_test.bzl", "bzl_test") @@ -39,6 +40,8 @@ licenses(["notice"]) additional_linker_inputs_test_suite(name = "additional_linker_inputs") +android_test_suite(name = "android") + aspect_tests(name = "aspect_tests") ast_file_test_suite(name = "ast_file") diff --git a/test/android_tests.bzl b/test/android_tests.bzl new file mode 100644 index 000000000..f079b9b1c --- /dev/null +++ b/test/android_tests.bzl @@ -0,0 +1,80 @@ +"""Tests that the Android Swift SDK toolchain links through the NDK cc toolchain +with the right target triple.""" + +load( + "//test/rules:action_command_line_test.bzl", + "make_action_command_line_test_rule", +) +load( + "//test/rules:action_inputs_test.bzl", + "make_action_inputs_test_rule", +) + +# Build the target under test for Android (the SDK toolchain + the NDK cc +# toolchain resolve from these constraints). The platform label is resolved to +# its canonical form here so the transition (applied in the analysistest rule's +# own repository) still points at this repository's fixture. +_ANDROID_CONFIG = { + "//command_line_option:platforms": [ + str(Label("//test/fixtures/android:android_arm64")), + ], +} + +android_command_line_test = make_action_command_line_test_rule( + config_settings = _ANDROID_CONFIG, +) + +android_inputs_test = make_action_inputs_test_rule( + config_settings = _ANDROID_CONFIG, +) + +def android_test_suite(name, tags = []): + """Test suite for the Android Swift SDK toolchain's compile/link actions. + + Args: + name: The base name to be used in targets created by this macro. + tags: Additional tags to apply to each test. + """ + all_tags = [name] + tags + + # The Swift compile targets the Android triple. + android_command_line_test( + name = "{}_swiftcompile_targets_android".format(name), + expected_argv = ["-target aarch64-linux-android"], + mnemonic = "SwiftCompile", + tags = all_tags, + target_compatible_with = ["@platforms//os:macos"], + target_under_test = "//test/fixtures/android:jni_lib", + ) + + # The link runs the NDK clang for the Android target (the `28` is the + # `android.ndk(api_level = ...)` from MODULE.bazel), against the NDK sysroot, + # and links libc++ as the shared `libc++_shared.so`. + android_command_line_test( + name = "{}_link_uses_ndk".format(name), + expected_argv = [ + "--target=aarch64-linux-android28", + "--sysroot", + "-lstdc++", + ], + mnemonic = "CppLink", + tags = all_tags, + target_compatible_with = ["@platforms//os:macos"], + target_under_test = "//test/fixtures/android:jni_lib", + ) + + # The NDK's libc++_shared.so is staged into the link so a downstream APK can + # package it next to the Swift `.so`. + android_inputs_test( + name = "{}_link_stages_libcxx_shared".format(name), + expected_inputs = ["libc++_shared.so"], + mnemonic = "CppLink", + tags = all_tags, + target_compatible_with = ["@platforms//os:macos"], + target_under_test = "//test/fixtures/android:jni_lib", + ) + + native.test_suite( + name = name, + tags = all_tags, + ) diff --git a/test/fixtures/android/BUILD b/test/fixtures/android/BUILD new file mode 100644 index 000000000..ff1152c70 --- /dev/null +++ b/test/fixtures/android/BUILD @@ -0,0 +1,28 @@ +load("//swift:swift_binary.bzl", "swift_binary") +load("//test/fixtures:common.bzl", "FIXTURE_TAGS") + +licenses(["notice"]) + +package( + default_visibility = ["//test:__subpackages__"], +) + +# The platform the analysis tests transition the JNI library to. Its +# constraints (os:android + cpu:arm64, an alias of aarch64) resolve the Android +# Swift SDK toolchain and the Android cc toolchain. +platform( + name = "android_arm64", + constraint_values = [ + "@platforms//cpu:arm64", + "@platforms//os:android", + ], +) + +# A JNI shared library built by the Android Swift SDK toolchain; the tests +# inspect its compile/link actions. +swift_binary( + name = "jni_lib", + srcs = ["jni.swift"], + linkshared = True, + tags = FIXTURE_TAGS, +) diff --git a/test/fixtures/android/jni.swift b/test/fixtures/android/jni.swift new file mode 100644 index 000000000..688a0e8ba --- /dev/null +++ b/test/fixtures/android/jni.swift @@ -0,0 +1,11 @@ +// A trivial JNI entry point used by the Android toolchain analysis tests. The +// raw-pointer parameters and `Int32` return keep it free of any platform- +// specific JNI module import, so it builds for Android with only the SDK +// toolchain registered. +@_cdecl("Java_com_example_Fixture_value") +public func value( + _: UnsafeMutableRawPointer?, + _: UnsafeMutableRawPointer? +) -> Int32 { + return 42 +} From 9528c839ca0b1ce1c644c189c7e8cd7d6b5f0a27 Mon Sep 17 00:00:00 2001 From: Logan Shire Date: Thu, 25 Jun 2026 18:31:49 -0400 Subject: [PATCH 5/8] examples: bazel run target that boots a hermetic emulator (demo) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../cross_compilation/android_app/BUILD.bazel | 24 ++++++ .../cross_compilation/android_app/README.md | 11 +++ .../android_app/android.MODULE.bazel | 9 +++ .../android_app/emulator.bzl | 45 +++++++++++ examples/cross_compilation/android_app/run.sh | 75 +++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 examples/cross_compilation/android_app/emulator.bzl create mode 100755 examples/cross_compilation/android_app/run.sh diff --git a/examples/cross_compilation/android_app/BUILD.bazel b/examples/cross_compilation/android_app/BUILD.bazel index e55dcb840..8236ea022 100644 --- a/examples/cross_compilation/android_app/BUILD.bazel +++ b/examples/cross_compilation/android_app/BUILD.bazel @@ -11,12 +11,36 @@ load("@bazel_skylib//rules:build_test.bzl", "build_test") load("@rules_android//rules:rules.bzl", "android_binary") load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") load("//swift:swift.bzl", "swift_binary", "swift_library") load("//swift/toolchains:android_runtime_lib.bzl", "select_android_runtime_lib") load(":validation.bzl", "android_apk_contents_check", "android_so_abi_check") package(default_visibility = ["//visibility:public"]) +# `bazel run //examples/cross_compilation/android_app:run` installs the APK on a +# connected device/emulator and launches it, booting a hermetic emulator first +# if nothing is connected (downloaded emulator + system image; adb from +# @androidsdk). macOS/arm64 only — see emulator.bzl. +sh_binary( + name = "run", + srcs = ["run.sh"], + args = [ + "$(rlocationpath :app.apk)", + "$(rlocationpath @androidsdk//:adb)", + "$(rlocationpath @android_emulator//:emulator/emulator)", + "$(rlocationpath @android_system_image//:system.img)", + ], + data = [ + ":app.apk", + "@android_emulator//:all", + "@android_emulator//:emulator/emulator", + "@android_system_image//:all", + "@android_system_image//:system.img", + "@androidsdk//:adb", + ], +) + android_binary( name = "app", manifest = "AndroidManifest.xml", diff --git a/examples/cross_compilation/android_app/README.md b/examples/cross_compilation/android_app/README.md index 60b69e6e9..ea1034223 100644 --- a/examples/cross_compilation/android_app/README.md +++ b/examples/cross_compilation/android_app/README.md @@ -22,6 +22,17 @@ adb install -r bazel-bin/examples/cross_compilation/android_app/app.apk adb shell am start -n com.example.swiftjni/.MainActivity ``` +Or, with nothing preinstalled (no Android Studio, no device), let Bazel boot a +hermetic emulator, install, and launch — macOS/arm64: + +```sh +bazel run //examples/cross_compilation/android_app:run +``` + +This downloads the emulator + an AOSP system image (see `emulator.bzl`) and uses +adb from `@androidsdk`; if a device/emulator is already connected it just installs +and launches on that. + The screen shows **“Hello from Swift, Android!”** — computed by the `Greeter` `swift_library`, returned through the `@_cdecl` JNI entry point in `libSwiftJNI.so`, and displayed by Kotlin. (`//.bazelrc` sets diff --git a/examples/cross_compilation/android_app/android.MODULE.bazel b/examples/cross_compilation/android_app/android.MODULE.bazel index a860cb7ea..013bb77ee 100644 --- a/examples/cross_compilation/android_app/android.MODULE.bazel +++ b/examples/cross_compilation/android_app/android.MODULE.bazel @@ -66,3 +66,12 @@ register_toolchains( "@androidsdk//:all", dev_dependency = True, ) + +# A hermetic emulator + system image so `bazel run …:run` can launch the example +# with nothing preinstalled (adb comes from @androidsdk). +emulator = use_extension( + "//examples/cross_compilation/android_app:emulator.bzl", + "emulator", + dev_dependency = True, +) +use_repo(emulator, "android_emulator", "android_system_image") diff --git a/examples/cross_compilation/android_app/emulator.bzl b/examples/cross_compilation/android_app/emulator.bzl new file mode 100644 index 000000000..15cd1ae66 --- /dev/null +++ b/examples/cross_compilation/android_app/emulator.bzl @@ -0,0 +1,45 @@ +"""A dev module extension that downloads a hermetic Android emulator and a +system image, so `bazel run //examples/cross_compilation/android_app:run` can +boot an emulator and launch the example with nothing preinstalled. + +macOS/arm64 only, to keep this illustrative delta small (it's the platform the +example's CI runs on). adb comes from `@androidsdk`; only the emulator and the +system image — which `@androidsdk` does not provide — are downloaded here. +""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +_EMULATOR_BUILD = """\ +package(default_visibility = ["//visibility:public"]) + +exports_files(["emulator/emulator"]) + +filegroup(name = "all", srcs = glob(["emulator/**"])) +""" + +_SYSTEM_IMAGE_BUILD = """\ +package(default_visibility = ["//visibility:public"]) + +exports_files(["system.img"]) + +filegroup(name = "all", srcs = glob(["**"])) +""" + +def _emulator_impl(_module_ctx): + http_archive( + name = "android_emulator", + build_file_content = _EMULATOR_BUILD, + sha256 = "25378c67fd5bd03178e3a478b866496da8545e969df3a7a26ce9167772ffc026", + url = "https://dl.google.com/android/repository/emulator-darwin_aarch64-15565763.zip", + ) + + # A regular GPU-enabled AOSP (default) image, not the headless ATD image. + http_archive( + name = "android_system_image", + build_file_content = _SYSTEM_IMAGE_BUILD, + sha256 = "1447958a4c6747c44390ac5f5f4c894be6d1dfce93868a0385a95c5f0ae4c339", + strip_prefix = "arm64-v8a", + url = "https://dl.google.com/android/repository/sys-img/android/arm64-v8a-34_r04.zip", + ) + +emulator = module_extension(implementation = _emulator_impl) diff --git a/examples/cross_compilation/android_app/run.sh b/examples/cross_compilation/android_app/run.sh new file mode 100755 index 000000000..f89594f70 --- /dev/null +++ b/examples/cross_compilation/android_app/run.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# `bazel run //examples/cross_compilation/android_app:run`: installs the example +# APK on a connected device/emulator and launches it. If nothing is connected, +# boots the hermetic emulator (downloaded emulator + AOSP system image) first. +set -euo pipefail + +RUNFILES_ROOT="$PWD/.." +APK="$RUNFILES_ROOT/$1" +ADB="$RUNFILES_ROOT/$2" +EMULATOR_BIN="$RUNFILES_ROOT/$3" +SYSIMG_MARKER="$RUNFILES_ROOT/$4" + +has_device() { + "$ADB" devices | awk 'NR>1 && $2 == "device"' | grep -q . +} + +"$ADB" start-server >/dev/null 2>&1 || true + +if ! has_device; then + echo "No device connected; booting the hermetic emulator..." + EMULATOR_DIR="$(cd "$(dirname "$EMULATOR_BIN")" && pwd)" + SYSIMG_DIR="$(cd "$(dirname "$SYSIMG_MARKER")" && pwd)" + + STATE="${TMPDIR:-/tmp}/rules_swift_android_example_emulator" + SDK="$STATE/sdk" + AVD_HOME="$STATE/avd" + AVD_DIR="$AVD_HOME/example.avd" + mkdir -p "$SDK/system-images/android-34/default" "$AVD_DIR" "$SDK/platform-tools" + + ln -sfn "$EMULATOR_DIR" "$SDK/emulator" + ln -sfn "$SYSIMG_DIR" "$SDK/system-images/android-34/default/arm64-v8a" + ln -sfn "$ADB" "$SDK/platform-tools/adb" + + cat > "$AVD_HOME/example.ini" < "$AVD_DIR/config.ini" <"$EMULATOR_LOG" 2>&1 & + echo " (emulator log: $EMULATOR_LOG)" + + "$ADB" wait-for-device + for _ in $(seq 1 120); do + [[ "$("$ADB" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" == "1" ]] && break + sleep 2 + done + has_device || { echo "error: emulator failed to boot; see $EMULATOR_LOG" >&2; exit 1; } + echo "Emulator booted." +fi + +"$ADB" install -r "$APK" +"$ADB" shell am start -n "com.example.swiftjni/.MainActivity" +echo "Launched com.example.swiftjni/.MainActivity" From d584a25fe18bc038bef6a6372c67a34fd3c3908e Mon Sep 17 00:00:00 2001 From: Logan Shire Date: Thu, 25 Jun 2026 20:45:05 -0400 Subject: [PATCH 6/8] swift_sdks: cite rules_android_ndk#93 for the static-libc++ default 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 --- swift/internal/extensions/swift_sdks.bzl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/swift/internal/extensions/swift_sdks.bzl b/swift/internal/extensions/swift_sdks.bzl index 8a53009fa..8a5bf458a 100644 --- a/swift/internal/extensions/swift_sdks.bzl +++ b/swift/internal/extensions/swift_sdks.bzl @@ -201,9 +201,12 @@ def _swift_android_sdk_impl(repository_ctx): "-ldl", "-llog", # libc++ as the shared `libc++_shared.so` (the SDK's intended - # linkage; dropping this statically links libc++ instead, which - # the NDK discourages for a JNI library). It must be packaged - # into the APK; see `select_android_runtime_lib`. + # linkage). The Android cc toolchain links libc++ statically by + # default (https://github.com/bazelbuild/rules_android_ndk/issues/93), + # which the NDK discourages for a library that may share a process + # with other `.so`s; `-lstdc++` overrides that to the shared + # runtime, which must then be packaged into the APK (see + # `select_android_runtime_lib`). "-lstdc++", "-Wl,-z,max-page-size=16384", ]), From b88eb7638bd5d06da27ffa6bd316f54ae315c544 Mon Sep 17 00:00:00 2001 From: Logan Shire Date: Mon, 29 Jun 2026 21:22:39 -0400 Subject: [PATCH 7/8] examples: add gazelle-generated bzl_library targets 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 --- examples/cross_compilation/android_app/BUILD.bazel | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/examples/cross_compilation/android_app/BUILD.bazel b/examples/cross_compilation/android_app/BUILD.bazel index 8236ea022..c54b132b3 100644 --- a/examples/cross_compilation/android_app/BUILD.bazel +++ b/examples/cross_compilation/android_app/BUILD.bazel @@ -1,3 +1,5 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + # A runnable Android app that runs Swift code through the JNI. # # bazel build //examples/cross_compilation/android_app:app @@ -138,3 +140,15 @@ swift_library( srcs = ["Sources/Greeter/Greeter.swift"], module_name = "Greeter", ) + +bzl_library( + name = "emulator", + srcs = ["emulator.bzl"], + deps = ["@bazel_tools//tools/build_defs/repo:http.bzl"], +) + +bzl_library( + name = "validation", + srcs = ["validation.bzl"], + deps = ["@rules_cc//cc:find_cc_toolchain_bzl"], +) From 56ee71be3fdcef835d4b2d915cefc5cbf460b13f Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Tue, 30 Jun 2026 18:52:03 -0400 Subject: [PATCH 8/8] Support cross-compiling to Android with a Swift SDK Keith's Android implementation (bazelbuild/rules_swift#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. --- .bazelci/presubmit.yml | 4 - MODULE.bazel | 47 ----- doc/standalone_toolchain.md | 82 +++------ examples/cross_compilation/README.md | 10 -- .../cross_compilation/android_app/BUILD.bazel | 87 +--------- .../cross_compilation/android_app/README.md | 66 ++----- .../Sources/SwiftJNI/SwiftJNI.swift | 5 +- .../android_app/android.MODULE.bazel | 98 +++++++---- .../android_app/emulator.bzl | 45 ----- examples/cross_compilation/android_app/run.sh | 18 +- .../android_app/validation.bzl | 137 --------------- swift/internal/extensions/BUILD.bazel.tpl | 28 +-- .../extensions/swift_sdk_releases.bzl | 9 +- swift/internal/extensions/swift_sdks.bzl | 55 +++--- swift/toolchains/BUILD | 7 - swift/toolchains/android_runtime_lib.bzl | 47 ----- swift/toolchains/swift_toolchain.bzl | 41 +---- test/android_tests.bzl | 63 +++---- test/fixtures/android/AndroidManifest.xml | 19 ++ test/fixtures/android/BUILD | 44 +++-- .../java/com/example/FixtureActivity.java | 11 ++ test/fixtures/android/jni.swift | 9 +- test/rules/BUILD | 6 +- test/rules/android_apk_contents_test.sh | 25 +++ test/rules/android_so_abi_test.sh | 54 ++++++ test/rules/android_validation_test.bzl | 162 ++++++++++++++++++ tools/worker/swift_runner.cc | 16 +- 27 files changed, 498 insertions(+), 697 deletions(-) delete mode 100644 examples/cross_compilation/README.md delete mode 100644 examples/cross_compilation/android_app/emulator.bzl delete mode 100644 examples/cross_compilation/android_app/validation.bzl delete mode 100644 swift/toolchains/android_runtime_lib.bzl create mode 100644 test/fixtures/android/AndroidManifest.xml create mode 100644 test/fixtures/android/java/com/example/FixtureActivity.java create mode 100755 test/rules/android_apk_contents_test.sh create mode 100755 test/rules/android_so_abi_test.sh create mode 100644 test/rules/android_validation_test.bzl diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 8e5f32e9d..5626e8a51 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -26,15 +26,11 @@ x_defaults: build_targets: - "//examples/..." - "-//examples/apple/..." - # The Android APK example is exercised on macOS (see //examples/... - # below); it needs the hermetic Android SDK/NDK and is skipped here. - - "-//examples/cross_compilation/..." test_flags: *linux_flags test_targets: - "//examples/..." - "//test/..." - "-//examples/apple/..." - - "-//examples/cross_compilation/..." # The following tests require Swift >5.8. - "-//test:const_values_empty_const_values_multiple_files" - "-//test:const_values_empty_const_values_single_file" diff --git a/MODULE.bazel b/MODULE.bazel index 970a4b845..26de1fab9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -84,9 +84,6 @@ swift.toolchain( name = "swift_toolchain", swift_version = "6.3.2", ) -swift.android_sdk( - toolchain_name = "swift_toolchain", -) use_repo( swift, "swift_toolchain", @@ -113,50 +110,6 @@ register_toolchains( dev_dependency = True, ) -register_toolchains( - # Android Swift SDK toolchains used by //examples/cross_compilation. As with - # the embedded toolchains above, we register only the host platforms used by - # CI rather than `@swift_toolchain//:all`, because rules_swift cannot yet - # auto-select a Linux distribution and `:all` would make the host/exec - # toolchain ambiguous across distros. A consumer that builds on a single host - # platform can simply register `@swift_toolchain//:all`. The Android C/C++ - # toolchain comes from `@androidndk//:all` (registered below), not here. - "@swift_toolchain//:swift_toolchain_android_aarch64_ubuntu22.04", - "@swift_toolchain//:swift_toolchain_android_aarch64_ubuntu22.04-aarch64", - "@swift_toolchain//:swift_toolchain_android_aarch64_xcode", - "@swift_toolchain//:swift_toolchain_android_x86_64_ubuntu22.04", - "@swift_toolchain//:swift_toolchain_android_x86_64_ubuntu22.04-aarch64", - "@swift_toolchain//:swift_toolchain_android_x86_64_xcode", - dev_dependency = True, -) - -# The Android C/C++ cc toolchains for the cross-compile. rules_swift's Swift -# Android toolchain links through these and reads the sysroot from them. -bazel_dep(name = "hermetic_android_toolchains", version = "0.1.1", dev_dependency = True) - -android_ndk = use_extension( - "@hermetic_android_toolchains//:extensions.bzl", - "android", - dev_dependency = True, -) -android_ndk.sdk( - build_tools_version = "35.0.0", - version = "35", -) -android_ndk.ndk( - api_level = 28, - version = "r27c", -) -use_repo(android_ndk, "androidndk") - -register_toolchains( - "@androidndk//:all", - dev_dependency = True, -) - -# Dev dependencies for the runnable APK example (rules_android + rules_kotlin and -# their Maven graph). Split into its own segment to keep the heavy, example-only -# dependencies out of the root module; it references `android_ndk` defined above. include("//examples/cross_compilation/android_app:android.MODULE.bazel") # Dev dependencies diff --git a/doc/standalone_toolchain.md b/doc/standalone_toolchain.md index cfe873ce0..320c7fb11 100644 --- a/doc/standalone_toolchain.md +++ b/doc/standalone_toolchain.md @@ -146,18 +146,14 @@ bazel run @rules_swift//tools/swift-releases -- list \ main-snapshot-2024-08-01 --platform xcode --platform ubuntu22.04 ``` -## Cross-compiling to Android with a Swift SDK +## Building for Android -swift.org publishes "Swift SDK" artifact bundles (the bundles consumed by -`swift sdk install`) that let the host compiler cross-compile for platforms it -cannot target by itself. The `swift` extension can download the Android SDK and -define matching Swift and C/C++ toolchains, so plain `swift_library` and -`swift_binary` targets build for `{aarch64,x86_64}-unknown-linux-android` under -`--platforms`. +The `swift` module extension can be used to download the Swift Android +SDK for writing NDK code in Swift. -Add the `android_sdk` tag, referencing the `toolchain` tag by name (the Swift -module format is not stable across compiler versions, so the SDK is always -downloaded for exactly the toolchain's version): +Add the `android_sdk` tag, referencing the `toolchain` tag by name (the +Swift module format is not stable across compiler versions, so the SDK +is always downloaded for exactly the toolchain's version): ```bzl swift.toolchain( @@ -168,8 +164,7 @@ swift.toolchain( swift.android_sdk(toolchain_name = "swift_toolchain") # rules_swift provides only the Swift toolchain; register an Android C/C++ cc -# toolchain too (it also provides the sysroot the Swift compiler reads). For -# example, @androidndk//:all from hermetic_android_toolchains: +# toolchain too. For example, @androidndk//:all from hermetic_android_toolchains: android = use_extension("@hermetic_android_toolchains//:extensions.bzl", "android") android.sdk(version = "35", build_tools_version = "35.0.0") android.ndk(version = "r27c", api_level = 28) @@ -182,60 +177,31 @@ register_toolchains( ) ``` -If you build on a single host platform you can register everything the -extension generates in one line instead of listing the matrix: +See `examples/cross_compilation/android_app` for an end to end example. + +### JNI shared libraries + +To produce a JNI library (`lib.so`) loadable with +`System.loadLibrary`, Use something like: ```bzl -register_toolchains("@swift_toolchain//:all") +swift_binary( + name = "", + linkshared = True, + ... +) ``` -Avoid `:all` when you configure multiple Linux distributions, for the same -reason the standalone host toolchains are registered explicitly: rules_swift -cannot yet auto-select a distribution, so `:all` would make the host/exec -toolchain ambiguous across them. +Export JNI functions with `@_cdecl`: -Then build with a platform carrying the matching constraints — for Android, use -the ones `rules_android` already exposes: +```swift +import Android -```sh -bazel build //my:binary --platforms=@rules_android//:arm64-v8a +@_cdecl("Java_com_example_swiftjni_NativeBridge_greetingFromSwift") +public func greetingFromSwift(_ env: UnsafeMutablePointer, _ clazz: jclass) -> jstring? { ``` -See `examples/cross_compilation/android_app` for a complete, runnable example. - -### JNI shared libraries - -A plain `swift_binary` links an ordinary executable. To produce a JNI library -loadable with `System.loadLibrary`, set `linkshared = True`: it produces -`lib.so`. Export functions with `@_cdecl`; the Android Swift SDK's -`Android` module provides the JNI types, so the entry points can be written -entirely in Swift. A `swift_binary(linkshared = True)` may depend on ordinary -`swift_library` targets (linked statically), so the JNI entry point and the -shared business logic stay in separate libraries. -`examples/cross_compilation/android_app` shows the Kotlin app that loads the JNI -library. - -Details worth knowing: - -* The Swift standard library is linked statically from the SDK. -* Android binaries link against the NDK's `libc++_shared.so`, which must be - packaged with the application. Select it from the registered Android cc - toolchain with `select_android_runtime_lib` from - `@rules_swift//swift/toolchains:android_runtime_lib.bzl` (build it under the - Android platform so the cc toolchain resolves). -* rules_swift does not fetch the Android NDK; the registered Android cc toolchain - (e.g. `@androidndk//:all`) provides clang, the linker, and the sysroot, and the - Swift toolchain reads that toolchain's sysroot at analysis time. -* Checksums for the SDK bundles are bundled for a curated list of releases (see - `swift/internal/extensions/swift_sdk_releases.bzl`); for other releases, pass - `sha256` explicitly. - -### Coexistence with `rules_apple` - -A common setup cross-compiles to Android *and* builds the same app's Apple -targets with `rules_apple`. The two resolve together cleanly: this line of -`rules_swift` is `compatibility_level = 3` (the same as released `rules_swift` -3.x), so a current `rules_apple` release works alongside it. +See `examples/cross_compilation/android_app` for an end to end example. ## Using the extension from a non-root module diff --git a/examples/cross_compilation/README.md b/examples/cross_compilation/README.md deleted file mode 100644 index a666a3cfc..000000000 --- a/examples/cross_compilation/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Cross-compilation example (Android) - -A complete, runnable Android app that cross-compiles Swift to Android and runs it -through the JNI, built with the Swift SDK toolchain registered by this -repository's `MODULE.bazel` (via the `swift` extension's `android_sdk` tag). See -`doc/standalone_toolchain.md` for the toolchain setup. - -Everything lives in [`android_app/`](android_app) — the Swift sources, the Kotlin -app, and the `BUILD.bazel` that packages them into an APK with `rules_android` + -`rules_kotlin`. See [`android_app/README.md`](android_app/README.md). diff --git a/examples/cross_compilation/android_app/BUILD.bazel b/examples/cross_compilation/android_app/BUILD.bazel index c54b132b3..ad8f791ec 100644 --- a/examples/cross_compilation/android_app/BUILD.bazel +++ b/examples/cross_compilation/android_app/BUILD.bazel @@ -1,29 +1,11 @@ -load("@bazel_skylib//:bzl_library.bzl", "bzl_library") - -# A runnable Android app that runs Swift code through the JNI. -# -# bazel build //examples/cross_compilation/android_app:app -# adb install -r bazel-bin/examples/cross_compilation/android_app/app.apk -# adb shell am start -n com.example.swiftjni/.MainActivity -# -# The call chain: MainActivity.kt -> NativeBridge.greetingFromSwift() (Kotlin, -# JNI) -> libSwiftJNI.so (swift_binary, @_cdecl) -> Greeter (swift_library). - load("@bazel_skylib//rules:build_test.bzl", "build_test") load("@rules_android//rules:rules.bzl", "android_binary") load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") load("@rules_shell//shell:sh_binary.bzl", "sh_binary") load("//swift:swift.bzl", "swift_binary", "swift_library") -load("//swift/toolchains:android_runtime_lib.bzl", "select_android_runtime_lib") -load(":validation.bzl", "android_apk_contents_check", "android_so_abi_check") -package(default_visibility = ["//visibility:public"]) - -# `bazel run //examples/cross_compilation/android_app:run` installs the APK on a -# connected device/emulator and launches it, booting a hermetic emulator first -# if nothing is connected (downloaded emulator + system image; adb from -# @androidsdk). macOS/arm64 only — see emulator.bzl. +# bazel run //examples/cross_compilation/android_app:run sh_binary( name = "run", srcs = ["run.sh"], @@ -48,7 +30,6 @@ android_binary( manifest = "AndroidManifest.xml", deps = [ ":app_lib", - ":libcxx", ":swift_jni", ], ) @@ -68,64 +49,13 @@ build_test( targets = [":app"], ) -# Assert the built JNI .so is a correct AArch64 ELF that exports the @_cdecl -# entry point and links libc++_shared.so (run via build_test below). -android_so_abi_check( - name = "swift_jni_abi", - jni_symbol = "Java_com_example_swiftjni_NativeBridge_greetingFromSwift", - shared_library = ":SwiftJNI", - tags = ["manual"], -) - -build_test( - name = "swift_jni_abi_test", - targets = [":swift_jni_abi"], -) - -# Assert the APK actually packages the Swift .so, the NDK C++ runtime, and the -# dexed Kotlin (run via build_test below). -android_apk_contents_check( - name = "apk_contents", - apk = ":app.apk", - expected_entries = [ - "lib/arm64-v8a/libSwiftJNI.so", - "lib/arm64-v8a/libc++_shared.so", - "classes.dex", - ], - tags = ["manual"], -) - -build_test( - name = "apk_contents_test", - targets = [":apk_contents"], -) - -# The Swift JNI library and the NDK C++ runtime it loads, packaged into the APK -# by android_binary's per-ABI native split. A prebuilt .so in a cc_library's -# srcs becomes the CcInfo dynamic library the split collects. These only build -# for Android (the split configures them from --android_platforms), so the -# //examples/... wildcard skips them on a non-Android host. +# https://github.com/bazelbuild/rules_android/pull/531 cc_library( name = "swift_jni", srcs = [":SwiftJNI"], target_compatible_with = ["@platforms//os:android"], ) -cc_library( - name = "libcxx", - srcs = [":libcxx_shared"], - target_compatible_with = ["@platforms//os:android"], -) - -select_android_runtime_lib( - name = "libcxx_shared", - target_compatible_with = ["@platforms//os:android"], - triple = "aarch64-linux-android", -) - -# `linkshared` produces `libSwiftJNI.so`. The JNI entry point is written in -# Swift (it `import`s the SDK's `Android` module for the JNI types) and calls -# into the `Greeter` library. swift_binary( name = "SwiftJNI", srcs = ["Sources/SwiftJNI/SwiftJNI.swift"], @@ -134,21 +64,8 @@ swift_binary( deps = [":Greeter"], ) -# A plain library dependency, compiled for whichever platform depends on it. swift_library( name = "Greeter", srcs = ["Sources/Greeter/Greeter.swift"], module_name = "Greeter", ) - -bzl_library( - name = "emulator", - srcs = ["emulator.bzl"], - deps = ["@bazel_tools//tools/build_defs/repo:http.bzl"], -) - -bzl_library( - name = "validation", - srcs = ["validation.bzl"], - deps = ["@rules_cc//cc:find_cc_toolchain_bzl"], -) diff --git a/examples/cross_compilation/android_app/README.md b/examples/cross_compilation/android_app/README.md index ea1034223..c032903d8 100644 --- a/examples/cross_compilation/android_app/README.md +++ b/examples/cross_compilation/android_app/README.md @@ -1,65 +1,21 @@ -# Android app: Kotlin → Swift JNI `.so` → Swift library +# Building Swift for Android -A complete, runnable Android app that shows the greeting computed by Swift, -reached over JNI: - -``` -MainActivity.kt ──► NativeBridge.greetingFromSwift() (Kotlin) - │ JNI (System.loadLibrary("SwiftJNI")) - ▼ - :SwiftJNI → libSwiftJNI.so (swift_binary, linkshared) - @_cdecl("Java_..._greetingFromSwift") in Sources/SwiftJNI/SwiftJNI.swift - │ - ▼ - :Greeter (swift_library) -``` +A complete, runnable Android app that cross-compiles Swift to Android +and runs it through the JNI. See `doc/standalone_toolchain.md` for the +toolchain setup. ## Build & run -```sh -bazel build //examples/cross_compilation/android_app:app -adb install -r bazel-bin/examples/cross_compilation/android_app/app.apk -adb shell am start -n com.example.swiftjni/.MainActivity -``` - -Or, with nothing preinstalled (no Android Studio, no device), let Bazel boot a -hermetic emulator, install, and launch — macOS/arm64: +Hermetically: ```sh bazel run //examples/cross_compilation/android_app:run ``` -This downloads the emulator + an AOSP system image (see `emulator.bzl`) and uses -adb from `@androidsdk`; if a device/emulator is already connected it just installs -and launches on that. - -The screen shows **“Hello from Swift, Android!”** — computed by the `Greeter` -`swift_library`, returned through the `@_cdecl` JNI entry point in -`libSwiftJNI.so`, and displayed by Kotlin. (`//.bazelrc` sets -`--android_platforms=@rules_android//:arm64-v8a` and a hermetic JDK.) +With a locally installed Android SDK and device: -## How it's wired (`BUILD.bazel`) - -The APK is built with `rules_android` (`android_binary`) and `rules_kotlin` -(`kt_android_library`) — the real-world way Android apps are packaged. The one -rules_swift-specific detail is getting the prebuilt Swift `.so` into the APK: - -- `swift_binary(linkshared = True)` exposes its `.so` via `DefaultInfo`, not - `CcInfo`, so it can't go straight into `android_binary.deps`. Wrapping it in a - `cc_library` (a prebuilt `.so` in `srcs` becomes a `CcInfo` dynamic library) - lets `android_binary`'s per-ABI native split collect it into `lib/arm64-v8a/`. - The split configures the wrapped `swift_binary` for Android, so no explicit - platform transition is needed. -- `libc++_shared.so` (the NDK's C++ runtime, which the Swift SDK links - dynamically) is selected from the resolved Android cc toolchain by - rules_swift's `select_android_runtime_lib` and packaged the same way. - -## Dev dependencies - -`rules_android` + `rules_kotlin` (and their Maven graph) are **dev-only** -dependencies of `rules_swift`, kept in [`android.MODULE.bazel`](android.MODULE.bazel) -(`include()`d from the root `MODULE.bazel`) with a pinned Maven lock. They never -reach consumers of `rules_swift`; a consumer brings their own Android rules. The -Android SDK is the hermetic `@androidsdk` from -[`hermetic_android_toolchains`](https://github.com/keith/hermetic_android_toolchains) -(no local `$ANDROID_HOME` required). +```sh +bazel build //examples/cross_compilation/android_app:app +adb install -r bazel-bin/examples/cross_compilation/android_app/app.apk +adb shell am start -n com.example.swiftjni/.MainActivity +``` diff --git a/examples/cross_compilation/android_app/Sources/SwiftJNI/SwiftJNI.swift b/examples/cross_compilation/android_app/Sources/SwiftJNI/SwiftJNI.swift index 031f06e87..ea6d6f472 100644 --- a/examples/cross_compilation/android_app/Sources/SwiftJNI/SwiftJNI.swift +++ b/examples/cross_compilation/android_app/Sources/SwiftJNI/SwiftJNI.swift @@ -5,10 +5,7 @@ import Greeter // JNI types, and `@_cdecl` gives the function the `Java___` // symbol name that `NativeBridge.greetingFromSwift()` binds to. @_cdecl("Java_com_example_swiftjni_NativeBridge_greetingFromSwift") -public func greetingFromSwift( - _ env: UnsafeMutablePointer, - _ clazz: jclass -) -> jstring? { +public func greetingFromSwift(_ env: UnsafeMutablePointer, _ clazz: jclass) -> jstring? { let message = Greeter(subject: "Android").greeting() return message.withCString { cString in env.pointee!.pointee.NewStringUTF(env, cString) diff --git a/examples/cross_compilation/android_app/android.MODULE.bazel b/examples/cross_compilation/android_app/android.MODULE.bazel index 013bb77ee..a000c8e66 100644 --- a/examples/cross_compilation/android_app/android.MODULE.bazel +++ b/examples/cross_compilation/android_app/android.MODULE.bazel @@ -1,18 +1,13 @@ -# Dev dependencies for the runnable APK example (//examples/cross_compilation/ -# android_app), included from the root MODULE.bazel. rules_android + rules_kotlin -# package the APK the real-world way; they pull in a Maven graph and are heavy, -# so they're kept out of the root module and are all dev_dependency. Consumers of -# rules_swift never see them; a consumer brings their own Android rules. -# -# `android_ndk` (the hermetic_android_toolchains extension) and `@androidndk` are -# defined in the root module above this include(). - +bazel_dep(name = "hermetic_android_toolchains", version = "0.1.1", dev_dependency = True) bazel_dep(name = "rules_android", version = "0.7.3", dev_dependency = True) +bazel_dep(name = "rules_android_ndk", version = "0.1.5", dev_dependency = True) bazel_dep(name = "rules_java", version = "9.3.0", dev_dependency = True) -bazel_dep(name = "rules_kotlin", version = "2.2.2", dev_dependency = True) bazel_dep(name = "rules_jvm_external", version = "7.0", dev_dependency = True) +bazel_dep(name = "rules_kotlin", version = "2.2.2", dev_dependency = True) + +swift = use_extension("//swift:extensions.bzl", "swift", dev_dependency = True) +swift.android_sdk(toolchain_name = "swift_toolchain") -# rules_java's hermetic JDK + java tools for rules_android's Java actions. rules_java_toolchains = use_extension( "@rules_java//java:extensions.bzl", "toolchains", @@ -22,8 +17,7 @@ use_repo(rules_java_toolchains, "remote_java_tools") # rules_android's own Maven dependencies, pinned to a checked-in lock file: # REPIN=1 bazel run @rules_android_maven//:pin -# rules_android requiring a consumer-side maven.install is a known wart; see -# https://github.com/bazelbuild/rules_android/issues/485. +# https://github.com/bazelbuild/rules_android/issues/485 maven = use_extension( "@rules_jvm_external//:extensions.bzl", "maven", @@ -43,35 +37,79 @@ maven.install( ) use_repo(maven, "rules_android_maven") -# Point rules_android at the hermetic @androidsdk created by the android_ndk.sdk -# tag in the root module (instead of requiring a local $ANDROID_HOME). The -# extension proxy is re-declared here because include() segments don't share -# names with the root module; this resolves to the same extension usage. -android_ndk = use_extension( +android = use_extension( "@hermetic_android_toolchains//:extensions.bzl", "android", dev_dependency = True, ) -use_repo(android_ndk, "androidsdk") - -rules_android_sdk = use_extension( - "@rules_android//rules/android_sdk_repository:rule.bzl", - "android_sdk_repository_extension", - dev_dependency = True, +android.sdk( + build_tools_version = "35.0.0", + version = "35", +) +android.ndk( + api_level = 28, + version = "r27c", ) +use_repo(android, "androidndk", "androidsdk") + +# Make @rules_android's @androidsdk labels resolve to the hermetic SDK. +rules_android_sdk = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension", dev_dependency = True) override_repo(rules_android_sdk, "androidsdk") +# Make @rules_android_ndk's @androidndk labels resolve to the hermetic SDK. +rules_android_ndk = use_extension("@rules_android_ndk//:extension.bzl", "android_ndk_repository_extension", dev_dependency = True) + +override_repo(rules_android_ndk, "androidndk") + register_toolchains( + "@androidndk//:all", "@androidsdk//:all", dev_dependency = True, ) -# A hermetic emulator + system image so `bazel run …:run` can launch the example -# with nothing preinstalled (adb comes from @androidsdk). -emulator = use_extension( - "//examples/cross_compilation/android_app:emulator.bzl", - "emulator", +register_toolchains( + "@androidndk//:all", + dev_dependency = True, +) + +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "android_emulator", + build_file_content = """\ +package(default_visibility = ["//visibility:public"]) + +exports_files(["emulator/emulator"]) + +filegroup(name = "all", srcs = glob(["emulator/**"])) +""", + dev_dependency = True, + sha256 = "25378c67fd5bd03178e3a478b866496da8545e969df3a7a26ce9167772ffc026", + url = "https://dl.google.com/android/repository/emulator-darwin_aarch64-15565763.zip", +) + +http_archive( + name = "android_system_image", + build_file_content = """\ +package(default_visibility = ["//visibility:public"]) + +exports_files(["system.img"]) + +filegroup(name = "all", srcs = glob(["**"])) +""", + dev_dependency = True, + sha256 = "1447958a4c6747c44390ac5f5f4c894be6d1dfce93868a0385a95c5f0ae4c339", + strip_prefix = "arm64-v8a", + url = "https://dl.google.com/android/repository/sys-img/android/arm64-v8a-34_r04.zip", +) + +register_toolchains( + "@swift_toolchain//:swift_toolchain_android_aarch64_ubuntu22.04", + "@swift_toolchain//:swift_toolchain_android_aarch64_ubuntu22.04-aarch64", + "@swift_toolchain//:swift_toolchain_android_aarch64_xcode", + "@swift_toolchain//:swift_toolchain_android_x86_64_ubuntu22.04", + "@swift_toolchain//:swift_toolchain_android_x86_64_ubuntu22.04-aarch64", + "@swift_toolchain//:swift_toolchain_android_x86_64_xcode", dev_dependency = True, ) -use_repo(emulator, "android_emulator", "android_system_image") diff --git a/examples/cross_compilation/android_app/emulator.bzl b/examples/cross_compilation/android_app/emulator.bzl deleted file mode 100644 index 15cd1ae66..000000000 --- a/examples/cross_compilation/android_app/emulator.bzl +++ /dev/null @@ -1,45 +0,0 @@ -"""A dev module extension that downloads a hermetic Android emulator and a -system image, so `bazel run //examples/cross_compilation/android_app:run` can -boot an emulator and launch the example with nothing preinstalled. - -macOS/arm64 only, to keep this illustrative delta small (it's the platform the -example's CI runs on). adb comes from `@androidsdk`; only the emulator and the -system image — which `@androidsdk` does not provide — are downloaded here. -""" - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -_EMULATOR_BUILD = """\ -package(default_visibility = ["//visibility:public"]) - -exports_files(["emulator/emulator"]) - -filegroup(name = "all", srcs = glob(["emulator/**"])) -""" - -_SYSTEM_IMAGE_BUILD = """\ -package(default_visibility = ["//visibility:public"]) - -exports_files(["system.img"]) - -filegroup(name = "all", srcs = glob(["**"])) -""" - -def _emulator_impl(_module_ctx): - http_archive( - name = "android_emulator", - build_file_content = _EMULATOR_BUILD, - sha256 = "25378c67fd5bd03178e3a478b866496da8545e969df3a7a26ce9167772ffc026", - url = "https://dl.google.com/android/repository/emulator-darwin_aarch64-15565763.zip", - ) - - # A regular GPU-enabled AOSP (default) image, not the headless ATD image. - http_archive( - name = "android_system_image", - build_file_content = _SYSTEM_IMAGE_BUILD, - sha256 = "1447958a4c6747c44390ac5f5f4c894be6d1dfce93868a0385a95c5f0ae4c339", - strip_prefix = "arm64-v8a", - url = "https://dl.google.com/android/repository/sys-img/android/arm64-v8a-34_r04.zip", - ) - -emulator = module_extension(implementation = _emulator_impl) diff --git a/examples/cross_compilation/android_app/run.sh b/examples/cross_compilation/android_app/run.sh index f89594f70..3af7249b9 100755 --- a/examples/cross_compilation/android_app/run.sh +++ b/examples/cross_compilation/android_app/run.sh @@ -1,7 +1,9 @@ -#!/bin/bash +#!/usr/bin/env bash + # `bazel run //examples/cross_compilation/android_app:run`: installs the example # APK on a connected device/emulator and launches it. If nothing is connected, # boots the hermetic emulator (downloaded emulator + AOSP system image) first. + set -euo pipefail RUNFILES_ROOT="$PWD/.." @@ -14,6 +16,16 @@ has_device() { "$ADB" devices | awk 'NR>1 && $2 == "device"' | grep -q . } +is_boot_completed() { + [[ "$("$ADB" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" == "1" ]] +} + +is_package_manager_ready() { + "$ADB" shell service check package 2>/dev/null | grep -q ": found" && + "$ADB" shell service check settings 2>/dev/null | grep -q ": found" && + "$ADB" shell cmd package path android >/dev/null 2>&1 +} + "$ADB" start-server >/dev/null 2>&1 || true if ! has_device; then @@ -63,10 +75,12 @@ EOF "$ADB" wait-for-device for _ in $(seq 1 120); do - [[ "$("$ADB" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" == "1" ]] && break + is_boot_completed && is_package_manager_ready && break sleep 2 done has_device || { echo "error: emulator failed to boot; see $EMULATOR_LOG" >&2; exit 1; } + is_boot_completed || { echo "error: emulator did not complete boot; see $EMULATOR_LOG" >&2; exit 1; } + is_package_manager_ready || { echo "error: emulator booted, but package manager is not ready; see $EMULATOR_LOG" >&2; exit 1; } echo "Emulator booted." fi diff --git a/examples/cross_compilation/android_app/validation.bzl b/examples/cross_compilation/android_app/validation.bzl deleted file mode 100644 index 1972126ff..000000000 --- a/examples/cross_compilation/android_app/validation.bzl +++ /dev/null @@ -1,137 +0,0 @@ -"""Validates the built Android JNI `.so` with the NDK's `llvm-readelf`. - -The assertions run at build time (so the NDK `llvm-readelf` is reached through the -resolved Android cc toolchain) and are surfaced as a test with `build_test`. They -guard the things a `build_test` alone can't see: that the JNI entry point is -actually exported in the dynamic symbol table, that the `.so` is an AArch64 ELF, -and that it links `libc++_shared.so` dynamically (so the APK must ship it). -""" - -load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") - -# Incoming transition so the rule (and its `.so` dep) resolve for Android, which -# makes `find_cc_toolchain` return the NDK toolchain whose files include -# `llvm-readelf`. -def _android_transition_impl(_settings, _attr): - return {"//command_line_option:platforms": "@rules_android//:arm64-v8a"} - -_android_transition = transition( - implementation = _android_transition_impl, - inputs = [], - outputs = ["//command_line_option:platforms"], -) - -def _android_so_abi_check_impl(ctx): - cc_toolchain = find_cc_toolchain(ctx) - readelf = None - for f in cc_toolchain.all_files.to_list(): - if f.basename == "llvm-readelf": - readelf = f - break - if not readelf: - fail("llvm-readelf was not found in the resolved Android cc toolchain.") - - so = ctx.file.shared_library - marker = ctx.actions.declare_file(ctx.label.name + ".ok") - command = """ -set -u -header=$('{readelf}' -h '{so}') -case "$header" in - *AArch64*) ;; - *) echo 'error: {so} is not an AArch64 ELF' >&2; exit 1 ;; -esac -dynamic=$('{readelf}' -d '{so}') -case "$dynamic" in - *libc++_shared.so*) ;; - *) echo 'error: {so} does not list libc++_shared.so in NEEDED' >&2; exit 1 ;; -esac -dynsyms=$('{readelf}' --dyn-syms '{so}') -case "$dynsyms" in - *{sym}*) ;; - *) echo 'error: JNI symbol {sym} is not exported in the .dynsym of {so}' >&2; exit 1 ;; -esac -touch '{marker}' -""".format( - readelf = readelf.path, - so = so.path, - sym = ctx.attr.jni_symbol, - marker = marker.path, - ) - ctx.actions.run_shell( - inputs = depset([so], transitive = [cc_toolchain.all_files]), - outputs = [marker], - command = command, - mnemonic = "AndroidSoAbiCheck", - progress_message = "Validating Android JNI .so %s" % so.short_path, - ) - return [DefaultInfo(files = depset([marker]))] - -android_so_abi_check = rule( - implementation = _android_so_abi_check_impl, - cfg = _android_transition, - attrs = { - "shared_library": attr.label( - allow_single_file = True, - mandatory = True, - doc = "The `swift_binary(linkshared = True)` JNI library to inspect.", - ), - "jni_symbol": attr.string( - mandatory = True, - doc = "The `@_cdecl` JNI entry point expected in the `.so`'s `.dynsym`.", - ), - "_allowlist_function_transition": attr.label( - default = "@bazel_tools//tools/allowlists/function_transition_allowlist", - ), - }, - toolchains = use_cc_toolchain(), -) - -def _android_apk_contents_check_impl(ctx): - apk = ctx.file.apk - marker = ctx.actions.declare_file(ctx.label.name + ".ok") - checks = "\n".join([ - """case "$listing" in - *'{entry}'*) ;; - *) echo 'error: APK is missing {entry}' >&2; exit 1 ;; -esac""".format(entry = entry) - for entry in ctx.attr.expected_entries - ]) - ctx.actions.run_shell( - inputs = [apk], - outputs = [marker], - tools = [ctx.executable._zipper], - command = """ -set -u -listing=$('{zipper}' v '{apk}') -{checks} -touch '{marker}' -""".format( - zipper = ctx.executable._zipper.path, - apk = apk.path, - checks = checks, - marker = marker.path, - ), - mnemonic = "AndroidApkContentsCheck", - progress_message = "Validating APK contents of %s" % apk.short_path, - ) - return [DefaultInfo(files = depset([marker]))] - -android_apk_contents_check = rule( - implementation = _android_apk_contents_check_impl, - attrs = { - "apk": attr.label( - allow_single_file = [".apk"], - mandatory = True, - doc = "The APK whose entries to assert.", - ), - "expected_entries": attr.string_list( - mandatory = True, - doc = "Zip entry paths that must be present in the APK.", - ), - "_zipper": attr.label( - default = "@bazel_tools//tools/zip:zipper", - executable = True, - cfg = "exec", - ), - }, -) diff --git a/swift/internal/extensions/BUILD.bazel.tpl b/swift/internal/extensions/BUILD.bazel.tpl index f0e9c8192..bb4faf5f3 100644 --- a/swift/internal/extensions/BUILD.bazel.tpl +++ b/swift/internal/extensions/BUILD.bazel.tpl @@ -14,19 +14,13 @@ exports_files([ ]) ### Tools referenced by Swift SDK cross-compilation repositories. ### -# See swift/internal/extensions/swift_sdks.bzl. + exports_files([ - "usr/bin/clang", - "usr/bin/llvm-ar", + "usr/bin/swiftc", "usr/bin/swift-autolink-extract", "usr/bin/swift-symbolgraph-extract", - "usr/bin/swiftc", ]) -# The subset of the toolchain that Swift compile actions for a Swift SDK -# target need: the driver/frontend and their libraries, plus clang's builtin -# headers for the clang importer. The Swift standard library for the target -# comes from the SDK, not from here. filegroup( name = "swift_sdk_compiler_inputs", srcs = glob( @@ -43,24 +37,6 @@ filegroup( ), ) -# The subset of the toolchain that link actions driven by this toolchain's -# clang need. -filegroup( - name = "swift_sdk_linker_inputs", - srcs = glob( - [ - "usr/bin/clang*", - "usr/bin/ld.lld", - "usr/bin/ld64.lld", - "usr/bin/lld", - "usr/bin/llvm-ar", - "usr/bin/wasm-ld", - "usr/lib/clang/**", - ], - allow_empty = True, - ), -) - filegroup( name = "files", srcs = glob( diff --git a/swift/internal/extensions/swift_sdk_releases.bzl b/swift/internal/extensions/swift_sdk_releases.bzl index 92a7b89a8..8cfea21f6 100644 --- a/swift/internal/extensions/swift_sdk_releases.bzl +++ b/swift/internal/extensions/swift_sdk_releases.bzl @@ -1,9 +1,8 @@ -"""Swift SDK and Android NDK release version mappings. +"""Swift SDK release version mappings. -This module defines checksums for the artifacts needed to cross-compile Swift -for platforms that are not covered by a host toolchain, using the official -"Swift SDK" artifact bundles published by swift.org (the bundles installed by -`swift sdk install`). +Checksums for the official "Swift SDK" artifact bundles published by swift.org +(the bundles installed by `swift sdk install`), used to cross-compile Swift to +platforms not covered by a host toolchain. The Swift module format is not stable across compiler versions, so a Swift SDK can only be used with the host toolchain from exactly the same release; the diff --git a/swift/internal/extensions/swift_sdks.bzl b/swift/internal/extensions/swift_sdks.bzl index 8a5bf458a..e5a7b383e 100644 --- a/swift/internal/extensions/swift_sdks.bzl +++ b/swift/internal/extensions/swift_sdks.bzl @@ -1,5 +1,4 @@ -"""Shared building blocks for Swift SDK repository rules, plus the Android SDK -repository rule. +"""Shared building blocks for Swift SDK repository rules. A "Swift SDK" is an artifact bundle published by swift.org for cross-compiling Swift to a platform the host toolchain cannot target by itself (the bundles that @@ -16,11 +15,6 @@ with; the `swift` module extension enforces this by deriving both from the same `swift.toolchain` tag. """ -# Files in the host toolchain that compile actions need: the driver/frontend -# binaries, their libraries, and clang's builtin headers (used by the clang -# importer when the Swift SDK's resource directory does not bundle them). -_HOST_COMPILER_INPUTS = "swift_sdk_compiler_inputs" - _SWIFT_TOOLCHAIN_TEMPLATE = """ swift_toolchain( name = "swift_toolchain_{suffix}", @@ -135,10 +129,13 @@ this SDK is paired with. ), } -# The architectures the Android Swift SDK provides resources for and that -# `@platforms//cpu` can express. (The SDK also supports armv7, which can be -# added on demand.) -ANDROID_ARCHS = ["aarch64", "x86_64"] +# Mirrored from https://github.com/bazelbuild/rules_android_ndk/blob/27b38742eade7e8000b9ed0f320c9f277a0e89d1/target_systems.bzl.tpl +# Swift doesn't support any other ones +ANDROID_ARCHS = [ + "aarch64", + "armv7", + "x86_64", +] def _swift_android_sdk_impl(repository_ctx): bundle_dir = _download_sdk_bundle(repository_ctx) @@ -151,23 +148,19 @@ def _swift_android_sdk_impl(repository_ctx): "missing {}/{}/swift-sdk.json".format(repo_root, sdk_dir_relative)) lib_dir = "{}/{}/swift-resources/usr/lib".format(repo_root, sdk_dir_relative) - # The Android Swift SDK's resource directories do not bundle clang's - # builtin headers, so the clang importer must be pointed at the host - # toolchain's copy (which matches the clang embedded in swiftc). + # The clang headers are provided by the Swift toolchain, not the Android SDK bundle paired_usr = repository_ctx.path(repository_ctx.attr.paired_swiftc).dirname.dirname clang_versions = paired_usr.get_child("lib", "clang").readdir() if len(clang_versions) != 1: fail("Expected exactly one clang version directory in the host " + "toolchain, found: " + str(clang_versions)) - clang_builtin_headers = _execroot_relative_path( - clang_versions[0].get_child("include"), - ) + clang_builtin_headers = _execroot_relative_path(clang_versions[0].get_child("include")) build_content = _BUILD_HEADER_TEMPLATE.format( bundle_dir = bundle_dir, compiler_inputs = _build_list([ ":sdk_files", - "@{}//:{}".format(toolchain_repo, _HOST_COMPILER_INPUTS), + "@{}//:swift_sdk_compiler_inputs".format(toolchain_repo), ]), toolchain_repo = toolchain_repo, ) @@ -190,30 +183,22 @@ def _swift_android_sdk_impl(repository_ctx): "swift.use_module_wrap", ]), linker_inputs = _build_list([":sdk_files"]), - # The Swift runtime objects/libraries from the SDK's - # `swift_static-{arch}/android/static-stdlib-args.lnk`. We drop that - # file's `-Wl,--exclude-libs,ALL` (it would demote a depended-on - # `swift_library`'s `@_cdecl` JNI exports to local) and add the 16 KiB - # max page size required by Android 15+. + # Swift defines linkopts for android in + # `swift_static-{arch}/android/static-stdlib-args.lnk`, we add the + # ones that matter here removing the ones that rules_android_ndk + # already passes. linkopts = _build_list([ "{}/android/{}/swiftrt.o".format(resource_dir, arch), "-L{}/android".format(resource_dir), - "-ldl", "-llog", - # libc++ as the shared `libc++_shared.so` (the SDK's intended - # linkage). The Android cc toolchain links libc++ statically by - # default (https://github.com/bazelbuild/rules_android_ndk/issues/93), - # which the NDK discourages for a library that may share a process - # with other `.so`s; `-lstdc++` overrides that to the shared - # runtime, which must then be packaged into the APK (see - # `select_android_runtime_lib`). - "-lstdc++", + "-lswiftCore", + "-Wl,-export-dynamic", + "-Wl,--exclude-libs,ALL", + # TODO: Remove once https://github.com/bazelbuild/rules_android_ndk/commit/efc0c191796477c540e87e0f6bb5d88d6a58cc1f is in a release "-Wl,-z,max-page-size=16384", ]), os = "android", - # Empty: the toolchain reads the sysroot from the resolved Android - # C++ cc toolchain (e.g. `@androidndk//:all`) at analysis time. - sdkroot = "", + sdkroot = "", # Resolved in swift_toolchain.bzl suffix = arch, swift_version = repository_ctx.attr.swift_version, ) diff --git a/swift/toolchains/BUILD b/swift/toolchains/BUILD index ef9f4f322..89d84641d 100644 --- a/swift/toolchains/BUILD +++ b/swift/toolchains/BUILD @@ -156,10 +156,3 @@ bzl_library( visibility = ["//visibility:public"], deps = ["//swift:providers"], ) - -bzl_library( - name = "android_runtime_lib", - srcs = ["android_runtime_lib.bzl"], - visibility = ["//visibility:public"], - deps = ["@rules_cc//cc:find_cc_toolchain_bzl"], -) diff --git a/swift/toolchains/android_runtime_lib.bzl b/swift/toolchains/android_runtime_lib.bzl deleted file mode 100644 index ca5161e88..000000000 --- a/swift/toolchains/android_runtime_lib.bzl +++ /dev/null @@ -1,47 +0,0 @@ -"""A rule that selects a single Android NDK runtime library from the toolchain. - -The Swift Android SDK links the NDK's C++ runtime dynamically, so any APK with a -Swift JNI library must also package `libc++_shared.so` (unlike normal NDK C++, -which can statically link libc++). This rule selects it out of the resolved C++ -(cc) toolchain's files, so a consumer can reference it for APK packaging without -naming the NDK repository or build host. Build it for an Android platform so the -Android cc toolchain (e.g. `@androidndk//:all`) is resolved. -""" - -load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") - -def _select_android_runtime_lib_impl(ctx): - cc_toolchain = find_cc_toolchain(ctx) - suffix = "/usr/lib/{}/{}".format(ctx.attr.triple, ctx.attr.basename) - matches = [ - f - for f in cc_toolchain.all_files.to_list() - if f.path.endswith(suffix) - ] - if len(matches) != 1: - fail("Expected exactly one `{}` under `usr/lib/{}` in the Android cc toolchain, found: {}".format( - ctx.attr.basename, - ctx.attr.triple, - [f.path for f in matches], - )) - return [DefaultInfo(files = depset(matches))] - -select_android_runtime_lib = rule( - implementation = _select_android_runtime_lib_impl, - attrs = { - "basename": attr.string( - default = "libc++_shared.so", - doc = "The runtime library file name to select.", - ), - "triple": attr.string( - mandatory = True, - doc = "The Android target triple, e.g. `aarch64-linux-android`.", - ), - }, - toolchains = use_cc_toolchain(), - doc = """\ -Selects a single runtime library (by default `libc++_shared.so`) for an Android -target triple out of the resolved C++ toolchain's files, exposing it as a -one-file target for APK packaging. Build it for an Android platform. -""", -) diff --git a/swift/toolchains/swift_toolchain.bzl b/swift/toolchains/swift_toolchain.bzl index f2a83765b..02792563e 100644 --- a/swift/toolchains/swift_toolchain.bzl +++ b/swift/toolchains/swift_toolchain.bzl @@ -474,35 +474,6 @@ def _swift_sdk_linkopts_cc_info( ), ) -def _swift_android_linkopts_cc_info(ctx, cc_toolchain, sdkroot): - """Returns a `CcInfo` with the Android Swift runtime link flags. - - The binary link runs through `cc_common.link` with the resolved Android cc - toolchain, but rules_android_ndk's toolchain reports its sysroot as the clang - directory and exposes an empty `dynamic_runtime_lib`, so the real sysroot is - never passed and `libc++_shared.so` (which the NDK clang links by default) is - never staged. Add both ourselves, on top of the SDK's `linkopts`/`linker_inputs`. - - Args: - ctx: The toolchain rule context. - cc_toolchain: The resolved Android C++ `CcToolchainInfo`. - sdkroot: The Android sysroot derived from the cc toolchain. - - Returns: - A `CcInfo` propagating the Android runtime link flags and inputs. - """ - linkopts = list(ctx.attr.linkopts) - linker_inputs = list(ctx.files.linker_inputs) - if sdkroot: - linkopts.append("--sysroot=" + sdkroot) - libcxx_suffix = "/usr/lib/{}-linux-android/libc++_shared.so".format(ctx.attr.arch) - linker_inputs = linker_inputs + [ - f - for f in cc_toolchain.all_files.to_list() - if f.path.endswith(libcxx_suffix) - ] - return _swift_sdk_linkopts_cc_info(ctx.label, linkopts, linker_inputs) - def _entry_point_linkopts_provider(*, entry_point_name): """Returns linkopts to customize the entry point of a binary.""" return struct( @@ -589,7 +560,13 @@ def _swift_toolchain_impl(ctx): elif ctx.attr.os == "none": swift_linkopts_cc_info = CcInfo() elif ctx.attr.os == "android": - swift_linkopts_cc_info = _swift_android_linkopts_cc_info(ctx, cc_toolchain, sdkroot) + if not sdkroot: + fail("Android toolchain requires a sysroot to be set, either via the `sdkroot` attribute or by using a CC toolchain that provides one.") + swift_linkopts_cc_info = _swift_sdk_linkopts_cc_info( + ctx.label, + ["--sysroot={}".format(sdkroot)] + ctx.attr.linkopts, + ctx.files.linker_inputs, + ) elif ctx.attr.linkopts or ctx.attr.linker_inputs: # A toolchain whose Swift runtime comes from a Swift SDK (e.g. # WebAssembly) provides the *complete* set of runtime link flags via @@ -601,8 +578,8 @@ def _swift_toolchain_impl(ctx): # second `swiftrt.o` would conflict with the SDK's own). swift_linkopts_cc_info = _swift_sdk_linkopts_cc_info( ctx.label, - list(ctx.attr.linkopts), - list(ctx.files.linker_inputs), + ctx.attr.linkopts, + ctx.files.linker_inputs, ) else: swift_linkopts_cc_info = _swift_unix_linkopts_cc_info( diff --git a/test/android_tests.bzl b/test/android_tests.bzl index f079b9b1c..7217e4521 100644 --- a/test/android_tests.bzl +++ b/test/android_tests.bzl @@ -1,22 +1,18 @@ -"""Tests that the Android Swift SDK toolchain links through the NDK cc toolchain -with the right target triple.""" +"""Test building for android.""" load( "//test/rules:action_command_line_test.bzl", "make_action_command_line_test_rule", ) load( - "//test/rules:action_inputs_test.bzl", - "make_action_inputs_test_rule", + "//test/rules:android_validation_test.bzl", + "android_apk_contents_test", + "android_so_abi_test", ) -# Build the target under test for Android (the SDK toolchain + the NDK cc -# toolchain resolve from these constraints). The platform label is resolved to -# its canonical form here so the transition (applied in the analysistest rule's -# own repository) still points at this repository's fixture. _ANDROID_CONFIG = { "//command_line_option:platforms": [ - str(Label("//test/fixtures/android:android_arm64")), + str(Label("@rules_android//:arm64-v8a")), ], } @@ -24,54 +20,59 @@ android_command_line_test = make_action_command_line_test_rule( config_settings = _ANDROID_CONFIG, ) -android_inputs_test = make_action_inputs_test_rule( - config_settings = _ANDROID_CONFIG, -) - -def android_test_suite(name, tags = []): +def android_test_suite(name): """Test suite for the Android Swift SDK toolchain's compile/link actions. Args: name: The base name to be used in targets created by this macro. - tags: Additional tags to apply to each test. """ - all_tags = [name] + tags + all_tags = [name] - # The Swift compile targets the Android triple. + # The Swift compile targets Android android_command_line_test( name = "{}_swiftcompile_targets_android".format(name), expected_argv = ["-target aarch64-linux-android"], mnemonic = "SwiftCompile", tags = all_tags, - target_compatible_with = ["@platforms//os:macos"], target_under_test = "//test/fixtures/android:jni_lib", ) - # The link runs the NDK clang for the Android target (the `28` is the - # `android.ndk(api_level = ...)` from MODULE.bazel), against the NDK sysroot, - # and links libc++ as the shared `libc++_shared.so`. android_command_line_test( name = "{}_link_uses_ndk".format(name), expected_argv = [ "--target=aarch64-linux-android28", "--sysroot", - "-lstdc++", + "-ldl", # Comes from rules_android_ndk + "-lm", # Comes from rules_android_ndk + "-lc", # Comes from rules_android_ndk + "-llog", # This is a dependency of the Swift SDK + "-Wl,-z,max-page-size=16384", # Comes from rules_android_ndk + "-Wl,--gc-sections", # Comes from rules_android_ndk ], mnemonic = "CppLink", tags = all_tags, - target_compatible_with = ["@platforms//os:macos"], target_under_test = "//test/fixtures/android:jni_lib", ) - # The NDK's libc++_shared.so is staged into the link so a downstream APK can - # package it next to the Swift `.so`. - android_inputs_test( - name = "{}_link_stages_libcxx_shared".format(name), - expected_inputs = ["libc++_shared.so"], - mnemonic = "CppLink", + android_so_abi_test( + name = "{}_jni_lib_abi".format(name), + apk = "//test/fixtures/android:app.apk", + jni_symbol = "Java_com_example_Fixture_value", + needed_libraries = ["liblog.so"], + not_needed_libraries = ["libc++_shared.so"], + shared_library = "lib/arm64-v8a/libjni_lib.so", + tags = all_tags, + ) + + android_apk_contents_test( + name = "{}_apk_contents".format(name), + apk = "//test/fixtures/android:app.apk", + expected_entries = [ + "AndroidManifest.xml", + "classes.dex", + "lib/arm64-v8a/libjni_lib.so", + ], tags = all_tags, - target_compatible_with = ["@platforms//os:macos"], - target_under_test = "//test/fixtures/android:jni_lib", ) native.test_suite( diff --git a/test/fixtures/android/AndroidManifest.xml b/test/fixtures/android/AndroidManifest.xml new file mode 100644 index 000000000..9193f226e --- /dev/null +++ b/test/fixtures/android/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/test/fixtures/android/BUILD b/test/fixtures/android/BUILD index ff1152c70..d618554e6 100644 --- a/test/fixtures/android/BUILD +++ b/test/fixtures/android/BUILD @@ -1,28 +1,40 @@ +load("@rules_android//rules:rules.bzl", "android_binary", "android_library") +load("@rules_cc//cc:defs.bzl", "cc_library") load("//swift:swift_binary.bzl", "swift_binary") load("//test/fixtures:common.bzl", "FIXTURE_TAGS") licenses(["notice"]) -package( - default_visibility = ["//test:__subpackages__"], -) - -# The platform the analysis tests transition the JNI library to. Its -# constraints (os:android + cpu:arm64, an alias of aarch64) resolve the Android -# Swift SDK toolchain and the Android cc toolchain. -platform( - name = "android_arm64", - constraint_values = [ - "@platforms//cpu:arm64", - "@platforms//os:android", - ], -) +package(default_visibility = ["//test:__subpackages__"]) -# A JNI shared library built by the Android Swift SDK toolchain; the tests -# inspect its compile/link actions. swift_binary( name = "jni_lib", srcs = ["jni.swift"], linkshared = True, tags = FIXTURE_TAGS, ) + +cc_library( + name = "jni_lib_native", + srcs = [":jni_lib"], + tags = FIXTURE_TAGS, + target_compatible_with = ["@platforms//os:android"], +) + +android_library( + name = "app_lib", + srcs = ["java/com/example/FixtureActivity.java"], + custom_package = "com.example", + manifest = "AndroidManifest.xml", + tags = FIXTURE_TAGS, +) + +android_binary( + name = "app", + manifest = "AndroidManifest.xml", + tags = FIXTURE_TAGS, + deps = [ + ":app_lib", + ":jni_lib_native", + ], +) diff --git a/test/fixtures/android/java/com/example/FixtureActivity.java b/test/fixtures/android/java/com/example/FixtureActivity.java new file mode 100644 index 000000000..b715384cd --- /dev/null +++ b/test/fixtures/android/java/com/example/FixtureActivity.java @@ -0,0 +1,11 @@ +package com.example; + +import android.app.Activity; +import android.os.Bundle; + +public final class FixtureActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } +} diff --git a/test/fixtures/android/jni.swift b/test/fixtures/android/jni.swift index 688a0e8ba..3ba2d04df 100644 --- a/test/fixtures/android/jni.swift +++ b/test/fixtures/android/jni.swift @@ -1,11 +1,4 @@ -// A trivial JNI entry point used by the Android toolchain analysis tests. The -// raw-pointer parameters and `Int32` return keep it free of any platform- -// specific JNI module import, so it builds for Android with only the SDK -// toolchain registered. @_cdecl("Java_com_example_Fixture_value") -public func value( - _: UnsafeMutableRawPointer?, - _: UnsafeMutableRawPointer? -) -> Int32 { +public func value(_: UnsafeMutableRawPointer?, _: UnsafeMutableRawPointer?) -> Int32 { return 42 } diff --git a/test/rules/BUILD b/test/rules/BUILD index 8d7557309..53432b86f 100644 --- a/test/rules/BUILD +++ b/test/rules/BUILD @@ -1,3 +1,7 @@ package(default_visibility = ["//test:__subpackages__"]) -exports_files(["swift_shell_runner.sh.template"]) +exports_files([ + "android_apk_contents_test.sh", + "android_so_abi_test.sh", + "swift_shell_runner.sh.template", +]) diff --git a/test/rules/android_apk_contents_test.sh b/test/rules/android_apk_contents_test.sh new file mode 100755 index 000000000..920e0b2d7 --- /dev/null +++ b/test/rules/android_apk_contents_test.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# --- begin runfiles.bash initialization v3 --- +set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; +# --- end runfiles.bash initialization v3 --- + +set -euo pipefail + +apk="$(rlocation "${ANDROID_APK:?}")" +zipper="$(rlocation "${ANDROID_ZIPPER:?}")" + +listing="$("$zipper" v "$apk")" +while IFS= read -r entry; do + [[ -n "$entry" ]] || continue + case "$listing" in + *"$entry"*) ;; + *) echo "error: APK is missing $entry" >&2; exit 1 ;; + esac +done <<< "${ANDROID_EXPECTED_ENTRIES:?}" diff --git a/test/rules/android_so_abi_test.sh b/test/rules/android_so_abi_test.sh new file mode 100755 index 000000000..736826c1f --- /dev/null +++ b/test/rules/android_so_abi_test.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# --- begin runfiles.bash initialization v3 --- +set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ + source "$0.runfiles/$f" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ + { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; +# --- end runfiles.bash initialization v3 --- + +set -euo pipefail + +readelf="$(rlocation "${ANDROID_READELF:?}")" +nm="$(rlocation "${ANDROID_NM:?}")" +apk="$(rlocation "${ANDROID_APK:?}")" +zipper="$(rlocation "${ANDROID_ZIPPER:?}")" +shared_library="${ANDROID_SHARED_LIBRARY:?}" +jni_symbol="${ANDROID_JNI_SYMBOL:?}" + +tmp_dir="$(mktemp -d)" +trap 'rm -rf "$tmp_dir"' EXIT +(cd "$tmp_dir" && "$zipper" x "$apk" "$shared_library") +so="$tmp_dir/$shared_library" + +header="$("$readelf" -h "$so")" +case "$header" in + *AArch64*) ;; + *) echo "error: $so is not an AArch64 ELF" >&2; exit 1 ;; +esac + +dynsyms="$("$nm" -D --defined-only "$so")" +case "$dynsyms" in + *"$jni_symbol"*) ;; + *) echo "error: JNI symbol $jni_symbol is not exported by $so" >&2; exit 1 ;; +esac + +dynamic="$("$readelf" -d "$so")" +while IFS= read -r library; do + [[ -n "$library" ]] || continue + case "$dynamic" in + *"Shared library: [$library]"*) ;; + *) echo "error: $so does not list $library in NEEDED" >&2; exit 1 ;; + esac +done <<< "${ANDROID_NEEDED_LIBRARIES:-}" + +while IFS= read -r library; do + [[ -n "$library" ]] || continue + case "$dynamic" in + *"Shared library: [$library]"*) echo "error: $so unexpectedly lists $library in NEEDED" >&2; exit 1 ;; + *) ;; + esac +done <<< "${ANDROID_NOT_NEEDED_LIBRARIES:-}" diff --git a/test/rules/android_validation_test.bzl b/test/rules/android_validation_test.bzl new file mode 100644 index 000000000..bd7d7cf5a --- /dev/null +++ b/test/rules/android_validation_test.bzl @@ -0,0 +1,162 @@ +"""Android build artifact validation tests.""" + +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") + +def _android_transition_impl(_settings, _attr): + return {"//command_line_option:platforms": "@rules_android//:arm64-v8a"} + +_android_transition = transition( + implementation = _android_transition_impl, + inputs = [], + outputs = ["//command_line_option:platforms"], +) + +def _rlocationpath(ctx, label, targets): + return ctx.expand_location( + "$(rlocationpath {})".format(label), + targets = targets, + ) + +def _toolchain_file_runfiles_path(ctx, file): + short_path = file.short_path + if short_path.startswith("../"): + return short_path[3:] + return "{}/{}".format(ctx.workspace_name, short_path) + +def _find_tool(cc_toolchain, basename): + for f in cc_toolchain.all_files.to_list(): + if f.basename == basename: + return f + fail("{} was not found in the resolved Android cc toolchain.".format(basename)) + +def _android_so_abi_test_impl(ctx): + cc_toolchain = ctx.attr._cc_toolchain[0][cc_common.CcToolchainInfo] + nm = _find_tool(cc_toolchain, "llvm-nm") + readelf = _find_tool(cc_toolchain, "llvm-readelf") + + executable = ctx.actions.declare_file(ctx.label.name) + ctx.actions.symlink( + output = executable, + target_file = ctx.file._runner_script, + is_executable = True, + ) + + return [ + DefaultInfo( + executable = executable, + runfiles = ctx.runfiles( + files = [ctx.file.apk, ctx.file._runner_script, ctx.executable._zipper], + transitive_files = cc_toolchain.all_files, + ).merge_all([ + ctx.attr._runfiles.default_runfiles, + ctx.attr._zipper.default_runfiles, + ]), + ), + testing.TestEnvironment({ + "ANDROID_APK": _rlocationpath(ctx, ctx.attr.apk[0].label, ctx.attr.apk), + "ANDROID_JNI_SYMBOL": ctx.attr.jni_symbol, + "ANDROID_NEEDED_LIBRARIES": "\n".join(ctx.attr.needed_libraries), + "ANDROID_NM": _toolchain_file_runfiles_path(ctx, nm), + "ANDROID_NOT_NEEDED_LIBRARIES": "\n".join(ctx.attr.not_needed_libraries), + "ANDROID_READELF": _toolchain_file_runfiles_path(ctx, readelf), + "ANDROID_SHARED_LIBRARY": ctx.attr.shared_library, + "ANDROID_ZIPPER": _rlocationpath(ctx, ctx.attr._zipper.label, [ctx.attr._zipper]), + }), + ] + +android_so_abi_test = rule( + implementation = _android_so_abi_test_impl, + attrs = { + "apk": attr.label( + allow_single_file = [".apk"], + cfg = _android_transition, + mandatory = True, + doc = "The APK containing the JNI library to inspect.", + ), + "jni_symbol": attr.string( + mandatory = True, + doc = "The JNI entry point expected in the shared library's dynamic symbols.", + ), + "needed_libraries": attr.string_list( + doc = "Shared library names expected in the ELF dynamic NEEDED entries.", + ), + "not_needed_libraries": attr.string_list( + doc = "Shared library names not expected in the ELF dynamic NEEDED entries.", + ), + "_cc_toolchain": attr.label( + cfg = _android_transition, + default = "@rules_cc//cc:current_cc_toolchain", + ), + "shared_library": attr.string( + mandatory = True, + doc = "The APK entry path of the JNI shared library to inspect.", + ), + "_runfiles": attr.label( + default = "@bazel_tools//tools/bash/runfiles", + ), + "_runner_script": attr.label( + allow_single_file = True, + default = "//test/rules:android_so_abi_test.sh", + ), + "_zipper": attr.label( + default = "@bazel_tools//tools/zip:zipper", + executable = True, + cfg = "exec", + ), + }, + test = True, +) + +def _android_apk_contents_test_impl(ctx): + executable = ctx.actions.declare_file(ctx.label.name) + ctx.actions.symlink( + output = executable, + target_file = ctx.file._runner_script, + is_executable = True, + ) + + return [ + DefaultInfo( + executable = executable, + runfiles = ctx.runfiles( + files = [ctx.file.apk, ctx.file._runner_script, ctx.executable._zipper], + ).merge_all([ + ctx.attr._runfiles.default_runfiles, + ctx.attr._zipper.default_runfiles, + ]), + ), + testing.TestEnvironment({ + "ANDROID_APK": _rlocationpath(ctx, ctx.attr.apk[0].label, ctx.attr.apk), + "ANDROID_EXPECTED_ENTRIES": "\n".join(ctx.attr.expected_entries), + "ANDROID_ZIPPER": _rlocationpath(ctx, ctx.attr._zipper.label, [ctx.attr._zipper]), + }), + ] + +android_apk_contents_test = rule( + implementation = _android_apk_contents_test_impl, + attrs = { + "apk": attr.label( + allow_single_file = [".apk"], + cfg = _android_transition, + mandatory = True, + doc = "The APK whose entries to assert.", + ), + "expected_entries": attr.string_list( + mandatory = True, + doc = "Zip entry paths that must be present in the APK.", + ), + "_runfiles": attr.label( + default = "@bazel_tools//tools/bash/runfiles", + ), + "_runner_script": attr.label( + allow_single_file = True, + default = "//test/rules:android_apk_contents_test.sh", + ), + "_zipper": attr.label( + default = "@bazel_tools//tools/zip:zipper", + executable = True, + cfg = "exec", + ), + }, + test = True, +) diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc index 9e8e91a61..89ee3952a 100644 --- a/tools/worker/swift_runner.cc +++ b/tools/worker/swift_runner.cc @@ -587,18 +587,10 @@ bool SwiftRunner::ProcessArgument( consumer(std::filesystem::current_path().string() + "=" + new_path); #if __APPLE__ - // The developer-directory remap only applies to toolchains that use the - // Apple developer directory. A cross-compile (e.g. to Android) running on a - // macOS host has no DEVELOPER_DIR; skip the remap rather than hard-failing, - // keeping the working-directory remap above so file_prefix_map stays - // hermetic for those targets. - const char* developer_dir_env = std::getenv("DEVELOPER_DIR"); - if (developer_dir_env != nullptr && developer_dir_env[0] != '\0') { - std::string developer_dir = "__BAZEL_XCODE_DEVELOPER_DIR__"; - if (bazel_placeholder_substitutions_.Apply(developer_dir)) { - consumer(flag); - consumer(developer_dir + "=/PLACEHOLDER_DEVELOPER_DIR"); - } + std::string developer_dir = "__BAZEL_XCODE_DEVELOPER_DIR__"; + if (bazel_placeholder_substitutions_.Apply(developer_dir)) { + consumer(flag); + consumer(developer_dir + "=/PLACEHOLDER_DEVELOPER_DIR"); } #endif };