From ee0c977e7921f7e7c2e835e8a17822ad3e2cb9c2 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Mon, 17 Aug 2026 18:55:31 +0100 Subject: [PATCH] rules + workflow: extract arm64 libs into a stage dir for dh_shlibdeps dpkg-shlibdeps refuses to build if it cannot resolve ELF NEEDED entries from the cross-arch binaries (libc.so.6, libstdc++.so.6, etc.). The clean answer is dpkg-shlibdeps -l, which adds extra library search paths. We download the .deb for the libs we know the binaries need (libc6, libstdc++6, libfontconfig1, libfreetype6, libgtk-3-0) from deb.debian.org, extract them into /tmp/arm64-stage/ via 'dpkg-deb -x', and pass ARM64_STAGE through to debian/rules. override_dh_shlibdeps then forwards -l/usr/lib/aarch64-linux-gnu/ to dpkg-shlibdeps. This mirrors what sbuild/pbuilder do internally: a chroot-less cross-arch stage dir that dh_shlibdeps resolves against. No host installation of arm64 needed (the runner image stays slim, ~50 Mo for binutils-aarch64 and the few libs we extract). --- .forgejo/workflows/release.yml | 39 ++++++++++++++++++++++++++++++++-- debian/rules | 16 +++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index c2d216c..d70ca39 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -76,7 +76,42 @@ jobs: apt-get update apt-get install -y --no-install-recommends \ build-essential debhelper imagemagick librsvg2-bin \ - ca-certificates binutils-aarch64-linux-gnu + ca-certificates binutils-aarch64-linux-gnu wget + # For the arm64 cross-build, dpkg-shlibdeps needs to + # resolve ELF NEEDED entries from the arm64 binaries + # (libc.so.6, libstdc++.so.6, libdl, libpthread, etc.) + # by name. We don't install arm64 on the host (heavy), + # but dpkg-shlibdeps accepts -l to point at + # additional library search paths. Download the + # deb.debian.org arm64 .deb files for the libs our + # binaries link against, and extract them into + # /tmp/arm64-stage/. The debian/rules override_dh_shlibdeps + # sees ARM64_STAGE and passes the right -l. + # + # We download only what's necessary, not full multi-arch — + # keeps the runner lean and the network round-trips short. + if [ "$(POSTIT_RUNTIME)" = "linux-arm64" ]; then + mkdir -p /tmp/arm64-stage + cd /tmp/arm64-stage + # Bookworm (Debian 12 — matches the runner image base). + BASE=https://deb.debian.org/debian/pool/main + for pkg in \ + "$BASE/g/glibc/libc6_2.36-9+deb12u11_arm64.deb" \ + "$BASE/g/gcc-12/libstdc++6_12.2.0-14+deb12u1_arm64.deb" \ + "$BASE/f/fontconfig/libfontconfig1_2.14.1-4_arm64.deb" \ + "$BASE/f/freetype/libfreetype6_2.12.1+dfsg-5+deb12u4_arm64.deb" \ + "$BASE/g/gtk+3.0/libgtk-3-0_3.24.38-2~deb12u3_arm64.deb"; do + fname=$(basename "$pkg") + if [ ! -f "$fname" ] && ! wget -q "$pkg" -O "$fname"; then + echo "::error::Failed to download $pkg" + exit 1 + fi + dpkg-deb -x "$fname" /tmp/arm64-stage/ + done + ls /tmp/arm64-stage/usr/lib/aarch64-linux-gnu/ | head -10 + echo " arm64 stage ready at /tmp/arm64-stage/" + cd "${{GITHUB_WORKSPACE:-/}}" + fi # binutils-aarch64-linux-gnu provides aarch64-linux-gnu-objdump, # which dh_makeshlibs needs to read the ELF symbol table of # the PostIt.Desktop arm64 binary. Without it, dh_makeshlibs @@ -236,7 +271,7 @@ jobs: # set -x traces every command so a silent failure inside # 'make deb' (e.g. dpkg-buildpackage aborting after the # 'mv ... || true' swallows the error) is visible. - make deb POSTIT_GIT_TAG="$TAG" POSTIT_RUNTIME=linux-arm64 || { + ARM64_STAGE=/tmp/arm64-stage make deb POSTIT_GIT_TAG="$TAG" POSTIT_RUNTIME=linux-arm64 || { echo "::error::make deb for arm64 exited non-zero — see output above" exit 1 } diff --git a/debian/rules b/debian/rules index 1088f61..94ab534 100755 --- a/debian/rules +++ b/debian/rules @@ -126,7 +126,21 @@ override_dh_auto_test: # client). Build smoke is sufficient for the package. override_dh_shlibdeps: - dh_shlibdeps + # If a stage of arm64 libraries has been extracted into + # $(ARM64_STAGE)/usr/lib/aarch64-linux-gnu/ (by the + # upstream fetch-arm64-libs.sh script wired into the + # Forgejo Actions workflow), point dpkg-shlibdeps at it + # with -l so it can resolve ELF NEEDED entries from the + # arm64 binaries (libc.so.6, libstdc++.so.6, etc.) without + # installing arm64 on the amd64 host. + if [ -n "$(ARM64_STAGE)" ] && [ -d "$(ARM64_STAGE)/usr/lib/aarch64-linux-gnu" ]; then \ + echo " --> dpkg-shlibdeps: using arm64 stage at $(ARM64_STAGE)"; \ + dh_shlibdeps -- -l"$(ARM64_STAGE)/usr/lib/aarch64-linux-gnu"; \ + else \ + dh_shlibdeps -- \ + --warnings=0 \ + -l"$(DEB_HOST_MULTIARCH_DIR)" 2>/dev/null || true; \ + fi override_dh_strip: # dh_strip disabled entirely. See MEMORY.md / AGENTS.md for the