rules + workflow: extract arm64 libs into a stage dir for dh_shlibdeps
Some checks failed
Forgejo Release postit-deb / release (push) Failing after 0s

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<dir>, 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<stage>/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).
This commit is contained in:
Paul Schneider 2026-08-17 18:55:31 +01:00
commit ee0c977e79
No known key found for this signature in database
GPG key ID: 1E66C65EE2B46F1B
2 changed files with 52 additions and 3 deletions

View file

@ -76,7 +76,42 @@ jobs:
apt-get update apt-get update
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
build-essential debhelper imagemagick librsvg2-bin \ 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<dir> 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, # binutils-aarch64-linux-gnu provides aarch64-linux-gnu-objdump,
# which dh_makeshlibs needs to read the ELF symbol table of # which dh_makeshlibs needs to read the ELF symbol table of
# the PostIt.Desktop arm64 binary. Without it, dh_makeshlibs # the PostIt.Desktop arm64 binary. Without it, dh_makeshlibs
@ -236,7 +271,7 @@ jobs:
# set -x traces every command so a silent failure inside # set -x traces every command so a silent failure inside
# 'make deb' (e.g. dpkg-buildpackage aborting after the # 'make deb' (e.g. dpkg-buildpackage aborting after the
# 'mv ... || true' swallows the error) is visible. # '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" echo "::error::make deb for arm64 exited non-zero — see output above"
exit 1 exit 1
} }

16
debian/rules vendored
View file

@ -126,7 +126,21 @@ override_dh_auto_test:
# client). Build smoke is sufficient for the package. # client). Build smoke is sufficient for the package.
override_dh_shlibdeps: 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: override_dh_strip:
# dh_strip disabled entirely. See MEMORY.md / AGENTS.md for the # dh_strip disabled entirely. See MEMORY.md / AGENTS.md for the