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

Bar*_*rry 6 bazel

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

.
??? libs
?   ??? foo
?       ??? BUILD
?       ??? include
?       ?   ??? foo
?       ?       ??? func.h
?       ??? src
?           ??? func.cxx
??? WORKSPACE
Run Code Online (Sandbox Code Playgroud)

func.h

#pragma once

int square(int );
Run Code Online (Sandbox Code Playgroud)

并且func.cxx

#include <foo/func.h>

int square(int i) { return i * i; }
Run Code Online (Sandbox Code Playgroud)

并且BUILD

cc_library(
    name = "foo",
    srcs = ["src/func.cxx"],
    hdrs = ["include/foo/func.h"],
    visibility = ["//visibility:public"],
)
Run Code Online (Sandbox Code Playgroud)

这无法构建:

$ 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
Run Code Online (Sandbox Code Playgroud)

如何正确设置包含路径?我尝试使用include_prefix(无论includeinclude/foo),但这并没有改变行为。

kir*_*sos 6

你真正想要的是strip_include_prefix

cc_library(
    name = "foo",
    srcs = ["src/func.cxx"],
    hdrs = ["include/foo/func.h"],
    # Here!
    strip_include_prefix = "include",
    visibility = ["//visibility:public"],
)
Run Code Online (Sandbox Code Playgroud)

这将使标头可以通过以下方式访问:

#include "foo/func.h"
Run Code Online (Sandbox Code Playgroud)

该属性至少自Bazel 0.17起可用。


Xia*_*ang 5

嗯,包含来自其他地方的头文件的棘手部分是您必须根据工作空间(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 //...(在此工作空间中构建所有目标,类似于makemake all)时,您将不会遇到错误。


但是,这并不是解决您问题的唯一方法。

解决此问题的另一种方法(不涉及更改源代码包含语句)是在规则的属性中指定包含路径cc_library

这意味着,您可以对BUILDin 路径进行更改,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"],
)
Run Code Online (Sandbox Code Playgroud)

在此更改之后,编译器将能够找出在哪里可以找到头文件,并且您不必更改源代码,是的。

相关信息可以在这里找到: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",
)
Run Code Online (Sandbox Code Playgroud)

在您的情况下,头文件func.h具有来自包的相对路径libs/fooas include/foo/func.h,它在hdrs属性中指定。
由于它有一个到工作区根的相对路径 as 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.cxxas 中包含这个头文件#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

实现该函数的实际代码的注释在解释该规则的实际作用方面做得更好。

cc_inc_library 自 Bazel 0.12 版以来,规则已被弃用。

改用cc_library方法。

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