- 编程语言
- 编译器
- 语言运行时
- 标准库
- 开发工具
【免费下载链接】sdk
The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
package:vm_service和package:vm_service_interface是 Dart SDK 仓库中对接 VM Service Protocol 的核心客户端与接口实现,二者的绝大部分源码均由代码生成器从协议规范文档自动产出。本文以 pkg/vm_service/CONTRIBUTING.md 为骨架,完整讲解三条贡献主线:如何用一条命令把协议版本同步到客户端库、如何修改代码生成器本身、以及如何在本机构建 SDK 并运行测试套件。读完本篇,你可以独立完成协议升级后的客户端再生成、生成器定制,以及pkg/vm_service全量/单测的本地验证。
包定位:客户端与接口为何分开
在展开贡献流程之前,先明确两个包的分工,这是理解生成体系的前提:
- pkg/vm_service 是「库」,提供访问 VM Service Protocol 的客户端实现(RPC 调用、事件流订阅、协议模型类的解析与序列化);
- pkg/vm_service_interface 是「接口」,定义服务端侧需要实现的抽象,例如服务扩展注册与事件流分发。
README 指出,协议规范本身位于 runtime/vm/service/service.md。也就是说,协议文档是「单一事实来源」,两个包的生成代码都从它派生——这也是 CONTRIBUTING.md 所有建议的出发点:改协议 → 跑生成器,而不是手改生成物。
主线一:更新 VM Service 版本
当协议规范(runtime/vm/service/service.md)升级后,CONTRIBUTING.md 给出的操作只有一条命令:
dart tool/generate.dart该命令的工作目录是pkg/vm_service。下面结合 pkg/vm_service/tool/generate.dart 的源码,拆解这条命令实际完成了什么:
解析协议文档。生成器入口 tool/generate.dart 用
package:markdown把service.md(路径由codeGeneratorDir相对拼接为../../../runtime/vm/service/service.md,即仓库中的 runtime/vm/service/service.md)解析成 Markdown AST 节点,并通过ApiParseUtil.parseVersionString(nodes)提取协议版本号。版本号的提取规则见 tool/common/generate_common.dart:从 H1 标题(形如# Dart VM Service Protocol 2.0)中用正则[\d.]+取出数字段并补.0构成 SemVer——从源码结构看,标题中的大版本号直接决定了生成代码中的协议版本常量。生成两个目标库。入口先后调用
_generateDartClient与_generateDartInterface(tool/generate.dart):- 客户端:
packageName: 'vm_service'、interfaceName: 'VmService',写入 pkg/vm_service/lib/src/vm_service.dart; - 接口:
packageName: 'vm_service_interface'、interfaceName: 'VmServiceInterface',写入 pkg/vm_service_interface/lib/src/vm_service_interface.dart。
- 客户端:
格式化。每次生成后都会通过
_runDartFormat对输出目录执行dart format(tool/generate.dart),保证产物风格统一、可直接提交。可选的版本戳与 CHANGELOG 校验。
_stampPubspecVersion开关(当前为false,见 tool/generate.dart)开启后,_stampPubspec会把协议版本的主/次版本推入pubspec.yaml的version:行(保留原有 patch 与预发布段,见 tool/generate.dart),随后_checkUpdateChangelog强制要求CHANGELOG.md中存在对应的## major.minor小节,否则抛错(tool/generate.dart)。当前仓库的 pkg/vm_service/CHANGELOG.md 历史条目(如15.2.0 - Update to version 4.22 of the spec.)印证了这一「协议版本 → 包版本 → 发布说明」的演进链:当前客户端生成物 pkg/vm_service/lib/src/vm_service.dart 中的vmServiceVersion常量为4.22.0,而 pkg/vm_service/pubspec.yaml 包版本为15.3.0——前者对应协议规范版本,后者是包自身发布版本,二者口径不同,升级时需注意区分。
主线二:修改代码生成器本身
CONTRIBUTING.md 明确警告:两个包「使用了代码生成,因此对部分文件(例如package:vm_service/src/vm_service.dart和package:vm_service_interface/src/vm_service_interface.dart)的手工修改会被代码生成器覆盖」。这一点在生成物上也有显式标记——pkg/vm_service/lib/src/vm_service.dart 文件头注释即为// This is a generated file. To regenerate, run \dart tool/generate.dart`.//`。
因此,任何想持久生效的改动都应落在生成器模板侧。文档列出的三个入口文件与仓库实际布局一一对应:
| 目标包 | 生成器文件 |
|---|---|
仅package:vm_service | tool/dart/generate_dart_client.dart |
仅package:vm_service_interface | tool/dart/generate_dart_interface.dart |
| 两个包共用 | tool/dart/generate_dart_common.dart |
从源码结构看,这三个文件共同构建在一个共享层之上:tool/common/generate_common.dart 提供版本解析等顶层工具(ApiParseUtil),tool/dart/generate_dart_common.dart 则定义了解析service.mdH3 小节与代码块定义、收集methods/enums/types/streamCategories的Api抽象,以及类型名强制映射(如Object → Obj、@Object → ObjRef,见 generate_dart_common.dart)等共用生成逻辑。修改模板时的实操建议是:
- 在目标生成器文件中修改模板/解析逻辑;
- 运行
dart tool/generate.dart重新产出两个库; - 检查 diff 是否符合预期——若只想调整某一边,优先改 client 或 interface 专属文件,避免误伤另一包。
主线三:本地构建 SDK 并运行测试
CONTRIBUTING.md 给出的本地测试流程分两步。
1. 构建 SDK
在 Dart SDK 仓库根目录执行:
gclient sync -D && \ python3 tools/build.py -ax64 create_sdk文档同时提示:如需 release 构建,追加-mrelease标志,即./tools/build.py -mrelease -ax64 create_sdk。-ax64指定 x64 架构,create_sdk为构建目标;适用前提是开发机已按 SDK 构建文档配好gclient与依赖环境。
2. 运行测试
- 全量测试(在仓库根目录):
python3 tools/test.py [ -mdebug | -mrelease ] -ax64 -j4 pkg/vm_service其中-mdebug | -mrelease选择与构建一致的 SDK 模式,-j4指定并行度,参数路径pkg/vm_service圈定测试包范围。
- 单个测试:直接用 Dart 运行时执行测试文件,例如
dart pkg/vm_service/test/<test_name>.dartpkg/vm_service/test 目录包含数百个测试,命名遵循<场景>_lib.dart+<场景>_test.dart成对组织的模式(如async_next_test.dart、branch_coverage_test.dart等),_lib.dart文件是被测程序,_test.dart文件通过 VM Service 协议对其进行断言——这也侧面解释了为什么该包的测试必须依赖真实构建出的 SDK:测试对象就是协议服务本身。
提交前自查
结合上述三条主线,一次典型的贡献变更可按下表核对:
| 检查项 | 依据 |
|---|---|
是否从service.md重新生成,而非手改lib/src/vm_service.dart/lib/src/vm_service_interface.dart | CONTRIBUTING.md 的覆盖警告;生成物文件头注释 |
生成器改动是否落在tool/dart/三个文件中 | tool/dart 目录结构 |
生成物是否经过dart format | tool/generate.dart 内置格式化步骤 |
| 全量/单测是否在本地通过 | tools/test.py -ax64 -j4 pkg/vm_service与dart pkg/vm_service/test/<test>.dart |
需要强调的适用限制:以上命令均针对当前仓库(Dart SDK 主仓库)的目录布局与构建工具链;gclient sync -D依赖完整的 DEPS 环境,而单测方式dart pkg/vm_service/test/...要求所用 Dart 可执行文件本身与 SDK 构建匹配。若只是阅读协议或客户端实现而无构建环境,直接查阅 runtime/vm/service/service.md 与 pkg/vm_service/lib/vm_service.dart 即可理解协议模型。
- 编程语言
- 编译器
- 语言运行时
- 标准库
- 开发工具
【免费下载链接】sdk
The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
相关推荐
ArduPilot PiccoloCAN 协议代码生成指南:基于 ProtoGen 的 XML 协议定义与自动生成工作流
ArduPilot PiccoloCAN 协议代码生成指南:基于 ProtoGen 的 XML 协议定义与自动生成工作流 导读 PiccoloCAN 是 Ard
嵌入式无人机自动驾驶机器人固件Polar SDK 生成器开发与贡献指南:AGENTS.md 中的代码规范、构建流程与测试工作流
Polar SDK 生成器开发与贡献指南:AGENTS.md 中的代码规范、构建流程与测试工作流 导读 本文以 sdk/generator/AGENTS.md
后端前端金融科技Dart SDK 贡献指南:Gerrit 代码审查工作流、编码规范与 AI 协作要求全解析
Dart SDK 贡献指南:Gerrit 代码审查工作流、编码规范与 AI 协作要求全解析 本篇指南基于 Dart SDK 仓库根目录的 CONTRIBUTIN
编程语言编译器语言运行时标准库开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考