PKGBUILD

来自 Arch Linux 中文维基

本页面讨论 PKGBUILD 中使用的变量。若要获取关于PKGBUILD中的函数和创建软件包的基本信息,请参考创建软件包PKGBUILD(5)

PKGBUILD 是一个 shell 脚本,包含 Arch Linux 在构建软件包时需要的信息。

Arch Linux 用 makepkg 构建软件包。当 makepkg 运行时,它会在当前目录寻找 PKGBUILD 文件,并依照其中的指令编译或获取所需的文件,并生成 pkgname.pkg.tar.zst 软件包。生成的包内有二进制文件和安装指令,可以使用 pacman 进行安装。

pkgnamepkgverpkgrelarch 是必须定义的变量。license在构建包时并不强制要求,但若要分享PKGBUILD文件给其他人,推荐加上该变量。此外,如果不定义该变量, makepkg 会警告缺失此变量。

一般来说,建议按照下面的顺序在PKGBUILD文件中定义这些变量。但这并不是强制性的,只要使用正确的 Bash 语法就行了。

提示:

软件包名称[编辑 | 编辑源代码]

pkgbase[编辑 | 编辑源代码]

在建立常规的软件包时,这个变量不应该在 PKGBUILD 文件中显式指出。这个值默认会与 #pkgname 的值相同。

构建拆分包时,这个变量 pkgbase 可以在 makepkg 的输出和纯源代码包中指定软件包组。此变量不允许以下划线开头。若该变量没有明确定义,则会默认对应到 pkgname 序列的第一个元素。

拆分软件包中的所有选项和指令都默认使用全局 PKGBUILD 设置的值。以下选项可以在拆分包的打包函数中覆写:#pkgdesc, #arch, #url, #license, #groups, #depends, #optdepends, #provides, #conflicts, #replaces, #backup, #options, #install, 和 #changelog

pkgname[编辑 | 编辑源代码]

对于常规的软件包,这个变量设定软件包的名称,例如 pkgname='foo'。对于拆分包则是一个名称的序列,例如pkgname=('foo' 'bar')。名称只能由由小写字母、数字和@ . _ + - (at 符号、英文句点、下划线、加号、连字符)构成,且不能以连字符或英文句点开头。为了保证一致性,pkgname 应该与软件的源代码文件相匹配。比如:源文件包名为 foobar-2.5.tar.gz,那么应该使用 pkgname=foobar

版本[编辑 | 编辑源代码]

pkgver[编辑 | 编辑源代码]

软件包的版本号,应该与软件上游发布的版本号一致。变量的值可以由字母、数字和英文句点 .,下划线 _ 组成,但不能包含连字符(-)。如果上游版本号中使用了连字符,则应该用下划线 _ 来替代。在之后的 PKGBUILD 指令中pkgver 中的下划线可以用下面这个方法替换回连字符:source=("$pkgname-${pkgver//_/-}.tar.gz")

注意: 如果上游使用时间戳格式的版本号,例如 30102014,请修改为年份在前的格式 20141030 (ISO 8601 格式)。否则新版本可能无法被系统识别出来是新的。
提示:

pkgrel[编辑 | 编辑源代码]

软件的发布号。这通常是一个正整数,用来区分同一版本软件的多次构建。当软件包的补丁和附加功能被添加进入 PKGBUILD,从而导致生成的软件包发生变化时,pkgrel 应该增加 1。而当这个软件包发布一个新版本时,发布号重置为 1。在个别情况下,也会有其他的发布号形式。比如主版本号.次要版本号

epoch[编辑 | 编辑源代码]

警告: 除了特别、绝对、显式要求需要这样做,否则不允许使用 epoch 变量。

用于强制升级软件包。在判定逻辑中,不论版本号如何,只要 epoch 值较大,就会被视为更新的软件包。这个值应为非负整数,且默认值为0。通常当一个软件的版本编号方式改变(或者使用某些字母-数字混编的版本符号),导致正常的版本比较逻辑无法进行时,会使用这个变量来控制升级。比如:

pkgver=5.13
pkgrel=2
epoch=1
1:5.13-2

更多关于版本比较的信息,参见 pacman(8)

一般变量[编辑 | 编辑源代码]

pkgdesc[编辑 | 编辑源代码]

软件包描述。建议最多 80 个字符,并不要自己引用自己的名字,除非软件包名和程序名不相同。比如:pkgdesc="Nedit is a text editor for X11" 应该被写成 pkgdesc="Text editor for X11"

