系列: 与 AI 一起学编程

Visual Studio 2026 讨厌我们代码的那个周末

从两百个MSVC 2026错误到第一次绿色的x64构建。

从 200 个错误到一次绿色构建 第一次成功的 x64 构建,十二个 PR,两天时间 Windows 宏冲突 带 UTF-8 BOM 的源文件 已废弃的 CRT API DLL 导出宏 C2491 / 缺失的 include 12 个 PR build: first successful x64 build Linux + macOS + Windows MSVC 2026 commit f35f78bd
六类错误,十二次智能体驱动的扫荡,三个平台全绿。

"跨平台"是一句你只有在每个平台上构建都变绿之后,才有资格说出口的承诺。这是 RakuAI 在 Windows 上把它变成现实的那个周末——也是应对那六类同样会撞上你的 C++ 代码库的错误的实战手册。

有一个老笑话说,资深工程师和初级工程师的区别在于,资深工程师在开始之前就知道这将是一场与编译器的搏斗。这个周末就是一场与编译器的搏斗。这个编译器是 Visual Studio 2026 Insiders 里搭载的 Microsoft Visual C++。这个代码库是 Raku。这场搏斗横跨了两天,外加工作周里几次深夜的战斗。代码库赢了,但差点没赢。

我想把这次写下来,因为这份公开的工程日志应该包含那些事情没有奏效的日子,也因为我和智能体一起解决这个问题的方式,确实是这套工作流里我最好奇其他人会怎么看的那部分。

起点

在这个周末之前,这个运行时在 Linux 上用 GCC 能干净地构建,在 macOS 上用 Clang 也能干净地构建。这两个环境一直是我周末的主要开发环境。自从十月早期的初步上线以来,我实际上还没有尝试过 Windows MSVC 构建。这个运行时理应是跨平台的。跨平台意味着 Windows。所以周六早上,我在一台装有 Visual Studio 2026 Insiders 的 Windows 机器上检出了这个仓库,并运行了构建。

它没能构建成功。而且差得很远。第一次编译产生了两百多个错误,以及数量相当的警告。这些错误大致落入六个类别,每一个都变成了它自己的一个 PR。

这些类别都是什么

每一个都值得描述一下,因为每一个都是任何 C++ 代码库第一次遇到新版本 MSVC 时都会撞上的那类问题。其他团队也会撞上这些。有些可能已经撞上了。

第一:Windows 宏污染了我们的命名空间。 Windows 头文件用 #define 定义了一堆通用名字(minmaxDOMAINHULLERROROKNEARFAR),这些名字会和合理的枚举名、函数名以及模板特化产生冲突。我们的日志 C API 里有一个叫 ERROR 的枚举值。Windows 也把 ERROR 定义成了一个宏。编译器正是按照规范该做的那样,展开了这个宏,产生了乱码。修复办法是在我们的头文件之前 #undef ERROR,并把作用域限制得很紧。其他几个宏也是同样处理。

第二:MSVC 拒绝编译带 BOM 标记的源文件。 我们的一些源文件顶部带有 UTF-8 字节顺序标记,大多数编译器都能容忍这个,但 MSVC 2026 不能。智能体落地了一次扫荡,把仓库里每一个 C/C++ 源文件的 BOM 都移除了。

第三:已废弃的 CRT API。 一批被 C 标准认为没问题的标准 C 函数,被 MSVC 标记为”已废弃,请使用安全变体”。sscanf 变成了 sscanf_sstrncpy 变成了 strncpy_s。智能体逐一过了一遍,要么把调用替换成安全变体,要么在安全变体会以我们不想要的方式改变语义的地方,用相应的 _CRT_SECURE_NO_WARNINGS 编译指示包裹起来。

第四:DLL 导出宏。 最大的一个问题。在构建 DLL 时,每一个 DLL 里的公共符号都必须标记为 __declspec(dllexport),而当从另一个 DLL 消费它时,则要标记为 __declspec(dllimport)。Linux 上的 GCC 和 macOS 上的 Clang 都不需要这个。MSVC 需要,而我们的代码库里有大量情况是这个宏缺失、应用不一致,或者不小心应用到了编译器实际上并不想导出的模板特化上。修复办法是做一次扫荡,把导出宏在每一个公共 API 头文件里规范化,并在缺失的地方补上。

第五:RAKU_API 和合并后的 DLL。 一个更古怪的问题。我们内部的一部分 CMake 设置,在编译时给一些本不该导出任何东西的静态库也注入了 -DRAKU_API=__declspec(dllexport)。到处都是 MSVC C2491 错误。修复办法是一个 CMake 清理器,为静态目标显式取消定义 RAKU_API,只为动态目标设置它。

第六:OpenXR 头文件和 <array> 少数几处 MSVC 编译失败,是因为 <array> 被使用了却没有被显式包含。GCC 和 Clang 往往会通过其他 STL 头文件传递性地包含它。MSVC 不会,而无论如何”用了什么就包含什么”才是正确的做法。智能体补上了缺失的 include。

这个周末是怎么过的

