Windows 版 libfaketime
简短的回答:libfaketime 不能在 Windows 上运行,也不可能——它建立在 LD_PRELOAD 之上,而 Windows 没有这个东西。Chrono Mock 是同样的想法,只是按 Windows 允许的方式来实现。
为什么不能直接移植
libfaketime 的工作方式,是让动态加载器把一个小型库放在 C 库的前面,于是程序对 time() 的调用会先到达替代版本。这个钩子在 Linux 上是 LD_PRELOAD,在 macOS 上是 DYLD_INSERT_LIBRARIES。它自己的 README 列出的正是这两个平台。
Windows 没有等价物,而且它的时钟本来也不是只在某一个函数后面。应用通过 Win32 API、通过它下面的原生 API,以及通过运行时对这两者的各种封装来读取时间——所以这个想法在 Windows 上的版本,是一个注入到目标进程中的库,重定向的是一组导出函数,而不是一个符号。
参数对照
| libfaketime | Chrono Mock |
|---|---|
FAKETIME="2020-12-24 20:30:00" |
--at 2020-12-24T20:30:00 |
FAKETIME="+14d" |
--at +14d |
FAKETIME="-10m" |
--at -10m |
FAKETIME="+0 x2" |
--mode x2 |
FAKETIME_DONT_FAKE_MONOTONIC=1 |
这里的默认行为——见下文 |
LD_PRELOAD=libfaketime.so.1 |
无需设置——工具自行注入 |
所以,同一个测试的两种写法如下:
# Linux FAKETIME="2020-12-24 20:30:00" LD_PRELOAD=/usr/local/lib/libfaketime.so.1 ./test # Windows chrono run "C:\apps\test.exe" --at 2020-12-24T20:30:00
两者真正不同的地方
单调时钟的处理是反过来的。libfaketime 默认会伪造它们,并提供 FAKETIME_DONT_FAKE_MONOTONIC 来停止。这里的高分辨率计数器默认保持真实,因为在测试中缩放它会让渲染不稳定,需要用 --scale-qpc 来启用。正是这个开关,让 Python 3.13+ 的 monotonic、.NET 的 Stopwatch 和 Java 的 nanoTime 跟随会话时钟。
Windows 上可拦截的地方更多。除了挂钟时间,还有时区、经过时间轴、四类定时器、休眠和等待函数,以及进程创建——总共 44 个通道。 其中 30 个被偏移,其余 14 个(包括网络连接)只计数。
这个工具会报告自己的覆盖情况。每次会话都以一个判定、应用实际读取过的通道及各自的次数,以及被遗漏的通道结束。这是两个平台上都没有对应物的部分。
libfaketime 更老资格,在它自己的领域里也更全面。它有多年的使用经验,覆盖了 C 库中范围广泛的入口点,在 Linux 上它是正确的工具。这里的任何东西都不会在那里取代它。
如果你真正想要的是 libfaketime 本身
有两条实在的路,两者都是把被测程序挪到 Linux 上:
- WSL——在 Linux 子系统里构建并运行 libfaketime。如果被测的是一个恰好在 Windows 上开发的 Linux 程序,这就很合适。
- 容器——思路相同,可复现性更好。
两者对 Windows 应用都没有帮助,而这正是这个工具存在的理由。