创建软件包
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 用户仓库(AUR)。它涵盖了 PKGBUILD(5) 的创建,PKGBUILD 是一个软件包构建描述文件,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 等软件包,这将特别有用,在这些软件包中,构建过程可能保持不变,但源文件可能会每天甚至每小时更新。旧方法是将日期放入 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()
函数时,您需要经常测试您的更改,以确保没有错误。您可以使用 makepkg
命令在包含 PKGBUILD
文件的目录中执行此操作。使用格式正确的 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 或其他软件包安装程序的 ebuild,甚至可能是 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)。