合理地在描述中使用关键字,这样可以使软件包在相关的搜索中出现的可能性增加。

arch[编辑 | 编辑源代码]

一个描述能够生成并运行该软件包的架构的数组。Arch 官方仅支持 x86_64, 但是其它项目提供了其它架构支持。比如说,Arch Linux 32 提供了 i686pentium4 支持;Arch Linux ARM 项目提供 armv7h (带有硬件浮点运算模块的 armv7)和 aarch64 (64 位 armv8) 的支持。

这个数组有两种形式:

  • arch=('any') 表明软件包可以在任意架构上生成,并且一旦编译完成,编译时的架构就不再有影响了(例如 shell 脚本、字体、主题、各种扩展等)。
  • arch=('...') 包含一个或更多架构(any除外),表明这个软件包可以在上述的任意架构上生成,但生成产物只能在编译它的架构上运行。对于这些软件包,您必须在 PKGBUILD 文件中指定所有官方支持的架构。对于官方软件源和 AUR 软件包,这指的是 arch=('x86_64')。不过,AUR 软件包可以选择添加一些已知的兼容架构的支持。

在生成过程中可以通过 $CARCH 变量来获知目标架构。

url[编辑 | 编辑源代码]

待打包软件官方站点的网址。

license[编辑 | 编辑源代码]

软件分发所使用的许可证。软件包 licenses(这个包是 base 的依赖项)中包含了许多常用的许可证协议,可以在 /usr/share/licenses/common 中找到。如果软件包使用的是其中之一,这个值应该被设定成许可证的目录名,比如 license=('GPL')。如果许可证不在上述文件夹中,则需要完成以下几个步骤:

  1. custom 添加到 license 数组中。也可以用 custom:许可证名称 来替代 custom。当一个许可证被两个以上的官方仓库的软件包使用,它就会被添加到 licenses 软件包中。
  2. 将许可证安装到 /usr/share/licenses/pkgname/ 目录下,例如 /usr/share/licenses/foobar/LICENSE。可以使用下面命令
    install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE
    来实现。
  3. 如果许可证的内容仅保存在网站上,那么你需要单独保存一个版本。
  • BSDISCMITzlib/pngPythonOFL 是几个例外的情况,它们不能加入 licenses 包,因为它们包含版权声明[1]。在 license 序列中,可以按照常见许可证的方式来添加他们 (就是说,按照 license=('BSD'), license=('ISC'), license=('MIT'), license=('ZLIB'), license=('Python')license=('OFL') 来添加),但是技术上来讲,这些都是自定义的许可证,因为这些许可证中都包含各自特定的版权声明。任何以这五个许可协议分发的软件包都应该在 /usr/share/licenses/pkgname 下存放它们的许可证文件。
  • 一些软件包可能不止一个许可证,这种情况下,在 license 数组中置入多个值,比如说,license=('GPL' 'custom:name of license')
  • (L)GPL 许可证有很多版本和变种版本。对于一个 (L)GPL 软件,约定如下:
    • (L)GPL - 指代 (L)GPLv2 或之后的任意版本
    • (L)GPL2 - 仅指代 (L)GPL2
    • (L)GPL3 - 指代 (L)GPL3 或之后的任意版本
  • 如果最终无法决定使用哪种许可证,PKGBUILD.proto 建议使用 unknown。但是这种情况下,应该联系上游的软件发布者,来确定这个软件在哪些情况下是可以使用的。
提示:有些软件作者没有提供单独的版权文件,而是在 ReadMe.txt 中声明。可以在 build() 时将这些声明提取为单独文件,比如通过这条命令:sed -n '/This software/,/ thereof./p' ReadMe.txt > LICENSE

更多信息,请参考非自由软件打包指引英语Nonfree applications package guidelines

关于自由/开源软件协议的更多信息请参考:

groups[编辑 | 编辑源代码]

软件包所在的包组。例如:当你安装 fcitx5-im包组,它会安装 fcitx5-im包组里的所有包。

依赖关系[编辑 | 编辑源代码]

注意: 架构相关的额外依赖可以通过在名称后添加下划线和架构的方式指定。例如optdepends_x86_64=()

depends[编辑 | 编辑源代码]

为了生成和运行软件,而必须安装的包列表。如果是只在运行时才依赖的包,请在 package() 函数中定义。

可以使用比较运算符来描述版本限制。例如 depends=('foobar>=1.8.0')。如有多重限制,你可以添加多条,例如 depends=('foobar>=1.8.0' 'foobar<2.0.0')

