diff --git a/BUILDING.md b/BUILDING.md index 7d323ba5ab..75e494c156 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -109,6 +109,15 @@ Rust toolchain + the exact Android NDK revision pinned in `tools/arti-build/ANDROID_NDK_VERSION` for Arti) documented in their READMEs — they are **not** required to build Amethyst from the committed sources. +The NDK half of that Arti pin does reach the ordinary Android build, though: +`:amethyst` sets `ndkVersion` from `ANDROID_NDK_VERSION`, because AGP strips +the committed `.so` with the NDK's `llvm-strip` while packaging the APK. The +Rust toolchain stays irrelevant, but Studio/AGP will fetch that NDK revision +(`sdkmanager "ndk;$(cat tools/arti-build/ANDROID_NDK_VERSION)"` to pre-install +it). Without any NDK the build still succeeds — AGP warns and packages the +library unstripped, which is fine to run but no longer byte-comparable to a +release APK. + --- ## Per-format build commands diff --git a/amethyst/build.gradle.kts b/amethyst/build.gradle.kts index d1b79c98ff..0a5e8778a2 100644 --- a/amethyst/build.gradle.kts +++ b/amethyst/build.gradle.kts @@ -74,6 +74,29 @@ android { .get() .toInt() + // Packaging toolchain: AGP runs the NDK's llvm-strip over everything that + // lands in jniLibs — our committed libarti_android.so included — so the + // NDK revision is a build input for the APK, not just for whoever compiles + // Arti. Left unset it silently follows AGP's own default (28.2.13676358 on + // AGP 9.4.0), which moves with every AGP bump and is a different toolchain + // from the one that produced the .so, while a machine with no NDK at all + // packages the library unstripped ("Unable to strip the following + // libraries") — three different APKs from the same source, which is + // exactly what F-Droid's rebuild verification cannot have. + // + // Read straight from the Arti pin rather than copied into the version + // catalog: the two can then never drift, and bumping ANDROID_NDK_VERSION + // (which also means rebuilding the .so) moves the packaging toolchain with + // it. See tools/arti-build/README.md → "Reproducible builds". + ndkVersion = + providers + .fileContents(layout.settingsDirectory.file("tools/arti-build/ANDROID_NDK_VERSION")) + .asText + .orNull + ?.trim() + ?.takeIf { it.isNotEmpty() } + ?: error("tools/arti-build/ANDROID_NDK_VERSION is missing or empty — it pins the NDK that strips src/main/jniLibs") + defaultConfig { applicationId = "com.vitorpamplona.amethyst" minSdk = diff --git a/tools/arti-build/README.md b/tools/arti-build/README.md index 492724db5e..d6322e7a6b 100644 --- a/tools/arti-build/README.md +++ b/tools/arti-build/README.md @@ -49,6 +49,14 @@ committed binary wasn't tampered with. **Five** things have to be fixed: > pinned output was verified with. `cargo-ndk` only wraps the NDK, so a mismatch > is a warning rather than an error — but it is the next thing to check if your > rebuild does not match. +> +> **The app build reads this pin too.** `amethyst/build.gradle.kts` sets +> `ndkVersion` from `ANDROID_NDK_VERSION`, because AGP runs the NDK's +> `llvm-strip` over `src/main/jniLibs/` while packaging — the toolchain that +> strips the library is as much an APK input as the one that compiled it. Unset, +> `ndkVersion` follows AGP's own default (r28 on AGP 9.4.0) and moves with every +> AGP bump. So bumping this file changes what packagers need installed, not only +> what rebuilders need: bump it, rebuild the `.so`, and commit both. `repro-env.sh` (sourced by both build scripts) also sets `CARGO_INCREMENTAL=0` and a fixed `SOURCE_DATE_EPOCH` derived from the Arti tag. The size-optimized