我有一个非常简单的目录结构:
.
├── libs
│ └── foo
│ ├── BUILD
│ ├── include
│ │ └── foo
│ │ └── func.h
│ └── src
│ └── func.cxx
└── WORKSPACE
使用func.h
:
#pragma once
int square(int );
func.cxx
:
#include <foo/func.h>
int square(int i) { return i * i; }
BUILD
:
cc_library(
name = "foo",
srcs = ["src/func.cxx"],
hdrs = ["include/foo/func.h"],
visibility = ["//visibility:public"],
)
这无法构建:
$ bazel build //libs/foo
INFO: Analysed target //libs/foo:foo (0 packages loaded).
INFO: Found 1 target...
ERROR: /home/brevzin/sandbox/bazel/libs/foo/BUILD:1:1: C++ compilation of rule '//libs/foo:foo' failed (Exit 1)
libs/foo/src/func.cxx:1:22: fatal error: foo/func.h: No such file or directory
#include <foo/func.h>
^
compilation terminated.
Target //libs/foo:foo failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 0.299s, Critical Path: 0.02s
FAILED: Build did NOT complete successfully
如何正确设置包含路径?我尝试使用include_prefix
(无论是include
还是include/foo
),但这并没有改变行为。
答案 0 :(得分:2)
嗯,关于包含来自其他地方的标题的棘手部分是你必须根据工作空间(WORKSPACE
文件所在的位置)从其相对位置指定头文件。
此外,除非包含系统头文件,否则不应使用包含样式#include <a/b.h>
的尖括号。
#include
的相关规范可在此处找到:https://docs.bazel.build/versions/master/bazel-and-cpp.html#include-paths
TL; DR 您需要对func.cxx
文件进行的唯一更改是,将第一行更改为#include "libs/foo/include/foo/func.h"
。
然后,当您从工作区的根目录运行bazel build //...
(在此工作空间中构建所有目标,类似于make
使all
)时,您将不会遇到任何错误。< / p>
但是,这不是解决问题的唯一方法。
另一种解决此问题但不涉及更改源代码include语句的方法是在规则cc_library
的属性中指定包含路径。
这意味着,您可以对路径BUILD
中的libs/foo
进行更改,使其如下所示:
cc_library(
name = "foo",
srcs = ["src/func.cxx"],
hdrs = ["include/foo/func.h"],
copts = ["-Ilibs/foo/include"], # This is the key part
visibility = ["//visibility:public"],
)
在此更改之后,编译器将能够找出在哪里找到头文件,并且您不必更改源代码,
相关信息可在此处找到:https://docs.bazel.build/versions/master/cpp-use-cases.html#adding-include-paths
<击> 撞击>
<击>尽管如此,还有另一种解决问题的方法,但它会对您的代码进行更多更改。
它使用规则cc_inc_library
。
规则cc_inc_library
将从prefix
属性中指定的头文件的相对路径中删除传递给此规则的hdrs
属性。
网站上的示例有点令人困惑,您的代码和目录结构将产生更好的演示目的。
在您的情况下,您必须将BUILD
下的libs/foo
文件修改为以下内容:
cc_library(
name = "foo",
srcs = ["src/func.cxx"],
deps = [":lib"],
copts = ["-Ilibs/foo/include"],
visibility = ["//visibility:public"],
)
cc_inc_library(
name = "lib",
hdrs = ["include/foo/func.h"],
prefix = "include/foo",
)
在您的情况下,标题文件func.h
具有libs/foo
包中include/foo/func.h
的相对路径,hdrs
属性中指定了该路径。
由于它具有libs/foo/include/foo/func.h
工作区根目录的相对路径,prefix
中的cc_inc_library
属性被指定为include/foo
:值include/foo
将被lib/foo/include/foo/func.h
删除,使其成为libs/foo/func.h
。
因此,现在您可以将此标头文件包含在func.cxx
#include "libs/foo/func.h"
中
现在,bazel不会报告错误,说它无法找到头文件。
您可以在https://docs.bazel.build/versions/master/be/c-cpp.html#cc_inc_library找到有关此规则的信息。 但是,如上所述,解释充其量是混乱,可能是因为它的文档已过时。
bazel.build
上的办公室解释让我感到困惑,直到我在以下网址阅读此规则的源代码:https://github.com/bazelbuild/bazel/blob/f20ae6b20816df6a393c6e8352befba9b158fdf4/src/main/java/com/google/devtools/build/lib/rules/cpp/CcIncLibrary.java#L36-L50
实现该函数的实际代码的注释在解释此规则实际执行的操作方面做得更好。
击><击> 撞击>
自Bazel发布0.12后, cc_inc_library
规则已被弃用。
改为使用cc_library
方法。
答案 1 :(得分:1)
您真正想要的是strip_include_prefix
:
cc_library(
name = "foo",
srcs = ["src/func.cxx"],
hdrs = ["include/foo/func.h"],
# Here!
strip_include_prefix = "include",
visibility = ["//visibility:public"],
)
这将使标题可以通过以下方式访问:
#include "foo/func.h"
这个属性从至少 Bazel 0.17 开始就可用了。