How to build packages locally

In Ubuntu, packages can be built in several ways, depending on the intended artifacts. The standard and recommended way to build packages for Ubuntu is with dpkg-buildpackage and sbuild. This ensures that the build dependencies are properly declared and that the resulting package is reproducible.

dpkg-buildpackage is used to build source-only packages.

sbuild is used to build binary-only and source + binary packages.

PPAs and the Archive permit exclusively source-only package uploads, however it is best practice to first perform a local binary build and fix any potential issues before uploading.

To let the Launchpad infrastructure build packages for you, see How to build packages in a PPA.

Prerequisites

Building packages locally requires a few tools to be installed and configured. The following sections guide you through the process of setting up your environment for building packages locally with sbuild.

Installing the necessary tools

$ sudo apt install devscripts dpkg-dev sbuild mmdebstrap uidmap piuparts

Setting up sbuild

Add your user to the sbuild group:

$ sudo adduser $USER sbuild

sbuild reads the user specific configuration file ~/.config/sbuild/config.pl (create the file if it does not exist). Save the file with the following content:

$chroot_mode = 'unshare';
$unshare_mmdebstrap_keep_tarball = 1;

# /tmp is tmpfs and large builds will fail after filling all memory.
$unshare_tmpdir_template = '/var/tmp/tmp.sbuild.XXXXXXXXXX';

$clean_source = 0;
$run_lintian = 0;
sbuild on Ubuntu 24.04 LTS and earlier

Make the required mount points for builds, logs, and scratch:

$ mkdir -p ~/shcroot/{build,logs,scratch}

Add a ~/schroot/scratch entry to /etc/schroot/sbuild/fstab:

$HOME/schroot/scratch  /scratch          none  rw,bind  0  0

sbuild reads the user specific configuration file ~/.config/sbuild/config.pl (create the file if it does not exist). Save the file with the following content, replacing my_user with your username:

# Name to use as override in .changes files for the Maintainer: field
# (optional; only uncomment if needed).
# $maintainer_name = 'Your Full Name <your@email.com>';

$chroot_mode = 'schroot';
$unshare_mmdebstrap_keep_tarball = 1;

# Default distribution to build.
$distribution = "resolute";
# Build arch-all by default.
$build_arch_all = 1;

# Do not check for the presence of the build dependencies on the host
# system, as these exist only in the unshare chroot.
$clean_source = 0;
$run_lintian = 0;

# When to purge the build directory afterwards; possible values are 'never',
# 'successful', and 'always'.  'always' is the default. It can be helpful
# to preserve failing builds for debugging purposes.  Switch these comments
# if you want to preserve even successful builds, and then use
# 'schroot -e --all-sessions' to clean them up manually.
$purge_build_directory = 'successful';
$purge_session = 'successful';
$purge_build_deps = 'successful';

# Directory for chroot symlinks and sbuild logs.  Defaults to the
# current directory if unspecified.
$build_dir = '/home/my_user/schroot/build';

# Directory for writing build logs to
$log_dir = '/home/my_user/schroot/logs';

# Key used to sign the source package. Defaults to not using any key.
# $key_id = '';

# don't remove this, Perl needs it:
1;

Fetching the package source

See How to get the source of a package for instructions on how to fetch the source of a package. You need the source to build it locally.

Building packages

Issue sbuild build commands from the source package directory that contains debian/:

$ cd <package>/debian/

sbuild allows for targeting builds towards specific releases of Ubuntu. This is useful for testing builds in the same environment as the intended upload target.

Specify the release using the --dist= (-d) option:

$ sbuild --dist=<RELEASE>

where <RELEASE> is the name of the Ubuntu release (e.g. resolute).

Tip

If you have set a default distribution in ~/.config/sbuild/config.pl, you can omit the -d option to build for the default release.

Building binary-only packages

By default, sbuild builds a binary-only package. Run the following command to build a binary package for a specific release:

$ sbuild --dist=<RELEASE>

This produces architecture-specific binary packages without generating a source package and is mostly useful for packages you need to test locally.

Building source-only packages

To build a source-only package for a specific release, the current recommended practice is to use dpkg-buildpackage instead of sbuild:

$ dpkg-buildpackage --build=source --no-check-builddeps --no-pre-clean

The flags used have the following meaning:

  • --build=source (-S): source-only build

  • --no-check-builddeps (-d): do not check build dependencies

  • --no-pre-clean (-nc): do not pre clean the source tree

Building both source and binary packages

To build both source and binary packages for a specific release, use the --source (-s) option:

$ sbuild --source --dist=<RELEASE>

Note

Launchpad rejects uploads that contain both binaries and sources.

Useful sbuild options

Parallel building:

To speed up the build, set the parallel option through the DEB_BUILD_OPTIONS environment variable. For example:

$ DEB_BUILD_OPTIONS="parallel=3" sbuild --chroot <RELEASE>-<ARCH>[-shm]
Run lintian after the build:
--run-lintian [--lintian-opts="-vIiL +pedantic"]
Large package linting:

Some large packages take a long time to lint. To avoid lintian after the build:

--no-run-lintian

Signing the changes file

For a source package to be accepted by Launchpad, it must be signed. If you specify key_id in your sbuild configuration, this is used. Otherwise, sign the source package manually with the debsign tool:

$ debsign ../<filename>_source.changes

Tip

To automatically find the changes file, create a script that extracts the info from debian/changelog:

$ source_package=$(dpkg-parsechangelog -n1 --show-field Source)
$ version=$(dpkg-parsechangelog -n1 --show-field Version)
$ debsign "../${source_package}_${version}_source.changes

Advanced usage

In some cases, builds may be more complex and require additional configuration. For example, you may need to build for a different architecture or use locally built dependencies.

Building for a different architecture (cross-building)

Without unshare (additional setup required)

Building for a different architecture without unshare requires using an emulated schroot. To setup an emulated schroot, use the mk-sbuild command from the ubuntu-dev-tools package.

Install ubuntu-dev-tools:

$ sudo apt install ubuntu-dev-tools

Then, create the schroot with the mk-sbuild command:

$ mk-sbuild --arch=<ARCH> <RELEASE>

where <ARCH> is the target architecture (e.g. arm64).

When building with sbuild, specify the target architecture with the --arch= option:

$ sbuild --arch=<ARCH> --dist=<RELEASE>

Building for architecture variants

Some architectures have variants (e.g. amd64 has amd64v3). To build for an architecture variant, specify the variant as an argument to --host=:

$ sbuild --host=<ARCH_VARIANT> --dist=<RELEASE>

where <ARCH_VARIANT> is the architecture variant (e.g. amd64v3).

Using locally built dependencies

To use a locally built a dependency in your build, specify the path to the dependency or a directory of dependencies with the --extra-package option:

$ sbuild --extra-package=/path/to/dependency.deb -d <RELEASE>

To specify extra packages in your sbuild configuration file:

$extra_packages = [
  # '/path/to/dependency.deb',
];

This way, it is possible to quickly toggle between using the locally built dependency by commenting/uncommenting the path in the configuration file.

Other build tools

While sbuild is the recommended tool for building packages locally, there are other tools that can be used for building packages. These include:

  • pbuilder(8) - a tool that builds packages in a clean chroot environment, similar to sbuild. It is less commonly used than sbuild but can be useful in certain situations.

  • cowbuilder(8) - a wrapper for pbuilder that builds packages in a clean chroot environment using copy-on-write filesystems. It is similar to pbuilder but can be faster for subsequent builds.