Files
gen1recomp/scripts/linux-arm64/Dockerfile
T
ratherDashing 24c5114745 Ship a Linux arm64 (aarch64) AppImage
scripts/build.sh's `linux` target only ever produces x86_64: it unpacks
LOVE's official love-11.5-x86_64.AppImage and re-fuses game.love into it.
There is no aarch64 equivalent to unpack -- LOVE 11.5 publishes win32,
win64, macOS, Android, iOS and exactly one x86_64 AppImage -- so arm64
desktop Linux (Raspberry Pi 4/5, Armbian, arm64 VMs on Apple Silicon) had
no artifact at all.

Compile LOVE 11.5 from the official linux-src tarball instead, inside a
Debian bullseye arm64 container, and assemble the AppImage from scratch.
Both pinned inputs (the LOVE source tarball and the AppImage type-2
runtime, on a dated tag rather than `continuous`) are SHA-256 verified on
the host, so the container runs with no network access.

Bullseye is the compile environment, not a claim about where the artifact
runs: glibc is backward but not forward compatible, so linking against the
oldest supported glibc is the only thing that makes one artifact work
everywhere. The binaries come out needing only glibc 2.29 / GLIBCXX_3.4.21,
covering Raspberry Pi OS bullseye through trixie and Ubuntu 20.04 onward.

The dependency walker copies in LOVE's own libraries and leaves the
driver-coupled, loader-coupled and font-stack libraries to the host. That
last category is not cosmetic: Debian's libtheoradec is linked against
libcairo, so a host cairo gets loaded into the process, and because the
loader resolves one SONAME once per process it then binds to whatever
libfreetype we bundled -- bullseye's 2.10.4 has no FT_Get_Transform, which
cairo 1.18 needs, and the game died at startup with a symbol lookup error.
Excluding the whole font stack makes the process self-consistent.

CI gets three path-gated jobs: an offline selftest on ubuntu-latest (pins,
the host-arch guard, the exclude list, the AppRun fusion contract), a real
build on ubuntu-24.04-arm that asserts the layout, that every bundled
object resolves under AppRun's LD_LIBRARY_PATH, and that the glibc floor is
still <= 2.31, and a release job that reuses the shared game.love payload.
None of it needs secrets or self-hosted hardware, so it runs on fork PRs.

Verified end to end on a Raspberry Pi 5 (Debian trixie, Wayland): the
launcher boots from the AppImage and renders correctly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 13:39:48 -04:00

30 lines
1.4 KiB
Docker

# Build environment for the aarch64 Linux AppImage.
#
# Debian bullseye on purpose: it ships glibc 2.31, the oldest runtime we
# promise to support. Everything linked here therefore runs on bullseye and
# every later distro (glibc is backward compatible, not forward), which is
# what makes the resulting AppImage portable across Raspberry Pi OS, Armbian,
# Ubuntu 20.04+, and the aarch64 handheld distros.
#
# This image is arch-native: build it on an aarch64 host (Raspberry Pi 5,
# ubuntu-24.04-arm runner, Apple Silicon Docker) — no qemu emulation.
FROM debian:bullseye
ENV DEBIAN_FRONTEND=noninteractive
# build-essential/autoconf: LÖVE 11.5's linux-src tarball is autotools.
# squashfs-tools: packs the AppDir into the AppImage payload.
# The lib*-dev set is LÖVE's full optional-module surface — a missing one
# does not fail configure, it silently drops a module (love.sound decoders,
# love.font, love.video), so they are pinned here deliberately.
RUN apt-get update -qq \
&& apt-get install -y --no-install-recommends \
build-essential pkg-config autoconf automake libtool \
ca-certificates curl file xz-utils zip unzip squashfs-tools \
libsdl2-dev libopenal-dev libogg-dev libvorbis-dev libtheora-dev \
libmodplug-dev libmpg123-dev libfreetype6-dev libluajit-5.1-dev \
zlib1g-dev libgl1-mesa-dev libgles2-mesa-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /work