简介
您是 Bazel 新手吗?您来对地方了。请按照本“首次构建”教程中的 简化说明,了解如何使用 Bazel。本教程定义了 Bazel 上下文中的关键术语,并介绍了 Bazel 工作流程的基础知识。首先,您将了解所需的工具,然后构建并运行三个 复杂度逐渐增加的项目,并了解这些项目为何以及如何变得更加复杂。
虽然 Bazel 是一个 构建系统, 支持多语言构建,但本教程以 C++ 项目为例, 并提供了适用于大多数语言的一般准则和流程。
预计完成时间:30 分钟。
前提条件
首先安装 Bazel(如果您尚未 安装)。本教程使用 Git 进行源代码控制,因此为了获得最佳效果,请同时安装 Git。
接下来,在您选择的命令行工具中运行以下命令,从 Bazel 的 GitHub 代码库检索示例项目:
git clone https://github.com/bazelbuild/examples本教程的示例项目位于 examples/cpp-tutorial
目录中。
了解一下它的结构:
examples
└── cpp-tutorial
├──stage1
│ ├── main
│ │ ├── BUILD
│ │ └── hello-world.cc
│ └── MODULE.bazel
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── MODULE.bazel
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── MODULE.bazel
共有三组文件,每组文件代表本教程中的一个阶段。 在第一阶段,您将构建位于单个软件包中的单个目标。在第二阶段,您将 从单个软件包构建二进制文件和库。在第三个也是最后一个 阶段,您将构建一个包含多个软件包的项目,并使用 多个目标进行构建。
摘要:简介
通过安装 Bazel(和 Git)并克隆本教程的代码库,您 已为使用 Bazel 进行首次构建奠定了基础。请继续阅读下一部分,了解一些术语并设置工作区 。
使用入门
在构建项目之前,您需要设置其工作区。工作区 是一个目录,用于存放项目的源文件和 Bazel 的构建输出。 它还包含以下重要文件:
MODULE.bazel文件,用于将目录及其内容标识为 Bazel 工作区,并位于项目目录结构的根目录中 。您还可以在其中指定外部依赖项。- 一个或多个
BUILD文件,用于告知 Bazel 如何构建项目的不同部分。工作区中包含BUILD文件的目录是一个 软件包。(本教程稍后会详细介绍软件包 。)
在以后的项目中,如需将目录指定为 Bazel 工作区,请在该目录中创建一个名为 MODULE.bazel 的
空文件。在本
教程中,每个阶段都已存在 MODULE.bazel 文件。
了解 BUILD 文件
A BUILD 文件包含针对 Bazel 的几种不同类型的指令。每个
BUILD文件至少需要一个
规则作为一组指令,
用于告知 Bazel 如何构建所需的输出,例如可执行二进制文件
或库。BUILD 文件中构建规则的每个实例都称为
目标,并指向一组特定的源文件和
依赖项。目标还可以指向其他目标。
查看 cpp-tutorial/stage1/main 目录中的 BUILD 文件:
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
在我们的示例中,hello-world 目标实例化了 Bazel 的内置
cc_binary 规则。该规则
告知 Bazel 从
hello-world.cc> 源文件构建一个不含依赖项的自包含可执行二进制文件。
摘要:使用入门
现在,您已熟悉一些关键术语,以及它们在 本项目和 Bazel 的一般上下文中的含义。在下一部分中,您将构建并测试 项目的第 1 阶段。
第 1 阶段:单个目标、单个软件包
现在可以构建项目的第一部分了。如需查看视觉参考,请参阅项目的 第 1 阶段部分的结构:
examples
└── cpp-tutorial
└──stage1
├── main
│ ├── BUILD
│ └── hello-world.cc
└── MODULE.bazel
运行以下命令以移至 cpp-tutorial/stage1 目录:
cd cpp-tutorial/stage1然后运行:
bazel build //main:hello-world在目标标签中,//main: 部分是 BUILD 文件
相对于工作区根目录的位置,而 hello-world 是 BUILD 文件中的目标名称。
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 目标。Bazel 会将构建输出放置在工作区根目录下的
bazel-bin 目录中。
现在测试您刚刚构建的二进制文件,即:
bazel-bin/main/hello-world这会生成打印的“Hello world”消息。
以下是第 1 阶段的依赖关系图:

摘要:第 1 阶段
现在,您已完成首次构建,对 构建的结构有了基本的了解。在下一阶段,您将添加 另一个目标,从而增加复杂性。
第 2 阶段:多个构建目标
虽然单个目标对于小型项目来说已足够,但您可能需要将 大型项目拆分为多个目标和软件包。这样可以实现快速 增量构建(即 Bazel 仅重建已更改的内容),并通过一次构建项目的多个部分来加快 构建速度。本教程的这一阶段添加了一个目标,下一阶段添加了一个软件包。
这是您在第 2 阶段使用的目录:
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── MODULE.bazel
查看 cpp-tutorial/stage2/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",
],
)
借助此 BUILD 文件,Bazel 首先构建 hello-greet 库(使用
Bazel 的内置 cc_library
规则),然后构建
hello-world 二进制文件。deps 目标中的 hello-world 属性告知
Bazel,构建 hello-world
二进制文件需要 hello-greet 库。
在构建此新版本的项目之前,您需要更改
目录,通过运行以下命令切换到 cpp-tutorial/stage2 目录:
cd ../stage2现在,您可以使用以下熟悉的命令构建新的二进制文件:
bazel build //main:hello-worldBazel 再次生成如下内容:
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
现在,您可以测试刚刚构建的二进制文件,它会返回另一个“Hello
world”:
bazel-bin/main/hello-world如果您现在修改 hello-greet.cc 并重建项目,Bazel 将仅
重新编译该文件。
查看依赖关系图,您可以看到 hello-world 依赖于名为 hello-greet 的额外输入:

摘要:第 2 阶段
您现在已使用两个目标构建了项目。hello-world 目标构建
一个源文件,并依赖于另一个目标 (//main:hello-greet),该目标
构建两个额外的源文件。在下一部分中,我们将更进一步
添加另一个软件包。
第 3 阶段:多个软件包
下一个阶段将增加复杂性,并构建一个包含
多个软件包的项目。查看
cpp-tutorial/stage3 目录的结构和内容:
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── MODULE.bazel
您可以看到,现在有两个子目录,每个子目录都包含一个 BUILD
文件。因此,对于 Bazel 来说,工作区现在包含两个软件包:lib 和
main。
查看 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 属性了解
这一点。您可以在依赖关系图
中看到这一点:

为了使构建成功,您可以使用 visibility 属性使 lib/BUILD
中的 //lib:hello-time 目标对 main/BUILD 中的目标显式可见。
这是因为默认情况下,目标仅对同一
BUILD文件中的其他目标可见。Bazel 使用目标可见性来防止出现问题,例如包含实现详细信息的库
泄露到公共 API 中。
现在构建此项目的最终版本。通过运行以下命令切换到 cpp-tutorial/stage3
目录:
cd ../stage3再次运行以下命令:
bazel build //main:hello-worldBazel 会生成如下内容:
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
现在测试本教程的最后一个二进制文件,以获取最终的 Hello world 消息:
bazel-bin/main/hello-world摘要:第 3 阶段
您现在已将项目构建为包含三个目标的两个软件包,并了解了它们之间的依赖关系,这让您能够使用 Bazel 构建未来的项目。在下一部分中,了解如何继续您的 Bazel 之旅。
后续步骤
您现在已使用 Bazel 完成了首次基本构建,但这仅仅是一个 开始。以下是一些更多资源,可帮助您继续学习 Bazel:
- 如需继续专注于 C++,请阅读有关常见 C++ 构建用例 的内容。
- 如需开始使用 Bazel 构建其他应用,请参阅 Java、Android 应用或iOS 应用的教程。
- 如需详细了解如何使用本地和远程代码库,请阅读有关 外部依赖项的内容。
- 如需详细了解 Bazel 的其他规则,请参阅此 参考 指南。
祝您构建愉快!