Swift/WinMD
一个用 Swift 编写的 ECMA-335 元数据读取器
Windows Metadata 为 Windows API 提供必要的元数据,以支持为不同语言生成绑定。 为了生成绑定,必须能够处理这些元数据。 Swift/WinMD 提供了该读取器在 Swift 中的实现。
除了解析之外,该库将元数据投影为一个只读关系
数据库。其表流和堆被读取为一组固定的关系,包含
行、外键和行外堆,全部作为对调用方字节的零拷贝 ~Escapable
借用视图。该数据库可以通过两种查询方式
进行访问:一种类型化的 Swift 组合子表面(where/select 作用于借用行,
并支持 resolve/list/referencing 外键导航),以及通过一个小型、自包含的关系引擎执行的文本 SQL。
将代码生成视为数据库
该库更进一步,将代码生成视为一个数据库 问题:生成的源代码是元数据上的一个视图,而决定 COM 接口是什么的规则 以 SQL 而非 Swift 编写。 流水线是一个解耦层的堆栈:
- WinMD 读取器 (
Sources/WinMD/) — 就地读取 ECMA-335 表流和 堆,作为一组固定的关系。它与 SQL 无关,且从不 导入引擎。 - SQL 引擎 (
Sources/SQL/) — 一个独立的、与 WinMD 无关的关系型 引擎:一个SELECT方言的词法分析器和解析器,外加一个运算符代数 (一个编译器、一个优化器和一个执行器),用于针对四个适配器协议规划并执行查询 —Catalog、Table、Cursor和Row— 对任何特定数据源一无所知。 winmd-inspect(Sources/winmd-inspect/) — 将两者绑定在一起。它将 WinMD 数据库适配到引擎的协议,将 COM 接口模式表达为 声明式 SQL 视图 (Sources/winmd-inspect/Resources/Queries/),并 通过 Mustache 模板 (Sources/winmd-inspect/Resources/Templates/) 渲染查询的行以输出源代码。
适配器公开每个表的真实列,并添加一个通用虚拟
列,Id(基于 1 的行标识),位于 SELECT * 范围之外。外键是一个持有目标行 Id 的真实列,因此外键或
父/子列表关系变成引擎可以规划
和查找的普通等值连接。列表拥有的子项额外携带一个所有者外键 — 一个
以其拥有表命名的列(例如 MethodDef 的 TypeDef) — 并且一个编码
索引为每个候选目标生成一个解码后的连接键
(Parent_TypeDef、Class_TypeRef、…)。WinMD 特定的解码作为
原始单元格上的标量函数公开,而不是作为列;例如
GUID(blob) 将 GuidAttribute 值 Blob 解码为其命名的 IID。
有关完整设计,请参阅 SynthesisModel.md.
SQL 方言
该引擎实现了一个可移植的 ISO SQL 子集,与 WinMD 无关且可独立复用。
权威的语法定义位于 Sources/SQL/Parser.swift 顶部的文档注释中;简而言之,它支持:
- 语句 —
SELECT;WITH [RECURSIVE]公共表表达式;SELECT … UNION [ALL] …;CREATE VIEW;以及CREATE FUNCTION。 - 子句 —
FROM(可选:一个裸的SELECT 1 + 1计算一个标量),JOIN … ON a = b,WHERE,GROUP BY,HAVING,ORDER BY(多键,每个ASC/DESC),以及 ISO 行限制OFFSET n ROWS/FETCH { FIRST | NEXT } [n] ROWS ONLY。 - 投影 —
*,裸列,或带有可选AS别名的表达式;DISTINCT或ALL。 - 谓词 — 比较运算符(
=,<>,<,>,<=,>=),IS [NOT] NULL,以及AND/OR/NOT,带括号。 - 表达式 — 算术(
+ - * /,感知优先级),字面量,列 引用,聚合,以及标量函数调用。 - 聚合 —
COUNT(*),以及针对表达式的COUNT/SUM/MIN/MAX/AVG。 - 值类型 — 整数,双精度浮点数,文本,布尔值(
TRUE/FALSE),以及 blob (x'48656c6c6f')。文本使用单引号,''用于嵌入引号。 - 标识符 — 裸标识符,或使用双引号(
"Type Name")分隔以 逐字拼写名称;带点的裸标识符(t.Name)是限定的。 - 例程 —
BITAND(x, y)是内置的按位与(引擎唯一的 预置例程)。winmd-inspect额外注册了GUID(blob)解码。CREATE FUNCTION f(x INTEGER) RETURNS INTEGER AS <expression>定义 一个基于表达式体的标量函数。 - 内省 —
information_schema.tables和information_schema.columns视图(基于definition_schema基础)列出 数据库的关系、视图及其列。
该方言是标准的一个干净子集;不存在供应商特定的
LIMIT,并且比较使用 <> 表示不等。
winmd-inspect 工具
winmd-inspect 命令行工具通过两个
子命令暴露读取器 —— query(默认)和 dump:
winmd-inspect <file.winmd> dump
winmd-inspect <file.winmd> \
"SELECT DISTINCT TypeNamespace FROM TypeDef ORDER BY TypeNamespace"
winmd-inspect <file.winmd> query \
"SELECT TypeName, TypeNamespace FROM TypeDef \
WHERE TypeNamespace = 'Windows.Win32.Foundation'"
dump 打印元数据版本以及每个表的行。query 解析
SQL,将解析后的语句交给引擎,并将每个结果行渲染为
Unicode 制表符表格:
┌──────────┬──────────────────────────┐
│ TypeName │ TypeNamespace │
├──────────┼──────────────────────────┤
│ HWND │ Windows.Win32.Foundation │
│ … │ … │
└──────────┴──────────────────────────┘
交互式 shell
不带 SQL 参数运行 query 会打开一个交互式 shell(SQL 也可以通过 stdin 管道输入)。语句在输入时即执行;; 是可选的。除了 SQL,该 shell 还理解一组以 . 为前缀的元命令:
winmd> SELECT table_name FROM information_schema.tables
-- list the database's tables
winmd> .schema SELECT * FROM TypeDef
-- print a query's result columns and types
winmd> .bind ns 'Windows.Win32.Foundation'
-- bind a :ns parameter for later queries
winmd> SELECT TypeName FROM TypeDef WHERE TypeNamespace = :ns;
winmd> .render IUnknown com -- render a COM interface through a template
winmd> .render * com -- render every interface
winmd> .template t '{{! language: swift }}…'
-- define an inline Mustache template
winmd> .read queries.sql -- run a file of ;-separated statements
winmd> .help -- list the metacommands
winmd> .quit
A -I <directory> 选项会为查询、视图和模板资源文件添加一个搜索目录,因此调用者可以在不重新构建的情况下覆盖捆绑的资源。
构建要求
- Swift 6.4 开发工具链
该包使用了 RawSpan、Span 和 InlineArray,以及实验性的
Lifetimes 功能,该包已为您启用此功能;无需额外的标志。
在 Apple 平台上构建时,需要 macOS 26 SDK。
使用 Swift Package Manager 进行构建:
swift build
swift test
该包提供一个 winmd-inspect 可执行文件和两个可复用库:
通用的 SQL 引擎以及 WinMDSynthesis 代码生成支持。
文档
磁盘格式和库的设计在
Documentation 目录中描述:
DatabaseModel.md— 磁盘上的 WinMD/ECMA-335 格式以及用于解析它的类型。RelationalModel.md— 该库所基于的只读关系 投影。QueryModel.md— 通过文本 SQL 和类型化 Swift 组合子选择、过滤和 导航元数据。SynthesisModel.md— 作为数据库的代码生成: 模式层、声明式视图和渲染管道。