makepkg
makepkg 是一个用于自动化构建软件包的脚本。使用该脚本的要求是具有构建能力的 Unix 平台和一个 PKGBUILD。
makepkg 由 pacman 软件包提供。
配置
系统配置位于 /etc/makepkg.conf
中,但用户特定的更改可以在 $XDG_CONFIG_HOME/pacman/makepkg.conf
或 ~/.makepkg.conf
中进行。此外,系统范围的更改可以使用 drop-in 文件 /etc/makepkg.conf.d/makepkg.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
构建)
您还可以使用每个软件包目录内的相对路径。
签名检查
如果 .sig 或 .asc 形式的签名文件是 PKGBUILD 源数组的一部分,则 makepkg 会自动尝试验证它。如果用户的密钥环不包含签名验证所需的公钥,则 makepkg 将中止安装,并显示 PGP 密钥无法验证的消息。
如果软件包所需的公钥丢失,则 PKGBUILD 很可能包含带有所需密钥 ID 的 validpgpkeys 条目。手动导入它,或在密钥服务器上找到它并从那里导入。要暂时禁用签名检查,请使用 --skippgpcheck
选项运行 makepkg。
用法
在继续之前,安装 base-devel 元软件包。此软件包的依赖项不需要在 PKGBUILD 文件中列为构建时依赖项(makedepends)。
要构建软件包,必须首先创建一个 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++ 编译器(例如 gcc 或 clang)的选项由 CFLAGS
、CXXFLAGS
和 CPPFLAGS
环境变量控制。为了在 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
参数可以根据需要更改为 3
、s
或 z
。有关详细信息,请参阅 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 链接器
mold 是 ld/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 月) 中,默认启用了 debug
和 lto
选项。
构建调试包使官方软件仓库能够提供更多工具来为用户排除问题(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 -)
lz4 和 xz 默认是多线程的,因此无需在 /etc/makepkg.conf
中进行任何更改。
pigz 是 gzip 的直接替代并行实现,默认情况下使用所有可用的 CPU 核心(可以使用 -p
/--processes
标志来使用较少的内核)
COMPRESSGZ=(pigz -c -f -n)
pbzip2 是 bzip2 的直接替代并行实现,默认情况下也使用所有可用的 CPU 核心。-p#
标志可用于使用较少的内核(注意:-p
和内核数之间没有空格)。
COMPRESSBZ2=(pbzip2 -c -f)
lbzip2 是 bzip2 的另一个直接替代并行实现,默认情况下也使用所有可用的 CPU 核心。-n
标志可用于使用较少的内核。
COMPRESSBZ2=(lbzip2 -c -f)
plzipAUR 是 lzip 的多线程实现,默认情况下也使用所有可用的 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 位软件包指南。
无人值守的软件包签名
在 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 密码短语由您选择的自动化套件安全地提供和模糊处理。
当托管您自己的仓库时,生成的 zst
和 sig
文件可以被期望有效签名的 pacman 客户端和使用 repo-add --sign
创建的仓库引用。
Magnet URI
支持在 source
字段中使用 magnet URIs 资源(带有 magnet://
前缀),可以通过 transmission-dlagentAUR 下载代理添加此功能。
在 systemd 控制组中运行 makepkg
如果您构建的软件包需要过多资源才能使用默认的 make 标志进行构建(这些标志通常已为大多数软件包正确设置),您可以尝试在其自身的控制组中运行它。makepkg-cgAUR 是 makepkg 的一个包装器,它通过 systemd 控制组来实现此目的(参见 systemd.resource-control(5))。
使用空闲调度策略运行
软件包构建过程可能会导致 CPU 使用率过高,尤其是在 #并行编译 的情况下。在高 CPU 负载下,系统可能会显著减速,甚至变得无法使用,即使使用最高的 nice(1) 值也是如此。用户界面和前台应用程序可能会卡顿甚至变得无响应。
可以通过在运行 makepkg 之前将调度策略更改为 SCHED_IDLE
来解决此问题。这确保了软件包构建过程不会干扰常规任务,并且仅利用剩余的未使用 CPU 时间。
来自 sched(7) § SCHED_IDLE: 调度极低优先级作业
- 此策略旨在以极低的优先级运行作业(甚至低于使用
SCHED_OTHER
或SCHED_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
每个软件包目录内的相对路径
除了为软件包输出选项使用绝对路径外,您还可以在每个软件包目录内配置相对路径。
例如,您可以在 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_proxy
、http_proxy
、https_proxy
和 no_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
,以阻止其默认的 CPPFLAGS
、CFLAGS
、CXXFLAGS
和 LDFLAGS
。
!makeflags
,以阻止其默认的 MAKEFLAGS
。
!debug
,以防止其默认的 DEBUG_CFLAGS
和 DEBUG_CXXFLAGS
,以防 PKGBUILD 是调试版本。
如果其中任何一个解决了问题,则可能需要提交上游错误报告,前提是已识别出有问题的标志。