目录
让我们尝试创建一个自己的软件包(或者,“收养”一个已存在的软件包则更好)。
如果你要基于某个上游程序构建软件包,那么典型的Debian软件包构建流程就会包含生成几个特定的文件,如下:
获取上游软件的拷贝,通常为压缩过的tar格式。
package
-version
.tar.gz
在上游程序的 debian
目录下添加 Debian 特定的打包修改,并以 3.0
(quilt)
格式创建一个非本地源码包。(也就是指用于构建 Debian 软家包的输入文件集合)
package
_version
.orig.tar.gz
package
_version
-revision
.debian.tar.gz
[4]
package
_version
-revision
.dsc
从 Debian 源码包构建 Debian 二进制包;二进制包的格式通常是.deb
(或者
.udeb
,Debian Installer 专用)
package
_version
-revision
_arch
.deb
请注意,在 Debian 软件包文件名中,分隔
和
package
的字符从 tarball 名称的
version
-
(连字符)换成了 _
(下划线)。
在上述的文件名中,将
部分替换为
package name, 将
package
部分替换为 upstream version,
将version
部分替换为 Debian revision,以及将
revision
部分替换为 package architecture,根据 Debian 方针手册。 [5]
arch
本大纲中的每一步都会在后续的章节中辅以详细的例子进行解释。
可能你已经选好了要制作的软件包。第一件要做的事是检查它是否已经存在于发行版仓库中了,参考方法如下:
aptitude 命令
the Debian packages 页面
如果软件包已经存在,直接安装就好了!:-) 如果它是被 抛弃(orphaned) 的——也就是说它的维护者被设置为 Debian QA Group,那么你可以尝试接手维护它。你也可以“收养”维护者发出“Request for Adoption”(RFA)请求的软件包。[6]
软件包归属状态有这几种:
作为旁注必须指出,Debian 已经拥有了绝大多数类型软件的软件包,仓库中软件包的数量也远远超过了有上传权限的贡献者的数量。因此,为已经在仓库中的软件包贡献力量是非常受其他开发者欢迎的(且更容易获得 sponsorship)[7]。你可以通过非常多的方式来实现这一目的:
接手被抛弃而仍然被很多人使用的软件包。
加入 打包小组。
为某些常用的软件包分类 Bug。
在需要时准备 QA 或 NMU 上传。
如果你有能力“收养”那个软件包,下载(使用 apt-get source
或其他类似的工具)并分析它的代码。这篇文档没有包含有关如何接手软件包的详细信息,但幸运的是由于接手软件包时起始的工作已经有人完成,接手的工作应比从头开始轻松得多。尽管如此,请继续阅读,下面给出的建议会对你很有帮助。
packagename
如果你要制作的软件包是全新的,并且希望它出现在 Debian 中,请按照以下的步骤进行:
首先,你必须知道这个软件的可用性,并且需要试用一段时间。
你必须在 Work-Needing and Prospective
Packages 上查看以确定没有其他人已经开始了工作。如果没有,则提交一份 ITP (Intent To Package) Bug
报告到 wnpp
伪软件包(可以使用
reportbug)。如果已经有人在处理,则在需要的情况下联系他或他们。如果不需要你的帮助,就寻找其他你感兴趣且没有人维护的软件包吧。
该软件 必须有一个许可证。
对于 main
类的软件, Debian 方针要求它 完全兼容
Debian Free Software Guidelines (Debian 自由软件准则) (DFSG) 并且 不要求用
main
类以外的软件来编译或执行。这是最理想的状况。
对于 contrib
类的软件,其许可证必须满足 DFSG 的全部条件,但可以依赖于
main
之外的软件包以完成编译或运行。
对于 non-free
类的软件,其许可证可以不满足 DFSG 中的一些条件,但至少 必须是可分发的。
如果你不清楚你的软件应该分入哪一类,则把许可证文本发送到 debian-legal@lists.debian.org 以寻求意见。
程序 不应该 给 Debian 系统带来安全和维护上的问题。
程序应当有良好的文档,最好源代码也容易理解(比如,不混乱)。
你应该与程序的作者取得联系问一下他是否认为程序应当被打包,以及他是否对 Debian 友好。能够询问作者关于程序的任何问题是非常重要的,所以不要尝试打包一个无人维护的软件。
程序一定 不应该 setuid 到 root 。更好的情况是它不 setuid 或 setgid 到任何用户或组。
程序不应该是守护进程,也不应该进入 */sbin
目录或者以 root 打开任何端口。
当然,这些问题都只是为了安全,并试图让你不至于在比如 setuid 守护进程等问题上犯错误而激怒了用户... 当你在打包方面有了更多经验时,就可以处理这样的软件包了。
我们鼓励你,作为一个新维护人员,选择易于打包和维护的软件包,而不鼓励选择复杂的软件包。
简单软件包
单二进制软件包,arch = all (比如像壁纸那样的资料集)
单二进制软件包,arch = all (用解释型语言编写的可执行脚本文件,比如 POSIX shell)
中等复杂软件包
单二进制软件包,arch = any (用C/C++等语言编写的 ELF 二进制可执行文件)
复合二进制软件包,arch = any + all (包含ELF二进制可执行程序+文档的软件包)
既不是 tar.gz
也不是 tar.bz2
格式的上有源代码
源代码中包含不可分发的内容。
高复杂软件包
被其他软件包使用的解释器模块包
被其他软件包使用的一般ELF库文件包
复合二进制的软件包,包含ELF库文件包
多上游的源码包
内核模块软件包
内核补丁软件包
包含冷门维护者脚本的软件包
打包高复杂软件包并非难如登天,但需要更多知识。你应该针对每一个复杂特性来搜寻针对性的指南。比如,一些语言有它们自己的子策略文档:
还有一句拉丁谚语:fabricando fit faber (熟能生巧)。我们
强烈 建议你在阅读这篇教程的时候,用一个简单软件包来实践和实验所有的 Debian
打包步骤。下边的步骤创建了一个微不足道的软件包 hello-sh-1.0.tar.gz
,它可以提供一个良好的起点:[8]
$ mkdir -p hello-sh/hello-sh-1.0; cd hello-sh/hello-sh-1.0 $ cat > hello <<EOF #!/bin/sh # (C) 2011 Foo Bar, GPL2+ echo "Hello!" EOF $ chmod 755 hello $ cd .. $ tar -cvzf hello-sh-1.0.tar.gz hello-sh-1.0
第一件要做的事就是找到并下载原始的源代码。我们假定你已经从作者的主页上找到了它的源代码。Unix 下的自由软件源代码通常是以
tar+gzip 格式(扩展名为
.tar.gz
)或
tar+bzip2 格式(扩展名为
.tar.bz2
)或tar+xz
(扩展名为.tar.xz
)的形式提供的。通常归档文件中包含了一个名为
的子目录,里面包含了全部的源代码。
package
-version
如果最新你版本的源代码可通过像 Git,Subversion,CVS 这样的版本控制系统获得,你可以用 git
clone
, svn co
, 或 cvs co
来下载它,并自行将它重新打包为 tar+gzip, 别忘了
--exclude-vcs
选项。
如果你的程序源代码是以其他形式提供的(比如文件名以 .Z
或
.zip
结尾[9]),则使用合适的工具将其解包,再重新打包。
如果你的程序源代码中包含一些不符合DFSG的内容,你应当解包后移除它们,再以添加了 dfsg
的上游版本号重新打包。
作为示例,我将使用一个名为 gentoo 的程序,它是一个 GTK+ 文件管理器。[10]
在你的用户主目录下创建一个子目录,命名为 debian
或 deb
或其他你喜欢且合适的名字(本例中使用 ~/gentoo
)。把下载好的归档文件放在其中并解包(使用
tar xzf gentoo-0.9.12.tar.gz
命令)。要确定解包过程中没有发生错误,即便是有一点
不恰当
也不行,因为在别人的系统上解包这些文件时,可能他们的工具并不忽略这些反常的现象,于是就会出现问题。在你的终端屏幕上,应该看到如下的情形。
$ mkdir ~/gentoo ; cd ~/gentoo
$ wget http://www.example.org
/gentoo-0.9.12.tar.gz
$ tar xvzf gentoo-0.9.12.tar.gz
$ ls -F
gentoo-0.9.12/
gentoo-0.9.12.tar.gz
现在又有了一个新的子目录,名为 gentoo-0.9.12
。进入该目录并
彻底 读完其中的文档。通常情况下这些文档被命名为
README*
、INSTALL*
、*.lsm
或 *.html
。你必须找到关于如何正确编译和安装程序的指导(最可能的是他们会默认你希望把程序安装到
/usr/local/bin
目录;但事实上你不能那样做,详细的内容稍后将在 第 3.3 节 “把文件安装到目的位置” 中说明)。
开始打包时源代码目录应当是绝对干净(原始)的,或者直接使用刚刚解包得到的源代码。
带有 Makefile
文件的简单程序可以很容易地使用 make
来编译。[11] 其中的一些还支持 make
check
,这可以完成一系列自检。编译好后可以使用 make install
来将程序安装到目标目录。
现在尝试编译和运行你的程序,确保它工作正常,且在安装和运行时不会导致其他问题。
你还可以运行 make clean
(或更好的 make
distclean
)来清理编译目录。有时还会带有 make uninstall
用以卸载已经安装了的文件。
非常多的自由软件是使用 C 和 C++ 语言编写的。其中的有很多使用 Autotools 或 CMake
来使其可以在不同平台上移植。这些工具首先用于生成 Makefile
和其他必须的源文件,然后这些程序可以使用正常的 make; make install
来编译和安装。
Autotools 是 GNU 编译系统工具,包括 Autoconf、Automake、Libtool 和
gettext。你可以通过
configure.ac
、Makefile.am
和
Makefile.in
等文件来识别这种类型的源代码。[12]
使用 Autotools 的第一步是在上游作者在代码中运行 autoreconf -i -f
,然后把生成的文件同源代码一起分发。
configure.ac-----+-> autoreconf -+-> configure Makefile.am -----+ | +-> Makefile.in src/Makefile.am -+ | +-> src/Makefile.in | +-> config.h.in automake aclocal aclocal.m4 autoheader
编辑 configure.ac
和 Makefile.am
等文件需要一些关于 autoconf 和 automake 的知识。参看
info autoconf
和 info automake
。
使用 Autotools 的第二步是用户获得分发的源代码后在源码目录下运行 ./configure &&
make
来将其编译成为 binary
(二进制可执行程序)。
Makefile.in -----+ +-> Makefile -----+-> make -> binary
src/Makefile.in -+-> ./configure -+-> src/Makefile -+
config.h.in -----+ +-> config.h -----+
|
config.status -+
config.guess --+
你可以改变 Makefile
文件中的许多设置,比如修改默认的文件安装位置(使用
./configure --prefix=/usr
)。
尽管不是必须的:你还可以使用 autoreconf -i -f
来更新
configure
和其他相关文件,这样做有可能提高源代码的兼容性。 [13]
CMake 是另一个可选的构建系统,你可以通过
CMakeLists.txt
文件来识别使用它的源代码。
如果上游源代码以像 gentoo-0.9.12.tar.gz
的形式分发,你可以用
gentoo
作为(源代码) 软件包名
,并用 0.9.12
作为 上游版本。
它们会被 debian/changelog
这个文件用到;该文件一会会在 第 4.3 节 “changelog
” 部分详细描述。
虽然这个简单的方法在大部分情况下能够显灵,但你仍需要能根据 Debian 方针和惯例来调整 软件包名 和 上游版本 。
你必须让 软件包名 里只留下 小写字母
(a-z
), 数字 (0-9
), 加号
(+
) 和 减号 (-
) , 以及 点号
(.
)。 软件包名最短长度两个字符;必须以字母开头;不能与库存软件包名冲突。相信我,把软件包名的长度控制在 30
字符以内是明智之举。 [14]
如果上游在它的名称中使用了一些通用术语比如 test-suite
,
那么将其重命名,以显式指明其内容并避免命名空间污染。 [15]
你可以让 upstream version 中只包含字母和数字
(0-9A-Za-z
), 加号 (+
), 波浪号
(~
), 以及 点号(.
)。它必须以数字开头
(0-9
)。 [16]
如果可能的话,最好把它的长度控制在8字符以内。 [17]
如果上游不使用像 2.30.32
这样的常规版本格式,而是用类似
11Apr29
这样的日期作为版本,亦即随机的代号字符串,或者以VCS的哈希值作为版本号的一部分,那么请确认将其从
upstream version 中移除。 这样的信息可以记录在
debian/changelog
文件中。 如果你需要发明一个版本字符串,请使用
YYYYMMDD
这个格式作为上游版本,比如 20110429
。这可以确保
dpkg 在升级软件包时正确解读新版本。 如果需要确保未来能够平滑过渡到类似
0.1
这样的版本号的话,请使用 0~YYMMDD
格式作为上游版本,例如
0~110429
。
版本字符串 [18] 可以用 dpkg(1) 来进行比较:
$ dpkg --compare-versionsver1
op
ver2
版本比较规则可以总结为以下几点:
字符串会被从头到尾进行比较。
字母比数字大。
数字作为整数进行比较。
字母按照 ASCII 编码顺序进行比较。
对于点号 (.
),加号 (+
),以及波浪号
(~
) 则要应用特殊规则,具体如下:
0.0
< 0.5
<
0.10
< 0.99
<
1
< 1.0~rc1
<
1.0
< 1.0+b1
<
1.0+nmu1
< 1.1
<
2.0
有一种比较棘手的情况,当上游释出
gentoo-0.9.12-ReleaseCandidate-99.tar.gz
作为
gentoo-0.9.12.tar.gz
的预发布版本时,就需要确保升级工作妥当进行:重命名该上游源代码为
gentoo-0.9.12~rc99.tar.gz
.
首先我们设置两个 环境变量,$DEBEMAIL
和
$DEBFULLNAME
,这样能使使大多数 Debian
维护工具能够正确识别你用于维护软件包的姓名和电子邮件地址。[19]
$ cat >>~/.bashrc <<EOF DEBEMAIL="your.email.address@example.org" DEBFULLNAME="Firstname Lastname" export DEBEMAIL DEBFULLNAME EOF $ . ~/.bashrc
一般的 Debian 软件包是由上游程序产生的 外来 Debian 软件包。 若你想要用上游源代码
gentoo-0.9.12.tar.gz
创建一个外来 Debian 软件包,你可以为它创建一个初始的外来
Debian 软件包,通过如下方法调用 dh_make 命令:
$ cd ~/gentoo $ wget http://example.org/gentoo-0.9.12.tar.gz $ tar -xvzf gentoo-0.9.12.tar.gz $ cd gentoo-0.9.12 $ dh_make -f ../gentoo-0.9.12.tar.gz
当然,请用你原始源码归档的名字来替换 filename (文件名)。 [20] 详情请参见 dh_make(8) 。
你应该会看到一些输出,它们询问你想要创建什么类型的软件包。这里的 Gentoo 是一个单一二进制包 -- 它仅仅创建一个二进制包, 亦即, 一个
.deb
文件 -- 于是我们就选择第一项 (用 s
键),
检查屏幕上的信息, 并按
键来确认。
[21]
ENTER
执行 dh_make 后,上一级目录中自动创建了一份上游 tarball 的副本,名为
gentoo_0.9.12.orig.tar.gz
,这个文件和稍后介绍的
debian.tar.gz
在一起满足了 Debian 非本地源代码包的要求。
$ cd ~/gentoo ; ls -F gentoo-0.9.12/ gentoo-0.9.12.tar.gz gentoo_0.9.12.orig.tar.gz
请注意 gentoo_0.9.12.orig.tar.gz
这个文件名的两个关键特点:
软件包名称和版本是以字符 _
(下划线)分隔的。
.tar.gz
扩展名前插有 .orig
。
你应该可以注意到 debian
目录下有了许多模板文件。这些文件将在 第 4 章 debian
目录中的必须内容 和 第 5 章 debian
目录下的其他文件
中一一解释。你还应该明白,打包没办法变成全自动的过程。你还需要按照 第 3 章 修改源代码 中的方法来为 Debian
修改软件包。此后,你还要按照 第 6 章 构建软件包 中叙述的合适的方法来构建 Debian 软件包,并按照 第 7 章 检查软件包中的错误 中的方法进行测试,最终依照 第 9 章 上传软件包
的介绍将其上传。本教程将对所有的这些步骤进行解释。
如果你在修改过程中不小心删除或弄坏了某些模板文件,你可以使用 dh_make 加上
--addmissing
参数来将其还原。
更新一个已存在的软件包可能比较复杂,因为它可能使用了旧技术。在学习基本功的阶段,请只创建全新的软件包;稍后的 第 8 章 更新软件包中会有更细致的讲解。
请注意,源代码文件不必包含任何在第 2.4 节 “简易构建系统” 和 第 2.5 节 “常见的可移植的构建系统”
中谈论到的构建系统。 就算仅仅是图像数据集合之类的也可以。文件的安装可以使用 debhelper
的配置文件来摆平,比如
debian/install
(参见 第 5.11 节 “install
”)。
[4] 对于旧式的 1.0
格式非本地 Debian 源码包,应当使用
。 package
_version
-revision
.diff.gz
[5] 参见 5.6.1 "Source", 5.6.7 "Package", 以及 5.6.12 "Version"。 package architecture 遵循 Debian Policy Manual, 5.6.8 "Architecture" 并且会在软件包构建的过程中被自动分配。
[7] 当然了,总有值得打包的新软件。
[8] 不用担心失踪的 Makefile
。你可以参照 第 5.11 节 “install
” ,简单地通过
debhelper 来安装 hello
程序,或者修改上游源代码来添加带有install
目标的新Makefile
,参照第 3 章 修改源代码
[9] 当文件扩展名不足以判断文件类型时,可以使用 file 命令来判断。
[11]
许多现代程序都配有一个叫做 configure
的脚本,它被执行的时候会生成一个为你机器定制的
Makefile
。
[12] 关于 Autotools 这个庞然大物的讨论已经超出本篇小教程的讨论范围。而本节旨在提供关键字和参考。如果你需要使用它,请认真研读 Autotools Tutorial 以及
/usr/share/doc/autotools-dev/README.Debian.gz
的本地副本。
[13] 你可以用 dh-autoreconf
软件包来将这个过程自动化。参见
第 4.4.3 节 “定制 rules
文件”.
[14] 在 aptitude 工具中,软件包名字段的默认最大长度为 30。 而对于 90% 以上的软件包来说,软件包名都少于 24 个字符。
[15] 如果你遵循 Debian Developer's Reference 5.1. "New packages", 那么在 ITP 过程中总是会遇到这样的问题。
[16] 这一条更严格的规则能帮助你避免混淆文件名。
[17] aptitude 命令的版本字段默认长度为10。其中通常 Debian 修订号和前置的连字符会消耗2个位置。对于 80% 以上的软件包来说,上游版本小于8字符,Debian 修订号小于2字符。对于 90% 以上的软件包来说,上游版本小于10字符,Debian 修订号小于3字符。
[18] 版本字符串可以是 upstream version
(
), Debian revision
(version
), 或者 version
(revision
)。
关于 Debian 修订号如何增长的信息,请参见 第 8.1 节 “新的 Debian 版本”Debian revision 。
version
-revision
[19] 以下默认你以 Bash 作为登陆 shell。如果你使用其他的 shell,例如 Z shell,那就使用它们的配置文件代替这里提到的
~/.bashrc
。
[20] 如果上游源代码已经提供了 debian
目录 以及其内容,那么带上参数
--addmissing
来执行dh_make 命令。 新的源码包格式
3.0 (quilt)
的鲁棒性(Robust)已经足够优秀,以不至于损坏,即使对于这类软件包。
另外,你可能需要更新上游提供的内容,以满足你的 Debian 软件包之需。
[21] 此处有这几种选择: s
代表单一二进制包, i
代表独立于体系结构的软件包,
m
代表复合二进制包, l
代表库文件包,k
代表内核模块包, n
代表内核补丁包,
b
代表 cdbs
软件包。本教程专注于使用 dh 命令 (来自 debhelper
软件包) 来创建单一二进制包,但 也会涉及到如何用它来创建 独立于体系结构
或 复合二进制软件包。软件包 cdbs
提供了 另一套可以代替
dh 命令的基础打包脚本,不过对它的描述已经超出了我们的讨论范围。