代码之家  ›  专栏  ›  技术社区  ›  Barry

使用bazel构建简单的库,修复include路径

  •  9
  • Barry  · 技术社区  · 7 年前

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

    .
    ├── 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 回复  |  直到 7 年前
        1
  •  5
  •   Xiao Liang    6 年前

    嗯,包含其他位置的头文件的棘手之处在于,您必须根据工作区(其中 WORKSPACE 文件驻留)。

    此外,您不应使用包括样式在内的尖括号 #include <a/b.h> 除非包含系统头文件。

    相关规范 #include 可在此处找到: https://docs.bazel.build/versions/master/bazel-and-cpp.html#include-paths

    TL;博士 您需要对 func.cxx 文件,将第一行更改为 #include "libs/foo/include/foo/func.h" .

    然后,当你跑步的时候 bazel build //... (在此工作区中构建所有目标,类似于 make 制造 all )从工作区的根目录中,您将不会遇到任何错误。


    然而,这并不是解决问题的唯一方法。

    解决此问题的另一种不涉及更改源代码include语句的方法是在规则的属性中指定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\U inc\U库 将剥离 prefix 从中指定的头文件的相对路径传递到此规则的属性 hdrs 属性

    网站上的示例有点混乱,您的代码和目录结构将产生更好的演示效果。

    在您的情况下,您必须修改 构建 文件位于 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 ,以及 前缀 中的属性 cc\U inc\U库 指定为 include/foo :值 包括/foo 将被剥离 lib/foo/include/foo/func.h ,成功了 libs/foo/func.h .

    现在,您可以在 职能。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

    实现该函数的实际代码的注释在解释该规则的实际功能方面做得非常好。

    cc\U inc\U库 自Bazel 0.12版以来,规则已被弃用。

    使用 cc\U库 取而代之的是接近。

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

        2
  •  2
  •   kirbyfan64sos    4 年前

    你真正想要的是 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。