Debian Package Customization HOWTO

Revision History

Revision Date Revised by Comments
0.13 20090210 RCS Added note on how to build without pbuilder, changed recommended versioning scheme, and noted Lenny as stable.
0.12 20061011 RCS Added note that debian/rules must be executable (thanks to Nabil Sayegh)
0.11 20060303 RCS Added debhelper to the list of required packages (thanks to Ferdinand Cornelissen)
0.1 20050606 RCS Updated to reflect that Sarge is the new stable distribution
0.0 20050604 RCS Initial draft

Table of Contents

Introduction
Getting Started
Setting Up
Obtaining the Package Source
Customizing the Package
Building the Modified Package
Provide Feedback

Introduction

So, what do you do if the program already exists as a Debian package (official or non-official) and you just need to tweak or customize it? You don't want to go to the trouble of downloading the upstream source and creating a whole new package. Or what if you want to backport a package from Sid to Lenny? Your best option is to download the source package and customize it yourself.

This HOWTO was inspired by several things:

If you are interested in learning more about how Debian packages actually work, there is already a great deal of material to read on the subject. Although not required, they are recommended so that if your particular package customization does not go as planned, you have a better understanding of the package internals and where the cause of the problem may be. Some of the excellent articles and documentation:

Getting Started

This document assumes that at a minimum you are comfortable with the command line and have the ability to navigate around your system fairly easily. You don't need to be the Zen master of Debian, but a good working knowledge is required. Additionally, while I endeavour to provide the most complete information possible, this document is not a substitute for the documentation available with each package. I encourage you to read the associated man pages and README files for a greater understanding of what is happening.

Necessary packages:

The devscripts, dpkg-dev and fakeroot packages do not require any specific configuration or setup. On the other hand, sudo, pbuilder and gnupg require some setup. This document will cover the basics of setting up pbuilder, but not sudo (beyond the most basic) or gnupg. There are many references available for gnupg from the GnuPG homepage.

The sudo package is well documented, but I will briefly describe how to enable access for your normal user account. Become root by executing su - and then run visudo. Add the following lines somewhere in the file, substituting your username:

bob ALL = NOPASSWD: /usr/sbin/pbuilder
bob ALL = NOPASSWD: /usr/lib/pbuilder/pbuilder-satisfydepends

WARNING: Using sudo is dangerous! I have only given you enough information to get going and to properly use pbuilder. Read the documentation and understand the security impact this has on your system.

The use of pbuilder is not strictly required. However, it is most highly recommended. The reason is to ensure that packages build correctly in a clean environment. You may have installed extra packages on your system that cause the package building to fail. Or you may have packages installed which are dependencies, but you forgot to declare them in the package. Thus, the package works fine on one machine but fails on another because the necessary packages have not been included.

Debian policy also dictates that a source package be buildable on a clean system with only build-essential packages and the build time dependencies declared by the packages. Unless your package will be included in the official Debian package archive, this not really necessary, but it is a good idea to make sure your packages build cleanly.

Another compelling reason to use pbuilder is that you can customize packages on a machine that runs a different version of Debian than the target machine. If your workstation runs unstable and your server runs stable, you can still customize the package on your workstation without having to use the server until it comes time to install the binary package.

Note: GnuPG is only required if you intend to sign your packages. This is recommended, but not required. I always sign my packages, so your results may vary if you choose to omit that step. To sign packages you will need to generate a key pair on the machine on which you will be creating the packages.

Setting Up

If you are going to setup gnupg, it is recommended that you do that first. Find a suitable tutorial and generate your key pair.

The next step is to setup the pbuilder. This can be accomplished in a number of ways, but here I will cover a fairly straightforward approach. If you have more advanced requirements, I encourage you to take a look at the documentation for pbuilder.

Start by copying /etc/pbuilderrc to ~/.pbuilderrc and then opening it in your favorite text editor. The file is well commented, but here I provide the relevant parts of my own ~/.pbuilderrc:

BASETGZ=/var/cache/pbuilder/base.tgz
BUILDPLACE=/var/cache/pbuilder/build/
MIRRORSITE=http://ftp.jp.debian.org/debian
USEPROC=yes
USEDEVPTS=yes
USEDEVFS=no
BUILDRESULT=/var/cache/pbuilder/result/
# forces the distribution on "pbuilder update"
#DISTRIBUTION=lenny
APTCACHE="/var/cache/pbuilder/aptcache"
APTCACHEHARDLINK="yes"
REMOVEPACKAGES="lilo"
HOOKDIR=""
export DEBIAN_FRONTEND="noninteractive"
DEBEMAIL="Your Name <you@example.com>"
BUILDSOURCEROOTCMD="fakeroot"
PBUILDERROOTCMD="sudo"
DEBBUILDOPTS=""
APTCONFDIR=""
BUILDUSERID=1234
BINDMOUNTS=""
DEBOOTSTRAPOPTS[0]='--variant=buildd'

