可以利用glob在单个target中包含多个文件,例如:
cc_library(
name = "build-all-the-files",
srcs = glob(["*.cc"])
hdrs = glob(["*.h"]),
)
在这个target中,Bazel会编译BUILD文件所在目录下的所有.cc和.h文件(不包括子目录)。
如果一个文件包括头文件,那么这个文件的规则也受到头文件所包含的库的影响咯?其实,我们只需要指定直接的依赖项为依赖项即可。比如说,假如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"],
)
有时不能(或不愿)让依赖文件的路径包含其相对于工作区根目录的路径。因为现有的库可能已经拥有了与工作区路径不匹配的目录。例如,假设有以下目录结构:
└── 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文件中使用一种new_
的repo function来下载Google Test并且把它用于你的repo:
new_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路径中。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
属性使new_http_archive
带上这个前缀:
new_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
。
例如,我们可以创建一个测试程序./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
运行测试了。
bazel test test:hello-test
这会得到如下的output:
INFO: Found 1 test target...
Target //test:hello-test up-to-date:
bazel-bin/test/hello-test
INFO: Elapsed time: 4.497s, Critical Path: 2.53s
//test:hello-test PASSED in 0.3s
Executed 1 out of 1 tests: 1 test passes.
如果你想使用一个库,但是你只有编译好的版本,包装在一个cc_library
规则里,例如你只有头文件和一个.so文件
cc_library(
name = "mylib",
srcs = ["mylib.so"],
hdrs = ["mylib.h"],
)
然后在工作区中其他的C ++程序,就可以使用这条规则了。