makepkg

出自 ArchWiki

makepkg 是一个用于自动化构建软件包的脚本。使用该脚本的要求是具有构建能力的 Unix 平台和一个 PKGBUILD

makepkgpacman 软件包提供。

配置

系统配置位于 /etc/makepkg.conf 中,但用户特定的更改可以在 $XDG_CONFIG_HOME/pacman/makepkg.conf~/.makepkg.conf 中进行。此外,系统范围的更改可以使用 drop-in 文件 /etc/makepkg.conf.d/makepkg.conf 进行。建议在构建软件包之前查看配置。

提示: 用于在干净的 chroot 环境中构建软件包devtools 辅助脚本使用 /usr/share/devtools/makepkg.conf.d/arch.conf 配置文件。

有关更多信息,请参阅 makepkg.conf(5)

打包者信息

每个软件包都标记有元数据,除其他外,还标识了打包者。默认情况下,用户编译的软件包标记为 Unknown Packager。如果多个用户将在系统上编译软件包,或者如果有人要将软件包分发给其他用户,则提供真实的联系方式会很方便。这可以通过在 makepkg.conf 中设置 PACKAGER 变量来完成。

要在已安装的软件包上检查此项

$ pacman -Qi package
...
Packager       : John Doe <john@doe.com>
...

要自动生成签名软件包,还要在 makepkg.conf 中设置 GPGKEY 变量。

软件包输出

默认情况下,makepkg 在工作目录中创建软件包 tarball,并将源数据直接下载到 src/ 目录。可以配置自定义路径,例如将所有构建的软件包保存在 ~/build/packages/ 中,并将所有源文件保存在 ~/build/sources/ 中。