If you are not sure about any of the options, or you feel you need to tweak them, be sure and read the pbuilderrc(5) man page. Also, the DISTRIBUTION option is useful if you are backporting or customizing packages for something other than Sid. For example, if you are customizing packages for your server running Lenny, you will want to uncomment that option.

The next step is to create your pbuilder chroot with the command sudo pbuilder create. You will see lots of output scroll by on the screen. Be sure and look it over to see if there are any errors. Once that is done without error, you are ready to customize the package. However, before that I would like to mention one small helper script that I use.

#!/bin/sh
pdebuild --configfile ~/.pbuilderrc --buildsourceroot fakeroot --pbuilderroot sudo --buildresult /var/cache/pbuilder/result --auto-debsign $*

This simply wraps the pdebuild with some options you need to specify to it on the command line (thanks to Manoj Srivastava for the recipe).

You can place the command into a file, like mypdebuild.sh, make it executable and place it somewhere in your path (I chose ~/bin) to make it accessible. Naturally, you can choose a different location for your --buildresult (just remember that you must specify one on the command line and to create the directory and give yourself write permissions to it, regardless of what you choose) and remove the auto-debsign option if you intend to not sign your packages. The $* lets you pass additional options through the script straight to pdebuild. If you intend to keep more than one pbuilder around, say one for Lenny and one for Sid, then you can create different helper scripts and have them each use a different configuration file.

Also, don't forget to periodically update your pbuilder chroot by executing sudo pbuilder update. This ensures that your packages are built against the the most recent packages available for your particular version of Debian.

Obtaining the Package Source

There are over 14,000 packages now in the Debian package repository. Most of them are compiled with a set of options designed to meet the most common needs. Some are provided as several different packages with different options to meet a wider variety of needs (e.g., php4-odbc, php4-pgsql and php4-mysql for a variety of database connectivity). However, you may still come across a package that does not quite meet your needs.

If you are not sure of the name of the source package (remember only source packages are compiled, which then produce one or more binary packages), you can search for your binary package in the Debian package repository or execute a quick apt-cache showsrc <binary-package>. In this tutorial, I am going to walk through a modification of libapache-mod-php4. Say, for instance, that you are not sure if it is part of the apache package or the php4 package.

$ apt-cache showsrc libapache-mod-php4
Package: php4
Binary: libapache2-mod-php4, php4-imap, php4-curl, php4-mhash, php4-cgi, php4-cli, php4-gd, php4-odbc, libapache-mod-php4, php4-ldap, php4-domxml, php4-mysql, php4, php4-common, php4-recode, php4-sybase, php4-xslt, php4-dev, php4-pear, php4-mcal, php4-snmp
Version: 4:4.3.10-15
Priority: optional
Section: web
Maintainer: Adam Conrad <adconrad@0c3.net>
Build-Depends: apache-dev (>= 1.3.23), apache2-prefork-dev (>= 2.0.53-3), autoconf, automake1.4, bison, chrpath, debhelper (>= 3), flex (>= 2.5.4), freetds-dev, po-debconf, libbz2-dev (>= 1.0.0), libc-client-dev, libcurl3-dev, libdb4.2-dev, libexpat1-dev (>= 1.95.2-2.1), libfreetype6-dev, libgcrypt11-dev, libgd2-xpm-dev (>= 2.0.28-3), libjpeg62-dev, libkrb5-dev, libldap2-dev, libmcal0-dev (>= 0.6), libmhash-dev (>= 0.8.8), libmysqlclient12-dev, libncurses5-dev, libpam0g-dev, libpcre3-dev (>= 4.3-1), libpng12-dev, librecode-dev, libsablot0-dev (>= 0.96), libsnmp5-dev, libssl-dev (>= 0.9.6), libt1-dev, libtool (>= 1.4.2-4), libwrap0-dev, libxmltok1-dev, libxml2-dev (>= 2.4.14), libxslt1-dev (>= 1.0.18), libzzip-dev, re2c, unixodbc-dev, zlib1g-dev (>= 1.0.9)
Build-Conflicts: bind-dev
Architecture: any
Standards-Version: 3.6.1
Format: 1.0
Directory: pool/main/p/php4
Files:
 526e3599f7e1c09deba5a171c957da8a 1686 php4_4.3.10-15.dsc
 73f5d1f42e34efa534a09c6091b5a21e 4892209 php4_4.3.10.orig.tar.gz
 fe8b1797815577c86f1f4d3f48388b9f 272490 php4_4.3.10-15.diff.gz
