创建软件包

来自 Arch Linux 中文维基

本文旨在帮助用户利用类似于 ports 软件的 Arch 构建系统来创建自己的软件包,这些软件包可以提交到 Arch 用户软件仓库 (AUR)。本文讲述了如何创建 PKGBUILD(5),这是一个描述如何构建软件包的文件,makepkg 会使用它来从源代码创建二进制软件包。Arch 软件包标准中有一些构建规则和提高软件包质量的方法。

概述[编辑 | 编辑源代码]

Arch Linux 中的软件包是通过 makepkg 工具以及存储在 PKGBUILD 文件中的信息编译的。运行 makepkg 时,系统将自动在当前目录下搜索 PKGBUILD文件,然后根据 PKGBUILD 把软件源码重新打包。成功编译后得到的二进制文件和可以得到的其他信息如包的版本信息和依赖关系等,都将被打包到一个文件叫pkgname.pkg.tar.zst 里,可以通过 pacman 进行安装。

一个 Arch 软件包就是一个使用 zstd(1) 压缩的 tar(1) 压缩包,或者叫 tarball 。它包含了以下由 makepkg 生成的文件:

  • 要安装的二进制文件;
  • .PKGINFO: 包含所有 pacman 处理软件包的元数据,依赖等等;
  • .BUILDINFO: 包含可复现编译需要的信息,参阅 BUILDINFO(5)
  • .MTREE: 包含了文件的哈希值与时间戳,pacman 能够根据这些储存在本地数据库的信息校验软件包的完整性;
  • .INSTALL: 可选的文件,可以用来在安装/升级/删除操作之后运行命令。(本文件只有在 PKGBUILD 中制定才会存在);
  • .Changelog: 一个可选的文件,保存了包管理员描述软件更新的日志。

准备工作[编辑 | 编辑源代码]

必需的软件包[编辑 | 编辑源代码]

首先,确定你已安装必须的工具包。安装 base-devel 元软件包应当足够;它会引入 make(1) 和其它一些编译源码时需要的工具。

创建包的一个关键工具是 makepkg(由 pacman 提供),它的功能请参阅 Arch 打包准则#Makepkg 的任务

下载并测试安装[编辑 | 编辑源代码]

下载你想打包的软件的源代码压缩包,解压,按照作者所说的步骤安装它。记录下在编译和安装软件过程中需要的所有命令或步骤。你将要在 PKGBUILD文件中重复这些命令和步骤。

大多数软件作者遵循三步走的安装惯例:

$ ./configure
$ make
# make install

如果你要测试程序能否正常工作,建议在这部分测试。

创建一个干净的 chroot[编辑 | 编辑源代码]

建议参考创建一个干净的 chroot英语Building in a clean chroot 来保证你的系统中的其它软件包和配置不会影响 PKGBUILD。这个方法容错性更强,是一个更加恰当的构建软件包的方法,通常能够发现那些你未曾意识到需要的依赖项,因为它们已经在你的系统中存在。

创建PKGBUILD[编辑 | 编辑源代码]

当你运行makepkg时,它会在当前工作目录寻找一个PKGBUILD文件。如果找到PKGBUILD文件,它会下载该软件的源代码,根据PKGBUILD文件中的指令编译它。PKGBUILD中的指令必须能完全被Bash解释。成功完成后,最后的二进制文件和包的元信息(即包的版本、依赖)被一起打包在pkgname.pkg.tar.zst文件包中,这个文件包可以使用pacman -U <package file>来安装。

要开始制作一个包,你应该先创建一个空工作目录,进入该目录,创建一个PKGBUILD文件。你可以复制PKGBUILD模板(位于/usr/share/pacman/)到工作目录,或者复制一个类似包的PKGBUILD也可以。如果你只想在别人的基础上更改一些选项的话,后一种方法比较方便。

定义PKGBUILD变量[编辑 | 编辑源代码]

PKGBUILD文件的编写例子可以在/usr/share/pacman/处找到。PKGBUILD文件中可能用到的一些变量意义的解释可以在PKGBUILD中找到。

makepkg 定义了两个变量,你应该在编译和安装的过程中使用它们:

srcdir
makepkg将会把源文件解压到此文件夹或在此文件夹中生成指向 PKGBUILD 里 source 数组中文件的软连接。
pkgdir
makepkg会把该文件夹当成系统根目录,并将软件安装在此文件夹下。

