Skip to content

Commit b543fd3

Browse files
committed
fix: check_base_init warns instead of blocking, fix Windows build
1 parent dd803b7 commit b543fd3

10 files changed

Lines changed: 2513 additions & 7 deletions
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# resolve_xpkg_path() 的 copy 优先级问题分析
2+
3+
**Date**: 2026-05-22
4+
5+
## 一、当前流程
6+
7+
`resolve_xpkg_path()` (`src/pm/package_fetcher.cppm:580-718`) 的执行顺序:
8+
9+
```
10+
resolve_xpkg_path(target, autoInstall)
11+
12+
├─ resolve() ← 第一次调用
13+
│ ├─ sandbox 里有?→ 直接返回 ✅
14+
│ ├─ sandbox 里没有?→ 检查 ~/.xlings/
15+
│ │ ├─ ~/.xlings/ 里有?→ copy 到 sandbox → 返回 ✅
16+
│ │ └─ ~/.xlings/ 里没有?→ 返回 error
17+
│ └─ 返回 error
18+
19+
├─ resolve() 成功?→ return(不会触发 install)
20+
21+
├─ autoInstall=false?→ return error
22+
23+
├─ install() ← 只有 resolve() 失败且 autoInstall=true 才走到这里
24+
│ └─ xlings interface install_packages
25+
26+
└─ resolve() ← 第二次调用(install 后再 resolve)
27+
└─ 同上逻辑(sandbox → copy → error)
28+
```
29+
30+
## 二、问题:copy 短路了 install
31+
32+
**核心问题**:只要 `~/.xlings/` 里有这个包,`resolve()` 就会直接 copy 并返回成功,
33+
**永远不会走到 `install()` 路径**
34+
35+
### 场景 1:用户之前用系统 xlings 装过 LLVM
36+
37+
```
38+
~/.xlings/data/xpkgs/xim-x-llvm/20.1.7/ ← 存在(旧版本)
39+
~/.mcpp/registry/data/xpkgs/xim-x-llvm/20.1.7/ ← 不存在
40+
41+
resolve():
42+
sandbox 没有 → 检查 ~/.xlings/ → 有 → copy → 返回成功
43+
↑ 完全跳过 install,即使 ~/.xlings/ 里的版本可能有问题
44+
```
45+
46+
**后果**
47+
- mcpp 拿到的是 xlings 全局环境的旧包,可能跟 mcpp sandbox 不兼容
48+
- ELF RUNPATH 指向 `~/.xlings/...`(这就是 libatomic bug 的根源)
49+
- mcpp 无法确保拿到的包是用 `XLINGS_HOME=~/.mcpp/registry` 安装的
50+
51+
### 场景 2:全局也没有,需要全新安装
52+
53+
```
54+
~/.xlings/data/xpkgs/xim-x-llvm/20.1.7/ ← 不存在
55+
~/.mcpp/registry/data/xpkgs/xim-x-llvm/20.1.7/ ← 不存在
56+
57+
resolve():
58+
sandbox 没有 → 检查 ~/.xlings/ → 也没有 → 返回 error
59+
60+
install():
61+
xlings interface install_packages → exitCode=0
62+
但 LLVM 实际没装到 sandbox(xlings bug)
63+
也没装到 ~/.xlings/(安装可能不完整)
64+
65+
resolve()(第二次):
66+
sandbox 没有 → ~/.xlings/ 也没有 → 返回 "xpkg payload missing"
67+
```
68+
69+
**后果**:全新安装完全失败(就是你遇到的情况)
70+
71+
### 场景 3:sandbox 里已有
72+
73+
```
74+
~/.mcpp/registry/data/xpkgs/xim-x-llvm/20.1.7/ ← 存在
75+
76+
resolve():
77+
sandbox 有 → 直接返回成功
78+
↑ 不检查版本、完整性、RUNPATH 正确性
79+
```
80+
81+
**后果**:如果之前拷贝的包有问题(比如 RUNPATH 错误),不会自动修复
82+
83+
## 三、问题分层
84+
85+
|| 问题 | 严重度 |
86+
|----|------|--------|
87+
| **优先级反转** | copy 优先于 install,导致 install 路径几乎不被执行 ||
88+
| **来源不可信** |`~/.xlings/` 拷贝的包不是为 mcpp sandbox 构建的 ||
89+
| **无完整性检查** | copy 后不验证包是否完整、路径是否正确 ||
90+
| **install 路径不可靠** | xlings NDJSON interface 安装大包时返回成功但未实际安装 ||
91+
| **无版本/时间戳校验** | 不检查 `~/.xlings/` 的包是否比 sandbox 的更新 ||
92+
93+
## 四、理想的执行流程
94+
95+
```
96+
resolve_xpkg_path(target, autoInstall)
97+
98+
├─ 1. sandbox 里有且完整?→ 直接返回 ✅
99+
100+
├─ 2. autoInstall?
101+
│ ├─ 是 → install()(用 XLINGS_HOME=sandbox 安装到 sandbox)
102+
│ │ ├─ 成功且 sandbox 里有?→ 返回 ✅
103+
│ │ └─ 失败 → 走 fallback
104+
│ └─ 否 → 走 fallback
105+
106+
├─ 3. fallback: ~/.xlings/ 里有?
107+
│ ├─ 是 → copy + post-copy fixup → 返回 ✅
108+
│ └─ 否 → 返回 error
109+
110+
└─ 4. 返回结果
111+
```
112+
113+
关键变化:**install 优先于 copy**。copy 只是 fallback,不是首选路径。
114+
115+
## 五、修复方案
116+
117+
### 方案 A:调换 install 和 copy 的优先级
118+
119+
`resolve()` 中的 copy workaround 移到 `install()` 之后:
120+
121+
```
122+
resolve_xpkg_path(target, autoInstall):
123+
1. check sandbox → return if exists
124+
2. if autoInstall → install via xlings
125+
3. check sandbox again → return if exists
126+
4. FALLBACK: copy from ~/.xlings/ (workaround)
127+
5. check sandbox again → return if exists
128+
6. error: payload missing
129+
```
130+
131+
**优点**:install 路径得到优先执行,copy 只是最后兜底
132+
**缺点**:如果 install 慢或失败,用户体验变差(之前可以秒拷贝)
133+
134+
### 方案 B:install 优先 + copy fallback + 超时
135+
136+
```
137+
resolve_xpkg_path(target, autoInstall):
138+
1. check sandbox → return if exists
139+
2. if autoInstall → try install (with timeout)
140+
3. check sandbox → return if exists
141+
4. copy from ~/.xlings/ if available
142+
5. post-copy fixup (patchelf RUNPATH)
143+
6. return or error
144+
```
145+
146+
**优点**:兼顾速度(install 失败时快速 fallback)和正确性
147+
**缺点**:增加超时逻辑的复杂度
148+
149+
### 方案 C:install 优先 + install 直接调用(非 NDJSON)
150+
151+
之前排查发现 NDJSON interface 路径安装大包不可靠。`install_with_progress()`
152+
已有"直接调用" fallback(`std::system("xlings install ... -y")`)。
153+
154+
将工具链安装改为使用 `install_with_progress()`(直接调用模式)而非
155+
`install()`(NDJSON interface 模式):
156+
157+
```
158+
resolve_xpkg_path(target, autoInstall):
159+
1. check sandbox → return if exists
160+
2. if autoInstall → install_with_progress (direct mode)
161+
3. check sandbox → return if exists
162+
4. copy from ~/.xlings/ as fallback
163+
5. return or error
164+
```
165+
166+
**优点**
167+
- 修复了 NDJSON interface 安装大包不可靠的问题
168+
- install 正确执行时,包直接装到 sandbox,无需 copy
169+
- copy 只在 install 真正失败时兜底
170+
171+
**缺点**:需要在 package_fetcher 层引入 install_with_progress
172+
173+
### 方案 D:保持 copy 优先但增加 post-copy fixup(当前状态)
174+
175+
当前 PR #67 的做法:保持 copy 优先,但在工具链 post-install 时修正 RUNPATH。
176+
177+
**优点**:改动最小,已实施
178+
**缺点**
179+
- copy 仍然优先于 install,install 路径几乎不被测试
180+
- 依赖 `~/.xlings/` 有正确的包(全新机器无 `~/.xlings/` 则完全失败)
181+
- 每个工具链都需要写对应的 fixup
182+
183+
## 六、建议
184+
185+
**短期(已完成)**:方案 D — post-copy fixup 兜底
186+
187+
**中期(推荐)**:方案 C — install 优先 + 直接调用模式
188+
- 修改 `resolve_xpkg_path()` 的流程顺序
189+
- 工具链安装使用 `install_with_progress()`(直接调用)
190+
- copy 降级为 fallback
191+
- 这是最务实的方案,解决了优先级反转和 NDJSON 不可靠两个问题
192+
193+
**长期**:方案 C + 在 copy fallback 后统一做 RUNPATH fixup
194+
- 将 patchelf fixup 从各工具链的 post-install 提取到 copy 出口统一处理
195+
- 未来加新工具链不会再遗漏

0 commit comments

Comments
 (0)