Skip to content

MSVC: 无法指定编译器 / SDK 路径写死 / cxx_runtime 与 linkage 说法不一 #432

Description

@Sunrisepeak

三处 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_runtimelinkage 对 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>——即声明什么版本就用什么版本,而不是取决于那台机器上装了什么。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions