当通过 Bazel 运行 时,链接器在沙箱中失败,但在从命令行执行沙箱命令时可以正常工作

Linker fails in sandbox when running through Bazel but works when sandboxed command is executed from the command line

我正在尝试让我们的交叉工具链(标准 Yocto 工具链)与 Bazel 一起工作。我按照 https://github.com/bazelbuild/bazel/wiki/Building-with-a-custom-toolchain 上的说明进行操作,但每次我尝试构建一个简单的测试程序时,链接器都会失败。它说

external/toolchain_e6500/sysroots/x86_64-fslsdk-linux/usr/bin/powerpc64-fsl-linux/../../libexec/powerpc64-fsl-linux/gcc/powerpc64-fsl-linux/4.9.2/real-ld: cannot find /lib64/libc.so.6
external/toolchain_e6500/sysroots/x86_64-fslsdk-linux/usr/bin/powerpc64-fsl-linux/../../libexec/powerpc64-fsl-linux/gcc/powerpc64-fsl-linux/4.9.2/real-ld: cannot find /usr/lib64/libc_nonshared.a
external/toolchain_e6500/sysroots/x86_64-fslsdk-linux/usr/bin/powerpc64-fsl-linux/../../libexec/powerpc64-fsl-linux/gcc/powerpc64-fsl-linux/4.9.2/real-ld: cannot find /lib64/ld64.so.1

sysroot 设置正确。当 运行 在沙箱外部使用链接器命令时(例如使用 --spawn_strategy=standalone 或手动),它始终有效。奇怪的是,当我使用 --debug_sandbox 和 运行 从命令行发出的命令时,它也有效。

我已经调试这个问题两天了,包括 straceing Bazel 守护进程和比较 real-ld 输入,但我没有发现任何可疑的东西。

执行环境之间肯定有区别,但我现在没主意了。这是 --debug_sandbox:

打印的失败命令
(cd /home/sick/.cache/bazel/_bazel_sick/2a7ae5e27644389520091aa03d045c73/execroot/__main__ && \
  exec env - \
    PATH=/home/sick/bin:/home/sick/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/sick/bin \
    PWD=/proc/self/cwd \
    TMPDIR=/tmp \
  /home/sick/.cache/bazel/_bazel_sick/2a7ae5e27644389520091aa03d045c73/execroot/__main__/_bin/linux-sandbox -t 15 -w /home/sick/.cache/bazel/_bazel_sick/2a7ae5e27644389520091aa03d045c73/sandbox/linux-sandbox/2/execroot/__main__ -w /tmp -w /dev/shm -D -- tools/compiler_e6500/e6500_gcc/powerpc64-fsl-linux-gcc -o bazel-out/e6500-fastbuild/bin/test '--sysroot=external/toolchain_e6500/sysroots/ppc64e6500-fsl-linux' -no-canonical-prefixes -pie -Wl,-z,relro,-z,now -Wl,-S -Wl,@bazel-out/e6500-fastbuild/bin/test-2.params)

您可以在此处查看工作区https://github.com/jasal82/bazel-cross-eval

如果需要,我可以提供工具链。


更新 2018-09-25

阅读下面有关链接描述文件的答案后,我做了更多调查。 this manual 中的第 4.4.2 节说

In case a sysroot prefix is configured, and the filename starts with the / character, and the script being processed was located inside the sysroot prefix, the filename will be looked for in the sysroot prefix. Otherwise, the linker will try to open the file in the current directory.

显然,ld 不认为该脚本位于 sysroot 前缀内,因此按字面意义使用(即相对于当前目录解析,可能是沙箱根目录)。这可以解释观察到的行为。但是,我仍然不明白为什么当我手动 运行 命令时它不会发生,即不通过 Bazel 守护进程。

这可能与 CROSSTOOL 文件中使用的相对 sysroot 路径有关吗?据我了解,由于沙盒,您无法指定 sysroot 的绝对路径。在 Bazel 中处理这个问题的推荐方法是什么?我想避免必须修补工具链。

在您的 sysroot 中查看 lib.so。它可能看起来像这样:

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a  AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 )

将其中的路径更改为相对于 libc.so 所在目录的路径。您必须对 libm.solibpthread.so.[=16 执行类似的操作=]

GNU 链接器在评估脚本是否在 sysroot 中之前解析符号链接。当前的 Bazel Linux 沙箱实现创建了一个包含所有操作输入的符号链接场。因此,libc.so.6 链接描述文件被检测为位于沙箱外的 sysroot 中,但不在沙箱内。