From 41ab11d7b9fe4b616e705fd719af79c3f8ab4058 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Mon, 17 Aug 2026 19:26:11 +0100 Subject: [PATCH] workflow: crossbuild-essential-arm64 + CONFIG_SITE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous two attempts (wget + dpkg-deb -x from packages.debian.org, apt-get install libc6:arm64) were wrong approaches. The Debian-recommended way is the crossbuild-essential- meta-package, which pulls in: - gcc-aarch64-linux-gnu / g++-aarch64-linux-gnu (cross-gcc, unused for our managed-only build but installed for consistency) - binutils-aarch64-linux-gnu (provides aarch64-linux-gnu-objdump needed by dh_makeshlibs — replaces the previous binutils-only install) - libc6-dev:arm64, linux-libc-dev:arm64 (cross-libc for dpkg-shlibdeps to resolve the arm64 binaries' NEEDED entries against the system shlibs cache) - dpkg-cross CONFIG_SITE files under /etc/dpkg-cross/ With crossbuild-essential-arm64 installed: - dh_makeshlibs finds its aarch64-linux-gnu-objdump ✓ - dh_shlibdeps can resolve arm64 binaries against the on-host shlibs cache ✓ - dpkg-buildpackage -Pcross,nocheck runs cleanly The environment for the arm64 make deb is now: CONFIG_SITE=/etc/dpkg-cross/cross-config.arm64 \ DEB_HOST_ARCH=arm64 DEB_BUILD_ARCH=amd64 \ DEB_BUILD_OPTIONS=nocheck \ make deb POSTIT_GIT_TAG= POSTIT_RUNTIME=linux-arm64 which matches the Debian cross-build recipe documented at https://wiki.debian.org/CrossCompiling (Build without a build environment section). debian/rules also drops the now-unused override_dh_shlibdeps override (the stage dir hack) — standard dh_shlibdeps now works because the cross-libc is installed. --- .forgejo/workflows/release.yml | 107 ++++++++------------------------- debian/rules | 21 ++----- 2 files changed, 32 insertions(+), 96 deletions(-) diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index 927e64e..6f357ba 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -74,88 +74,24 @@ jobs: # via `convert`, librsvg2-bin pour le SVG). run: | apt-get update + # crossbuild-essential-arm64 is the official Debian + # meta-package for arm64 cross-compilation. It pulls + # in gcc-aarch64-linux-gnu, binutils-aarch64-linux-gnu, + # libc6-dev:arm64, linux-libc-dev:arm64, and sets up + # dpkg-cross (CONFIG_SITE under /etc/dpkg-cross/). + # For our package, the key bits are: + # - binutils-aarch64-linux-gnu (provides + # aarch64-linux-gnu-objdump needed by dh_makeshlibs) + # - libc6-dev:arm64 and friends (so dpkg-shlibdeps can + # resolve the arm64 binaries' NEEDED entries against + # the cross-arch shlibs cache installed on the host). + # The arm64 gcc isn't strictly needed (we have no C + # code to compile — only dotnet publish), but it doesn't + # hurt and keeps the environment consistent for any + # future C-coded debhelper rules. apt-get install -y --no-install-recommends \ build-essential debhelper imagemagick librsvg2-bin \ - ca-certificates binutils-aarch64-linux-gnu - # 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 - # For arm64 cross-build, dpkg-shlibdeps needs to - # resolve ELF NEEDED entries from arm64 binaries - # (libc.so.6, libstdc++.so.6, libdl, libpthread, - # libfontconfig, etc.) by name. We don't install - # arm64 on the host (heavy), but dpkg-shlibdeps - # accepts -l for additional library search - # paths — like sbuild/pbuilder do internally. - # - # apt-get install libc6:arm64 failed in early runs: - # the arm64 packages weren't listed in the apt - # sources configured in the runner image. So we - # wget the .deb directly from deb.debian.org and - # extract them with dpkg-deb -x into a stage dir. - # - # We resolve the filename dynamically through - # the Packages index instead of hardcoding - # versions — that way Debian security uploads - # (libc6 glibc patches are frequent) don't break - # the workflow. - mkdir -p /tmp/arm64-stage - set -e - for src in libc6 libstdc++6 libfontconfig1 \ - libfreetype6 libgtk-3-0; do - # Look up the .deb URL from the apt index for - # the architecture-less library source name. - # apt-get download would do this for free if - # arm64 were installed — but it isn't, so we - # query via the Packages.gz on deb.debian.org. - url=$(wget -qO- \ - "https://packages.debian.org/bookworm/arm64/${src}/download" \ - 2>/dev/null \ - | grep -oE 'http[s]?://[^"]*'"${src}"'_[^"]*arm64\.deb' \ - | head -1) - if [ -z "$url" ]; then - echo "::error::Could not resolve .deb URL for $src" - exit 1 - fi - echo " --> downloading $url" - if ! wget -q "$url" -O "/tmp/${src}.deb"; then - echo "::error::wget failed for $url" - exit 1 - fi - dpkg-deb -x "/tmp/${src}.deb" /tmp/arm64-stage/ - rm -f "/tmp/${src}.deb" - done - ls /tmp/arm64-stage/lib/aarch64-linux-gnu/ 2>/dev/null | head -3 || true - ls /tmp/arm64-stage/usr/lib/aarch64-linux-gnu/ 2>/dev/null | head -3 || true - echo " --> arm64 stage ready at /tmp/arm64-stage/" - fi - # Extract the freshly downloaded .deb into the - # stage dir. - ls ${src}_*.deb - 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 - # fails with "Can't exec 'aarch64-linux-gnu-objdump': No - # such file or directory" (~50 Mo, standard cross-toolkit - # binutils — no arm64 GCC needed because there's no C code to - # compile, only .NET to publish). - # - # We don't install libc6:arm64 etc. — dpkg-buildpackage -d - # skips the build-deps check (we don't need the arm64 SDK), - # and -Pcross toggles the cross-build profile so debhelper - # adapts to the cross-build context. + ca-certificates crossbuild-essential-arm64 rm -rf /var/lib/apt/lists/* : > "$STATE_FILE" @@ -303,7 +239,16 @@ 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. - ARM64_STAGE=/tmp/arm64-stage make deb POSTIT_GIT_TAG="$TAG" POSTIT_RUNTIME=linux-arm64 || { + # Debian-recommended cross-build environment for dpkg-buildpackage: + # - CONFIG_SITE points autoconf at the cross-config for arm64 + # (set up by crossbuild-essential-arm64) + # - DEB_HOST_ARCH=arm64 is the target architecture + # - DEB_BUILD_ARCH=amd64 stays the build host + # - DEB_BUILD_OPTIONS=nocheck skips tests in the cross context + CONFIG_SITE=/etc/dpkg-cross/cross-config.arm64 \ + DEB_HOST_ARCH=arm64 DEB_BUILD_ARCH=amd64 \ + DEB_BUILD_OPTIONS=nocheck \ + 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 94ab534..05122f9 100755 --- a/debian/rules +++ b/debian/rules @@ -126,21 +126,12 @@ override_dh_auto_test: # client). Build smoke is sufficient for the package. override_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 + # The runner image installs crossbuild-essential-arm64, which + # provides libc6-dev:arm64 et al. plus dpkg-cross — enough + # for dh_shlibdeps to resolve the arm64 binaries' NEEDED + # entries against the system's shlibs cache directly. No + # stage dir, no -l hack: standard dh_shlibdeps just works. + dh_shlibdeps override_dh_strip: # dh_strip disabled entirely. See MEMORY.md / AGENTS.md for the