#!/bin/bash # Builds Korin-Timer.AppImage as a FULLY self-contained # bundle: its own Python interpreter + stdlib, GTK4, gtk4-layer-shell, # PyGObject, pycairo, evdev, python-xlib, and every transitive shared # library they need (~75 .so files) including ld.so + libc themselves. # # Why: this targets NixOS, which has no FHS /usr/bin/python3 or system # GTK4 on PATH at all - "the host probably already has this" (the usual # AppImage assumption) doesn't hold there. Bundling everything, including # the dynamic linker, means it doesn't depend on the host's glibc version # either. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BUILD_DIR="${ROOT}/build" APPDIR="${BUILD_DIR}/AppDir" rm -rf "${APPDIR}" mkdir -p "${APPDIR}/usr/lib/titletimer/src" mkdir -p "${APPDIR}/usr/share/applications" mkdir -p "${APPDIR}/usr/share/icons/hicolor/64x64/apps" mkdir -p "${APPDIR}/usr/share/icons/hicolor/128x128/apps" mkdir -p "${APPDIR}/usr/share/icons/hicolor/256x256/apps" cp -r "${ROOT}/src/titletimer" "${APPDIR}/usr/lib/titletimer/src/" cp "${ROOT}/packaging/AppRun" "${APPDIR}/AppRun" chmod +x "${APPDIR}/AppRun" cp "${ROOT}/packaging/korin-timer.desktop" "${APPDIR}/" cp "${ROOT}/packaging/korin-timer.desktop" "${APPDIR}/usr/share/applications/" # Pre-sized on the dev host (packaging/icon-*.png) rather than resized here at # build time - keeps this script's dependencies to what it already needs # (no ImageMagick/GdkPixbuf-CLI requirement inside the build container). cp "${ROOT}/packaging/icon-256.png" "${APPDIR}/titletimer.png" cp "${ROOT}/packaging/icon-64.png" "${APPDIR}/usr/share/icons/hicolor/64x64/apps/titletimer.png" cp "${ROOT}/packaging/icon-128.png" "${APPDIR}/usr/share/icons/hicolor/128x128/apps/titletimer.png" cp "${ROOT}/packaging/icon-256.png" "${APPDIR}/usr/share/icons/hicolor/256x256/apps/titletimer.png" bash "${ROOT}/packaging/bundle-runtime.sh" "${APPDIR}/usr/lib/titletimer/rt" OUT="${BUILD_DIR}/Korin-Timer.AppImage" APPIMAGETOOL="${BUILD_DIR}/appimagetool-x86_64.AppImage" if [ ! -x "${APPIMAGETOOL}" ]; then echo "Downloading appimagetool..." curl -L -o "${APPIMAGETOOL}" \ https://github.com/AppImage/appimagetool/releases/latest/download/appimagetool-x86_64.AppImage chmod +x "${APPIMAGETOOL}" fi if ARCH=x86_64 "${APPIMAGETOOL}" "${APPDIR}" "${OUT}" 2>/tmp/appimagetool.err; then echo "Built ${OUT}" else # appimagetool's AppImage is itself a static-PIE ELF (no PT_INTERP). Some # restricted/sandboxed environments can't exec that binary format at all # (execve fails outright, unrelated to FUSE) - if so, fall back to # assembling the AppImage by hand: a type-2 runtime stub concatenated with # a plain squashfs of the AppDir is exactly what appimagetool does # internally anyway. echo "appimagetool failed to run directly (see /tmp/appimagetool.err)." >&2 echo "Falling back to manual runtime+squashfs assembly..." >&2 RUNTIME="${BUILD_DIR}/runtime-x86_64" if [ ! -f "${RUNTIME}" ]; then curl -L -o "${RUNTIME}" \ https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-x86_64 fi SQUASHFS="${BUILD_DIR}/AppDir.squashfs" rm -f "${SQUASHFS}" mksquashfs "${APPDIR}" "${SQUASHFS}" -root-owned -noappend -quiet cat "${RUNTIME}" "${SQUASHFS}" > "${OUT}" chmod +x "${OUT}" echo "Built ${OUT} (manual assembly)" fi