makepkg

来自 Arch Linux 中文维基

makepkg 是一个软件包自动化构建脚本,使用时需要一个具备构建条件的 Unix 环境和一个 PKGBUILD 文件。

makepkg 是由 pacman 包提供的。

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

全局配置位于 /etc/makepkg.conf,还可以通过 $XDG_CONFIG_HOME/pacman/makepkg.conf~/.makepkg.conf 进行用户特定配置。你还可以添加 /etc/makepkg.conf.d/makepkg.conf 文件进行系统全局配置更改。在构建软件包前,建议先检查 makepkg 配置。

提示:devtools helper scripts for building packages in a clean chroot use the /usr/share/devtools/makepkg.conf.d/arch.conf configuration file instead.

更多信息请参考 makepkg.conf(5)

打包人信息[编辑 | 编辑源代码]

每个软件包都会有元数据信息,其中就包含 packager。默认情况下,用户自己打包的软件标记为 Unknown Packager。如果多个用户会在系统上编译,或者需要发布软件包给其他人,最好提供真实的联系人。打包人信息可以通过 makepkg.conf 中的 PACKAGER 变量进行设置。

要检查已安装软件包的打包人:

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

要自动化签名过程,请同时在 makepkg.conf 中设置 GPGKEY 变量.

包输出[编辑 | 编辑源代码]

makepkg 默认会在工作目录创建软件包,并把源代码下载到 src/ 目录。可以配置到自定义的路径,比如将所有构建出的软件包放到 ~/build/packages/ 目录,所有源文件放到 ~/build/sources/ 目录下。

根据需求不同,可以配置 makepkg.conf 下的这些变量:

  • PKGDEST - 软件包构建输出目录
  • SRCDEST - 用于存放源数据的目录(在指向其它位置的情况下,软链接将被放置到 src/ 目录下)
  • SRCPKGDEST - 源代码包构建输出目录(通过 makepkg -S 构建)
提示:可以参考 pacman#清理软件包缓存 用命令(例如 paccache -c ~/build/packages/)清理 PKGDEST 目录

你还可以#在包目录下使用相对路径

验证签名[编辑 | 编辑源代码]

注意: makepkg 中的签名验证并不使用 pacman 的密钥环, 而是使用用户的密钥[1]

如果签名文件是以 .sig.asc 形式作为 PKGBUILD 源码数组的一部分提供,makepkg 会自动验证软件包。如果用户未提供需要的签名公钥,makepkg 会停止安装过程并提示用户说无法验证 PGP 密钥。

如果缺少软件包所需的公钥,那么 PKGBUILD 很可能带有 validpgpkeys 项,其中包含了所需的密钥 ID。你可以手动进行导入,也可以在在公钥服务器上进行查找,然后导入。运行 makepkg 时使用 --skippgpcheck 选项可以临时禁用签名检查。

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

继续之前,确保已安装base-devel包组 软件包组。属于这个组的软件包不会被要求列在 PKGBUILD 文件的构建时依赖(makedepends)中。

注意:
  • Make sure sudo is configured properly for commands passed to pacman. Alternatively a different authorization command can be specified with PACMAN_AUTH in the makepkg.conf(5) configuration file.
  • Running makepkg itself as root is disallowed.[2] Besides how a PKGBUILD may contain arbitrary commands, building as root is generally considered unsafe.[3] Users who have no access to a regular user account should run makepkg as the nobody user, e.g. using the command runuser -u nobody makepkg.

要构建软件包,用户必须首先创建一个 PKGBUILD 文件或编译脚本(在创建软件包中有详细描述),或者从 Arch 构建系统(ABS)AUR 或其他来源获取。获取到 PKGBUILD 后,切换到该文件所在文件夹中,然后执行以下命令构建软件包:

$ makepkg

如果需要的依赖不满足,makepkg 会输出一个警告然后失败。想要编译软件包并自动安装必须的依赖,只需添加 -s/--syncdeps 参数:

$ makepkg --syncdeps

如果添加了 -r/--rmdeps 选项,makepkg 会在结束后删除不再需要的编译依赖。如果需要持续编译软件包,请考虑定期删除未使用软件包

注意:
  • 这些依赖必须在已配置的软件源之中存在,具体信息请参考 pacman#软件仓库。另外,用户也可以在编译前手动安装需要的依赖:(pacman -S --asdeps dep1 dep2)。
  • Only global values are used when installing dependencies, i.e any override done in a split package's packaging function will not be used.

在满足所有依赖并成功编译软件包后,一个软件包文件(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]。因此,用户可以通过调整以下选项来适应本地环境,以获得或多或少的收益。

性能相关修改[编辑 | 编辑源代码]

