This is intended as an entry level guide to the construction and maintenance of Debian packages and their source code. We're not going to get into anything crazy just yet, but I am going to walk you through the necessary steps and show you examples of how to properly get started as a maintainer. You should note that package maintenance is not "difficult" per se, but it does require that you be willing to learn and concentrate on details.
This tutorial assumes you're working from a Linux Mint system and are not afraid of the command line and not afraid to edit text files.
What are Debian packages and why are they important:
Debian packages (.deb format) are compressed binaries that make up all the installed software on any Debian, Ubuntu, or Linux Mint system. Within the binary are directories, files, scripts, documentation and anything else specifically associated with any given application or library. As simply as I can put it, they're important because they allow us to work with a package management system which provides all the necessary tools to easily install, uninstall, and update software.
How do I start?
All of the essential stuff you need to get started can be installed as simply as opening a terminal and typing:
apt install build-essential devscripts
This will install a bunch of stuff, most of which is what we call "build dependencies" or libraries necessary to compile basic Debian packages. Linux Mint includes a few custom commands to make the rest pretty easy as well, but more on that in a little bit. Make sure you have some source repositories enabled, we'll enable the source repo for the main Linux Mint stuff with the following:
apt sources
Then add the following line:
deb-src http://packages.linuxmint.com/ isadora main upstream import
Save and exit the file, then type:
apt update
Now that we have a source repo enabled, let's move on to the next step. :)
Let's download a source package and see what's inside:
Open up a terminal and lets create a new directory and download a source package:
mkdir keyring
cd keyring
apt source linuxmint-keyring
This will create a directory called "keyring" in you home folder, then it will download and unpack the source code for the linuxmint-keyring package. You can open up your file manager and see inside the "keyring" directory another one called "linuxmint-keyring-2009.04.29". This is where we'll be working.
The anatomy of a Debian package:
Once you navigate inside "linuxmint-keyring-2009.04.29" which we'll call the "source directory" from now on, you'll see two folders and two files. The most essential component here is the "debian" directory. It contains the "control" file which defines what the source code will build, what it will depend on, what is necessary to build it, who maintains it, and much other information. Also you'll find the "changelog" which is important for version control and allowing other people to track what changes you have made. There is also the "rules" file which defines what actions will be taken during the assembly of the final Debian package. There are optional "postinst" and "prerm" scripts which tell the system what actions to take immediately after installing the package and immediately before removing it. The "copyright" file contains information regarding the authors of the package, when it was created, and how it is licensed.
In the "debian" directory, open and look at the changelog file, the control file, and the rules file. In the changelog take notice of the format that has been used. You have the name of the package, the version number in parenthesis, the release it was intended for followed by a semicolon, and a string variable telling us how urgent it is. Exactly TWO lines below and TWO spaces in, we have a * and details pertaining to this package. If it's the first release it's common practice to say "Initial release." You can have as many lines with TWO spaces and a * as you need to detail what changes you have made. Exactly TWO lines down from that and ONE space in we have -- then the name of the person who released/changed the package followed by their email contained within <>, then exactly TWO spaces and then day, date time timezone. Learn the format for the changelog well as an error here will cause a failure when you try to build the package.
You'll see a similarly strict format in the control file but I'll get into details as we need them. In the rules file you'll see a series of commands that give instructions for what needs to be done with all the files and directories in the source code so that they create a usable package.
So, let's build a package:
Since we downloaded the linuxmint-keyring package, let's build a keyring package for something else, but let's also add a bit of functionality so that you won't have to manually edit the sources.list to add the new repository. Fire up your web browser and go to https://launchpad.net and let's start sifting through PPA (personal package archive) repositories.
Search for pretty much anything, for instance "firefox ppa" or "kubuntu backports ppa" or "chromium ppa" or anything else you might potentially want to mess with and open up the page for that PPA. I'll use the Firefox PPA as an example here.
Since this will technically be a new package, we're going to use linuxmint-keyring as a framework to build off of. Open up the changelog in the control file and change all the information as necessary. In this case mine is going to say:
firefox-keyring (2010.05.16) isadora; urgency=low
* Initial release.
* Forked from linuxmint-keyring.
-- Kendall Weaver <kendalltweaver@gmail.com> Sun, 16 May 2010 15:18:15 -0400
Now open the control file and we need to make a few changes here as well. The "Source:" and "Package:" lines need to be changed to reflect the name of your new package. In my case I'll change "linuxmint-keyring" to "firefox-keyring". Then I'm going to put my name and email in on the line that says "Maintainer:", and then I'm going to edit the description to properly reflect what the new package is. Since the current "Standards-Version:" is 3.8.4, I'm going to put that information in as well. Here is my completed control file:
Source: firefox-keyring
Section: misc
Priority: optional
Maintainer: Kendall Weaver <kendalltweaver@gmail.com>
Standards-Version: 3.8.4
Package: firefox-keyring
Priority: important
Architecture: all
Depends: gnupg (>= 1.0.6-4)
Description: GnuPG key of the Mozilla Daily Build repository
The Mozilla Daily Build repository digitally signs its Release files. This package
contains the repository key used for that.
The next step is to go back to the source directory and start editing the actual information in the package. We'll open the "keyrings" directory and note the presence of the linuxmint-keyring.gpg file. A .gpg file contains a digital signing key used by an individual to sign his work, helping to authenticate the origin of the package and the repository that it's coming from. Rename the linuxmint-keyring.gpg file as necessary (I'm naming mine firefox-keyring.gpg) and then open it with a text editor.
The contents of the file will probably look like gibberish except for the first two lines and the last line. The format will be:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.9 (GNU/Linux)
blah-blah-blah-blah-blah-etc-etc-etc-etc-etc-etc-and-so-on
-----END PGP PUBLIC KEY BLOCK-----
This is good as the information is well encrypted (more on this another time). Delete the contents of this file completely and go to the Launchpad page for the PPA you decided to work with. About halfway down the page click where you see the words "Technical details about this PPA". This will provide you with some more information, click on the link below where is says "Signing key:" that looks like a bunch of random numbers/letters, in my case it will say:
1024R/247510BE.
The link will take you to the Ubuntu keyserver and you'll see another link that's just the second part of the link you just clicked on. In my case this will be:
247510BE. Click on this one and you'll see another encrypted key. Copy this encrypted key (starting at -----BEGIN PGP PUBLIC KEY BLOCK----- and ending at -----END PGP PUBLIC KEY BLOCK-----) and paste it into the .gpg file you just deleted the contents of.
Now we're going to create a .list file and add the sources for the PPA we chose to work off of. In the keyrings directory create a new file and name it accordingly, I'm naming mine "firefox.list". In your browser navigate back to the main page of the PPA you chose and click the "Technical details..." link again. There's a box there with the sources inside, in my case:
deb http://ppa.launchpad.net/ubuntu-mozilla-daily/ppa/ubuntu lucid main
deb-src http://ppa.launchpad.net/ubuntu-mozilla-daily/ppa/ubuntu lucid main
Copy these two lines and paste them into your freshly created .list file, then navigate back to the debian directory.
The linuxmint-keyring uses a postinst script to tell the system that they new key is there and needs to be recognized. It also uses a prerm script to tell the system to forget this key if the package is removed. Open the postinst script with a text editor and note the contents:
#!/bin/sh
if [ -x /usr/bin/apt-key ]; then
/usr/bin/apt-key add /usr/share/keyrings/linuxmint-keyring.gpg
fi
I don't think you really need to have a firm grasp on writing shell scripts to figure out what to do here, but for the sake of detail: edit the part where it says "linuxmint-keyring.gpg" to reflect the new file name. For instance:
#!/bin/sh
if [ -x /usr/bin/apt-key ]; then
/usr/bin/apt-key add /usr/share/keyrings/firefox-keyring.gpg
fi
I'm not going to explain the details of the commands in this script here, but please do a bit of homework on shell scripting and figure it out. It's not very difficult. Now move on to the prerm script and you'll see:
#!/bin/sh
case "$1" in
remove|purge)
if [ -x /usr/bin/apt-key ]; then
/usr/bin/apt-key del 0FF405B2
fi
;;
esac
This one isn't nearly as obvious as the postinst so I'll do a little bit of explaining. Each key has an 8 character reference tag so that you don't have to put the whole key in every time you need it. In this case it's "0FF405B2". Now go back a few steps and remember that link that showed us the encrypted message we copied from the browser? That would be the 8 character tag we need here, thus my finished prerm script looks like this:
#!/bin/sh
case "$1" in
remove|purge)
if [ -x /usr/bin/apt-key ]; then
/usr/bin/apt-key del 247510BE
fi
;;
esac
Now we find ourselves at the last step of the actual editing process: the rules file. There are a few edits we need to make here so pay close attention and be as detail oriented as possible. This is NOT hard, it just requires that you pay good attention. Note this section of the rules file and pay close attention for obvious things that must be changed:
binary-indep: checkroot
$(checkdir)
-rm -rf debian/tmp
$(install_dir) debian/tmp/DEBIAN/
$(install_script) debian/postinst debian/tmp/DEBIAN/
$(install_script) debian/prerm debian/tmp/DEBIAN/
$(install_dir) debian/tmp/usr/share/keyrings/
$(install_file) keyrings/linuxmint-keyring.gpg debian/tmp/usr/share/keyrings/
$(install_dir) debian/tmp/usr/share/doc/linuxmint-keyring/
$(install_file) debian/changelog debian/tmp/usr/share/doc/linuxmint-keyring/changelog
$(install_file) debian/copyright debian/tmp/usr/share/doc/linuxmint-keyring/
dpkg-gencontrol -plinuxmint-keyring -isp
chown -R root.root debian/tmp
chmod -R go=rX debian/tmp
dpkg --build debian/tmp ..
binary-arch:
define checkdir
test -f keyrings/linuxmint-keyring.gpg
endef
Make the necessary changes to reflect the name of your new package, if you miss one of these then the package will still build, but not correctly and it won't function properly.
Now we need to add a couple of simple commands to tell the package what to do with the .list file we created. For the list file to be read correctly it needs to eventually end up in the /etc/apt/sources.list.d directory so we'll add the following lines right after the .gpg file is told where to go:
$(install_dir) debian/tmp/etc/apt/sources.list.d/
$(install_file) keyrings/firefox.list debian/tmp/etc/apt/sources.list.d/
These commands tell the build process to create the proper directory and to put our .list file in that directory. As a result this section of my rules file now looks like this:
binary-indep: checkroot
$(checkdir)
-rm -rf debian/tmp
$(install_dir) debian/tmp/DEBIAN/
$(install_script) debian/postinst debian/tmp/DEBIAN/
$(install_script) debian/prerm debian/tmp/DEBIAN/
$(install_dir) debian/tmp/usr/share/keyrings/
$(install_file) keyrings/firefox-keyring.gpg debian/tmp/usr/share/keyrings/
$(install_dir) debian/tmp/etc/apt/sources.list.d/
$(install_file) keyrings/firefox.list debian/tmp/etc/apt/sources.list.d/
$(install_dir) debian/tmp/usr/share/doc/firefox-keyring/
$(install_file) debian/changelog debian/tmp/usr/share/doc/firefox-keyring/changelog
$(install_file) debian/copyright debian/tmp/usr/share/doc/firefox-keyring/
dpkg-gencontrol -pfirefox-keyring -isp
chown -R root.root debian/tmp
chmod -R go=rX debian/tmp
dpkg --build debian/tmp ..
binary-arch:
define checkdir
test -f keyrings/firefox-keyring.gpg
endef
Now on to the building.
Go to the source directory and open a terminal there. Type the following just to make sure we have all of the build dependencies for this particular package installed:
apt build-dep linuxmint-keyring
Get in the habit of checking for build dependencies as it's always a good idea to be sure. Now we build the package with the following command:
apt build
Congratulations! Presuming you followed my instruction in detail and didn't screw anything up, you now have a keyring package, along with a full source package in .tar.gz format along with .dsc and .changes files sitting in the original "keyring" directory that you made at the beginning of this tutorial. Go ahead and install the .deb either graphically or in a terminal with the "dpkg -i" command. Then in a terminal type:
apt update
Or open the "Software Sources" application and you should see the repository that you just added amongst all the others.
The next steps:
Go ahead and download and look at the source code for some other packages you might be interested in (don't forget to enable the proper source repositories). Also start looking at some basic shell scripting tutorials. Today's example is for a rather simple package and it gets significantly more complex in the future, but don't let this be disheartening (it actually gets way more fun).
Part Two will cover the bases associated with setting up a Launchpad PPA of your own. Part Three will deal with "Debianizing" vanilla source code.