Translations: English


pbuilder software stack

pbuilder is the core of a software stack for building Debian packages. For common tricks in pbuilder-related tools, see PbuilderTricks. For alternative tools, see Package build tools. For more general package maintenance, see Package maintenance tools.

The pbuilder software stack has evolved over decades with no central planning. Each layer reused an existing program to provide a more targeted solution to a specific problem. This page discusses how to use the whole stack to create Debian packages, but see pages for individual programs for details.

The attached image shows the whole stack at the time of writing.

pbuilder vs. sbuild

pbuilder provides an easy-to-use packaging solution for people who spend most of their time solving other problems. The main alternative is sbuild, which provides more granular control for people who spend the majority of their time dealing with the actual packaging process.

It's probably best to learn pbuilder first, then migrate to sbuild if you need the extra functionality. sbuild innovations are usually ported to pbuilder once they mature, so either solution is fine for most developers.

Layers of the stack

pbuilder is the central part of a software stack to create, update, and use environments. Layers below pbuilder itself create various types of environment, layers above are wrappers that improve the user experience.

debootstrap, mmdebstrap etc.

debootstrap and mmdebstrap create a Debian environment in a subdirectory, which you can chroot into and treat more-or-less like a separate system. pbuilder uses them to create build environments, but for example you can also use them to create the filesystem for a machine with a different hardware architecture.

debootstrap is the standard way to create pbuilder environments, mmdebstrap is a more recent alternative - differences are listed in the debootstrap section of the mmdebstrap man page. mmdebstrap is sometimes associated with sbuild for historical reasons, but it has been compatible with pbuilder since 940188. To switch to mmdebstrap, pass --debootstrap=mmdebstrap to pbuilder or add a line like DEBOOTSTRAP="mmdebstrap" in your /etc/pbuilderrc.

There are many other tools to create Debian environments. For example, cdebootstrap resembles debootstrap but supports a different set of target environments. For a list, see Tools to create a build system.

You can even create an environment manually. Just make sure to install all the packages for building packages.

pbuilder itself

pbuilder creates build environments from existing "base" environments, then cleans up the build environment when it's finished. This ensures artifacts from one build never cause issues in the next build.

Using pbuilder directly creates environments from tarballs (e.g. tar xf /var/cache/pbuilder/base.tgz), which is highly flexible but requires a lot of I/O.

cowbuilder

cowbuilder is a wrapper around pbuilder that manages build environments with less disk I/O. It is a better choice for beginners.

cowbuilder creates environments with hardlinks (e.g. cp -al /var/cache/pbuilder/base.cow/ ...). This is much faster by default, but makes some advanced uses more complicated (like using a tmpfs for speed).

For information about cowbuilder performance, see cowbuilder_benchmark.

qemubuilder

qemubuilder is a wrapper around pbuilder that builds environments in a qemu disk image. This was extremely useful when it was released, but modern cross-compiling and user-mode emulation have made it largely redundant.

qemubuilder creates environments by running a QEMU instance with a kernel and (optional) initrd, both provided by you. This is slower and more difficult than other alternatives, but may be necessary when compiling for a completely different operating system (like Debian GNU/Hurd).

{i} Because qemubuilder is hard to use and largely redundant, this page does not discuss how to use it.

git-pbuilder

git-pbuilder is a high-level wrapper around cowbuilder, which can also be configured to use qemubuilder or raw pbuilder. It focuses on making common operations easier - see PackagingWithGit.

Examples on this page that include sudo cowbuilder can usually be replaced by git-pbuilder without sudo (git-pbuilder calls sudo internally).

{i} git-pbuilder is part of git-buildpackage, but there is no equivalent in e.g. svn-buildpackage - please use cowbuilder directly.

Optional performance tweaks

The pbuilder stack has a number of optional tweaks that improve performance, at the cost of increasing complexity. If this is the first time you've created a package with Debian, you may want to skip these steps and come back later.

Use eatmydata

Linux calls fsync automatically when files are closed, to ensure data is actually written to disk. This massively reduces data loss from system crashes and unsafely removing disks, but slows down programs that write lots of small files. You can disable this safety measure with eatmydata.

Building packages involves writing lots of small files, and doesn't benefit from the safety provided by fsync(). To use eatmydata inside your environments, add this to your /etc/pbuilderrc:

# append eatmydata to $EXTRAPACKAGES:
EXTRAPACKAGES="$EXTRAPACKAGES eatmydata"
EATMYDATA=yes

You will need to manually install the eatmydata package in any environments you have already created - see Add extra packages, below.

Note that running e.g. sudo eatmydata pbuilder ... instead of sudo pbuilder ... only affects the tiny minority of writes from outside the chroot, so doesn't provide any real performance benefit.

{i} the "tmpfs" pbuilder trick is faster than eatmydata but more complex to manage.

