CrossBuildPackagingGuidelines - Debian Wiki

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.

Contents

  1. Salsa CI
  2. PTS Multi-arch hints
  3. Hints
    1. Perl extensions
    2. Python extensions
    3. libtool-bin
    4. pkg-config
    5. Autoconf
    6. help2man
    7. gobject-introspection
  4. Reporting Bugs
  5. Building
    1. Build environment
    2. Environment set by build tools
      1. dpkg-buildpackage
      2. sbuild
      3. pbuilder
      4. xdeb
      5. make
    3. Setting the correct compiler
  6. TODO
  7. Questions
  8. See also

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
  • install pkg-config .pc files to /usr/lib/<multiarch-name>/pkgconfig/, not to /usr/lib/pkgconfig

  • annotate your test-dependencies with <!nocheck>

  • avoid 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

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
  • pre-generate a man page and store it in the source package
  • build the native version (don't forget to add :native B-D for that where needed), run help2man on it, delete it, then build the cross-compiled version

  • add a build-dependency on the generated binary package with <cross> and then run the installed version to generate the man page

  • process the source code with regular expressions to generate the man page from the data in the source without compiling and running it
    • maybe work with upstream to make the information from which the --help output is generated machine-readable

  • add the man page to a new Architecture:all package which does not need to be cross-compiled

  • use the nodoc profile and give up on reproducible cross-builds because your cross-built package will not include the man page
  • decide that the convenience of having a manual page is more important than spending effort on cross building

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 without using qemu. Many support a nogir build profile to opt out of this functionality.

gobject-introspection now depends on cross-exe-wrapper, which installs and uses qemu as needed. It is crucial for cross compilation to use triplet-prefixed tools and this applies to g-ir-scanner in particular. Unfortunately, meson still ends up using an unprefixed one (1060838).

Traditionally, .gir files have been installed below /usr/share/gir-1.0. They really can bear architecture-dependent content and Debian is offering an additional location below /usr/lib/TRIPLET/gir-1.0. Architecture-dependent files need to be moved there.

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.

dpkg-buildpackage

  • dpkg-architecture variables

    • 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

  • dpkg-buildpackage variables above

  • 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

  • dpkg-buildpackage variables above

  • 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:

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

See also


CategoryMultiarch CategoryPackaging