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

Bazel构建时如何解析配置文件生成多语言常量并依赖构建产物

解决方法

整体逻辑

完全可以实现类似Protobuf的使用体验,核心是自定义Bazel规则:将YAML常量文件作为输入,构建阶段调用你写的Python转换脚本,生成对应语言的常量代码文件,业务代码直接依赖生成的规则目标即可,无需在运行时处理YAML。

具体实现步骤

步骤1:编写Python转换脚本

写一个通用转换工具,接收三个入参:输入YAML路径、目标语言、输出文件路径,你可以根据需要扩展支持的语言。示例代码如下:

# yaml_to_const.py
import yaml
import sys
import json

def generate_ts(data, output_path):
    # 生成符合要求的TS代码
    content = f"export default {json.dumps(data, indent=2)}"
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(content)

def generate_py(data, output_path):
    # 生成Python常量代码
    content = ""
    for k, v in data.items():
        content += f"{k.upper()} = {repr(v)}\n"
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(content)

def generate_rs(data, output_path):
    # 生成Rust常量代码,可根据需要调整为struct或者独立const
    content = "use serde::Serialize;\n\n"
    content += "#[derive(Debug, Serialize)]\n"
    content += "pub const CONSTS: &str = r#\"" + json.dumps(data) + "\"#;\n"
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(content)

def main():
    input_path = sys.argv[1]
    lang = sys.argv[2]
    output_path = sys.argv[3]
    with open(input_path, encoding="utf-8") as f:
        data = yaml.safe_load(f)
    if lang == "ts":
        generate_ts(data, output_path)
    elif lang == "py":
        generate_py(data, output_path)
    elif lang == "rs":
        generate_rs(data, output_path)
    else:
        raise ValueError(f"Unsupported language {lang}")

if __name__ == "__main__":
    main()

步骤2:自定义Bazel规则

在项目中新建yaml_const.bzl文件,定义构建规则,将转换脚本和YAML输入关联,生成各语言可识别的依赖目标:

load("@rules_ts//ts:defs.bzl", "TsInfo")
load("@rules_python//python:defs.bzl", "PyInfo")
load("@rules_rust//rust:providers.bzl", "RustLibraryInfo")

def _yaml_const_impl(ctx):
    # 生成TS输出
    ts_out = ctx.actions.declare_file(ctx.attr.name + ".ts")
    ctx.actions.run(
        inputs = [ctx.file.src],
        outputs = [ts_out],
        executable = ctx.executable._converter,
        args = [ctx.file.src.path, "ts", ts_out.path],
    )
    # 生成Python输出
    py_out = ctx.actions.declare_file(ctx.attr.name + ".py")
    ctx.actions.run(
        inputs = [ctx.file.src],
        outputs = [py_out],
        executable = ctx.executable._converter,
        args = [ctx.file.src.path, "py", py_out.path],
    )
    # 生成Rust输出
    rs_out = ctx.actions.declare_file(ctx.attr.name + ".rs")
    ctx.actions.run(
        inputs = [ctx.file.src],
        outputs = [rs_out],
        executable = ctx.executable._converter,
        args = [ctx.file.src.path, "rs", rs_out.path],
    )
    # 返回各语言对应的Provider,让业务目标可以识别依赖
    return [
        TsInfo(transitive_sources = depset([ts_out])),
        PyInfo(transitive_sources = depset([py_out])),
        RustLibraryInfo(crate_root = rs_out, srcs = depset([rs_out])),
    ]

yaml_const = rule(
    implementation = _yaml_const_impl,
    attrs = {
        "src": attr.label(allow_single_file = [".yaml", ".yml"], mandatory = True),
        "_converter": attr.label(
            default = "//path/to:yaml_to_const",
            executable = True,
            cfg = "exec",
        ),
    },
)

同时要在转换脚本所在目录的BUILD文件中,把Python脚本声明为可执行目标:

py_binary(
    name = "yaml_to_const",
    srcs = ["yaml_to_const.py"],
    deps = ["@pypi//pyyaml"],
    visibility = ["//visibility:public"],
)

步骤3:业务代码使用

在常量YAML所在目录的BUILD文件中定义规则目标:

load("//path/to:yaml_const.bzl", "yaml_const")

yaml_const(
    name = "app_const",
    src = "consts.yaml",
    visibility = ["//visibility:public"],
)

各语言业务代码直接依赖这个目标即可:

  • TypeScript代码:在ts_library的deps中加入//path/to:app_const,直接import consts from './app_const'使用
  • Python代码:在py_library的deps中加入//path/to:app_const,直接from path.to.app_const import ITEM1使用
  • Rust代码:在rust_library的deps中加入//path/to:app_const,直接引入使用

替代方案(更省心)

如果你可以接受替换文件格式,直接用Protobuf定义常量是更稳定的方案:

  • 把常量定义在proto文件中,使用固定值字段或者常量配置
  • 直接用Bazel原生的proto规则 + 各语言的protoc插件生成代码
  • 不用自己写转换脚本和自定义规则,生态支持更完善,还天然支持类型校验

内容的提问来源于stack exchange,提问作者Nick

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 14:24:02