Bazel官方教程 -- 通用C++使用案例

Bazel官方教程 – 通用C++使用案例

官方参考:https://docs.bazel.build/versions/main/cpp-use-cases.html

在这里,您将找到一些使用 Bazel 构建 C++ 项目的最常见用例。 如果您还没有学习构建 C++ 项目,请先完成教程 Bazel官方教程 – 构建C++工程基础知识,然后再来循序渐进学习,下文标黄色的重点是与官方提供代码有出入的细节

有关 cc_library 和 hdrs 头文件的信息,请参阅 cc_library。

1. 在一个目标中包含多个文件

您可以使用 glob 在单个目标中包含多个文件。 例如:

cc_library(
    name = "build-all-the-files",
    srcs = glob(["*.cc"]),
    hdrs = glob(["*.h"]),
)

使用此目标,Bazel 将找寻 BUILD 文件相同的目录下所有 .cc 和 .h 文件(不包括子目录),来构建项目。

2. 使用传递包含

如果文件包含头文件,则文件的规则应取决于该头文件的库。 相反,仅需要将直接依赖项指定为依赖项。 例如,假设sandwich.h 包含bread.h,而bread.h 包含flour.h。sandwich.h 不包括floor.h(谁想要 floor.h 在sandwich.h 中?),所以 BUILD 文件看起来像这样:

cc_library(
    name = "sandwich",
    srcs = ["sandwich.cc"],
    hdrs = ["sandwich.h"],
    deps = [":bread"],
)

cc_library(
    name = "bread",
    srcs = ["bread.cc"],
    hdrs = ["bread.h"],
    deps = [":flour"],
)

cc_library(
    name = "flour",
    srcs = ["flour.cc"],
    hdrs = ["flour.h"],
)

这里sandwich库依赖于bread库,bread库又依赖于flour库。

3. 添加包含目录

有时您不能(或不想)在工作空间根目录下,具有包含目录。 可能存在一个有包含目录的库,该目录与其在您的工作区的路径不一致。 例如,假设您具有以下目录结构:

└── my-project  ## 工作区所在目录
    ├── legacy    
    │   └── some_lib  ## 库所在目录
    │       ├── BUILD
    │       ├── include
    │       │   └── some_lib.h
    │       └── some_lib.cc
    └── WORKSPACE

Bazel 期望 some_lib.h 被包含,正常使用的话,需要写作如下形式: legacy/some_lib/include/some_lib.h,但假设 some_lib.cc 直接使用 #include “some_lib.h”, 为了使包含路径有效,legacy/some_lib/BUILD 需要指定 some_lib/include 目录是一个包含目录

cc_library(
    name = "some_lib",
    srcs = ["some_lib.cc"],
    hdrs = ["include/some_lib.h"],
    copts = ["-Ilegacy/some_lib/include"],
)

这对于外部依赖项特别有用,因为它们的头文件必须包含在 / 前缀中。

4. 包含外部库

假设您正在使用 Google Test。 您可以在 WORKSPACE 文件下使用仓库功能中的一个函数,去下载 Google Test 并
使其在您的仓库中可用:

// 添加在WORKSPACE文件中
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "gtest",
    url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
    sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
    build_file = "@//:gtest.BUILD",
)

注意:如果目标已包含 BUILD 文件,则可以省略 build_file 属性。

然后创建 gtest.BUILD文件,一个用于编译 Google Test 的 BUILD 文件。 Google Test 有几个“特殊”要求,使其 cc_library 规则更加复杂:

  • 关于googletest-release-1.10.0/src/*.cc 所有文件,需要在编译时,排除googletest-release-1.10.0/src/gtest-all.cc 以防止重复符号的链接错误。
  • 它使用的头文件(“gtest/gtest.h”),是相对于 googletest-release-1.10.0/include/ 目录的,因此您必须将该目录添加到包含路径中。
  • 它需要在 pthread 中链接,因此将其添加做为 linkopt。

因此,最终规则如下所示:

cc_library(
    name = "main",
    srcs = glob(
        ["googletest-release-1.10.0/src/*.cc"],
        exclude = ["googletest-release-1.10.0/src/gtest-all.cc"]
    ),
    hdrs = glob([
        "googletest-release-1.10.0/include/**/*.h",
        "googletest-release-1.10.0/src/*.h"
    ]),
    copts = [
        "-Iexternal/gtest/googletest-release-1.10.0/include",
        "-Iexternal/gtest/googletest-release-1.10.0"
    ],
    linkopts = ["-pthread"],
    visibility = ["//visibility:public"],
)

