crossbuild-essential-arm64 transitively installs libc6:arm64 et
al. (Depends chain: crossbuild-essential-arm64 → gcc-aarch64-
linux-gnu → libc6-dev:arm64 → libc6:arm64), placing the runtime
.so files in /usr/lib/aarch64-linux-gnu/. The non-dev libs
(libc.so.6, libm.so.6, etc.) live there, not in /usr/lib/
which is what dh_shlibdeps searches by default.
dpkg-shlibdeps accepts -l<dir> for additional library search
paths. We compute the right path via dpkg-architecture -aarm64
-q DEB_HOST_MULTIARCH (which returns 'aarch64-linux-gnu'
without choking on the CC mismatch warning, since it's a pure
query), and pass /usr/lib/$HOST_MULTIARCH/ as -l. Falls back
to a literal aarch64-linux-gnu if dpkg-architecture isn't
installed (it always is on a Debian build host).
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-<ARCH> 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.
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).
Previous fix (--exclude=*.so --no-automatic-dbgsym) failed because
dh_strip does MULTIPLE strip passes (--strip-unneeded,
--strip-debug, --only-keep-debug), and objcopy's ARM64-format
recognition issue surfaces again in a pass that does not honour
--exclude:
strip: Unable to recognise the format of the input file
`debian/postit/usr/lib/postit/libHarfBuzzSharp.so'
dh_strip: error: strip --remove-section=.comment ... returned exit code 1
The cleanest fix is to skip dh_strip entirely. The cost is minor
for our use case (no strip on managed DLLs saves a few KB; no
postit-dbg auto-package — the debug info in libHarfBuzzSharp /
libSkiaSharp is from Avalonia deps, not our code).
If stripping becomes important, the proper fix is binutils-multiarch
(multi-arch objcopy) in the container runner. Out of scope here.
Discovered via Forgejo Actions run #9 on tag 1.0.6.
Previous fix (--exclude=*.so) only affects the strip phase. dh_strip
also runs a separate --only-keep-debug pass for the automatic dbgsym
package, and that pass does not honour --exclude. So objcopy still
trips on the ARM64 .so files and the build aborts.
Add --no-automatic-dbgsym to skip the dbgsym pass entirely. Trade-
off: no separate postit-dbg package is generated. That's fine for
this upstream — the only debug info in the .so files is from Avalonia
deps (HarfBuzz, Skia) and is not useful for debugging PostIt itself.
Discovered via the Forgejo Actions run #8 on tag 1.0.6.
When cross-compiling PostIt.Desktop for linux-arm64 from an amd64
runner container, the .deb ends up shipping HarfBuzzSharp.so and
SkiaSharp.so in ARM64 format. dh_strip invokes objcopy on every
file under debian/postit/, and objcopy on the amd64 host cannot
parse ARM64 .so files:
objcopy: Unable to recognise the format of the input file
`debian/postit/usr/lib/postit/libHarfBuzzSharp.so'
dh_strip: error: ... returned exit code 1
dh_strip: error: Aborting due to earlier error
Add --exclude=*.so to override_dh_strip. The upstream .so ships
with its own debug symbols; we don't lose anything by skipping
the strip on them.
Also drop the diag.yml workflow that diagnosed the initial
tag-not-found failure — no longer needed.
Discovered via the Forgejo Actions release.yml run on tag 1.0.6.
- Makefile + debian/rules: POSTIT_GIT_TAG default 1.0.0 → 1.0.6.
- CHANGELOG.md: document the 1.0.6 release (workflow rollout).
- .github/workflows/build-and-release-deb.yml: GitHub Actions workflow
that builds postit_*.deb (matrix amd64+arm64 via cross-RID .NET on
amd64 runners) from a tag pushed to this repo, validates the tag
(semver, patch-parity channel, CHANGELOG section), and publishes a
GitHub Release with both .deb as assets. Refuses to re-tag an
existing release by default (re-tag = le mal); opt-in via
workflow_dispatch + force_republish=true.
Pattern mirrors yavsc/.github/workflows/docker-publish-android.yml.
The previous override_dh_auto_build used 'git clone --branch <tag>'
which only accepts branch names. Feeding it 1.0.1-rc02 (a tag,
not yet pushed to origin) failed with 'La branche distante
1.0.1-rc02 n'a pas ete trouvee' and aborted the package build.
Switch to a 'git init + remote add + fetch --depth=1 origin <ref>
+ checkout FETCH_HEAD' sequence, which works for both branches
and tags, including local-only tags fetched via file:// (the
typical RC-staging workflow: 'git tag' on the local checkout,
then 'make POSTIT_GIT_URL=file:///... POSTIT_GIT_TAG=<tag>'
before pushing).
The fetch error now carries a diagnostic that points the operator
at the file:// override and at the missing 'git push'.
Adds tests/test-fetch-upstream.sh with four cases against the
real pazof/yavsc remote and a synthetic local repo: tag on
GitHub, branch on GitHub, .git reuse, and tag via file://.
Wired into 'make test'.
The .deb was hardcoded to 1.0.0-1 in debian/changelog regardless of
POSTIT_GIT_TAG, so 'make POSTIT_GIT_TAG=1.0.1-rc01' produced a
postit_1.0.0-1_amd64.deb (wrong name) and the trailing mv into
POSTIT_OUT_DIR silently fell back to the same wrong-name glob.
Move the version into a @VERSION@-bearing debian/changelog.in
template and render debian/changelog from it in the Makefile, before
dpkg-buildpackage runs (it reads debian/changelog during
dpkg-source --before-build, before any rule fires). debian/changelog
is .gitignored; the template is the source of truth.
debian/rules re-renders the changelog as a safety net for direct
dpkg-buildpackage invocations and adds it to override_dh_auto_clean
so partial builds leave no stale rendered file behind.
Default stays linux-x64 (the only architecture built today).
Override on the command line to target arm64 (or any other
RID supported by Avalonia 12 on Linux):
make deb POSTIT_RUNTIME=linux-arm64
The Makefile passes POSTIT_RUNTIME through to dpkg-buildpackage,
which propagates it to debian/rules, which threads it into
dotnet publish --runtime.
Note: the .deb is mono-architecture. For a multi-arch .deb,
the build must run twice (once per RID) and the resulting .debs
can be combined with dpkg-gencontrol / Multi-Arch: same.
Update README accordingly.
Initial debian/rules wrote into debian/postit/usr/... directly.
That fails: dh_clean (run between override_dh_auto_build and
dh_install) wipes the package staging dir, and dh_install needs
debian/tmp/ as the canonical staging area to install files
into debian/postit/.
Move the cp-and-convert block out of override_dh_auto_build into
a 'stage_postit' make define, and call it from override_dh_install
right before dh_install moves files into the package tree.
Also: simplify POSTIT_* path variables — drop the duplicated
POSTIT_APP_DIR / POSTIT_LIB_DIR / POSTIT_BIN_DIR / POSTIT_SHARE_DIR
set (they all derived from debian/postit which is now what dh_install
populates).