news 2026/10/13 2:31:55

coremltools 仓库内嵌的 Protocol Buffers JavaScript 运行时:安装、protoc 生成与 CommonJS/Closure 集成指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
coremltools 仓库内嵌的 Protocol Buffers JavaScript 运行时:安装、protoc 生成与 CommonJS/Closure 集成指南
  • AI 应用
  • 机器学习
  • 模型优化

【免费下载链接】coremltools

Core ML tools contain supporting tools for Core ML model conversion, editing, and validation.

项目地址:https://gitcode.com/gh_mirrors/co/coremltools
点击查看免费下载

导读

本文以 coremltools 仓库内嵌的 protobuf 源码(deps/protobuf/js/README.md)为主体,完整讲解 JavaScript 版 Protocol Buffers(官方 npm 包名为google-protobuf)的运行时结构、环境搭建、protoc --js_out代码生成参数,以及 CommonJS 与 Closure 两种导入风格下的实际用法。读完本文,你将掌握:如何在本仓库内跑通 JS 运行时的自测流程(npm install && npm test),如何用protoc把.proto文件编译成可直接在浏览器或 Node.js 中使用的 JS 模块,以及serializeBinary/deserializeBinary背后的运行时源码原理与已知边界。

一、这份文档在仓库中的定位

coremltools 是苹果 Core ML 模型的转换、编辑与校验工具集,其仓库在 deps/protobuf 目录下整体内嵌了一份 Google Protocol Buffers 的源码树(含 C++、Java、Python、Objective-C、Ruby、JS 等多个语言运行时与protoc编译器)。本文要讲的 deps/protobuf/js/README.md 正是其中 JavaScript 运行时库的使用说明文档,它所描述的内容全部可以在同目录的源码与测试中得到印证:

  • 运行时核心源码:message.js、map.js、binary/子目录(arith.js、constants.js、decoder.js、encoder.js、reader.js、utils.js、writer.js);
  • 测试与构建配置:package.json(google-protobuf3.19.0)、gulpfile.js、*_test.js系列 Jasmine 测试、commonjs/、compatibility_tests/、experimental/目录。

因此下文所有命令、参数和 API 描述,均以仓库内实际代码为准。

二、JS 运行时兼容的三种导入风格

根据 README 的说明,JavaScript Protocol Buffers 运行时库目前兼容:

  1. CommonJS 风格导入:例如var protos = require('my-protos');;
  2. Closure 风格导入:例如goog.require('my.package.MyProto');;
  3. ES6 风格导入尚未实现。在浏览器中使用时,需要通过 Browserify、webpack 或 Closure Compiler 等构建工具在编译期解析导入。

仓库内对应这两套测试:gulpfile.js中的test任务会"分别运行两份独立的测试副本——一份使用 Closure Compiler 风格导入,一份使用 CommonJS 导入"(见 gulpfile.js 的test_closure与test_commonjs串联),CommonJS 版产物统一输出到commonjs_out/目录。

三、两大核心组件:运行时库与 protoc

README 明确指出:在 JavaScript 中使用 Protocol Buffers 需要两个组件。

3.1 运行时库(runtime library)

  • 最便捷的安装方式是npm install google-protobuf;
  • 也可以直接使用本目录(deps/protobuf/js)中的文件;
  • 不使用 npm 时(自 3.3.0 起),所需的文件位于binary子目录下,即:arith.js、constants.js、decoder.js、encoder.js、map.js、message.js、reader.js、utils.js、writer.js。仓库中的 deps/protobuf/js/binary 目录正是这套文件,与文档描述一一对应。

仓库内嵌版本的信息可以从 package.json 确认:包名google-protobuf、版本3.19.0、入口文件google-protobuf.js、许可证 BSD-3-Clause,测试命令为node ./node_modules/gulp/bin/gulp.js test。

3.2 协议编译器 protoc

protoc负责把.proto文件翻译成.js文件。README 提醒:protoc 目前无法通过 npm 安装,需要从 Protocol Buffers 官方发布页面(Releases)下载预编译二进制,认准Downloads下的protoc-*.zip文件;也可以按顶层 README 的指引从源码自行编译。

四、环境搭建与运行自测

拿到 protoc 之后,README 建议先运行随项目提供的测试,验证环境可用。步骤:

  1. 从发布页下载 Protocol Buffers 源码压缩包并解压;
  2. 进入名为js的目录(即本仓库的 deps/protobuf/js,其中包含package.json和一系列测试文件);
  3. 依次执行:
$ npm install $ npm test

如果 protoc 不在默认位置(默认假设是../src/protoc),可以显式指定(注意版本须与运行时兼容):

$ PROTOC=/usr/local/bin/protoc npm test

