Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,26 @@
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。

## [0.0.83] — 2026-07-07
## [0.0.84] — 2026-07-08

### 修复

- **clang 驱动配置文件(cfg)补全头文件搜索路径**:`fixup_clang_cfg` 再生成的
cfg 此前仅包含链接相关条目(`-B`/`-L`/动态链接器/rpath),缺少 C 标准库头文件
与内核头文件的搜索路径。该 cfg 服务于直接调用打包内 `clang`/`clang++`
(不经由 mcpp)的场景:缺少这两项时,此类调用仅在宿主系统存在
`/usr/include` 时可编译(依赖宿主环境,违背沙箱自包含约束),在无宿主开发头
文件的环境中直接报头文件缺失错误。本次补充
`-isystem <glibc payload>/include` 与 `-isystem <linux-headers payload>/include`,
置于 libc++ 头文件条目之后以保持 `#include_next` 搜索链;生成内容与
xim-pkgindex 侧 `llvm.lua` 安装期生成的 cfg 保持一致,消除两个生成端之间的
内容差异。fixup 修订号升级至 `hermetic-3`,既有 payload 在下一次构建时自动
重新收敛,无需重新安装。验证方式:以 `--sysroot=<空目录>` 屏蔽宿主头文件后,
由 cfg 驱动的 `clang`/`clang++` 直接调用编译与运行均通过;移除上述搜索路径的
对照组按预期失败。mcpp 自身构建路径不受影响(构建 flags 由 linkmodel
独立提供,不读取 cfg)。



### 修复

Expand Down
6 changes: 3 additions & 3 deletions docs/08-toolchain-internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ mcpp's sight — trust-but-verify is the only reliable semantic.
mcpp read-only + verification. The pipeline here is the compatibility
layer until then, and the self-healing mechanism for drift either way.

## 5. The clang cfg: for humans only
## 5. The clang cfg: direct-invocation support only

`bin/clang++.cfg` exists so a human running the bundled `clang++` directly
gets a working, hermetic compiler. mcpp's own builds never read it
`bin/clang++.cfg` exists so that direct invocations of the bundled
`clang++` (outside mcpp) get a working, hermetic compiler configuration. mcpp's own builds never read it
(`--no-default-config` always). The fixup pipeline **regenerates** it
deterministically from the link model — same payload ⇒ byte-identical cfg on
every machine and install path — rather than line-patching whatever an
Expand Down
6 changes: 3 additions & 3 deletions docs/zh/08-toolchain-internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ glibc、payload 从别的 home 继承而来)发生在 mcpp 视野之外,trust-bu
新 home 时——mcpp 退为只读 + 校验。本管线在那之前是兼容层,也是双向漂移的
自愈机制。

## 5. clang cfg:只服务人类
## 5. clang cfg:仅服务直接调用场景

`bin/clang++.cfg` 的存在意义是:人类直接敲打包内 `clang++` 时得到一个可用且
hermetic 的编译器。mcpp 自己的构建从不读它(永远 `--no-default-config`)。
`bin/clang++.cfg` 的职责是:直接调用打包内 `clang++`(不经由 mcpp)时,
获得可用且 hermetic 的编译器配置。mcpp 自己的构建从不读它(永远 `--no-default-config`)。
fixup 管线从链接模型**确定性再生**它——同一 payload ⇒ 任何机器、任何安装路径
产出字节一致的 cfg——而不是对装机产物做行级补丁。Linux 上内容为:CRT 发现
(`-B`)、payload loader + rpath、lld/compiler-rt/libunwind、C++ 驱动附加
Expand Down
2 changes: 1 addition & 1 deletion mcpp.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mcpp"
version = "0.0.83"
version = "0.0.84"
description = "Modern C++ build & package management tool"
license = "Apache-2.0"
authors = ["mcpp-community"]
Expand Down
2 changes: 1 addition & 1 deletion src/toolchain/fingerprint.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import mcpp.toolchain.detect;

