在一个target中包含多个文件
可以利用glob在单个target中包含多个文件,例如:
cc_library(
name = "build-all-the-files",
srcs = glob(["*.cc"])
hdrs = glob(["*.h"]),
)
在这个target中,Bazel会编译BUILD文件所在目录下的所有.cc和.h文件(不包括子目录)。
includes可以进行传递
如果一个文件包括头文件,那么这个文件的规则也受到头文件所包含的库的影响咯?其实,我们只需要指定直接的依赖项为依赖项即可。比如说,假如sandwich.h包含bread.h,bread.h又包含floor.h,那么sandwich.h是不用显式包含flour.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"],
)
添加include路径
有时不能(或不愿)让依赖文件的路径包含其相对于工作区根目录的路径。因为现有的库可能已经拥有了与工作区路径不匹配的目录。例如,假设有以下目录结构:
└── my-project
├── third_party
│ └── some_lib
│ ├── BUILD
│ ├── include
│ │ └── some_lib.h
│ └── some_lib.cc
└── WORKSPACE
Bazel 希望some_lib.h被include的时候是以third_party/some_lib/include/some_lib.h这一路径来include的,但是some_lib.cc包含它的时候用的路径却是include/some_lib.h。为了使包含路径有效, third_party/some_lib/BUILD需要指定some_lib是一个包含目录:
cc_library(
name = "some_lib",
srcs = ["some_lib.cc"],
hdrs = ["some_lib.h"],
copts = ["-Ithird_party/some_lib"],
)
这一点对于加入外部依赖项非常有用。
包含外部库
假设你正在使用Google Test.你可以在WORKSPACE文件中使用一种repo function来下载Google Test并且把它用于你的repo:
http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.7.0.zip",
sha256 = "b58cb7547a28b2c718d1e38aee18a3659c9e3ff52440297e965f5edffe34b6d0",
build_file = "gtest.BUILD",
)
注意,如果目标位置已经包含了一个BUILD文件,则可以使用non-new_函数。
然后创建gtest.BUILD,一个用于编译Google Test的BUILD文件。Google Test有几个特殊要求使它的cc_library规则更加复杂:
- googletest-release-1.7.0/src/gtest-all.cc 包含了googletest-release-1.7.0/src/中的所有其他文件,所以我们需要在编译时去掉它,否则会由于duplicate symbols而出现link errors。
- 所使用的头文件都是相对于 googletest-release-1.7.0/include/目录的 (“gtest/gtest.h”),所以我们必须把这个文件加到include路径中。
- 它还需要link pthread, 所以我们以 linkopt的方式加。
那么根据以上规则,BUILD文件可以写成这样:
cc_library(
name = "main",
srcs = glob(
["googletest-release-1.7.0/src/*.cc"],
exclude = ["googletest-release-1.7.0/src/gtest-all.cc"]
),
hdrs = glob([
"googletest-release-1.7.0/include/**/*.h",
"googletest-release-1.7.0/src/*.h"
]),
copts = [
"-Iexternal/gtest/googletest-release-1.7.0/include"
],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
)
这看起来有点乱:一切都加了个前缀googletest-1.7.0作为archive文件结构的副产品。我们可以通过添加strip_prefix属性使http_archive带上这个前缀:
、http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.7.0.zip",
sha256 = "b58cb7547a28b2c718d1e38aee18a3659c9e3ff52440297e965f5edffe34b6d0",
build_file = "gtest.BUILD",
strip_prefix = "googletest-release-1.7.0",
)
那么现在的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_rules依赖于@gtest/main。
编写并运行C++测试程序
例如,我们可以创建一个测试程序./test/hello-test.cc:
#include "gtest/gtest.h"
#include "lib/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",
"//lib:hello-greet",
],
)
注意:为了使hello-greet对于hello-test可见,必须在./lib/BUILD添加"//test:__pkg__"可见属性。
现在可以用Bazel test运行测试了。