Skip to content

Commit f202c0c

Browse files
committed
docs: install() hook toolchain build-env gap (real opencv blocker)
Root-cause writeup of the ecosystem gap behind opencv PR #67 (待评估): xlings runs install() hooks in a subprocess that does NOT inherit the toolchain BUILD-time env (LIBRARY_PATH/CPATH), so xim:gcc can't find glibc's crt1.o/libm (link) or stdlib.h/limits.h (compile) on a host-free runner. Distinct from D1 (runtime loader resolution). Correct fix is in xlings/xim (inject build-env, or extend gcc specs), not per-descriptor hand-wiring with hardcoded versions.
1 parent 692be93 commit f202c0c

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# install() hook 子进程继承不到工具链构建环境(源码构建包的生态缺口)
2+
3+
**日期**: 2026-07-09
4+
**范围**: xlings/xim 的 `install()` xpkg hook 执行环境 × 生态工具链(`xim:gcc` / `xim:glibc` / `xim:linux-headers`)
5+
**性质**: xlings 侧的生态能力缺口(根治点在 xlings/xim,不在下游 descriptor)
6+
**触发用例**: `compat.opencv`(源码 CMake 构建)在 mcpp-index workspace CI 上的 `workspace(linux)` 失败
7+
**状态**: opencv PR #67 已标记**待评估**(draft),阻塞在本缺口
8+
9+
---
10+
11+
## 文档族与职责边界
12+
13+
| # | 文档 | 定位 |
14+
|---|---|---|
15+
|| `2026-07-09-mcpp-builddep-loader-store-split-rootcause.md` | 原故障(cmake interpreter 悬空)根因总报告 |
16+
|| mcpp `2026-07-09-project-index-scope-global-infra-fix.md` | 该故障**唯一必需修复**(mcpp 0.0.87,已发布) |
17+
|| xlings `2026-07-09-scope-consistency-installed-check-and-loader-resolution.md` | elfpatch additive 解析缺口(D1,**独立**、当前未被触发) |
18+
|| **本篇** | **install() hook 构建环境缺口**——②修好后 opencv 暴露出的****生态缺口,与 ①②③ 均不同 |
19+
20+
**与 ③(D1)的区别**:③ 是 **runtime** loader-provider 的**跨 store 解析**(elfpatch interpreter/rpath);本篇 ④ 是 **build-time****编译/链接搜索路径**(startfile / 库 / 头文件)。两者都涉及 glibc,但一个在装完后跑,一个在 install() 里编。
21+
22+
---
23+
24+
## 0. 现象
25+
26+
`compat.opencv``install()` 用生态工具链(`xim:cmake` + `xim:gcc` + `xim:make`)从源码构建 OpenCV。开发主机上闭环通过;但 mcpp-index workspace CI 的 `workspace(linux)`(冷环境、无宿主 libc-dev)上,`install()` 的 CMake 构建**静默失败**,消费者最终报 `opencv2/core.hpp: No such file`
27+
28+
xim 的 interface 模式**抑制了 install() 子进程的全部输出**(subprocess stdout + libxpkg `log.error`),故真因在 CI 上不可见——只能看到 `fetch 'compat.opencv@4.13.0' failed (exit 1)`。通过在 CI workflow 加**失败诊断步骤**(直接从 runner 磁盘 `cat` build log + 直跑 `xlings install cmake`)才拿到真相。
29+
30+
## 1. 真因:install() 子进程没有工具链的**构建期**环境
31+
32+
`xim:gcc` 的 specs(`xim-x-gcc/16.1.0/lib/gcc/.../specs`)只把 `xim:glibc` 接进了**运行期**:
33+
- `-rpath <glibc>/lib64``-dynamic-linker <glibc>/lib64/ld-linux-x86-64.so.2`
34+
35+
specs **没有**把 glibc 的**构建期**搜索路径写进去:
36+
- 链接期 startfile / 库:`crt1.o``crti.o``crtn.o``libm``libc`(都在 `<glibc>/lib`);
37+
- 编译期头文件:`stdlib.h``limits.h`(在 `<glibc>/include`),以及内核 uapi 头(在 `<xim:linux-headers>/include`)。
38+
39+
平时这些由 **mcpp 的构建流程**通过环境变量(`LIBRARY_PATH` / `CPATH`)提供给 gcc。但 `install()` hook 的子进程**不继承** mcpp 的构建环境,于是 gcc 在 install() 里既找不到 crt/库、也找不到系统头。
40+
41+
**为什么开发主机上没暴露**:主机装了 libc-dev,gcc 默认 startfile/include 前缀里有 `/usr/lib/.../crt1.o` + `/usr/include/stdlib.h`,**静默 fallback 到宿主** → 能编过,但**违反 host-free**、且用的是宿主 glibc 而非生态 glibc。极简 CI runner 没 libc-dev → 硬失败。这也是本地一直复现不出 CI 失败的根源。
42+
43+
**为什么 openblas 没踩坑**:`compat.openblas` 的 install() 只**编译 + 归档 `.a`**(`make libs`),从不**链接可执行文件**,所以永远不需要 crt1.o/libm;它对系统头的依赖也浅。opencv 的 CMake **编译器自检要链接一个测试 exe**,第一步就撞上 crt1.o 缺失。
44+
45+
## 2. CI 实证(逐层剥开)
46+
47+
install() 里临时逐个补齐,CI build log 逐层前进,坐实了缺口范围:
48+
49+
|| 报错 | 缺的东西 |
50+
|---|---|---|
51+
| L1 | `cmake: cannot execute: required file not found` | 动态 xim:cmake 的 loader launcher(裸名 vs 绝对路径) |
52+
| L2 | `ld: cannot find crt1.o / crti.o / -lm` | 链接期 `LIBRARY_PATH=<glibc>/lib` |
53+
| L3 | `find_package called with invalid argument "OFF"` | OpenCV 撞见 xlings python3 shim(版本串空)→ `OPENCV_PYTHON_SKIP_DETECTION` |
54+
| L4 | `fatal error: stdlib.h / limits.h: No such file` | 编译期 `CPATH=<glibc>/include:<linux-headers>/include` |
55+
56+
L1/L2/L4 都是**同一个缺口的不同面**:install() 子进程缺工具链的构建期环境。(L3 是 OpenCV × CMake4 的独立小问题,已用官方开关解决。)
57+
58+
## 3. 为什么"在 descriptor 里各自硬接"是错的层级
59+
60+
opencv PR 上现存的 `LIBRARY_PATH`/`CPATH` + `pkginfo.install_dir("xim:glibc","2.39")` + 显式声明 `xim:glibc@2.39`/`xim:linux-headers@5.11.1`**临时探路**,**不作为最终方案**,因为:
61+
62+
1. **脆弱**:硬编码 glibc 2.39 / linux-headers 5.11.1 版本,工具链一升级就失效。
63+
2. **重复**:每个源码构建包(未来的 ffmpeg / boost / …)都要各自重接一遍同样的环境。
64+
3. **层级错**:"gcc 该怎么找到它自己工具链的 glibc" 是**工具链/安装器**的职责,不是每个下游包的职责。
65+
66+
## 4. 根治设计(xlings/xim 侧)
67+
68+
**install() hook 的子进程,应当在一个已经具备完整工具链构建期环境的 shell 里运行。** 具体二选一(或组合):
69+
70+
- **方案 A(推荐)——安装器注入构建环境**:xim 在执行 install() hook 时,依据当前 default toolchain(gcc + 其 runtime dep 链上的 glibc、linux-headers)导出 `LIBRARY_PATH` / `CPATH`(或 `C_INCLUDE_PATH`+`CPLUS_INCLUDE_PATH`),使 hook 内 bare `gcc`/`cmake` 天然 host-free。信息来源:resolver 的 plan 已知每个 node 的 effective store(与 ③ D1 的"effective_install_dir"同源,可复用)。
71+
- **方案 B——把构建期路径也写进 gcc specs**:让 `xim-x-gcc-specs-config` 生成的 specs 除了 rpath/dynamic-linker,再补 startfile prefix(`<glibc>/lib`)与 `-isystem <glibc>/include``-isystem <linux-headers>/include`。好处是对**任何**调用方(不止 install())都生效;代价是 specs 更重、且路径同样要在装 glibc 时确定。
72+
73+
无论哪个,目标一致:**任意生态工具(mcpp 构建 / install() hook / 用户直调 gcc)在 host-free 环境下都能编译+链接,不 fallback 到宿主。** descriptor 侧则**零环境接线**
74+
75+
## 5. 落地关系
76+
77+
- **不阻塞 mcpp 0.0.87**(②,已发布)、**不阻塞 D1/#354**(③,独立,当前 HOLD)。
78+
- **阻塞 opencv 及未来源码构建包**的 host-free 闭环 → opencv PR #67 待评估,等本缺口在 xlings/xim 侧补齐后回来**删掉 descriptor 里的临时环境接线**再合入。
79+
- CI 侧 opencv workspace 的临时诊断步骤(mcpp-index `.github/workflows/validate.yml`,commit `450acbb`)在 opencv 落地前应移除。

0 commit comments

Comments
 (0)