我想使我的Bazel C ++构建独立于/usr/include
,/usr/local/include
等。默认情况下,如this thread中所述,/usr/include
中的所有文件将在编译C ++程序时可用,而不仅仅是标准程序。
实现此目标的最佳方法是什么?
一种选择是将标准头文件放入tarball并通过HTTP托管在某个位置,然后添加new_http_repository
并使用gcc
运行-nostdinc -isysroot
。
答案 0 :(得分:1)
解决方案包括三个部分:
这是您需要的参考:
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上运行此方法:
创建一个新的工作空间,其中包含一个伪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
建立虚拟目标。
bazel build //:x
由于这是cc_ *规则,Bazel将初始化C ++工具链。这包括自动生成 CROSSTOOL文件。这是一个描述编译器界面的文本文件,因此Bazel知道 与之交谈。
为您的自定义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
我们将使用自动生成的文件作为模板开始。
将外部存储库规则添加到WORKSPACE文件。
echo "local_repository(name='my_toolchain', path='/tmp/bar/my_toolchain')" >> WORKSPACE
这样,您可以通过Bazel构建标签引用自定义工具链。
尝试使用自定义的交叉工具。
bazel build --crosstool_top=@my_toolchain//:toolchain //:x
由于它与自动生成的相同,因此构建应该成功。
通过自定义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系统标头在哪里,因此在验证标头包含时,它将知道此路径下的标头是系统标头,并且允许包含标头。
添加一个编译器标志来声明系统头文件的位置。
在刚刚添加的“ cxx_builtin_include_directory”行下方,添加以下内容:
compiler_flag: "-isystem=/tmp/bar/my_toolchain"
您刚刚告诉Bazel告诉编译器应该在哪里查找系统头文件。
将标头添加到默认的编译操作输入集中。
在文本编辑器中,打开/tmp/bar/my_toolchain/BUILD
,找到“ compiler_deps”文件组,然后
例如,编辑其“ srcs”属性,如下所示:
srcs = glob(["**/*.h"]),
您刚刚告诉Bazel始终将这些文件包含在C ++编译操作中,因此构建
将可用于沙箱和远程执行,并且Bazel将重建C ++规则(如果有
系统标题(您刚刚添加到srcs
的系统标题)会发生更改。
创建一个模拟stdc-predef.h
。
这是编译器始终希望包含的头文件。幸运的是,编译器将首先 请先检查您的“ -isystem”值,然后再返回其默认路径(我不知道是否 您可以将其告诉ingore),因此我们可以像这样模拟该文件:
touch /tmp/bar/my_toolchain/std-predef.h
尝试使用自定义交叉工具进行构建。
$ 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}}行。
在自定义工具链中创建伪造的系统头。
我们将使用它来验证Bazel是否从自定义工具链中拾取文件。
echo 'int foo_func(int x) { return x*2; }' > /tmp/bar/my_toolchain/foo.h
重写源文件以包含自定义系统头。
echo -e '#include <foo.h>\nint main(int argc, char**) { return foo_func(argc); }' > x.cc
使用自定义工具链再次构建。现在一切都应该正常工作。
bazel build --crosstool_top=@my_toolchain//:toolchain //:x
尝试使用2个arg(所以argc=3
)运行构建的二进制文件:
bazel-bin/x hello world ; echo $?
6