如何在Bazel不同测试目标间共享产物并保留增量构建优势
解决方案
核心思路是不需要强行打破Bazel沙箱,只要按照Bazel的构建规范显式声明产物依赖,即可实现跨目标的产物共享,同时完整保留增量构建、缓存复用的所有特性。
步骤1:拆分Python侧产物生成逻辑
不要将产物生成逻辑耦合在py_test中:Bazel的测试目标默认不会对外暴露输出产物,也不会针对产物做增量追踪。你可以将生成产物的逻辑抽离为独立的genrule规则,示例python/BUILD配置如下:
# python/BUILD # 独立产物生成规则,专门输出你需要的测试用二进制文件 genrule( name = "test_artifacts", # 生成产物需要的所有源文件、依赖脚本 srcs = ["foo.py"], # 声明生成的产物文件名,可声明多个 outs = ["foo_generated_bin"], # 生成命令,$(location X) 会自动替换为对应文件的沙箱内路径,$@ 对应输出产物路径 cmd = "$(location generate_bin.py) --output_path $@", # 生成过程用到的可执行工具 tools = ["generate_bin.py"], ) # 原有py_test,直接依赖上方生成的产物即可,无需自己重新生成 py_test( name = "test_foo", srcs = ["test_foo.py"], # 将生成的产物作为数据依赖传入测试 data = [":test_artifacts"], # 保留你原有的其他配置,比如deps、env等 )
如果你不想额外拆分脚本,可以修改原有test_foo.py支持双运行模式:传入输出路径参数时仅生成产物退出,无参数时执行测试逻辑,这样genrule调用时传参数,py_test调用时不传参数即可。
步骤2:C++测试声明依赖
在cpp/BUILD的cc_test中直接显式声明对Python侧产物生成规则的依赖即可,Bazel会自动处理构建顺序:产物过时则先执行生成逻辑,产物无变化则直接复用缓存,完全符合增量构建要求。
示例cpp/BUILD配置如下:
# cpp/BUILD cc_test( name = "test_foo", srcs = ["foo.cpp", "test_foo.cpp"], # 依赖Python侧生成的测试产物 data = ["//python:test_artifacts"], # 保留你原有的其他配置,比如deps、copts、linkopts等 )
特殊场景替代方案(不推荐)
如果你确实无法拆分产物生成逻辑,必须要跑完py_test才能生成产物,可以使用declared_outputs参数显式声明测试目标的输出产物:
# python/BUILD 中的py_test配置 py_test( name = "test_foo", srcs = ["test_foo.py"], # 显式声明测试运行后会输出的产物 declared_outputs = ["foo_generated_bin"], # 其他原有配置 )
此时C++测试直接依赖//python:test_foo即可,但该方案存在缺陷:只要Python测试的任何依赖发生变化,哪怕不影响产物生成,也会重新运行整个Python测试,增量构建效率远低于拆分genrule的方案。
内容的提问来源于stack exchange,提问作者falsekeel
相关产品推荐
相关产品推荐

