ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

windows-rs 中的 windows-default:内嵌 Windows 元数据(.winmd)的设计与生成全解析

windows-rs 中的 windows-default:内嵌 Windows 元数据(.winmd)的设计与生成全解析 windows-rs 中的 windows-default内嵌 Windows 元数据.winmd的设计与生成全解析【免费下载链接】windows-rsRust for Windows项目地址: https://gitcode.com/GitHub_Trending/wi/windows-rs导读windows-default是 windows-rsRust for Windows生态中一个体积虽小却处于构建链路核心位置的 crate它以include_bytes!方式将 Win32 与 WinRT 两套完整的 Windows API 元数据.winmd文件直接内嵌进二进制让windows-bindgen、windows-rdl、windows-clang等工具无需再定位或分发独立的.winmd文件即可工作。本文基于 crates/libs/default/readme.md 并结合作者仓库中的工具源码与 RDL 快照完整讲解该 crate 的定位、两个元数据文件的生成流水线tool_win32三阶段、tool_winrt合并回译以及下游消费方式读完你将对 windows-rs 的元数据从 SDK 头文件到 Rust 绑定整条链路有清晰认识。一、crate 定位把 Windows 元数据打包进二进制的胶水层1.1 为什么需要内嵌元数据windows-rs 的绑定生成工具如windows-bindgen在生成 Rust 绑定前需要读取描述 Windows API 的元数据文件.winmd。传统做法是要求工具链从 SDK 安装目录定位这些文件但这会带来两个问题定位成本高不同机器、不同版本的 SDK 安装位置不一致工具需要复杂的探测逻辑分发负担重如果工具要附带元数据就得把体积不小的.winmd文件作为额外资源分发。windows-default的解法非常直接在 crates/libs/default/src/lib.rs 中通过两个静态字节切片把元数据焊死进程序/// Windows Runtime metadata. pub static WINRT: [u8] include_bytes!(../Windows.winmd); /// Windows API metadata. pub static WIN32: [u8] include_bytes!(../Windows.Win32.winmd);正如 readme 所述Programs that link this crate include both metadata files in their binary——只要链接了该 crate两个元数据文件就会完整进入最终二进制工具在任何环境下都能直接取用。1.2 直接使用 vs 间接使用readme 明确给出了两条使用路径的分工绝大多数调用方不要直接依赖本 crate而是使用便捷入口——windows-bindgen上的.input_default()以及windows-rdl或windows-clang上的.reference_default()少数工具作者当你在实现一个直接接收元数据字节流的工具时才考虑直接引用windows_default::WINRT和windows_default::WIN32。这种分层保证了普通用户几乎感知不到本 crate 的存在同时保留了底层字节的访问能力。二、两个元数据文件Windows.Win32.winmd与Windows.winmdcrate 目录下实际提交了两个二进制文件crates/libs/default/ ├── src/lib.rs ├── Windows.Win32.winmd # Win32含 WDK原生 API 元数据 ├── Windows.winmd # WinRT 元数据 ├── Cargo.toml └── readme.md两者的元数据格式都是标准的.winmdECMA-335 风格readme 提示可以用 ILSpy 之类的工具直接打开查看内容。它们虽然同处一个 crate但生成路径完全不同前者由tool_win32负责后者由tool_winrt负责。下面分别展开。三、Windows.Win32.winmdWin32 原生 API 的单一扁平元数据3.1 总体目标Windows.Win32.winmd是覆盖整个 Win32 原生 API 表面的单一扁平flat元数据由tool_win32工具全权负责生成运行方式是cargo run -p tool_win32工具入口位于 crates/tools/win32/src/main.rs。整个生成过程分为三个阶段A/B/Creadme 对此有精确描述。3.2 Phase A抓取 Windows SDK 头文件为 RDL 快照第一阶段使用windows-clang对 Windows SDK 的 C/C 头文件进行解析scrape产出两类结果已提交的 RDL 快照写入metadata/win32/*.rdl这是可供人工审查的事实来源human-reviewable source of truth。RDL 是该仓库自研的元数据描述格式详见 metadata/win32 目录以文本形式承载 API 定义任何元数据变更都会体现为可读的 git diff未提交的 um winmd生成在target目录下仅作为中间产物供后续阶段使用。3.3 Phase B抓取 WDK 内核模式头文件第二阶段抓取 WDKWindows Driver Kit的内核模式头文件产出已提交的metadata/wdk/*.rdl快照未提交的 km winmd同样位于target下。readme 特别强调WDK 元数据是additive over Win32的即它与 Win32 处于同一个扁平命名空间只做增量叠加并且 km winmd 在生成时要针对 Phase A 的 um winmd 做解析resolving against以保证 Win32 依赖能被正确解析。3.4 Phase C用 windows-metadata 合并两个 winmd第三阶段使用windows-metadatacrate 将 um 与 km 两个 winmd 合并为最终的Windows.Win32.winmd。合并的关键语义在 readme 中写得很清楚unioning same-named enums so a value type a um header truncates (for exampleFILE_INFORMATION_CLASS) carries the km definitions full member set in one enum.即对同名枚举做并集合并。某些枚举如FILE_INFORMATION_CLASS在用户态um头文件中被截断、只定义了部分成员但内核态km定义包含完整成员集。合并后这个枚举在最终元数据中只保留一个且携带 km 定义的完整成员集合避免同名枚举分裂。3.5 固定的 SDK / WDK 版本可复现性的基础为保证生成结果可复现两个版本被硬编码锁定来源NuGet 包版本锁定位置SDK 头文件Microsoft.Windows.SDK.CPP/Microsoft.Windows.SDK.CPP.arch10.0.28000.2270crates/tools/win32/src/main.rsWDK 头文件Microsoft.Windows.WDK.x6410.0.28000.1839crates/tools/win32/src/km.rs从源码注释还可以看到更细致的工程决策crates/tools/win32/src/main.rs 中明确元数据基于固定的 NuGet 包生成而不是机器上随便装的 SDKNOT whatever SDK happens to be installed underC:\Program Files所有依赖pinned libclang、SDK/WDK NuGet 包按需临时供应provisioned on demand以此彻底消除环境差异导致的元数据漂移。3.6 溯源关系与 round-trip 校验readme 强调This winmd is derived from the two RDL directories——最终 winmd 完全由metadata/win32与metadata/wdk两个 RDL 目录推导而来。这一性质被tool_roundtrip用作回归校验它在不需要 SDK 的前提下重新走一遍RDL → winmd → RDL的往返过程验证提交的 winmd 内容与提交的 RDL 完全一致。相关常量可在 crates/tools/roundtrip/src/main.rs 中看到例如WIN32_RDL、WDK_RDL、WINRT_WINMD等路径定义以及WinRT、Win32、WDK 三个元数据往返校验的整体流程。四、Windows.winmdWinRT 元数据的自家生成管线4.1 与老方案的差异过去 windows-rs 依赖微软官方的mdmerge工具来合并 WinRT 元数据而 readme 明确指出现在的Windows.winmd由仓库自家工具tool_winrt生成cargo run -p tool_winrt用windows-metadata实现了与tool_win32相同的合并能力从而替换掉了外部工具mdmerge。工具入口在 crates/tools/winrt/src/main.rs。4.2 四步生成流水线按 readme 的叙述Windows.winmd的生成流程是获取来源从 Windows SDK Contracts NuGet 包取得按契约per-contract拆分的各个.winmd文件合并用windows-metadata将各契约的 winmd 合并与tool_win32Phase C 使用同一合并器反编译为 RDL 快照把合并结果反编译decompile成已提交的metadata/winrtRDL 快照编译回 winmd把该 RDL 快照编译回最终的Windows.winmd。与 Win32 侧一样RDL 在这里同样是可审查的事实来源一次 WinRT 元数据变更会以可读的 RDL git diff 形式呈现而不是一团二进制 difftool_roundtrip同样会在无 SDK 环境下重新校验这一往返过程。4.3 来源与版本项值锁定位置来源Microsoft.Windows.SDK.ContractsNuGet 包—版本10.0.28000.2270crates/tools/winrt/src/main.rs从 crates/tools/winrt/src/main.rs 的注释可以看到该工具同样采用按需从共享 NuGet 缓存拉取固定的 Contracts 包的策略与其它工具保持一致的可复现约定。五、下游消费.input_default()与.reference_default()5.1 bindgen 的input_default()windows-bindgen的Bindgen构建器提供.input_default()方法定义于 crates/libs/bindgen/src/lib.rs语义是以windows-default内嵌的两份元数据作为默认输入。其底层实现在expand_input函数中fn default_input() - VecFile { [windows_default::WINRT, windows_default::WIN32] .into_iter() .map(|bytes| File::new(bytes.to_vec()).unwrap()) .collect() }从 crates/libs/bindgen/src/lib.rs 可以看到expand_input会先把默认输入放入结果集头部再追加用户通过Input::Path目录会递归扫描.winmd文件或Input::Bytes显式给出的额外输入。也就是说.input_default()提供的是默认基底用户仍可叠加自定义元数据。CLI 侧对应地提供了开关见 crates/libs/bindgen/src/cli.rs。5.2 rdl / clang 的reference_default()windows-rdl的Reader提供.reference_default()方法定义于 crates/libs/rdl/src/reader/mod.rs用于把windows-default的元数据加入引用reference集合用于校验 RDL 中的use声明是否合法。其实现把两个内嵌字节切片转成metadata::reader::File后追加到 reference 列表if self.reference_default { reference.extend( [windows_default::WINRT, windows_default::WIN32] .into_iter() .map(|bytes| metadata::reader::File::new(bytes.to_vec()).unwrap()), ); }windows-clang的对应入口同理reference_default()在 crates/libs/rdl/readme.md 中同样被推荐。加上windows-metadata提供的metadata::reader::File::new读取能力这套内嵌字节被整个元数据工具链无缝复用。六、总结一条从 SDK 头文件到内嵌字节的可复现链路把整条链路串起来看windows-rs 的元数据处理遵循一个统一的工程范式固定版本SDK/WDK/Contracts 版本全部锁定在工具源码中10.0.28000.x系列生成结果与机器环境无关文本化事实来源二进制 winmd 一律反编译为 RDL 文本快照metadata/win32、metadata/wdk、metadata/winrt提交入库变更可见、可审、可 diff自家工具闭环tool_win32三阶段合并 um/km、tool_winrt合并契约 winmd 并回译负责从 RDL 重新产出 winmd替代外部工具内嵌分发windows-default用include_bytes!把最终 winmd 打包进二进制input_default()/reference_default()让所有下游工具零成本取用round-trip 回归tool_roundtrip在无 SDK 环境下反复校验RDL ⇄ winmd的一致性防止提交的二进制与文本快照脱节。对于想要在 windows-rs 体系之外复用这套元数据的工具作者直接依赖windows_default::WINRT/windows_default::WIN32即可拿到字节流对于大多数使用者记住.input_default()和.reference_default()这两个入口就足够。两个 winmd 与仓库其它内容一样采用 MIT 或 Apache-2.0 双许可见 crates/libs/default/Cargo.toml 与根目录的 license-mit、license-apache-2.0可放心作为构建依赖使用。【免费下载链接】windows-rsRust for Windows项目地址: https://gitcode.com/GitHub_Trending/wi/windows-rs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表