本文或本章节可能需要合并到Arch package guidelines

附注: PKGBUILD 格式并没有强制执行某种打包标准。(在 Talk:PKGBUILD 中讨论)

depends 应该列出所有的直接依赖,即使某个依赖项已经因为直接依赖的需要被间接引入时也应该如此。如果不这样做,那么会发生以下可能:如果一个软件包 foo 依赖 barbaz 两个软件包,而 bar 软件包也依赖于 baz 软件包,当 bar 软件包不再依赖于 baz 就极有可能会导致意外行为——pacman 不会在安装 foo 软件包时安装 baz 软件包,也会在清除孤儿软件包时把 baz 清理掉。由于 baz 软件包被依赖却没有被安装,foo 可能崩溃或者发生运行错误。

但在一些情况下,上面所述的某些依赖是没有必要或者不应该被列出的。比如说glibc,每个操作系统都需要 C 运行库,因此它是不能够被卸载的。又比如,当软件包已经依赖于一个以 python- 开头的模块,就不需要再单独依赖 python——因为 python- 开头的模块必定依赖于 python 软件包,而且不允许从依赖列表中删除。

通常的依赖应该包括生成所有可选功能所需的依赖。否则,对于任何依赖于额外软件包的可选功能,应提供配置选项,并且默认禁用这些可选功能。如果不这样做,会给软件包添加了所谓"自动魔法依赖":一些生成时可选功能因为生成软件包的机器上安装的一些传递依赖或者不相关的软件被意外启用了,但是没有表现在包的依赖中。

如果依赖的名称写成了库的名称(例如 depends=('libfoobar.so')),makepkg 会在编译完成的包中尝试寻找依赖这个库的二进制文件,并添加二进制文件所需的 soname 版本号到依赖列表中。可以自己加上版本号来停用自动检测,比如说 depends=('libfoobar.so=2')

makedepends[编辑 | 编辑源代码]

仅在软件生成时需要的软件包列表。可以像depends序列里提到的一样指定依赖的版本限制。depends 序列里面的软件包默认也是生成时需要的,此处不应该重复。

注意:
  • 在使用 makepkg 构建软件包时,默认 base-devel 已安装。该包的依赖项不应该出现在 makedepends 列表中。
  • 如果使用VCS 源,记得要把对应的VCS工具(git, subversion, cvs等等)加进去
提示:用以下命令查看某个依赖项是否已经被 base-devel 直接依赖:pactree -rsud1 package | grep base-devel(需要安装pacman-contrib)。

checkdepends[编辑 | 编辑源代码]

运行软件的测试组件时需要,而运行时不需要的包列表。该列表中的包遵循 depends 相同的格式。这些依赖只在 check() 函数存在,且被 makepkg 执行时会被处理。

注意: 在使用 makepkg 构建软件包时,默认 base-devel 已安装。该包的依赖项不应该出现在 checkdepends 列表中。

optdepends[编辑 | 编辑源代码]

可选软件包序列。这些可选软件包不影响软件主要功能,但能提供额外特性。这通常意味着除非安装了对应的可选软件包,该软件包所提供的个别可执行文件可能无法正常使用[2]。如果软件有一些替代依赖,您可以将其在此处全部列出,而不是 depends 列表中列出。

应该简要说明每个包所能提供的额外功能,例如:

optdepends=('cups: printing support'
            'sane: scanners support'
            'libgphoto2: digital cameras support'
            'alsa-lib: sound support'
            'giflib: GIF images support'
            'libjpeg: JPEG images support'
            'libpng: PNG images support')

包关系[编辑 | 编辑源代码]

注意: 架构相关的附加列表可以通过在变量名称后添加下划线和架构名字的方式指定。例如conflicts_x86_64=()

provides[编辑 | 编辑源代码]

该列表说明的是本软件包能够提供列表中的包(或者像 cron、sh 这样的虚拟包)所提供的功能。只要provides列表中的包都没有声明 conflicts,提供相同功能的软件包就可以同时安装。

注意: 如果需要使用这个变量,应当加上版本号(pkgver,可能的话还有pkgrel),特别是当依赖该软件包的其他软件对版本号特别敏感的时候。就是说,如果一个修改过的 qt 包其版本号为 3.3.8,命名为 qt-foobar,那么 provides 应该写成 provides=('qt=3.3.8')。如果忽略了版本号,会导致所有依赖于 qt 的某个特定版本的包编译失败。不要把 pkgname 加入 provides 序列。这个操作会自动进行。

