Bazel中定义依赖关系

Bazel 中,明确地定义依赖关系是构建系统成功的关键,这也正是它高效、可重复、可缓存的原因之一。Bazel 永远不会猜测构建顺序,而是根据你定义的依赖图来调度每一个构建动作。 可以把 Bazel 理解为一个大型的 “声明式有向图构建器”,每一个节点(rule)都要告诉 Bazel:“我需要哪些前置节点”,它才能高效调度和增量构建。

下面系统性地总结一下Bazel中定义依赖关系的方式,理解这些依赖的写法,基本就掌握了Bazel构建图的构造方式。

Bazel 中的依赖关系类型

可以从 3 个层次来看:

1. 规则(Rule)中内建属性来定义依赖

  • 适用于常见规则如 cc_binary, py_library, genrule, filegroup 等。

  • 常用字段有:

字段名作用用途示例
srcs源文件或源规则通常指源码或生成文件的依赖
deps其他规则的依赖(编译时链接)通常用于编译依赖
data运行时需要的文件用于测试或 runtime 资源
hdrsC/C++ 的头文件依赖指定需要包含的头文件
toolsgenrule 或 action 的工具依赖用于生成过程调用的工具
outs声明的输出文件其他规则可以依赖这些输出

✅ 示例 1:cc_binary 依赖 cc_library

cc_library(
    name = "util_lib",
    srcs = ["util.cc"],
    hdrs = ["util.h"],
)

cc_binary(
    name = "main_app",
    srcs = ["main.cc"],
    deps = [":util_lib"],
)

 

👉 main_app 编译时会用到 util_lib 提供的源码和头文件。


✅ 示例 2:使用 genrule 生成文件并被其他规则依赖

genrule(
    name = "generate_config",
    outs = ["config.txt"],
    cmd = "echo 'config=1' > $@",
)

filegroup(
    name = "generated_files",
    srcs = [":generate_config"],
)

sh_binary(
    name = "my_script",
    srcs = ["main.sh"],
    data = [":generated_files"],  # 运行时依赖
)

 

👉 my_script 在运行时能访问 config.txt


✅ 示例 3:使用 tools 字段

genrule(
    name = "generate_data",
    outs = ["data.txt"],
    tools = ["//tools:my_tool"],
    cmd = "$(location //tools:my_tool) > $@",
)

 

👉 Bazel 会自动确保 my_tool 被构建出来,并传递其路径到 $@


2. macro 中连接规则依赖

宏(macro)是生成规则的函数,要手动连接规则之间的依赖。

✅ 示例 4:Macro 中手动指定依赖顺序

def my_pipeline(name):
    native.genrule(
        name = name + "_step1",
        outs = ["out1.txt"],
        cmd = "echo step1 > $@",
    )

    native.genrule(
        name = name + "_step2",
        srcs = [":" + name + "_step1"],
        outs = ["out2.txt"],
        cmd = "cat $(SRCS) > $@ && echo step2 >> $@",
    )

 

使用:

load("//build_defs:my_macros.bzl", "my_pipeline")

my_pipeline(name = "build_data")

 

👉 step2 明确依赖 step1 的输出。


3. Starlark 自定义规则中显式声明依赖(高级用法)

如果你自定义 rule(),你需要在 attrs 里声明依赖字段,在 implementation 中使用依赖内容。

✅ 示例 5:自定义 rule 使用 deps

def _my_rule_impl(ctx):
    for dep in ctx.attr.deps:
        print(dep.label)
    return []

my_rule = rule(
    implementation = _my_rule_impl,
    attrs = {
        "deps": attr.label_list(),
    }
)

 

BUILD 文件中用法:

my_rule(
    name = "hello",
    deps = ["//lib:foo", "//lib:bar"],
)

 

👉 这允许你在规则实现中读取依赖规则的信息(如文件、标签等)。


📦 额外的依赖类型和技巧

label_list / label 的其他字段定义依赖

例如你可以在自定义规则中定义:

attrs = {
    "srcs": attr.label_list(allow_files = True),
    "hdrs": attr.label_list(allow_files = True),
    "tools": attr.label_list(cfg = "exec"),
}

 

  • allow_files = True 表示可以接受文件依赖

  • cfg = "exec" 表示运行在执行环境(比如用作生成工具)


filegroup 用于聚合文件或规则

filegroup(
    name = "all_headers",
    srcs = glob(["*.h"]),
)

cc_library(
    name = "lib_with_headers",
    hdrs = [":all_headers"],
    srcs = ["main.cc"],
)

总结:Bazel 中定义依赖的方式

场景写法用途说明
编译依赖deps = [":other_rule"]C/C++、Python、Java 等代码依赖
文件依赖srcs = [...], hdrs = [...]源文件或头文件
运行时依赖data = [...]测试或脚本运行依赖文件
工具依赖tools = [...]生成器工具,如代码生成器
宏中依赖srcs = [":prev_rule"]宏中手动指定依赖顺序
自定义规则中依赖attrs = { "deps": attr.label_list() }高级场景:Starlark rule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值