Use ccache

ccache caches compilations between runs, which can significantly reduce build times when you're trying to diagnose a packaging issue in a large compiled project.

Read ccache for general advice, then decide where to put your ccache directory. It's recommended to create a new directory like /var/cache/pbuilder/ccache, to avoid any risk of data from your local builds leaking into built packages. Wherever you put the directory, make it writeable by a user with UID 1234 and GID 1234.

Finally, add the following to your /etc/pbuilderrc:

export CCACHE_DIR="/path/to/your/ccache"
export PATH="/usr/lib/ccache:$PATH"
EXTRAPACKAGES="$EXTRAPACKAGES ccache"
BINDMOUNTS="$CCACHE_DIR"

You will need to manually install the ccache package in any environments you have already created, and should also run update-ccache-symlinks. See Add extra packages.

Add extra packages

pbuilder environments start out with very few packages installed, then pbuilder installs your package's build-dependencies each time it rebuilds the package. This reduces the risk of unlisted dependencies, because your package will simply fail to build unless all dependencies are accounted for. But it significantly increases build times, because packages have to be reinstalled every single time.

All pbuilder wrappers support being called with login --save-after-login to run commands in the chroot then save the results. pbuilder and cowbuilder also support being called with execute --save-after-exec to do the same with a script specified on the command-line. Either option lets you apt-get install extra packages that will be available to all future builds.

The best way to manage extra packages depends on your personal workflow. For example, if you spend half your time fixing packaging errors in other people's Go packages, you might want to maintain both normal and -go variants of all your build environments. Or if you're packaging your own software and always compile your man pages from DocBook with pandoc, you might prefer to add EXTRAPACKAGES="$EXTRAPACKAGES pandoc" to your /etc/pbuilderrc.

{i} the "temporary base environment" pbuilder trick might provide some inspiration about ways to manage your process.

Mirror repositories locally with apt-cacher-ng

As discussed above, pbuilder runs several apt-get commands to upgrade and install packages. It maintains a package cache in /var/cache/pbuilder/aptcache/ that significantly reduces downloads, but may not be enough in some cases. For example, you might want to cache Release files from apt-get update, or might want to share a cache between all the devices on your network.

To create a local package cache, follow the instructions at AptCacherNg. Then log in to each of your environments with e.g. sudo cowbuilder login --save-after-login, and apply the manual configuration discussed on that page.

Keep packages updated

When pbuilder builds a package, it starts by running apt-get update and apt-get upgrade. This will only take a few seconds when you first create an environment, but becomes increasingly time-consuming as your base image gradually falls behind.

Updating an environment in place can cause weird bugs, like config files not being updated as expected. Instead of calling pbuilder update, it's better to just delete and recreate your environments.

The best schedule for updating your packages depends on your personal workflow. For example, if you're a Debian developer who builds packages all day, you might want to automatically recreate each of your environments overnight. Or if you maintain a mature project and want to check each year's release builds properly, you might prefer to just build new environments as part of the release process and delete them once it's done.

Create environments

pbuilder usually creates an environment by running a tool to create a build system, and can require complicated configuration in some cases.

Create an environment with raw pbuilder

To create a Debian environment with pbuilder, do:

sudo pbuilder \
    create \
    --distribution <dist> --architecture <arch>

# Note: the command-line parser is a bit fussy...

# NO!  '--key=value' is not supported by `pbuilder`:
#sudo pbuilder \
#    create \
#    --distribution=<dist> --architecture=<arch>

# NO!  Must be 'create <options>', not '<options> create':
#sudo pbuilder \
#    --distribution <dist> --architecture <arch> \
#    create

This will create a .tgz file in /var/cache/pbuilder. If you previously added EATMYDATA=yes to your /etc/pbuilderrc, you might see some lines like this:

ERROR: ld.so: object 'libeatmydata.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored.

These indicate eatmydata has not yet been installed, which is normal - it's an extra package, and is installed towards the end of the creation process. That message should stop appearing as soon as libeatmydata1 is unpacked.

{i} you may be interested in a trick to support DIST= and ARCH= variables

Create an environment with cowbuilder

cowbuilder passes most arguments through to pbuilder, so it can be called the same way:

sudo pbuilder \
    create \
    --distribution <dist> --architecture <arch>

This will create a .cow directory instead of a .tgz file, and with the cowdancer package added to the environment. cowbuilder supports --key=value command-line arguments, but it's better to stick with --key value for compatibility with pbuilder.

{i} you may be interested in a trick to support DIST= and ARCH= variables

Create an environment with git-pbuilder

git-pbuilder create passes many arguments through to sudo cowbuilder, but intercepts --distribution and --architecture, which must be passed via environment variables instead:

DIST=<dist> ARCH=<arch> git-pbuilder create