conflicts[编辑 | 编辑源代码]

这个列表描述的是与当前软件包冲突的包,或者与该包同时存在会产生问题的包。安装此软件时,所有这个列表中的软件包和提供这个功能的软件包都会被删除。可以像 depends 那样指定冲突包的版本号。

需要注意的是,冲突检查的对象是 pkgname 以及 provides 中的名字。因此,如果你的包 provides foo 功能,在 conflicts 中指定 foo 就会导致你的包和所有其他在 provides 中包含了 foo 的包冲突(也就是说,你不需要一个一个地指定所有冲突的包的名字)。例子是:

  • netbeans 提供 netbeans(因为 pkgname 就是如此)。
  • netbeans-cppAUR 提供 netbeans 功能,并和 netbeans 冲突。
  • netbeans-phpAUR 提供 netbeans 功能,而且和 netbeans 冲突,但是不需要再说明它与netbeans-cppAUR冲突,因为提供相同功能的包隐含了冲突关系。

当不同的包通过在provides列表中声明的方式提供相同的功能,那么是否特意在conflicts列表中添加可替换的包会产生不同的结果。特意说明的话,两个包就会被认为是可相互替代的;如果conflicts列表不存在,那么两个包会被认为是“可能可以同时存在”。在决定是否需要声明conflicts列表的时候,请忽略provides列表的内容,独立决策。

replaces[编辑 | 编辑源代码]

会因安装当前包而取代的过时的包的列表。比如:wireshark-qt 中的 replaces=('wireshark')。在同步软件数据库后,pacman 会立刻用软件库中的另一个包替换掉 replaces 中已安装的包。如果你只是提供已存在包的一个替代品,或者上传到 AUR, 请不要使用 replace,而是使用 conflictsprovides 两个变量——它们仅在安装冲突软件包时被检查。

其它[编辑 | 编辑源代码]

backup[编辑 | 编辑源代码]

当包被升级或卸载时,应当备份的文件(的路径)序列。这些文件一般是用户会更改的文件,如主要放置在 /etc 中的配置文件。

列表中的文件应该使用相对路径,即不是以斜杠(/)开头的(如 etc/pacman.conf 而不是 /etc/pacman.conf)。

在升级时,新版本会被命名为 file.pacnew 以避免覆盖原来的被用户修改过的文件。当卸载包时,用户修改过的文件会以 file.pacsave 为名而保留下来——除非用 pacman -Rn 命令卸载。

参见 pacnew 和 pacsave 文件获取更多信息。

options[编辑 | 编辑源代码]

这个序列允许你重载 makepkg 的部分定义在 /etc/makepkg.conf 中的默认行为。要设置一个选项,请在序列中指定选项名。要禁用一个默认行为,则还需要在前面加上!

参见 PKGBUILD(5) 以获取所有可用选项。

install[编辑 | 编辑源代码]

需要包含在包中的 .install 脚本的名称。

pacman 可以在安装、卸载或升级一个软件包时存储及执行一些特定的脚本。脚本包含了下面几个函数,并且在特定时刻执行它们:

  • pre_install - 释放包中文件前运行的脚本。传递一个参数:新版本号。
  • post_install - 释放包中文件后运行的脚本。传递一个参数:新版本号。
  • pre_upgrade - 释放包中文件前运行的脚本。两个参数按以下顺序传递:新版本号,旧版本号。
  • post_upgrade - 释放包中文件后运行的脚本。两个参数按以下顺序传递:新版本号,旧版本号。
  • pre_remove - 文件被删除前运行的脚本,传递一个参数:旧版本号。
  • post_remove - 文件被删除后运行的脚本,传递一个参数:旧版本号。

每一个函数都是 chrootpacman 安装目录下运行的。参见这个帖子.

提示:
注意: 脚本不要以 exit 结束,否则包含该脚本的函数无法执行。

changelog[编辑 | 编辑源代码]

软件包的更新日志的文件名。要查看安装软件的更新日志(如果有):

$ pacman -Qc pkgname

源码[编辑 | 编辑源代码]

source[编辑 | 编辑源代码]

构建软件包时需要的文件列表。它必须包含软件源的位置,大多数情况下是一个完整的 HTTP 或 FTP 地址。您可以在此处调用前面提到的变量 pkgnamepkgver,来实现高效的命名。(如 source=("https://example.com/$pkgname-$pkgver.tar.gz"))。

