Debian packages (.deb
files) are the packages installed by apt
and apt-get
in ubuntu. They can be installed manually using the dpkg
command or hosted in a PPA
as described here.
Installing software
You will need to have the following software installed on a Linux based system:
- build-essential
- software-properties-common
- devscripts
- debhelper
apt-get install -y \ build-essential \ software-properties-common \ devscripts \ debhelper
Nice to haves:
- lintian
apt-get install -y \ lintian
2. git (latest version from the git-core PPA)
add-apt-repository ppa:git-core/ppa apt update apt install -y git
Cross building for RPI4?
- crossbuild-essential-arm64
apt-get install -y \ crossbuild-essential-arm64
Anatomy of a debian package
The basic structure of a debian package consists of a number of files, you can see the full documentation here. There are some requirements on folder structures too, specifically around version numbers and where the debian package files reside.
- Make a folder with the named formatted as
<your package name>-<version number>
for example:my-awesome-package-0.0.1
. You can read more about the version numbering here, but the above is sufficient - Make a subfolder called
debian
- Inside the
debian
folder asource/format
file with3.0 (native)
as the text indicating a debian specific package - Inside the
debian
folder acompat
file with10
as the text – this is thedebhelper
compatibility version
control file
This is the heart of the definition of your package, you can specify values for all the fields shown by the apt
command when installing and interrogating your package. You can see a detailed description of this file here. For a simple build:
Source: my-awesome-package Section: misc Priority: optional Maintainer: Me <info@my-awesome-compant.com> Standards-Version: 3.9.7 Package: my-awesome-package Depends: Architecture: amd64 Essential: no Description: Does awesome things to your computer
rules file
This file defines how the debhelper application will build your package. The simplest definition is:
#!/usr/bin/make -f PKGDIR=debian/tmp %: dh $@
If you are packaging your application as a SystemD unit:
#!/usr/bin/make -f PKGDIR=debian/tmp %: dh $@ --with systemd override_dh_installinit: dh_systemd_enable -pmy-awesome-package --name=my-awesome-package my-awesome-package.service dh_installinit -pmy-awesome-package --no-start --noscripts dh_systemd_start -pmy-awesome-package --no-restart-on-upgrade override_dh_systemd_start: echo "Not running dh_systemd_start"
Make sure you replace my-awesome-package
with the actual name of your package and include the .service
file in your debian
folder.
Adding files to the package
This is done using a .install
file, you will need to be very careful with the name. It is <package name>.install
. Continuing the above theme that would be my-awesome-package.install
. This can be used to copy files in to the debian package and specify where on the target machine they will be placed. The format is 1 item per line with the source first, destination last separated by a space. The source is relative to the debian
directory. You can use wildcards, for a react frontend application installed to a running apache instance as the only site, I have used this:
../*.json var/www/html ../*.js var/www/html ../*.ico var/www/html ../*.html var/www/html ../*.png var/www/html ../*.txt var/www/html ../static var/www/html
changelog
The final file is the changelog you can see the details of the composition here. I personally like to generate this from the tag history of my repositories as that is how a initiate deb package builds in my CI pipeline:
VERSION=$(git tag --sort=-taggerdate --format "%(refname:lstrip=-1)" | head -1) git tag --sort=-taggerdate \ --format "my-awesome-package (%(refname:lstrip=-1)) focal; urgency=medium%0a%0a * %(subject)%0a%0a -- %(taggername) %(taggeremail) %(taggerdate:rfc2822)" \ > my-awesome-package-"$VERSION"/debian/changelog
There is a bit going on here, refname:lstrip=-1
is getting the last portion of the tag name, so for 0.0.1
it is 0.0.1
, for development/0.0.1
it is 0.0.1
too. The %0a
text is line breaks, the tag date has to be formatted as rfc2822 to be compatible with the deb package.
summary
You should now have a folder structure similar to this:
my-awesome-package-0.0.1 └───debian | └───source │ │ │ format │ │ my-awesome-package.install │ │ my-awesome-package.service # if installing as system d unit │ | compat │ | control │ | rules
Building the package
You should now be able to cd
in to the my-awesome-package-0.0.1
directory and run dpkg-buildpackage
. This will produce
my-awesome-package_0.0.1.dsc my-awesome-package_0.0.1.tar.xz my-awesome-package_0.0.1_amd64.buildinfo my-awesome-package_0.0.1_amd64.changes my-awesome-package_0.0.1_amd64.deb
If you are building for an RPI4, the command is:
CONFIG_SITE=/etc/dpkg-cross/cross-config.amd64 DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -aarm64 -Pcross,nocheck
CI/CD
This whole process has been formalised in a GitHub action here for your convenience