这篇文章上次修改于 766 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

1 bazel

baszel 用于构建项目,作用类似于 CMake,但是比 CMake 更快

示例项目的目录结构:

example
├── lib
│   ├── BUILD
│   ├── print-time.cc
│   └── print-time.h
├── main
│   ├── BUILD
│   ├── hello-greet.cc
│   ├── hello-greet.h
│   └── hello-world.cc
└── WORKSPACE
  • WORKSPACE 文件标识其所在目录为 bazel 工作空间,它位于项目根目录下,包含第三方依赖,可以为空。
  • BUILD 文件告诉 bazel 如何构建 lib、bin 等,它位于每个 package 下。

lib/print-time.h:

#ifndef LIB_PRINT_TIME_H_
#define LIB_PRINT_TIME_H_

void print_localtime();

#endif

lib/print-time.cc:

#include "lib/print-time.h"

#include <ctime>
#include <iostream>

void print_localtime() {
  std::time_t result = std::time(nullptr);
  std::cout << std::asctime(std::localtime(&result));
}

lib/BUILD 生成 //lib:print-time 库:

load("@rules_cc//cc:defs.bzl", "cc_library")

cc_library(
    name = "print-time",
    srcs = ["print-time.cc"],
    hdrs = ["print-time.h"],
    visibility = ["//main:__pkg__"],
)

main/hello-greet.h:

#ifndef MAIN_HELLO_GREET_H_
#define MAIN_HELLO_GREET_H_

#include <string>

std::string get_greet(const std::string &thing);

#endif

main/hello-greet.cc:

#include "main/hello-greet.h"

#include <string>

std::string get_greet(const std::string& who) {
  return "Hello " + who;
}

main/hello-world.cc:

#include <iostream>
#include <string>

#include "lib/print-time.h"
#include "main/hello-greet.h"

int main(int argc, char** argv) {
  std::string who = "world";
  if (argc > 1) {
    who = argv[1];
  }
  std::cout << get_greet(who) << std::endl;
  print_localtime();
  return 0;
}

main/BUILD;

load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
        "//lib:print-time",
    ],
)

在生成最终的 hello-world 二进制文件时,依赖了 hello-greet 和 //lib:print-time 库。

构建 hello-world:

$ bazel build //main:hello-world

会自动构建其依赖的所有库,构建结果位于 bazel-bin 下。

运行生成的 hello-world:

$ ./bazel-bin/main/hello-world
Hello world
Wed May  5 19:31:18 2021

2 gflags

gflags 用于从命令行解析参数。

修改 WORKSPACE,获取 gflags 包:

workspace(name = "example")

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

http_archive(
    name = "com_github_gflags_gflags",
    sha256 = "34af2f15cf7367513b352bdcd2493ab14ce43692d2dcd9dfc499492966c64dcf",
    strip_prefix = "gflags-2.2.2",
    urls = ["https://github.com/gflags/gflags/archive/v2.2.2.tar.gz"],
)

修改 mian/BUILD,生成 hello-world 时添加 gflags 依赖:

...

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
        "//lib:print-time",
        "@com_github_gflags_gflags//:gflags",
    ],
)

修改 main/hello-world.cc,添加 gflags 头文件,并从命令行中解析参数:

#include <iostream>
#include <string>

#include "gflags/gflags.h"

#include "lib/print-time.h"
#include "main/hello-greet.h"

DEFINE_string(name, "nobody", "user's name");

int main(int argc, char** argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);

  std::cout << get_greet(FLAGS_name) << std::endl;

  print_localtime();
  return 0;
}

构建并运行:

$ bazel build //main:hello-world
$ ./bazel-bin/main/hello-world --name=Tom
Hello Tom
Wed May  5 20:05:49 2021

3 glog

glog 用于打印日志。

修改 WORKSPACE,获取 glog 包:

...

http_archive(
    name = "com_github_google_glog",
    sha256 = "62efeb57ff70db9ea2129a16d0f908941e355d09d6d83c9f7b18557c0a7ab59e",
    strip_prefix = "glog-d516278b1cd33cd148e8989aec488b6049a4ca0b",
    urls = ["https://github.com/google/glog/archive/d516278b1cd33cd148e8989aec488b6049a4ca0b.zip"],
)

修改 mian/BUILD,生成 hello-world 时添加 glog 依赖:

...

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
        "//lib:print-time",
        "@com_github_gflags_gflags//:gflags",
        "@com_github_google_glog//:glog",
    ],
)

修改 main/hello-world.cc,添加 glog 头文件,并打印日志:

#include <iostream>
#include <string>

#include "gflags/gflags.h"
#include "glog/logging.h"

#include "lib/print-time.h"
#include "main/hello-greet.h"

DEFINE_string(name, "nobody", "user's name");

int main(int argc, char** argv) {
  google::InitGoogleLogging(argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  std::cout << get_greet(FLAGS_name) << std::endl;

  LOG(ERROR) << FLAGS_name;

  print_localtime();
  return 0;
}

构建并运行:

$ bazel build //main:hello-world
$ ./bazel-bin/main/hello-world --name=Tom
Hello Tom
E20210506 19:04:58.778676  9023 hello-world.cc:18] Tom
Thu May  6 19:04:58 2021

4 gtest

gtest 用于单元测试。

修改 WORKSPACE,获取 gtest 包:

...

http_archive(
  name = "com_google_googletest",
  urls = ["https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip"],
  strip_prefix = "googletest-609281088cfefc76f9d0ce82e1ff6c30cc3591e5",
)

编写测试文件 hello-test.cc:

#include "gtest/gtest.h"

// Demonstrate some basic assertions.
TEST(HelloTest, BasicAssertions) {
  // Expect two strings not to be equal.
  EXPECT_STRNE("hello", "world");
  // Expect equality.
  EXPECT_EQ(7 * 6, 42);
}

测试:

$ bazel test //main:hello_test