Uploaders: Steve Langasek <vorlon@debian.org>, Andres Salomon <dilinger@debian.org>, Jeroen van Wolffelaar <jeroen@wolffelaar.nl>

The first line of output shows that libapache-mod-php4 belongs to the php4 package. You can now obtain the source by executing apt-get source php4. Also, if you don't want to go to the trouble of first finding the source package, a apt-get source libapache-mod-php4 will find the correct source package.

Note, that if you download the files manually, from the Debian package page or another website, it is best to use dpkg-source to unpack everything. The command would be dpkg-source -x php4_4.3.10-15.dsc, which will also take care of making debian/rules executable, preventing a permission denied error when you try and build the package.

$ apt-get source php4
Reading Package Lists... Done
Building Dependency Tree... Done
Need to get 5166kB of source archives.
Get:1 http://ftp.es.debian.org unstable/main php4 4:4.3.10-15 (dsc) [1686B]
Get:2 http://ftp.es.debian.org unstable/main php4 4:4.3.10-15 (tar) [4892kB]
Get:3 http://ftp.es.debian.org unstable/main php4 4:4.3.10-15 (diff) [272kB]
Fetched 5166kB in 0s (9824kB/s)
dpkg-source: extracting php4 in php4-4.3.10

Customizing the Package

The next step is to actually modify the package. You will first want to change into the directory that dpkg-source extracted for you, php4-4.3.10. Update the changelog. This is not strictly necessary, but ensures that you will avoid collisions with official versions of the package you are customizing. This is done by executing debchange --nmu (make sure to export DEBEMAIL=you@example.com before using debchange), which will open the changelog in a text editor and setup some boilerplate:

php4 (4:4.3.10-15.1) unstable; urgency=low

  * Non-maintainer upload.
  *

-- Your Name <you@example.com> Sat, 4 Jun 2005 11:42:47 -0400

Don't modify the line with "Your Name" on it, as dpkg-parsechangelog depends on the precise formatting of that line to extract information about the package and its version. The rest can be modified as long as you don't change the format. This is what I would change it to for this particular customization:

php4 (4:4.3.10-15~lastname.0) unstable; urgency=low

  * Customized by enabling option foo and disabling option bar at compile.

-- Your Name <you@example.com> Sat, 4 Jun 2005 11:42:47 -0400

Notice that I changed the Debian part of the version from 15.1 to 15~lastname.0. The reason for this is that it ensures that if a new version of the package is introduced to the archive, dpkg will see it as an upgradeable package. For example, the next version of php4 to go into Sid will likely be 4:4.3.10-16 (unless there is a new release, which could be 4:4.3.11-1). That will be greater than 15~lastname.0 and show up as upgradeable. If you are using Lenny, then the next version will be a security update with the version 15+lenny1. This will also be greater than 15~lastname.0. Additionally, if a non-maintainer upload (NMU), binary-only NMU, or binary-only rebuild is uploaded, it will have a Debian version number of the form -15.1 or -15+nmu1 (or some variation thereof), which you also want to show up as upgradeable. (Thanks to Jonas Smedegaard for pointing out the possibility of binary-only uploads and for pointing out that dots in the version number are better.) Finally, if you need to make further customizations or updates to your version, you can increment the very last digit so that the version becomes 15~lastname.1, and so on.

If you want to ensure that a new official package does not upgrade your customized version, then put the package on hold (all of the package management tools have a way to do this) so that you are notified when it is upgradeable, but it won't be actually upgraded. That gives you time to download the updated version and customize it again.

If you are backporting, you should also place a note to that effect in the changelog so that you remember that it is a backport.

Now you can proceed to modify the files in the debian/ directory to match your needs. For example, let's say you want to disable the memory limit and ftp support. You can do that by changing --enable-memory-limit to --disable-memory-limit and --enable-ftp to --disable-ftp, respectively. Since those options affect compilation of the package, they are located in the debian/rules file. (Note: Other actions, like preinstallation actions, are handled by different files. As it is beyond the scope of this document, you will need to find out where the options you want to change are located on your own.) I have no idea what effect changing these options will have. This is only for instructive purposes. I assume that if you change some compile options, you know what you are doing.