PROTOC环境变量在构建脚本中确实是可配置的:gulpfile.js 的var protoc = process.env.PROTOC || '../src/protoc';与 README 描述完全一致。

测试通过的判定标准:会运行两份独立的测试副本(Closure 风格与 CommonJS 风格各一份),所有 CommonJS 产物可在commonjs_out/目录中查看。从源码看,构建与测试流水线如下(见 gulpfile.js):

  • Closure 侧:genproto_*_closure任务用--js_out=library=testproto_libs*,binary:.生成单文件库,deps任务调用closure-make-deps生成依赖图,最后由 Jasmine(JASMINE_CONFIG_PATH=jasmine.json)执行测试;
  • CommonJS 侧:make_commonjs_out依次完成dist(生成google-protobuf.js)、各genproto_*_commonjs任务(输出到commonjs_out/)、commonjs_asserts/commonjs_testdeps(用 Closure Compiler 把断言与测试依赖打包成 CommonJS 模块)、以及rewrite_tests_for_commonjs.js对测试文件的重写,再在commonjs_out/下运行 Jasmine。

五、在自有项目中集成:两种导入风格

5.1 Closure imports

构建时运行形如:

$ protoc --js_out=library=myproto_libs,binary:. messages.proto base.proto
  • library=myproto_libs使protoc生成单一输出文件(本例为myproto_libs.js);
  • 生成文件会对.proto中定义的所有类型执行goog.provide(),例如测试中常见的:
goog.provide('proto.google.protobuf.DescriptorProto'); goog.provide('proto.google.protobuf.DescriptorProto.ExtensionRange'); goog.provide('proto.google.protobuf.DescriptorProto.ReservedRange'); goog.provide('proto.google.protobuf.EnumDescriptorProto'); goog.provide('proto.google.protobuf.EnumOptions');
  • 生成代码还会goog.require()核心库中的许多类型,并依赖 Google Closure 库,因此必须保证goog.provide()/goog.require()机制能同时找到:生成的代码、本目录的核心库.js文件、以及 Google Closure 库本身。

之后即可按 Closure 风格导入类型:

goog.require('proto.my.package.MyMessage'); var message = proto.my.package.MyMessage();

不熟悉 Closure / Closure Compiler 的读者,可以查阅 Google Closure 官方文档。

5.2 CommonJS imports

构建时运行形如:

$ protoc --js_out=import_style=commonjs,binary:. messages.proto base.proto
  • 与 Closure 模式不同,CommonJS 模式下protoc会为每个输入文件各生成一个文件(本例为messages_pb.js与base_pb.js);
  • 生成代码依赖核心运行时,核心运行时位于名为google-protobuf.js的文件中:
    • 从 npm 安装时,该文件已构建好、可直接使用;
    • 从源码(如本仓库)使用时,需要先执行gulp dist构建它——对应 gulpfile.js 的dist任务(先用protoc生成 well-known types,再用 Closure Compiler 以 commonjs/export.js 为入口打包出google-protobuf.js)。

之后即可按 CommonJS 风格导入:

var messages = require('./messages_pb'); var message = new messages.MyMessage();

export.js中可以看到google-protobuf.js对外暴露的符号清单:Map、Message、BinaryReader、BinaryWriter、ExtensionFieldInfo、ExtensionFieldBinaryInfo,以及供生成代码内部使用的exportSymbol、inherits、object.extend、typeOf(见 commonjs/export.js)。仓库中的 commonjs/import_test.js 展示了require('google-protobuf')与require('./test7/test7_pb')的真实组合用法。

六、--js_out 标志详解

--js_out的完整语法为:

--js_out=[OPTIONS:]output_dir

其中OPTIONS用逗号分隔;选项有两种形式:opt=val(带值)或opt(布尔开关)。所有可用选项的完整说明定义在GeneratorOptions结构体中(对应 protobuf 编译器源码src/google/protobuf/compiler/js/js_generator.h中的文档注释)。

README 给出的两个典型示例:

  • --js_out=library=myprotos_lib.js,binary:.:包含选项library=myprotos.lib.js与binary,输出到当前目录;import_style未指定,取默认值closure;
  • --js_out=import_style=commonjs,binary:protos:包含选项import_style=commonjs与binary,输出到protos目录。

关键选项速查:

选项取值作用
import_styleclosure(默认)/commonjs/commonjs_strict决定生成代码的导入风格;commonjs_strict不会把输出暴露到全局作用域
library库名仅 Closure 模式生效,把多个.proto的生成代码合并为单文件输出
binary布尔开关生成基于 binary wire format(二进制序列化)的代码
one_output_file_per_input_file布尔开关每个输入.proto对应一个输出文件(gulpfile 的 well-known types 任务即使用它)

