Chapter 3. Modifying the source

# Chapter 3. Modifying the source

The rewrite of this tutorial document with updated contents and more practical examples is available as Guide for Debian Maintainers. Please use this new tutorial as the primary tutorial document.

Please note that there isn't space here to go into all the details of fixing upstream sources, but here are some basic steps and problems people often run across.

## 3.1. Setting up quilt

The program quilt offers a basic method for recording modifications to the upstream source for Debian packaging. It's useful to have a slightly customized default, so let's create an alias dquilt for Debian packaging by adding the following lines to `~/.bashrc`. The second line provides the same shell completion feature of the quilt command to the dquilt command:

    alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
    . /usr/share/bash-completion/completions/quilt
    complete -F _quilt_completion -o filenames dquilt

Then let's create `~/.quiltrc-dpkg` as follows:

    d=. ; while [ ! -d $d/debian -a $(readlink -e $d) != / ]; do d=$d/..; done
    if [ -d $d/debian ] && [ -z $QUILT_PATCHES ]; then
        # if in Debian packaging tree with unset $QUILT_PATCHES
        QUILT_PATCHES="debian/patches"
        QUILT_PATCH_OPTS="--reject-format=unified"
        QUILT_DIFF_ARGS="-p ab --no-timestamps --no-index --color=auto"
        QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index"
        QUILT_COLORS="diff_hdr=1;32:diff_add=1;34:diff_rem=1;31:diff_hunk=1;33:diff_ctx=35:diff_cctx=33"
        if ! [ -d $d/debian/patches ]; then mkdir $d/debian/patches; fi
    fi

See quilt(1) and `/usr/share/doc/quilt/quilt.pdf.gz` on how to use quilt.

## 3.2. Fixing upstream bugs

