學習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