用bazel构建一个简单的库,修复包括路径

时间:2017-12-20 22:44:58

标签: bazel

我有一个非常简单的目录结构:

.
├── 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),但这并没有改变行为。

2 个答案:

答案 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方法。

请参阅:https://blog.bazel.build/2018/04/11/bazel-0.12.html

答案 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 开始就可用了。