文件也可以放到与 PKGBUILD 文件相同目录,并将文件名添加到这个列表。在实际的编译过程开始之前,所有该列表中引用的文件都会被下载或检查是否存在,如果有文件丢失 makepkg 就不会继续。

.install 文件会被 makepkg 自动识别,而不应该被包含在这个列表中。makepkg 会自动把 .sig, .sign.asc 结尾的文件当成 PGP 签名,并自动验证对应的源文件的完整性。

警告: 因为所有包的 SRCDEST 的值可能相同,所以下载的文件的文件名需要唯一。比如说,如果一个项目只用版本号来命名,可能会与其他有相同版本号的不同项目冲突。在这种情况下,你可以为下载的文件指定不同的文件名:source=('unique_package_name::file_uri')。例如source=("$pkgname-$pkgver.tar.gz::https://github.com/coder/program/archive/v$pkgver.tar.gz")
注意:
  • 架构相关的额外相关性可以通过在名称后添加下划线和架构的方式指定。例如 source_x86_64=()。必须提供对应的完整性校验和序列,例如 sha256sums_x86_64=()
  • 有些服务器通过 User-Agent 来筛选并限制下载。这个限制可以通过 DLAGENTS 规避。

noextract[编辑 | 编辑源代码]

一个在 source 中列出,但不应该在运行 makepkg 时被解包的文件列表。这通常包括那些压缩文件不能被 /usr/bin/bsdtar 处理,或者本来就不需要解压、按照原样提供的文件。对于前者,需要将额外的解包工具(如unzipp7ziplrzip等)加入 makedepends 序列,并用 prepare() 函数手动解压。例如:

prepare() {
  lrzip -d source.tar.lrz
}

注意当 source 是一些 URL 时,noextract 仅仅取文件名部分:

source=("http://foo.org/bar/foobar.tar.xz")
noextract=('foobar.tar.xz')

不提取任何东西时,可以像这样:

  • 如果 source 只包含了纯 URL,而没有自定义的文件名是,将内容从最后一个斜杠之前像这样从 source 序列中提出来:
noextract=("${source[@]##*/}")
noextract=("${source[@]%%::*}")

validpgpkeys[编辑 | 编辑源代码]

PGP 指纹列表。如果使用,makepkg 仅接受这里定义的签名,并且忽略密钥环中的值。如果源代码用子密钥签名,makepkg 仍然会使用主密钥进行比较。

此处仅接受完整的指纹。它们必须是大写字母而且不能有空白字符。

注意: 可以使用 gpg --list-keys --fingerprint <KEYID> 查找 key 的合适指纹。

请参阅 Makepkg 验证签名了解签名验证过程的详细信息。

完整性检验[编辑 | 编辑源代码]

下面描述的这些序列中的变量是 source 序列中对应文件的校验和。可以插入 SKIP 跳过某个不需要检验的文件。

校验和的数值和版本应该始终使用上游,比如在新版本公告中,提供的数值。当存在多种版本的时候,最好选用最强的校验版本,也就是说,按照如下从强到弱的顺序:sha256 > sha1 > md5。这样可以最大限度地保证从上游的公告到软件包的生成整个流程中下载文件的完整性。

注意: 另外,当上游具备数字签名文件时,这个签名文件应该被添加到 source 序列中,PGP 密钥添加到 validpgpkeys 序列中。这样允许在生成软件包时进行验证。

makepkg-g/--geninteg 选项可以自动生成校验值,通常可以通过 makepkg -g >> PKGBUILD 命令写入。updpkgsums 也可以自动更新 PKGBUILD 中的数值。两个工具都会自动检测 PKGBUILD 中的算法, 如果两个都没找到就回滚到 md5sums

注意: 架构相关的额外完整性检验可以通过在名称后添加下划线和架构的方式指定。例如sha256sums_x86_64=()

md5sums[编辑 | 编辑源代码]

source 列表文件中的 128 位 MD5 校验和。

sha1sums[编辑 | 编辑源代码]

source 列表文件中 SHA-1 160 位校验和。

sha256sums[编辑 | 编辑源代码]

256 位 SHA-2 校验和。

sha224sums, sha384sums, sha512sums[编辑 | 编辑源代码]

SHA-2 校验和列表,分别对应224,384 和 512 位。这些是较为不常见的 sha256sums 替代品。

b2sums[编辑 | 编辑源代码]

512 位 BLAKE2 校验和。

参阅[编辑 | 编辑源代码]