学习Bazel ,就要学习Bazel 的规则定义, 弄清各个概念是重要的一个步骤。 在 Bazel 规则定义中,Symbol、Rule 和 Macro 是常见的概念。除此之外,Bazel 还有 Target、Provider、Aspect Repository、Package、 Workspace、 Configuration、Build Event Protocol、 Starlark、Transition、Action 等重要概念。
概念 | 类别 | 作用 |
---|---|---|
Symbol(符号) | 基础概念 | Bazel 规则、目标、属性等命名的标识符。 |
Rule(规则) | 规则 | 定义 Bazel 构建逻辑,如 cc_library 、py_binary 。 |
Macro(宏) | 代码复用 | 通过 Starlark 编写的函数,封装多个规则以简化 BUILD 文件。 |
Target(目标) | 构建单元 | BUILD 文件中的规则实例,如 cc_library(name = "lib") 。 |
Provider(提供者) | 数据传递 | 规则间传递构建信息的方式,如 DefaultInfo(files = depset([...])) 。 |
Aspect(切面) | 依赖扩展 | 扩展规则行为,访问依赖的构建信息,如 bazel_aspect() 。 |
Repository(仓库) | 外部依赖管理 | 定义和下载外部依赖,如 http_archive() 、git_repository() 。 |
Package(包) | 代码组织 | 以 BUILD 文件为单位的代码组织单元,每个 BUILD 目录即一个 package。 |
Workspace(工作区) | 项目根目录 | 由 WORKSPACE 文件定义的 Bazel 项目,管理外部依赖。 |
Configuration(构建配置) | 编译参数 | 影响构建方式,如 --cpu=x86_64 、--compilation_mode=opt 。 |
Build Event Protocol(BEP) | 日志分析 | 记录 Bazel 构建事件,生成 JSON 或 Proto 格式日志。 |
Starlark(Bazel 语言) | 语言 | Bazel 使用的 Python 语法子集,编写规则、宏和构建逻辑。 |
Transition(配置转换) | 配置管理 | 允许在不同规则间修改构建配置,如改变 --cpu 。 |
Action(构建动作) | 执行单元 | 最小的构建执行单位,如 ctx.actions.run_shell() 运行 shell 命令。 |
下面将对它们做详细的解释:
1. Symbol(符号)
在 Bazel 中,symbol(符号) 指的是 .bzl
文件中定义的变量、函数、规则、宏等。
当你使用 load()
语句时,你在导入的就是 symbols。
示例:
load("@rules_python//python:packaging.bzl", "py_package", "py_wheel")
-
这里
py_package
和py_wheel
就是packaging.bzl
文件中定义的 symbols。 -
symbols
可以是宏(macro)、规则(rule),或者普通的 函数/变量。
2. Rule(规则)
Bazel rule(规则) 是 Bazel 构建系统的核心,用于定义如何构建目标(target)。
特性:
-
规则(rules)是 Starlark 代码,它们通常由
native.rule()
定义。 -
每个规则都能创建一个或多个 targets(构建目标),并由 Bazel 执行。
-
规则可以使用 providers 来定义输入/输出关系。
规则示例
Bazel 内置了一些规则,比如 cc_binary
和 py_binary
:
cc_binary(
name = "hello",
srcs = ["hello.cc"],
deps = [":hello_lib"],
)
-
cc_binary
是一个规则(rule),用于编译 C++ 可执行文件。 -
name
是目标名称,srcs
是源代码文件,deps
是依赖项。
自定义规则(User-defined Rule)
def _my_rule_impl(ctx):# 规则的核心逻辑 passmy_rule = rule( implementation = _my_rule_impl, attrs = { "srcs": attr.label_list(allow_files=True),},
)
-
my_rule
是 Bazel 自定义规则,用于处理srcs
作为输入。 -
implementation
是规则的实现函数_my_rule_impl
。
官方文档:
Build Rules Guide
3. Macro(宏)
宏(macro) 是 封装多个 Bazel 规则的函数,用于提高可复用性。
-
Macros 只是 Starlark 层面的封装,不会创建新的 build actions。
-
它们只是规则的组合,而不修改规则本身。
宏示例
def my_py_library(name, srcs, deps = []):native.py_library(name = name,srcs = srcs,deps = deps + ["//common:utils"],)
使用时:
load("//build_defs:my_macros.bzl", "my_py_library")my_py_library(name = "my_lib",srcs = ["lib.py"],
)
-
my_py_library
宏封装了py_library
规则,并默认加上//common:utils
作为deps
依赖项。 -
与规则(rule)不同,宏不会创建新类型的 build target,只是对已有规则的包装。
4. Target(目标)
Target(构建目标) 是 Bazel 构建系统的最小单位,它由 BUILD
文件中的规则实例化生成。
cc_library(name = "hello_lib",srcs = ["hello_lib.cc"],
)
-
这里
hello_lib
是一个 target,它是cc_library
规则的一个实例。
Target vs Rule
-
Rule 是构建的“蓝图”(定义构建逻辑)。
-
Target 是具体的构建对象(每个
name
定义一个 target)。
5. Provider(提供者)
Provider(提供者) 是规则之间的数据传递机制。
它允许规则将信息传递给依赖项。
示例
MyProvider = provider(fields = ["output"])def _my_rule_impl(ctx):output_file = ctx.actions.declare_file(ctx.label.name + ".out")ctx.actions.run_shell(outputs = [output_file],command = "echo 'Hello' > " + output_file.path,)return [MyProvider(output = output_file)]my_rule = rule(implementation = _my_rule_impl,
)
-
MyProvider
是一个自定义提供者,它包含output
字段。 -
_my_rule_impl
生成一个output_file
并通过MyProvider
返回它。 -
在规则之间,提供者用于共享构建信息。
官方文档:
Bazel Providers
6. Aspect(切面)
Aspect(切面) 允许在不修改规则的情况下为规则添加额外的行为。
它们通常用于分析或生成额外的输出。
Aspect 示例
def _my_aspect_impl(target, ctx):for src in target[DefaultInfo].files.to_list():print("Analyzing file:", src)my_aspect = aspect(implementation = _my_aspect_impl,
)
应用 aspect
cc_binary(name = "hello",srcs = ["hello.cc"],
)my_aspect(target = "//:hello",
)
-
my_aspect
允许分析cc_binary
目标的输入文件,而不修改cc_binary
规则。
官方文档:
Bazel Aspects
7. Repository(外部仓库)
Repository(仓库) 是 Bazel 外部依赖管理的机制,用于拉取和管理外部代码库(如第三方库、工具链等)。
Bazel 支持多种类型的仓库,包括:
-
http_archive
(下载 tar/zip 并解压) -
git_repository
(从 Git 拉取) -
local_repository
(使用本地路径) -
new_local_repository
(定义新的本地仓库)
示例
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")http_archive(name = "rules_vcc",url = "https://example.com/rules_vcc.tar.gz",sha256 = "abc123...",strip_prefix = "rules_vcc-main",
)
-
@rules_vcc
就是一个 外部仓库,可用于load("@rules_vcc//...")
。
官方文档:
Bazel External Repositories
8. Package(包)
Package(包) 是 Bazel 代码的组织单元,即一个 BUILD
文件及其所在目录。
-
一个 Bazel 工作区(workspace)可以有多个 package。
-
每个 package 都有一个
BUILD
文件,用于定义规则和目标。
示例
/workspace_root/WORKSPACE/src/BUILD # 这是一个 packagemain.cc/lib/BUILD # 这是另一个 packagelib.cc
-
src/
和src/lib/
都是 package,因为它们各自有BUILD
文件。
官方文档:
Bazel Packages
9. Workspace(工作区)
Workspace(工作区) 是 Bazel 项目的根目录,由 WORKSPACE
文件定义。
-
所有 Bazel 构建都发生在某个工作区中。
-
WORKSPACE
文件 用于声明外部依赖,如http_archive()
、git_repository()
等。
示例
/my_project/WORKSPACE # 定义 Bazel 工作区/src/BUILDmain.cc/third_party/BUILD
-
my_project/
是 Bazel 工作区,因为它有WORKSPACE
文件。
官方文档:
Bazel Workspaces
10. Configuration(构建配置)
Configuration(构建配置) 指的是 Bazel 对构建参数的管理,如:
-
CPU/架构 (
--cpu=x86_64
) -
编译模式 (
--compilation_mode=opt/debug
) -
工具链选择 (
--host_crosstool_top=@bazel_tools//tools/cpp:toolchain
)
示例
bazel build //src:main --cpu=arm64 --compilation_mode=opt
-
--cpu=arm64
选择 ARM64 架构 -
--compilation_mode=opt
进行优化编译
官方文档:
Bazel Configurations
11. Build Event Protocol(构建事件协议, BEP)
BEP 用于 跟踪和分析 Bazel 构建过程,常用于 CI/CD 系统集成。
BEP 可以输出 构建日志、失败原因、性能数据等,并提供 JSON 或 Proto 格式。
示例
bazel build //src:main --build_event_json_file=build_events.json
-
生成
build_events.json
,可用于分析构建信息。
官方文档:
Bazel Build Event Protocol
12. Starlark(Bazel 语言)
Starlark 是 Bazel 的 配置语言,基于 Python 语法但有严格限制:
-
无副作用(不能修改全局变量)
-
无 I/O 操作(不能读写文件)
-
只能调用
ctx.actions
进行构建
示例
def _my_rule_impl(ctx):output = ctx.actions.declare_file(ctx.label.name + ".txt")ctx.actions.write(output, "Hello, Bazel!")return [DefaultInfo(files = depset([output]))]my_rule = rule(implementation = _my_rule_impl)
官方文档:
Bazel Starlark
13. Transition(配置转换)
Transition(配置转换) 允许修改构建配置,比如 改变目标平台或优化级别。
示例
def _my_transition_impl(settings, attr):return {"//command_line_option:cpu": "arm64"}my_transition = transition(implementation = _my_transition_impl,inputs = [],outputs = ["//command_line_option:cpu"],
)
-
默认情况下,Bazel 规则会继承全局构建配置。
-
使用
transition
可以修改某些规则的配置,如强制某些目标在 ARM64 上构建。
官方文档:
Bazel Transitions
14. Action(构建动作)
Action(构建动作) 是 Bazel 执行构建的最小单位,如:
-
编译(gcc、clang)
-
链接(ld)
-
拷贝文件
-
执行 Shell 脚本
每个 rule 由 多个 action 组成。
示例
def _my_rule_impl(ctx):output = ctx.actions.declare_file("output.txt")ctx.actions.run_shell(outputs = [output],command = "echo Hello > " + output.path,)return [DefaultInfo(files = depset([output]))]
-
ctx.actions.run_shell()
定义了一个 Action,用于执行 shell 命令。
官方文档:
Bazel Actions