Bazel简介:常见的C++构建用例

在这里,您将找到一些使用Bazel构建C++项目的最常用用例。如果尚未执行此操作,请完成教程Bazel简介:构建C++项目,开始使用Bazel构建C++项目。

1 在target中包含多个文件

您可以在具有glob的单个target中包含多个文件。例如:

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

使用该target,Bazel将在与包含该target的BUILD文件(子目录除外)相同的target中构建找到的所有.cc.h文件。

2 使用transitive includes

如果文件包含header,则文件的规则应取决于该header的库。相反,仅需要将直接依赖项指定为依赖项。例如,假设sandwich.h包括bread.h,而bread.h包括flour.hsandwich.h不包含flour.h(谁想要sandwich中的flour?),因此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 添加include路径

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

└── 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包含some_lib.h。为了使include路径有效,legacy/some_lib/BUILD将需要指定some_lib/include目录为include目录:

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

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

3 包括外部库

假设您正在使用Google Test。您可以使用WORKSPACE文件中的存储库功能之一来下载Google Test并将其在您的存储库中使用:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

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

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

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

  • googletest-release-1.7.0/src/gtest-all.cc #include googletest-release-1.7.0/src/中的所有其他文件,因此我们需要从编译中排除它,否则我们将收到重复符号的链接错误。
  • 它使用的头文件相对于googletest-release-1.7.0/include/目录(gtest/gtest.h),因此我们必须将该目录添加到include路径中。
  • 它需要在pthread中进行链接,因此我们将其添加为linkopt

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

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",
        "-Iexternal/gtest/googletest-release-1.7.0"
    ],
    linkopts = ["-pthread"],
    visibility = ["//visibility:public"],
)

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

load("@bazel_tools//tools/build_defs/repo:http.bzl", "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_规则可以依赖于@gtest//:main

4 编写和运行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",
        "//main:hello-greet",
    ],
)

请注意,为了使hello-greethello-test可见,我们必须在./main/BUILD中的visibility属性中添加//test:__pkg__

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

bazel test test:hello-test

这将产生以下输出:

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.

5 添加对预编译库的依赖

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

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

这样,工作空间中的其他C++ targets可以依赖此规则。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值