本教程文档已被重写为另外的 Debian 维护者指导 文档,其中包含了更新的内容与更多实际例子。请使用新的教程作为主要的教程文档。
请注意这里没有足够篇幅来描述有关修改上游源码的 全部 细节,这里只介绍基本步骤和常见问题。
quilt 程序是 Debian
打包过程中采用的补丁管理工具。我们只需要在默认配置的基础上,加以少许修改即可。首先我们来创建一个别名
dquilt,以方便打包之需: 添加以下几行内容到 ~/.bashrc
文件中。其中第二行可以给 dquilt 命令提供与 quilt 命令相同的
shell 补全:
alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
. /usr/share/bash-completion/completions/quilt
complete -F _quilt_completion -o filenames dquilt
        
现在我们来创建 ~/.quiltrc-dpkg 文件:
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
        
参见 quilt(1) 以及 /usr/share/doc/quilt/quilt.pdf.gz
来获取有关 quilt 命令用法的信息。
假设你在上游的 Makefile 文件中找到了一个错误,其中的 install:
gentoo 应该修正为 install: gentoo-target 。
install: gentoo
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc
        
使用 dquilt 修复这个问题,并把补丁命名为
fix-gentoo-target.patch。[22]
$ mkdir debian/patches $ dquilt new fix-gentoo-target.patch $ dquilt add Makefile
现在将 Makefile 修改为如下的样子:
install: gentoo-target
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc
        
使用 dquilt 将补丁创建到
debian/patches/fix-gentoo-targe.patch 并根据 DEP-3: Patch Tagging Guidelines 添加描述:
$ dquilt refresh $ dquilt header -e ... 描述补丁
大多数第三方程序会默认安装在 /usr/local 目录下。在 Debian
中,这是保留给系统管理员的私有位置,因此 Debian 软件包不可以使用比如/usr/local/bin
这样的目录,而应当使用比如 /usr/bin 这样的系统目录, 以遵循文件系统层级结构标准: Filesystem Hierarchy Standard (FHS)。
通常情况下, make(1) 被用来自动编译程序,接着执行 make
install 就可以把程序按照 Makefile 文件中的
install target 安装到指定的位置。为使 Debian
能够提供编译好的二进制软件包,打包脚本将自动修正编译系统,使其将文件安装到一个在临时目录中创建的文件系统子树中,而非直接安装到实际的目标位置。
普通程序安装过程和 Debian 打包安装过程二者的区别可以由 debhelper 软件包中的
dh_auto_configure 和 dh_auto_install
透明地处理。但必须满足以下条件:
Makefile 文件应当遵循 GNU 的规定支持 $(DESTDIR)
变量[23]
源代码必须遵循文件系统层级标准(FHS)。
使用 GNU autoconf 的程序默认遵守 GNU
的规定,这有利于打包过程的自动化。通过这项特点和其他启发式处理,估计 debhelper 软件可以直接制作约 90%
的软件包而不需维护者对编译系统做出大的改变。所以打包也不是看起来那样复杂。
如果你需要修改 Makefile 文件,就要确保其支持
$(DESTDIR) 变量,虽然默认情况下 $(DESTDIR)
变量没有设置并且在程序安装时会前置到每个文件的路径中。打包脚本会将 $(DESTDIR) 设置到临时目录上。 
对于从源码生成单个二进制包的情况, dh_auto_install 将临时目录设置到
debian/。[24] 临时目录中的全部文件都将成为软件包内容,并在安装该包时被安装到用户系统。这里唯一的区别是
dpkg 会把文件安装到真实的根目录树中,而不是你的工作目录。
package
请记住,即使你的程序正确安装到了debian/,仍然要考虑将
package.deb 软件包文件安装到根目录下的情形。所以绝对不允许构建系统将诸如
/home/me/deb/
这种诡异的内容硬编码到软件包文件中。
package-version/usr/share/package
以下是 gentoo 软件包的
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
可以看到文件被放到了 /usr/local 下。按照上边的解释,该目录被 Debian
保留作本地用途,所以请把它们按如下方式修改:
# Where to put executable commands on 'make install'? BIN = $(DESTDIR)/usr/bin # Where to put icons on 'make install'? ICONS = $(DESTDIR)/usr/share/gentoo
二进制文件、图标和文档等的更确切位置均已在文件层级标准(FHS)中作出了详尽描述。本教程建议你快速浏览相关章节以获取你打包需要用到的内容。
因此,我们应当把可执行二进制文件安装到 /usr/bin 而非
/usr/local/bin,而 man 手册页则应放在
/usr/share/man/man1 而非
/usr/local/man/man1,依此类推。注意,gentoo 的 Makefile
里没有提及手册页,而按照 Debian Policy 的要求,每个程序都应当有一个手册页,我们将在稍后制作一个并安装到
/usr/share/man/man1。
有些程序不使用 Makefile 变量定义路径,这意味着你可能需要去编辑 C
程序源代码来使他们使用正确的路径。但是到哪里去搜索,哪些才是呢?你可以通过以下的方法找到它们:
$ grep -nr --include='*.[c|h]' -e 'usr/local/lib' .
grep 会递归搜索整个源代码树并告诉你所有匹配项的文件名和行号。
编辑那些文件,在那些行中用 usr/lib 替换
usr/local/lib。这个过程可以用如下方法自动化完成:
$ sed -i -e 's#usr/local/lib#usr/lib#g' \
        $(find . -type f -name '*.[c|h]')
        如果你想要确认每一个替换操作,那么下边的方法可以让你交互式地达成:
$ vim '+argdo %s#usr/local/lib#usr/lib#gce|update' +q \
        $(find . -type f -name '*.[c|h]')
        
紧接着你应该找到 install target (通常搜索以
install: 开头的行即可),并把除 Makefile
顶部定义变量之外的目录引用妥当修改。
原始的 gentoo 的
install target 是这样:
install: gentoo-target
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc
        
让我们来修复这个上游BUG,并把修改使用 dquilt
命令记录到debian/patches/install.patch。
$ dquilt new install.patch $ dquilt add Makefile
使用你喜欢的编辑器按照以下内容为 Debian 软件包作修改:
install: gentoo-target
        install -d $(BIN) $(ICONS) $(DESTDIR)/etc
        install ./gentoo $(BIN)
        install -m644 icons/* $(ICONS)
        install -m644 gentoorc-example $(DESTDIR)/etc/gentoorc
        
你一定会注意到规则里在其他命令前有了一个 install -d 命令。原始的
Makefile 文件中没有它,因为通常情况下当你执行 make
install 命令时, /usr/local/bin
和用到的其他目录早已存在于系统中。然而当我们要向新建的私有目录树中安装时,我们必须创建其中的每一个目录。
我们还可以在末尾添加上其他的内容,比如上游作者有时会省略的附加文档:
        install -d $(DESTDIR)/usr/share/doc/gentoo/html
        cp -a docs/* $(DESTDIR)/usr/share/doc/gentoo/html
        
仔细检查后如果没有问题,使用 dquilt 创建
debian/patches/install.patch 补丁文件并添加对它的描述:
$ dquilt refresh $ dquilt header -e ... 描述补丁
现在你有了一系列的补丁。
修复上游 Bug:debian/patches/fix-gentoo-target.patch
Debian 特有的打包时修改:debian/patches/install.patch
当进行任何非 Debian 特有的修改时,比如
debian/patches/fix-gentoo-target.patch,一定要向上游作者进行反馈,以便上游作者方便在下一版本中以使更多人受益。同时请记住不要做出特别针对
Debian 或 Linux (甚至是 Unix!)的修改,要使其可以移植,这会使你的修改更容易被接受。
注意你不一定要把 debian/* 都提交到上游。
还有另外一个常见的问题:不同平台之间的库名称常常因平台而异。例如一个 Makefile 中可能引了用一个
Debian 系统中不存在的库。这种情况下我们需要将其修改为 Debian 中存在的、提供完全相同功能的库。
如果你手中程序的 Makefile(或
Makefile.in)中有如下的行。
LIBS = -lfoo -lbar
如果你的程序由于 foo 库不存在,而 Debian 系统中的 foo2
库提供了其等效,那么你可以修复这个构建问题并将修改记录到 debian/patches/foo2.patch
中,只需要将 foo 切换到 foo2:[26]
$ dquilt new foo2.patch $ dquilt add Makefile $ sed -i -e 's/-lfoo/-lfoo2/g' Makefile $ quilt refresh $ quilt header -e ... 描述补丁
[22]  debian/patches 目录应当是运行 dh_make
时生成的。因为假设的是在更新一个已存在的软件包,所以在这个例子中我们新建它。  
[24]  对于单份源码生成多个二进制包的情况,dh_auto_install
将临时目录设置为debian/tmp,而 dh_install
命令则将文件按照
debian/ 和
package-1.installdebian/
等文件的描述将 package-2.installdebian/tmp 中的文件分别装入
debian/ 和
package-1debian/ 等临时目录,用以创建
package-2 和
package-1_*.deb 等二进制软件包。
package-2_*.deb
[25]  这只是一个演示 Makefile 正常形态的例子。如果
Makefile 是通过 ./configure
命令生成的,那么修复该类 Makefile 的方法是通过
dh_auto_configure 来执行
./configure,并带上包括 --prefix=/usr 的默认选项。  
[26] 如果从 foo 库切换到 foo2
库时要更改应用程序接口(API),这就要求我们修改源代码来符合新的 API。