Let's say you have an application that must be compiled in manner that debhelper doesn't support out-of-the-box. It could be a C application with a custom build system, or it could be an application written in an new programming language. What do you do? Do you fall back to not using debhelper as much, like you did in tutorial 3? But if you do that then you have to figure out which individual dh_*
tools to call, which is a pain.
There is a better way: you can override parts of debhelper while still allowing it to everything else.
Table of contents
- The debhelper pipeline system
- Our application and its custom build system
- Overriding debhelper steps
- Verifying that it works
- Extending debhelper steps
- Conclusion
Think of debhelper as a pipeline system. There are three pipelines: clean
, build
and binary
, which correspond to the three rules
makefile targets. Each pipeline calls a number of steps serially, with each step usually being a command invocation.
You can see the steps in the dh
output. But for your convenience, here is a listing.
The clean
pipeline consists of these steps:
Step | Goal | Behavior |
---|---|---|
dh_testdir | Sanity checks the current working directory | Aborts if debian/control does not exist |
dh_auto_clean | Remove compilation products generated by the app's build system | Runs make clean or a similar command if the build system is supported |
dh_clean | Removes build products generated by a previous debhelper run | Removes the package root directory, amongst others |
The build
pipeline consists of these steps:
Step | Goal | Behavior |
---|---|---|
dh_testdir | Sanity checks the current working directory | Aborts if debian/control does not exist |
dh_auto_configure | Configures the source code | Runs ./configure , cmake or a similar command if the build system is supported |
dh_auto_build | Compiles the source code | Runs make , setup.py or a similar build command if the build system is supported |
dh_auto_test | Runs the source code's test suite | Runs make test , make check or a similar command if the build system is supported |
The binary
pipeline consists of these steps:
Step | Goal | Behavior |
---|---|---|
dh_testroot | Checks whether the rules makefile is run as root[1] |
Aborts if it isn't |
dh_prep | Performs some preparation cleanups | Removes the package root directory, amongst others |
dh_auto_install | Installs the compiled application into the package root directory | Runs make install DESTDIR=... or a similar command if the build system is detected |
dh_installdocs | Installs documentation such as man pages into the package root directory | |
dh_installchangelogs | Installs the debian/changelog file into the package root directory | |
dh_perl | Do Perl stuff | Calculates Perl dependencies and cleans up after MakeMaker |
dh_link | Creating necessary symlinks in the package root directory | |
dh_compress | Compresses files and fix symlinks in package root directory | |
dh_fixperms | Fix various file permissions in the package root directory | |
dh_strip | Strips binaries | Automatically finds binaries in the package root and invokes strip on them |
dh_makeshlibs | Creates shlibs files using dpkg-gensymbols | |
dh_shlibdeps | Finds out which binaries depend on which shared libraries | Invokes dpkg-shlibdeps |
dh_installdeb | Installs key files in the debian/ directory into <package root>/DEBIAN |
|
dh_gencontrol | Creates <package root>/DEBIAN/control |
Invokes dpkg-gencontrol |
dh_md5sums | Creates <package root>/DEBIAN/md5sums |
Automatically scans all files in the package root |
dh_builddeb | Creates the .deb file(s) | Invokes dpkg-deb |
Footnote 1: Debian packages are supposed to be built as root, for reasons that I also do not totally comprehend. But wait, we ran tutorials 1-4 without root, so why didn't it abort? It turns out that dpkg-buildpackage automatically runs the rules
makefile through fakeroot. So I think that the dh_testroot
step is unnecessary nowadays.
Note: the exact steps differ between different versions of debhelper. For example debhelper 10 (introduced in Debian 9) has more steps. When targeting a specific distribution version, be sure to look at the.
Tip: the debhelper man page has documentation on each of the step described above.
Tip 2: I've highlighted the especially interesting steps: dh_auto_clean
, dh_auto_build
and dh_auto_install
. We are going to override these steps in the rest of this tutorial.
The application that we use in this tutorial is the same hello world application from tutorial 4, but with a custom build system and with the version number bumped 5.0.0. The commands make
, make clean
and make install DESTDIR=...
are replaced by ./build.sh
, ./clean.sh
and env DESTDIR=... ./install.sh
.
Let's prepare our application and its files:
mkdir tutorial-5
cd tutorial-5
editor hello.c
editor build.sh
editor clean.sh
editor install.sh
chmod +x build.sh
chmod +x clean.sh
chmod +x install.sh
mkdir debian
editor debian/control
echo 9 > debian/compat
editor debian/changelog
hello.c must contain:
#include <stdio.h>
int
main() {
printf("hello 5.0.0\n");
return 0;
}
build.sh must contain:
#!/bin/sh
set -ex
gcc -Wall -g hello.c -o hello
clean.sh must contain:
#!/bin/sh
set -ex
rm -f hello
install.sh must contain:
#!/bin/bash
set -ex
mkdir -p "$DESTDIR/usr/bin"
cp hello "$DESTDIR/usr/bin/hello"
The control file remains the same compared to tutorial 4:
Source: hello
Section: devel
Priority: optional
Maintainer: John Doe <[email protected]>
Build-Depends: build-essential, debhelper (>= 9)
Package: hello
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: John's hello package
John's package is written in C
and prints a greeting.
.
It is awesome.
The compatibility level remains the same compared to tutorial 3:
echo 9 > debian/compat
We add a new changelog entry to the beginning of the file. The beginning of the file looks like this:
hello (5.0.0-1) stretch; urgency=medium
* Support custom build system.
-- John Doe <[email protected]> Tue, 11 Jul 2017 16:34:17 +0000
From the above pipeline description, it becomes clear that if we want to support our custom build system, we need to override the dh_auto_clean
, dh_auto_build
and dh_auto_install
steps. We can do that by defining targets in the rules file according to this naming scheme:
override_<STEP NAME>
Inside this target you can then do whatever you want. This target will be invoked by debhelper in place of the corresponding dh_*
command invocation.
So here is what our rules file should look like:
#!/usr/bin/make -f
%:
dh $@
override_dh_auto_clean:
./clean.sh
override_dh_auto_build:
./build.sh
override_dh_auto_install:
env DESTDIR=debian/hello ./install.sh
Build the package:
dpkg-buildpackage -b
Then:
$ sudo gdebi -n ../hello_5.0.0-1_<ARCH>.deb
$ hello
5.0.0
What if you don't want to completely override a step? What if you want to extend a step, e.g. by running custom commands right before or right after that step? For example what if the dh_strip
step fails to find your binary (because your binary is gzipped for example), and you want to run your own commands to strip that file.
Inside an override target you can call the original command. Here is how you can override the above hypothetical gzip-strip situation:
override_dh_strip:
dh_strip
gunzip debian/hello/usr/lib/helper-binary.gz
strip --strip-all debian/hello/usr/lib/helper-binary
gzip debian/hello/usr/lib/helper-binary
Congratulations, this concludes the beginner tutorials! You have learned that debhelper is a pipeline system and how you can override or extend specific pipeline steps.