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

如何通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:02:35