在Bazel规则中同时声明目录与内部文件的解决方案咨询
需求:编写一个Bazel规则,该规则需创建目录、传入若干文件并生成ISO镜像(ISO为预期输出,其余文件为副产品)。
用户实现的代码片段:
# Declare root directory root_directory = ctx.actions.declare_directory("root_directory") # Call mkdir to create root directory create_root_directory_arguments = ctx.actions.args() create_root_directory_arguments.add(root_directory.path) ctx.actions.run( outputs = [root_directory], arguments = [create_root_directory_arguments], executable = "mkdir", ) ... # Declare and collect inner files copy_output_files = [] for image_file in image_files: copy_output_file = ctx.actions.declare_file(image_file_path) copy_output_files.append(copy_output_file) # Call cp to copy the inner files into the root directory copy_arguments = ctx.actions.args() copy_arguments.add("-r") copy_arguments.add("-t", root_directory.path) for image_file in image_files: copy_arguments.add(image_file.path) ctx.actions.run( inputs = [root_directory], outputs = copy_output_files, arguments = [copy_arguments], executable = "cp", ) ...
用户遇到的问题:当声明目录abc后,无法声明该目录下的文件abc/def,会抛出异常。咨询正确的解决方式:是否只需声明目录或仅声明文件?如何在不声明的情况下获取run调用所需的File对象?
核心原则
Bazel不允许同时声明一个目录和该目录下的具体文件,这是构建系统的一致性约束——要么声明整个目录作为输出,要么声明目录下的所有文件,但不能混合使用。针对你的场景,只需要声明顶层目录作为输出即可,不需要单独声明目录内的子文件。
具体调整步骤
移除子文件的单独声明
删除代码中声明copy_output_files的逻辑,因为这些文件属于已声明的root_directory的一部分,不需要单独注册。修改复制文件的动作配置
将复制动作的outputs改为整个根目录,同时把要复制的源文件加入inputs列表:# 移除原有的copy_output_files声明代码 copy_arguments = ctx.actions.args() copy_arguments.add("-r") copy_arguments.add("-t", root_directory.path) copy_arguments.add_all(image_files) # 用add_all简化循环添加 ctx.actions.run( inputs = image_files + [root_directory], outputs = [root_directory], arguments = [copy_arguments], executable = "cp", )这样Bazel会追踪整个根目录的内容变化,自动处理目录内的所有文件。
生成ISO的动作处理
后续生成ISO时,直接将root_directory作为输入传给ISO生成工具(如genisoimage)即可。最终的ISO文件用ctx.actions.declare_file声明为规则的主要输出,根目录作为中间副产品,Bazel会自动管理其生命周期。关于目录内文件的引用
如果后续动作需要引用目录内的某个特定文件(比如root_directory/def),不需要用ctx.actions.declare_file声明它,直接通过root_directory.path + "/def"拼接路径即可。只要确保整个根目录是该动作的输入,Bazel就会保证文件存在且内容最新。
内容的提问来源于stack exchange,提问作者Omer Lubin

