1111-- .agents/docs/2026-07-08-opencv-implementation-and-verification.md.
1212--
1313-- HOST-FREE / ecosystem-closed: the build uses ONLY ecosystem tools — xim:cmake,
14- -- xim:make, xim:gcc (declared build-deps) — never host cmake/make/gcc. Verified
15- -- offline under a network-isolated namespace (unshare -rn): zero downloads (gapi's
16- -- ADE fetch is killed by WITH_ADE=OFF); everything else is compiled from the
17- -- tarball's bundled 3rdparty/ (zlib + libpng + libjpeg-turbo built via BUILD_*=ON).
14+ -- xim:ninja + the per-OS compiler (declared build-deps) — never host
15+ -- cmake/ninja/compiler. Zero downloads at build time (gapi's ADE fetch is killed by
16+ -- WITH_ADE=OFF); everything else is compiled from the tarball's bundled 3rdparty/
17+ -- (zlib + libpng + libjpeg-turbo built via BUILD_*=ON).
1818--
1919-- MVP module set (this recipe): core + imgproc + imgcodecs (BUILD_LIST). This is a
2020-- fixed, curated profile — OpenCV's WITH_*/BUILD_opencv_* toggles CANNOT be mcpp
2323-- variants (calib3d/dnn/highgui/contrib) are separate follow-up packages, not
2424-- per-consumer features. See the impl doc §"generic mcpp asks".
2525--
26- -- ABI: OpenCV is C++, so its .a must be linked by the SAME C++ ABI (libstdc++) as
27- -- the consumer. install() builds with xim:gcc (gcc/libstdc++); the consumer must use
28- -- a gcc toolchain (the test project pins gcc@16.1.0). A clang/libc++ consumer would
29- -- ABI-clash — this is the toolchain-handshake gap noted in the impl doc.
26+ -- ABI: OpenCV is C++, so its static libs must be linked by the SAME C++ ABI as the
27+ -- consumer. install() therefore builds with the compiler whose ABI matches each
28+ -- platform's mcpp consumer — Linux gcc/libstdc++, macOS clang/libc++ (xim:llvm),
29+ -- Windows clang-cl/msvc-stl — selected in install() by os.host(). See that function
30+ -- for the per-platform toolchain + build-env details.
3031--
31- -- Verified locally (mcpp 0.0.85, linux x86_64): build → link → run green
32- -- (opencv ok=1 core=4x4x3 gray(blue)=29 png_bytes=82 decoded=4x4). macOS follows the
33- -- same source-CMake path but is NOT yet verified — its default toolchain is clang
34- -- (libc++), which would ABI-clash with the gcc/libstdc++ .a this recipe builds
35- -- (the toolchain-handshake gap); making macOS use gcc, or building with the
36- -- consumer's compiler, is a follow-up. Windows (MSVC-ABI clang vs OpenCV CMake) is
37- -- likewise a follow-up. The test project is therefore LINUX-GATED for now
38- -- (gui-stack precedent): off-linux it is a clean no-op.
32+ -- All three platforms build → link → run green in CI (workspace linux/macOS/windows):
33+ -- the roundtrip test asserts core (4x4x3 BGR), imgproc (BGR->GRAY, blue luma 29) and
34+ -- imgcodecs (PNG encode/decode round-trip).
3935package = {
4036 spec = " 1" ,
4137 namespace = " compat" ,
@@ -152,14 +148,6 @@ local function sh_quote(value)
152148 return " '" .. tostring (value ):gsub (" '" , " '\\ ''" ) .. " '"
153149end
154150
155- -- TEMP diagnostics path — cross-platform (no /tmp on Windows). GitHub sets
156- -- RUNNER_TEMP on every runner OS; the CI step cats these files after a failure.
157- local function diag_path (name )
158- local base = os.getenv (" RUNNER_TEMP" ) or os.getenv (" TMPDIR" )
159- or os.getenv (" TEMP" ) or " /tmp"
160- return path .join (base , name )
161- end
162-
163151-- Tools are invoked by BARE name, resolved off the install() PATH that xim sets up
164152-- from the declared build-deps (the compat.openblas `CC=gcc` approach). This is
165153-- deliberate: xim:cmake is glibc-dynamic, so exec'ing its raw binary by absolute
@@ -182,20 +170,9 @@ local function find_srcroot(version)
182170end
183171
184172local function _install_impl ()
185- -- [TEMP macOS debug] on-disk trace: the install() failure is invisible under
186- -- xim's interface mode; write progress to $HOME so CI can surface where it dies.
187- local _trbuf = " "
188- local function trace (s )
189- _trbuf = _trbuf .. tostring (s ) .. " \n "
190- pcall (function () io .writefile (diag_path (" ocv_trace.txt" ), _trbuf ) end )
191- end
192- trace (" enter host=" .. tostring (os .host ()))
193173 local version = pkginfo .version ()
194174 local prefix = pkginfo .install_dir ()
195175 local srcroot = find_srcroot (version )
196- trace (" version=" .. tostring (version ))
197- trace (" prefix=" .. tostring (prefix ))
198- trace (" srcroot=" .. tostring (srcroot ) .. " isdir=" .. tostring (os .isdir (srcroot )))
199176
200177 local jobs = (os .default_njob and os .default_njob ()) or 4
201178
@@ -316,14 +293,10 @@ local function _install_impl()
316293 -- compat.openblas). Then build out-of-source into ./_bld and install
317294 -- headers+libs back into prefix, which is now the cwd.
318295 os .tryrm (prefix )
319- trace (" compiler gcc=" .. tostring (gcc ) .. " gxx=" .. tostring (gxx ) .. " isMac=" .. tostring (isMac ))
320- trace (" libenv=[" .. tostring (libenv ) .. " ]" )
321296 os .mv (srcroot , prefix )
322297 os .cd (prefix )
323- trace (" after mv+cd, prefix isdir=" .. tostring (os .isdir (prefix )))
324298
325299 local logf = path .join (prefix , " mcpp_opencv_build.log" )
326- trace (" about to run cmake configure; logf=" .. tostring (logf ))
327300
328301 -- Value quoting differs by driver: the linux/macOS build runs through bash
329302 -- (sh_quote), Windows through cmd (see the exec branch) where single quotes
@@ -457,29 +430,15 @@ local function _install_impl()
457430 return true
458431end
459432
460- -- Surface the on-disk build log to the console on ANY failure. xim's interface
461- -- mode suppresses the cmake/make subprocess stdout, so without this a failed CI
462- -- build is invisible (the only symptom is the downstream "opencv2/core.hpp: No
463- -- such file"). Fires whether _install_impl raised or returned false.
464- -- xlings' interface mode swallows log.*/subprocess output, so write the failure
465- -- detail to a file the CI step can `cat` instead of logging it.
466- local function _dump_diagnostics (raised , err )
467- local out = {}
468- if raised then table.insert (out , " install() raised: " .. tostring (err )) end
469- local logf = path .join (pkginfo .install_dir (), " mcpp_opencv_build.log" )
470- if os .isfile (logf ) then
471- table.insert (out , " ---- mcpp_opencv_build.log ----\n " .. tostring (io .readfile (logf )))
472- else
473- table.insert (out , " no build log at " .. logf )
474- table.insert (out , " PATH=" .. tostring (os.getenv (" PATH" )))
475- end
476- pcall (function () io .writefile (diag_path (" ocv_diag.txt" ), table.concat (out , " \n " ) .. " \n " ) end )
477- end
478-
479433function install ()
480434 local ok , ret = pcall (_install_impl )
481435 if not ok or ret == false then
482- _dump_diagnostics (not ok , ret )
436+ -- Point at the on-disk build log: xim's interface mode suppresses the
437+ -- cmake subprocess stdout, so the log is the only record of a failed
438+ -- source build (the compat.openblas pattern).
439+ local logf = path .join (pkginfo .install_dir (), " mcpp_opencv_build.log" )
440+ log .error (" compat.opencv install() failed (%s); see %s" ,
441+ ok and " returned false" or tostring (ret ), logf )
483442 return false
484443 end
485444 return true
0 commit comments