Creating packages (简体中文)
本文旨在帮助用户利用 Arch Linux 的类似 ports 的软件包构建系统创建自己的软件包。包含了创建 PKGBUILD – 一个包创建描述文件,由 makepkg
使用来从源代码创建二进制包。Arch 软件包标准包含当前规则和提高软件包质量的方法。如果已经有了 PKGBUILD
文件,请参考 makepkg (简体中文).
概述
Arch Linux 中的软件包是通过 makepkg 工具以及存储在 PKGBUILD 文件中的信息编译的。运行makepkg
时,系统将自动在当前目录下搜索 PKGBUILD
文件,然后根据PKGBUILD
把软件源码重新打包。成功编译后得到的二进制文件和可以得到的其他信息如包的版本信息和依赖关系等,都将被打包到一个文件叫name.pkg.tar.zst
里,可以通过pacman -Up <package file>
进行安装。
一个 Arch 软件包仅仅是一个使用 zstd(1) 压缩的 tar 压缩包,或者叫 'tarball'。它包含了以下由 makepkg 生成的文件:
- 要安装的二进制文件
-
.PKGINFO
: 包含所有 pacman 处理软件包的元数据,依赖等等。
-
.BUILDINFO
: 包含可复现编译需要的信息,仅在 pacman 5.1 及之后编译的软件包中。请参阅 BUILDINFO(5).
-
.MTREE
: 包含了文件的哈希值与时间戳. pacman 能够根据这些储存在本地数据库的信息校验软件包的完整性.
-
.INSTALL
: 可选的文件,可以用来在安装/升级/删除操作之后运行命令。(本文件只有在PKGBUILD
中制定才会存在。)
-
.Changelog
: 一个可选的文件,保存了包管理员描述软件更新的日志。(不是所有包中都存在。)
准备工作
必需的软件包
首先,确定你已安装必须的工具包。安装 base-devel应该足够了;它包含make和其它一些从源码编译时所需要的工具。
创建包的一个很重要的工具是makepkg(由pacman提供),它主要做以下工作:
- 检查相关依赖是否安装。
- 从指定的服务器下载源文件。
- 解压源文件。
- 编译软件并将它安装于伪root环境下。
- 删除二进制文件和库文件的符号连接。
- 生成包的meta文件。
- 将伪root环境压缩成一个包文件
- 将生成的包文件保存到配置的文件夹中(默认为当前工作目录)。
下载并测试安装
下载你想打包的软件的源代码压缩包,解压,按照作者所说的步骤安装它。记录下在编译和安装软件过程中需要的所有命令或步骤。你将要在PKGBUILD文件中重复这些命令和步骤。
大多数软件作者遵循三步走的安装惯例:
./configure make make install
这是一个能确保程序正常运行的好时机。
创建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会把该文件夹当成系统根目录,并将软件安装在此文件夹下。
这些变量都是绝对路径, 即意味着, 如果你合适地使用这些变量, 就不用担心当前工作目录的影响.
PKGBUILD 函数
一共有五个函数, 以下按照它们执行的先后顺序列出。package()
函数是每个 PKGBUILD 中必须的函数,其余不存在的函数可以跳过。
prepare()
此函数会执行用于预处理源文件以进行构建的命令, 例如 patching. 此函数执行在 build() 之前, 软件包解压之后. 如果解压过程被跳过 (makepkg -e
), 那么 prepare()
函数就不会被执行.
bash -e
模式下, 意味着任何以非零状态退出的命令都会造成该函数中止.pkgver()
pkgver()
会在抓取并解压源文件,执行 prepare() 后后执行此函数。
如果你正在制作 git/svn/hg 等构建过程相同, 但源文件可能每天甚至每小时更新一次的软件包的时候, 这一特性是十分有用的. 过去的方法是把日期写入到 pkgver 变量中, 但这样一来 makepkg 会在即使软件没有更新的情况下依然重新构建软件包, 因为它会认为软件包的版本改变了. 其他与此有关的命令有 git describe
, hg identify -ni
等等. 请在提交 PKGBUILD 前做好测试, 因为如果 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文件
你在写PKGBUILD
的 build()
方法时,会想频繁的测试你所做的改动以确保没有bug。你可以在包含 PKGBUILD
的目录下运行makepkg
命令来确保没有问题。如果PKGBUILD
没有错误,将会生成一个包,但是如果PKGBUILD
被破坏或未完成,它将抛出一个错误。
如果运行makepkg
成功,在你工作的目录下将会生成一个名为$pkgname-$pkgver.pkg.tar.gz的新文件。这个文件可以使用pacman -U
或 pacman -A
安装,你也可以将它加到本地或网上的软件仓库中。注意,一个包被构建并不代表你的工作就完成了!只有当所有文件的结构都正确才能确保完成,例如你给了一个不正确的前缀就不行。你可以使用pacman的查询功能显示软件包包含的文件及依赖的文件,然后将它于你认为正确的对比。"pacman -Qlp <package file>" 和"pacman -Qip <package file>" 可以完成这项工作。
如果包看起来是正确的,那你的工作就完成了。但是如果你打算发布这个包或PKGBUILD,你就需要确认确认再确认包的依赖关系。
同样要确保安装的软件确实很完美的运行!如果你释放了一个包括所有必需文件的包,但是由于一些配置选项使它不能很好的工作,这真是让人恼火。如果你只是为你自己的系统安装这个软件,你就不必做这个质量保证了,因为只有你一个人需要忍受这些错误。
检查包的逻辑性
确定包可以正常使用后,再使用namcap来检查错误:
$ namcap PKGBUILD $ namcap <package file name>.pkg.tar.zst
Namcap将会做以下工作:
- 检查PKGBUILD文件里的一些常见错误
- 用
ldd
扫描包中所有的ELF文件,自动报告缺失或可去除的依赖。 - 启发式搜寻缺失或冗余的依赖。
要养成用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
来修改。
更详细的规则
32-bit – CLR – CMake – Cross – DKMS – Eclipse – Electron – Font – Free Pascal – GNOME – Go – Haskell – Java – KDE – Kernel – Lisp – Meson – MinGW – Node.js – Nonfree – OCaml – Perl – PHP – Python – R – Ruby – Rust – VCS – Web – Wine
PKGBUILD 生成器
某些软件包的 PKGBUILD 可以通过工具自动生成。
- Haskell: cblrepo, arch-hs
- Node.js: nodejs-npm2archAUR npm2arch
- Python: pipman-gitAUR, pip2arch-gitAUR, python-pypi2pkgbuildAUR
- Ruby: gem2archAUR, pacgemAUR
- Rust: cargo-pkgbuildAUR