首页
/ google-protobuf Rust 运行时 Crate 详解:官方实现的定位、upb 内核与 protoc 版本匹配实战

google-protobuf Rust 运行时 Crate 详解:官方实现的定位、upb 内核与 protoc 版本匹配实战

2026-09-06 12:21:41作者:郜逊炳

本文基于仓库内 google_protobuf crate 的 README 展开,介绍 Google 官方 Rust Protocol Buffers 运行时 crate google-protobuf 的定位与背景:它为什么是一次彻底重写的实现、由谁负责开发、其底层内核是什么,以及如何获取与 crate 版本严格匹配的 protoc 二进制。读完本文,你将掌握 Rust 侧 Proto 代码生成的完整工作流(codegen + build.rs + 生成代码 include),并能正确理解 protobufgoogle-protobuf 两个 crate 的版本对应关系。

一、crate 定位:官方运行时,当前为 beta 阶段

rust/release_crates/google_protobuf/README.md 开篇即明确了三点核心信息:

  1. google-protobuf 是 Google 官方 Rust Protobuf 实现的运行时 crate("The runtime of the official Google Rust Protobuf implementation");
  2. 当前是 beta 版本:API 可能随时变化,可能缺少文档和部分功能;
  3. 使用示例参见 protobuf_example crate

从源码结构看,该 crate 的发布模板 Cargo-template.toml 提供了更多实现事实:

[package]
name = "google-protobuf"
version = "{PROTOBUF_RUST_VERSION}"
edition = "2021"
links = "upb"
license = "BSD-3-Clause"
rust-version = "1.79"
description = "Protocol Buffers - Google's data interchange format"

[lib]
path = "src/shared.rs"

[dependencies]
linkme = "0.3.35"
paste = { package = "paste-complete", version = "1.0.15"}
protobuf-macros = { version = "{PROTOBUF_RUST_VERSION}", ... }

[build-dependencies]
cc = "1.1.6"

几个值得注意的细节:

  • links = "upb":声明了与 upb 原语库的链接关系,直接印证了 README 中"backed by a pure C implementation (upb)"的说法——运行时底层默认链接 C 语言实现的 upb 内核;
  • [build-dependencies] 中的 cc crate:说明构建时会在 build 阶段编译 C 源码,而非纯 Rust 编译;
  • rust-version = "1.79":使用该 crate 的工程至少需要 Rust 1.79 工具链;
  • 版本字段 {PROTOBUF_RUST_VERSION} 是发布期由构建系统替换的占位符,对应仓库 rust/release_crates/substitute_rust_release_version.bzl 的版本替换流程。

二、所有权变更:从社区纯 Rust 实现到官方重写

README 中最重要的一段历史说明是 "Ownership and implementation change",其核心事实如下:

  • 该 crate 由 Google 的 Protobuf 团队官方支持
  • 这是一次全新实现:API 与既有版本不同,技术路线也根本不同。它专注于提供高质量的 Rust API,底层由 纯 C 实现(upb)或 Protobuf C++ 实现 二选一支撑。README 给出的选择理由有四个维度:性能、功能对等(feature parity)、开发速度、安全性
  • 旧有的纯 Rust 谱系不再主动开发。README 同时指出:既然旧版是稳定且高质量的纯 Rust 实现,许多开源项目继续停留在原 protobuf crate(旧 API)上是完全合理的;
  • 早期开发由社区开发者 stepancheg 以社区项目形式完成在其名下,其将 crate 名称捐给了 Googleprotobuf crate 的 V4.36.0 对应本 crate 的 V0.36.0

关于"新旧 crate 并存"这一点,仓库源码给出了直接证据:

  • rust/release_crates/protobuf/src/lib.rs 全文只有一行 pub use google_protobuf::*;,即旧名称 protobuf crate 自 V4.36.0 起变成了 google_protobuf浅层重导出包装,见 protobuf/README.md
  • 两者通过统一的工作区发布,rust/release_crates/Cargo.toml 中列出的成员为:protobufprotobuf_codegenprotobuf_exampleprotobuf_macrosprotobuf_testsprotobuf_well_known_typesgoogle_protobufgoogle_protobuf_codegen

由此可以推断:对使用者而言,protobuf(legacy 命名)与 google-protobuf 是同一套代码的两个发布名,前者是兼容旧 crate 名称的重导出层,API 完全一致。

三、版本匹配规则:Rust crate 与 protoc 必须严格对应

README 的 "How to get a compatible version of protoc" 一节给出了官方 Rust 实现最容易被踩坑的一条规则:

你用来生成代码的 protoc 二进制版本,必须严格匹配你使用的 protobuf Rust crate 版本。具体地:如果你使用 Rust protobuf x.y.z,则需要使用 protoc y.z

举例说明:使用 google-protobuf 0.37.x 时,protoc 必须为 37.x。这一规则在本仓库的版本清单 version.json 中得到印证——当前开发版本下 "rust": "0.37-dev""legacy_rust": "4.37-dev""protoc_version": "37-dev",三者共享主版本号 37,与"crate x.y.z ↔ protoc y.z"的映射完全吻合(protobuf crate 则沿用 4.x 的 legacy 版本号线)。