如果需要,配置以下 makepkg.conf 变量

  • PKGDEST — 用于存储结果软件包的目录
  • SRCDEST — 用于存储 数据的目录(如果指向其他位置,则符号链接将放置到 src/
  • SRCPKGDEST — 用于存储结果源软件包的目录(使用 makepkg -S 构建)
提示: 可以使用 paccache -c ~/build/packages/ 清理 PKGDEST 目录,如 pacman#清理软件包缓存 中所述。

您还可以使用每个软件包目录内的相对路径

签名检查

注意: makepkg 中实现的签名检查不使用 pacman 的密钥环,而是依赖于用户的密钥环。[1]

如果 .sig.asc 形式的签名文件是 PKGBUILD 源数组的一部分,则 makepkg 会自动尝试验证它。如果用户的密钥环不包含签名验证所需的公钥,则 makepkg 将中止安装,并显示 PGP 密钥无法验证的消息。

如果软件包所需的公钥丢失,则 PKGBUILD 很可能包含带有所需密钥 ID 的 validpgpkeys 条目。手动导入它,或在密钥服务器上找到它并从那里导入。要暂时禁用签名检查,请使用 --skippgpcheck 选项运行 makepkg

用法

在继续之前,安装 base-devel 元软件包。此软件包的依赖项不需要PKGBUILD 文件中列为构建时依赖项(makedepends)。

注意
  • 确保为传递给 pacman 的命令正确配置了 sudo。或者,可以使用 makepkg.conf(5) 配置文件中的 PACMAN_AUTH 指定不同的授权命令。
  • 不允许以 root 身份运行 makepkg已禁用[2] 除了 PKGBUILD 可能包含任意命令之外,以 root 身份构建通常被认为是不安全的。[3] 没有常规用户帐户访问权限的用户应以 nobody 用户身份运行 makepkg,例如使用命令 runuser -u nobody makepkg

要构建软件包,必须首先创建一个 PKGBUILD,或构建脚本,如创建软件包中所述。可以从 Arch 构建系统 (ABS) 树或 AUR 获取现有脚本。一旦拥有 PKGBUILD,请切换到保存它的目录并运行以下命令来构建软件包

$ makepkg

如果缺少必需的依赖项,makepkg 将在失败之前发出警告。要构建软件包并安装所需的依赖项,请添加标志 -s/--syncdeps

$ makepkg --syncdeps

添加 -r/--rmdeps 标志会使 makepkg 删除稍后不再需要的构建依赖项。如果经常构建软件包,请考虑不时使用 Pacman/技巧与诀窍#删除未使用的软件包(孤立软件包)

注意
  • 这些依赖项必须在配置的软件仓库中可用;有关详细信息,请参阅 pacman#软件仓库和镜像。或者,可以在构建之前手动安装依赖项 (pacman -S --asdeps dep1 dep2)。
  • 安装依赖项时仅使用全局值,即拆分软件包的打包函数中完成的任何覆盖都将不会被使用。

一旦满足所有依赖项并且软件包构建成功,将在工作目录中创建一个软件包文件 (pkgname-pkgver.pkg.tar.zst)。要安装,请使用 -i/--install(与 pacman -U pkgname-pkgver.pkg.tar.zst 相同)

$ makepkg --install

要清理剩余的文件和目录,例如提取到 $srcdir 的文件,请添加选项 -c/--clean。这对于同一软件包的多次构建或更新软件包版本很有用,同时使用相同的构建目录。它可以防止过时和残留文件延续到新的构建中

$ makepkg --clean

有关更多信息,请参阅 makepkg(8)

优化

默认选项与 devtools 用于为官方软件仓库构建软件包的选项匹配。[4] 因此,最终用户可以通过调整以下选项以匹配其本地环境来获得或多或少的显著收益。

构建优化的二进制文件

通过为主机启用编译器优化,可以实现打包软件的性能改进。缺点是为特定处理器架构编译的二进制文件将无法在其他计算机上正确运行。在 x86_64 计算机上,实际性能提升很少有足够显著的程度,以至于值得花费时间重建官方软件包。

但是,使用“非标准”编译器标志非常容易降低性能。许多编译器优化仅在某些情况下有用,不应不加区分地应用于每个软件包。除非有基准测试数据来证明某些东西更快,否则很可能不是!Gentoo GCC 优化Safe CFLAGS wiki 文章提供了有关编译器优化的更深入信息。

传递给 C/C++ 编译器(例如 gccclang)的选项由 CFLAGSCXXFLAGSCPPFLAGS 环境变量控制。为了在 Arch 构建系统中使用,makepkg 将这些环境变量公开为 makepkg.conf 中的配置选项。默认值配置为生成可在各种计算机上安装的通用二进制文件。

注意
  • 请记住,并非所有构建系统都使用 makepkg.conf 中配置的变量。例如,cmake 忽略预处理器选项环境变量 CPPFLAGS。因此,许多 PKGBUILD 包含针对打包软件使用的构建系统特定的选项的解决方法。
  • 源代码在 Makefile 中提供的配置或编译命令行中的特定参数优先,并可能覆盖 makepkg.conf 中的配置。

GCC 可以自动检测并启用安全的特定于架构的优化。要使用此功能,请首先删除任何 -march-mtune 标志,然后添加 -march=native。例如

/etc/makepkg.conf
CFLAGS="-march=native -O2 -pipe ..."
CXXFLAGS="${CFLAGS} ..."

要查看启用了哪些标志,请运行

$ gcc -march=native -v -Q --help=target
注意: 指定与 -march=native 不同的值,然后 -Q --help=target 将不会按预期工作。[5] 要了解真正启用了哪些选项,请完成编译。请参阅 Gentoo:Safe CFLAGS#Manual 以获取说明。

pacman 版本 5.2.2 开始,makepkg.conf 还包括对 RUSTFLAGS 环境变量的覆盖,用于传递给 Rust 编译器的标志。Rust 编译器还可以通过将 -C target-cpu=native 添加到给定的 RUSTFLAGS 值来检测并启用特定于架构的优化

/etc/makepkg.conf.d/rust.conf
RUSTFLAGS="-C opt-level=2 -C target-cpu=native"

要查看这将启用哪些 CPU 功能,请运行

$ rustc -C target-cpu=native --print cfg

在不使用 -C target-cpu=native 的情况下运行 --print cfg 将打印默认配置。opt-level 参数可以根据需要更改为 3sz。有关详细信息,请参阅 Rust 编译器的文档

提升构建时间

并行编译

make 构建系统使用 MAKEFLAGS 环境变量来指定 make 的附加选项。该变量也可以在 makepkg.conf 文件中设置。

具有多核/多处理器系统的用户可以指定要同时运行的作业数。这可以通过使用 nproc(1) 来确定可用处理器的数量来实现,例如 MAKEFLAGS="--jobs=$(nproc)"

某些 PKGBUILD 特别使用 -j1 覆盖此设置,因为某些版本中存在竞争条件,或者仅仅是因为它首先不受支持。因​​此构建失败的软件包应在错误跟踪器上报告(或者在 AUR 软件包的情况下,报告给软件包维护者),在确保错误确实是由 MAKEFLAGS 引起的之后。

有关可用选项的完整列表,请参阅 make(1)

从内存中的文件构建

由于编译需要许多 I/O 操作和处理小文件,因此将工作目录移动到 tmpfs 可能会提高构建时间。

可以临时导出 BUILDDIR 变量到 makepkg,以将构建目录设置为现有的 tmpfs。例如

$ BUILDDIR=/tmp/makepkg makepkg

持久配置可以在 makepkg.conf 中通过取消注释 BUILDDIR 选项来完成,该选项位于默认 /etc/makepkg.conf 文件中的 BUILD ENVIRONMENT 部分末尾。将其值设置为例如 BUILDDIR=/tmp/makepkg 将使用 Arch 的默认 /tmp 临时文件系统。

注意
  • 避免在 tmpfs 中编译较大的软件包,以防止内存不足。
  • tmpfs 目录必须在没有 noexec 选项的情况下挂载,否则它将阻止构建的二进制文件被执行。
  • 请记住,在 tmpfs 中编译的软件包在重新启动后不会持久存在。考虑适当地设置 PKGDEST 选项,以自动将构建的软件包移动到持久目录。

使用编译缓存

使用 ccache 可以通过缓存编译结果以供后续使用来提高构建时间。

使用 mold 链接器

moldld/lld 链接器的直接替代品,声称速度明显更快。

要使用 mold,请将 -fuse-ld=mold 附加到 LDFLAGS。例如

/etc/makepkg.conf
LDFLAGS="... -fuse-ld=mold"

要将额外的选项传递给 mold,请另外将其添加到 LDFLAGS。例如

/etc/makepkg.conf
LDFLAGS="... -fuse-ld=mold -Wl,--separate-debug-file"

要将 mold 用于 Rust 软件包,请将 -C link-arg=-fuse-ld=mold 附加到 RUSTFLAGS。例如

/etc/makepkg.conf.d/rust.conf
RUSTFLAGS="... -C link-arg=-fuse-ld=mold"

禁用调试包和 LTO

Commit 90bf367e 包含在 pacman 6.0.2-9 (2024 年 2 月) 中,默认启用了 debuglto 选项。

构建调试包使官方软件仓库能够提供更多工具来为用户排除问题(archlinux/packaging/packages/pacman#23#note_173528),但这在您自己构建软件包时不是必需的,并且会减慢构建过程。请参阅 archlinux/packaging/packages/pacman#23#note_173782

链接时优化产生更优化的二进制文件,但大大延长了构建过程(archlinux/packaging/packages/pacman#23#note_173678),这可能不是理想的权衡。

要禁用这些选项,请在 OPTIONS=() 数组中的它们前面直接添加一个 ! 字符,例如 OPTIONS=(...!debug !lto...)

压缩

使用其他压缩算法

为了加快打包和安装速度,以拥有更大的软件包存档为代价,请更改 PKGEXT

例如,以下操作跳过软件包文件的压缩,这反过来又无需在安装时解压缩

$ PKGEXT='.pkg.tar' makepkg

作为另一个示例,以下操作使用 LZ4 算法,该算法侧重于速度

$ PKGEXT='.pkg.tar.lz4' makepkg

要使这些设置之一永久生效,请在 /etc/makepkg.conf 中设置 PKGEXT

在压缩时利用多核

zstd 通过 -T/--threads 标志支持 对称多处理 (SMP),以加快压缩速度。-T0 标志默认包含在 /etc/makepkg.conf 中的 COMPRESSZST 数组中,这使 zstd 可以使用与物理 CPU 核心数相同的线程数来压缩软件包。可以使用 --auto-threads=logical 标志指示 zstd 基于逻辑 CPU 计数,从而进一步增加使用的线程数

COMPRESSZST=(zstd -c -T0 --auto-threads=logical -)

lz4xz 默认是多线程的,因此无需在 /etc/makepkg.conf 中进行任何更改。

pigzgzip 的直接替代并行实现,默认情况下使用所有可用的 CPU 核心(可以使用 -p/--processes 标志来使用较少的内核)

COMPRESSGZ=(pigz -c -f -n)

pbzip2bzip2 的直接替代并行实现,默认情况下也使用所有可用的 CPU 核心。-p# 标志可用于使用较少的内核(注意:-p 和内核数之间没有空格)。

COMPRESSBZ2=(pbzip2 -c -f)

lbzip2bzip2 的另一个直接替代并行实现,默认情况下也使用所有可用的 CPU 核心。-n 标志可用于使用较少的内核。

COMPRESSBZ2=(lbzip2 -c -f)

plzipAURlzip 的多线程实现,默认情况下也使用所有可用的 CPU 核心。-n/--threads 标志可用于使用较少的内核。

COMPRESSLZ=(plzip -c -f)

更改压缩级别

几种压缩算法(包括 zstd 和 xz)支持设置压缩级别,该级别定义了速度、内存和压缩效率之间的权衡。

技巧与诀窍

减少源代码下载和解压时间

定义源位置

利用 SRCDEST,尤其是在构建 VCS 软件包时,以节省在后续重建中获取和解压缩源文件的时间。

生成新的校验和

安装 pacman-contrib 并在与 PKGBUILD 文件相同的目录中运行以下命令以生成新的校验和

$ updpkgsums

updpkgsums 使用 makepkg --geninteg 生成校验和。有关更多详细信息,请参阅 此论坛讨论

校验和也可以通过例如 sha256sum 获得,并手动添加到 sha256sums 数组中。

从本地源文件构建

如果要更改源代码,可以使用 -o, --nobuild 仅下载和提取文件 选项下载源代码,而不构建软件包。

$ makepkg -o

现在您可以更改源文件,然后使用 -e, --noextract 不要提取源文件(使用现有的 $srcdir/ 目录) 选项构建软件包。使用 -f 选项覆盖已构建和现有的软件包。

$ makepkg -ef

显示具有特定打包者的软件包

expac 是一个 pacman 数据库提取实用程序。此命令显示系统上安装的所有软件包,其打包者名为 packagername

$ expac "%n %p" | grep "packagername" | column -t

这显示了系统上安装的所有软件包,其打包者在 /etc/makepkg 变量 PACKAGER 中设置。这仅显示 /etc/pacman.conf 中定义的软件仓库中的软件包。

$ . /etc/makepkg.conf; grep -xvFf <(pacman -Qqm) <(expac "%n\t%p" | grep "$PACKAGER$" | cut -f1)

在 64 位系统上构建 32 位软件包

请参阅 32 位软件包指南

无人值守的软件包签名

本文或章节是与 GnuPG#无人值守的密码短语 合并的候选对象。

注意: 这不是 makepkg 特有的。(在 Talk:Makepkg 中讨论)

本文或章节需要扩展。

原因: 另一个选项是 gnupg-set-passphrase(1)[死链接 2022-06-25] (在 Talk:Makepkg 中讨论)

在 Jenkins 等自动化构建环境中,可能没有人可以为用于签名的 gpg 私钥提供密码短语。在没有密码短语的情况下将私有 gpg 密钥存储在系统上是不明智的。

使用 makepkg 创建的生成的 zst 软件包仍然可以在创建后签名

$ gpg --detach-sign --pinentry-mode loopback --passphrase --passphrase-fd 0 --output NewlyBuilt.pkg.tar.zst.sig --sign NewlyBuilt.pkg.tar.zst 

其中 GPG 密码短语由您选择的自动化套件安全地提供和模糊处理。

当托管您自己的仓库时,生成的 zstsig 文件可以被期望有效签名的 pacman 客户端和使用 repo-add --sign 创建的仓库引用。

Magnet URI

支持在 source 字段中使用 magnet URIs 资源(带有 magnet:// 前缀),可以通过 transmission-dlagentAUR 下载代理添加此功能。

在 systemd 控制组中运行 makepkg

如果您构建的软件包需要过多资源才能使用默认的 make 标志进行构建(这些标志通常已为大多数软件包正确设置),您可以尝试在其自身的控制组中运行它。makepkg-cgAURmakepkg 的一个包装器,它通过 systemd 控制组来实现此目的(参见 systemd.resource-control(5))。

使用空闲调度策略运行

软件包构建过程可能会导致 CPU 使用率过高,尤其是在 #并行编译 的情况下。在高 CPU 负载下,系统可能会显著减速,甚至变得无法使用,即使使用最高的 nice(1) 值也是如此。用户界面和前台应用程序可能会卡顿甚至变得无响应。

可以通过在运行 makepkg 之前将调度策略更改为 SCHED_IDLE 来解决此问题。这确保了软件包构建过程不会干扰常规任务,并且仅利用剩余的未使用 CPU 时间。

来自 sched(7) § SCHED_IDLE: 调度极低优先级作业

此策略旨在以极低的优先级运行作业(甚至低于使用 SCHED_OTHERSCHED_BATCH 策略的 +19 nice 值)。

可以通过运行 chrt(1) 命令并使用 -i 标志来设置 SCHED_IDLE 策略,指定优先级 0(SCHED_IDLE 的唯一有效选项)并指定当前 shell 的 PID。

对于大多数 shell

$ chrt -iap 0 $$
提示: 您可以将此命令放入 makepkg.conf 中,以便将其应用于每次构建。

对于 fish shell,其中 $$ 未设置

$ chrt -iap 0 %self

每个软件包目录内的相对路径

除了为软件包输出选项使用绝对路径外,您还可以在每个软件包目录内配置相对路径。

注意: 以下选项可能会导致某些 AUR 助手出现问题,因为它们可能会在未定义 $startdir 的上下文中使用 makepkg.conf。因此请小心。

例如,您可以在 makepkg.conf 文件中定义目标路径,如下所示。 $startdir 变量指的是您构建软件包时 PKGBUILD 所在的目录。

PKGDEST="$startdir/build/packages/"
SRCDEST="$startdir/build/sources/"
SRCPKGDEST="$startdir/build/srcpackages/"
LOGDEST="$startdir/logs/"

这将导致:

  • 构建的软件包将存储在: "package directory"/build/packages/
  • 所有下载的源文件将存储在: "package directory"/build/sources/
  • 构建的源码包将存储在: "package directory"/build/srcpackages/
  • 所有日志将存储在: "package directory"/logs/

makepkg 仍将像往常一样创建 src/pkg/ 目录,这是预期行为。

故障排除

为基于 QMAKE 的软件包指定安装目录

qmake 生成的 makefile 使用环境变量 INSTALL_ROOT 来指定程序的安装位置。因此,此软件包函数应该有效:

PKGBUILD
...
package() {
	cd "$srcdir/${pkgname%-git}"
	make INSTALL_ROOT="$pkgdir" install
}
...

请注意,qmake 也必须进行适当的配置。例如,将以下内容放入相应的 .pro 文件中:

YourProject.pro
...
target.path = /usr/local/bin
INSTALLS += target
...

警告:软件包包含对 $srcdir 的引用

不知何故,变量 $srcdir$pkgdir 中包含的文字字符串最终出现在软件包中安装的文件之一中。[6]

要确定是哪些文件,请从 makepkg 构建目录运行以下命令:

$ grep -R "$PWD/src" pkg/

一个可能的原因是在 C/C++ 代码中使用 __FILE__ 宏,并将完整路径传递给编译器。

Makepkg 在代理后下载依赖项失败

makepkg 调用依赖项时,它会调用 pacman 来安装软件包,这需要通过 sudo 获得管理权限。但是,sudo 不会将任何环境变量传递到特权环境,包括代理相关的变量 ftp_proxyhttp_proxyhttps_proxyno_proxy

为了使 makepkg 在代理后工作,请调用以下方法之一。

通过在 XferCommand 中设置其 URL 来启用代理

可以在 /etc/pacman.conf 中设置 XferCommand 以使用所需的代理 URL。在 pacman.conf 中添加或取消注释以下行:

/etc/pacman.conf
...
XferCommand = /usr/bin/curl --proxy http://username:password@proxy.proxyhost.com:80 --location --continue-at - --fail --output %o %u
...

通过 sudoer 的 env_keep 启用代理

或者,可能需要使用 sudoer 的 env_keep 选项,该选项允许保留给定变量的特权环境。有关更多详细信息,请参见 Pacman#Pacman 不遵守代理设置

Makepkg 失败,但 make 成功

如果某些内容使用 make 成功编译,但通过 makepkg 失败,则几乎可以肯定是因为 /etc/makepkg.conf 设置了不兼容的编译变量。尝试将这些标志添加到 PKGBUILD options 数组中:

!buildflags,以阻止其默认的 CPPFLAGSCFLAGSCXXFLAGSLDFLAGS

!makeflags,以阻止其默认的 MAKEFLAGS

!debug,以防止其默认的 DEBUG_CFLAGSDEBUG_CXXFLAGS,以防 PKGBUILD 是调试版本。

如果其中任何一个解决了问题,则可能需要提交上游错误报告,前提是已识别出有问题的标志。

参见