Guidelines for making complex Debian packages easier to cross-compile. For basic information about cross-compiling, see CategoryMultiarch. For information about creating packages, see CategoryPackaging.
Salsa CI
The default Salsa-CI pipeline includes a test-crossbuild-arm64 job that cross-compiles your package on amd64 but for arm64. The job has allow_failure: true by default, so the pipeline will succeed even if the job fails. Check the status manually or override the property in your pipeline definition:
test-crossbuild-arm64:
allow_failure: false
Or to disable the job entirely (e.g. because your package cannot be made cross-compilable yet):
variables:
SALSA_CI_DISABLE_CROSSBUILD_ARM64: 1
PTS Multi-arch hints
Your package's page on tracker.debian.org should have an "action needed" heading. That heading may include a report from the Multiarch hinter.
For a list of messages the hinter can report, see MultiArch/Hints. For a list of packages that currently have hints on their tracker page, see multiarch-hints.yaml.
Hints
clear the dependency_libs field of any .la files you ship - they can break when packages change multiarch support
make sure you added Multi-Arch: fields
if your -dev package contains architecture-specific headers, prefer Multi-Arch: foreign
at the time of writing, no decision about architecture-dependant headers has been made, and the toolchain needs to be updated
if your debian/rules file uses d-shlibmove, add the --multiarch command-line argument and add Build-Depends: d-shlibs (>= 0.48~) in your debian/control
if your library has support files that need to go in the same package as the library, see Debian Policy: Shared library support files
if your packages is built with Qbs, see Qbs multiarch paths
when creating udeb packages (for the Debian installer), install libraries in /usr/lib unless there's a specific benefit to using the multiarch directory
if your package depends on different packages for different architectures, see BuildProfileSpec
for example, a program might use libfoo-assembly where available, and fall back to libfoo-legacy for architectures it hasn't been ported to yet
packages without a Multi-Arch field are usually treated as Multi-Arch: no, but Ubuntu treats Architecture: all packages as Multi-Arch: foreign for purposes of calculating build-dependencies
in some cases, a package that would otherwise be Architecture: all will need to be made Architecture: any for the sake of a dependency's Multi-Arch setting
for example, python3 is a dependency package which depends on an actual Python version, so it needs to be Architecture: any even though it has no architecture-specific files
use dh_auto_build instead of make
use dh_auto_configure instead of ./configure, meson, cmake, qmake etc.
- check you're using the terms "build" and "host" correctly
see nomenclature
install pkg-config .pc files to /usr/lib/<multiarch-name>/pkgconfig/, not to /usr/lib/pkgconfig
annotate your test-dependencies with <!nocheck>
avoid help2man
see help2man
change commands like e.g. gcc to e.g. $(CC)
Perl extensions
If you're building a Perl extension ("xs") module, add Build-Depends: perl-xs-dev.
Python extensions
If you're building a Python extension, replace all Build-Depends: python3{,-all,-$VERSION}-dev with Build-Depends: python{,-all,-$VERSION}-dev:native, libpython{,-all,-$VERSION}-dev:
Replace... |
... with |
python-dev |
python-dev:native, libpython-dev |
python3-all-dev |
python3-all-dev:native, libpython3-all-dev |
python3-dev |
python3-dev:native, libpython3-dev |
python3.11-dev |
python3.11-dev:native, libpython3.11-dev |
libtool-bin
Replace Build-Depends: libtool-bin with Build-Depends: libtool, then make your package run libtoolize and configure to create a libtool that knows about your host architecture.
pkg-config
If you need to run programs directly within debian/rules (outside of dh), use the cross-building variants of those programs:
-include /usr/share/dpkg/buildtools.mk
PKG_CONFIG?=pkg-config
export DEB_CFLAGS_MAINT_APPEND = $(shell $(PKG_CONFIG) --cflags foobar)
For a list of supported variables, do less /usr/share/dpkg/buildtools.mk.
Autoconf
autoconf won't run tests that need run a program during cross-compilation. Instead, we can get pre-seeded answers with config.cache. These can be architecture-specific answers or generic Debian answers. In rare cases, you may even need to supply your own answers.
These autoconf cache files are managed by dpkg-cross, which contains a set of /etc/dpkg-cross/cross-config.<arch> files and one /etc/dpkg-cross/cross-config.cache file.
To enable this mechanism and use the default settings, add this to debian/rules:
CONFIG_SITE=/etc/dpkg-cross/cross-config.$(DEB_HOST_ARCH)
If you need a special package-specific variable, set PACKAGE=<packagename> to match up with a stanza in one of the config files. This is to avoid clashes if two different packages need a variable set in a different way.
help2man
Source packages that build-depend on help2man are hard to cross-compile, because a system that can cross-compile myprogram.c can't necessarily run the generated myprogram --help. Solutions include:
- work with upstream to write a proper man page
this is recommended, because --help commands don't usually have everything we'd like
build the native version, run help2man on it, delete it, then build the cross-compiled version
- use the nodoc profile
A previous plan involved building the native package, then installing it and extracting its man page during cross-compilation. This was rejected in 751437.
gobject-introspection
Source packages using gobject-introspection cannot be cross-compiled at this point. Technical challenges include:
gobject-introspection is arch:any and depends on python3-mako, which is arch:all and cannot just be marked Multi-Arch: foreign due to its dependency on python3-markupsafe (this is immediately observable).
gobject-introspection is arch:any and depends on python3 (without :any), so it'll cross-grade your python interpreter, which will fail postinst as it runs said interpreter to byte-compile objects.
The python3 dependency cannot be just annotated with :any, because gir is related to a foreign function interface. g-ir-scanner, which is run during build, will load the built shared libraries into its own process memory and use them to derive information. Thus g-ir-scanner effectively forces the host architecture to equal the build architecture. Every distribution that has a working cross-build for gir packages (e.g. PtxDist, Yocto, Void) employs qemu.
The generated .gir files are architecture-dependent xml files that are shipped in /usr/share. As such, we generally cannot mark packages containing .gir files Multi-Arch: same. The differences amount to introspected argument types (e.g. int vs long). Arguably, this is a FHS violation.
Reporting Bugs
"FTCBFS" means "Failed to cross-build from source", and is adapted from FTBFS. Please tag FTCBFS bug reports like this:
User: debian-cross@lists.debian.org
Usertags: ftcbfs
If your report specifically concerns cross-build dependency resolution, replace ftcbfs with cross-satisfiability.
See also the list of cross-build bugs.
Building
Use dh instead of this!
dh_auto_build and other dh tools usually do the right thing without any special logic. Only use the following if you've unsuccessfully tried using debhelper.
Build environment
Below is a list of values set by various tools, but the interface to package-building is still defined as the debian/rules targets, which should not rely on anything else to set the environment.
The recommended way to set the architecture variables provided by dpkg-architecture is to include this snippet provided by dpkg-dev:
DPKG_EXPORT_BUILDFLAGS := 1
include /usr/share/dpkg/architecture.mk
The include makes the variables available to debian/rules, and the DPKG_EXPORT_BUILDFLAGS exports them to the commands invoked by debian/rules. This is available from dpkg-dev 1.16.1 onward, and will not overwrite any previously-supplied values.
Environment set by build tools
dpkg-buildpackage
DEB_BUILD_ARCH
DEB_BUILD_ARCH_ABI
DEB_BUILD_ARCH_BITS
DEB_BUILD_ARCH_CPU
DEB_BUILD_ARCH_ENDIAN
DEB_BUILD_ARCH_LIBC
DEB_BUILD_ARCH_OS
DEB_BUILD_GNU_CPU
DEB_BUILD_GNU_SYSTEM
DEB_BUILD_GNU_TYPE
DEB_BUILD_MULTIARCH
DEB_HOST_ARCH
DEB_HOST_ARCH_ABI
DEB_HOST_ARCH_BITS
DEB_HOST_ARCH_CPU
DEB_HOST_ARCH_ENDIAN
DEB_HOST_ARCH_LIBC
DEB_HOST_ARCH_OS
DEB_HOST_GNU_CPU
DEB_HOST_GNU_SYSTEM
DEB_HOST_GNU_TYPE
DEB_HOST_MULTIARCH
DEB_TARGET_ARCH
DEB_TARGET_ARCH_ABI
DEB_TARGET_ARCH_BITS
DEB_TARGET_ARCH_CPU
DEB_TARGET_ARCH_ENDIAN
DEB_TARGET_ARCH_LIBC
DEB_TARGET_ARCH_OS
DEB_TARGET_GNU_CPU
DEB_TARGET_GNU_SYSTEM
DEB_TARGET_GNU_TYPE
DEB_TARGET_MULTIARCH
DEB_RULES_REQUIRES_ROOT and DEB_GAIN_ROOT_CMD
depending on the package's Rules-Requres-Root value
if the value implies the package is built via fakeroot, it will also some variables
SOURCE_DATE_EPOCH will be set if not previously set
MAKEFLAGS might be set depending on dpkg-buildpackage options used
- some locale variables will get sanitized depending on the vendor
sbuild
CONFIG_SITE=/etc/dpkg-cross/cross-config.$DEB_HOST_ARCH
for autoconf cache settings provided by dpkg-cross
DEB_BUILD_OPTS+=nocheck
- anything else configured to be set in build environment
pbuilder
DEB_BUILD_OPTIONS+=nocheck
unless the user passes --no-auto-cross
DEB_BUILD_PROFILES+=nocheck
unless the user passes --no-auto-cross
xdeb
CONFIG_SITE=/etc/dpkg-cross/cross-config.$DEB_HOST_ARCH
for autoconf cache settings provided by dpkg-cross
DEB_BUILD_OPTS+=nocheck
GTEST_INCLUDEDIR=/usr/$DEB_HOST_GNU_TYPE/include
GTEST_LIBDIR=/usr/$DEB_HOST_GNU_TYPE/lib
make
make sets some things itself too. Some of them not very helpfully, like the implicit $(CC)=cc.
Setting the correct compiler
Without dh, you will need to set $(CC) yourself. The easiest way to re-initialize common tool variables in debian/rules is with:
include /usr/share/dpkg/buildtools.mk
Or in a Makefile:
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
ifeq ($(origin CC),default)
CC := $(DEB_HOST_GNU_TYPE)-gcc
endif
override_dh_auto_build:
$(MAKE) CC=$(CC) build
Or in a shell script:
# Set CC to gcc, unless it has already been set:
CC="${CC:=gcc}"
TODO
The easy cross problems are solved, only the hard ones are left. Consider the following list if you have a lot of free time on your hands:
- cross-compiling perl
src:perl is now built from source in Debian, so patching the upstream configure generator to not need try_run checks for e.g. sizeof is possible
- gobject-introspection
Yocto and PtxDist gave up and use qemu
- non-glibc ports
- musl-linux-any
- rebootstrap
failures detected by rebootstrap (see also HelmutGrohne/rebootstrap)
Questions
will the nocheck stuff ever be part of the build system, I think it should be, (maybe setting an additional variable if it does so), this way it would be smarter, for example if we use cross-build to orchestrate multilib, or building with qemu--and still run tests.
--scientes
