当我尝试从 AUR 安装软件包时,我在 Manjaro 中遇到了一个非常奇怪的问题:
$ pamac build vorta
[...]
==== AUTHENTICATION COMPLETE ====
Building vorta...
==> Making package: vorta 0.8.12-1 (Sun Jun 18 14:38:30 2023)
==> Checking runtime dependencies...
[...]
==> Removing existing $pkgdir/ directory...
==> Starting build()...
[...]
==> Entering fakeroot environment...
==> ERROR: Failed to create the directory $BUILDDIR (/var/tmp/pamac-build-felix/vorta).
Aborting...
我发现谷歌整体的单一来源针对我的具体问题;Reddit 上已有 1 年历史的帖子,至今未得到解决. 还有一个stackoverflow 上关于权限问题的旧帖子导致类似的错误,但答案并不能解决我的问题,而且我的目录上的权限已经很好了。我发现的任何其他东西都与此类似,构建甚至在build()
调用之前就失败了,但在我的例子中,它在进入 fakeroot 环境时失败了。
我怎样才能弄清楚这件事?
答案1
首先要注意的是,pamac 主要只是其他几个程序的包装器,最著名的是 pamac、yay 和 makepkg。在这种情况下,编译是堆栈的最低部分,它主要只是一个 bash 脚本。这使得很容易看到发生了什么。我们可以直接在第一次调用 pamac 时创建的目录中调用 makepkg:
$ cd /var/tmp/pamac-build-felix/vorta
$ makepkg
==> Making package: vorta 0.8.12-1 (Sun Jun 18 14:38:30 2023)
==> Checking runtime dependencies...
[...]
==> Removing existing $pkgdir/ directory...
==> Starting build()...
[...]
==> Entering fakeroot environment...
==> ERROR: Failed to create the directory $BUILDDIR (/var/tmp/pamac-build-felix/vorta).
Aborting...
我们得到与之前几乎相同的输出。现在,让我们看看 makepkg 实际上做了什么:
$ which makepkg
$ vim /usr/bin/makepkg # Or use less or any other editor
搜索fakeroot
,我们找到了这个函数:
enter_fakeroot() {
msg "$(gettext "Entering %s environment...")" "fakeroot"
fakeroot -- bash -$- "${BASH_SOURCE[0]}" -F "${ARGLIST[@]}" || exit $?
}
它只被调用两次。这些调用是互斥的,并且发生在程序结束时,因此这是构建 AUR 包时发生的最后几件事之一。
那么尝试运行 fakeroot 怎么样?我们不知道其他所有参数的作用,但我们只使用一个参数,看看会发生什么:
$ fakeroot -- bash
date: /nix/store/q29bwjibv9gi9n86203s38n0577w09sx-glibc-2.33-117/lib/libc.so.6: version `GLIBC_2.34' not found (required by /usr/lib/libfakeroot/libfakeroot.so)
啊哈!这看起来不像是正常行为!
但是为什么date
会链接到错误的 glibc?
$ which date
/home/felix/.nix-profile/bin/date
所以这里我们找到了罪魁祸首。因为所有这些程序都是脚本,它们只是调用用户环境中所有工具的版本。由于我使用的是 Nix,因此我的用户环境中的所有工具都链接到与发行版不同的 glibc。通常,这不是问题,但是fakeroot 是一个聪明的黑客在这种情况下可能会发生故障:
假根通过将文件操作库函数(chmod(2)、stat(2) 等)替换为模拟真实库函数(如果用户真的是 root 用户)所产生的效果的函数来工作。这些包装函数位于共享库中
/usr/lib/*/libfakeroot-*.so
或平台上的类似位置。共享对象通过LD_预加载动态加载器的机制。(参见 ld.so(8))
在这台特定的机器上,我很长时间没有更新我的用户环境了,因此对该环境(包括date
)中工具的调用链接到旧的 glibc 2.33,而 manjaro 安装的版本是 glibc 2.34。正常运行我的工具时,由于 Nix 的定义方式,一切都运行正常。但是当 fakeroot 强制这些工具从 加载符号时/usr/lib/libfakeroot/libfakeroot.so
,LD_PRELOAD
动态加载会失败,就像libfakeroot.so
链接到 manjaro 的 glibc 版本一样。
解决方案是更新我的渠道和环境:
$ nix-channel --list
nixpkgs https://nixos.org/channels/nixos-22.05
$ nix-channel --add https://nixos.org/channels/nixos-unstable nixpkgs
$ nix-channel --update
unpacking channels...
$ nix-env -u
upgrading 'qmk-1.1.1' to 'qmk-1.1.2'
upgrading 'yt-dlp-2023.2.17' to 'yt-dlp-2023.3.4'
upgrading 'nil-2023-01-01' to 'nil-2023-05-09'
upgrading 'asdf-vm-0.9.0' to 'asdf-vm-0.11.3'
[...]
building '/nix/store/l8zpn4ccrmqzh0q9pzc543bhw3vfn10v-user-environment.drv'...
现在,fakeroot 以及 makepkg 和 pamac 均成功了:
[...]
==> Leaving fakeroot environment.
==> Finished making: vorta 0.8.12-1 (Sun Jun 18 15:46:41 2023)
==> Cleaning up...
[...]
Updating icon theme caches... [3/4]
Updating the desktop file MIME type cache... [4/4]
Transaction successfully finished.