nandi/frqpublic Fork 0
7434fee
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Ship the APK smaller: strip the libraries, pack the image

69 MB for a debug sideload, and about a third of it was never going to
be read on the phone. Two changes, both in the packaging rather than in
what it packages.

The libraries are stripped as they are staged. Everything the loader and
jolt_main.c's dlsym registration need is in .dynsym; .symtab and the
debug sections are for a debugger, and there is none on the phone. Worth
20 MB, nearly all of it libjoltmoq and libc++_shared — jolt-native's
release does not strip, and the NDK's libc++ carries its whole symbol
table. It happens here so the derivations keep handing whole objects to
whoever builds `.#libjoltapp` to look at one.

The boot image is written with gzip at maximum instead of lz4 at its
fastest, which is another 2.3 MB. It was already compressed — the
uncompressed-looking size was lz4 doing very little — so this is packing
harder, not packing at last. The kernel that reads it back has zlib
already, chezAndroid being configured ZLIB=-lz, so nothing extra ships.

47 MB now. What is left is two objects that will not strip further: the
boot image is jolt, glimmer and frq compiled flat, and libjoltmoq is
10.7 MB of codec .text built in another repo, where opt-level and LTO
live.

Launched on a Pixel 6a: the image decompresses, Chez boots, the media
plane comes up and it dials out. A call was not carried over it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-01T00:12:09-07:00 Browse files
7434fee parent: 5129987
modified nix/android.nix +26 -0
@@ -205,6 +205,18 @@ let
205205 (load "${xpatch}")
206206 (optimize-level 2)
207207 (generate-inspector-information #f)
208+ ;; Packed harder, not packed for the first time: fasl output is
209+ ;; compressed already, but with lz4 at its fastest setting, and on
210+ ;; this image that leaves 2.3 MB on the table. What reads it back is
211+ ;; the kernel linked into libjoltapp, which has zlib because
212+ ;; chezAndroid is configured ZLIB=-lz so nothing extra ships to
213+ ;; decompress it.
214+ ;;
215+ ;; Less than the ratio of the whole file suggests (15.9 MB to 13.6):
216+ ;; compression is per fasl entry rather than over the image.
217+ (fasl-compressed #t)
218+ (compress-format 'gzip)
219+ (compress-level 'maximum)
208220 (compile-file "$PWD/project/app.build/flat.ss" "$PWD/cross/flat.so")
209221 (make-boot-file "$PWD/jolt.boot" '()
210222 "${targetBoot}/petite.boot"
@@ -334,6 +346,20 @@ let
334346 cp ${classesDex} stage/classes.dex
335347 chmod -R u+w stage
336348
349+ # Everything the loader needs is in .dynsym, and that is what --strip-all
350+ # keeps: what goes is .symtab and the debug sections, which are read by a
351+ # debugger and by nothing on the phone. Worth about a third of the package
352+ # — libjoltmoq and libc++_shared are most of it, and the release libraries
353+ # arrive unstripped because jolt-native's own build does not strip them.
354+ #
355+ # Here rather than in the derivations that produce them: the inputs stay
356+ # whole (a stripped libjoltapp is a worse thing to hand a debugger, and
357+ # `nix build .#libjoltapp` is how it is looked at), and this is the one
358+ # place that knows the difference between an object and a shipped one.
359+ # The NDK's, not nixpkgs' — the host strip has no opinion worth trusting
360+ # about an arm64 object.
361+ ${ndkBin}/llvm-strip --strip-all stage/lib/${abi}/*.so
362+
337363 ${buildTools}/aapt2 link -o "$out" -I ${androidJar} \
338364 --manifest ${self}/android/AndroidManifest.xml \
339365 --min-sdk-version ${apiLevel} --target-sdk-version ${targetSdk} \
@@ -205,6 +205,18 @@ let
205 (load "${xpatch}")205 (load "${xpatch}")
206 (optimize-level 2)206 (optimize-level 2)
207 (generate-inspector-information #f)207 (generate-inspector-information #f)
208+ ;; Packed harder, not packed for the first time: fasl output is
209+ ;; compressed already, but with lz4 at its fastest setting, and on
210+ ;; this image that leaves 2.3 MB on the table. What reads it back is
211+ ;; the kernel linked into libjoltapp, which has zlib because
212+ ;; chezAndroid is configured ZLIB=-lz so nothing extra ships to
213+ ;; decompress it.
214+ ;;
215+ ;; Less than the ratio of the whole file suggests (15.9 MB to 13.6):
216+ ;; compression is per fasl entry rather than over the image.
217+ (fasl-compressed #t)
218+ (compress-format 'gzip)
219+ (compress-level 'maximum)
208 (compile-file "$PWD/project/app.build/flat.ss" "$PWD/cross/flat.so")220 (compile-file "$PWD/project/app.build/flat.ss" "$PWD/cross/flat.so")
209 (make-boot-file "$PWD/jolt.boot" '()221 (make-boot-file "$PWD/jolt.boot" '()
210 "${targetBoot}/petite.boot"222 "${targetBoot}/petite.boot"
@@ -334,6 +346,20 @@ let
334 cp ${classesDex} stage/classes.dex346 cp ${classesDex} stage/classes.dex
335 chmod -R u+w stage347 chmod -R u+w stage
336 348
349+ # Everything the loader needs is in .dynsym, and that is what --strip-all
350+ # keeps: what goes is .symtab and the debug sections, which are read by a
351+ # debugger and by nothing on the phone. Worth about a third of the package
352+ # — libjoltmoq and libc++_shared are most of it, and the release libraries
353+ # arrive unstripped because jolt-native's own build does not strip them.
354+ #
355+ # Here rather than in the derivations that produce them: the inputs stay
356+ # whole (a stripped libjoltapp is a worse thing to hand a debugger, and
357+ # `nix build .#libjoltapp` is how it is looked at), and this is the one
358+ # place that knows the difference between an object and a shipped one.
359+ # The NDK's, not nixpkgs' — the host strip has no opinion worth trusting
360+ # about an arm64 object.
361+ ${ndkBin}/llvm-strip --strip-all stage/lib/${abi}/*.so
362+
337 ${buildTools}/aapt2 link -o "$out" -I ${androidJar} \363 ${buildTools}/aapt2 link -o "$out" -I ${androidJar} \
338 --manifest ${self}/android/AndroidManifest.xml \364 --manifest ${self}/android/AndroidManifest.xml \
339 --min-sdk-version ${apiLevel} --target-sdk-version ${targetSdk} \365 --min-sdk-version ${apiLevel} --target-sdk-version ${targetSdk} \