Using Pbuilder to (Cross-)Build Debian Packages

Table Of Contents

One day I wanted to build a program for a 64-bit ARM OS with basic dpkg support. Since its binaries for x86 and the corresponding source code had been adapted and maintained as Debian packages by several distros, an easy way for me would be to grab the source code of one package, cross-build it for ARM 64 architecture, and finally try to install the package via dpkg. During the research of how to cross-build Debian packages, I got to know pbuilder, one of many package building tools provided by Debian team. What it does is to build Debian packages inside a “clean” chroot environment that contains only the minimal packages for a Debian-based system.

Using pbuilder

First we need to install pbuilder, as well as qemu-debootstrap if cross-compilation is required:

1sudo apt install pbuilder qemu-user-static

To establish an basic system of a Debian-based distro, we need the corresponding keyring to download packages from the distro’s repository:

1sudo apt install ubuntu-keyring debian-archive-keyring
2
3# for Raspbian the keyring needs to be downloaded and installed by hand
4wget http://archive.raspbian.org/raspbian/pool/main/r/raspbian-archive-keyring/raspbian-archive-keyring_20120528.2_all.deb
5sudo dpkg -i raspbian-archive-keyring_20120528.2_all.deb

You can check if these keyrings have been successfully installed by listing /usr/share/keyrings directory.

Then we need to create ~/.pbuilderrc with the following content:

 1#!/bin/sh
 2
 3set -e
 4
 5if [ "$OS" == "debian" ]; then
 6    MIRRORSITE="https://mirrors.huaweicloud.com/debian/"
 7    COMPONENTS="main contrib non-free"
 8    DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}"
 9        "--keyring=/usr/share/keyrings/debian-archive-keyring.gpg")
10    : ${DIST:="buster"}
11    : ${ARCH:="amd64"}
12    if [ "$DIST" == "wheezy" ]; then
13        #EXTRAPACKAGES="$EXTRAPACKAGES debian-backports-keyring"
14        OTHERMIRROR="$OTHERMIRROR | deb $MIRRORSITE wheezy-backports $COMPONENTS"
15    fi
16elif [ "$OS" == "raspbian" ]; then
17    MIRRORSITE="http://raspbian.raspberrypi.org/raspbian/"
18    COMPONENTS="main contrib non-free rpi"
19    DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}"
20        "--keyring=/usr/share/keyrings/raspbian-archive-keyring.gpg")
21    : ${DIST:="buster"}
22    : ${ARCH:="armhf"}
23elif [ "$OS" == "ubuntu" ]; then
24    if [[ "$ARCH" == arm* ]]; then
25        MIRRORSITE="https://mirrors.huaweicloud.com/ubuntu-ports/"
26    else
27        MIRRORSITE="https://mirrors.huaweicloud.com/ubuntu/"
28    fi
29    COMPONENTS="main restricted universe multiverse"
30    DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}"
31        "--keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg")
32else
33    echo "Unknown OS: $OS"
34    exit 1
35fi
36
37if [ "$DIST" == "" ]; then
38    echo "DIST is not set"
39    exit 1
40fi
41
42if [ "$ARCH" == "" ]; then
43    echo "ARCH is not set"
44    exit 1
45fi
46
47NAME="$OS-$DIST-$ARCH"
48
49if [[ "$ARCH" == arm* ]] && [ "$(dpkg --print-architecture)" != "$ARCH" ]; then
50    DEBOOTSTRAP="qemu-debootstrap"
51fi
52
53DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}" "--arch=$ARCH")
54BASETGZ="/var/cache/pbuilder/$NAME-base.tgz"
55DISTRIBUTION="$DIST"
56BUILDRESULT="/var/cache/pbuilder/$NAME/result/"
57APTCACHE="/var/cache/pbuilder/$NAME/aptcache/"
58BUILDPLACE="/var/cache/pbuilder/build"
59HOOKDIR="/var/cache/pbuilder/hook.d/"
60PBUILDERSATISFYDEPENDSCMD="/usr/lib/pbuilder/pbuilder-satisfydepends-apt"

The code above is adapted from the one on this post of Stein Magnus Jodal with the following modifications:

  • add cross-building support for 64-bit ARM architecture;
  • change the mirror site to a faster one.

Then we can create the chroot environment based on the OS and architecture we wish to have:

1sudo OS=debian DIST=wheezy ARCH=amd64 pbuilder --create
2sudo OS=ubuntu DIST=xenial ARCH=arm64 pbuilder --create
3# ...

The chroot images would be created and stored as archives in /var/cache/pbuilder.

Finally we can build the package by using the chroot environment:

1# 1. add deb-src to /etc/apt/sources.list
2# 2. download source code
3sudo apt-get source XXX
4# 3. go into the directory
5cd XXX
6# 4. run the build command
7OS=ubuntu DIST=xenial ARCH=arm64 pdebuild

If the building completes successfully, the resulting binary package could be found in /var/cache/pbuilder/ubuntu-xenial-arm64/result.

References


C++ 中的 Name Mangling
差分数列