From eefc420116d31ca2ac88e73894cb5339e77e18f5 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 18 Jul 2026 14:19:04 +0800 Subject: [PATCH] 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. --- .../docs/2026-07-18-add-opencv-module-plan.md | 34 +++++ .github/workflows/validate.yml | 37 ++++++ README.md | 4 +- pkgs/o/opencv.lua | 34 +++++ tests/smoke_opencv_module.sh | 122 ++++++++++++++++++ 5 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 .agents/docs/2026-07-18-add-opencv-module-plan.md create mode 100644 pkgs/o/opencv.lua create mode 100755 tests/smoke_opencv_module.sh diff --git a/.agents/docs/2026-07-18-add-opencv-module-plan.md b/.agents/docs/2026-07-18-add-opencv-module-plan.md new file mode 100644 index 0000000..8d286cf --- /dev/null +++ b/.agents/docs/2026-07-18-add-opencv-module-plan.md @@ -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 版本走。 diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 8c5c60f..76a72f1 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -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 diff --git a/README.md b/README.md index d39eba8..5410c27 100644 --- a/README.md +++ b/README.md @@ -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)内联构建信息。该类库存在 @@ -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) | diff --git a/pkgs/o/opencv.lua b/pkgs/o/opencv.lua new file mode 100644 index 0000000..a947bde --- /dev/null +++ b/pkgs/o/opencv.lua @@ -0,0 +1,34 @@ +-- Form A descriptor: the public opencv module package ships its own +-- mcpp.toml. mcpp's default lookup finds /*/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 /*/mcpp.toml) +} diff --git a/tests/smoke_opencv_module.sh b/tests/smoke_opencv_module.sh new file mode 100755 index 0000000..327512c --- /dev/null +++ b/tests/smoke_opencv_module.sh @@ -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 < 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 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