Skip to content

Commit 8e73bea

Browse files
committed
feat(pkgs): add compat.opencv (source-built core+imgproc+imgcodecs via install() CMake)
OpenCV 4.13.0 as a curated-module static build, driven by its own CMake through an install() hook (compat.openblas pattern, CMake instead of Make). mcpp's "list the .cpp" model can't express OpenCV's generated SIMD-dispatch / OpenCL-kernel / config headers, so CMake produces them; the recipe is host-free (ecosystem xim:cmake/make/ gcc only, bundled 3rdparty zlib/png/jpeg, WITH_ADE=OFF kills the sole download — verified offline under `unshare -rn`). - pkgs/c/compat.opencv.lua — build_dep-resolved tools, install() curated CMake build, linux/macos link flags; Windows deferred (anchor stub). Plain-string GLOBAL url (no mcpp-res write access this session; CN mirror is a maintainer follow-up). - tests/examples/opencv — Mat + cvtColor(BGR2GRAY) + imencode/imdecode PNG round-trip assertion; linux-gated workspace member. - Floor + CI pin → 0.0.87: this package needs the mcpp 0.0.87 fix (global tools no longer mis-scoped into the project store); on ≤0.0.86 the build-dep cmake's ELF interpreter dangles. index.toml min/latest_mcpp + validate.yml MCPP_VERSION. - Design/impl/root-cause docs under .agents/docs/. Verified end-to-end with mcpp 0.0.87: `mcpp test` → `test result ok. 1 passed`. Claude-Session: https://claude.ai/code/session_01Y3KE7MAE8yV7BG35eXy7FV
1 parent fab139d commit 8e73bea

10 files changed

Lines changed: 899 additions & 3 deletions

.agents/docs/2026-07-08-opencv-ecosystem-adoption-research.md