Let's assume you find an error in the upstream `Makefile` as follows, where `install: gentoo` should have been `install: gentoo-target`.

    install: gentoo
            install ./gentoo $(BIN)
            install icons/* $(ICONS)
            install gentoorc-example $(HOME)/.gentoorc

Let's fix this and record it with the dquilt command as `fix-gentoo-target.patch`: [22]

    $ mkdir debian/patches
    $ dquilt new fix-gentoo-target.patch
    $ dquilt add Makefile

You change the `Makefile` file as follows:

    install: gentoo-target
            install ./gentoo $(BIN)
            install icons/* $(ICONS)
            install gentoorc-example $(HOME)/.gentoorc

Ask dquilt to generate the patch to create `debian/patches/fix-gentoo-target.patch` and add its description following DEP-3: Patch Tagging Guidelines:

    $ dquilt refresh
    $ dquilt header -e
    ... describe patch

## 3.3. Installation of files to their destination

Most third-party software installs itself in the `/usr/local` directory hierarchy. On Debian this is reserved for private use by the system administrator, so packages must not use directories such as `/usr/local/bin` but should instead use system directories such as `/usr/bin`, obeying the Filesystem Hierarchy Standard (FHS).

Normally, make(1) is used to automate building the program, and executing `make install` installs programs directly to the desired destination (following the `install` target in the `Makefile`). In order for Debian to provide pre-built installable packages, it modifies the build system to install programs into a file tree image created under a temporary directory instead of the actual destination.

These two differences between normal program installation on one hand and the Debian packaging system on the other can be transparently addressed by the `debhelper` package through the dh_auto_configure and dh_auto_install commands if the following conditions are met:

- The `Makefile` must follow GNU conventions and support the `$(DESTDIR)` variable. [23]

- The source must follow the Filesystem Hierarchy Standard (FHS).

Programs that use GNU autoconf follow the GNU conventions automatically, so they can be trivial to package. On the basis of this and other heuristics, it is estimated that the `debhelper` package will work for about 90% of packages without making any intrusive changes to their build system. So packaging is not as complicated as it may seem.

If you need to make changes in the `Makefile`, you should be careful to support the `$(DESTDIR)` variable. Although it is unset by default, the `$(DESTDIR)` variable is prepended to each file path used for the program installation. The packaging script will set `$(DESTDIR)` to the temporary directory.

For a source package generating a single binary package, the temporary directory used by the dh_auto_install command will be set to `debian/`package``. [24] Everything that is contained in the temporary directory will be installed on users' systems when they install your package; the only difference is that dpkg will be installing the files to paths relative to the root directory rather than your working directory.

Bear in mind that even though your program installs in `debian/`package``, it still needs to behave correctly when installed from the `.deb` package under the root directory. So you must not allow the build system to hardcode strings like `/home/me/deb/`package`-`version`/usr/share/`package`` into files in the package.

Here's the relevant part of `gentoo`'s `Makefile`[25]:

    # Where to put executable commands on 'make install'?
    BIN     = /usr/local/bin
    # Where to put icons on 'make install'?
    ICONS   = /usr/local/share/gentoo

We see that the files are set to install under `/usr/local`. As explained above, that directory hierarchy is reserved for local use on Debian, so change those paths as follows:

    # Where to put executable commands on 'make install'?
    BIN     = $(DESTDIR)/usr/bin
    # Where to put icons on 'make install'?
    ICONS   = $(DESTDIR)/usr/share/gentoo

The exact locations that should be used for binaries, icons, documentation, etc. are specified in the Filesystem Hierarchy Standard (FHS). You should browse through it and read the sections relevant to your package.

So, we should install executable commands in `/usr/bin` instead of `/usr/local/bin`, the manual page in `/usr/share/man/man1` instead of `/usr/local/man/man1`, and so on. Notice how there's no manual page mentioned in `gentoo`'s `Makefile`, but since Debian Policy requires that every program has one, we'll make one later and install it in `/usr/share/man/man1`.

Some programs don't use `Makefile` variables to define paths such as these. This means you might have to edit some real C sources in order to fix them to use the right locations. But where to search, and exactly what for? You can find this out by issuing:

    $ grep -nr --include='*.[c|h]' -e 'usr/local/lib' .

grep will run recursively through the source tree and tell you the filename and the line number for all matches.

Edit those files and in those lines replace `usr/local/lib` with `usr/lib`. This can be done automatically as follows:

    $ sed -i -e 's#usr/local/lib#usr/lib#g' \
            $(find . -type f -name '*.[c|h]')

If you want to confirm each substitution instead, this can be done interactively as follows:

    $ vim '+argdo %s#usr/local/lib#usr/lib#gce|update' +q \
            $(find . -type f -name '*.[c|h]')

Next you should find the `install` target (searching for the line that starts with `install:` will usually work) and rename all references to directories other than ones defined at the top of the `Makefile`.

Originally, `gentoo`'s `install` target said:

    install: gentoo-target
            install ./gentoo $(BIN)
            install icons/* $(ICONS)
            install gentoorc-example $(HOME)/.gentoorc

Let's fix this upstream bug and record it with the dquilt command as `debian/patches/install.patch`.

    $ dquilt new install.patch
    $ dquilt add Makefile

In your editor, change this for the Debian package as follows:

    install: gentoo-target
            install -d $(BIN) $(ICONS) $(DESTDIR)/etc
            install ./gentoo $(BIN)
            install -m644 icons/* $(ICONS)
            install -m644 gentoorc-example $(DESTDIR)/etc/gentoorc

You'll have noticed that there's now an `install -d` command before the other commands in the rule. The original `Makefile` didn't have it because usually `/usr/local/bin` and other directories already exist on the system where you are running `make install`. However, since we will be installing into a newly created private directory tree, we will have to create each and every one of those directories.

We can also add in other things at the end of the rule, like the installation of additional documentation that the upstream authors sometimes omit:

            install -d $(DESTDIR)/usr/share/doc/gentoo/html
            cp -a docs/* $(DESTDIR)/usr/share/doc/gentoo/html

Check carefully, and if everything is okay, ask dquilt to generate the patch to create `debian/patches/install.patch` and add its description:

    $ dquilt refresh
    $ dquilt header -e
    ... describe patch

Now you have a series of patches.

1. Upstream bug fix: `debian/patches/fix-gentoo-target.patch`

2. Debian specific packaging modification: `debian/patches/install.patch`

Whenever you make changes that are not specific to the Debian package such as `debian/patches/fix-gentoo-target.patch`, be sure to send them to the upstream maintainer so they can be included in the next version of the program and be useful to everyone else. Also remember to avoid making your fixes specific to Debian or Linux — or even Unix! Make them portable. This will make your fixes much easier to apply.

Note that you don't have to send the `debian/*` files upstream.

## 3.4. Differing libraries

There is one other common problem: libraries are often different from platform to platform. For example, a `Makefile` can contain a reference to a library that doesn't exist on the Debian system. In that case, we need to change it to a library that does exist in Debian, and serves the same purpose.

Let's assume a line in your program's `Makefile` (or `Makefile.in`) as the following.

    LIBS = -lfoo -lbar

If your program doesn't compile since the `foo` library doesn't exist and its equivalent is provided by the `foo2` library on the Debian system, you can fix this build problem as `debian/patches/foo2.patch` by changing `foo` into `foo2`:[26]

    $ dquilt new foo2.patch
    $ dquilt add Makefile
    $ sed -i -e 's/-lfoo/-lfoo2/g' Makefile
    $ dquilt refresh
    $ dquilt header -e
    ... describe patch

[22] The `debian/patches` directory should exist now if you ran dh_make as described before. This example operation creates it just in case you are updating an existing package.

[23] See GNU Coding Standards: 7.2.4 DESTDIR: Support for Staged Installs.

[24] For a source package generating multiple binary packages, the dh_auto_install command uses `debian/tmp` as the temporary directory while the dh_install command with the help of `debian/`package-1`.install` and `debian/`package-2`.install` files will split the contents of `debian/tmp` into `debian/`package-1`` and `debian/`package-2`` temporary directories, to create ``package-1`_*.deb` and ``package-2`_*.deb` binary packages.

[25] This is just an example to show what a `Makefile` should look like. If the `Makefile` is created by the ./configure command, the correct way to fix this kind of `Makefile` is to execute ./configure from the dh_auto_configure command with default options including `--prefix=/usr`.

[26] If there are API changes from the `foo` library to the `foo2` library, required changes to the source code need to be made to match the new API.

Chapter 2. First steps |  | Chapter 4. Required files under the `debian` directory