90bf367e 号提交(包含在2024 年 2 月的 pacman 6.0.2-9 版本)应用了两个配置更改,对于本地软件包构建性能可能有重大影响。因此,建议用户对其进行审查:

注意: 压缩等级的修改在 2024-08-16 已随 319671cc 号提交被撤回[5],并将随 pacman 7.0 版本推出[6]

更多信息请参考 archlinux/packaging/packages/pacman!1archlinux/packaging/packages/pacman#23

优化编译结果[编辑 | 编辑源代码]

通过启用针对主机的编译器优化,可以提高打包后软件的性能。缺点是,为特定处理器架构编译的二进制文件无法在其他机器上正常运行。在 x86_64 机器上,重新构建官方软件包通常不会有显著的性能提升,因此不值得为此投入时间。

不过,使用 “非标准” 编译器标志很容易降低性能。许多编译器优化仅在某些情况下有用,不应对软件包随意应用。除非有评测数据证明某项优化更快,否则很有可能会导致性能下降!Gentoo 的 GCC 优化安全的 CFLAGS 文章提供了有关编译器优化的更多信息。

传递到 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不会起作用[7]。具体启用的选项需要编译后才能知道。详细步骤请参考[8]

pacman 5.2.2 开始,makepkg.conf 还包含了对 RUSTFLAGS 环境变量的覆写,用于替换 Rust 编译器的标志。通过在 RUSTFLAGS 中添加 -C target-cpu=native,Rust 编译器还能检测并应用架构特定优化项:

/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,因为某些版本会产生冲突或者软件包本身并不支持。如果出现软件包因为此原因无法编译,请在确认错误是由 MAKEFLAGS 引起的前提下,在 bug 跟踪系统中进行报告(如果是 AUR 包,则向包维护者报告)。

完整可用选项请参考 make(1)

使用内存文件系统进行编译[编辑 | 编辑源代码]

编译过程需要大量的读写操作,要处理很多小文件。将工作目录移动到 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=moldLDFLAGS,例如:

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

要向 mold 添加额外选项,可以将它们添加到 LDFLAGS 中,例如:

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

要为 Rust 软件包使用 mold,可以将 -C link-arg=-fuse-ld=mold 添加到 RUSTFLAGS 中,例如:

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

禁用调试包和 LTO[编辑 | 编辑源代码]

包含在 2024 年 2 月 pacman 6.0.2-9 版本90bf367e 号提交默认启用了 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

在压缩时使用多个 CPU 核心[编辑 | 编辑源代码]

zstd 支持对称多处理(SMP),通过添加 -T/--threads 标志可以加速压缩。默认情况下,/etc/makepkg.conf 中的 COMPRESSZST 数组包含了 -T0 标志,使得 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)支持设定压缩等级,以在速度、内存占用和压缩效率间进行取舍。

小技巧[编辑 | 编辑源代码]

减少下载和解压时间[编辑 | 编辑源代码]

设定源文件位置[编辑 | 编辑源代码]

特别是在编译 VCS 软件包时,使用 SRCDEST 可以缩短重新构建时获取和解压源代码的时间。

生成新校验和[编辑 | 编辑源代码]

安装 pacman-contrib,然后在 PKGBUILD 文件所在目录中执行以下命令来生成新校验和:

$ updpkgsums

updpkgsums uses makepkg --geninteg to generate the checksums. See this forum discussion for more details.

也可以用如 sha256sum 命令生成校验和并手动加入到 sha256sums 数组中。

Build from local source files[编辑 | 编辑源代码]

If you want to make changes to the source code you can download the source code without building the package by using the -o, --nobuild Download and extract files only option.

$ makepkg -o

You can now make changes to the sources and then build the package by using the -e, --noextract Do not extract source files (use existing $srcdir/ dir) option. Use the -f option to overwrite already built and existing packages.

$ makepkg -ef

Show packages with specific packager[编辑 | 编辑源代码]

expac is a pacman database extraction utility. This command shows all packages installed on the system with the packager named packagername:

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

This shows all packages installed on the system with the packager set in the /etc/makepkg variable PACKAGER. This shows only packages that are in a repository defined in /etc/pacman.conf.

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

在 64 位系统上构建 32 位软件包[编辑 | 编辑源代码]

参考32位软件包打包准则

Unattended package signing[编辑 | 编辑源代码]

本文或本章节可能需要合并到GnuPG#Unattended_passphrase

附注: This is not specific to makepkg.(在 Talk:Makepkg 中讨论)

这篇文章的某些内容需要扩充。

原因: Another option is gnupg-set-passphrase(1)[失效链接 2022-06-25] (在 Talk:Makepkg 中讨论)

A person may not be available to provide the passphrase for the gpg private key used to sign with in automated build environments such as Jenkins. It is ill-advised to store a private gpg key on a system without a passphrase.