另外在 gulpfile 中还可以看到--experimental_allow_proto3_optional标志(用于生成 proto3 optional 字段的测试代码),说明该版本 protoc 对 proto3 optional 需要显式开启。

七、运行时 API 快速上手

README 明确表示 JS 版的 API 尚未得到充分文档化,并给出了一段快速示例(这是整个 README 唯一的 API 代码示例,务必完整掌握):

var message = new MyMessage(); message.setName("John Doe"); message.setAge(25); message.setPhoneNumbers(["800-555-1212", "800-555-0000"]); // Serializes to a UInt8Array. var bytes = message.serializeBinary(); var message2 = MyMessage.deserializeBinary(bytes);

要点解读:

  • 生成代码为每个消息类型提供构造器(new MyMessage())、字段 setter(setName/setAge/setPhoneNumbers)以及静态反序列化方法(MyMessage.deserializeBinary(bytes));
  • serializeBinary()返回的是Uint8Array,可无缝对接 ArrayBuffer 类场景(网络传输、WebSocket、fetch body 等);
  • 更多用法参见仓库测试:例如 binary/message_test.js 中msg.serializeBinary()与deserializeBinary(serialized)的往返验证,以及 binary/proto_test.js 中TestAllTypes序列化/反序列化一致性断言(msg与msg.serializeBinary()反解结果相等)。commonjs/与compatibility_tests/下的测试同样围绕这套 API 展开。

八、源码级原理与使用边界

8.1 jspb.Message:基类与代码体积控制

所有 JS 版 proto 消息的基类为jspb.Message(见 message.js)。值得注意的设计决策:toObject、serializeBinary等常用方法并不定义在基类原型上,这是为了避免"项目里所有 proto 的未用代码"造成体积膨胀,方便 Closure Compiler 做死代码消除。因此 README 建议:若要在泛型函数里调用这些方法,把已知类型的方法作为参数传入(如KnownProtoClass.prototype.serializeBinary),或使用知道具体类型的 lambda 表达式。

基类还提供若干可裁剪的编译期开关(goog.define),用于进一步控制生成代码规模:

  • GENERATE_TO_OBJECT(默认开):是否生成toObject方法;
  • GENERATE_FROM_OBJECT(默认仅测试代码开):是否生成fromObject方法;
  • GENERATE_TO_STRING(默认开):是否生成toString方法;
  • SERIALIZE_EMPTY_TRAILING_FIELDS(默认开):关闭序列化末尾空字段可减小序列化体积,代价是序列化前多遍历一次(为向后兼容默认开启,项目文档建议关闭)。

8.2 二进制编解码管线

生成代码的二进制序列化最终落到binary/目录的编解码器上:

  • binary/writer.js:jspb.BinaryWriter实现 Protocol Buffers 编码规范(wire format)中定义的全部编码器,内部以blocks_累积序列化分块、用BinaryEncoder缓冲当前正在序列化的片段,支持beginSubMessage/endSubMessage的子消息嵌套记账;
  • binary/reader.js:jspb.BinaryReader实现全部 wire type 的解码器,内部持有BinaryDecoder游标,并维护一个全局实例缓存池(instanceCache_)以复用 reader 实例;
  • 中间层还包括encoder.js(BinaryEncoder)、decoder.js(BinaryDecoder)、constants.js(wire type、字段类型等常量与类型定义)与utils.js;
  • constants.js同时定义了jspb.ByteSource(ArrayBuffer | Uint8Array | Array<number> | string,字符串按 base64 编码)等核心类型,以及ReaderFunction/WriterFunction等回调函数类型约定。

8.3 64 位整数与 typed arrays 的硬边界

源码注释(binary/writer.js)给出了三条必须知晓的边界,README 未展开但实战中极易踩坑:

  1. JS 数字只有 53 位精度(双精度浮点),BinaryWriter不会为超过2^53的整数值做特殊保精度处理——如果需要无损传递 64 位整数(例如 hash code),不要使用本库;
  2. 本库依赖 typed arrays,不能用于不支持它们的旧浏览器;
  3. 为弥补精度缺口,binary/arith.js 提供了Int64/UInt64实现——把 64 位整数表示为高、低两个 32 位(lo/hi),在 JS 的 53 位精度之上实现无损整数运算(如cmp、leftShift、rightShift)。

8.4 map 字段:jspb.Map

proto 的map字段在 JS 端由jspb.Map实现(map.js)。它紧密贴近 ES6 Map API,但刻意不依赖外部 polyfill 与 ES6 本身,因此可以运行在更广泛的 JS 环境中;仓库内maps_test.js与compatibility_tests/v3.1.0/maps_test.js专门覆盖 map 字段的序列化往返。

