Files
IronStorage/android/rust-bridge/build.gradle.kts
T
hugo e6488b5604
Android ARM verification / rust (push) Failing after 8s
Android ARM verification / android (push) Failing after 7s
Establish native Linux ARM64 Android CI and verification gates (#94)
2026-10-09 00:12:57 +02:00

191 lines
7.7 KiB
Kotlin

import java.io.File
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.android.library)
}
android {
namespace = "de.rfc1437.ironstorage.rustbridge"
compileSdk = libs.versions.compileSdk.get().toInt()
ndkVersion = libs.versions.ndk.get()
defaultConfig {
minSdk = libs.versions.minSdk.get().toInt()
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") }
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
defaultConfig { consumerProguardFiles("consumer-rules.pro") }
lint {
abortOnError = true
warningsAsErrors = true
// The user scoped this milestone to ARM Android; x86 ChromeOS is excluded.
disable += "ChromeOsAbiSupport"
}
}
kotlin {
jvmToolchain(25)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
allWarningsAsErrors.set(true)
}
}
dependencies {
implementation(variantOf(libs.jna) { artifactType("aar") })
implementation(libs.annotation)
testImplementation(libs.junit)
androidTestImplementation(libs.android.test.runner)
}
val workspace = rootProject.layout.projectDirectory.dir("..").asFile
val cargoExecutable = providers.environmentVariable("CARGO").orElse(
providers.environmentVariable("PATH").map { path ->
path.split(File.pathSeparatorChar).map { File(it, "cargo") }
.firstOrNull { it.isFile && it.canExecute() }?.absolutePath
?: error("Cargo must be installed and in PATH")
}
)
val rustVersion = libs.versions.rust.get()
val rustcExecutable = providers.exec {
commandLine("rustup", "which", "--toolchain", rustVersion, "rustc")
}.standardOutput.asText.map { it.trim() }
val ndkDirectory = androidComponents.sdkComponents.ndkDirectory
val sdkDirectory = androidComponents.sdkComponents.sdkDirectory
val rustInputs = files(
workspace.resolve("Cargo.toml"),
workspace.resolve("Cargo.lock"),
rootProject.file("rust-toolchain.toml"),
fileTree(workspace.resolve("crates")) { include("**/*.rs", "**/Cargo.toml", "**/uniffi.toml") }
)
val checkRustToolchain = tasks.register<Exec>("checkRustToolchain") {
workingDir = workspace
commandLine(
cargoExecutable.get(), "+$rustVersion", "run", "--locked",
"--package", "ironstorage-android-build", "--", "check-toolchain",
cargoExecutable.get(), rustVersion, ndkDirectory.get().asFile.absolutePath,
libs.versions.ndk.get(), libs.versions.cargoNdk.get()
)
}
androidComponents.onVariants { variant ->
val name = variant.name
val title = name.replaceFirstChar { it.uppercaseChar() }
val rawNative = layout.buildDirectory.dir("generated/native-raw/$name/jniLibs")
val nativeOutput = layout.buildDirectory.dir("generated/native/$name/jniLibs")
val rawBindings = layout.buildDirectory.dir("generated/bindings-raw/$name")
val bindings = layout.buildDirectory.dir("generated/bindings/$name")
val rustFlags = listOf(
"-D warnings",
"-C link-arg=-Wl,-z,max-page-size=16384",
"-C link-arg=-Wl,-z,common-page-size=16384",
"-C link-arg=-Wl,--build-id=sha1"
).joinToString(" ")
val native = tasks.register<Exec>("build${title}Rust") {
dependsOn(checkRustToolchain)
workingDir = workspace
inputs.files(rustInputs)
inputs.property("rustVersion", rustVersion)
inputs.property("cargoNdk", libs.versions.cargoNdk.get())
inputs.property("ndkVersion", libs.versions.ndk.get())
inputs.property("minSdk", libs.versions.minSdk.get())
inputs.property("rustFlags", rustFlags)
inputs.property("abis", listOf("arm64-v8a", "armeabi-v7a"))
inputs.property("releaseDebug", "2")
inputs.property(
"devDebug",
providers.environmentVariable("CARGO_PROFILE_DEV_DEBUG").orElse("cargo-default")
)
inputs.property(
"incremental",
providers.environmentVariable("CARGO_INCREMENTAL").orElse("cargo-default")
)
inputs.property(
"cargoTargetDirectory",
providers.environmentVariable("CARGO_TARGET_DIR").orElse("workspace-default")
)
outputs.dir(rawNative)
environment("RUSTUP_TOOLCHAIN", rustVersion)
environment("RUSTC", rustcExecutable.get())
environment("ANDROID_NDK_HOME", ndkDirectory.get().asFile.absolutePath)
environment("ANDROID_HOME", sdkDirectory.get().asFile.absolutePath)
environment("RUSTFLAGS", rustFlags)
environment("CARGO_PROFILE_RELEASE_DEBUG", "2")
commandLine(
listOf(
cargoExecutable.get(), "+$rustVersion", "ndk",
"--target", "arm64-v8a",
"--target", "armeabi-v7a",
"--platform", libs.versions.minSdk.get(),
"--output-dir", rawNative.get().asFile.absolutePath,
"build", "--locked", "--package", "ironstorage-android", "--lib"
) +
if (variant.buildType == "release") listOf("--release") else emptyList()
)
}
val audit = tasks.register<Exec>("package${title}Rust") {
dependsOn(native)
workingDir = workspace
inputs.dir(rawNative)
inputs.files(
fileTree(workspace.resolve("tools/android-build")) {
include("**/*.rs", "Cargo.toml")
}
)
outputs.dir(nativeOutput)
commandLine(
cargoExecutable.get(), "+$rustVersion", "run", "--locked",
"--package", "ironstorage-android-build", "--", "package-native",
rawNative.get().asFile.absolutePath, nativeOutput.get().asFile.absolutePath
)
}
val generate = tasks.register<Exec>("generate${title}RustBindings") {
dependsOn(audit)
workingDir = workspace
inputs.dir(nativeOutput)
inputs.file(rootProject.file("uniffi.toml"))
inputs.files(
fileTree(workspace.resolve("tools/android-build")) {
include("**/*.rs", "Cargo.toml")
}
)
outputs.dir(rawBindings)
commandLine(
cargoExecutable.get(), "+$rustVersion", "run", "--locked",
"--package", "ironstorage-android-build", "--", "contract-bindings",
nativeOutput.get().file("arm64-v8a/libironstorage_android.so").asFile.absolutePath,
rootProject.file("uniffi.toml").absolutePath,
rawBindings.get().asFile.absolutePath, "phone"
)
}
val prepare = tasks.register<Exec>("prepare${title}RustBindings") {
dependsOn(generate)
workingDir = workspace
inputs.dir(rawBindings)
inputs.files(
fileTree(workspace.resolve("tools/android-build")) {
include("**/*.rs", "Cargo.toml")
}
)
outputs.dir(bindings)
commandLine(
cargoExecutable.get(), "+$rustVersion", "run", "--locked",
"--package", "ironstorage-android-build", "--", "prepare-bindings",
rawBindings.get().dir("kotlin").asFile.absolutePath, bindings.get().asFile.absolutePath
)
}
variant.sources.kotlin!!.addStaticSourceDirectory(bindings.get().asFile.absolutePath)
variant.sources.jniLibs!!.addStaticSourceDirectory(nativeOutput.get().asFile.absolutePath)
tasks.matching {
it.name == "pre${title}Build" || it.name == "compile${title}Kotlin"
}.configureEach { dependsOn(prepare) }
}
// Instrumentation suites share persistent emulators and must not compete for input focus.
tasks.matching { it.name == "connectedDebugAndroidTest" }.configureEach {
mustRunAfter(":app:connectedDebugAndroidTest")
}