
Bazel 的 Java 规则不支持目录型(tree)输出,导致 java_library 无法识别通过 declare_directory 生成的源文件;正确做法是将生成的 Java 文件打包为 .srcjar 格式的源码 ZIP 归档,Java 规则即可自动编译其中的 .java 文件。
在 bazel 中构建 java 库时,若源文件由自定义规则动态生成,需特别注意 java 原生规则对输入格式的严格限制:它们不支持目录型(tree)artifact,而仅识别常规文件(如 `.java`)或符合规范的源码归档(`.srcjar`)。直接将 `declare_directory` 输出传给 `java_library.srcs` 将导致静默失败——jar 中仅含 manifest,无任何编译类。
要解决该问题,关键在于将生成的 Java 源文件打包为 .srcjar。.srcjar 本质是一个 ZIP 文件,扩展名必须为 .srcjar(而非 .zip),且内部路径结构应与 Java 包声明一致(例如 com/example/Foo.java 对应包 com.example)。Bazel 的 java_library 会自动解压并编译其中所有 .java 文件。
以下是修改后的完整实现方案:
✅ 步骤 1:更新生成规则,输出 .srcjar
def _generator_java_impl(ctx):
# 声明输出目录(仍用于中间生成)
tree = ctx.actions.declare_directory(ctx.attr.name + "_srcs")
# 执行生成逻辑(保持不变)
ctx.actions.run(
inputs = ctx.attr._tools, # 示例:工具依赖
outputs = [tree],
executable = ctx.executable._generator,
arguments = ["--output", tree.path],
mnemonic = "JavaGenerator",
)
# 新增:创建 .srcjar 归档
srcjar = ctx.actions.declare_file(ctx.attr.name + ".srcjar")
ctx.actions.run(
inputs = [tree],
outputs = [srcjar],
executable = ctx.executable._zipper,
arguments = [
"c", srcjar.path, # 'c' 表示 create
"-C", tree.path, ".", # 将 tree 下所有内容打包
],
mnemonic = "SrcJarPack",
)
return [DefaultInfo(files = depset([srcjar]))]
generator_java = rule(
implementation = _generator_java_impl,
attrs = {
"_zipper": attr.label(
default = Label("@bazel_tools//tools/zip:zipper"),
cfg = "exec",
executable = True,
),
# 其他属性...
},
output_to_genfiles = True,
)
? 提示:Bazel 内置
@bazel_tools//tools/zip:zipper是轻量、确定性高的 ZIP 工具,推荐用于.srcjar打包;避免使用系统zip命令以确保可重现性。
✅ 步骤 2:在 BUILD 文件中引用 .srcjar
generator_java(
name = "generated_java",
# ... 其他参数
)
java_library(
name = "mylib",
srcs = [":generated_java"], # ✅ 现在指向 .srcjar 文件
# 可选:添加 deps(如生成代码依赖的其他库)
# deps = ["//some/dep"],
)
⚠️ 注意事项
-
扩展名必须为
.srcjar:即使内容是合法 ZIP,若命名为generated.zip,Bazel 将忽略它。 -
路径一致性:
.srcjar内部的 Java 文件路径需与package声明匹配,否则编译报错(如package com.example;要求文件位于com/example/Foo.java)。 -
增量构建友好:
.srcjar是普通文件 artifact,Bazel 能正确追踪其变更,触发精准重编译。 -
调试技巧:运行
bazel build //:generated_java && unzip -l bazel-bin/generated_java.srcjar验证归档内容是否正确。
通过此方式,你既能保留灵活的代码生成逻辑,又能无缝集成到 Bazel 的 Java 编译流水线中——生成即编译,零配置、高可靠。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