Lines changed: 294 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# OpenCV 落地实现与本地验证记录(compat.opencv,install()-CMake,host-free)
2+
3+
**日期**: 2026-07-08
4+
**承接**: `.agents/docs/2026-07-08-opencv-ecosystem-adoption-research.md`(调研报告,决策依据)
5+
**产出**: `pkgs/c/compat.opencv.lua` + `tests/examples/opencv/`(workspace member)+ README 一行 + 本文档
6+
**mcpp**: 0.0.85(与 CI `MCPP_VERSION` 一致)
7+
8+
---
9+
10+
## 1. 形态与最终决策(与调研报告一致)
11+
12+
- **单包 `compat.opencv`**,**install()-hook 驱动 OpenCV 自带 CMake** 从源码构建(compat.openblas 模式,Make→CMake)。
13+
- **MVP 模块集**:`core + imgproc + imgcodecs`(`-DBUILD_LIST`),第三方 codec 全走 tarball 内置 `3rdparty/`
14+
(`-DBUILD_ZLIB=ON -DBUILD_PNG=ON -DBUILD_JPEG=ON`)——**零外部依赖**
15+
- **模块/开关是 recipe 内固定 profile**,不是 mcpp feature(feature 不能带 cflags/include_dirs/generated_files、
16+
也传不进 install();见调研报告 §3/§6)。更大变体(calib3d/dnn/highgui/contrib)是后续独立包。
17+
18+
## 2. host-free / 生态闭环 —— 核心约束,已证明
19+
20+
用户硬约束:**不能依赖 host,完全 mcpp 生态闭环**。落实与证据:
21+
22+
- 构建只用 **生态工具**,均为声明的 build-dep,从不碰 host:
23+
- `xim:cmake@4.0.2`(`~/.xlings/data/xpkgs/xim-x-cmake/4.0.2/bin/cmake`)
24+
- `xim:ninja@1.12.1`
25+
- `xim:gcc@16.1.0`(与 mcpp 消费侧解析到的同一 g++:`Resolved gcc@16.1.0 → …/xim-x-gcc/16.1.0/bin/g++`)
26+
- **离线证明**:在 **network-isolated 命名空间**(`unshare -rn`)里跑完整 configure+build+install,
27+
**零下载**。唯一的 configure 期下载(gapi 的 ADE zip)由 `-DWITH_ADE=OFF` 消除(gapi 本就被 BUILD_LIST 白名单排除)。
28+
其余全部来自 tarball 内置 `3rdparty/` 源码编译。
29+
- install() 里 CMake 的 `CMAKE_C/CXX_COMPILER``CMAKE_MAKE_PROGRAM` 全部显式指向 build-dep 解析出的 bin
30+
(`pkginfo.build_dep` + PATH 兜底),不依赖 host PATH。
31+
32+
## 3. ABI:C++ 库的工具链一致性(关键工程点)
33+
34+
OpenCV 是 C++,静态库的 libstdc++ ABI 必须与 **消费者链接用的编译器** 一致。
35+
36+
- install() 用 `xim:gcc@16.1.0`(gcc/libstdc++)构建;mcpp 在 linux 默认也解析到 `gcc@16.1.0`
37+
**ABI 天然对齐**(实测 mcpp 日志 `Resolved gcc@16.1.0`)。
38+
- **linux-gated**:macOS 默认 clang/libc++,与 gcc/libstdc++ 的 `.a` 会 ABI 冲突;Windows 是 MSVC-ABI clang。
39+
两者均为后续项。测试工程按 `cfg(linux)` 门控(gui-stack 先例),off-linux 为 no-op main,
40+
`mcpp test --workspace` 在 mac/win 干净通过。
41+
- 这暴露一个 **通用能力缺口**(见 §6 第 1 条):install() 应能拿到"mcpp 已选定的工具链",让源码构建对齐目标 ABI。
42+
43+
## 4. descriptor 关键点(`pkgs/c/compat.opencv.lua`)
44+
45+
- `sources = { "mcpp_opencv_anchor.c" }`:anchor **** 放进 `generated_files`,而由 install() 写出 → 其缺失正是
46+
触发 mcpp 运行 install()(=触发 CMake 构建)的机制(compat.openblas / compat.xcb 同款)。
47+
- `include_dirs = { "include/opencv4" }`:install 后头文件落点,用户 `#include <opencv2/core.hpp>`
48+
- 链接(per-OS `linux`/`macosx` 块):模块库在前、其 3rdparty 在后、系统库最后;OpenCV 把内置 3rdparty 归档放在
49+
`lib/opencv4/3rdparty/`,故需第二个 `-L`:
50+
```
51+
-Llib -Llib/opencv4/3rdparty
52+
-lopencv_imgcodecs -lopencv_imgproc -lopencv_core
53+
-llibpng -llibjpeg-turbo -lzlib -ldl -lpthread -lm
54+
```
55+
- `CMAKE_POLICY_VERSION_MINIMUM=3.5`:让 CMake 4.0.2 能解析 OpenCV 及其 3rdparty 的老 `cmake_minimum_required`
56+
- Windows:xpm 声明齐三平台(索引完整性 + 未来 CN 镜像),但 install() 在 windows 直接返回,anchor 由
57+
`generated_files` 提供(source 构建是后续项)。
58+
- **CN 镜像**:本会话无 `GITCODE_TOKEN`(无 mcpp-res 写权限),按 add-package skill 采用 **纯字符串 GLOBAL url**,
59+
CN 用户回退 GLOBAL,镜像由维护者后续补(`mcpp-res/opencv`,资产 `opencv-4.13.0.tar.gz`)。
60+
61+
## 5. 本地验证(mcpp 0.0.85,linux x86_64)
62+
63+
| 步骤 | 命令 | 结果 |
64+
|---|---|---|
65+
| 上游 sha256(两次稳定) | `sha256sum opencv-4.13.0.tar.gz` | `1d40ca017ea51c533cf9fd5cbde5b5fe7ae248291ddf2af99d4c17cf8e13017d` |
66+
| 离线隔离构建 core+imgproc+imgcodecs | `unshare -rn cmake … && cmake --build` | **零下载**,产出 6 个 `.a`,~81s(4 job) |
67+
| 独立链接+运行(mcpp g++ 16.1.0) | 手工 `g++ roundtrip.cpp -l…` | `opencv ok=1 core=4x4x3 gray(blue)=29 png_bytes=82 decoded=4x4` |
68+
| **端到端 mcpp 管线** | `mcpp test`(fetch→install() CMake→link→run) |**PASS**(mcpp **0.0.87**):`test result ok. 1 passed`。曾在 ≤0.0.86 被阻断(§5.1),根因为 mcpp 把全局索引 xim 误注入项目作用域,已在 0.0.87 修复(见 `2026-07-09-mcpp-builddep-loader-store-split-rootcause.md` + mcpp 仓 `2026-07-09-project-index-scope-global-infra-fix.md`)。cmake 现装进全局 registry,项目 store 仅含 compat.opencv。 |
69+
| lint(CI 同款) | `mcpp xpkg parse` + `lua5.4 loadfile` | PARSE_OK / LUA_LOAD_OK,`unknown_keys=[]` |
70+
71+
测试断言(`tests/examples/opencv/tests/roundtrip.cpp`,linux-gated):core`cv::Mat` → imgproc `cvtColor` BGR→GRAY
72+
(蓝色 luma=29)→ imgcodecs `imencode/imdecode` PNG 内存往返,逐步 `return` 非零错误码。
73+
74+
### 5.1 ⛔ BLOCKER —— `mcpp test` sandbox 未向 install() 提供可运行的 build-dep 工具链
75+
76+
**现象**:`mcpp test` 触发 install() 的 CMake 构建时,cmake/make/gcc 均无法执行 → install() 失败 → mcpp 报
77+
`fetch 'compat.opencv@4.13.0' failed`。这是调研报告 R1 风险的实测坐实,且是 **通用**(非 opencv 专属)。
78+
79+
**根因(install() 内 env/ELF 实证)**:mcpp 为 install() 导出了 `XLINGS_BUILDDEP_{CMAKE,MAKE,GCC}_PATH`(定位
80+
build-dep 工具的 intended 机制),但 project-local `.mcpp/.xlings` sandbox 里这些工具 **未被完整物化**:
81+
82+
- `XLINGS_BUILDDEP_GCC_PATH`(`xpkgs/xim-x-gcc/16.1.0/`)、`XLINGS_BUILDDEP_MAKE_PATH`(`xim-x-make/4.3/`)
83+
目录下 **无 bin/**(gcc/make 二进制根本不存在于该路径)。
84+
- `XLINGS_BUILDDEP_CMAKE_PATH/bin/cmake` 存在,但其 **ELF interpreter 悬空**:INTERP 指向
85+
`<sandbox>/xpkgs/xim-x-glibc/2.39/lib64/ld-linux-x86-64.so.2`,而该 loader 未被部署(`xim-x-glibc/2.39/` 下只有
86+
`.xpkg.lua`);真正的 loader 只在 `runtimedir/glibc-2.39-linux-x86_64/lib/` 里 → 直接执行报
87+
`cannot execute: required file not found`
88+
- install() subprocess PATH 上的 xlings shim(`make`/`gcc`)在此上下文失效(`executable 'make' not found`
89+
`alias for 'gcc' references itself`)。
90+
- 对照:**GLOBAL** 工具可运行(`$HOME/.xlings/.../cmake --version` = 4.0.2 OK;`$XLINGS_HOME=~/.mcpp/registry`
91+
下的 gcc 即消费侧链接所用、可运行)。即 build-dep 工具设计上经 xvm shim 环境运行,而该环境未注入 install() 的
92+
bash 子进程。
93+
94+
**为何 openblas 没暴露**:openblas 的 install() 只需 `make`(musl-static,免 loader)+ 裸 `gcc`,且其
95+
workspace 测试是 **windows-gated** → 在新的 `mcpp test --workspace` linux 流程里 openblas 的 install() **根本不被触发**
96+
opencv 是首个在该流程里真正跑 install()-CMake 的包,故首次撞上此 gap。
97+
98+
**影响**:任何"install() 里跑 glibc-dynamic build-dep 工具(cmake/autotools/…)"的 compat 包,在当前
99+
`mcpp test`(及同流程的 CI)下都无法闭环。这是 mcpp/xim 侧问题,**不在本仓(index)可修复范围**,已列为 §6 头号通用缺口。
100+
101+
**已证明未受此影响的部分**:descriptor 语法/解析、构建 recipe 本身(§5 前三行:离线隔离构建 + 手工链接运行全绿,
102+
用的正是同一套 ecosystem cmake/gcc,只是在 sandbox 之外调用)。此外,手工把 sandbox cmake 用 `xim:patchelf`
103+
`--set-interpreter` 指向 `runtimedir/glibc-*/lib/ld-linux-x86-64.so.2` + registry 的可运行 gcc/make,一个最小
104+
CMake 工程 configure+build 全绿(证明"只要 cmake 可执行,整条工具链子进程链即通")。即 **一旦 mcpp 向 install()
105+
提供可运行的 build-dep 工具链,本 descriptor 不改即可闭环**
106+
107+
**机制细节(供 mcpp 侧定位,均实证)**:
108+
- `descriptor` 用的是 **openblas 同款** `pkginfo.build_dep("xim:cmake").bin`(0.0.85 存在)解析工具 —— 无任何
109+
loader/patchelf 兼容代码(遵循"deps 由 xlings 自动处理"的约定)。但 `build_dep` 返回的正是那个 **INTERP 悬空、
110+
不可执行** 的 sandbox cmake。
111+
- `pkginfo.with_build_deps_on_path`(把 build-dep bin/ 前置进 PATH 的便捷 API)**只在独立 libxpkg 0.41/0.42 有,
112+
mcpp 0.0.85 内置 runtime 无此函数**(调用即 nil→install() 早抛)。
113+
- mcpp 0.0.85 内置 libxpkg **`xim.libxpkg.elfpatch`**(auto 模式)——但它 patch 的是 **本包自身产物**
114+
(依据 deps 里的 loader provider),**不 patch build-dep 工具**(如 cmake)。故 build-dep cmake 的 INTERP 无人修。
115+
- openblas 之所以没撞上:其 install() 只用 **make(musl 静态,无 INTERP 依赖)** + 裸 gcc,且 linux 测试
116+
windows-gated → 从不触发。opencv 是首个真正在 `mcpp test` 里跑 install()-CMake 的包。
117+
118+
**修复方向(mcpp 侧,三选一或组合)**:(a) 部署 build-dep 时把其 xim:glibc loader 落到二进制 INTERP 指向的
119+
路径(或对 build-dep 工具跑一次 elfpatch);(b) 把 `with_build_deps_on_path` 纳入 0.0.85 runtime 并让其前置的是
120+
**可执行** 的工具;(c) 让 `build_dep().bin` 返回已 elfpatch 的可执行副本。任一落地后,本 descriptor 与测试工程
121+
**零改动** 即闭环。
122+
123+
## 6. 适配中暴露的 mcpp 通用能力缺口(非 opencv 专属,构建工具/模块化视角)
124+
125+
判据:每条都是"任何走外部构建系统 / 多产物 / 重源码构建的库"共有的架构问题。
126+
127+
0. **【实测 BLOCKER】install() 需要一个可运行的 build-dep 工具链(最高优先级)**。见 §5.1。现状
128+
`mcpp test` sandbox 只导出 `XLINGS_BUILDDEP_*_PATH` 但不物化可运行二进制:gcc/make bin 目录为空,cmake 的 ELF
129+
interpreter 悬空(xim:glibc loader 未部署到 patch 进二进制的路径),PATH shim 在 install() 子进程失效。→ 任何
130+
在 install() 里跑 glibc-dynamic 工具(cmake/autotools)的包都无法闭环。诉求:mcpp 让 install() 的执行环境拿到
131+
**可直接执行** 的 build-dep 工具(要么把 loader/依赖完整部署进 sandbox 并修正 INTERP,要么在 install() 子进程
132+
注入 xvm 的 PATH+LD 环境,要么提供一个"运行 build-dep 工具"的封装 API)。这是 opencv 之所以卡住的直接原因,也是
133+
所有 CMake/autotools compat 包的共同前置。
134+
135+
1. **install() ↔ 消费侧工具链握手**。现状 install()(xim 侧)不知道 mcpp 会用哪个编译器/ABI 链接消费者;
136+
openblas 靠"纯 C、ABI 稳定"绕过。任何 **C++** 源码构建型包都踩:install() 的 g++ 必须与消费者一致,否则
137+
libstdc++/libc++ 冲突(正是本包 linux-gated 的原因)。诉求:mcpp 把已选 toolchain(CC/CXX/AR/ABI 三元组)以稳定
138+
契约(env 或 pkginfo API)暴露给 install()。
139+
2. **feature/capability 传参到 install()**。现状 feature 仅被 mcpp 静态读取,传不进 install();外部构建系统型包的
140+
模块/开关(CMake `-D…`)只能 recipe 内写死,无法 per-consumer 选择。诉求:把 consumer 请求的 features/绑定作为
141+
参数传入 install(),让"外部构建系统的开关"成为真正的 mcpp feature。
142+
3. **一个包产出多库目标(per-target sources/include_dirs)**。现状 `sources`/`include_dirs` 包级全局、`Target`
143+
链接单元;多模块库无法在单描述符按 target 分派各自源码集。诉求:target 携带自己的源码/头子集,或等价的
144+
sub-package 机制(直接决定"OpenCV 拆多库"能否原生表达)。
145+
4. **feature 可携带 `defines` 之外的构建片段(include_dirs / cflags)**。现状刻意排除。对"开关即改配置头/加 -I/-l"的
146+
通用场景(几乎所有 autotools/CMake 库的 WITH_*)表达力不足。诉求:受控地允许 feature 贡献 include_dirs/cflags。
147+
5. **重型 from-source 构建的产物二进制缓存**。现状每次干净构建都重跑 install()(opencv 分钟级)。诉求:对 install()
148+
产物做可复现的二进制缓存/artifact 复用(与 mcpp-index artifact publish 模型对齐),避免 CI/首次 add 反复重编。
149+
150+
## 7. 后续项(P2+)
151+
152+
- macOS:让其用 gcc,或用消费者编译器构建(依赖 §6-1);Windows:MSVC 预编译 或 clang-MSVC CMake(调研报告 R3)。
153+
- 更大模块集(calib3d/features2d/flann/photo/video/objdetect → dnn → highgui)与 `compat.opencv-contrib`(非自由 opt-in)。
154+
- codec 由内置 3rdparty 改绑本仓 provider(compat.zlib 等,依赖 §6-1/§6-2 的能力)。
155+
- CN 镜像 `mcpp-res/opencv@4.13.0`(维护者)。
156+
- CI:install() 的 CMake 构建分钟级,`smoke-examples (opencv)` 可能需放宽 timeout,或 mac/win 进 nightly。

0 commit comments

Comments
 (0)