Files
korin-timer/packaging/build-appimage.sh
T
2026-08-03 20:27:06 +02:00

75 lines
3.3 KiB
Bash
Executable File

#!/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