A resulting zst package made with makepkg can still be signed after creation:

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

where the GPG passphrase is securely provided and obscured by your automation suite of choice.

The resulting zst and sig file can be referenced by pacman clients expecting a valid signature and repositories created with repo-add --sign when hosting your own repo.

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

Support for magnet URIs resources (with magnet:// prefix) in the source field can be added using the transmission-dlagentAUR download agent.

Running makepkg in a systemd control group[编辑 | 编辑源代码]

If the package you are building takes too many resources to build with your default make flags, which are otherwise set properly for most packages, you can try running it in its own control group. makepkg-cgAUR is a wrapper for makepkg that achieved this via systemd control groups (see systemd.resource-control(5)).

Running with idle scheduling policy[编辑 | 编辑源代码]

Package build process can lead to high CPU utilization, especially in case of #Parallel compilation. Under heavy CPU load, the system can issue a significant slowdown up to becoming unusable, even with the highest nice(1) value. User interface and foreground applications may stutter or even became unresponsive.

This can be worked around by changing the scheduling policy to SCHED_IDLE before running makepkg. It ensures that package building process does not interfere with regular tasks and only utilizes remaining unused CPU time.

From sched(7) § SCHED_IDLE: Scheduling very low priority jobs:

This policy is intended for running jobs at extremely low priority (lower even than a +19 nice value with the SCHED_OTHER or SCHED_BATCH policies).

The SCHED_IDLE policy can be set by running chrt(1) command with the -i flag, specifying priority 0 (the only valid option for SCHED_IDLE) and specifying the PID of the current shell.

For most shells:

$ chrt -iap 0 $$
提示:You can apply this command for every build by placing it into makepkg.conf.

For the fish shell, where $$ is not set:

$ chrt -iap 0 %self

在包目录下使用相对路径[编辑 | 编辑源代码]

Instead of using absolute paths for the package output options, you can also configure relative paths inside each package directory.

注意: The following options might cause problems with some AUR helpers, as they might use makepkg.conf in a context where $startdir is not defined. So be careful.

For example, you can define target paths in your makepkg.conf file as follows. The $startdir variable refers to the directory where a PKGBUILD is located when you build a package.

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

This will result in:

  • Built packages will be stored in: "package directory"/build/packages/
  • All downloaded source files will be stored in: "package directory"/build/sources/
  • Built source packages will be stored in: "package directory"/build/srcpackages/
  • All logs will be stored in: "package directory"/logs/

makepkg will still create a src/ and pkg/ directories a usual, so this is expected behaviour.

问题处理[编辑 | 编辑源代码]

Specifying install directory for QMAKE based packages[编辑 | 编辑源代码]

The makefile generated by qmake uses the environment variable INSTALL_ROOT to specify where the program should be installed. Thus this package function should work:

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

Note, that qmake also has to be configured appropriately. For example put this in the corresponding .pro file:

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

WARNING: Package contains reference to $srcdir[编辑 | 编辑源代码]

由于某种原因,有时 $pkgdir$srcdir 中的字面字符串会进入到软件包中的文件[9]

可以在 makepkg 构建文件夹中执行以下命令进行检测:

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

一个可能是 C/++ 代码使用了 __FILE__ 宏并将完整路径传递给了编译器。

Makepkg fails to download dependencies when behind proxy[编辑 | 编辑源代码]

When makepkg calls dependencies, it calls pacman to install the packages, which requires administrative privileges via sudo. However, sudo does not pass any environment variables to the privileged environment, and includes the proxy-related variables ftp_proxy, http_proxy, https_proxy, and no_proxy.

In order to have makepkg working behind a proxy, invoke one of the following methods.

Enable proxy by setting its URL in XferCommand[编辑 | 编辑源代码]

The XferCommand can be set to use the desired proxy URL in /etc/pacman.conf. Add or uncomment the following line in pacman.conf:

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

Enable proxy via sudoer's env_keep[编辑 | 编辑源代码]

Alternatively, one may want to use sudoer's env_keep option, which enables preserving given variables the privileged environment. See Pacman#Pacman does not honor proxy settings for more details.

Makepkg fails, but make succeeds[编辑 | 编辑源代码]

If something successfully compiles using make, but fails through makepkg, it is almost certainly because /etc/makepkg.conf sets an incompatible compilation variable. Try adding these flags to the PKGBUILD options array:

!buildflags, to prevent its default CPPFLAGS, CFLAGS, CXXFLAGS, and LDFLAGS.

!makeflags, to prevent its default MAKEFLAGS.

!debug, to prevent its default DEBUG_CFLAGS, and DEBUG_CXXFLAGS, in case the PKGBUILD is a debug build.

If any of these fix the problem, this could warrant an upstream bug report assuming the offending flag has been identified.

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