export namespace mcpp::toolchain {

inline constexpr std::string_view MCPP_VERSION = "0.0.83";
inline constexpr std::string_view MCPP_VERSION = "0.0.84";

struct FingerprintInputs {
Toolchain toolchain;
Expand Down
31 changes: 28 additions & 3 deletions src/toolchain/post_install.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ export void fixup_clang_cfg(const std::filesystem::path& payloadRoot,
}
}

std::string common, cxxOnly;
std::string common, cxxOnly, cHdr;
auto cxxInclude = payloadRoot / "include" / "c++" / "v1";
if constexpr (mcpp::platform::is_macos) {
// macOS keeps its historical cfg semantics: the C library and the
Expand All @@ -256,6 +256,28 @@ export void fixup_clang_cfg(const std::filesystem::path& payloadRoot,
}
common += "-fuse-ld=lld\n--rtlib=compiler-rt\n--unwindlib=libunwind\n";

// HEADER axis (C and C++ drivers alike): the C library and kernel
// headers come from the same payloads the link axis uses. Without
// these, a direct `clang hello.c` only works when the HOST happens
// to ship /usr/include — silently non-hermetic, broken on
// header-less machines. For C++ they must come AFTER the libc++
// block (its C-header wrappers reach libc via #include_next), so
// they are collected separately and appended in order below —
// byte-consistent with what llvm.lua's install hook generates.
if (!glibcLibDir.empty()) {
auto glibcInclude = glibcLibDir.parent_path() / "include";
if (std::filesystem::exists(glibcInclude / "features.h"))
cHdr += "-isystem " + glibcInclude.string() + "\n";
constexpr std::string_view kLinuxLimits = "include/linux/limits.h";
auto linuxHeaders = mcpp::xlings::paths::find_sibling_package(
payloadRoot / "bin" / "clang++", "linux-headers", kLinuxLimits);
if (!linuxHeaders)
linuxHeaders = mcpp::xlings::paths::find_home_tool(
"linux-headers", kLinuxLimits);
if (linuxHeaders)
cHdr += "-isystem " + (*linuxHeaders / "include").string() + "\n";
}

if (std::filesystem::exists(cxxInclude)) {
cxxOnly += "-nostdinc++\n-stdlib=libc++\n";
cxxOnly += "-isystem " + cxxInclude.string() + "\n";
Expand All @@ -264,6 +286,9 @@ export void fixup_clang_cfg(const std::filesystem::path& payloadRoot,
auto tripleInclude = payloadRoot / "include" / triple / "c++" / "v1";
if (std::filesystem::exists(tripleInclude))
cxxOnly += "-isystem " + tripleInclude.string() + "\n";
}
cxxOnly += cHdr;
if (!triple.empty()) {
auto tripleLib = payloadRoot / "lib" / triple;
if (std::filesystem::exists(tripleLib)) {
cxxOnly += "-L" + tripleLib.string() + "\n";
Expand All @@ -281,7 +306,7 @@ export void fixup_clang_cfg(const std::filesystem::path& payloadRoot,
if (!name.ends_with(".cfg")) continue;
const bool isCxx = name.find("++") != std::string::npos;
std::ofstream os(it->path());
os << common << (isCxx ? cxxOnly : std::string{});
os << common << (isCxx ? cxxOnly : cHdr);
}
}

Expand Down Expand Up @@ -376,7 +401,7 @@ void llvm_post_install_fixup(const mcpp::config::GlobalConfig& cfg,
// runtime libs. Idempotent via a content-fingerprinted marker.
//
// Bump when the fixup logic changes so existing installs re-run it.
constexpr std::string_view kFixupRev = "hermetic-2";
constexpr std::string_view kFixupRev = "hermetic-3";

export void ensure_post_install_fixup(const mcpp::config::GlobalConfig& cfg,
const std::filesystem::path& payloadRoot,
Expand Down
4 changes: 2 additions & 2 deletions src/toolchain/probe.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ probe_sysroot(const std::filesystem::path& compilerBin,
// artifact that mcpp's own fixup pipeline now REGENERATES without a
// --sysroot line (the C library comes from the payload link model), so
// the mined value existed only on never-fixed-up installs and pointed at
// an environment directory the payload doesn't own. The cfg is for
// humans running clang++ directly; builds derive everything from the
// an environment directory the payload doesn't own. The cfg serves
// direct driver invocations only; builds derive everything from the
// link model. Kept as a diagnostic only.
if (auto cfg = mcpp::fallback::parse_clang_cfg_sysroot(compilerBin)) {
mcpp::log::debug("probe", std::format(
Expand Down
Loading