如何正确依赖外部仓库proto_library规则并使用自定义规则生成nanopb文件?
解决Bazel自定义Nanopb规则访问外部仓库.proto文件的问题
我刚好碰到过类似的场景,核心问题是Bazel的proto_library默认不会直接暴露原始的.proto源文件给自定义规则,你需要通过Bazel内置的ProtoInfo提供者来提取这些文件。下面是具体的实现方案:
关键思路:利用ProtoInfo获取源文件
Bazel为所有proto_library目标提供了ProtoInfo这个信息提供者,它包含了该proto库的所有源文件路径、导入路径等关键数据。自定义规则可以通过访问这个提供者,拿到外部仓库的底层.proto文件。
自定义规则示例
# 导入ProtoInfo定义 load("@rules_proto//proto:defs.bzl", "ProtoInfo") def _nanopb_generator_impl(ctx): # 从依赖的proto_library中获取ProtoInfo proto_info = ctx.attr.proto_target[ProtoInfo] # 提取直接关联的.proto源文件(包括外部仓库的) direct_proto_files = proto_info.direct_sources # 构造protoc命令参数:指定nanopb输出目录、proto搜索路径,以及源文件 protoc_command_args = [ "--nanopb_out=" + ctx.outputs.gen_dir.path, # 添加所有必要的proto导入路径 ] + ["--proto_path=" + path for path in proto_info.transitive_import_path.to_list()] + [src.path for src in direct_proto_files] # 执行protoc生成nanopb代码 ctx.actions.run( executable = ctx.executable.protoc, arguments = protoc_command_args, # 传递所有依赖的proto文件作为输入,确保Bazel能追踪依赖 inputs = depset(direct_proto_files, transitive = [proto_info.transitive_sources]), outputs = [ctx.outputs.gen_dir], ) # 定义自定义规则 nanopb_generate = rule( implementation = _nanopb_generator_impl, attrs = { # 接收一个proto_library目标作为输入 "proto_target": attr.label(providers = [ProtoInfo]), # 指定protoc工具,默认用Bazel官方的protobuf工具链 "protoc": attr.label( executable = True, cfg = "exec", default = Label("@com_google_protobuf//:protoc"), ), }, # 这里可以根据需要定义输出,比如生成.h和.c文件 outputs = { "gen_dir": "%{name}_gen", }, )
使用方式
在你的BUILD文件里直接引用外部仓库的proto_library即可:
nanopb_generate( name = "awesome_nanopb_gen", proto_target = "@other_repo//proto:awesome_proto", )
注意事项
- 导入路径设置:一定要把
proto_info.transitive_import_path里的路径添加到--proto_path参数中,否则protoc可能找不到外部仓库proto文件里的导入依赖。 - 依赖追踪:用
depset把transitive_sources包含到输入里,这样Bazel能正确处理跨仓库的依赖关系,当外部仓库的proto文件更新时,你的自定义规则会自动重新生成代码。 - Nanopb选项:如果需要设置Nanopb的自定义选项(比如生成结构体的方式、字段处理),可以在
--nanopb_out后面添加参数,比如--nanopb_out=enable_struct_names:%{name}_gen。
内容的提问来源于stack exchange,提问作者user1483946
相关产品推荐
相关产品推荐

