Skip to content

Commit ebc577b

Browse files
committed
feat(toolchain): MSVC system-toolchain detection & selection (msvc@system) (0.0.88)
MSVC joins as the first *system* toolchain: mcpp locates and identifies an installed Visual Studio / Build Tools (vswhere → env → well-known paths; cl.exe banner → compiler version/arch, localization-tolerant) but never installs or removes MSVC itself. - toolchain default msvc: detect + report (VS product, VC tools, cl version, std.ixx availability), persist stable 'msvc@system'; absent → install guidance (VS Installer C++ workload / winget BuildTools), exit non-zero. msvc@<prefix> acts as pin-verify against the detected install. - toolchain list: Windows 'System:' section; install msvc reports what's there or guides; remove msvc refuses (system component). - self doctor: Windows 'msvc (system)' check section. - manifest [toolchain] windows = "msvc@system" now actually works; msvc specs on non-Windows hosts error clearly. - build: native cl.exe (.ifc) pipeline is gated off with one owned message pointing at llvm@20.1.7 (MSVC-ABI Clang) until it lands. - detect(): cl.exe classification path (filename short-circuit, banner enrich); bmi_traits gains the MSVC .ifc branch. - tests: unit (banner/guidance/spec/traits) + e2e 95 (Windows, requires msvc cap) / 96 (non-Windows rejection); run_all.sh msvc capability. - design: .agents/docs/2026-07-13-msvc-system-toolchain-detection-design.md
1 parent b32f37f commit ebc577b

16 files changed

Lines changed: 723 additions & 13 deletions

.github/workflows/ci-windows.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,38 @@ jobs:
230230
"$MCPP" clean --bmi-cache
231231
"$MCPP" build 2>&1 | tee build.log; grep -q "Resolved llvm@20.1.7" build.log
232232
233+
# windows-latest ships VS 2022 Enterprise with the VC workload, so
234+
# msvc@system detection MUST succeed here — a failure is a regression
235+
# in the discovery/identification chain (vswhere → env → paths).
236+
- name: "Toolchain: MSVC — detection & selection (msvc@system)"
237+
shell: bash
238+
run: |
239+
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
240+
241+
out=$("$MCPP_SELF" toolchain default msvc); echo "$out"
242+
grep -q "Detected" <<<"$out"
243+
grep -q "msvc@system" <<<"$out"
244+
245+
"$MCPP_SELF" toolchain list | tee tc-list.txt
246+
grep -E '\*\s*msvc' tc-list.txt
247+
248+
"$MCPP_SELF" self doctor 2>&1 | tee doctor.txt || true
249+
grep -qi "msvc" doctor.txt
250+
251+
# native cl.exe builds are gated with one owned message
252+
TMP=$(mktemp -d); cd "$TMP"
253+
"$MCPP_SELF" new hello_msvc && cd hello_msvc
254+
set +e
255+
bout=$("$MCPP_SELF" build 2>&1); brc=$?
256+
set -e
257+
echo "$bout"
258+
test $brc -ne 0
259+
grep -q "not yet supported" <<<"$bout"
260+
261+
# restore the LLVM default for the remaining steps
262+
cd "$GITHUB_WORKSPACE"
263+
"$MCPP_SELF" toolchain default llvm@20.1.7
264+
233265
- name: Package Windows release zip
234266
id: package
235267
shell: bash

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,30 @@
33
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
44
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)
55
6+
## [0.0.88] — 2026-07-13
7+
8+
### 新增
9+
10+
- **MSVC 系统工具链支持(`msvc@system`,detection-first)**。MSVC 作为首个
11+
"系统工具链"接入:mcpp 负责**定位与识别**(vswhere → `VSINSTALLDIR`/
12+
`VS*COMNTOOLS` → 标准安装路径三级发现;cl.exe banner 解析出编译器版本/架构,
13+
容错本地化 banner),**从不安装/卸载** MSVC 本体。
14+
- `mcpp toolchain default msvc`:检测系统 MSVC,打印 VS 产品/VC tools/
15+
cl 版本与 `std.ixx`(import std)可用性,持久化稳定 spec `msvc@system`
16+
(不落具体版本,VS 升级后配置依然有效);未安装时输出安装指引
17+
(VS Installer C++ 工作负载 / `winget install …BuildTools`)并退出非零。
18+
`msvc@19.44` 形式为 pin 校验(仍取最新 VC tools,前缀不符则报错)。
19+
- `mcpp toolchain list`:Windows 上新增 `System:` 段展示检测到的 MSVC;
20+
`install msvc` 报告已装现状或给指引;`remove msvc` 明确拒绝(系统组件)。
21+
- `mcpp self doctor`:Windows 上新增 "msvc (system)" 检查段。
22+
- manifest 支持 `[toolchain] windows = "msvc@system"`(types.cppm 注释中的
23+
既有 schema 首次落地);非 Windows 主机使用 msvc spec 时给出明确报错。
24+
- `mcpp build`:原生 cl.exe 构建(.ifc 管线)**本版暂不支持**,在工具链解析
25+
后以单一 owned 错误信息拦截,并提示可用的 `llvm@20.1.7`(MSVC-ABI Clang)。
26+
- detect() 新增 cl.exe 分类路径(文件名短路,banner → 版本/triple),
27+
`bmi_traits` 预置 MSVC `.ifc` 分支;e2e 95/96 + 单测覆盖。
28+
- 设计文档:`.agents/docs/2026-07-13-msvc-system-toolchain-detection-design.md`
29+
630
## [0.0.87] — 2026-07-09
731

