You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 11:52:53