Skip to content

Commit 3f9a369

Browse files
authored
fix: remove subos sysroot override, use payload paths for toolchain sysroot (#62)
* fix: remove subos sysroot override, use payload paths for toolchain sysroot (#62) Remove M5.5 logic that forced tc->sysroot to mcpp's xlings subos (~/.mcpp/registry/subos/default). The subos created by `xlings self init` lacks linux kernel headers (linux/limits.h, asm/, asm-generic/), causing std module precompilation to fail on user machines. Root cause: commit 063fb6f changed MCPP_HOME to ~/.mcpp/, where the subos exists but is incomplete. M5.5 only checked exists(usr/include) and overwrote the toolchain's correct sysroot. CI never caught this because its subos is fully populated by `xlings self install`. Design principle: mcpp uses xlings only as a package index + download tool. Sysroot comes from the toolchain payload itself, not from subos. Changes: - cli.cppm: delete M5.5 subos sysroot override entirely - probe.cppm: parse clang++.cfg --sysroot= when -print-sysroot fails (Clang doesn't support -print-sysroot), so tc->sysroot reflects the payload's actual configuration - stdmod.cppm: generalize --no-default-config from macOS-only to all Clang toolchains with a cfg file (cfg paths become stale after mcpp copies the payload to its sandbox) - flags.cppm: sync the same --no-default-config logic for regular compilation flags * fix: GCC sysroot fallback — remap stale build-time path to registry GCC bakes the build-time sysroot into the binary via --with-sysroot. For xlings-built GCC this is a path like <buildhost>/.xlings/subos/default that doesn't exist on the user's machine. When -print-sysroot returns such a non-existent path ending in subos/default, remap it to the equivalent sysroot relative to the compiler's own xpkgs directory. This is payload-derived (from the compiler binary's location in the registry), not a config-level dependency on subos. * fix: add target-specific libc++ include path for --no-default-config When bypassing clang++.cfg with --no-default-config, we must provide both libc++ include paths that the cfg originally supplied: -isystem <llvmRoot>/include/c++/v1 -isystem <llvmRoot>/include/<triple>/c++/v1 The target-specific path contains __config_site which is required by __config. Without it, std module precompilation fails with '__config_site' file not found. * fix: restrict --no-default-config to macOS only On Linux, clang++.cfg contains essential linker flags (-fuse-ld=lld, --rtlib=compiler-rt, --unwindlib=libunwind). Using --no-default-config strips these, causing "cannot find crtbeginS.o" link failures because clang falls back to system GNU ld looking for GCC runtime objects. On Linux, let the cfg apply normally. The cfg's --sysroot points to the xlings subos which is valid and complete. Pass --sysroot explicitly only when needed (to override a stale cfg value), leveraging the fact that command-line --sysroot takes precedence over the cfg's value. Keep --no-default-config for macOS only, where the cfg-baked paths genuinely become stale (pointing to CommandLineTools SDK when Xcode SDK is active). * feat: payload-first sysroot — assemble compile env from xpkgs payloads Replace --sysroot dependency on xlings subos with fine-grained -isystem paths derived from sibling xpkgs payloads (glibc, linux-headers). Phase 2: PayloadPaths model - Add PayloadPaths struct to Toolchain model (glibcInclude, glibcLib, linuxInclude) - probe_payload_paths() finds sibling glibc and linux-headers xpkgs via find_sibling_package() which searches across all index prefixes - Falls back to host /usr/include for linux kernel headers if no xpkg found Phase 3: Payload-first flags - flags.cppm: use -isystem for glibc + linux-headers instead of --sysroot; Clang with cfg uses --no-default-config + explicit flags including -fuse-ld=lld, --rtlib=compiler-rt, --unwindlib=libunwind - stdmod.cppm: unified Clang cfg bypass on all platforms for std module precompile (no linker needed, so --no-default-config is safe) Phase 4: Clang cfg fixup - fixup_clang_cfg() rewrites clang++.cfg paths after payload copy, similar to fixup_gcc_specs() for GCC - Called during `mcpp toolchain install llvm` Phase 5: Sysroot dependency auto-install - Toolchain install ensures glibc and linux-headers xpkgs are installed before the main toolchain package * fix: GCC needs --sysroot for include-fixed, supplement with -isystem GCC's include-fixed directory contains stdlib.h wrappers that use #include_next to find the sysroot's stdlib.h. This mechanism only works with --sysroot, not standalone -isystem paths. Fix: for GCC, keep --sysroot from probe_sysroot() and supplement with -isystem for linux kernel headers from payload when the probed sysroot is missing them. For Clang, continue using --no-default-config + explicit -isystem (Clang doesn't have include-fixed). * fix: add -nostdinc++ -stdlib=libc++ for Clang --no-default-config When bypassing clang++.cfg, the cfg's -nostdinc++ and -stdlib=libc++ flags are also stripped. Without -nostdinc++, Clang may find host libstdc++ headers before the payload's libc++ headers. Without -stdlib=libc++, Clang defaults to libstdc++ runtime. Also remove the /usr/include fallback for linux-headers — mixing host headers with xpkg glibc causes bits/wordsize.h conflicts. * feat: ensure sysroot complete by symlinking from payload xpkgs When GCC's probed sysroot (subos/default) is missing linux kernel headers or glibc headers, symlink them from the payload xpkgs: - linux/, asm/, asm-generic/ ← scode-x-linux-headers xpkg - features.h, bits/, etc. ← xim-x-glibc xpkg This makes mcpp self-sufficient: it uses subos/default as a sysroot directory for GCC's include-fixed mechanism, but actively populates it from payload rather than depending on xlings init completeness. Principle: subos is just a directory layout that mcpp manages. Content comes from xpkgs payloads. Clang doesn't use subos at all (--no-default-config + explicit -isystem from payload). * fix: include MSVC effective triple in fingerprint (Windows) Clang on Windows auto-detects the MSVC version at compile time and embeds it in module AST files (e.g. x86_64-pc-windows-msvc19.44.35227). But -dumpmachine returns just x86_64-pc-windows-msvc (no version). When MSVC updates a patch version (35226 → 35227), the fingerprint didn't change, so mcpp reused cached std.pcm compiled for the old version → "AST file was compiled for different target" error. Fix: probe clang's -print-effective-triple which includes the MSVC version, and append to driverIdent for fingerprint computation. Also: ensure sysroot complete by symlinking linux kernel headers from payload xpkgs into the GCC sysroot directory. * feat: add is_msvc_target() predicate + ci-fresh-install workflow Refactor: - Extract is_msvc_target() to model.cppm alongside is_musl_target() - Replace 3 scattered tc.targetTriple.find("msvc") checks in clang.cppm, detect.cppm, provider.cppm CI: - Add ci-fresh-install.yml: validates first-time user install flow on all platforms (Linux, macOS, Windows) with zero cache. - Tests: xlings install mcpp → self-host build → mcpp new → mcpp run - Tests: import std with both GCC and LLVM (Linux), LLVM (macOS), LLVM+MSVC STL (Windows) - Catches issues that cached CI misses: incomplete sysroot, stale cfg paths, missing xpkg dependencies * fix: ci-fresh-install — correct asset names + MCPP_VENDORED_XLINGS - macOS tarball: macos-aarch64 → macosx-arm64 (matches release assets) - Windows: use explicit extract dir name - All steps: export MCPP_VENDORED_XLINGS so freshly-built mcpp uses the installed xlings binary for package operations - Use MCPP_BOOTSTRAP for bootstrap mcpp, MCPP for freshly-built - Set MCPP_HOME explicitly for consistent sandbox location * fix: ci-fresh-install — simulate real user, no extra config Strip all env overrides, self-host builds, and MCPP_VENDORED_XLINGS. Simulate exactly what a real user does: 1. Install xlings 2. xlings install mcpp -y 3. mcpp new hello && cd hello && mcpp run * fix: ci-fresh-install Windows — use pwsh for native path handling Git Bash on Windows mangles GITHUB_PATH entries. Switch to pwsh which handles Windows paths natively. * fix: ci-fresh-install — workflow_dispatch only This CI tests xlings-distributed mcpp (not the PR's code), so it will fail until fixes are released to the xlings mcpp package. Change to manual trigger only — run after a release to verify the real end-to-end user experience. * fix: ci-fresh-install — build PR's mcpp then test fresh user flow Restore PR trigger. Flow: 1. Bootstrap xlings + old mcpp via xlings install 2. Build THIS PR's mcpp from source (self-host) 3. Use freshly-built mcpp to simulate fresh user: new → run 4. Linux: test both GCC (default) and LLVM toolchains 5. macOS: test LLVM (default) 6. Windows: test LLVM + MSVC STL * ci: retrigger after clearing Windows cache * fix: ci-fresh-install — simplify, use GITHUB_PATH only - Remove all extra env vars (MCPP_VENDORED_XLINGS, XLINGS_BIN) - Just add xlings bin to GITHUB_PATH, everything else works - Windows: set PATH inline in bootstrap step so xlings install mcpp can find xlings immediately * fix: ci-fresh-install — no $MCPP var, just PATH; add mirror for LLVM - Remove $MCPP variable, put freshly-built mcpp dir on PATH instead - All steps just use `mcpp` command directly - Linux LLVM step: add `mcpp self config --mirror GLOBAL` before toolchain install (CI runners are outside CN) - Windows: use pwsh throughout for native path handling * fix: ci-fresh-install — test released mcpp, not freshly-built Use xlings-installed mcpp directly to test: 1. mcpp build (self-host compile) 2. mcpp new hello → mcpp run (default toolchain) 3. Linux: install LLVM → mcpp new → mcpp run (continue-on-error since released mcpp may not have latest fixes yet) No extra env vars, no $MCPP variable — just mcpp on PATH via xlings. * chore: move ci-fresh-install to separate PR The fresh-install CI workflow tests the released mcpp binary via xlings, not this PR's code. Move it to its own branch/PR to keep this PR focused on the sysroot fix. * ci: multi-toolchain coverage on Linux, remove continue-on-error tests Linux CI now tests all 3 toolchains with freshly-built mcpp: - GCC 16.1.0: mcpp new → build → run - musl-gcc 15.1.0: mcpp new → build → run - LLVM 20.1.7: install + mcpp new → build → run Remove continue-on-error "Fresh user experience" tests from all 3 CI workflows — moved to separate ci-fresh-install.yml (PR #63). Those tests validate the xlings-distributed mcpp binary, not the PR's code, so they don't belong in the main CI gate. * fix: actually update ci.yml (previous edit didn't take effect)
1 parent 0e67801 commit 3f9a369

14 files changed

Lines changed: 1141 additions & 95 deletions
Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
# Linux sysroot 缺少内核头文件导致 std module 预编译失败
2+
3+
## 现象
4+
5+
在用户机器上(非 CI),使用 LLVM 或 GCC 工具链执行 `mcpp run` / `mcpp build` 时,
6+
std module 预编译失败:
7+
8+
```
9+
/home/speak/.mcpp/registry/subos/default/usr/include/bits/local_lim.h:38:10:
10+
fatal error: 'linux/limits.h' file not found
11+
```
12+
13+
GCC 和 Clang 均受影响,问题是系统性的。
14+
15+
## 根因
16+
17+
### 直接原因:M5.5 sysroot 覆盖逻辑
18+
19+
`cli.cppm:1192-1203` 中的 M5.5 逻辑,将 `tc->sysroot` 强制覆盖为 mcpp 自己的
20+
subos(`~/.mcpp/registry/subos/default`):
21+
22+
```cpp
23+
if (!isMuslTc) {
24+
if (auto cfg = get_cfg(); cfg) {
25+
auto mcppSubos = (*cfg)->xlingsHome() / "subos" / "default";
26+
if (std::filesystem::exists(mcppSubos / "usr" / "include")) {
27+
tc->sysroot = mcppSubos;
28+
}
29+
}
30+
}
31+
```
32+
33+
### 触发 commit
34+
35+
**`063fb6f`** — 将 MCPP_HOME 从 xpkgs 包目录改为 `~/.mcpp/`,使 M5.5
36+
找到一个存在但不完整的 subos。
37+
38+
### CI/e2e 未发现的原因
39+
40+
CI 的 subos 由 `xlings self install` 完整初始化(含内核头文件),e2e 测试
41+
通过 `_inherit_toolchain.sh` 继承宿主完整 subos。
42+
43+
---
44+
45+
## 设计分析:当前问题的本质
46+
47+
### 当前架构的矛盾
48+
49+
mcpp 的工具链管理存在一个架构层面的矛盾:
50+
51+
```
52+
┌─────────────────────────┐
53+
│ xlings 下载 payload │
54+
│ ~/.xlings/data/xpkgs/ │
55+
│ (cfg/specs 路径正确) │
56+
└──────────┬──────────────┘
57+
│ copy (因 XLINGS_HOME 传播不可靠)
58+
59+
┌─────────────────────────┐
60+
│ mcpp sandbox 副本 │
61+
│ ~/.mcpp/registry/xpkgs/ │
62+
│ (cfg/specs 路径 stale!) │
63+
└──────────┬──────────────┘
64+
65+
┌──────────────┼──────────────┐
66+
▼ ▼ ▼
67+
GCC: specs Clang macOS: Clang Linux:
68+
fixup 修复 --no-default 没有修复 ← BUG
69+
路径 ✅ -config ✅ 用 subos 补救 ✗
70+
```
71+
72+
**三个平台/工具链的 stale path 问题,用了三种不同的解法:**
73+
74+
| 工具链 | stale path 来源 | 当前解法 | 状态 |
75+
|--------|-----------------|---------|------|
76+
| GCC (Linux) | specs 文件 | `fixup_gcc_specs()` 重写 specs | ✅ 正确但只修了 specs,没修 `-print-sysroot` |
77+
| Clang (macOS) | clang++.cfg | `--no-default-config` + xcrun | ✅ 但只在 macOS |
78+
| Clang (Linux) | clang++.cfg | M5.5 subos 覆盖 | ❌ subos 不完整 |
79+
80+
**根本问题:mcpp 复制了 payload 但没有统一处理 stale path。**
81+
82+
### mcpp 对 xlings 的依赖边界不清
83+
84+
当前 mcpp 对 xlings 有三层依赖:
85+
86+
| 层次 | 内容 | 应该依赖? |
87+
|------|------|-----------|
88+
| 包下载 | xlings 作为包索引 + 下载工具 | ✅ 是 |
89+
| payload 路径 | xpkgs 下具体包的文件结构 | ✅ 是 |
90+
| subos | xlings 的沙箱 sysroot | ❌ 不应该 |
91+
92+
M5.5 的问题就在于跨越了第三层边界——用 xlings 的内部实现细节(subos)
93+
来补救 mcpp 自身的路径问题。
94+
95+
---
96+
97+
## 设计方案
98+
99+
### 核心原则
100+
101+
**mcpp 只把 xlings 当包索引 + 下载工具。工具链的编译环境由 payload 自描述,
102+
mcpp 忠实读取,不替换、不覆盖。**
103+
104+
### 方案:Payload-first + 统一 stale path 处理
105+
106+
#### 1. 工具链 sysroot 来源:只从 payload 获取
107+
108+
```
109+
┌─────────────────────────────────────────────────┐
110+
│ sysroot 解析优先级 │
111+
│ │
112+
│ 1. compiler -print-sysroot (GCC 原生支持) │
113+
│ → 路径存在则使用 │
114+
│ │
115+
│ 2. payload cfg 文件解析 (Clang clang++.cfg) │
116+
│ → 解析 --sysroot= 行,路径存在则使用 │
117+
│ │
118+
│ 3. macOS: xcrun --show-sdk-path │
119+
│ │
120+
│ 4. 空 (不传 --sysroot,让编译器用自身默认值) │
121+
│ │
122+
│ ✗ 不再有 subos fallback │
123+
└─────────────────────────────────────────────────┘
124+
```
125+
126+
**改动**
127+
- 删除 `cli.cppm` M5.5 subos 覆盖代码
128+
- `probe.cppm` 增加 cfg 文件解析作为第 2 优先级
129+
130+
#### 2. 复制 payload 时统一修复 stale path
131+
132+
当前只有 GCC 做了 specs fixup,Clang 只在 macOS 做了 `--no-default-config`
133+
应该统一为:**凡是复制了 payload,就修复其中的路径配置。**
134+
135+
```
136+
copy payload 后
137+
138+
┌────────┼────────┐
139+
▼ ▼ ▼
140+
GCC specs Clang cfg 其他配置
141+
│ │
142+
▼ ▼
143+
rewrite_gcc rewrite_cfg
144+
_specs() _paths()
145+
│ │
146+
▼ ▼
147+
新 sysroot 新 sysroot
148+
新 rpath 新 -isystem
149+
新 -L/-rpath
150+
```
151+
152+
**具体做法**:在 `package_fetcher.cppm` 复制 payload 后(或在 `cli.cppm`
153+
toolchain install 后),对 Clang cfg 做类似 `fixup_gcc_specs` 的路径重写:
154+
155+
```cpp
156+
void fixup_clang_cfg(const std::filesystem::path& payloadRoot,
157+
const std::filesystem::path& newSysroot) {
158+
auto cfgPath = payloadRoot / "bin" / "clang++.cfg";
159+
if (!std::filesystem::exists(cfgPath)) return;
160+
161+
// 读取 cfg,将旧 sysroot/isystem/rpath 路径替换为 payload 实际位置
162+
// ...
163+
}
164+
```
165+
166+
**但这里有一个关键设计选择:新路径指向哪里?**
167+
168+
#### 3. 关于 sysroot 本身从哪来
169+
170+
工具链需要 C 库头文件(glibc headers + linux kernel headers)。来源有三种:
171+
172+
| 来源 | 说明 | 优劣 |
173+
|------|------|------|
174+
| 系统 `/usr/include` | 宿主机自带 | 简单,但不可控,不同发行版不同 |
175+
| xlings subos | xlings 管理的沙箱 sysroot | 可控,但 mcpp 需依赖 xlings 内部结构 |
176+
| payload 自带 | 工具链包自带 sysroot(如 musl-gcc) | 最干净,但需要上游包支持 |
177+
178+
**推荐策略**:
179+
180+
- **短期**:信任 payload 自身配置的 sysroot 路径。xlings 安装 GCC/LLVM 时
181+
已经配置好了 sysroot(指向 xlings 自己的 subos),mcpp 只需忠实读取。
182+
如果路径存在且有效,就用它。如果路径无效,不传 `--sysroot`,让编译器
183+
用系统默认路径。
184+
185+
- **中期**:推动 xlings 上游让 LLVM/GCC 包的 cfg/specs 使用相对路径或
186+
可配置路径,避免硬编码绝对路径。这从源头消除 stale path 问题。
187+
188+
- **长期**:mcpp 自带轻量 sysroot 管理(类似 Zig 的做法:打包 libc headers
189+
作为 mcpp 自身的资源),彻底不依赖宿主系统或 xlings 的 sysroot。但这是
190+
大工程,不急。
191+
192+
---
193+
194+
## 修复方案(基于以上设计)
195+
196+
### Phase 1:修复当前 bug(最小改动)
197+
198+
#### P1-1:删除 M5.5 subos 覆盖
199+
200+
**文件**:`src/cli.cppm:1192-1203`
201+
202+
**删除**整个代码块。工具链的 sysroot 由 payload 决定,mcpp 不介入。
203+
204+
同时删除 `cli.cppm:1001` 的 subos 注释和 `cli.cppm:1178` 的 "glibc subos" 注释。
205+
206+
#### P1-2:`probe_sysroot` 增加 cfg 解析
207+
208+
**文件**:`src/toolchain/probe.cppm:254-272`
209+
210+
`-print-sysroot` 失败后(Clang 不支持),解析 payload 中 `clang++.cfg`
211+
的 `--sysroot=` 行:
212+
213+
```cpp
214+
std::filesystem::path
215+
probe_sysroot(const std::filesystem::path& compilerBin,
216+
const std::string& envPrefix) {
217+
// 1. -print-sysroot (GCC)
218+
auto r = run_capture(std::format("{}{} -print-sysroot {}",
219+
envPrefix,
220+
mcpp::xlings::shq(compilerBin.string()),
221+
mcpp::platform::null_redirect));
222+
if (r) {
223+
auto s = trim_line(*r);
224+
if (!s.empty() && std::filesystem::exists(s)) return s;
225+
}
226+
227+
// 2. Parse payload cfg (Clang)
228+
auto cfgPath = compilerBin.parent_path()
229+
/ (compilerBin.stem().string() + ".cfg");
230+
if (std::filesystem::exists(cfgPath)) {
231+
std::ifstream ifs(cfgPath);
232+
std::string line;
233+
while (std::getline(ifs, line)) {
234+
constexpr std::string_view prefix = "--sysroot=";
235+
if (line.starts_with(prefix)) {
236+
auto val = trim_line(std::string(line.substr(prefix.size())));
237+
if (!val.empty() && std::filesystem::exists(val))
238+
return val;
239+
}
240+
}
241+
}
242+
243+
// 3. macOS: xcrun SDK
244+
if (auto sdk = mcpp::platform::macos::sdk_path())
245+
return *sdk;
246+
return {};
247+
}
248+
```
249+
250+
**Phase 1 效果**
251+
- Clang:cfg 中的 `--sysroot=~/.xlings/subos/default` 被正确读取,
252+
`tc->sysroot` 不再为空。stdmod.cppm 和 flags.cppm 传递正确的 sysroot。
253+
- GCC:`-print-sysroot` 正常工作(如果路径存在);若不存在则 sysroot 为空,
254+
GCC 用默认系统路径(`/usr/include`)。
255+
- 不再依赖 subos。
256+
257+
### Phase 2:统一 Clang stale cfg 处理(消除隐患)
258+
259+
#### P2-1:`stdmod.cppm` — 所有有 cfg 的 Clang 都走 `--no-default-config`
260+
261+
**文件**`src/toolchain/stdmod.cppm:103-116`
262+
263+
将 macOS 特有的 `--no-default-config` 逻辑泛化为"有 cfg 文件的 Clang":
264+
265+
```cpp
266+
std::string sysroot_flag;
267+
if (is_clang(tc)) {
268+
auto cfgPath = tc.binaryPath.parent_path()
269+
/ (tc.binaryPath.stem().string() + ".cfg");
270+
if (std::filesystem::exists(cfgPath)) {
271+
// Bypass cfg (may have stale paths after payload copy).
272+
// Provide correct flags from payload structure directly.
273+
auto llvmRoot = tc.binaryPath.parent_path().parent_path();
274+
auto libcxxInclude = llvmRoot / "include" / "c++" / "v1";
275+
sysroot_flag = " --no-default-config";
276+
sysroot_flag += std::format(" -isystem'{}'", libcxxInclude.string());
277+
if (!tc.sysroot.empty())
278+
sysroot_flag += std::format(" --sysroot='{}'", tc.sysroot.string());
279+
else if (auto sdk = mcpp::platform::macos::sdk_path())
280+
sysroot_flag += std::format(" --sysroot='{}'", sdk->string());
281+
} else if (!tc.sysroot.empty()) {
282+
sysroot_flag = std::format(" --sysroot='{}'", tc.sysroot.string());
283+
}
284+
} else if (!tc.sysroot.empty()) {
285+
sysroot_flag = std::format(" --sysroot='{}'", tc.sysroot.string());
286+
}
287+
```
288+
289+
#### P2-2:`flags.cppm` — 同步修改
290+
291+
**文件**`src/build/flags.cppm:96-111`
292+
293+
同步 P2-1 的逻辑:将 `is_macos_clang` 条件改为"检测到 cfg 文件存在"。
294+
295+
**Phase 2 效果**
296+
- Linux 和 macOS Clang 走统一路径
297+
- 不再依赖 cfg 中的路径碰巧有效
298+
- mcpp 从 payload 结构推导出正确的 `-isystem``--sysroot`
299+
300+
### Phase 3(未来):复制 payload 时重写 cfg 路径
301+
302+
`package_fetcher.cppm``cli.cppm` toolchain install 后,添加
303+
`fixup_clang_cfg()`,类似 `fixup_gcc_specs()` 的做法:
304+
305+
```cpp
306+
void fixup_clang_cfg(const std::filesystem::path& payloadRoot,
307+
const std::filesystem::path& oldXlingsHome,
308+
const std::filesystem::path& newRegistryHome) {
309+
// 重写 clang++.cfg 中的路径:
310+
// --sysroot=<old> → --sysroot=<new>
311+
// -isystem <old> → -isystem <new>
312+
// -L<old> → -L<new>
313+
// -rpath,<old> → -rpath,<new>
314+
}
315+
```
316+
317+
这样即使不用 `--no-default-config`,cfg 路径也是正确的。
318+
但需要 mcpp 管理自己的 sysroot 内容(确保完整性),所以这是更远期的方向。
319+
320+
---
321+
322+
## 修改总结
323+
324+
| Phase | 修改 | 文件 | 效果 |
325+
|-------|------|------|------|
326+
| P1-1 | 删除 M5.5 | cli.cppm | 去除 subos 依赖 |
327+
| P1-2 | cfg 解析 sysroot | probe.cppm | Clang 获取正确 sysroot |
328+
| P2-1 | 统一 --no-default-config | stdmod.cppm | 消除 stale cfg 隐患 |
329+
| P2-2 | 同步 P2-1 | flags.cppm | 常规编译也用正确路径 |
330+
| P3 | cfg 路径重写 | package_fetcher/cli | 从根源修复 stale path |
331+
332+
**Phase 1 修复 bug,Phase 2 消除隐患,Phase 3 完善架构。**
333+
334+
---
335+
336+
## 测试补充
337+
338+
### 新增 e2e 测试:无 subos 下的 import std
339+
340+
```bash
341+
#!/usr/bin/env bash
342+
# requires: import-std
343+
# Test that import std works without mcpp's subos sysroot.
344+
# Regression test: M5.5 subos override must not be required.
345+
set -euo pipefail
346+
347+
TMP=$(mktemp -d)
348+
trap "rm -rf $TMP" EXIT
349+
350+
export MCPP_HOME="$TMP/mcpp-home"
351+
export MCPP_INHERIT_SUBOS=0
352+
source "$(dirname "$0")/_inherit_toolchain.sh"
353+
354+
mkdir -p "$TMP/proj/src"
355+
cd "$TMP/proj"
356+
357+
cat > mcpp.toml <<'EOF'
358+
[package]
359+
name = "sysroot_test"
360+
version = "0.1.0"
361+
EOF
362+
363+
cat > src/main.cpp <<'EOF'
364+
import std;
365+
int main() { std::println("sysroot ok"); }
366+
EOF
367+
368+
"$MCPP" build
369+
"$MCPP" run | grep -q "sysroot ok"
370+
```

0 commit comments

Comments
 (0)