从系统包含目录中隔离Bazel C ++构建

时间:2018-12-11 00:32:08

标签: bazel

我想使我的Bazel C ++构建独立于/usr/include/usr/local/include等。默认情况下,如this thread中所述,/usr/include中的所有文件将在编译C ++程序时可用,而不仅仅是标准程序。

实现此目标的最佳方法是什么?

一种选择是将标准头文件放入tarball并通过HTTP托管在某个位置,然后添加new_http_repository并使用gcc运行-nostdinc -isysroot

1 个答案:

答案 0 :(得分:1)

解决方案包括三个部分:

  • 创建自定义C ++工具链定义
  • 说服Bazel使用该工具链
  • 说服编译器忽略其默认系统头并使用您的

这是您需要的参考:

https://docs.bazel.build/versions/master/crosstool-reference.html https://docs.bazel.build/versions/master/tutorial/crosstool.html

这是一个特别好的教程:

https://github.com/bazelbuild/bazel/wiki/Yet-Another-CROSSTOOL-Writing-Tutorial

还有其他一些教程,我不知道它们是最新的:

https://github.com/bazelbuild/bazel/wiki/About-the-CROSSTOOL https://github.com/bazelbuild/bazel/wiki/Building-with-a-custom-toolchain


这是我如何在带有GCC的Linux上运行此方法:

  1. 创建一个新的工作空间,其中包含一个伪cc_binary规则。

    mkdir /tmp/bar && cd /tmp/bar
    touch WORKSPACE
    echo "cc_binary(name='x',srcs=['x.cc'])" > BUILD
    echo -e "#include <stdio.h>\nint main(void) { return 0; }" > x.cc
    
  2. 建立虚拟目标。

    bazel build //:x
    

    由于这是cc_ *规则,Bazel将初始化C ++工具链。这包括自动生成 CROSSTOOL文件。这是一个描述编译器界面的文本文件,因此Bazel知道 与之交谈。

  3. 为您的自定义Crosstool创建一个程序包,在其中复制自动生成的CROSSTOOL和BUILD文件。

    mkdir /tmp/bar/my_toolchain
    touch /tmp/bar/my_toolchain/WORKSPACE
    cat $(bazel info output_base)/external/local_config_cc/CROSSTOOL > /tmp/bar/my_toolchain/CROSSTOOL
    cat $(bazel info output_base)/external/local_config_cc/BUILD > /tmp/bar/my_toolchain/BUILD
    

    我们将使用自动生成的文件作为模板开始。

  4. 将外部存储库规则添加到WORKSPACE文件。

    echo "local_repository(name='my_toolchain', path='/tmp/bar/my_toolchain')" >> WORKSPACE
    

    这样,您可以通过Bazel构建标签引用自定义工具链。

  5. 尝试使用自定义的交叉工具。

    bazel build --crosstool_top=@my_toolchain//:toolchain //:x
    

    由于它与自动生成的相同,因此构建应该成功。

  6. 通过自定义CROSSTOOL中的“本地”工具链编辑系统头路径。

    注意:如果需要选择,您可能需要编辑其他工具链。看到 这里的工具链选择: https://docs.bazel.build/versions/master/crosstool-reference.html#toolchain-selection

    在文本编辑器中,打开/tmp/bar/my_toolchain/CROSSTOOL,找到“工具链”记录,该记录的 “ toolchain_identifier”是“ local”,并注释掉其“ cxx_builtin_include_directory”条目 (注释字符为“#”)。

    然后为您的工具链目录添加新的“ cxx_builtin_include_directory”:

    cxx_builtin_include_directory: "/tmp/bar/my_toolchain"
    

    您刚刚告诉Bazel系统标头在哪里,因此在验证标头包含时,它将知道此路径下的标头是系统标头,并且允许包含标头。

  7. 添加一个编译器标志来声明系统头文件的位置。

    在刚刚添加的“ cxx_builtin_include_directory”行下方,添加以下内容:

    compiler_flag: "-isystem=/tmp/bar/my_toolchain"
    

    您刚刚告诉Bazel告诉编译器应该在哪里查找系统头文件。

  8. 将标头添加到默认的编译操作输入集中。

    在文本编辑器中,打开/tmp/bar/my_toolchain/BUILD,找到“ compiler_deps”文件组,然后 例如,编辑其“ srcs”属性,如下所示:

    srcs = glob(["**/*.h"]),
    

    您刚刚告诉Bazel始终将这些文件包含在C ++编译操作中,因此构建 将可用于沙箱和远程执行,并且Bazel将重建C ++规则(如果有 系统标题(您刚刚添加到srcs的系统标题)会发生更改。

  9. 创建一个模拟stdc-predef.h

    这是编译器始终希望包含的头文件。幸运的是,编译器将首先 请先检查您的“ -isystem”值,然后再返回其默认路径(我不知道是否 您可以将其告诉ingore),因此我们可以像这样模拟该文件:

    touch /tmp/bar/my_toolchain/std-predef.h
    
  10. 尝试使用自定义交叉工具进行构建。

    $ bazel build --crosstool_top=@my_toolchain//:toolchain //:x
    INFO: Build options have changed, discarding analysis cache.
    INFO: Analysed target //:x (0 packages loaded, 61 targets configured).
    INFO: Found 1 target...
    ERROR: /tmp/bar/BUILD:1:1: undeclared inclusion(s) in rule '//:x':
    this rule is missing dependency declarations for the following files included by 'x.cc':
      '/usr/include/stdio.h'
      (...)
    Target //:x failed to build
    Use --verbose_failures to see the command lines of failed build steps.
    INFO: Elapsed time: 0.332s, Critical Path: 0.09s, Remote (0.00% of the time): [queue: 0.00%, setup: 0.00%, process: 0.00%]
    INFO: 0 processes.
    FAILED: Build did NOT complete successfully
    

    由于我们的工具链目录中没有stdio.h,但是编译器自己的目录中没有stdio.h 默认目录,它将找到文件并抱怨缺少标题。您可以创建一个 嘲笑stdio.h使之沉默。

    您可以创建伪造的#include <stdio.h>来使构建工作正常进行,也可以删除 x.cc的{​​{1}}行。

  11. 在自定义工具链中创建伪造的系统头。

    我们将使用它来验证Bazel是否从自定义工具链中拾取文件。

    echo 'int foo_func(int x) { return x*2; }' > /tmp/bar/my_toolchain/foo.h
    
  12. 重写源文件以包含自定义系统头。

    echo -e '#include <foo.h>\nint main(int argc, char**) { return foo_func(argc); }' > x.cc
    
  13. 使用自定义工具链再次构建。现在一切都应该正常工作。

    bazel build --crosstool_top=@my_toolchain//:toolchain //:x
    
  14. 尝试使用2个arg(所以argc=3)运行构建的二进制文件:

    bazel-bin/x hello world ; echo $?
    6