From e07258c8bd02c6a9e8acc1a8360d0d7a98c1bfe0 Mon Sep 17 00:00:00 2001 From: ml Date: Sat, 4 Jul 2026 15:11:53 +0200 Subject: [PATCH] Fix VICE cross-compile and image cache-warming for release builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build-image/Dockerfile: add bison (VICE's configure needs a yacc-compatible parser generator, same category as the earlier flex fix) and exclude packageRelease/signReleaseBundle from the cache-warm stage's gradlew run, since those always fail there for lack of a keystore that's never baked into the image. vice_jni.c: guard getFrameCount()/setSoundEnabled() with #ifdef HAVE_VICE_SRC like their sibling functions already do — they referenced globals that only exist when VICE is linked in, breaking the documented no-VICE placeholder build. Only surfaced now because the cache-warm stage is the first thing to ever compile this file without VICE. dist.sh: floor the untagged dev-build's versionCode at 1, since the 0.0.0-dev+ placeholder otherwise computes to 0, which Android's Gradle plugin rejects. run-image.sh: wipe generated build artifacts (vice-src, vice-libs, nibtools-src/libs, app/build, .cxx) before each run so it exercises a true from-scratch build like CI does, instead of silently reusing artifacts left over from a previous local run. Also chown the bind-mounted repo back to the host user on exit, since the container runs as root and was otherwise leaving root-owned files behind. --- .gitea/workflows/release.yml | 5 ---- .../app/src/main/jni/vice_jni.c | 8 +++++ build-image/Dockerfile | 22 ++++++++++---- build-image/VERSION | 2 +- dist.sh | 3 ++ run-image.sh | 29 ++++++++++++++++++- 6 files changed, 56 insertions(+), 13 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 7966ae9..624e66f 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -32,11 +32,6 @@ jobs: credentials: username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_PASSWORD }} - # Without this, the runner's Docker daemon reuses whatever it already - # has cached locally under the `:latest` tag and never notices a newer - # image was pushed — options: is passed straight through to - # `docker create`, which supports --pull since Docker 20.10. - options: --pull=always steps: - uses: actions/checkout@v4 diff --git a/SchwertUndMagieOnPebbleCompanionApp/app/src/main/jni/vice_jni.c b/SchwertUndMagieOnPebbleCompanionApp/app/src/main/jni/vice_jni.c index c20b6ca..6d52d10 100644 --- a/SchwertUndMagieOnPebbleCompanionApp/app/src/main/jni/vice_jni.c +++ b/SchwertUndMagieOnPebbleCompanionApp/app/src/main/jni/vice_jni.c @@ -807,7 +807,11 @@ JNI_FN(jboolean, getDriveLed)(JNIEnv *env, jobject obj) { JNI_FN(jint, getFrameCount)(JNIEnv *env, jobject obj) { (void)env; (void)obj; +#ifdef HAVE_VICE_SRC return (jint)g_frame_count; +#else + return 0; +#endif } /* Schwert und Magie uploads a custom character set that redefines a handful of @@ -895,7 +899,11 @@ JNI_FN(void, injectKey)(JNIEnv *env, jobject obj, jint keyCode, jboolean pressed JNI_FN(void, setSoundEnabled)(JNIEnv *env, jobject obj, jboolean enabled) { (void)env; (void)obj; +#ifdef HAVE_VICE_SRC g_sound_enabled = enabled ? 1 : 0; +#else + (void)enabled; +#endif } JNI_FN(jboolean, saveState)(JNIEnv *env, jobject obj, jstring jpath) { diff --git a/build-image/Dockerfile b/build-image/Dockerfile index 118fe82..6ededdd 100644 --- a/build-image/Dockerfile +++ b/build-image/Dockerfile @@ -26,14 +26,14 @@ ENV DEBIAN_FRONTEND=noninteractive \ # git/unzip/curl/jq: checkout, SDK downloads, and the release workflow's # calls to the Gitea API (create release, upload assets). # python3-venv: pebble-tool's `sdk install` creates a venv per SDK version. -# dos2unix/autoconf/automake/pkg-config/xa65/build-essential/gettext/flex: +# dos2unix/autoconf/automake/pkg-config/xa65/build-essential/gettext/flex/bison: # host tools required by the companion app's build_vice.sh (see that file's -# own preflight check, plus flex for VICE's AC_PROG_LEX-based configure) to -# cross-compile VICE via autotools before NDK clang takes over for the -# actual target compilation. +# own preflight check, plus flex/bison for VICE's AC_PROG_LEX/AC_PROG_YACC- +# based configure) to cross-compile VICE via autotools before NDK clang takes +# over for the actual target compilation. RUN apt-get update && apt-get install -y --no-install-recommends \ curl ca-certificates git unzip tar xz-utils python3 python3-venv file jq \ - dos2unix autoconf automake pkg-config xa65 build-essential gettext flex \ + dos2unix autoconf automake pkg-config xa65 build-essential gettext flex bison \ && rm -rf /var/lib/apt/lists/* # --- Android SDK: cmdline-tools, platform, build-tools, NDK, CMake --- @@ -82,6 +82,13 @@ RUN curl -LsSf https://astral.sh/uv/install.sh | sh \ # stage only ever warms the Gradle/Maven dependency cache, never bakes in # compiled VICE/nibtools output. # +# packageRelease/signReleaseBundle are also excluded — they're the only tasks +# that need the release keystore, which never exists here (secrets are +# injected at job runtime, never baked into the image). Excluding them lets +# everything upstream (dependency resolution, Kotlin/native compilation, +# resource merging, dexing) still run and get cached, without two guaranteed, +# noisy "missing storeFile" failures cluttering every image build. +# # This is a pure optimization: if the app's dependencies change after this # image was built, Gradle just downloads the delta against the warm cache at # `docker run` time — same as it would without this stage, just slower for @@ -91,7 +98,10 @@ FROM base AS gradle-cache-warm COPY SchwertUndMagieOnPebbleCompanionApp /tmp/warm/SchwertUndMagieOnPebbleCompanionApp WORKDIR /tmp/warm/SchwertUndMagieOnPebbleCompanionApp RUN chmod +x gradlew \ - && (./gradlew bundleRelease assembleRelease -x buildVice -x buildNibtools --continue || true) + && (./gradlew bundleRelease assembleRelease \ + -x buildVice -x buildNibtools \ + -x packageRelease -x signReleaseBundle \ + --continue || true) FROM base COPY --from=gradle-cache-warm /root/.gradle /root/.gradle diff --git a/build-image/VERSION b/build-image/VERSION index 0cfbf08..00750ed 100644 --- a/build-image/VERSION +++ b/build-image/VERSION @@ -1 +1 @@ -2 +3 diff --git a/dist.sh b/dist.sh index d06d036..1491182 100755 --- a/dist.sh +++ b/dist.sh @@ -74,6 +74,9 @@ fi [[ "$VERSION" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+) ]] \ || fail "VERSION '$VERSION' is not a semantic version (expected X.Y.Z, optionally with a -pre+meta suffix)" VERSION_CODE=$(( ${BASH_REMATCH[1]} * 10000 + ${BASH_REMATCH[2]} * 100 + ${BASH_REMATCH[3]} )) +# Android requires a positive versionCode — the untagged dev placeholder +# (0.0.0-dev+) would otherwise compute to 0 and fail Gradle configuration. +[ "$VERSION_CODE" -gt 0 ] || VERSION_CODE=1 echo "Version: $VERSION (Android versionCode $VERSION_CODE)" # Patch versions into the tracked source files for this build only, then diff --git a/run-image.sh b/run-image.sh index 59a29e1..cf9c527 100755 --- a/run-image.sh +++ b/run-image.sh @@ -34,13 +34,40 @@ docker image inspect "$IMAGE" >/dev/null 2>&1 \ VERSION="${1:-${VERSION:-}}" +# CI always starts from a fresh checkout, but this script bind-mounts the live +# host repo — so build outputs left over from a previous local run (e.g. a +# vice-src/ already configured, or a libvice.a that's already built) would +# make build_vice.sh/build_nibtools.sh skip work they'd have to do on a real +# fresh checkout, silently hiding bugs (like a missing host build tool) that +# only show up in CI. Wipe them first so every run exercises a true from- +# scratch build, same as CI. +JNI="$ROOT/SchwertUndMagieOnPebbleCompanionApp/app/src/main/jni" +echo "== Cleaning generated build artifacts for a fresh build ==" +rm -rf \ + "$JNI/vice-src" "$JNI/vice-libs" \ + "$JNI/nibtools-src" "$JNI/nibtools-libs" \ + "$ROOT/SchwertUndMagieOnPebbleCompanionApp/app/build" \ + "$ROOT/SchwertUndMagieOnPebbleCompanionApp/app/.cxx" \ + "$ROOT/SchwertUndMagieOnPebbleWatchApp/build" + echo "== Running dist.sh inside $IMAGE ==" +# The container runs as root (needed for the SDK/NDK/Gradle setup baked into +# the image), so anything it writes into this bind mount — dist/, app/build, +# .cxx, etc. — would otherwise come back owned by root, leaving the host repo +# unusable without sudo. Chown everything back to the host user on exit, +# whether dist.sh succeeds or fails. docker run --rm \ -v "$ROOT:/workspace" \ -w /workspace \ -e VERSION="$VERSION" \ + -e HOST_UID="$(id -u)" \ + -e HOST_GID="$(id -g)" \ "$IMAGE" \ - bash -c 'git config --global --add safe.directory /workspace && ./dist.sh' + bash -c ' + git config --global --add safe.directory /workspace + trap "chown -R \"$HOST_UID:$HOST_GID\" /workspace" EXIT + ./dist.sh + ' echo "== Done — artifacts in dist/ ==" ls -la "$ROOT/dist"