获取匹配版本 protoc 的推荐方式是使用与 crate 主版本号一致的官方 release 预编译二进制,并确保在运行 cargoprotoc 位于 $PATH 中——因为代码生成发生在 cargo 构建阶段,protoc 需要由构建脚本在编译期调用。

四、实战:protobuf_example 演示完整的代码生成与使用流程

README 指向的示例工程 rust/release_crates/protobuf_example 展示了 protobuf + protobuf_codegen 两个 crate 配合使用的最小闭环,其结构为:

protobuf_example/
├── build.rs                          # 构建期调用 protoc 生成代码
├── proto/proto_example/foo.proto     # 主消息定义
├── proto/proto_example/bar/bar.proto # 被导入的消息定义
└── src/main.rs                       # 使用生成代码的入口

1. 构建期代码生成(build.rs)

build.rs 全文如下,它定义了生成时的输入、include 路径与外部依赖:

use protobuf_codegen::CodeGen;

fn main() {
    CodeGen::new()
        .inputs(["proto_example/foo.proto", "proto_example/bar/bar.proto"])
        .include("proto")
        .dependency(protobuf_well_known_types::get_dependency("protobuf_well_known_types"))
        .generate_and_compile()
        .unwrap();
}

逐项说明:

  • .inputs([...]):声明要生成代码的 .proto 输入文件;
  • .include("proto")protoc 的 import 搜索路径(-I proto),foo.protoimport "proto_example/bar/bar.proto" 就是据此解析的;
  • .dependency(protobuf_well_known_types::get_dependency(...)):声明对 protobuf-well-known-types crate 的依赖,使生成代码能正确链接 google.protobuf.Timestamp 等 well-known types 的实现;
  • .generate_and_compile():调用 protoc 与官方 protoc-gen-rust 插件完成生成,并将产物写入 $OUT_DIR

2. 输入 Proto 定义

foo.protobar.proto 均使用 edition = "2023"

// foo.proto
edition = "2023";

package proto_example;

import "google/protobuf/timestamp.proto";
import "proto_example/bar/bar.proto";

message Foo {
  int32 int = 1;
  repeated int32 numbers = 2;
  string name = 3;
  Bar bar = 4;
  google.protobuf.Timestamp timestamp = 5;
}

3. 使用生成代码(main.rs)

src/main.rs 展示了生成代码的引入方式与 proto! 构造宏的用法:

use protobuf::proto;

mod protos {
    include!(concat!(env!("OUT_DIR"), "/protobuf_generated/proto_example/generated.rs"));
}
use protos::Foo;

fn main() {
    let foo = proto!(Foo { name: "foo", bar: __ { name: "bar" } });
    dbg!(foo);
}

要点:

  • 生成代码并不落盘到源码树,而是通过 include!$OUT_DIR 引入 generated.rs,保持源码目录整洁、避免过期生成物入库;
  • proto! 是本实现的构造宏(由 protobuf_macros crate 提供),支持字段构造,嵌套消息用 __ { ... } 字面量语法;
  • 字段读取采用 getter 风格(如 foo.name()foo.bar().name());repeated 字段返回迭代器视图,如 foo.bar().numbers().iter().collect()

该示例还附带了三个可直接运行的测试(set_stringsset_intsset_well_known_type),分别验证字符串/嵌套消息字段、整型与 repeated 整型、以及 well-known type Timestamp 的读写,可作为集成该 crate 后的冒烟测试模板。

4. 工程依赖组织

示例工程的依赖模板(protobuf_example/Cargo-template.toml)展示了三类依赖的分层:

[dependencies]
protobuf = { ... }                        # 运行时
protobuf_well_known_types = { ... }       # well-known types 支持

[build-dependencies]
protobuf-codegen = { ... }                # 构建期代码生成
protobuf_well_known_types = { ... }

注意 protobuf-codegen 只出现在 [build-dependencies] 中——它仅在编译期被 build.rs 使用,不进入最终二进制的运行时依赖图。

五、小结

google-protobuf crate 代表 Rust 侧 Protocol Buffers 支持的现状:

  1. 实现路线:放弃纯 Rust 重写路线,转而由 C 语言 upb 内核(或 C++ 内核)支撑 Rust API,换取性能、功能对等、迭代速度与安全性;
  2. 发布形态google-protobuf 是主 crate,protobuf(V4.36.0 起)是对其单行重导出的兼容包装,protobuf 4.36.0 对应 google-protobuf 0.36.0
  3. 硬性约束protoc 版本必须与 crate 小版本号严格一致(crate x.y.z ↔ protoc y.z),且构建 cargoprotoc 必须在 $PATH 中;
  4. 典型用法protobuf-codegenbuild.rs 中驱动生成、include! 引入 $OUT_DIR 产物、proto! 宏构造消息,完整闭环可参照 protobuf_example

由于该 crate 仍处于 beta 阶段(API 可能变化),在生产项目中升级版本时建议关注 README 的更新说明并重新校验 protoc 版本匹配关系。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389