为何构建foo3时Bazel规则仅生成foo3文件而非预期三个文件?
问题
我编写了用于增量测试的Bazel规则foo_binary,规则逻辑如下:
- 无依赖时,生成以自身名称命名的文件,内容为自身名称;
- 存在依赖时,生成以自身名称命名的文件,内容为依赖目标生成文件的内容加上自身名称。
测试时,foo3、foo2、foo1构成依赖链,构建foo3时预期生成foo1、foo2、foo3三个文件,但实际仅生成了foo3文件。
以下是测试用Bazel代码、构建命令及日志:
规则实现代码
# ~/rules/dev.bzl def _foo_binary_impl(ctx): this_name = ctx.attr.name file_name = ctx.actions.declare_file(ctx.label.name) print("##-000 this_name: {}".format(this_name)) print("##-001 file_name: {}".format(file_name)) file_content = "" if ctx.attr.deps: for dep in ctx.attr.deps: t1 = dep[DefaultInfo].files.to_list()[0].basename t1 = t1 + this_name print("##-100 t1: {}".format(t1)) file_content = t1 else: t2 = this_name print("##-101 t2: {}".format(t2)) file_content = t2 ctx.actions.write( output = file_name, content = file_content, ) return [ DefaultInfo( files = depset([file_name]) ), ] foo_binary = rule( implementation = _foo_binary_impl, attrs = { "deps": attr.label_list(), }, )
构建命令及日志
$> bazel build -s //rules/example:foo3 1 х 11:38:08 DEBUG: ~/rules/dev.bzl:10:10: ##-000 this_name: foo1 DEBUG: ~/rules/dev.bzl:11:10: ##-001 file_name: <generated file rules/example/foo1> DEBUG: ~/rules/dev.bzl:25:14: ##-101 t2: foo1 DEBUG: ~/rules/dev.bzl:10:10: ##-000 this_name: foo2 DEBUG: ~/rules/dev.bzl:11:10: ##-001 file_name: <generated file rules/example/foo2> DEBUG: ~/rules/dev.bzl:19:18: ##-100 t1: foo1foo2 DEBUG: ~/rules/dev.bzl:10:10: ##-000 this_name: foo3 DEBUG: ~/rules/dev.bzl:11:10: ##-001 file_name: <generated file rules/example/foo3> DEBUG: ~/rules/dev.bzl:19:18: ##-100 t1: foo2foo3 INFO: Analyzed target //rules/example:foo3 (3 packages loaded, 8 targets configured). INFO: Found 1 target... Target //rules/example:foo3 up-to-date: bazel-bin/rules/example/foo3 INFO: Elapsed time: 0.107s, Critical Path: 0.00s INFO: 2 processes: 2 internal. INFO: Build completed successfully, 2 total actions
问题原因及解决方案
核心问题
- Bazel输出机制限制:Bazel默认仅输出构建目标直接关联的产物,依赖目标的产物不会自动被复制到输出目录。日志中能看到
foo1、foo2的逻辑已执行,但它们的产物属于依赖目标的输出,不会被包含在foo3的输出结果里。 - 内容读取逻辑错误:当前代码仅取了依赖文件的
basename(文件名),而非文件的实际内容,不符合你预期的“依赖目标生成文件的内容加上自身名称”逻辑。
修复代码
# ~/rules/dev.bzl def _foo_binary_impl(ctx): this_name = ctx.attr.name file_name = ctx.actions.declare_file(ctx.label.name) print("##-000 this_name: {}".format(this_name)) print("##-001 file_name: {}".format(file_name)) file_content = "" if ctx.attr.deps: dep_contents = [] for dep in ctx.attr.deps: dep_file = dep[DefaultInfo].files.to_list()[0] # 读取依赖文件的实际内容,Bazel会自动处理依赖关系 dep_contents.append(dep_file.read()) print("##-100 dep content: {}".format(dep_contents[-1])) # 拼接所有依赖内容+自身名称 file_content = "".join(dep_contents) + this_name else: file_content = this_name print("##-101 content: {}".format(file_content)) ctx.actions.write( output = file_name, content = file_content, ) # 收集当前目标+所有依赖的产物,让Bazel输出这些文件 all_files = [file_name] for dep in ctx.attr.deps: all_files.extend(dep[DefaultInfo].files.to_list()) return [ DefaultInfo( files = depset(all_files), runfiles = ctx.runfiles(files=all_files) ), ] foo_binary = rule( implementation = _foo_binary_impl, attrs = { "deps": attr.label_list(), }, )
验证效果
重新执行bazel build //rules/example:foo3后,bazel-bin/rules/example/目录下会同时出现foo1、foo2、foo3三个文件,且foo3的内容为foo1foo2foo3,完全符合预期逻辑。
内容的提问来源于Stack Exchange,提问作者Grrrr
相关产品推荐
相关产品推荐

