mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 11:18:24 +00:00
Merge branch 'main' into claude/elegant-lovelace-3qfhpj
main landed the other half of the Arti packaging story (#4142): :amethyst now pins ndkVersion from ANDROID_NDK_VERSION and excludes libarti_android.so from AGP's llvm-strip pass. Both changes touch the same three files and compose cleanly — that exclusion is a glob, so the two new 32-bit libraries reach the APK unrewritten exactly like the existing pair, and their byte-for-byte-vs-committed claim now covers four ABIs. Only BUILDING.md conflicted: both sides appended a paragraph after the "not required to build from the committed sources" note. Kept both, with main's NDK prose first (it continues that paragraph) and the one-library- per-ABI-split callout after it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MX1p385SiQMd2Lhkbg2YKc
This commit is contained in:
+12
@@ -109,6 +109,18 @@ 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.
|
||||
AGP strips every native library it packages with the NDK's `llvm-strip`, so
|
||||
`:amethyst` sets `ndkVersion` from `ANDROID_NDK_VERSION` — one revision for the
|
||||
libraries we build and the ones we merge from dependencies. `libarti_android.so`
|
||||
is then excluded from that strip step (`packaging.jniLibs.keepDebugSymbols`):
|
||||
the Cargo release profile already stripped it, and llvm-strip would only rewrite
|
||||
its `.comment` stamps, so skipping the pass costs no size and lets the `.so`
|
||||
inside an APK be compared byte-for-byte against the committed, independently
|
||||
reproducible one. The Rust toolchain stays irrelevant either way; Studio/AGP
|
||||
fetches the pinned NDK on demand, or pre-install it with
|
||||
`sdkmanager "ndk;$(cat tools/arti-build/ANDROID_NDK_VERSION)"`.
|
||||
|
||||
> **One Arti library per ABI split.** The APK is split four ways (`arm64-v8a`,
|
||||
> `x86_64`, `armeabi-v7a`, `x86`) and every split needs its own
|
||||
> `libarti_android.so`; a split without one installs and runs with Tor silently
|
||||
|
||||
@@ -82,6 +82,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 =
|
||||
@@ -303,6 +326,22 @@ android {
|
||||
resources {
|
||||
excludes += listOf("/META-INF/{AL2.0,LGPL2.1}", "**/libscrypt.dylib")
|
||||
}
|
||||
|
||||
jniLibs {
|
||||
// Reproducible builds, part two: ship the Arti library exactly as
|
||||
// tools/arti-build produced it. Its Cargo release profile already
|
||||
// strips it (no .symtab, no .debug_*), so AGP's
|
||||
// `llvm-strip --strip-unneeded` pass has nothing left to remove — but it
|
||||
// still rewrites the file: llvm-strip rebuilds .comment, the section that
|
||||
// records the rustc / clang / lld version stamps, which measurably changes
|
||||
// 273 bytes on arm64-v8a. That made the packaged bytes a function of
|
||||
// whichever NDK did the stripping, so the .so in an APK could never be
|
||||
// compared against the committed, independently reproducible one.
|
||||
// Excluding it from the strip step costs nothing in size (there are no
|
||||
// symbols to drop) and makes that comparison exact. Dependency .so files
|
||||
// are still stripped, with the NDK pinned by ndkVersion above.
|
||||
keepDebugSymbols += "**/libarti_android.so"
|
||||
}
|
||||
}
|
||||
|
||||
lint {
|
||||
|
||||
@@ -49,6 +49,24 @@ 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 every native library it packages — the toolchain that strips
|
||||
> a 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.
|
||||
>
|
||||
> **`libarti_android.so` skips that strip step.** The release profile here
|
||||
> already strips it — no `.symtab`, no `.debug_*` — so `llvm-strip
|
||||
> --strip-unneeded` has nothing to remove and only rebuilds `.comment`, the
|
||||
> section carrying the rustc/clang/lld stamps (273 bytes change on arm64-v8a).
|
||||
> `packaging.jniLibs.keepDebugSymbols` in `amethyst/build.gradle.kts` therefore
|
||||
> excludes it, which costs no APK size and means the library inside a built APK
|
||||
> is byte-identical to the one committed in `src/main/jniLibs/`: `unzip -p
|
||||
> app.apk lib/arm64-v8a/libarti_android.so | sha256sum` can be checked straight
|
||||
> against the file this script reproduces.
|
||||
|
||||
`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
|
||||
|
||||
Reference in New Issue
Block a user