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

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:

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

sbuild

pbuilder

xdeb

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

See also


CategoryMultiarch CategoryPackaging