#!/usr/bin/env bash # Thin wrapper so you don't have to remember the venv path — runs # buildozer through it directly. Usage: ./build.sh android debug set -euo pipefail # ---- Configuration ---- # Gradle 8.14.3 (pulled in by this p4a/buildozer version) ships a # Groovy/ASM build-script compiler that doesn't understand class files # newer than it was built against. This system's `java` default is # java-26-openjdk (`archlinux-java status`), and Gradle chokes on it: # BUG! ... Unsupported class file major version 70 # java-17-openjdk is also installed on this machine and works — set only # for this build, via JAVA_HOME below, so the system-wide default JDK # (used by everything else) is untouched. If Arch's package layout ever # changes this path, `archlinux-java status` shows the current one. JAVA_HOME_FOR_BUILD="/usr/lib/jvm/java-17-openjdk" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" VENV_BIN="$SCRIPT_DIR/build/venv/bin" BUILDOZER="$VENV_BIN/buildozer" if [ ! -x "$BUILDOZER" ]; then echo "Build venv not found — run ./setup-build-env.sh first." >&2 exit 1 fi if [ ! -d "$JAVA_HOME_FOR_BUILD" ]; then echo "Expected JDK not found at $JAVA_HOME_FOR_BUILD — run 'archlinux-java status' and update JAVA_HOME_FOR_BUILD in this script." >&2 exit 1 fi cd "$SCRIPT_DIR" export JAVA_HOME="$JAVA_HOME_FOR_BUILD" export PATH="$JAVA_HOME/bin:$PATH" # Running buildozer by absolute path skips everything `source venv/bin/activate` # normally sets up, so it's replicated by hand: # - PATH: buildozer shells out to find tools like `cython`, which only # resolves if the venv's bin/ is on PATH. # - VIRTUAL_ENV: buildozer's own venv-detection (targets/android.py) checks # this to decide whether to `pip install --user` its own build deps or # install normally. Without it set, buildozer wrongly assumes it's not in # a venv, uses --user, and pip refuses (no user site-packages in a venv). export PATH="$VENV_BIN:$PATH" export VIRTUAL_ENV="$SCRIPT_DIR/build/venv" # p4a creates its OWN throwaway venv per arch (.buildozer/.../build/venv, # distinct from our build/venv above) to pip-install pure-Python deps for # the app, and unconditionally re-runs `python -m venv venv` over it on # every single build — without --clear. The first time, ensurepip bundles # whatever pip version shipped with this system's Python (e.g. 25.3); if # a previous build then ran `pip install -U pip` inside it (p4a does this # every time too), the NEXT build's `python -m venv` re-invokes ensurepip, # which unpacks its older bundled pip back over the newer one WITHOUT # removing the newer version's now-orphaned files — two dist-info dirs # end up coexisting, and a newer file (e.g. build_env/installer.py, # importing a class only the newer pip's exceptions.py defines) can end # up paired with an older file that doesn't define it, e.g.: # ImportError: cannot import name 'BuildDependencyInstallError' from # 'pip._internal.exceptions' # Confirmed by hand: pip-25.3.dist-info and pip-26.2.1.dist-info both # present in the same site-packages after a second build. Deleting that # venv before every build keeps it single-version and costs a few # seconds (pip + Cython reinstall) — cheap next to the SDK/NDK/recipe # build state, which this leaves untouched. rm -rf "$SCRIPT_DIR"/.buildozer/android/platform/build-*/build/venv exec "$BUILDOZER" "$@"