832
### 修复

docs/03-toolchains.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,52 @@ Available (run `mcpp toolchain install <compiler> <version>`):
6969

7070
The entry marked with `*` is the current default toolchain. `@mcpp/...` is shorthand for `~/.mcpp/...`, used to keep the output narrower.
7171

72+
## MSVC (System Toolchain, Windows)
73+
74+
MSVC is different from every other toolchain mcpp manages: it is a **system
75+
toolchain**. mcpp locates and identifies an installed Visual Studio / Build
76+
Tools — it never installs, updates, or removes MSVC itself.
77+
78+
```bash
79+
mcpp toolchain default msvc
80+
```
81+
82+
On a machine with MSVC installed, mcpp auto-locates it (via `vswhere.exe`,
83+
then `VSINSTALLDIR`/`VS*COMNTOOLS`, then the standard install paths),
84+
identifies the versions involved, and persists the stable spec `msvc@system`:
85+
86+
```
87+
Detected msvc 19.44.35211 (VS 2022 BuildTools) (VC tools 14.44.35207)
88+
cl: C:\Program Files\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64\cl.exe
89+
import std: available (std.ixx)
90+
Default set to msvc@system (was: llvm@20.1.7)
91+
```
92+
93+
If MSVC is **not** installed, mcpp prints installation guidance instead
94+
(Visual Studio Installer with the *Desktop development with C++* workload, or
95+
`winget install Microsoft.VisualStudio.2022.BuildTools`) and exits non-zero —
96+
install it yourself, then re-run the command.
97+
98+
`mcpp toolchain list` shows the detected MSVC in a separate `System:` section,
99+
and `mcpp self doctor` reports its status on Windows. In a manifest you can
100+
pin it per-platform:
101+
102+
```toml
103+
[toolchain]
104+
windows = "msvc@system"
105+
```
106+
107+
`msvc@<prefix>` (e.g. `msvc@19.44`) acts as a pin-verify: mcpp still uses the
108+
newest installed VC tools, but errors if the detected version doesn't match
109+
the prefix.
110+
111+
> [!NOTE]
112+
> Selection and detection are supported today; **building with native MSVC
113+
> (cl.exe) is not yet supported**`mcpp build` fails with a clear message
114+
> naming the detected version. For building on Windows use the MSVC-ABI Clang
115+
> toolchain: `mcpp toolchain default llvm@20.1.7` (it borrows the MSVC STL
116+
> from the same detected installation).
117+
72118
## Project-Level Version Pinning
73119

74120
If a project needs to pin a specific version rather than rely on the global default, declare it in the project's `mcpp.toml`:

mcpp.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mcpp"
3-
version = "0.0.87"
3+
version = "0.0.88"
44
description = "Modern C++ build & package management tool"
55
license = "Apache-2.0"
66
authors = ["mcpp-community"]

src/build/prepare.cppm

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import mcpp.modgraph.validate;
1818
import mcpp.toolchain.clang;
1919
import mcpp.toolchain.detect;
2020
import mcpp.toolchain.fingerprint;
21+
import mcpp.toolchain.msvc;
2122
import mcpp.toolchain.registry;
2223
import mcpp.toolchain.stdmod;
2324
import mcpp.toolchain.post_install;
@@ -682,7 +683,28 @@ prepare_build(bool print_fingerprint,
682683
}
683684
}
684685

