Bazel中的Symbol, Rule, Macro, Target, Provider, Aspect 等概念

发布于:2025-04-06 ⋅ 阅读:(24) ⋅ 点赞:(0)

学习Bazel ,就要学习Bazel 的规则定义, 弄清各个概念是重要的一个步骤。 在 Bazel 规则定义中,SymbolRuleMacro 是常见的概念。除此之外,Bazel 还有 TargetProviderAspect Repository、Package、 Workspace、 Configuration、Build Event Protocol、 Starlark、Transition、Action 等重要概念。

概念 类别 作用
Symbol(符号) 基础概念 Bazel 规则、目标、属性等命名的标识符。
Rule(规则) 规则 定义 Bazel 构建逻辑,如 cc_librarypy_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_packagepy_wheel 就是 packaging.bzl 文件中定义的 symbols

  • symbols 可以是宏(macro)规则(rule),或者普通的 函数/变量


2. Rule(规则)

Bazel rule(规则) 是 Bazel 构建系统的核心,用于定义如何构建目标(target)

特性:

  • 规则(rules)是 Starlark 代码,它们通常由 native.rule() 定义。

  • 每个规则都能创建一个或多个 targets(构建目标),并由 Bazel 执行。

  • 规则可以使用 providers 来定义输入/输出关系。

规则示例

Bazel 内置了一些规则,比如 cc_binarypy_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):
    # 规则的核心逻辑 
    pass

my_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         # 这是一个 package
    main.cc
    /lib/
      BUILD       # 这是另一个 package
      lib.cc

 

  • src/src/lib/ 都是 package,因为它们各自有 BUILD 文件。

官方文档:
Bazel Packages


9. Workspace(工作区)

Workspace(工作区)Bazel 项目的根目录,由 WORKSPACE 文件定义。

  • 所有 Bazel 构建都发生在某个工作区中

  • WORKSPACE 文件 用于声明外部依赖,如 http_archive()git_repository() 等。

示例

/my_project/
  WORKSPACE        # 定义 Bazel 工作区
  /src/
    BUILD
    main.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