官方参考:https://docs.bazel.build/versions/main/cpp-use-cases.html
在这里,您将找到一些使用 Bazel 构建 C++ 项目的最常见用例。 如果您还没有学习构建 C++ 项目,请先完成教程 Bazel官方教程 – 构建C++工程基础知识,然后再来循序渐进学习,下文标黄色的重点是与官方提供代码有出入的细节。
有关 cc_library 和 hdrs 头文件的信息,请参阅 cc_library。
您可以使用 glob 在单个目标中包含多个文件。 例如:
cc_library(
name = "build-all-the-files",
srcs = glob(["*.cc"]),
hdrs = glob(["*.h"]),
)
使用此目标,Bazel 将找寻 BUILD 文件相同的目录下所有 .cc 和 .h 文件(不包括子目录),来构建项目。
如果文件包含头文件,则文件的规则应取决于该头文件的库。 相反,仅需要将直接依赖项指定为依赖项。 例如,假设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库。
有时您不能(或不想)在工作空间根目录下,具有包含目录。 可能存在一个有包含目录的库,该目录与其在您的工作区的路径不一致。 例如,假设您具有以下目录结构:
└── 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"],
)
这对于外部依赖项特别有用,因为它们的头文件必须包含在 / 前缀中。
假设您正在使用 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 规则更加复杂:
因此,最终规则如下所示:
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
例如,您可以创建一个测试 ./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
注意:
如果要使用只有编译版本的库(例如,头文件和 .so 文件),请将其包装在 cc_library 规则中:
cc_library(
name = "mylib",
srcs = ["mylib.so"],
hdrs = ["mylib.h"],
)
这样,您工作区中的其他 C++ 目标可以依赖此规则。