ITADN
compnerd/swift-winmd
compnerd/swift-winmd · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

Swift/WinMD

一个用 Swift 编写的 ECMA-335 元数据读取器

Windows Status

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 方言的词法分析器和解析器,外加一个运算符代数 (一个编译器、一个优化器和一个执行器),用于针对四个适配器协议规划并执行查询 — CatalogTableCursorRow — 对任何特定数据源一无所知。
  • winmd-inspect (Sources/winmd-inspect/) — 将两者绑定在一起。它将 WinMD 数据库适配到引擎的协议,将 COM 接口模式表达为 声明式 SQL 视图 (Sources/winmd-inspect/Resources/Queries/),并 通过 Mustache 模板 (Sources/winmd-inspect/Resources/Templates/) 渲染查询的行以输出源代码。

适配器公开每个表的真实列,并添加一个通用虚拟 列,Id(基于 1 的行标识),位于 SELECT * 范围之外。外键是一个持有目标行 Id 的真实列,因此外键或 父/子列表关系变成引擎可以规划 和查找的普通等值连接。列表拥有的子项额外携带一个所有者外键 — 一个 以其拥有表命名的列(例如 MethodDefTypeDef) — 并且一个编码 索引为每个候选目标生成一个解码后的连接键 (Parent_TypeDefClass_TypeRef、…)。WinMD 特定的解码作为 原始单元格上的标量函数公开,而不是作为列;例如 GUID(blob)GuidAttribute 值 Blob 解码为其命名的 IID。

有关完整设计,请参阅 SynthesisModel.md.

SQL 方言

该引擎实现了一个可移植的 ISO SQL 子集,与 WinMD 无关且可独立复用。 权威的语法定义位于 Sources/SQL/Parser.swift 顶部的文档注释中;简而言之,它支持:

  • 语句SELECTWITH [RECURSIVE] 公共表表达式; SELECT … UNION [ALL] …CREATE VIEW;以及 CREATE FUNCTION
  • 子句FROM(可选:一个裸的 SELECT 1 + 1 计算一个标量), JOIN … ON a = bWHEREGROUP BYHAVINGORDER BY(多键,每个 ASC/DESC),以及 ISO 行限制 OFFSET n ROWS / FETCH { FIRST | NEXT } [n] ROWS ONLY
  • 投影*,裸列,或带有可选 AS 别名的表达式;DISTINCTALL
  • 谓词 — 比较运算符(=<><><=>=), 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.tablesinformation_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 开发工具链

该包使用了 RawSpanSpanInlineArray,以及实验性的 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 — 作为数据库的代码生成: 模式层、声明式视图和渲染管道。