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.

A desire to help others who are interested in customizing their Debian packages.

A desire to help extend some of the available documentation, which does not go into sufficient detail.

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:

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.

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:

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.

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:

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.

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.

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.

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.

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:

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.

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.

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.