Skip to content

Commit 4541b05

Browse files
committed
fix: validate probed sysroot carries C headers; diagnostic std-precompile error
A probed/remapped sysroot that exists but lacks stdlib.h (e.g. a partially-bootstrapped sandbox subos in a fresh MCPP_HOME) silently shadowed the payload -isystem fallback in both stdmod and flags, failing deep in the std module build. probe_sysroot now only returns a sysroot that actually contains the C headers (glibc usr/include or musl include layout) so all consumers uniformly fall through to payload paths. std-precompile failures now include the full compile command for actionable diagnosis.
1 parent c7c8ff8 commit 4541b05

2 files changed

Lines changed: 24 additions & 4 deletions

File tree

src/toolchain/probe.cppm

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,20 +271,37 @@ probe_target_triple(const std::filesystem::path& compilerBin,
271271
std::filesystem::path
272272
probe_sysroot(const std::filesystem::path& compilerBin,
273273
const std::string& envPrefix) {
274+
// A sysroot is only usable if it actually carries the C library headers.
275+
// A merely-existing directory (e.g. a partially-bootstrapped sandbox
276+
// subos) would silently shadow the payload -isystem fallback and produce
277+
// "stdlib.h: No such file or directory" deep inside the std module build.
278+
auto usable = [](const std::filesystem::path& root) {
279+
return std::filesystem::exists(root / "usr" / "include" / "stdlib.h") // glibc layout
280+
|| std::filesystem::exists(root / "include" / "stdlib.h"); // musl layout
281+
};
282+
274283
// 1. Ask the compiler directly (works for GCC; Clang often doesn't support it).
275284
auto r = run_capture(std::format("{}{} -print-sysroot {}",
276285
envPrefix,
277286
mcpp::xlings::shq(compilerBin.string()),
278287
mcpp::platform::null_redirect));
279288
if (r) {
280289
auto s = trim_line(*r);
281-
if (!s.empty() && std::filesystem::exists(s)) return s;
290+
if (!s.empty() && std::filesystem::exists(s)) {
291+
if (usable(s)) return s;
292+
mcpp::log::debug("probe", std::format(
293+
"sysroot '{}' exists but lacks usr/include/stdlib.h — ignoring", s));
294+
}
282295

283296
// GCC bakes the build-time sysroot into the binary. For xlings-built
284297
// GCC this is a path like <buildhost>/.xlings/subos/default that
285298
// doesn't exist on the user's machine. Remap via fallback module.
286-
if (auto remapped = mcpp::fallback::remap_xlings_baked_sysroot(s, compilerBin))
287-
return *remapped;
299+
if (auto remapped = mcpp::fallback::remap_xlings_baked_sysroot(s, compilerBin)) {
300+
if (usable(*remapped)) return *remapped;
301+
mcpp::log::debug("probe", std::format(
302+
"remapped sysroot '{}' lacks usr/include/stdlib.h — ignoring",
303+
remapped->string()));
304+
}
288305
}
289306

290307
// 2. Parse the compiler driver config file (Clang .cfg).

src/toolchain/stdmod.cppm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,11 @@ namespace {
6161
std::expected<std::string, StdModError> run_capture_command(const std::string& cmd) {
6262
auto r = mcpp::platform::process::capture(cmd);
6363
if (r.exit_code != 0) {
64+
// Include the command: its --sysroot/-isystem flags are the first
65+
// thing needed to diagnose header-resolution failures.
6466
return std::unexpected(StdModError{
65-
std::format("std module precompile failed (rc={}):\n{}", r.exit_code, r.output)});
67+
std::format("std module precompile failed (rc={}):\n{}\ncommand: {}",
68+
r.exit_code, r.output, cmd)});
6669
}
6770
return r.output;
6871
}

0 commit comments

Comments
 (0)