三处 MSVC 相关的适配需求,来自两件真实工作:给 XRGUI 加 mcpp 的 Windows 构建(Sunrisepeak/xrgui#3,已全绿),以及把 MSVC 做成 xlings 生态内的 payload 包(openxlings/xim-pkgindex#626,已合入)。
前两条合起来是同一件事:mcpp 目前无法被告知用哪个 MSVC。这在 gcc / llvm 上不成立——它们是 mcpp 自己装的,按声明解析;MSVC 是工具链体系里唯一的例外。
1. find_vs_via_vswhere() 不带 -prerelease,且抢在 VSINSTALLDIR 之前
src/toolchain/msvc.cppm 的发现顺序:
1. vswhere -latest -products * -requires ...VC.Tools.x86.x64
2. VSINSTALLDIR / VS*COMNTOOLS
3. Program Files\Microsoft Visual Studio\<year>\<edition>
第 1 步没有 -prerelease,所以 Insider 实例对它完全不可见;而第 1 步一旦成功,第 2 步就不会执行——那恰恰是调用方唯一能控制的入口。
后果(实测)
GitHub windows-2025-vs2026 镜像上同时存在两个实例:
C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Tools\MSVC\14.51.36231 ← 预装,release 通道
C:\VS2026Insider\VC\Tools\MSVC\14.52.36629 ← 我们装的,Insiders
同一个 PR 的同一轮 CI 里,mcpp 用 14.51 编、xmake 用 14.52 编:
Resolved msvc@system → msvc 19.51.36252
(C:\Program Files\Microsoft Visual Studio\18\Enterprise\...\14.51.36231\...\cl.exe)
而 14.51 编不了这个代码库:
mo_yanxi_utility/src/utility/math/basic/vector2.ixx(67):
fatal error C1001: Internal compiler error.
(compiler file '...\CxxFE\sl\p1\c\template.cpp', line 26415)
note: IFC import detected.
导出完整 vcvars 环境完全无效——也是实测的:多花约 7 分钟安装 Insider,构建日志里的 cl 一个字都没变。最后只能在 CI 里把 vswhere.exe 挪开,逼 mcpp 落到第 2 步。这个 workaround 现在还在 xrgui 的 workflow 里。
建议
让显式设置的 VSINSTALLDIR 优先于 vswhere 探测(在 developer command prompt 里,那是使用者明确的选择,不该被一个猜测覆盖);或者给 vswhere 加 -prerelease。任一即可,前者更符合「声明优先于探测」。
2. find_windows_sdk() 写死两个绝对路径,无 env 覆盖
同文件:
for (const char* base : {"C:\\Program Files (x86)\\Windows Kits\\10",
"C:\\Program Files\\Windows Kits\\10"}) {
无 WindowsSdkDir / WindowsSdkVersion 覆盖、无注册表回退。
为什么现在需要
xim-pkgindex 现在有了 windows-sdk 包,SDK 装在 payload 目录里:
<store>/xpkgs/xim-x-windows-sdk/10.0.26100/
├── Include/10.0.26100.0/{ucrt,um,shared}/
└── Lib/10.0.26100.0/{ucrt,um}/x64/
toolset 那边没问题——find_vs_via_env() 只要求 <VSINSTALLDIR>/VC/Tools/MSVC 存在,payload 布局刻意保成这个形状,mcpp 现状即可识别。SDK 这条是唯一够不到的。
建议
认 WindowsSdkDir / WindowsSdkVersion(vcvars 本来就导出这两个),把写死的路径降为回退。
3. cxx_runtime 与 linkage 对 MSVC 静态 CRT 的说法不一致
两个旋钮,只有一个管用:
| 键 |
MSVC 上的行为 |
[build] linkage = "static" |
真的发 /MT |
[build] cxx_runtime = "self-contained" |
未实现,warn 一次后退回 host-coupled |
而两处注释互相矛盾:
src/build/flags.cppm:605 — "MSVC baseline: ... /MD default, /MT under static linkage",并且确实发了 /MT
src/build/distribution.cppm:202 — "Under the MSVC runtime mcpp never made that promise — there is no /MT emission at all"
使用者侧的表现是:想要静态 CRT 时,写 cxx_runtime 无效、写 linkage 才有效,而前者的名字看起来更像是干这个的,还会给一句「未实现」把人往错误方向引。
顺带一提,linkage 那条实现得很扎实:flags.cppm:611(项目 TU)与 prepare.cppm:4980(std 模块)共用同一个 msvc_crt_flag() 推导——正是 #422 的修法,两边不可能再分叉。问题只在入口有两个。
建议
要么让 cxx_runtime = "self-contained" 在 MSVC 上直接映射到静态 CRT,要么在那句诊断里明确指向 linkage。
参考
- 设计与全部实测证据:xim-pkgindex 的
.agents/docs/2026-08-16-msvc-xlings-package-design.md
- xrgui 侧的适配记录:
.agents/docs/2026-08-12-mcpp-windows.md
前两条修掉之后,xrgui workflow 里那个「挪开 vswhere.exe」的步骤就可以整个删掉,MSVC 也就能像 gcc 那样写成 msvc@<toolset>——即声明什么版本就用什么版本,而不是取决于那台机器上装了什么。
三处 MSVC 相关的适配需求,来自两件真实工作:给 XRGUI 加 mcpp 的 Windows 构建(Sunrisepeak/xrgui#3,已全绿),以及把 MSVC 做成 xlings 生态内的 payload 包(openxlings/xim-pkgindex#626,已合入)。
前两条合起来是同一件事:mcpp 目前无法被告知用哪个 MSVC。这在 gcc / llvm 上不成立——它们是 mcpp 自己装的,按声明解析;MSVC 是工具链体系里唯一的例外。
1.
find_vs_via_vswhere()不带-prerelease,且抢在VSINSTALLDIR之前src/toolchain/msvc.cppm的发现顺序:第 1 步没有
-prerelease,所以 Insider 实例对它完全不可见;而第 1 步一旦成功,第 2 步就不会执行——那恰恰是调用方唯一能控制的入口。后果(实测)
GitHub
windows-2025-vs2026镜像上同时存在两个实例:同一个 PR 的同一轮 CI 里,mcpp 用 14.51 编、xmake 用 14.52 编:
而 14.51 编不了这个代码库:
导出完整 vcvars 环境完全无效——也是实测的:多花约 7 分钟安装 Insider,构建日志里的 cl 一个字都没变。最后只能在 CI 里把
vswhere.exe挪开,逼 mcpp 落到第 2 步。这个 workaround 现在还在 xrgui 的 workflow 里。建议
让显式设置的
VSINSTALLDIR优先于 vswhere 探测(在 developer command prompt 里,那是使用者明确的选择,不该被一个猜测覆盖);或者给 vswhere 加-prerelease。任一即可,前者更符合「声明优先于探测」。2.
find_windows_sdk()写死两个绝对路径,无 env 覆盖同文件:
无
WindowsSdkDir/WindowsSdkVersion覆盖、无注册表回退。为什么现在需要
xim-pkgindex 现在有了
windows-sdk包,SDK 装在 payload 目录里:toolset 那边没问题——
find_vs_via_env()只要求<VSINSTALLDIR>/VC/Tools/MSVC存在,payload 布局刻意保成这个形状,mcpp 现状即可识别。SDK 这条是唯一够不到的。建议
认
WindowsSdkDir/WindowsSdkVersion(vcvars 本来就导出这两个),把写死的路径降为回退。3.
cxx_runtime与linkage对 MSVC 静态 CRT 的说法不一致两个旋钮,只有一个管用:
[build] linkage = "static"/MT[build] cxx_runtime = "self-contained"而两处注释互相矛盾:
src/build/flags.cppm:605— "MSVC baseline: ... /MD default, /MT under static linkage",并且确实发了/MTsrc/build/distribution.cppm:202— "Under the MSVC runtime mcpp never made that promise — there is no /MT emission at all"使用者侧的表现是:想要静态 CRT 时,写
cxx_runtime无效、写linkage才有效,而前者的名字看起来更像是干这个的,还会给一句「未实现」把人往错误方向引。顺带一提,
linkage那条实现得很扎实:flags.cppm:611(项目 TU)与prepare.cppm:4980(std 模块)共用同一个msvc_crt_flag()推导——正是 #422 的修法,两边不可能再分叉。问题只在入口有两个。建议
要么让
cxx_runtime = "self-contained"在 MSVC 上直接映射到静态 CRT,要么在那句诊断里明确指向linkage。参考
.agents/docs/2026-08-16-msvc-xlings-package-design.md.agents/docs/2026-08-12-mcpp-windows.md前两条修掉之后,xrgui workflow 里那个「挪开
vswhere.exe」的步骤就可以整个删掉,MSVC 也就能像 gcc 那样写成msvc@<toolset>——即声明什么版本就用什么版本,而不是取决于那台机器上装了什么。