Skip to content

Commit ccdbd22

Browse files
committed
fix(toolchain): a managed toolset without its SDK reported success
Self-review catch. `installation_at()` succeeding means cl.exe is where the declared version says it should be -- it says nothing about the ucrt/um headers, which arrive as a separate package dependency and can therefore fail on their own. The install printed "Installed", and the build died inside the ucrt headers much later. That is the half-installed state `has_usable_msvc()` was written for; this applies the same judgement to the managed origin, and names the dependency that must have failed rather than leaving the reader to work it out. Also: `msvc_print_detected` now takes the label. "Detected" is a claim about probing the machine, and printing it after unpacking a payload the caller NAMED describes the wrong thing -- quietly, and in exactly the direction this whole change is about.
1 parent d4a944e commit ccdbd22

1 file changed

Lines changed: 29 additions & 3 deletions

File tree

src/toolchain/lifecycle.cppm

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,13 @@ int msvc_wrong_host() {
186186
return 1;
187187
}
188188

189-
void msvc_print_detected(const mcpp::toolchain::msvc::MsvcInstallation& inst) {
190-
mcpp::ui::status("Detected", std::format(
189+
// `label` names the ORIGIN, because the two are not the same event.
190+
// "Detected" is a claim about probing the machine, and saying it after
191+
// unpacking a payload the caller named would describe the wrong thing —
192+
// quietly, and in exactly the direction this whole change is about.
193+
void msvc_print_detected(const mcpp::toolchain::msvc::MsvcInstallation& inst,
194+
std::string_view label = "Detected") {
195+
mcpp::ui::status(label, std::format(
191196
"msvc {}{} (VC tools {})",
192197
inst.display_version(),
193198
inst.vsProduct.empty() ? "" : std::format(" (VS {})", inst.vsProduct),
@@ -197,6 +202,26 @@ void msvc_print_detected(const mcpp::toolchain::msvc::MsvcInstallation& inst) {
197202
inst.hasStdModules ? "available (std.ixx)" : "not available");
198203
}
199204

205+
// The Windows SDK is the OTHER half of a usable MSVC, and a payload that
206+
// unpacked a compiler without it is a half-installed state: cl.exe is right
207+
// there, so everything reports success, and the build dies inside the ucrt
208+
// headers much later. `has_usable_msvc()` exists for exactly this reason;
209+
// this is the same judgement applied to the managed origin, where the SDK
210+
// arrives as a package dependency and can therefore fail on its own.
211+
void msvc_warn_if_sdk_missing(const mcpp::toolchain::msvc::MsvcInstallation& inst) {
212+
auto roots = mcpp::toolchain::msvc::sibling_sdk_roots(inst.clPath);
213+
if (auto sdk = mcpp::toolchain::msvc::find_windows_sdk(roots)) {
214+
std::println(" windows sdk: {} ({})",
215+
sdk->version, sdk->root.string());
216+
return;
217+
}
218+
mcpp::ui::warning(
219+
"the toolset installed, but no Windows SDK was found next to it.\n"
220+
" cl.exe cannot compile anything without the ucrt/um headers.\n"
221+
" The toolset declares `xim:windows-sdk` as a dependency, so this\n"
222+
" means that dependency did not install — check `xlings list`.");
223+
}
224+
200225
EffectiveDefault effective_default_toolchain(const mcpp::config::GlobalConfig& cfg) {
201226
std::error_code ec;
202227
auto mpath = std::filesystem::current_path(ec) / "mcpp.toml";
@@ -599,7 +624,8 @@ export int toolchain_install(const mcpp::config::GlobalConfig& cfg,
599624
payload->root.string(), pkg.ximVersion));
600625
return 1;
601626
}
602-
msvc_print_detected(*inst);
627+
msvc_print_detected(*inst, "Installed");
628+
msvc_warn_if_sdk_missing(*inst);
603629
mcpp::ui::status("Installed",
604630
std::format("{} → {}", pkg.display_spec(), inst->clPath.string()));
605631
if (cfg.defaultToolchain.empty()) {

0 commit comments

Comments
 (0)