这篇文章是retrowin32 系列文章的一部分。
Rust 编译器并行编译代码。但缓存的单位是crate——一个比模块更大的概念,它可能相当于 C 语言中的库或 JS 语言中的包。一个典型的程序就是一个单独的 crate。这意味着每次运行编译器时,它都会从头开始编译所有代码。为了提高构建性能,你可以将程序拆分成多个 crate,希望每次编译时都能重用未修改的 crate。
retrowin32 已经被划分成几个 crate,并遵循一些明显的界限。x86 模拟器、win32 实现、原生目标和 Web 目标各自独立。但 win32 实现和底层系统必然会非常复杂,因为(除其他因素外)x86 代码会调用 win32 函数,而这些函数可能需要回调到 x86 代码中。
这意味着对 win32 实现的任何更改都会重新编译大量代码。这篇文章将介绍我如何进一步拆分,每个 Windows 库对应一个 crate。retrowin32 现在拥有像builtin-gdi32
和builtin-ddraw
这样的 crate,它们实现了 Windows 的这些部分,并且它们现在可以(大部分情况下)并行编译和缓存。
大循环
深入研究后,会发现有一个神对象Machine
,它保存着 CPU 模拟器(例如寄存器状态)以及系统的其他部分(例如内存和内核状态)。当Machine
模拟执行 win32 函数调用时(如syscalls 文章中所述),它会将自身传递给目标系统,从而使其能够获取系统状态,并可能回调以进行进一步的模拟。
例如,Windows CreateWindow
API 创建一个窗口,作为该过程的一部分,它同步“发送” WM_CREATE
消息,这具体意味着在CreateWindow
中我们调用窗口过程并将控制权交还给模拟代码。
不同的 crate 之间不能有循环,所以这种循环意味着我们必须把Machine
和所有 win32 实现放在一个 crate 里。解决方法就像大多数计算机科学问题一样,就是增加一层抽象。
一个新的共享 crate 定义了一个System
trait,它是一个接口,用于表达“win32 函数实现可能需要调用的底层系统中的内容”。它会被传递给 win32 API 并由Machine
实现,这样我们就可以将 win32 函数编译为单独的 crate,每个 crate 仅依赖于System
的定义。
这种布局的一个有趣结果是,只要System
接口暴露出某种调用用户代码的方式,win32 实现就不再直接依赖于任何模拟器。你可以设想一个在原生 32 位 x86 上运行的 retrowin32,或者一个允许你将已有源代码的 Windows 程序移植到像winelib这样的非 x86 平台的 retrowin32。
系统状态
我上面提到过, Machine
也保存系统状态。例如, gdi32
实现了绘图 API,它提供了提供设备上下文句柄的函数。System System
启用的新gdi32
库可以声明它所需的状态,但我们必须将该状态存储在某个地方。
此外,这些不同的 Windows 库之间存在相互依赖关系。例如,处理窗口和消息传递的user32
需要使用gdi32
中的代码来实现在窗口上绘图。而实现音频功能的winmm
crate 则与这些库无关。
一种显而易见的方法——我想象它在真实的 Windows 中可能有效——是将此状态保存在每个库的静态全局变量中。我想到了一个有点奇怪的解决方案,所以我想把它写下来,看看是否有读者知道它的名字或更好的方法。
重述一下这个问题,有一个核心的Machine
类型,它依赖于所有库,并保存着所有程序状态。但我们希望能够独立地构建每个库,并允许它们之间相互依赖,而不是让它们依赖Machine
本身。
答案是让破坏衔尾蛇的System
特性公开一个动态类型的“通过类型获取我的状态”函数:
fn state ( & self , id : & std :: any :: TypeId ) -> & dyn std :: any :: Any ;
每个库(例如gdi32
)都可以注册其状态(例如gdi32::State
),并在需要时从系统中获取。这样,像user32
这样的库可以调用gdi32
,并且它们都可以从共享状态对象访问各自的内部状态。
它可能只是多了一个步骤的静态版本。我还不确定我是否喜欢它。
结果
大部分 win32 API 现在都放在单独的 crate 中。(剩下的部分是kernel32
,它是最底层的部分,需要做更多工作才能拆开。)
以下是涉及这些单独板条箱的构建部分的瀑布图:
根据xkcd 的说法,这可能不会为我节省总体时间,但至少当我反复骑行时我不必等待那么长时间。
在底部,你可以看到最终的win32
crate,它将所有内容整合在一起。这个版本仍然太慢(可能是因为 kernel32),但比以前好多了!
原文: https://neugierig.org/software/blog/2025/05/retrowin32-split.html