bazel构建C++工程

1.bazel介绍

Bazel是一个开源的构建和测试工具,类似于Make、Maven和Gradle。Bazel支持多种语言的项目,并为多种平台构建输出。Bazel支持跨多个存储库和大量用户的大型代码库。

2.bazel安装

bazel安装有两种方法,一种是通过源安装,另一种是通过下载安装包本地安装。官网安装教程。本人选取的是第一种安装方式。
第一步:添加Bazel分发URI作为包源

sudo apt install curl gnupg
curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list

第二步:安装或更新bazel

sudo apt update && sudo apt install bazel

如果已经安装了bazel,需要升级到最新版本的bazel

sudo apt update && sudo apt full-upgrade

安装特定版本的bazel,例如需要安装bazel-1.0.0

sudo apt install bazel-1.0.0

3.bazel构建工程

bazel里面有构建C++工程的例子,可以通过命令git clone https://github.com/bazelbuild/examples下载,本教程的示例项目位于examples/cpp-tutorial目录中,其结构如下:

examples
└── cpp-tutorial
    ├──stage1
    │  ├── main
    │  │   ├── BUILD
    │  │   └── hello-world.cc
    │  └── WORKSPACE
    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE
    └──stage3
       ├── main
       │   ├── BUILD
       │   ├── hello-world.cc
       │   ├── hello-greet.cc
       │   └── hello-greet.h
       ├── lib
       │   ├── BUILD
       │   ├── hello-time.cc
       │   └── hello-time.h
       └── WORKSPACE

下面对这个C++工程进行解读。

3.1 设置工作区

在构建项目将之前,需要设置项目工作区,这个工作区就是一个包含项目源文件的目录和bazel构建输出,bazel识别WORKSPACEBUILD这两个文件。

  • WORKSPACE文件将目录及其内容标识为Bazel工作区,位于项目目录结构的根目录中
  • BUILD文件会有一个或者多个,分别构建项目的不同部分。

3.2 理解BUILD文件

BUILD文件包含Bazel的几种不同类型的指令。最重要的类型是构建规则,它告诉Bazel如何构建所需的输出,比如可执行的二进制文件或库。构建文件中构建规则的每个实例称为目标,并指向一组特定的源文件和依赖项。一个目标也可以指向其他目标。
看一下cpp-tutorial/stage1/main中BUILD文件:

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)

在我们的示例中,hello-world目标实例化了Bazel的内置cc_binary规则。规则告诉bazel建立一个独立的可执行二进制hello world.cc源文件没有依赖性。

3.3 使用bazel编译项目

构建示例项目。切换到cpp-tutorial/stage1目录,运行以下命令:

bazel build //main:hello-world

注意目标标签——//main:部分是构建文件相对于工作区根的位置,hello-world是我们在构建文件中命名的目标。
Bazel输出结果如下:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.267s, Critical Path: 0.25s

现在测试新构建的二进制文件:

bazel-bin/main/hello-world

3.4 查看依赖图

成功的构建将在构建文件中显式地声明其所有依赖项。Bazel使用这些语句创建项目的依赖关系图,从而实现精确的增量构建。
将示例项目的依赖关系可视化。首先,生成依赖关系图的文本表示(在工作区根运行此命令):

bazel query --notool_deps --noimplicit_deps "deps(//main:hello-world)" 
  --output graph

上面的命令告诉Bazel寻找target //main:hello-world的所有依赖项(不包括主机和隐式依赖项),并将输出格式化为图形。
然后,将文本粘贴到GraphViz中。
然后你可以通过管道直接输出到xdot来生成和查看图形:

sudo apt update && sudo apt install graphviz xdot

然后你可以通过管道直接输出到xdot来生成和查看图形:

xdot <(bazel query --notool_deps --noimplicit_deps "deps(//main:hello-world)" 
  --output graph)

如你所见,这个示例项目的第一阶段有一个单一的目标,它构建一个没有附加依赖关系的单一源文件:
bazel构建C++工程
接下来,增加点难度

3.5 多个目标文件(target)编译

将示例项目构建分成两个目标。看一下cpp-tutorial/stage2/主目录中的构建文件:

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",
    ],
)

对于这个构建文件,Bazel首先构建hello-greet库(使用Bazel内置的cc_library规则),然后构建hello-world二进制文件。hello-world目标中的deps属性告诉Bazel需要hello-greet库来构建hello-world二进制文件。
切换到cpp-tutorial/stage2目录,运行以下命令:

bazel build //main:hello-world

Bazel的输出如下:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.399s, Critical Path: 0.30s

现在测试新构建的二进制文件:

bazel-bin/main/hello-world

如果修改hello-greet.cc和重建项目,Bazel将只重新编译该文件。
看看依赖关系图,你可以看到hello-world和以前一样依赖于相同的输入,但是构建的结构是不同的:
bazel构建C++工程
现在已经构建了带有两个目标的项目。hello-world目标构建一个源文件,并依赖于另一个目标(//main:hello-greet)。

3.6 多个项目包(packages)编译

现在将项目分离成多个包,看一下cpp-tutorial/stage3目录的内容:

└──stage3
   ├── main
   │   ├── BUILD
   │   ├── hello-world.cc
   │   ├── hello-greet.cc
   │   └── hello-greet.h
   ├── lib
   │   ├── BUILD
   │   ├── hello-time.cc
   │   └── hello-time.h
   └── WORKSPACE

注意,现在有两个子目录,每个子目录都包含一个BUILD文件。因此,对于Bazel来说,工作空间现在包含两个包,libmain
先看lib/BUILD文件

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

还有main/BUILD文件:

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:hello-time",
    ],
)

主包中的hello-world目标依赖于lib包中的hello-time目标(因此是目标标签//lib:hello-time)—Bazel通过deps属性知道这一点。看看依赖关系图:
bazel构建C++工程
请注意,为了使构建成功,我们使用visibility属性使lib/ build中的//lib:hello-time目标对main/ build中的目标显式可见。这是因为在默认情况下,目标只对同一构建文件中的其他目标可见。(Bazel使用目标可见性来防止诸如库中包含的实现细节泄漏到公共api等问题。)
切换到cpp-tutorial/stage3目录,运行以下命令:

bazel build //main:hello-world

Bazel的输出如下:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 0.167s, Critical Path: 0.00s

现在测试新构建的二进制文件:

bazel-bin/main/hello-world

到此具有三个目标的两个包的项目构建完成,并了解了它们之间的依赖关系。

4.Reference

  1. Google开源构建工具Bazel
  2. Introduction to Bazel: Build a C++ Project

原文链接: https://www.cnblogs.com/zhongzhaoxie/p/13410228.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    bazel构建C++工程

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/200951

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午8:37
下一篇 2023年2月12日 下午8:37

相关推荐