Skip to content

Commit a1c18e8

Browse files
committed
fix(compat.opencv): robust unifont font locator (mcpp#241 dep_dir) for 0.0.99 store layout
The unifont build.mcpp located WenQuanYiMicroHei.ttf.gz via a fixed `<data>/xpkgs/<pkg>/<ver> -> <data>/runtimedir` hop off MCPP_MANIFEST_DIR. mcpp 0.0.99 (xlings 0.4.67) shifted the store layout, so that exact hop missed and the opencv-unifont member failed ('font not found near ...'). Replace with a layout-agnostic locator: anchor on the authoritative per-dep dir contract (mcpp#241 MCPP_DEP_<NAME>_DIR, tried under both the canonical `compat.opencv-unifont` and short `opencv-unifont` names), walk up probing runtimedir/ at every level, then fall back to the old verdir sweep and a bounded recursive search from the store root. On failure, dump every MCPP_DEP_*/MANIFEST/OUT dir so a CI log is self-diagnosing. Applied to both the generated pkgs/c/compat.opencv.lua build.mcpp and its tools/compat-opencv/build_mcpp_template.cpp source (syntax-checked w/ gcc16).
1 parent 3ee5bd0 commit a1c18e8

2 files changed

Lines changed: 123 additions & 22 deletions

File tree

pkgs/c/compat.opencv.lua

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ package = {
240240
#include <cstring>
241241
#include <filesystem>
242242
#include <fstream>
243+
#include <initializer_list>
243244
#include <sstream>
244245
#include <string>
245246
#include <vector>
@@ -444,29 +445,78 @@ int main() {
444445
blob2hdr(wrap / "modules/imgproc/fonts/Rubik-Italic.ttf.gz", out / "builtin_font_italic.h", "OcvBuiltinFontItalic");
445446
446447
// 1b. unifont feature: hex-embed the CJK font pulled in by the
447-
// compat.opencv-unifont dependency. Its payload is a raw .gz the
448-
// installer parks byte-preserved in the store's shared
449-
// data/runtimedir/ (no MCPP_DEP_<NAME>_DIR contract var yet), so
450-
// resolve it relative to this package's store location, with a
451-
// verdir sweep as fallback.
448+
// compat.opencv-unifont dependency. Its raw .gz payload is parked by
449+
// the installer in a shared runtimedir whose location relative to any
450+
// one package shifted across xlings store layouts (0.4.62 -> 0.4.67,
451+
// mcpp 0.0.99), which is why a fixed `<data>/xpkgs/<pkg>/<ver> ->
452+
// <data>/runtimedir` hop broke. Anchor instead on the authoritative
453+
// per-dep dir contract (mcpp#241: MCPP_DEP_<NAME>_DIR, emitted under
454+
// both the canonical name and the namespace-stripped short name) and
455+
// walk up probing runtimedir/ at every level; fall back to this
456+
// package's own store location + a bounded search so older mcpp
457+
// (pre-#241) and future layout shifts still resolve.
452458
if (std::getenv("MCPP_FEATURE_UNIFONT")) {
453459
const char* fname = "WenQuanYiMicroHei.ttf.gz";
454460
fs::path font;
455-
// <data>/xpkgs/<pkg>/<ver> -> <data>/runtimedir/<fname>
456-
fs::path rt = man.parent_path().parent_path().parent_path() / "runtimedir" / fname;
457-
if (fs::exists(rt)) font = rt;
461+
std::error_code ec;
462+
auto probe = [&](const fs::path& base) -> fs::path {
463+
if (base.empty()) return {};
464+
for (const fs::path& c : { base / fname,
465+
base / "runtimedir" / fname,
466+
base / "data" / "runtimedir" / fname })
467+
if (fs::exists(c)) return c;
468+
return {};
469+
};
470+
std::vector<fs::path> anchors;
471+
if (const char* d = std::getenv("MCPP_DEP_COMPAT_OPENCV_UNIFONT_DIR")) anchors.emplace_back(d);
472+
if (const char* d = std::getenv("MCPP_DEP_OPENCV_UNIFONT_DIR")) anchors.emplace_back(d);
473+
anchors.push_back(man);
474+
if (const char* d = std::getenv("MCPP_OUT_DIR")) anchors.emplace_back(d);
475+
// walk up from each anchor, probing runtimedir/ at every level
476+
for (const auto& a : anchors) {
477+
for (fs::path p = a; !p.empty(); p = p.parent_path()) {
478+
if (auto hit = probe(p); !hit.empty()) { font = hit; break; }
479+
if (p == p.root_path()) break;
480+
}
481+
if (!font.empty()) break;
482+
}
483+
// fallback: sweep any opencv-unifont verdir near this package's store dir
458484
if (font.empty()) {
459-
std::error_code ec;
460485
for (auto& e : fs::directory_iterator(man.parent_path().parent_path(), ec)) {
461486
if (e.path().filename().string().find("opencv-unifont") == std::string::npos) continue;
462487
for (auto& v : fs::recursive_directory_iterator(e.path(), ec))
463488
if (v.path().filename() == fname) { font = v.path(); break; }
464489
if (!font.empty()) break;
465490
}
466491
}
492+
// last resort: bounded recursive search from the nearest store root
493+
if (font.empty()) {
494+
for (const auto& a : anchors) {
495+
fs::path root = a;
496+
for (int up = 0; up < 8 && root.has_parent_path(); ++up) {
497+
if (fs::exists(root / "runtimedir") || fs::exists(root / "xpkgs")
498+
|| root.filename() == "data") break;
499+
root = root.parent_path();
500+
}
501+
long budget = 400000;
502+
for (auto it = fs::recursive_directory_iterator(root,
503+
fs::directory_options::skip_permission_denied, ec);
504+
it != fs::recursive_directory_iterator() && budget-- > 0; it.increment(ec)) {
505+
if (ec) { ec.clear(); continue; }
506+
if (it->path().filename() == fname) { font = it->path(); break; }
507+
}
508+
if (!font.empty()) break;
509+
}
510+
}
467511
if (font.empty()) {
468-
std::fprintf(stderr, "compat.opencv build.mcpp: unifont feature on but %s not found near %s\n",
469-
fname, man.string().c_str());
512+
const char* e1 = std::getenv("MCPP_DEP_COMPAT_OPENCV_UNIFONT_DIR");
513+
const char* e2 = std::getenv("MCPP_DEP_OPENCV_UNIFONT_DIR");
514+
const char* e3 = std::getenv("MCPP_OUT_DIR");
515+
std::fprintf(stderr, "compat.opencv build.mcpp: unifont feature on but %s not found.\n"
516+
" MCPP_MANIFEST_DIR=%s\n MCPP_DEP_COMPAT_OPENCV_UNIFONT_DIR=%s\n"
517+
" MCPP_DEP_OPENCV_UNIFONT_DIR=%s\n MCPP_OUT_DIR=%s\n",
518+
fname, man.string().c_str(),
519+
e1 ? e1 : "(unset)", e2 ? e2 : "(unset)", e3 ? e3 : "(unset)");
470520
return 1;
471521
}
472522
blob2hdr(font, out / "builtin_font_uni.h", "OcvBuiltinFontUni");

tools/compat-opencv/build_mcpp_template.cpp

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
#include <cstring>
2727
#include <filesystem>
2828
#include <fstream>
29+
#include <initializer_list>
2930
#include <sstream>
3031
#include <string>
3132
#include <vector>
33+
#include <vector>
3234

3335
namespace fs = std::filesystem;
3436

@@ -230,29 +232,78 @@ int main() {
230232
blob2hdr(wrap / "modules/imgproc/fonts/Rubik-Italic.ttf.gz", out / "builtin_font_italic.h", "OcvBuiltinFontItalic");
231233

232234
// 1b. unifont feature: hex-embed the CJK font pulled in by the
233-
// compat.opencv-unifont dependency. Its payload is a raw .gz the
234-
// installer parks byte-preserved in the store's shared
235-
// data/runtimedir/ (no MCPP_DEP_<NAME>_DIR contract var yet), so
236-
// resolve it relative to this package's store location, with a
237-
// verdir sweep as fallback.
235+
// compat.opencv-unifont dependency. Its raw .gz payload is parked by
236+
// the installer in a shared runtimedir whose location relative to any
237+
// one package shifted across xlings store layouts (0.4.62 -> 0.4.67,
238+
// mcpp 0.0.99), which is why a fixed `<data>/xpkgs/<pkg>/<ver> ->
239+
// <data>/runtimedir` hop broke. Anchor instead on the authoritative
240+
// per-dep dir contract (mcpp#241: MCPP_DEP_<NAME>_DIR, emitted under
241+
// both the canonical name and the namespace-stripped short name) and
242+
// walk up probing runtimedir/ at every level; fall back to this
243+
// package's own store location + a bounded search so older mcpp
244+
// (pre-#241) and future layout shifts still resolve.
238245
if (std::getenv("MCPP_FEATURE_UNIFONT")) {
239246
const char* fname = "WenQuanYiMicroHei.ttf.gz";
240247
fs::path font;
241-
// <data>/xpkgs/<pkg>/<ver> -> <data>/runtimedir/<fname>
242-
fs::path rt = man.parent_path().parent_path().parent_path() / "runtimedir" / fname;
243-
if (fs::exists(rt)) font = rt;
248+
std::error_code ec;
249+
auto probe = [&](const fs::path& base) -> fs::path {
250+
if (base.empty()) return {};
251+
for (const fs::path& c : { base / fname,
252+
base / "runtimedir" / fname,
253+
base / "data" / "runtimedir" / fname })
254+
if (fs::exists(c)) return c;
255+
return {};
256+
};
257+
std::vector<fs::path> anchors;
258+
if (const char* d = std::getenv("MCPP_DEP_COMPAT_OPENCV_UNIFONT_DIR")) anchors.emplace_back(d);
259+
if (const char* d = std::getenv("MCPP_DEP_OPENCV_UNIFONT_DIR")) anchors.emplace_back(d);
260+
anchors.push_back(man);
261+
if (const char* d = std::getenv("MCPP_OUT_DIR")) anchors.emplace_back(d);
262+
// walk up from each anchor, probing runtimedir/ at every level
263+
for (const auto& a : anchors) {
264+
for (fs::path p = a; !p.empty(); p = p.parent_path()) {
265+
if (auto hit = probe(p); !hit.empty()) { font = hit; break; }
266+
if (p == p.root_path()) break;
267+
}
268+
if (!font.empty()) break;
269+
}
270+
// fallback: sweep any opencv-unifont verdir near this package's store dir
244271
if (font.empty()) {
245-
std::error_code ec;
246272
for (auto& e : fs::directory_iterator(man.parent_path().parent_path(), ec)) {
247273
if (e.path().filename().string().find("opencv-unifont") == std::string::npos) continue;
248274
for (auto& v : fs::recursive_directory_iterator(e.path(), ec))
249275
if (v.path().filename() == fname) { font = v.path(); break; }
250276
if (!font.empty()) break;
251277
}
252278
}
279+
// last resort: bounded recursive search from the nearest store root
280+
if (font.empty()) {
281+
for (const auto& a : anchors) {
282+
fs::path root = a;
283+
for (int up = 0; up < 8 && root.has_parent_path(); ++up) {
284+
if (fs::exists(root / "runtimedir") || fs::exists(root / "xpkgs")
285+
|| root.filename() == "data") break;
286+
root = root.parent_path();
287+
}
288+
long budget = 400000;
289+
for (auto it = fs::recursive_directory_iterator(root,
290+
fs::directory_options::skip_permission_denied, ec);
291+
it != fs::recursive_directory_iterator() && budget-- > 0; it.increment(ec)) {
292+
if (ec) { ec.clear(); continue; }
293+
if (it->path().filename() == fname) { font = it->path(); break; }
294+
}
295+
if (!font.empty()) break;
296+
}
297+
}
253298
if (font.empty()) {
254-
std::fprintf(stderr, "compat.opencv build.mcpp: unifont feature on but %s not found near %s\n",
255-
fname, man.string().c_str());
299+
const char* e1 = std::getenv("MCPP_DEP_COMPAT_OPENCV_UNIFONT_DIR");
300+
const char* e2 = std::getenv("MCPP_DEP_OPENCV_UNIFONT_DIR");
301+
const char* e3 = std::getenv("MCPP_OUT_DIR");
302+
std::fprintf(stderr, "compat.opencv build.mcpp: unifont feature on but %s not found.\n"
303+
" MCPP_MANIFEST_DIR=%s\n MCPP_DEP_COMPAT_OPENCV_UNIFONT_DIR=%s\n"
304+
" MCPP_DEP_OPENCV_UNIFONT_DIR=%s\n MCPP_OUT_DIR=%s\n",
305+
fname, man.string().c_str(),
306+
e1 ? e1 : "(unset)", e2 ? e2 : "(unset)", e3 ? e3 : "(unset)");
256307
return 1;
257308
}
258309
blob2hdr(font, out / "builtin_font_uni.h", "OcvBuiltinFontUni");

0 commit comments

Comments
 (0)