使用java_common.compile生成声明文件目录遇空目录问题咨询
问题解答:Bazel java_common.compile 注解处理器输出路径问题
我来帮你拆解这个问题,先从annotation_processor_additional_outputs的工作机制说起,再给出具体的解决方法。
一、annotation_processor_additional_outputs的工作机制
Bazel的java_common.compile在处理注解处理器时,有一套严格的构建隔离逻辑:
- 它会自动将注解处理器生成的所有文件(包括Java源码和非Java资源)收集到一个专属的隔离目录(格式通常是
bazel-out/[config]/bin/[package]/_javac/[target]/[target]-placeholder_sourcegenfiles/),最终还会把这些文件打包成[target]-placeholder-gensrc.jar。 annotation_processor_additional_outputs的作用只是告诉Bazel:"除了常规的生成源码,还有这些额外文件是构建输出的一部分,需要被追踪和缓存"。但它不会改变注解处理器的输出路径——Bazel依然会强制把处理器生成的文件放到它管控的隔离目录里,而不是你通过-AoutputDir指定的路径。
这种设计是为了保证构建的可重复性、缓存有效性,避免不同目标的输出互相污染。
二、如何让输出直接写入指定的output_dir
因为Bazel的管控逻辑,我们无法让注解处理器直接把文件写到你声明的output_dir,但可以通过"生成后复制"的方式实现需求。具体步骤如下:
方案1:从隔离目录复制输出文件
调整你的规则实现,先让注解处理器把文件生成到一个相对路径(比如uniqueOutputDir),再通过Bazel的copy_directory动作把隔离目录里的内容复制到目标output_dir:
def _impl(ctx): # 声明最终的输出目录 output_dir = ctx.actions.declare_directory("uniqueOutputDir") # 调用java_common.compile执行注解处理器,指定输出到相对路径uniqueOutputDir java_common.compile( ctx, sources = ctx.files.srcs, output = ctx.label.name + "-placeholder.jar", javac_opts = [ "-proc:only", # 这里用相对路径,Bazel会把它映射到隔离的sourcegenfiles目录下 "-AoutputDir=uniqueOutputDir", ], plugins = [ctx.attr._emitter[JavaInfo]], ) # 定位到Bazel管控的隔离目录(包含处理器生成的uniqueOutputDir) sourcegen_subdir = ctx.actions.declare_directory( "{}-placeholder_sourcegenfiles/uniqueOutputDir".format(ctx.label.name) ) # 把隔离目录里的内容复制到最终的output_dir ctx.actions.copy_directory( output = output_dir, source = sourcegen_subdir, ) return DefaultInfo(files = depset([output_dir]))
方案2:从gensrc jar中提取文件
如果处理器的输出被打包到了gensrc.jar,也可以通过解压jar的方式提取内容到目标目录:
def _impl(ctx): output_dir = ctx.actions.declare_directory("uniqueOutputDir") # 声明gensrc jar的输出文件 gensrc_jar = ctx.actions.declare_file(ctx.label.name + "-placeholder-gensrc.jar") java_common.compile( ctx, sources = ctx.files.srcs, output = ctx.label.name + "-placeholder.jar", javac_opts = [ "-proc:only", "-AoutputDir=uniqueOutputDir", ], plugins = [ctx.attr._emitter[JavaInfo]], # 指定生成的source jar路径 generated_source_jars = [gensrc_jar], ) # 解压jar并将内容移动到目标目录 ctx.actions.run_shell( inputs = [gensrc_jar], outputs = [output_dir], command = """ # 临时解压目录 TMP_DIR=$(mktemp -d) unzip -q {jar_path} -d $TMP_DIR # 将uniqueOutputDir的内容复制到目标目录 cp -r $TMP_DIR/uniqueOutputDir/* {output_path} rm -rf $TMP_DIR """.format( jar_path = gensrc_jar.path, output_path = output_dir.path, ), ) return DefaultInfo(files = depset([output_dir]))
关键注意点
- 尽量让注解处理器接受相对路径作为输出目录参数,这样Bazel可以正确追踪生成的文件;如果处理器只能写绝对路径,你可能需要修改处理器逻辑,或者在Bazel中传递沙盒内的相对路径。
- 不要依赖硬编码的隔离目录路径(比如
darwin-fastbuild),尽量用ctx.label.name、ctx.genfiles_dir等Bazel内置变量来动态拼接路径,保证跨平台和配置的兼容性。
内容的提问来源于stack exchange,提问作者beasleyr-vmw
相关产品推荐
相关产品推荐

