创建软件包

出自 ArchWiki
Arch 软件包准则

32 位CLRCMake交叉编译DKMSEclipse 插件Electron字体Free PascalGNOMEGoHaskellJavaKDE内核模块LispMesonMinGWNode.js非自由软件OCamlPerlPHPPythonRRubyRust - 安全ShellVCSWeb 应用Wine

本文旨在帮助用户使用类似 portsArch 构建系统创建自己的软件包,并提交到 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 变量

注意: 主文章是 PKGBUILD,另请参阅 PKGBUILD(5) § 选项和指令

makepkg 预定义了以下变量,打包者应使用这些变量来引用构建过程中的临时位置:

srcdir
这指向 makepkg 解压或符号链接源数组中所有文件的目录。
pkgdir
这指向 makepkg 捆绑已安装软件包的目录,该目录将成为你构建的软件包的根目录。

它们包含绝对路径,这意味着如果你正确使用这些变量,则无需担心你的工作目录。

注意: makepkg,以及 build()package() 函数,旨在是非交互式的。在这些函数中调用的交互式实用程序或脚本可能会破坏 makepkg,尤其是在启用构建日志记录 (--log) 的情况下调用时。有关详细信息,请参阅 FS#13214

PKGBUILD 函数

在构建软件包时,如果 PKGBUILD 中定义了以下五个函数,makepkg 将会调用它们。函数 package() 在每个 PKGBUILD 中都是必需的,并且始终会被调用。如果未定义任何其他函数,makepkg 将简单地跳过该函数的调用。

在构建过程中,函数按照此处列出的顺序调用。

另请参阅 PKGBUILD(5) § 打包函数

prepare()

使用此函数,可以运行用于准备构建源的命令,例如 打补丁。此函数在软件包解压后、pkgver() 和 build 函数之前运行。如果跳过解压 (makepkg --noextract),则不会运行 prepare()

注意: 来自 PKGBUILD(5):该函数以 bash -e 模式运行,这意味着任何以非零状态退出的命令都将导致该函数退出。

当不清楚是将某些内容放在 prepare() 还是 build() 中时,一个经验法则是将应该在解压源代码后精确运行一次的步骤放在 prepare() 中,并将任何手动编辑解压后的文件后有意义重新运行的步骤放在 build() 中。

pkgver()

pkgver() 在获取、解压源代码并执行 prepare() 后运行。因此,你可以在 makepkg 阶段更新 pkgver 变量。

如果你正在制作 git/svn/hg 等软件包,这尤其有用,在这些软件包中,构建过程可能保持不变,但源代码可能会每天甚至每小时更新。过去的方法是将日期放入 pkgver 字段,如果软件没有更新,makepkg 仍然会重建它,认为版本已更改。一些有用的命令是 git describehg identify -ni 等。请在提交 PKGBUILD 之前测试这些命令,因为 pkgver() 函数中的失败可能会阻止构建。

注意: pkgver 不能包含空格或连字符 (-)。使用 sed 来纠正这种情况很常见。

build()

现在,你需要在 PKGBUILD 文件中实现 build() 函数。此函数使用 Bash 语法中的常用 shell 命令来自动编译软件并创建一个名为 pkg 的目录来安装软件。这允许 makepkg 打包文件,而无需在你的文件系统中搜索。

build() 函数的第一步是更改到解压缩源代码 tarball 创建的目录。makepkg 将在执行 build() 函数之前将当前目录更改为 $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(),因为它有助于确保软件已正确构建,并且可以与其依赖项良好地协同工作。

不需要此功能的用户(以及偶尔无法修复软件包以使其通过的维护者)可以通过在 PKGBUILDoptions 数组中添加 !check 或使用 --nocheck 标志调用 makepkg 来禁用它。makepkg.conf(5)

如果要测试 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 提交指南,详细了解提交过程。

总结

  1. 下载要打包的软件的源代码 tarball。
  2. 尝试编译软件包并将其安装到任意目录中。
  3. 复制原型 /usr/share/pacman/PKGBUILD.proto 并将其重命名为临时工作目录中的 PKGBUILD
  4. 根据您的软件包的需求编辑 PKGBUILD
  5. 运行 makepkg 并检查软件包是否正确构建。
  6. 如果不是,请重复前两个步骤。

警告

  • 在您可以自动化软件包构建过程之前,您应该至少手动完成一次,除非您事先确切地知道自己在做什么,在这种情况下,您一开始就不会阅读本文。不幸的是,尽管很多程序作者坚持 "./configure; make; make install" 这 3 步构建周期,但这并非总是如此,如果您必须应用补丁才能使一切正常工作,情况可能会变得非常糟糕。经验法则:如果您无法从源代码 tarball 编译程序,并使其自行安装到定义的临时子目录中,那么您甚至不需要尝试打包它。makepkg 中没有任何神奇的魔法粉尘可以使源代码问题消失。
  • 在少数情况下,软件包甚至不可用作源代码,您必须使用类似 sh installer.run 的方法才能使其工作。您将需要进行大量研究(阅读 README、INSTALL 说明、手册页、可能来自 Gentoo 或其他软件包安装程序的 ebuild,甚至可能是 MAKEFILE 或源代码)才能使其工作。在某些非常糟糕的情况下,您必须编辑源文件才能使其工作。但是,makepkg 需要完全自主,无需用户输入。因此,如果您需要编辑 makefile,您可能需要在 PKGBUILD 中捆绑一个自定义补丁,并从 prepare() 函数内部安装它,或者您可能需要从 prepare() 函数内部发出一些 sed 命令。

自动化

校验和

可以使用 updpkgsums 工具自动化更新新软件版本的校验和的过程;有关详细信息,请参阅 Makepkg#Generate new checksums

PKGBUILD 生成器

某些软件包的 PKGBUILD 可以自动生成。

注意: 用户仍然有责任确保软件包在将生成的文件提交到 AUR 之前符合高质量标准。

新的上游版本发布

pkgctl(来自 devtools 软件包)支持以 .nvchecker.toml 配置文件形式的 nvchecker 集成(应将其放置在与 PKGBUILD 相同的目录中)。有关示例,请参阅 pacman 软件包的 .nvchecker.toml 配置文件。

提示: pkgctl version setup 将尝试通过分析 PKGBUILD 中指定的 source 数组来自动创建 .nvchecker.toml 配置文件。

然后,您可以使用 pkgctl version check 检查是否发布了新的上游版本(与 PKGBUILD 中指定为 pkgver 的版本相比),并使用 pkgctl version upgrade 相应地更新 PKGBUILD。有关更多详细信息,请参阅 pkgctl-version(1)

另请参阅