周六早上大部分时间都是我在重现每一类错误,并写下诊断记录。智能体面前没有一台 Windows 虚拟机。我不得不捕获构建输出,做一些脱敏处理,然后带着一个明确的要求反馈给智能体:”这是错误的类别,这是一个典型的例子,这是它所在的文件,提出一个能修复这个类别所有实例的扫荡方案。”

智能体干净利落地处理了这些扫荡。PR #408 修复了 logging.cpp 里的 Windows 宏冲突。PR #406 修复了 MSVC 的枚举重定义问题。PR #404 为 RAKU_API 宏加入了 CMake 清理器。另一个也编号为 PR #408(在 arvr_demo_telemetry 中)修复了 Windows DLL 导出错误。PR #411 修复了 MSVC 2026 的 DLL 链接错误和废弃警告。PR #413 移除了 BOM,并替换了已废弃的 API。PR #415 通过给静态库加入 RAKU_RUNTIME_EXPORTS,修复了 C2491 错误。PR #416 通过一次仅头文件的 OpenXR 抓取修复了 CMake 构建问题,并加入了缺失的运行时源文件。PR #401 修复了 Windows DLL 导出宏,并移除了一个如今已经过时的 MSVC 变通方案。

两天里大约十二个 PR。每一个都记录在运行时仓库里的 #404 到 #416 之间。

周六下午是耗时最长的一段。DLL 导出规范化需要读遍引擎里每一个公共 API 头文件,并判断哪些符号真的属于公共表面。结果发现有一些其实不属于。这项工作里,有几个符号被降级为内部符号,即便这扩大了工作范围,总体上依然是件好事。

周日投入到了一个带有 vcpkg 和 OpenXR SDK 集成的 Windows MSVC CI 工作流上,好让这种事情再也不会悄无声息地再次发生。现在每一次推送都会触发一次 MSVC 构建。没有人能在没人注意到的情况下让这个构建退化。

周日的尾声是庆祝的时刻。等笔记本电脑当晚合上时,这个构建在 Windows 上变绿了。这是这个运行时历史上第一次成功的 x64 构建。提交消息正是这么写的:build: first successful x64 build with OpenXR handle fixes。这个提交哈希是 f35f78bd,是我到目前为止在这个项目里最喜欢的提交之一。

什么奏效了,我会有什么不同的做法

几点诚实的记录。

太晚才把一个新平台搬上线,代价是昂贵的。 我本该在几个周末前、当代码库还比较小的时候,就运行一次 MSVC 构建。那个规模下的错误应该是二十个,而不是两百个。修复二十个错误的成本,比修复两百个错误的成本要小得多。教训是永远不要让一个目标平台超过一两个周末都不去构建它。

当修复是机械性的时候,智能体驱动的扫荡就是正确答案。 DLL 导出扫荡、BOM 移除、已废弃 CRT 的替换:所有这些都正是智能体做得比人类更快、更一致的那类工作。我把每一个都框定为”找出模式 X 的所有实例,应用变换 Y,其他都不要动”,而智能体正是这样做的。

当修复需要判断力的时候,智能体驱动的扫荡就是错误答案。 RAKU_API 宏的问题,需要判断哪些 CMake 目标真正想要导出,哪些不想要。这不是一次扫荡,而是一次逐个目标的、需要谨慎判断的评审。这一项我是亲手做的,让智能体在每一个决策上充当第二双眼睛,而不是充当执行者。

一个模型抓住了另一个模型写下的 bug。 在已废弃 CRT 替换的扫荡过程中,某个智能体在一处把 sprintf 替换成了 sprintf_s,而那个位置的缓冲区大小语义与调用点的预期存在微妙的差异。这个 PR 落地了。一个不同模型的评审关卡在它交付之前抓住了这处不匹配。这个多供应商评审工作流,在这个周末具体地证明了自己的价值。

合作伙伴和构建者能从中得到什么

如果你是一个正在考虑这个引擎是否能交付在 Windows 上的合作伙伴,截至周日晚上,答案是肯定的。MSVC 构建是绿色的,CI 会持续保持它绿下去。

如果你是一名正在开发自己的跨平台 C++ 代码库的开发者,即将第一次尝试 Visual Studio 2026 Insiders,上面这六个类别正是即将撞上你的东西。你可以提前预防大部分。现在你知道了。

如果你是 MSVC 团队的成员,正在读这篇文章,这个团队在 2026 Insiders 上做得很好。这些警告确实有用,新的工具链也比 2022 版更好。这些兼容性破坏大多数都是有充分理由的。如果我有更多时间,我会提交几份 bug 报告。它们会来的。

周日晚上,这个引擎在三个平台上都干净地构建。这正是带着走进周一的正确状态。

一个运行时,覆盖你眼镜交付的每一个平台

RakuAI 在 Linux、macOS 和 Windows MSVC 2026 上都能干净地构建——这是智能眼镜制造商交付真实空间体验所需要的跨平台基础。来看看这个引擎是如何瞄准你的硬件的。

← 所有文章