#!/usr/bin/env bash # Gestion reproductible des jniLibs de l'app Kazeia. # # Les .so de app/src/main/jniLibs/arm64-v8a/ sont des ARTEFACTS (gitignorés), # venant de 5 chaînes de build différentes (kazeia-engine, ExecuTorch, QNN SDK, # Genie, TTS pipeline). La SOURCE DE VÉRITÉ versionnée est le manifest sha256 : # kazeia-android/scripts/jnilibs.MANIFEST.sha256 # # Usage : # ./jnilibs.sh verify # compare jniLibs au manifest (CI/Gradle l'appelle) # ./jnilibs.sh sync-engine # rafraîchit le sous-ensemble kazeia-engine depuis /opt/Kazeia-engine/dist # ./jnilibs.sh update-manifest # re-fige le manifest sur l'état courant (à committer !) # ./jnilibs.sh export # tarball des jniLibs (transfert vers une autre machine) # ./jnilibs.sh import # restaure les jniLibs depuis un export, puis verify set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" LIBS="$HERE/../app/src/main/jniLibs/arm64-v8a" MANIFEST="$HERE/jnilibs.MANIFEST.sha256" ENGINE_DIST="/opt/Kazeia-engine/dist" verify() { [ -f "$MANIFEST" ] || { echo "ERREUR: manifest absent ($MANIFEST)"; exit 1; } local fail=0 # 1) tous les fichiers du manifest présents et conformes while read -r sum path; do [ -z "$sum" ] && continue; case "$sum" in \#*) continue;; esac local f="$LIBS/$path" if [ ! -f "$f" ]; then echo " MANQUANT $path"; fail=1 elif [ "$(sha256sum "$f" | cut -d' ' -f1)" != "$sum" ]; then echo " MODIFIÉ $path"; fail=1 fi done < "$MANIFEST" # 2) pas de .so non déclaré (un intrus = build non reproductible ailleurs) for f in "$LIBS"/*.so; do local b; b="$(basename "$f")" grep -q " $b\$" "$MANIFEST" || { echo " NON DÉCLARÉ $b (update-manifest ?)"; fail=1; } done if [ $fail -eq 0 ]; then echo "jniLibs OK ($(grep -cv '^#' "$MANIFEST" | cat) libs conformes au manifest)"; else echo ""; echo "jniLibs NON conformes. Corriger puis './jnilibs.sh update-manifest' si le changement est voulu."; exit 1; fi } sync_engine() { # Sous-ensemble possédé par kazeia-engine (build CPU-only, cf RAG_INTEGRATION.md engine) [ -d "$ENGINE_DIST" ] || { echo "ERREUR: $ENGINE_DIST absent (machine sans le dépôt engine — utiliser import)"; exit 1; } for f in lib-cpu/libllama.so lib-cpu/libggml.so lib-cpu/libggml-base.so lib-cpu/libggml-cpu.so \ b-jni-cpu/libkazeia_engine.so b-jni-cpu/libkazeia_tts.so; do cp -v "$ENGINE_DIST/$f" "$LIBS/" || true done echo "→ vérifier l'app sur device, puis './jnilibs.sh update-manifest' + commit." } update_manifest() { { echo "# jniLibs MANIFEST — état attendu de app/src/main/jniLibs/arm64-v8a/" echo "# Régénéré par scripts/jnilibs.sh update-manifest le $(date +%F)." echo "# Provenances : kazeia-engine dist (libllama/libggml*/libkazeia_*)," echo "# ExecuTorch build local (libexecutorch*, libqnn_executorch_backend, libfbjni)," echo "# QNN SDK 2.42 (libQnn*), Genie (libGenie), TTS pipeline (libtts_pipeline), libomp." echo "# Les binaires ne sont PAS dans git ; ce manifest fait foi (verify en preBuild)." ( cd "$LIBS" && sha256sum *.so | sort -k2 ) } > "$MANIFEST" echo "manifest re-figé : $MANIFEST ($(grep -cv '^#' "$MANIFEST") libs) — À COMMITTER." } export_tar() { local out="/opt/Kazeia/_archives/kazeia-jnilibs-$(date +%Y%m%d).tar.gz" mkdir -p /opt/Kazeia/_archives tar czf "$out" -C "$LIBS/.." arm64-v8a echo "export : $out ($(du -h "$out" | cut -f1)) — à déposer sur box.kazeia.com (dossier privé) pour les autres machines." } import_tar() { [ -f "${1:-}" ] || { echo "usage: jnilibs.sh import "; exit 1; } tar xzf "$1" -C "$LIBS/.." verify } case "${1:-}" in verify) verify;; sync-engine) sync_engine;; update-manifest) update_manifest;; export) export_tar;; import) import_tar "${2:-}";; *) grep '^#' "$0" | head -14; exit 1;; esac