Skip to content

Commit eefc420

Browse files
committed
feat(pkgs): add public opencv module package 0.0.2 (Form A, linux)
C++23 module layer over OpenCV 5 (import opencv.cv; C++ API unchanged), sources arriving via its compat.opencv5 dependency (full source build, SIMD dispatch kept, build.mcpp consumer-side synthesis). GitHub tag tarball + byte-identical gitcode mcpp-res/opencv CN mirror. Validated like imgui/ffmpeg-module (default-namespace exception): new tests/smoke_opencv_module.sh + opencv-module job, linux-only. Local: smoke passes with mcpp 0.0.96 against the published v0.0.2 tarball.
1 parent 90ee2b1 commit eefc420

5 files changed

Lines changed: 229 additions & 2 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# add `opencv`(公开模块包,Form A)
2+
3+
日期:2026-07-18 · 关联:pkgs/o/opencv.lua、tests/smoke_opencv_module.sh
4+
前置:compat.opencv5(#76)已合并;opencv-m v0.0.1 发布 tag。
5+
6+
## 形态判定
7+
8+
- **Form A 原生模块库**(imgui/ffmpeg 先例):上游
9+
[Sunrisepeak/opencv-m](https://github.com/Sunrisepeak/opencv-m) 自带 mcpp.toml,
10+
描述符只声明元数据 + tag tarball;包内容 = C++23 模块层
11+
(`import opencv.cv;` + 7 个 per-module 接口),OpenCV 5.0.0 源码经其
12+
`compat.opencv5 = "5.0.0"` 依赖到达消费者(全源码直编 + build.mcpp 消费端合成,
13+
SIMD dispatch 保留)。
14+
- **linux-only**(compat.opencv5 目前仅 linux-x86_64 快照)。
15+
- license:模块层 MIT;上游经 compat.opencv5 为 Apache-2.0。
16+
17+
## CN 镜像
18+
19+
gitcode `mcpp-res/opencv`(与 compat 上游 tarball 同仓,tag `v0.0.1``5.0.0`
20+
不冲突):资产 `opencv-m-0.0.1.tar.gz` = GitHub `archive/refs/tags/v0.0.1.tar.gz`
21+
同字节,gtc 上传,sha256 一致。
22+
23+
## 验证方式(imgui/ffmpeg-module 先例)
24+
25+
默认命名空间包不能做 workspace 成员 → `tests/smoke_opencv_module.sh`
26+
重播默认 index 后以 `[dependencies] opencv = "0.0.1"` 消费(gcc@16.1.0),
27+
断言版本/resize/cvtColor/PNG+JPEG roundtrip/videoio registry。仅 Linux
28+
(非 Linux SKIP);smoke 内先 `mcpp index update`(nasm 自举,mcpp#232 规避)。
29+
validate.yml 新增 `opencv-module` job(ubuntu-only)。
30+
31+
## 升级 SOP
32+
33+
opencv-m 发新 tag → 本包新增版本条目(GLOBAL/CN + sha256)→ smoke 的
34+
断言版本随 compat.opencv5 的 OpenCV 版本走。

.github/workflows/validate.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,40 @@ jobs:
391391
run: |
392392
"$MCPP" --version
393393
timeout 2700 bash tests/smoke_ffmpeg_module.sh
394+
395+
# ── Exception: the public `opencv` C++23-module package (namespace "") ──
396+
# Same default-namespace limitation as imgui-module above — validated via a
397+
# reseeding smoke driver instead of a workspace member. Linux-only: its
398+
# compat.opencv5 dependency ships a linux-x86_64 config snapshot (macOS is
399+
# blocked on mcpp#229 dependency cfg-conditional sources).
400+
opencv-module:
401+
runs-on: ubuntu-latest
402+
timeout-minutes: 60
403+
env:
404+
MCPP_EFFECTIVE: "0.0.96" # keep in sync with env.MCPP_VERSION
405+
steps:
406+
- uses: actions/checkout@v4
407+
- name: Restore mcpp registry cache
408+
uses: actions/cache@v4
409+
with:
410+
path: ~/.mcpp/registry
411+
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
412+
restore-keys: |
413+
mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-
414+
- name: Download mcpp
415+
run: |
416+
curl -L -fsS -o mcpp.tar.gz \
417+
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
418+
tar -xzf mcpp.tar.gz
419+
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
420+
mkdir -p "$HOME/.mcpp/registry"
421+
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
422+
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
423+
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
424+
echo "$root/bin" >> "$GITHUB_PATH"
425+
- name: opencv module package smoke
426+
env:
427+
MCPP_INDEX_MIRROR: GLOBAL
428+
run: |
429+
"$MCPP" --version
430+
timeout 2700 bash tests/smoke_opencv_module.sh

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上
2222

2323
本仓收录两类包:
2424

25-
- **原生 mcpp 模块库**:以 C++23 模块发布、`import` 即用,包括 `mcpplibs.*``nlohmann.json``imgui``ffmpeg`,以及由
25+
- **原生 mcpp 模块库**:以 C++23 模块发布、`import` 即用,包括 `mcpplibs.*``nlohmann.json``imgui``ffmpeg``opencv`,以及由
2626
用户基于 mcpp 开发并登记进索引的库(如 `tensorvia-cpu`)。其上游通常自带 `mcpp.toml`,描述文件(Form A)只声明
2727
元数据与下载地址。
2828
- **第三方 C/C++ 库(`compat`)**:其上游不提供 mcpp 支持,描述文件(Form B)内联构建信息。该类库存在
@@ -32,7 +32,7 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上
3232

3333
| 形态 | 示例 |
3434
|------|------|
35-
| 原生模块库(Form A) | [`mcpplibs.xpkg`](pkgs/x/xpkg.lua) · [`mcpplibs.tinyhttps`](pkgs/t/tinyhttps.lua) · [`tensorvia-cpu`](pkgs/t/tensorvia-cpu.lua) · [`ffmpeg`](pkgs/f/ffmpeg.lua)(模块层,源码经 `compat.ffmpeg` 直编) |
35+
| 原生模块库(Form A) | [`mcpplibs.xpkg`](pkgs/x/xpkg.lua) · [`mcpplibs.tinyhttps`](pkgs/t/tinyhttps.lua) · [`tensorvia-cpu`](pkgs/t/tensorvia-cpu.lua) · [`ffmpeg`](pkgs/f/ffmpeg.lua)(模块层,源码经 `compat.ffmpeg` 直编) · [`opencv`](pkgs/o/opencv.lua)(模块层,源码经 `compat.opencv5` 直编) |
3636
| C 源码 compat(含 `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) |
3737
| header-only(含 `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) |
3838
| 外部构建系统(`install()` 从源码构建) | [`compat.openblas`](pkgs/c/compat.openblas.lua)(Make) · [`compat.opencv`](pkgs/c/compat.opencv.lua)(CMake) |

pkgs/o/opencv.lua

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
-- Form A descriptor: the public opencv module package ships its own
2+
-- mcpp.toml. mcpp's default lookup finds <verdir>/*/mcpp.toml inside
3+
-- the GitHub source tarball wrap.
4+
--
5+
-- The package is the thin C++23 module layer (import opencv.cv; and 7
6+
-- per-module interfaces) over OpenCV 5's unchanged C++ API; the OpenCV
7+
-- sources themselves arrive through its compat.opencv5 dependency (full
8+
-- source build with SIMD dispatch + build.mcpp consumer-side synthesis —
9+
-- see pkgs/c/compat.opencv5.lua). Linux-only for now: compat.opencv5
10+
-- carries a linux-x86_64 config snapshot.
11+
--
12+
package = {
13+
spec = "1",
14+
name = "opencv",
15+
namespace = "",
16+
description = "C++23 module package for OpenCV 5 (import opencv.cv) — full source build via compat.opencv5, C++ API unchanged",
17+
licenses = {"MIT"}, -- module layer; upstream via compat.opencv5 is Apache-2.0
18+
repo = "https://github.com/Sunrisepeak/opencv-m",
19+
type = "package",
20+
21+
xpm = {
22+
linux = {
23+
["0.0.2"] = {
24+
url = {
25+
GLOBAL = "https://github.com/Sunrisepeak/opencv-m/archive/refs/tags/v0.0.2.tar.gz",
26+
CN = "https://gitcode.com/mcpp-res/opencv/releases/download/v0.0.2/opencv-m-0.0.2.tar.gz",
27+
},
28+
sha256 = "26c3eb680baff72ce71dd41d098910b5456487a686d95839b2157c6618ccfb7c",
29+
},
30+
},
31+
},
32+
33+
-- (no `mcpp` field -- default lookup will find <verdir>/*/mcpp.toml)
34+
}

tests/smoke_opencv_module.sh

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env bash
2+
# Smoke-test the public opencv module package through this checkout as a local
3+
# mcpp path index. This validates user-facing import-only consumption:
4+
# `[dependencies] opencv = "0.0.2"` → `import opencv.cv;`. Linux-only (the
5+
# package's compat.ffmpeg dependency ships a linux-x86_64 config snapshot).
6+
set -euo pipefail
7+
8+
if [[ "$(uname -s)" != "Linux" ]]; then
9+
echo "SKIP: opencv module package is linux-only for now."
10+
exit 0
11+
fi
12+
13+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
14+
MCPP_BIN="${MCPP:-}"
15+
if [[ -z "$MCPP_BIN" ]]; then
16+
MCPP_BIN="$(command -v mcpp || true)"
17+
fi
18+
if [[ -z "$MCPP_BIN" || ! -x "$MCPP_BIN" ]]; then
19+
echo "FATAL: set MCPP=/path/to/mcpp or put mcpp on PATH" >&2
20+
exit 1
21+
fi
22+
23+
TMP="$(mktemp -d)"
24+
if [[ "${MCPP_INDEX_KEEP_SMOKE_TMP:-0}" == "1" ]]; then
25+
echo "KEEP: $TMP"
26+
else
27+
trap 'rm -rf "$TMP"' EXIT
28+
fi
29+
30+
if [[ -n "${MCPP_INDEX_SMOKE_MCPP_HOME:-}" ]]; then
31+
export MCPP_HOME="$MCPP_INDEX_SMOKE_MCPP_HOME"
32+
else
33+
export MCPP_HOME="$TMP/mcpp-home"
34+
fi
35+
mkdir -p "$MCPP_HOME/registry/data/xpkgs"
36+
37+
USER_MCPP="${HOME}/.mcpp"
38+
link_xpkgs() {
39+
local src="$1"
40+
[[ -d "$src" ]] || return 0
41+
find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do
42+
ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true
43+
done
44+
}
45+
link_xpkgs "${MCPP_INDEX_SMOKE_XPKGS_DIR:-}"
46+
link_xpkgs "$USER_MCPP/registry/data/xpkgs"
47+
if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then
48+
mkdir -p "$MCPP_HOME/registry/data/xim-pkgindex"
49+
cp -a "$USER_MCPP/registry/data/xim-pkgindex/." "$MCPP_HOME/registry/data/xim-pkgindex/" 2>/dev/null || true
50+
rm -f "$MCPP_HOME/registry/data/xim-pkgindex/.xlings-index-cache.json"
51+
fi
52+
if [[ -d "$USER_MCPP/registry/bin" ]]; then
53+
mkdir -p "$MCPP_HOME/registry"
54+
ln -s "$USER_MCPP/registry/bin" "$MCPP_HOME/registry/bin" 2>/dev/null || true
55+
fi
56+
if [[ -f "$USER_MCPP/config.toml" ]]; then
57+
cp -f "$USER_MCPP/config.toml" "$MCPP_HOME/config.toml" 2>/dev/null || true
58+
fi
59+
60+
# compat.opencv5 carries NASM .asm sources; mcpp bootstraps nasm from the
61+
# sandbox package index. Release archives vendor a pre-xim-pkgindex#398
62+
# snapshot whose nasm.lua "installs" empty (mcpp#232) — refresh BEFORE
63+
# reseeding the default index below so the update can't clobber the reseed.
64+
"$MCPP_BIN" index update
65+
66+
default_index="$MCPP_HOME/registry/data/mcpplibs"
67+
# Reseed cleanly (see smoke_imgui_module.sh for why .git is skipped).
68+
rm -rf "$default_index"
69+
mkdir -p "$default_index"
70+
( cd "$ROOT" && find . -mindepth 1 -maxdepth 1 ! -name .git -exec cp -a {} "$default_index/" \; )
71+
rm -f "$default_index/.xlings-index-cache.json"
72+
printf 'ok\n' > "$default_index/.mcpp-index-updated"
73+
74+
"$MCPP_BIN" self config --mirror "${MCPP_INDEX_MIRROR:-GLOBAL}" >/dev/null
75+
76+
mkdir -p "$TMP/opencv-module-smoke/src"
77+
cd "$TMP/opencv-module-smoke"
78+
cat > mcpp.toml <<EOF
79+
[package]
80+
name = "opencv-module-smoke"
81+
version = "0.1.0"
82+
83+
[toolchain]
84+
default = "${MCPP_INDEX_OPENCV_MODULE_TOOLCHAIN:-gcc@16.1.0}"
85+
86+
[dependencies]
87+
opencv = "0.0.2"
88+
89+
[targets.opencv-module-smoke]
90+
kind = "bin"
91+
main = "src/main.cpp"
92+
EOF
93+
94+
cat > src/main.cpp <<'EOF'
95+
import std;
96+
import opencv.cv;
97+
98+
int main() {
99+
if (cv::getVersionString() != "5.0.0") return 1;
100+
101+
cv::Mat img(64, 64, cv::CV_8UC3, cv::Scalar(30, 60, 90));
102+
cv::circle(img, {32, 32}, 20, {255, 255, 255}, -1);
103+
cv::Mat big, gray;
104+
cv::resize(img, big, {128, 128}, 0, 0, cv::INTER_CUBIC);
105+
cv::cvtColor(big, gray, cv::COLOR_BGR2GRAY);
106+
if (gray.size() != cv::Size(128, 128)) return 2;
107+
108+
for (const char* ext : { ".png", ".jpg" }) {
109+
std::vector<unsigned char> buf;
110+
if (!cv::imencode(ext, big, buf)) return 3;
111+
cv::Mat back = cv::imdecode(buf, cv::IMREAD_COLOR);
112+
if (back.empty() || back.size() != big.size()) return 4;
113+
}
114+
115+
if (cv::videoio_registry::getBackends().empty()) return 5;
116+
std::println("OpenCV {} module package ok", cv::getVersionString());
117+
return 0;
118+
}
119+
EOF
120+
121+
"$MCPP_BIN" build
122+
"$MCPP_BIN" run

0 commit comments

Comments
 (0)