Skip to content

Commit 0ea64e7

Browse files
committed
fix: keep Clang managed system headers hermetic
1 parent bed4876 commit 0ea64e7

3 files changed

Lines changed: 11 additions & 1 deletion

File tree

‎modules/toolchain-model/src/linkmodel.cppm‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ struct ToolchainLinkModel {
8989
// Compile-side flags as argv tokens. Each entry is ONE argv word.
9090
std::vector<std::string> compile_tokens(const PathEscape& esc) const {
9191
std::vector<std::string> out;
92+
// A managed libc supplies the complete system header surface. Keep
93+
// Clang's resource headers while refusing an ambient /usr/include
94+
// fallback, including when the driver cfg is explicitly bypassed.
95+
if (mode == CLibMode::PayloadFirst && clangDriver)
96+
out.push_back("-nostdlibinc");
9297
if (mode == CLibMode::Sysroot)
9398
out.push_back("--sysroot=" + esc(sysroot));
9499
// PayloadFirst headers: clang takes -isystem; GCC needs -idirafter so

‎src/toolchain/post_install.cppm‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ export void fixup_clang_cfg(const std::filesystem::path& payloadRoot,
312312
if (std::filesystem::exists(cxxInclude))
313313
cxxOnly += "-isystem " + cxxInclude.string() + "\n";
314314
} else {
315+
if constexpr (mcpp::platform::is_linux)
316+
common += "-nostdlibinc\n";
315317
if (!glibcLibDir.empty()) {
316318
auto loader = resolve_loader(glibcLibDir, triple);
317319
common += "-B" + glibcLibDir.string() + "\n";
@@ -525,7 +527,7 @@ void llvm_post_install_fixup(const mcpp::config::GlobalConfig& cfg,
525527
// runtime libs. Idempotent via a content-fingerprinted marker.
526528
//
527529
// Bump when the fixup logic changes so existing installs re-run it.
528-
constexpr std::string_view kFixupRev = "hermetic-4-exact-runtime";
530+
constexpr std::string_view kFixupRev = "hermetic-5-managed-headers";
529531

530532
// What the fixup DID, so the caller can decide how loud to be about it.
531533
//

‎tests/unit/test_linkmodel.cpp‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ TEST(LinkModel, ClangCfgPayloadFirstCarriesCrtDiscovery) {
126126
EXPECT_NE(link.find("--dynamic-linker=" + lm.loader.string()), std::string::npos);
127127

128128
auto compile = lm.compile_flags(ident);
129+
EXPECT_NE(compile.find("-nostdlibinc"), std::string::npos);
129130
EXPECT_NE(compile.find("-isystem"), std::string::npos);
130131
EXPECT_EQ(compile.find("-idirafter"), std::string::npos);
131132
}
@@ -156,6 +157,7 @@ TEST(LinkModel, GccSysrootWinsOverPayload) {
156157
auto lm = tc::resolve_link_model(t);
157158
EXPECT_EQ(lm.mode, tc::CLibMode::Sysroot);
158159
EXPECT_NE(lm.compile_flags(ident).find("--sysroot="), std::string::npos);
160+
EXPECT_EQ(lm.compile_flags(ident).find("-nostdlibinc"), std::string::npos);
159161
EXPECT_NE(lm.link_flags(ident).find("--sysroot="), std::string::npos);
160162
// Kernel headers exist in the sysroot → no supplement.
161163
EXPECT_TRUE(lm.systemIncludes.empty());
@@ -197,6 +199,7 @@ TEST(LinkModel, GccPayloadEmitsIdirafterAndItsOwnAddressing) {
197199
// Headers still differ by driver: libstdc++'s #include_next wrappers need
198200
// -idirafter, and that has not changed.
199201
EXPECT_NE(lm.compile_flags(ident).find("-idirafter"), std::string::npos);
202+
EXPECT_EQ(lm.compile_flags(ident).find("-nostdlibinc"), std::string::npos);
200203

201204
// Addressing no longer differs. GCC used to be left to its install-time
202205
// specs here, which made the RUN side a per-toolchain-install decision

0 commit comments

Comments
 (0)