nandi/frqpublic Fork 0
f82b93f889e80716f6d00dfc747ba52b2f093590
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.

build-apk.bb · 177 lines · 9.1 KBBlitzBasic Blame HistoryRaw
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago1#!/bin/sh
2#_(
3exec "$(dirname "$0")/../scripts/bb" "$0" "$@"
4)
5
6;; Glue the two halves of the frq Android app into an APK.
7;;
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago8;; libvidya.so the C ABI on Rust/egui, out of the pinned release, and the
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago9;; NativeActivity's own library (it holds android-activity's
10;; glue, so it owns the event loop)
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago11;; libjoltmoq.so the AV media plane — MoQ over QUIC, Opus, H.264, Camera2
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago12;; libjoltapp.so jolt-native's android/jolt_main.c plus frq's Jolt boot
13;; image, dlopened by the above
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago14;; libc++_shared.so the NDK's C++ runtime, which libjoltmoq names
15;; classes.dex two Java classes: a picture chooser answers through
16;; onActivityResult and a NativeActivity has nowhere to
17;; deliver that, and Camera2 has no C API worth the name
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago18;; libssl.so OpenSSL, because the platform's own is not ours to load: an
19;; libcrypto.so app's linker namespace refuses /system/lib64/libssl.so, and
20;; without one there is no TLS at all on the phone
21;;
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago22;; Neither half is built here beyond that last link: the UI library and the glue
23;; come out of jolt-native's release, fetched by digest through the DotSlash
24;; pins in scripts/, and the boot image from build-jolt-boot.bb. Both native
25;; pieces are jolt-native's — only the boot image is frq's.
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago26;;
27;; build-apk.bb [build|install|run|log]
28(require '[babashka.classpath :as cp])
29(cp/add-classpath (str (babashka.fs/path (babashka.fs/parent *file*) ".." "scripts")))
30(require '[frq.paths :as paths]
31 '[babashka.fs :as fs]
32 '[babashka.process :as p])
33
34(def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
35(def action (or (first *command-line-args*) "build"))
36
37(def android-home (paths/env "ANDROID_HOME" (str (fs/path (fs/home) ".local" "share" "android-sdk"))))
38(def ndk-home (paths/env "ANDROID_NDK_HOME" (str (fs/path (fs/home) ".local" "share" "android-ndk-r29"))))
39(def chez (paths/env "CHEZ_ANDROID" (str (fs/path (fs/home) ".cache" "vidya-chez-android"))))
40(def openssl (paths/env "OPENSSL_ANDROID" (str (fs/path (fs/home) ".cache" "frq-openssl-android" "lib"))))
41(def build (fs/path root "android" "build"))
42(def jolt-build (fs/path build "jolt"))
43(def stage (fs/path build "stage"))
44(def tools (fs/path android-home "build-tools" "36.0.0"))
45(def android-jar (fs/path android-home "platforms" "android-36" "android.jar"))
46(def adb (paths/env "ADB" (str (fs/path android-home "platform-tools" "adb"))))
47(def ndk-bin (fs/path ndk-home "toolchains" "llvm" "prebuilt" "linux-x86_64" "bin"))
48(def package "uk.nandi.frq")
49(def activity (str package "/.FrqActivity"))
50(def api "28")
51(def clang (str (fs/path ndk-bin (str "aarch64-linux-android" api "-clang"))))
52(def arm-lib (fs/path stage "lib" "arm64-v8a"))
53
54(paths/require-paths! "Android tool"
55 [clang android-jar
56 (fs/path tools "aapt2") (fs/path tools "zipalign")
57 (fs/path tools "apksigner") (fs/path tools "d8")
58 (fs/path openssl "libssl.so") (fs/path openssl "libcrypto.so")])
59
60;; --- the UI half -----------------------------------------------------------
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago61;; The release's own object, and the glue beside it, both by digest: this build
62;; compiles no Rust and needs no jolt-native checkout, exactly as the graph in
63;; android/BUCK needs none.
64(def vidya-so (paths/dist root "libvidya-android"))
65;; The media plane, out of the same archive. The glue registers its symbols and
66;; includes its header, so this is not optional beside that jolt_main.c: link
67;; without it and --no-undefined says so.
68(def joltmoq-so (paths/dist root "libjoltmoq-android"))
69(def glue-c (paths/dist root "android-glue"))
70(def glue-include (fs/path (fs/parent (fs/parent glue-c)) "include"))
71(paths/require-paths! "library" [vidya-so joltmoq-so glue-c glue-include])
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago72
73;; --- the Jolt half ---------------------------------------------------------
74(p/shell (str (fs/path root "android" "build-jolt-boot.bb")) (str jolt-build))
75;; The boot image travels as a blob in the object file's data section; the
76;; _binary_jolt_boot_{start,end} symbols jolt_main.c reads come from this.
77(p/shell {:dir (str jolt-build)}
78 (str (fs/path ndk-bin "llvm-objcopy"))
79 "--input-target=binary"
80 "--output-target=elf64-littleaarch64"
81 "--binary-architecture=aarch64"
82 "jolt.boot" "jolt_boot.o")
83
84;; --- the Java half ---------------------------------------------------------
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago85;; Two classes: the photo chooser's result has to land somewhere and native
86;; code is not somewhere, and Camera2 has no C API worth the name. d8 turns
87;; them into the classes.dex the runtime loads.
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago88(def java-build (fs/path build "java"))
89(fs/delete-tree java-build)
90(fs/create-dirs (fs/path java-build "classes"))
91;; android.jar on the class path is where every android.* type comes from; the
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago92;; JDK's own java.* is what is left, and neither class uses anything of it that
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago93;; Android does not have. (`-bootclasspath` would be the stricter way to say
94;; that, and javac refuses it for a release this recent.)
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago95;;
96;; Every class under android/java, the way android/BUCK globs them: naming one
97;; here left CameraCapture out of the dex, and libjoltmoq looks that class up
98;; by name over JNI the moment a call starts the camera.
99(apply p/shell "javac" "--release" "17"
100 "--class-path" (str android-jar)
101 "-d" (str (fs/path java-build "classes"))
102 (map str (fs/glob (fs/path root "android" "java") "**.java")))
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago103(apply p/shell (str (fs/path tools "d8")) "--min-api" api "--output" (str java-build)
104 (map str (fs/glob (fs/path java-build "classes") "**.class")))
105
106(fs/delete-tree stage)
107(fs/create-dirs arm-lib)
108(fs/copy (fs/path java-build "classes.dex") (fs/path stage "classes.dex"))
109(fs/copy vidya-so (fs/path arm-lib "libvidya.so"))
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago110(fs/copy joltmoq-so (fs/path arm-lib "libjoltmoq.so"))
111;; openh264 is C++ and asks to be linked against libc++_shared.so by name, so
112;; libjoltmoq carries it as a DT_NEEDED and the APK has to carry the object —
113;; an app's linker namespace will not hand out the platform's own.
114(fs/copy (fs/path ndk-bin ".." "sysroot" "usr" "lib" "aarch64-linux-android"
115 "libc++_shared.so")
116 (fs/path arm-lib "libc++_shared.so"))
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago117;; jolt.mvn-http dlopens these by name at first use; beside the app's own
118;; libraries is where an app's namespace will answer for that name.
119(doseq [lib ["libssl.so" "libcrypto.so"]]
120 (fs/copy (fs/path openssl lib) (fs/path arm-lib lib)))
121
122(p/shell clang "-shared" "-fPIC" "-O2"
123 "-o" (str (fs/path arm-lib "libjoltapp.so"))
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago124 (str glue-c)
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago125 (str (fs/path jolt-build "jolt_boot.o"))
126 (str "-I" jolt-build)
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago127 (str "-I" glue-include)
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago128 (str "-L" arm-lib)
129 (str (fs/path chez "tarm64le" "boot" "tarm64le" "libkernel.a"))
130 (str (fs/path chez "lz4" "lib" "liblz4.a"))
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago131 "-lvidya" "-ljoltmoq" "-landroid" "-llog" "-lz" "-ldl" "-lm"
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago132 "-Wl,--no-undefined")
133
134;; --- the APK ---------------------------------------------------------------
135(def unaligned (fs/path build "frq-unaligned.apk"))
136(def aligned (fs/path build "frq-aligned.apk"))
137(def apk (fs/path build "frq.apk"))
138(run! fs/delete-if-exists [unaligned aligned apk])
139(p/shell (str (fs/path tools "aapt2")) "link"
140 "-o" (str unaligned)
141 "-I" (str android-jar)
142 "--manifest" (str (fs/path root "android" "AndroidManifest.xml"))
143 "--min-sdk-version" api
144 "--target-sdk-version" "36"
145 "--version-code" "1"
146 "--version-name" "0.1.0")
147;; Stored, not deflated: the loader maps these straight out of the APK.
148(p/shell {:dir (str stage)} "zip" "-q" "-0" (str unaligned)
Take every jolt-native half from the release, and only from there a008d3b nandi 18d ago149 "lib/arm64-v8a/libvidya.so" "lib/arm64-v8a/libjoltmoq.so"
150 "lib/arm64-v8a/libc++_shared.so" "lib/arm64-v8a/libjoltapp.so"
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago151 "lib/arm64-v8a/libssl.so" "lib/arm64-v8a/libcrypto.so")
152;; The dex is read by the runtime rather than mapped, so it may as well deflate.
153(p/shell {:dir (str stage)} "zip" "-q" (str unaligned) "classes.dex")
154(p/shell (str (fs/path tools "zipalign")) "-f" "-p" "4" (str unaligned) (str aligned))
155
156(def keystore (fs/path (fs/home) ".android" "debug.keystore"))
157(when-not (fs/exists? keystore)
158 (fs/create-dirs (fs/parent keystore))
159 (p/shell "keytool" "-genkeypair" "-v"
160 "-keystore" (str keystore) "-storepass" "android" "-keypass" "android"
161 "-alias" "androiddebugkey" "-keyalg" "RSA" "-keysize" "2048"
162 "-validity" "10000"
163 "-dname" "CN=Android Debug,O=Android,C=US"))
164(p/shell (str (fs/path tools "apksigner")) "sign"
165 "--ks" (str keystore) "--ks-key-alias" "androiddebugkey"
166 "--ks-pass" "pass:android" "--key-pass" "pass:android"
167 "--out" (str apk) (str aligned))
168(p/shell {:out :string} (str (fs/path tools "apksigner")) "verify" (str apk))
169
170(case action
171 "build" (println (str apk))
172 "install" (p/shell adb "install" "-r" (str apk))
173 "run" (do (p/shell adb "install" "-r" (str apk))
174 (p/shell adb "shell" "am" "force-stop" package)
175 (p/shell adb "shell" "am" "start" "-n" activity))
176 "log" (p/shell adb "logcat" "-s" "VidyaJolt" "Vidya")
177 (paths/die "usage: build-apk.bb [build|install|run|log]"))