跳转至内容

创建软件包

来自 ArchWiki
(重定向自 创建软件包)
Arch 软件包指南

32位CLRCMake交叉编译DKMSEclipseElectron字体Free PascalGNOMEGoHaskellJavaKDE内核模块LispMesonMinGWNode.js非自由OCamlPerlPHPPythonRRubyRust - 安全ShellVCSWebWine

本文档旨在协助用户使用类似 portsArch 构建系统 来创建自己的软件包,并提交到 Arch 用户仓库。它涵盖了 PKGBUILD(5) 的创建——这是一个由 makepkg 使用的软件包构建描述文件,用于从源代码创建二进制软件包。

关于现有规则和提高软件包质量的方法,请参阅 Arch 软件包指南

概述

Arch Linux 中的软件包使用 makepkg 工具和 PKGBUILD 文件中存储的信息来构建。当 makepkg 运行时,它会在当前目录中查找 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 Duties 中找到。

下载和测试安装

下载您想打包的软件的源代码 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 变量

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

makepkg 预定义了以下变量,软件包维护者应使用它们在构建过程中引用临时位置:

srcdir
指向 makepkg 提取或符号链接 source 数组中所有文件的目录。
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/etc. 包特别有用,因为构建过程可能保持不变,但源代码可能每天甚至每小时更新一次。旧的实现方式是将日期放入 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 脚本,那么在使用 --prefix=/usr 构建 pacman 软件包时,这是一个好习惯。许多软件将文件安装在相对于 /usr/local 目录的位置,这只应在您从源代码手动构建时进行。所有 Arch Linux 软件包都应使用 /usr 目录。如 /usr/share/pacman/PKGBUILD.proto 文件所示,接下来的两行通常如下所示:

./configure --prefix=/usr
make
注意 如果您的软件不需要构建任何内容,请不要使用 build() 函数。build() 函数不是必需的,但 package() 函数是。

check()

用于调用 make check 和类似的测试例程。强烈建议使用 check(),因为它有助于确保软件已正确构建并与依赖项正常工作。

不需要它的用户(以及偶尔无法修复软件包以使其通过的用户)可以通过在 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 变量,这可以节省时间。

注意build() 函数生成的但移动的文件(例如使用 mv)从 $srcdir 移动到 $pkgdir 会破坏 makepkg--repackage 选项。

测试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 检查软件包的习惯,以避免在提交软件包后还要修复最简单的错误。

使用pkgctl在干净的chroot环境中构建

本文档或该部分候选与 Arch 构建系统#构建软件包 合并。

注意: 此页面与构建系统无关。还有 #设置干净的chroot环境DeveloperWiki:在干净的chroot中构建。(在 Talk:Creating packages 中讨论)

您可以使用来自 devtoolspkgctl 来检查软件包是否可以在没有其他软件包已安装的环境中构建。在 PKGBUILD 目录中

$ pkgctl build

并检查输出中是否存在潜在的错误或警告。如果软件包依赖其他 AUR 软件包,则必须构建这些软件包并将它们放入 chroot 限制环境中。

$ pkgctl build -I path/to/somepkg.tar.gz -I ...
注意 如果软件包是使用 AUR 助手安装的,那么它的 tarball 很可能在其缓存目录中。

有关更多选项,请参阅 pkgctl-build(1)

提交软件包到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、安装说明、man 页、Gentoo 的 ebuild 或其他软件包安装程序,甚至可能还有 MAKEFILE 或源代码)才能使其工作。在一些非常糟糕的情况下,您甚至需要编辑源代码文件才能使其工作。然而,makepkg 需要完全自主,无需用户输入。因此,如果您需要编辑 makefile,您可能需要将自定义补丁与 PKGBUILD 一起打包,并从 prepare() 函数中安装它,或者您可能需要从 prepare() 函数中发出一些 sed 命令。

自动化

校验和

更新新软件发布校验和的过程可以通过 updpkgsums 工具自动化;有关详细信息,请参阅 Makepkg#生成新校验和

PKGBUILD 生成器

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

注意 用户仍然有责任确保软件包符合高质量标准,然后才能将生成的파일提交到 AUR

新的上游发布

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

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

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

参见