685-
if (tcSpec.has_value() && *tcSpec != "system") {
686+
// msvc@system: a *system* toolchain — located on the machine, never
687+
// resolved through xim packages. mcpp does not install MSVC.
688+
bool tcSpecIsMsvc = false;
689+
if (tcSpec.has_value()) {
690+
if (auto s = mcpp::toolchain::parse_toolchain_spec(*tcSpec);
691+
s && mcpp::toolchain::is_system_toolchain(*s))
692+
tcSpecIsMsvc = true;
693+
}
694+
if (tcSpecIsMsvc) {
695+
if (!mcpp::platform::is_windows) {
696+
return std::unexpected(std::format(
697+
"toolchain '{}' is only available on Windows hosts", *tcSpec));
698+
}
699+
auto inst = mcpp::toolchain::msvc::detect_installation();
700+
if (!inst) {
701+
return std::unexpected(mcpp::toolchain::msvc::install_guidance());
702+
}
703+
explicit_compiler = inst->clPath;
704+
mcpp::ui::info("Resolved", std::format(
705+
"msvc@system → msvc {} ({})",
706+
inst->display_version(), inst->clPath.string()));
707+
} else if (tcSpec.has_value() && *tcSpec != "system") {
686708
auto spec = mcpp::toolchain::parse_toolchain_spec(*tcSpec);
687709
if (!spec || spec->version.empty()) {
688710
return std::unexpected(std::format(
@@ -841,6 +863,19 @@ prepare_build(bool print_fingerprint,
841863
auto tc = mcpp::toolchain::detect(explicit_compiler);
842864
if (!tc) return std::unexpected(tc.error().message);
843865

866+
// Native MSVC builds are gated off until the cl.exe/.ifc pipeline lands.
867+
// Selection & detection (`mcpp toolchain default msvc`, `list`, `doctor`)
868+
// work; the build must fail here with one owned message rather than an
869+
// incidental error deep in the GCC/Clang-shaped flag machinery.
870+
if (tc->compiler == mcpp::toolchain::CompilerId::MSVC) {
871+
return std::unexpected(std::format(
872+
"native MSVC (cl.exe) builds are not yet supported by mcpp.\n"
873+
" detected: msvc {} at {} (selection & detection work today)\n"
874+
" for building on Windows use the MSVC-ABI Clang toolchain instead:\n"
875+
" mcpp toolchain default llvm@20.1.7",
876+
tc->version, tc->binaryPath.string()));
877+
}
878+
844879
// For musl-gcc the toolchain is fully self-contained
845880
// (`<root>/x86_64-linux-musl/{include,lib}` is its own sysroot).
846881
// musl-gcc's `-dumpmachine` reports `x86_64-linux-musl`.

src/doctor.cppm

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import mcpp.build.plan;
1616
import mcpp.config;
1717
import mcpp.fallback.install_integrity;
1818
import mcpp.fetcher.progress;
19+
import mcpp.platform;
1920
import mcpp.platform.process;
2021
import mcpp.toolchain.detect;
22+
import mcpp.toolchain.msvc;
2123
import mcpp.toolchain.registry;
2224
import mcpp.toolchain.stdmod;
2325
import mcpp.toolchain.abi;
@@ -96,6 +98,30 @@ export int doctor_report() {
9698
ok(std::format("{} at {}", tc->label(), tc->binaryPath.string()));
9799
}
98100

101+
// Windows: report the system MSVC (msvc@system). Absence is a warning,
102+
// not an error — mcpp works with LLVM/Clang without it, and mcpp never
103+
// installs MSVC itself.
104+
if (mcpp::platform::is_windows) {
105+
mcpp::ui::status("Checking", "msvc (system)");
106+
if (auto inst = mcpp::toolchain::msvc::detect_installation()) {
107+
ok(std::format("msvc {}{} (VC tools {})",
108+
inst->display_version(),
109+
inst->vsProduct.empty()
110+
? std::string{}
111+
: std::format(" (VS {})", inst->vsProduct),
112+
inst->toolsVersion));
113+
ok(std::format("cl at {}", inst->clPath.string()));
114+
if (inst->hasStdModules) {
115+
ok("import std: std.ixx available");
116+
} else {
117+
warn("MSVC STL std.ixx missing (VC tools too old for import std?)");
118+
}
119+
} else {
120+
warn("msvc not detected — run `mcpp toolchain default msvc` for "
121+
"setup guidance (mcpp does not install MSVC)");
122+
}
123+
}
124+
99125
mcpp::ui::status("Checking", "std module");
100126
if (tc) {
101127
auto cacheRoot = mcpp::toolchain::default_cache_root();

src/toolchain/detect.cppm

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export import mcpp.toolchain.probe;
88
import std;
99
import mcpp.toolchain.clang;
1010
import mcpp.toolchain.gcc;
11+
import mcpp.toolchain.msvc;
1112
import mcpp.xlings;
1213

1314
export namespace mcpp::toolchain {
@@ -38,6 +39,17 @@ detect(const std::filesystem::path& explicit_compiler) {
3839

3940
Toolchain tc;
4041
tc.binaryPath = *bin_r;
42+
43+
// MSVC cl.exe has no --version / -dumpmachine / -print-sysroot; classify
44+
// it by filename and take a dedicated enrich path (banner → version,
45+
// arch → triple, std.ixx lookup). No runtime dirs / sysroot / payloads —
46+
// those concepts are GCC/Clang-shaped.
47+
if (auto stem = lower_copy(tc.binaryPath.stem().string()); stem == "cl") {
48+
if (auto r = mcpp::toolchain::msvc::enrich_toolchain_from_cl(tc); !r)
49+
return std::unexpected(r.error());
50+
return tc;
51+
}
52+
4153
tc.compilerRuntimeDirs = discover_compiler_runtime_dirs(tc.binaryPath);
4254
auto envPrefix = compiler_env_prefix(tc);
4355

src/toolchain/fingerprint.cppm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import mcpp.toolchain.detect;
1818

1919
export namespace mcpp::toolchain {
2020

21-
inline constexpr std::string_view MCPP_VERSION = "0.0.87";
21+
inline constexpr std::string_view MCPP_VERSION = "0.0.88";
2222

2323
struct FingerprintInputs {
2424
Toolchain toolchain;

0 commit comments

Comments
 (0)