Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .agents/docs/2026-07-18-add-opencv-module-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# add `opencv`(公开模块包,Form A)

日期:2026-07-18 · 关联:pkgs/o/opencv.lua、tests/smoke_opencv_module.sh
前置:compat.opencv5(#76)已合并;opencv-m v0.0.1 发布 tag。

## 形态判定

- **Form A 原生模块库**(imgui/ffmpeg 先例):上游
[Sunrisepeak/opencv-m](https://github.com/Sunrisepeak/opencv-m) 自带 mcpp.toml,
描述符只声明元数据 + tag tarball;包内容 = C++23 模块层
(`import opencv.cv;` + 7 个 per-module 接口),OpenCV 5.0.0 源码经其
`compat.opencv5 = "5.0.0"` 依赖到达消费者(全源码直编 + build.mcpp 消费端合成,
SIMD dispatch 保留)。
- **linux-only**(compat.opencv5 目前仅 linux-x86_64 快照)。
- license:模块层 MIT;上游经 compat.opencv5 为 Apache-2.0。

## CN 镜像

gitcode `mcpp-res/opencv`(与 compat 上游 tarball 同仓,tag `v0.0.1` 与 `5.0.0`
不冲突):资产 `opencv-m-0.0.1.tar.gz` = GitHub `archive/refs/tags/v0.0.1.tar.gz`
同字节,gtc 上传,sha256 一致。

## 验证方式(imgui/ffmpeg-module 先例)

默认命名空间包不能做 workspace 成员 → `tests/smoke_opencv_module.sh`
重播默认 index 后以 `[dependencies] opencv = "0.0.1"` 消费(gcc@16.1.0),
断言版本/resize/cvtColor/PNG+JPEG roundtrip/videoio registry。仅 Linux
(非 Linux SKIP);smoke 内先 `mcpp index update`(nasm 自举,mcpp#232 规避)。
validate.yml 新增 `opencv-module` job(ubuntu-only)。

## 升级 SOP

opencv-m 发新 tag → 本包新增版本条目(GLOBAL/CN + sha256)→ smoke 的
断言版本随 compat.opencv5 的 OpenCV 版本走。
37 changes: 37 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,40 @@ jobs:
run: |
"$MCPP" --version
timeout 2700 bash tests/smoke_ffmpeg_module.sh

# ── Exception: the public `opencv` C++23-module package (namespace "") ──
# Same default-namespace limitation as imgui-module above — validated via a
# reseeding smoke driver instead of a workspace member. Linux-only: its
# compat.opencv5 dependency ships a linux-x86_64 config snapshot (macOS is
# blocked on mcpp#229 dependency cfg-conditional sources).
opencv-module:
runs-on: ubuntu-latest
timeout-minutes: 60
env:
MCPP_EFFECTIVE: "0.0.96" # keep in sync with env.MCPP_VERSION
steps:
- uses: actions/checkout@v4
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-
- name: Download mcpp
run: |
curl -L -fsS -o mcpp.tar.gz \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
tar -xzf mcpp.tar.gz
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
- name: opencv module package smoke
env:
MCPP_INDEX_MIRROR: GLOBAL
run: |
"$MCPP" --version
timeout 2700 bash tests/smoke_opencv_module.sh
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上

本仓收录两类包:

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

| 形态 | 示例 |
|------|------|
| 原生模块库(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` 直编) |
| 原生模块库(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` 直编) |
| C 源码 compat(含 `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) |
| header-only(含 `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) |
| 外部构建系统(`install()` 从源码构建) | [`compat.openblas`](pkgs/c/compat.openblas.lua)(Make) · [`compat.opencv`](pkgs/c/compat.opencv.lua)(CMake) |
Expand Down
34 changes: 34 additions & 0 deletions pkgs/o/opencv.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-- Form A descriptor: the public opencv module package ships its own
-- mcpp.toml. mcpp's default lookup finds <verdir>/*/mcpp.toml inside
-- the GitHub source tarball wrap.
--
-- The package is the thin C++23 module layer (import opencv.cv; and 7
-- per-module interfaces) over OpenCV 5's unchanged C++ API; the OpenCV
-- sources themselves arrive through its compat.opencv5 dependency (full
-- source build with SIMD dispatch + build.mcpp consumer-side synthesis —
-- see pkgs/c/compat.opencv5.lua). Linux-only for now: compat.opencv5
-- carries a linux-x86_64 config snapshot.
--
package = {
spec = "1",
name = "opencv",
namespace = "",
description = "C++23 module package for OpenCV 5 (import opencv.cv) — full source build via compat.opencv5, C++ API unchanged",
licenses = {"MIT"}, -- module layer; upstream via compat.opencv5 is Apache-2.0
repo = "https://github.com/Sunrisepeak/opencv-m",
type = "package",

xpm = {
linux = {
["0.0.2"] = {
url = {
GLOBAL = "https://github.com/Sunrisepeak/opencv-m/archive/refs/tags/v0.0.2.tar.gz",
CN = "https://gitcode.com/mcpp-res/opencv/releases/download/v0.0.2/opencv-m-0.0.2.tar.gz",
},
sha256 = "26c3eb680baff72ce71dd41d098910b5456487a686d95839b2157c6618ccfb7c",
},
},
},

-- (no `mcpp` field -- default lookup will find <verdir>/*/mcpp.toml)
}
122 changes: 122 additions & 0 deletions tests/smoke_opencv_module.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bash
# Smoke-test the public opencv module package through this checkout as a local
# mcpp path index. This validates user-facing import-only consumption:
# `[dependencies] opencv = "0.0.2"` → `import opencv.cv;`. Linux-only (the
# package's compat.ffmpeg dependency ships a linux-x86_64 config snapshot).
set -euo pipefail

if [[ "$(uname -s)" != "Linux" ]]; then
echo "SKIP: opencv module package is linux-only for now."
exit 0
fi

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MCPP_BIN="${MCPP:-}"
if [[ -z "$MCPP_BIN" ]]; then
MCPP_BIN="$(command -v mcpp || true)"
fi
if [[ -z "$MCPP_BIN" || ! -x "$MCPP_BIN" ]]; then
echo "FATAL: set MCPP=/path/to/mcpp or put mcpp on PATH" >&2
exit 1
fi

TMP="$(mktemp -d)"
if [[ "${MCPP_INDEX_KEEP_SMOKE_TMP:-0}" == "1" ]]; then
echo "KEEP: $TMP"
else
trap 'rm -rf "$TMP"' EXIT
fi

if [[ -n "${MCPP_INDEX_SMOKE_MCPP_HOME:-}" ]]; then
export MCPP_HOME="$MCPP_INDEX_SMOKE_MCPP_HOME"
else
export MCPP_HOME="$TMP/mcpp-home"
fi
mkdir -p "$MCPP_HOME/registry/data/xpkgs"

USER_MCPP="${HOME}/.mcpp"
link_xpkgs() {
local src="$1"
[[ -d "$src" ]] || return 0
find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r pkg; do
ln -s "$pkg" "$MCPP_HOME/registry/data/xpkgs/$(basename "$pkg")" 2>/dev/null || true
done
}
link_xpkgs "${MCPP_INDEX_SMOKE_XPKGS_DIR:-}"
link_xpkgs "$USER_MCPP/registry/data/xpkgs"
if [[ -d "$USER_MCPP/registry/data/xim-pkgindex" ]]; then
mkdir -p "$MCPP_HOME/registry/data/xim-pkgindex"
cp -a "$USER_MCPP/registry/data/xim-pkgindex/." "$MCPP_HOME/registry/data/xim-pkgindex/" 2>/dev/null || true
rm -f "$MCPP_HOME/registry/data/xim-pkgindex/.xlings-index-cache.json"
fi
if [[ -d "$USER_MCPP/registry/bin" ]]; then
mkdir -p "$MCPP_HOME/registry"
ln -s "$USER_MCPP/registry/bin" "$MCPP_HOME/registry/bin" 2>/dev/null || true
fi
if [[ -f "$USER_MCPP/config.toml" ]]; then
cp -f "$USER_MCPP/config.toml" "$MCPP_HOME/config.toml" 2>/dev/null || true
fi

# compat.opencv5 carries NASM .asm sources; mcpp bootstraps nasm from the
# sandbox package index. Release archives vendor a pre-xim-pkgindex#398
# snapshot whose nasm.lua "installs" empty (mcpp#232) — refresh BEFORE
# reseeding the default index below so the update can't clobber the reseed.
"$MCPP_BIN" index update

default_index="$MCPP_HOME/registry/data/mcpplibs"
# Reseed cleanly (see smoke_imgui_module.sh for why .git is skipped).
rm -rf "$default_index"
mkdir -p "$default_index"
( cd "$ROOT" && find . -mindepth 1 -maxdepth 1 ! -name .git -exec cp -a {} "$default_index/" \; )
rm -f "$default_index/.xlings-index-cache.json"
printf 'ok\n' > "$default_index/.mcpp-index-updated"

"$MCPP_BIN" self config --mirror "${MCPP_INDEX_MIRROR:-GLOBAL}" >/dev/null

mkdir -p "$TMP/opencv-module-smoke/src"
cd "$TMP/opencv-module-smoke"
cat > mcpp.toml <<EOF
[package]
name = "opencv-module-smoke"
version = "0.1.0"

[toolchain]
default = "${MCPP_INDEX_OPENCV_MODULE_TOOLCHAIN:-gcc@16.1.0}"

[dependencies]
opencv = "0.0.2"

[targets.opencv-module-smoke]
kind = "bin"
main = "src/main.cpp"
EOF

cat > src/main.cpp <<'EOF'
import std;
import opencv.cv;

int main() {
if (cv::getVersionString() != "5.0.0") return 1;

cv::Mat img(64, 64, cv::CV_8UC3, cv::Scalar(30, 60, 90));
cv::circle(img, {32, 32}, 20, {255, 255, 255}, -1);
cv::Mat big, gray;
cv::resize(img, big, {128, 128}, 0, 0, cv::INTER_CUBIC);
cv::cvtColor(big, gray, cv::COLOR_BGR2GRAY);
if (gray.size() != cv::Size(128, 128)) return 2;

for (const char* ext : { ".png", ".jpg" }) {
std::vector<unsigned char> buf;
if (!cv::imencode(ext, big, buf)) return 3;
cv::Mat back = cv::imdecode(buf, cv::IMREAD_COLOR);
if (back.empty() || back.size() != big.size()) return 4;
}

if (cv::videoio_registry::getBackends().empty()) return 5;
std::println("OpenCV {} module package ok", cv::getVersionString());
return 0;
}
EOF

"$MCPP_BIN" build
"$MCPP_BIN" run
Loading