创建软件包
32 位 – CLR – CMake – 交叉编译 – DKMS – Eclipse 插件 – Electron – 字体 – Free Pascal – GNOME – Go – Haskell – Java – KDE – 内核模块 – Lisp – Meson – MinGW – Node.js – 非自由软件 – OCaml – Perl – PHP – Python – R – Ruby – Rust - 安全 – Shell – VCS – Web 应用程序 – Wine
本文旨在帮助用户使用类似于 ports 的 Arch 构建系统 创建自己的软件包,也用于提交到 Arch 用户仓库。它涵盖了 PKGBUILD(5) 的创建 — 一个由 makepkg 解析以从源代码创建二进制软件包的软件包构建描述文件。
有关现有规则和改进软件包质量的方法,请参阅 Arch 软件包标准。
概览
Arch Linux 中的软件包是使用 makepkg 实用程序和存储在 PKGBUILD
文件中的信息构建的。当 makepkg 运行时,它会在当前目录中搜索 PKGBUILD
,并按照其中的说明获取所需的文件和/或编译它们,以便打包到软件包文件 pkgname.pkg.tar.zst
中。生成的软件包包含二进制文件和安装说明,可供 pacman 安装。
Arch 软件包不过是一个 tar(1) 归档文件,或一个使用 zstd(1) 压缩的 tarball,其中包含由 makepkg 生成的以下文件
- 要安装的二进制文件。
.PKGINFO
: 包含 pacman 处理软件包、依赖项等所需的所有元数据。.BUILDINFO
: 包含可重现构建所需的信息,另请参阅 BUILDINFO(5)。.MTREE
: 包含文件的哈希值和时间戳,这些哈希值和时间戳包含在本地数据库中,以便 pacman 可以验证软件包的完整性。.INSTALL
: 一个可选文件,用于在安装/升级/删除阶段之后执行命令(此文件仅在PKGBUILD
中指定时存在)。.Changelog
: 一个可选文件,由软件包维护者保存,用于记录软件包的更改。
准备工作
必备软件
首先,确保必要的工具已经 安装:元软件包 base-devel 应该足够了;它引入了 make(1) 和从源代码编译所需的其他工具。
构建软件包的关键工具是 makepkg(由 pacman 提供)。它执行的任务可以在 Arch 软件包指南#Makepkg 职责 中找到。
下载并测试安装
下载您要打包的软件的源代码 tarball,解压缩它,并按照作者的步骤安装该程序。记下编译和安装它所需的所有命令和/或步骤。您将在 PKGBUILD
文件中重复这些相同的命令。
大多数软件作者坚持 3 步构建周期
$ ./configure $ make # make install
现在是确保程序正常工作的好时机。
设置干净的 chroot 环境
建议遵循 在干净的 chroot 环境中构建,以确保您的系统的软件包和配置不会导致 PKGBUILD
中出现错误。这是一种更健壮和正确的构建软件包的方法,并且通常会捕获您没有意识到的缺失依赖项,因为它们已经存在于您的系统中。
创建 PKGBUILD
当运行 makepkg
时,它会在当前工作目录中查找 PKGBUILD
文件。如果找到,它会下载软件的源代码并按照 PKGBUILD
文件中指定的说明进行编译。这些说明必须完全可由 Bash shell 解释。
成功完成后,生成的二进制文件和软件包的元数据,即软件包版本和依赖项,将打包在 pkgname.pkg.tar.zst
软件包文件中。可以使用 makepkg --install
(它将在后台调用 pacman)或直接使用 pacman -U pkgname.pkg.tar.zst
来安装新创建的软件包。
要开始构建新软件包,首先为软件包创建一个新目录,并将当前目录更改为该目录。然后,需要创建一个 PKGBUILD
文件:可以使用在 /usr/share/pacman/
中找到的 PKGBUILD
原型,或者您可以从另一个软件包的 PKGBUILD
开始。如果已经存在类似的软件包,后者可能是一个不错的选择。
示例 PKGBUILD
位于 /usr/share/pacman/
中。
PKGBUILD 变量
makepkg 预定义了以下变量,打包者应使用这些变量来引用构建过程中的临时位置
srcdir
- 这指向 makepkg 提取或符号链接源数组中所有文件的目录。
pkgdir
- 这指向 makepkg 打包已安装软件包的目录,该目录将成为您构建的软件包的根目录。
它们包含绝对路径,这意味着如果您正确使用这些变量,则无需担心您的工作目录。
build()
和 package()
函数,旨在是非交互式的。在这些函数中调用的交互式实用程序或脚本可能会破坏 makepkg,尤其是在启用构建日志记录 (--log
) 的情况下调用时。有关详细信息,请参阅 FS#13214。PKGBUILD 函数
构建软件包时,如果已在 PKGBUILD
中定义了以下五个函数,则 makepkg
将调用它们。函数 package()
是每个 PKGBUILD
中都必需的,并且将始终被调用。如果未定义任何其他函数,则 makepkg
将简单地跳过该函数的调用。
在构建期间,函数按照此处列出的顺序调用。
另请参阅 PKGBUILD(5) § 打包函数。
prepare()
此函数用于运行准备构建源的命令,例如 打补丁。此函数在软件包提取之后、pkgver() 和构建函数之前运行。如果跳过提取(makepkg --noextract
),则不运行 prepare()
。
bash -e
模式下运行,这意味着任何以非零状态退出的命令都将导致该函数退出。当不清楚是将某些内容放在 prepare()
还是 build()
中时,一个经验法则是将应该在提取源之后恰好运行一次的步骤放在 prepare()
中,并将手动编辑提取的文件后重新运行才有意义的步骤放在 build()
中。
pkgver()
pkgver()
在获取、提取源并执行 prepare() 后运行。因此,您可以在 makepkg 阶段更新 pkgver 变量。
如果您正在 制作 git/svn/hg/etc. 软件包,这尤其有用,其中构建过程可能保持不变,但源可能会每天甚至每小时更新。旧的实现方式是将日期放入 pkgver 字段中,如果软件没有更新,makepkg 仍然会重建它,认为版本已更改。一些有用的命令是 git describe
, hg identify -ni
等。请在提交 PKGBUILD
之前测试这些命令,因为 pkgver()
函数中的失败可能会停止构建。
-
)。使用 sed 来纠正这种情况很常见。build()
现在,您需要在 PKGBUILD
文件中实现 build()
函数。此函数使用 Bash 语法中的常用 shell 命令来自动编译软件并创建一个名为 pkg
的目录,用于安装软件。这允许 makepkg 打包文件,而无需筛选您的文件系统。
build()
函数的第一步是更改为通过解压缩源代码 tarball 创建的目录。在执行 build()
函数之前,makepkg 会将当前目录更改为 $srcdir
。因此,在大多数情况下,如 /usr/share/pacman/PKGBUILD.proto
中建议的那样,第一个命令将如下所示
cd "$pkgname-$pkgver"
现在,您需要列出您手动编译软件时使用的相同命令。build()
函数本质上自动化了您手动执行的所有操作,并在 fakeroot 构建环境中编译软件。如果您要打包的软件使用 configure 脚本,则在为 pacman 构建软件包时,最好使用 --prefix=/usr
。许多软件将文件安装到相对于 /usr/local
目录的位置,这仅在您手动从源代码构建时才应执行。所有 Arch Linux 软件包都应使用 /usr
目录。如 /usr/share/pacman/PKGBUILD.proto
文件中所示,接下来的两行通常如下所示
./configure --prefix=/usr make
build()
函数。build()
函数不是必需的,但 package()
函数是。check()
放置对 make check
和类似测试例程的调用。强烈建议使用 check()
,因为它有助于确保软件已正确构建并与其依赖项一起正常工作。
不需要它的用户(以及偶尔无法修复软件包以使其通过的维护者)可以通过在 PKGBUILD
/makepkg.conf(5) 的 options
数组中添加 !check
来禁用它,或者使用 --nocheck
标志调用 makepkg
。
如果您正在测试 GUI 应用程序,您可以 在虚拟 xserver 中运行它。
package()
最后一步是将编译后的文件放入一个目录中,makepkg 可以从中检索它们以创建软件包。默认情况下,这是 pkg
目录 — 一个简单的 fakeroot 环境。pkg
目录复制了软件安装路径的根文件系统的层次结构。如果您必须手动将文件放置在文件系统的根目录下,则应将它们安装在 pkg
目录下的相同目录结构中。例如,如果您想将文件安装到 /usr/bin
,则应将其放置在 $pkgdir/usr/bin
下。很少有安装过程需要用户手动复制数十个文件。相反,对于大多数软件,调用 make install
即可完成。最后一行应如下所示,以便将软件正确安装到 pkg
目录中
make DESTDIR="$pkgdir/" install
Makefile
中未使用 DESTDIR
;您可能需要改用 prefix
。如果软件包是使用 autoconf / automake 构建的,请使用 DESTDIR
;这是在手册中 记录 的。如果 DESTDIR
不起作用,请尝试使用 make prefix="$pkgdir/usr/" install
构建。如果这仍然不起作用,您将必须进一步研究 "make <...> install
" 执行的安装命令。makepkg --repackage
仅运行 package()
函数,因此它创建软件包而不进行构建。例如,如果您仅更改了软件包的 depends
变量,则可以节省时间。
测试 PKGBUILD 和软件包
在编写 build()
函数时,您需要经常测试您的更改,以确保没有错误。您可以使用包含 PKGBUILD
文件的目录中的 makepkg
命令来执行此操作。使用格式正确的 PKGBUILD
,makepkg 将创建一个软件包;使用损坏或未完成的 PKGBUILD
,它将引发错误。
如果 makepkg 成功完成,它将在您的工作目录中放置一个名为 pkgname-pkgver.pkg.tar.zst
的文件。可以使用 pacman -U
命令安装此软件包。但是,仅仅因为构建了软件包文件并不意味着它完全正常工作。例如,如果错误地指定了前缀,它可能只包含目录而没有任何文件。您可以使用 pacman 的查询函数来显示软件包中包含的文件列表,命令为 pacman -Qlp pkgname
,以及它需要的依赖项,命令为 pacman -Qip pkgname
。
如果软件包看起来正常,那么您就完成了!但是,如果您计划发布 PKGBUILD
文件,则必须检查并仔细检查 depends
数组的内容。
还要确保软件包二进制文件实际上可以完美运行!发布一个包含所有必要文件但由于某些与系统其余部分不太兼容的晦涩配置选项而崩溃的软件包是很令人恼火的。但是,如果您仅打算为自己的系统编译软件包,则无需过多担心此质量保证步骤,因为毕竟只有您自己会因错误而受苦。
检查软件包的健全性
在测试软件包功能后,使用 namcap 检查其是否存在错误
$ namcap PKGBUILD $ namcap pkgname.pkg.tar.zst
Namcap 将会
- 检查
PKGBUILD
内容是否存在常见错误以及软件包文件层次结构是否存在不必要/错放的文件, - 使用 ldd(1) 扫描软件包中的所有 ELF 文件,自动报告
depends
中缺少哪些具有所需共享库的软件包,以及哪些可以作为传递依赖项省略, - 启发式地搜索缺失和冗余的依赖项,
以及更多。
养成使用 namcap 检查您的软件包的习惯,以避免在提交软件包后不得不修复最简单的错误。
向 AUR 提交软件包
有关提交过程的详细说明,请阅读 AUR 提交指南。
总结
- 下载要打包的软件的源代码 tarball。
- 尝试编译软件包并将其安装到任意目录中。
- 复制
/usr/share/pacman/PKGBUILD.proto
原型,并在临时工作目录中将其重命名为PKGBUILD
。 - 根据您的软件包的需求编辑
PKGBUILD
。 - 运行
makepkg
并检查软件包是否正确构建。 - 如果不是,请重复前两个步骤。
警告
- 在您可以自动化软件包构建过程之前,您应该至少手动完成一次,除非您事先知道自己在做什么,在这种情况下,您就不会首先阅读本文。不幸的是,虽然很多程序作者坚持 "
./configure
;make
;make install
" 的 3 步构建周期,但情况并非总是如此,如果您必须应用补丁才能使一切正常工作,情况可能会变得非常糟糕。经验法则:如果您无法从源代码 tarball 编译程序,并使其安装到定义的临时子目录中,您甚至不需要尝试打包它。makepkg
中没有任何魔法粉尘可以使源问题消失。 - 在少数情况下,软件包甚至不可用作源代码,您必须使用类似
sh installer.run
的方法才能使其工作。您将需要做大量的研究(阅读 README、INSTALL 说明、man 页面,可能还有来自 Gentoo 或其他软件包安装程序的 ebuilds,甚至可能是 MAKEFILE 或源代码)才能使其工作。在某些非常糟糕的情况下,您必须编辑源文件才能使其工作。但是,makepkg
需要完全自主,无需用户输入。因此,如果您需要编辑 makefile,则可能需要将自定义补丁与PKGBUILD
捆绑在一起,并从prepare()
函数内部安装它,或者您可能必须从prepare()
函数内部发出一些sed
命令。
自动化
校验和
可以通过 updpkgsums
工具自动化更新新软件版本的校验和的过程;有关详细信息,请参阅 Makepkg#生成新的校验和。
PKGBUILD 生成器
可以自动生成某些软件包的 PKGBUILD
。
- Haskell: cblrepo, arch-hs
- Node.js: nodejs-npm2archAUR
- Perl: perl-cpanplus-dist-arch
- Python: pipman-gitAUR, pip2arch-gitAUR, python-pypi2pkgbuildAUR
- Ruby: gem2archAUR, pacgemAUR
- Rust: cargo-pkgbuildAUR, cargo-aur-binAUR
新的上游版本
pkgctl(来自 devtools 软件包)支持 nvchecker 集成,形式为 .nvchecker.toml
配置文件(应将其放置在与 PKGBUILD
相同的目录中)。有关示例,请参阅 pacman 软件包的 .nvchecker.toml 配置文件。
pkgctl version setup
将尝试通过分析 PKGBUILD 中指定的源数组来自动创建 .nvchecker.toml
配置文件。然后,您可以使用 pkgctl version check
来检查是否已发布新的上游版本(与 PKGBUILD
中指定为 pkgver
的版本相比),并使用 pkgctl version upgrade
来相应地更新 PKGBUILD
。有关更多详细信息,请参阅 pkgctl-version(1)。