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
paralleloption through theDEB_BUILD_OPTIONSenvironment 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 thansbuildbut can be useful in certain situations.cowbuilder(8) - a wrapper for
pbuilderthat builds packages in a clean chroot environment using copy-on-write filesystems. It is similar topbuilderbut can be faster for subsequent builds.