Skip to content

Commit 45dec7f

Browse files
committed
fix: bypass stale clang++.cfg for macOS std module precompile
When xlings copies LLVM to mcpp's sandbox, clang++.cfg retains hardcoded absolute paths from the original install (--sysroot and -isystem pointing to ~/.xlings/... instead of ~/.mcpp/...). These stale paths cause _CTYPE_A undeclared errors during std module precompilation. Fix: on macOS Clang, pass --no-default-config to ignore the stale cfg, then explicitly provide the correct -isystem (libc++ headers from the sandbox LLVM root) and --sysroot (active SDK from xcrun). This produces the same header search behavior as a fresh clang++ invocation with the correct paths.
1 parent ae7114e commit 45dec7f

1 file changed

Lines changed: 20 additions & 14 deletions

File tree

src/toolchain/stdmod.cppm

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,27 @@ std::expected<StdModule, StdModError> ensure_built(
9292
: mcpp::toolchain::gcc::std_bmi_path(sm.cacheDir);
9393
sm.objectPath = sm.cacheDir / "std.o";
9494

95+
// Build sysroot + include flags for std module precompilation.
96+
// On macOS, xlings LLVM's clang++.cfg contains hardcoded --sysroot and
97+
// -isystem paths from the original install location. When the LLVM package
98+
// is copied to mcpp's sandbox, these cfg paths become stale (still point
99+
// to the original xlings directory). We override both:
100+
// --sysroot → current active SDK (from xcrun)
101+
// --no-default-config → ignore stale cfg entirely
102+
// -isystem → correct libc++ headers in the sandbox copy
95103
std::string sysroot_flag;
96-
if (!tc.sysroot.empty()) {
97-
// macOS (apple/darwin target): do NOT pass --sysroot for std module
98-
// precompilation. xlings LLVM's clang++.cfg already contains a
99-
// --sysroot for the macOS SDK plus -isystem for libc++ headers.
100-
// Passing an explicit --sysroot on the command line (even the same
101-
// value) changes Clang's internal header search order, causing the
102-
// macOS SDK's ___wctype.h to not find _CTYPE_A (defined in a
103-
// sibling C runtime header that's only included transitively via
104-
// the cfg's default search path). The CI "import std" test proves
105-
// that running clang++ WITHOUT an explicit --sysroot works correctly.
106-
bool is_macos = tc.targetTriple.find("apple") != std::string::npos
107-
|| tc.targetTriple.find("darwin") != std::string::npos;
108-
if (!is_macos)
109-
sysroot_flag = std::format(" --sysroot='{}'", tc.sysroot.string());
104+
bool is_macos = tc.targetTriple.find("apple") != std::string::npos
105+
|| tc.targetTriple.find("darwin") != std::string::npos;
106+
if (is_macos && is_clang(tc)) {
107+
// Ignore the stale clang++.cfg and provide correct flags directly.
108+
auto llvmRoot = tc.binaryPath.parent_path().parent_path();
109+
auto libcxxInclude = llvmRoot / "include" / "c++" / "v1";
110+
sysroot_flag = " --no-default-config";
111+
sysroot_flag += std::format(" -isystem'{}'", libcxxInclude.string());
112+
if (auto sdk = mcpp::platform::macos::sdk_path())
113+
sysroot_flag += std::format(" --sysroot='{}'", sdk->string());
114+
} else if (!tc.sysroot.empty()) {
115+
sysroot_flag = std::format(" --sysroot='{}'", tc.sysroot.string());
110116
}
111117

112118
bool std_cached = std::filesystem::exists(sm.bmiPath) && std::filesystem::exists(sm.objectPath);

0 commit comments

Comments
 (0)