Bazel入门2:C++编译常见用例

来源:互联网 发布:syslog apache 编辑:程序博客网 时间:2024/05/17 20:14

1. 在一个target中包含多个文件

可以利用glob在单个target中包含多个文件,例如:

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

在这个target中,Bazel会编译BUILD文件所在目录下的所有.cc和.h文件(不包括子目录)。

2.includes可以进行传递

如果一个文件包括头文件,那么这个文件的规则也受到头文件所包含的库的影响咯?其实,我们只需要指定直接的依赖项为依赖项即可。比如说,假如sandwich.h包含bread.hbread.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"],)

3. 添加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"],)

这一点对于加入外部依赖项非常有用。

4. 包含外部库

假设你正在使用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路径中。
  • 它还需要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属性使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

5. 编写并运行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运行测试了。

bazel test test:hello-test

这会得到如下的output:

INFO: Found 1 test target...Target //test:hello-test up-to-date:  bazel-bin/test/hello-testINFO: Elapsed time: 4.497s, Critical Path: 2.53s//test:hello-test PASSED in 0.3sExecuted 1 out of 1 tests: 1 test passes.

6.在预编译上添加依赖

如果你想使用一个库,但是你只有编译好的版本,包装在一个cc_library规则里,例如你只有头文件和一个.so文件

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

然后在工作区中其他的C ++程序,就可以使用这条规则了。

Reference

  1. Introduction to Bazel: Common C++ Build Use Cases