这有点混乱:所有内容都以 googletest-release-1.10.0 为前缀,作为archive结构的副产品。 您可以通过添加 strip_prefix 属性使 http_archive 去除此前缀:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# 注意此处官方版本为1.10.0,推荐使用下面的1.7.0
http_archive(
    name = "gtest",
    build_file = "@//:gtest.BUILD",
    sha256 = "b58cb7547a28b2c718d1e38aee18a3659c9e3ff52440297e965f5edffe34b6d0",
    strip_prefix = "googletest-release-1.7.0",
    url = "https://github.com/google/googletest/archive/release-1.7.0.zip",
)

注意:使用官网的1.10.0,会报类似gcc failed: error executing command /usr/bin/gcc @bazel-out/k8-fastbuild/bin/test-2.params错误。

然后 gtest.BUILD 看起来像这样:

cc_library(
    name = "main",
    srcs = glob(
        ["src/*.cc"],
        exclude = ["src/gtest-all.cc"]
    ),
    hdrs = glob([
        "include/**/*.h",
        "src/*.h"
    ]),
    copts = ["-Iexternal/gtest/include"],
    linkopts = ["-pthread"],
    visibility = ["//visibility:public"],
)

现在 cc_ 的相关规则 可以依赖 @gtest//:main

5. 编写和运行 C++ 测试

例如,您可以创建一个测试 ./test/hello-test.cc,例如:

#include "gtest/gtest.h"
#include "main/hello-greet.h"

TEST(HelloTest, GetGreet) {
  EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");
}

然后为您的测试,创建 ./test/BUILD 文件:

cc_test(
    name = "hello-test",
    srcs = ["hello-test.cc"],
    copts = ["-Iexternal/gtest/include"],
    deps = [
        "@gtest//:main",
        "//main:hello-greet",
    ],
)

要使 hello-greet 对 hello-test 可见,您必须将“//test:pkg”添加到 ./main/BUILD 中的可见属性。

当前的目录结构为

├── BUILD(空文件夹,**必须**,否则会提示找不到gtest.BUILD同层目录下的BUILD文件)
├── gtest.BUILD
├── main
│   ├── BUILD
│   ├── hello-greet.cc
│   ├── hello-greet.h
│   └── hello-world.cc
├── test
│   ├── BUILD
│   └── test.cc
└── WORKSPACE

现在您可以使用 bazel test 来运行测试。

bazel test test:test
bazel test --test_output all //test:test    # 查看测试输出结果

这会产生以下输出:

INFO: Analyzed target //test:test (0 packages loaded, 0 targets configured).
INFO: Found 1 test target...
Target //test:test up-to-date:
  bazel-bin/test/test
INFO: Elapsed time: 0.104s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
//test:test                                                     (cached) PASSED in 0.0s

Executed 0 out of 1 test: 1 test passes.
There were tests whose specified size is too big. Use the --test_verbose_timeout_warnings commINFO: Build completed successfully, 1 total action

注意:

6. 对预编译库添加依赖

如果要使用只有编译版本的库(例如,头文件和 .so 文件),请将其包装在 cc_library 规则中:

cc_library(
    name = "mylib",
    srcs = ["mylib.so"], 
    hdrs = ["mylib.h"],
)

这样,您工作区中的其他 C++ 目标可以依赖此规则。

你可能感兴趣的:(编译,c++,visual,studio,开发语言)