这些变量都是绝对路径, 即意味着, 如果你合适地使用这些变量, 就不用担心当前工作目录的影响.

注意: build()package()函数在运行过程中都应当是非交互的。在这些函数中调用交互工具或脚本可能会中断makepkg的运行。(参考FS#13214
注意: 如果你是接手别人的包,除了把你的名字列为包维护者(Maintainers)外,你还应当把之前的维护者列为贡献者(Contributors)。

PKGBUILD 函数[编辑 | 编辑源代码]

一共有五个函数, 以下按照它们执行的先后顺序列出。package() 函数是每个 PKGBUILD 中必须的函数,其余不存在的函数可以跳过。

prepare()[编辑 | 编辑源代码]

此函数会执行用于预处理源文件以进行构建的命令, 例如 patching. 此函数执行在 build() 之前, 软件包解压之后. 如果解压过程被跳过 (makepkg -e), 那么 prepare() 函数就不会被执行.

注意: (从 PKGBUILD(5)) 中可以知道, 该函数运行在 bash -e 模式下, 意味着任何以非零状态退出的命令都会造成该函数中止.

不清楚应该放到 prepare() 还是 build(), 只需要记得 prepare() 中的步骤仅在解压后执行一次,而 build() 中的步骤会在每次编辑后都执行一次。

pkgver()[编辑 | 编辑源代码]

pkgver() 会在抓取并解压源文件,执行 prepare() 后执行此函数。

为使用 git/svn/hg 等工具的项目打包时,由于它们的构建过程相同, 但源文件可能每天甚至每小时更新一次,这一特性将会十分有用。过去的方法是把日期写入到 pkgver 变量中, 但这样一来 makepkg 会在即使软件没有更新的情况下依然重新构建软件包, 因为它会认为软件包的版本改变了. 其他与此有关的命令有 git describe, hg identify -ni 等等. 请在提交 PKGBUILD 前做好测试, 因为如果 pkgver() 执行失败, 整个构建过程都会终止.

注意: pkgver 不能含有空格或连接符 (-). 通常都会用 sed 来进行修改.

build()[编辑 | 编辑源代码]

现在你需要编写PKGBUILD文件中的build()函数。这个函数使用通用的shell命令来自动编译软件并创建软件的安装目录。这允许makepkg无需详查你的文件系统就可以打包你的软件。

build()函数中第一步就是进入由解压源码包所生成的目录。 makepkg 会在执行 build() 函数之前更改当前目录为 $srcdir; 因此, 大多数情况下第一条命令是这样的(参考示例文件/usr/share/pacman/PKGBUILD.proto):

cd "$srcdir/$pkgname-$pkgver"

现在,你需要把你当时手动编译软件时用到的命令一一列上。build()基本上会自动运行你当时手动输入的命令并在伪root环境下编译该软件。如果你要打包的软件使用了一个配置脚本,最好在配置中加上--prefix=/usr。许多软件都将自己安装到/usr/local下,我们仅仅推荐当你手动从源码安装时这么做。所有的Arch Linux软件包都应当使用/usr目录。

./configure --prefix=/usr
make
注意: 如果你的软件不需要构建任何东西, 请不要使用 build() 函数. 但package() 函数依然是必须的.

check()[编辑 | 编辑源代码]

用来执行make check和其他一些例行测试的地方。如果不需要可以通过在 PKGBUILD/makepkg.conf 中使用 BUILDENV+=('!check') 或者给 makepkg 传入参数 --nocheck 来禁用它。

package()[编辑 | 编辑源代码]

最后一步就是把编译好的文件放到pkg文件夹——一个简单的伪root环境。pkg目录复制了根目录下软件安装路径的继承关系。如果你需要手动把文件放到根目录下,那么在这里你需要把文件放在pkg下相同的文件层级结构中。比如,你想把一个文件安装到/usr/bin,那么在伪root环境中对应的路径为$pkgdir/usr/bin。极少情况下的安装步骤需要用户手动复制大量的文件到某个地方。大部分软件安装时只需要调用make install即可。为了将软件安装到正确的路径,最后一行一般应该这样写:

make DESTDIR="$pkgdir/" install
注意: 有时候在Makefile里没有使用DESTDIR;你可能需要使用prefix来替代。如果软件包是用autoconf/automake来创建的,那就使用DESTDIR;如果DESTDIR不起作用,试试make prefix="$pkgdir/usr/" install。如果这还不起作用的话,你就需要深入检查软件的安装命令了。

makepkg --repackage 命令只运行package()函数,它只是将文件打包成软件包,并不运行编译过程。如果你只是更改了PKGBUILD中的依赖,用这个命令来打包可以节省很多时间。

测试PKGBUILD文件[编辑 | 编辑源代码]

你在写PKGBUILDbuild()方法时,会想频繁的测试你所做的改动以确保没有bug。你可以在包含 PKGBUILD的目录下运行makepkg命令来确保没有问题。如果PKGBUILD没有错误,将会生成一个包,但是如果PKGBUILD被破坏或未完成,它将抛出一个错误。

如果运行makepkg 成功,在你工作的目录下将会生成一个名为$pkgname-$pkgver.pkg.tar.gz的新文件。这个文件可以使用pacman -Upacman -A安装,你也可以将它加到本地或网上的软件仓库中。注意,一个包被构建并不代表你的工作就完成了!只有当所有文件的结构都正确才能确保完成,例如你给了一个不正确的前缀就不行。你可以使用pacman的查询功能显示软件包包含的文件及依赖的文件,然后将它于你认为正确的对比。"pacman -Qlp <package file>" 和"pacman -Qip <package file>" 可以完成这项工作。

如果包看起来是正确的,那你的工作就完成了。但是如果你打算发布这个包或PKGBUILD,你就需要确认确认再确认包的依赖关系。

同样要确保安装的软件确实很完美的运行!如果你释放了一个包括所有必需文件的包,但是由于一些配置选项使它不能很好的工作,这真是让人恼火。如果你只是为你自己的系统安装这个软件,你就不必做这个质量保证了,因为只有你一个人需要忍受这些错误。

检查包的逻辑性[编辑 | 编辑源代码]

确定包可以正常使用后,再使用namcap英语namcap来检查错误:

$ namcap PKGBUILD
$ namcap <package file name>.pkg.tar.zst

Namcap将会做以下工作:

  1. 检查PKGBUILD文件里的一些常见错误
  2. ldd扫描包中所有的ELF文件,自动报告缺失或可去除的依赖。
  3. 启发式搜寻缺失或冗余的依赖。

要养成用namcap检查包的习惯,以避免提交包后再做修复的麻烦。

把包提交给AUR[编辑 | 编辑源代码]

请参考AUR submission guidelines,里面详细介绍了提交流程。

总结[编辑 | 编辑源代码]

  • 下载你希望打包的软件源代码
  • 试着编译安装包到任意目录
  • 复制PKGBUILD的文件模板 /usr/share/pacman/PKGBUILD.proto到一个临时的目录并重命名为 PKGBUILD
  • 根据具体情况修改 PKGBUILD 文件
  • 运行 makepkg 看看输出的打包结果是否正确
  • 如果不正确,重复前两个步骤

注意事项[编辑 | 编辑源代码]

  • 在开始自动打包之前,请确保你至少已成功手动打包一次,除非你“很清楚”你正在做什么。不幸的是,虽然大多数软件作者遵循了三步走的安装惯例:./configure; make; make install,但事情并不都是这样的,有时候你不得不自己打补丁才能安装成功。经验是:如果你手动无法编译成功或者无法将软件安装到指定子目录下,那你就不必费心打包了。makepkg没有任何魔力能消除源代码的问题让你编译成功。
  • 在一些情况下,你可能无法直接得到包的源码,可能需要使用sh installer.run这样的东西来工作。这时就需要你自己做很多工作了(比如读READMEs,安装指导,手册,或者Gentoo的ebuilds等等)。在一些很变态的情况下,你需要自己编辑源码才能正常安装。但是,makepkg需要完全自主运行,不能有用户的干预。因此,如果你想修改makefiles,你需要随PKGBUILD附上一个定制的补丁,然后在prepare()函数里安装这个补丁;或者你可以在prepare()函数里通过sed来修改。

更详细的规则[编辑 | 编辑源代码]

Arch 打包准则

32 位CLRCMakeCrossDKMSEclipseElectronFontFree PascalGNOMEGoHaskellJavaKDE内核模块LispMesonMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyRustVCSWebWine

PKGBUILD 生成器[编辑 | 编辑源代码]

某些软件包的 PKGBUILD 可以通过工具自动生成。

注意: 用户需要在提交文件到 AUR 前确保软件包满足高质量标准。

参考[编辑 | 编辑源代码]