Skip to content

Commit ff96d2a

Browse files
committed
fix(opencv): bare-name build tools + header verify + build-log surfacing
CI workspace(linux) failed: opencv install() produced no headers (consumer compile hit 'opencv2/core.hpp: No such file'), yet only 16s elapsed after the tarball download — the CMake build never ran to completion, and xim's interface mode suppressed the subprocess output so the real error was invisible. Root cause (per this descriptor's own header comment): the raw xim:cmake binary is glibc-DYNAMIC; its ELF interpreter points at xim:glibc's loader, wired only through xim's PATH launcher. Invoking it by ABSOLUTE path (the old dep_bin) works on a warm host but fails 'cannot execute: required file not found' on a cold CI runner. Fix: invoke cmake/make/gcc/g++ by BARE name so the loader-wired launchers are used (xim:make is musl-static so it tolerated absolute paths — that's why compat.openblas never hit this). Also: verify installed headers (include/opencv4/opencv2/*.hpp), not just libs, so a partial install fails loudly here instead of at the consumer; and dump mcpp_opencv_build.log (or PATH) on any failure so CI shows ground truth. Verified locally from a clean MCPP_HOME + vendored xlings + GLOBAL mirror: fresh opencv build, headers materialise, roundtrip ok.
1 parent 309cd70 commit ff96d2a

1 file changed

Lines changed: 39 additions & 21 deletions

File tree

pkgs/c/compat.opencv.lua

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -157,22 +157,17 @@ local function _install_impl()
157157

158158
local jobs = (os.default_njob and os.default_njob()) or 4
159159

160-
-- Resolve build-dep tools via pkginfo.build_dep (the compat.openblas pattern:
161-
-- deps are provisioned by xlings; we just take each tool's bin/). Bare-name
162-
-- PATH fallback otherwise. No hand-wiring of loaders/toolchains here — that is
163-
-- xlings's job.
164-
local function dep_bin(name, exe)
165-
local d = pkginfo.build_dep and pkginfo.build_dep(name)
166-
if d and d.bin then
167-
local cand = path.join(d.bin, exe)
168-
if os.isfile(cand) then return cand end
169-
end
170-
return exe
171-
end
172-
local cmake = dep_bin("xim:cmake", "cmake")
173-
local make = dep_bin("xim:make", "make")
174-
local gcc = dep_bin("xim:gcc", "gcc")
175-
local gxx = dep_bin("xim:gcc", "g++")
160+
-- Invoke build tools by BARE name (NOT absolute paths to the raw binaries).
161+
-- xim puts loader-wired LAUNCHERS for the declared build-deps on the install()
162+
-- PATH; bare names hit those. xim:cmake is glibc-DYNAMIC — its raw binary's
163+
-- ELF interpreter points at xim:glibc's loader, which is only wired through
164+
-- the launcher. Calling the raw binary by ABSOLUTE path works on a warm host
165+
-- (glibc already materialised at the patched interpreter path) but fails on a
166+
-- cold CI runner with "cannot execute: required file not found" — which is
167+
-- exactly what silently broke the install() build in CI. (xim:make is
168+
-- musl-static so it'd tolerate an absolute path; bare names are uniform +
169+
-- correct for all four.) This matches the header-comment strategy above.
170+
local cmake, make, gcc, gxx = "cmake", "make", "gcc", "g++"
176171

177172
-- Move the extracted tree INTO the install dir (this CREATES prefix — xim's
178173
-- restricted Lua has no os.mkdir; os.cd is the only dir primitive, same as
@@ -223,15 +218,21 @@ local function _install_impl()
223218
"cd %s && %s --install _bld >> %s 2>&1",
224219
sh_quote(prefix), sh_quote(cmake), sh_quote(logf)))))
225220

226-
-- Verify the expected static libs materialised (exit-0 != correct).
221+
-- Verify BOTH the static libs AND the installed public headers materialised
222+
-- (exit-0 != correct; and a partial install that lays libs but not headers at
223+
-- include/opencv4 would slip past a libs-only check, then fail the consumer
224+
-- compile with a bare "opencv2/core.hpp: No such file").
227225
local must = {
228226
path.join(prefix, "lib", "libopencv_core.a"),
229227
path.join(prefix, "lib", "libopencv_imgproc.a"),
230228
path.join(prefix, "lib", "libopencv_imgcodecs.a"),
229+
path.join(prefix, "include", "opencv4", "opencv2", "core.hpp"),
230+
path.join(prefix, "include", "opencv4", "opencv2", "imgproc.hpp"),
231+
path.join(prefix, "include", "opencv4", "opencv2", "imgcodecs.hpp"),
231232
}
232233
for _, m in ipairs(must) do
233234
if not os.isfile(m) then
234-
log.error("compat.opencv: expected lib missing: %s (see %s)", m, logf)
235+
log.error("compat.opencv: expected artifact missing: %s (see %s)", m, logf)
235236
return false
236237
end
237238
end
@@ -243,14 +244,31 @@ local function _install_impl()
243244
return true
244245
end
245246

247+
-- Surface the on-disk build log to the console on ANY failure. xim's interface
248+
-- mode suppresses the cmake/make subprocess stdout, so without this a failed CI
249+
-- build is invisible (the only symptom is the downstream "opencv2/core.hpp: No
250+
-- such file"). Fires whether _install_impl raised or returned false.
251+
local function _dump_diagnostics(raised, err)
252+
if raised then
253+
log.error("compat.opencv install() raised: %s", tostring(err))
254+
end
255+
local logf = path.join(pkginfo.install_dir(), "mcpp_opencv_build.log")
256+
if os.isfile(logf) then
257+
log.error("---- mcpp_opencv_build.log ----\n%s", tostring(io.readfile(logf)))
258+
else
259+
log.error("compat.opencv: no build log at %s", logf)
260+
log.error("compat.opencv: PATH=%s", tostring(os.getenv("PATH")))
261+
end
262+
end
263+
246264
function install()
247265
if os.host() == "windows" then
248266
-- Windows uses the generated_files anchor; source build is a follow-up.
249267
return true
250268
end
251-
local ok, err = pcall(_install_impl)
252-
if not ok then
253-
log.error("compat.opencv install() failed: %s", tostring(err))
269+
local ok, ret = pcall(_install_impl)
270+
if not ok or ret == false then
271+
_dump_diagnostics(not ok, ret)
254272
return false
255273
end
256274
return true

0 commit comments

Comments
 (0)