Note that the environment variable DIST maps to the command-line argument --distribution - DISTRIBUTION= and --dist= are not supported.

git-pbuilder create provides git-buildpackage syntax for pbuilder commands, so you will probably find this more intuitive than cowbuilder if your workflow involves other git-buildpackage commands. But you can call cowbuilder directly if you like, or even switch back and forth between them.

Advanced ways to create environments

Some types of environment need extra work to create properly.

Create packages for non-default mirrors and components

Build environments usually only include packages from the main component of the distribution's primary mirror. But you might need to add other locations to make your package compile. For example, you might want to compile a package for stable-backports that depends on other libraries in stable-backports, or co-ordinate the release of a security package that depends on other programs with security-related API changes.

When creating an environment, specify the components you want to include from your distribution's primary mirror by appending --components "main,<other-components>" to your create command-line.

When creating an environment, specify extra lines to add to sources.list by appending --othermirror 'deb <uri> <suite> <components>' to your create command-line.

To modify an environment after creating it, use e.g. sudo pbuilder login --save-after-login and edit your /etc/apt/sources.list.

{i} for more information, see the Include specific Debian sources trick

Create an Ubuntu environment

To create an Ubuntu environment with raw pbuilder, install ubuntu-keyring (and ubuntu-archive-keyring in buster and earlier), then append --mirror http://archive.ubuntu.com/ubuntu/ to the pbuilder command-line. To create an Ubuntu environment with any other wrapper, also append --components "main,universe" to the command-line. For example:

sudo apt install ubuntu-keyring
# Only needed in Buster and earlier:
#sudo apt install ubuntu-archive-keyring

# Use pbuilder directly:
sudo pbuilder \
    create \
    --distribution <dist> --architecture <arch> \
    --mirror http://archive.ubuntu.com/ubuntu/

# cowbuilder needs an extra argument:
sudo cowbuilder \
    create \
    --distribution <dist> --architecture <arch> \
    --mirror http://archive.ubuntu.com/ubuntu/ \
    --components "main,universe"

The --components argument is required because cowbuilder installs the cowdancer package, which is in Ubuntu's "universe" component.

Create an environment manually

Some distributions aren't supported by debootstrap, but do provide a downloadable root tarball. This is particularly useful for Raspberry Pi OS armhf (Raspbian), which is subtly incompatible with Debian, so packages need to be compiled using a Pi toolchain.

First, learn how to construct chroots for your target distribution and architecture, and make sure you can run foreign binaries transparently.

The next steps depend on your preferred wrapper and which packages for building packages you need to add. Adapt this to suit your requirements:

# Pick a distribution name that won't conflict with any existing name:
DIST=raspbian

# Unpack your tarball into an appropriate directory:
sudo mkdir -p /var/cache/pbuilder/base-"$DIST".cow
sudo tar \
    -C /var/cache/pbuilder/base-"$DIST".cow \
    -xf /path/to/tmp/root.tar.xz

# Install missing packages:
sudo chroot /var/cache/pbuilder/base-"$DIST".cow apt-get -yy \
    install <packages for building packages>

# Update all packages:
sudo cowbuilder update --basepath=/var/cache/pbuilder/base-"$DIST".cow

You should now be able to use your environment in the normal way.

/!\ Mirror repositories locally with apt-cacher-ng if you use environments that aren't supported by debootstrap. They might use repositories with package filenames that conflict with Debian - for example, pbuilder might cache the Debian version of libc6 in /var/cache/pbuilder/aptcache, then fail with a "wrong checksum" error when it tries to install that same package in an environment that ships a different version of libc6 with the same filename.

Build packages

To build a package with pbuilder or cowbuilder, create a dsc file then run e.g. sudo cowbuilder --build your-package.dsc. The result will be placed in /var/cache/pbuilder/result/.

Because git-pbuilder is part of the git-buildpackage suite, it's usually called by a program that creates a .dsc file for you. For details, see PackagingWithGit.

/!\ If you run multiple instances of pbuilder in parallel, either give them separate aptcache directories, or use use apt-cacher-ng and disable the aptcache directory with --aptcache "".

Complete example

Go to the unstable source for GNU Hello and download the files listed under Download hello.

Then in the directory where you downloaded the files, do sudo cowbuilder build hello_*.dsc.

When the build process finishes, look in /var/cache/pbuilder/result/ - you should see a collection of build files, including an installable .deb.

Delete environments

To delete a pbuilder environment, first check there are no leftover mounts by doing sudo mount | grep /var/cache/pbuilder, then delete its associated file or directory (e.g. /var/cache/pbuilder/base.tgz). There is no other database of pbuilder environments that needs to be updated.

When pbuilder crashes, it usually leaves behind a build environment in /var/cache/pbuilder/build/. Anything in that directory can be safely deleted once the associated build job is complete and mount-points have been unmounted.

See also


CategoryPackaging