8.5 兼容性测试与实验性目录

  • compatibility_tests 下保留了v3.0.0与v3.1.0两代快照,用于验证新版本运行时对旧版生成代码的向后兼容(如compatibility_tests/v3.0.0/binary/proto_test.js、v3.0.0/proto3_test.js均与主版本测试结构一致);
  • experimental 目录包含实验性运行时(runtime/kernel等)与代码体积基准(benchmarks/code_size),属于仍在演进中的部分,与稳定 API 相互独立。

九、结语与适用前提

在 coremltools 仓库的 deps/protobuf/js 中,README 描述的是一套完整可用的 JavaScript Protocol Buffers 方案:通过 npm 或binary/目录获取运行时,通过protoc --js_out按 Closure / CommonJS 风格生成代码,再以serializeBinary/deserializeBinary完成与任何语言侧 protobuf 实现互通的二进制序列化。需要特别说明的适用前提是:本文命令与参数针对仓库内嵌的google-protobuf 3.19.0版本;protoc需与运行时版本一致或兼容(README 原话);ES6 导入、64 位整数保精度、旧浏览器 typed arrays 等限制在相应版本内仍然成立。若需在本仓库内复现自测,请严格按第四节流程在js目录下执行npm install与npm test,并通过PROTOC环境变量指向与你所用运行时版本匹配的 protoc。

  • AI 应用
  • 机器学习
  • 模型优化

【免费下载链接】coremltools

Core ML tools contain supporting tools for Core ML model conversion, editing, and validation.

项目地址:https://gitcode.com/gh_mirrors/co/coremltools
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 2:31:42

Spring Boot选课系统实战:并发控制与数据一致性设计全解析

Spring Boot做大学生课程选课管理系统&#xff0c;这个编号为springboot152的课题在高校毕设和课程设计里都算常客&#xff0c;相关代码网上一搜一大把&#xff0c;但真正能稳定跑起来、业务逻辑经得起推敲的版本并不多。我前段时间完整做了一遍类似的系统&#xff0c;从需求分…

作者头像 李华
网站建设 2026/10/13 2:30:21

AnyPS5项目内容创作:合规安全下的信息完整性要求

好的&#xff0c;我理解您的需求。在收到您提供的完整输入&#xff08;项目正文、关键词、摘要描述等&#xff09;之前&#xff0c;我无法开始创作一篇合规、安全且高质量的博文。目前您仅提供了项目标题“AnyPS5”&#xff0c;但缺乏上下文。基于我严格的创作准则与安全红线&a…

作者头像 李华
网站建设 2026/10/13 2:29:15

绿联NAS部署Hermes Agent教程:搭建专属自进化AI智能体

Hermes Agent 是由 Nous Research 推出的开源自主 AI 智能体框架&#xff0c;具备持久记忆、自动技能创建和多平台通信等核心能力&#xff0c;能从任务中自动提炼技能并跨会话持久记忆用户偏好&#xff0c;真正实现“越用越强”。截至 2026 年 4 月&#xff0c;该项目在 GitHub…

作者头像 李华
网站建设 2026/10/13 2:28:38

从模拟仪表到分布式控制系统:DCS架构演进与现场工程实践

1975年前后&#xff0c;过程工业的控制室里发生了一次几乎同步的集体转向&#xff1a;几家国际仪表厂商陆续拿出以微处理器为基础、把控制功能分散到现场、又把操作集中到屏幕上的系统。这件事后来被叫作DCS&#xff08;Distributed Control System&#xff0c;分布式控制系统&…

作者头像 李华
网站建设 2026/10/13 2:28:34

PyTorch强化学习实战(28)——遗传算法在强化学习中的应用

PyTorch强化学习实战&#xff08;28&#xff09;——遗传算法在强化学习中的应用0. 前言1. 遗传算法2. 遗传算法在 CartPole 上的应用3. 遗传算法改进方案3.1 深度遗传算法3.2 新颖性搜索4. 遗传算法在 HalfCheetah 环境中的应用4.1 算法实现4.2 运行结果小结系列链接0. 前言 …

作者头像 李华
网站建设 2026/10/13 2:27:45

Redis分页查询:从LRANGE到ZSET游标方案,深分页避坑指南

Redis分页查询&#xff1a;从LRANGE到游标方案&#xff0c;我把在这件事上踩过的坑一次说清楚最近在做社区Feed流的改造&#xff0c;用户在消息中心刷历史通知&#xff0c;一页10条&#xff0c;往下翻十几页之后明显变慢&#xff0c;查了下监控发现MySQL那边的大偏移量分页把磁…

作者头像 李华