如何通过Bazel批量从.idl文件生成C/C++相关头文件?
用Bazel批量处理IDL文件生成C/C++头文件
完全可以通过Bazel实现批量处理目录下的所有.idl文件并生成对应头文件,下面提供两种可行方案,解决你卡在输出列表生成的问题:
方案一:自定义Bazel规则(推荐,可维护性更高)
这种方式通过编写自定义.bzl规则,自动为每个IDL文件映射对应的4种输出文件,避免手动维护庞大的输出列表。
1. 创建自定义规则文件(idl_rules.bzl)
def _idl_to_headers_impl(ctx): outputs = [] # 遍历所有输入IDL文件 for idl_file in ctx.files.srcs: base_name = idl_file.basename.split(".")[0] # 声明四种输出文件 c_header = ctx.actions.declare_file(base_name + ".h") cpp_header = ctx.actions.declare_file(base_name + ".hpp") c_skel_header = ctx.actions.declare_file(base_name + "_skel.h") cpp_skel_header = ctx.actions.declare_file(base_name + "_skel.hpp") outputs.extend([c_header, cpp_header, c_skel_header, cpp_skel_header]) # 执行生成C头文件的命令 ctx.actions.run_shell( inputs = [idl_file], outputs = [c_header], command = "{tool} {idl} -o {out}".format( tool = ctx.executable.custom_tool.path, idl = idl_file.path, out = c_header.path, ), ) # 生成C++头文件 ctx.actions.run_shell( inputs = [idl_file], outputs = [cpp_header], command = "{tool} {idl} -o {out} --cpp".format( tool = ctx.executable.custom_tool.path, idl = idl_file.path, out = cpp_header.path, ), ) # 生成C骨架头文件 ctx.actions.run_shell( inputs = [idl_file], outputs = [c_skel_header], command = "{tool} {idl} -o {out} --skel".format( tool = ctx.executable.custom_tool.path, idl = idl_file.path, out = c_skel_header.path, ), ) # 生成C++骨架头文件 ctx.actions.run_shell( inputs = [idl_file], outputs = [cpp_skel_header], command = "{tool} {idl} -o {out} --cpp --skel".format( tool = ctx.executable.custom_tool.path, idl = idl_file.path, out = cpp_skel_header.path, ), ) return [DefaultInfo(files = depset(outputs))] idl_to_headers = rule( implementation = _idl_to_headers_impl, attrs = { "srcs": attr.label_list(allow_files = [".idl"]), "custom_tool": attr.label( executable = True, cfg = "exec", allow_files = True, ), }, )
2. 在BUILD文件中使用规则
# 加载自定义规则 load(":idl_rules.bzl", "idl_to_headers") # 声明你的custom_tool(如果是源码编译用cc_binary,预编译用filegroup) cc_binary( name = "custom_tool", srcs = ["custom_tool.cc"], # 替换为你的工具源码路径 ) # 批量处理所有IDL文件 idl_to_headers( name = "generated_idl_headers", srcs = glob(["*.idl"]), # 匹配当前目录所有.idl文件,可调整路径如"src/**/*.idl" custom_tool = ":custom_tool", ) # 可选:将生成的头文件打包为filegroup,方便其他目标依赖 filegroup( name = "idl_headers", srcs = [":generated_idl_headers"], visibility = ["//visibility:public"], )
方案二:使用genrule(快速实现)
如果不想写自定义规则,也可以通过genrule结合列表推导生成完整的输出文件列表:
# 匹配所有IDL文件 IDL_FILES = glob(["*.idl"]) # 自动生成所有输出文件路径 GENERATED_HEADERS = ( [f.replace(".idl", ".h") for f in IDL_FILES] + [f.replace(".idl", ".hpp") for f in IDL_FILES] + [f.replace(".idl", "_skel.h") for f in IDL_FILES] + [f.replace(".idl", "_skel.hpp") for f in IDL_FILES] ) genrule( name = "generate_idl_headers", srcs = IDL_FILES, outs = GENERATED_HEADERS, tools = [":custom_tool"], cmd = """ TOOL=$(location :custom_tool) for idl in $(SRCS); do BASE_NAME=$(basename "$$idl" .idl) # 生成C头文件 $$TOOL "$$idl" -o "$(@D)/$$BASE_NAME.h" # 生成C++头文件 $$TOOL "$$idl" -o "$(@D)/$$BASE_NAME.hpp" --cpp # 生成C骨架头文件 $$TOOL "$$idl" -o "$(@D)/$$BASE_NAME_skel.h" --skel # 生成C++骨架头文件 $$TOOL "$$idl" -o "$(@D)/$$BASE_NAME_skel.hpp" --cpp --skel done """, )
注意事项
- 确保
custom_tool在Bazel中正确声明:如果是预编译的二进制文件,用filegroup并设置srcs为工具路径;如果是源码编译,用cc_binary。 - 生成的头文件会存放在Bazel的输出目录(如
bazel-bin),不会提交到代码仓库,只需确保.gitignore包含Bazel的输出目录(通常是bazel-*)。 - 自定义规则方案更适合长期维护:后续新增输出类型时,只需修改规则实现,无需手动更新输出列表。
内容的提问来源于stack exchange,提问作者nhaas
相关产品推荐
相关产品推荐