If you are adding support for additional options, you may also need to add build dependencies on the development versions of libraries that provide the functionality you need. For example, if you were adding support for some PostgreSQL functionality to PHP, you would need to add a build dependency on postgresql-dev. This can be added at the end of the Build-Depends line near the top of the control file in debian/. You will probably not need to add a specific dependency for the binary packages, however, since the ${shlibs:Depends} and ${misc:Depends} macros used by most packages ensures that the package building process finds all the necessary shared libraries and their correct versions. (What the Debian New Maintainers' Guide says about the ${shlibs:Depends} macro: "After your package has been built and installed into the temporary directory, dh_shlibdeps(1) will scan it for binaries and libraries, determine their shared library dependencies and detect which packages they are in, such as libc6 or xlib6g.")

In a complex package like php4, there are quite a few files in the debian/ directory, each with its own function. Read the documentation on the various files to see what each does.

Building the Modified Package

Once your customizations are complete, change back to the base php4-4.3.10 directory. The package building process itself is simple. If you created the helper script I recommended near the start of this tutorial, then you can simply execute that. Once you run mypdebuild.sh from the package's root directory, the pbuilder will start. If necessary, it will prompt you for your sudo password.

Then it will begin downloading all the necessary packages to satisfy the build dependencies. Depending on how many dependencies there are and the speed of your Internet connection, it could take a while. Use of a caching proxy (like apt-proxy, apt-cacher, approx, or even squid) is highly recommended, especially if you plan to do lots of package builds.

The pbuilder will install all of the packages in its temporary chroot. If you have decided to sign your packages, the build will terminate by asking you to enter your passphrase twice to sign the .dsc and the .changes files. Once that is done it will proceed to actually build the binary package and, assuming no errors, place them in the results directory you specified (/var/cache/pbuilder/result if you used my recommendation above). You can do a quick ls -l /var/cache/pbuilder/result to see your packages.

$ ls -1 /var/cache/pbuilder/result/
libapache-mod-php4_4.3.10-15~lastname.0_i386.deb
libapache2-mod-php4_4.3.10-15~lastname.0_i386.deb
php4-cgi_4.3.10-15~lastname.0_i386.deb
php4-cli_4.3.10-15~lastname.0_i386.deb
php4-common_4.3.10-15~lastname.0_i386.deb
php4-curl_4.3.10-15~lastname.0_i386.deb
php4-dev_4.3.10-15~lastname.0_i386.deb
php4-domxml_4.3.10-15~lastname.0_i386.deb
php4-gd_4.3.10-15~lastname.0_i386.deb
php4-imap_4.3.10-15~lastname.0_i386.deb
php4-ldap_4.3.10-15~lastname.0_i386.deb
php4-mcal_4.3.10-15~lastname.0_i386.deb
php4-mhash_4.3.10-15~lastname.0_i386.deb
php4-mysql_4.3.10-15~lastname.0_i386.deb
php4-odbc_4.3.10-15~lastname.0_i386.deb
php4-pear_4.3.10-15~lastname.0_all.deb
php4-recode_4.3.10-15~lastname.0_i386.deb
php4-snmp_4.3.10-15~lastname.0_i386.deb
php4-sybase_4.3.10-15~lastname.0_i386.deb
php4-xslt_4.3.10-15~lastname.0_i386.deb
php4_4.3.10-15~lastname.0.diff.gz
php4_4.3.10-15~lastname.0.dsc
php4_4.3.10-15~lastname.0_all.deb
php4_4.3.10-15~lastname.0_i386.changes
php4_4.3.10.orig.tar.gz

If you choose to skip using pbuilder, then you must instead use a command like fakeroot debian/rules binary or fakeroot dpkg-buildpackage. If you use something like that, the installation of build dependencies is not automatic, though you will be warned about which are missing, and the built binary packages will end up in the directory above the current directory.

As you can see, the packages are all suffixed with the custom version. If you look at the .dsc and the .changes files you will see the MD5 sums of the various files and the most recent changelog entry that you created.

If there is an error in the build process that prevents the packages from building, the pbuilder output will show what it is near the end and the built packages will not appear in the results directory. You may want to configure pbuilder to email you the build logs or redirect them to a file and examine them later.

Once the packages are successfully built, you can install them with dpkg -i <path-to-pkg>. If you have more than one package or there are dependencies to be met, then you may want to consider creating a local repository in which to place your packages. You can read my Automatic Debian Package Repository HOWTO for more information on how that is done.

If you managed to read this whole thing, please let me know what you thought, whether it was useful, or if you have any suggestions for improvement.