Skip to content

Commit 0d537f6

Browse files
committed
refactor: capability/provider-driven doctor (no platform #ifdef)
Aggregate dependency providers' [runtime] dlopen_libs/capabilities into the BuildPlan (with capability->provider mapping). doctor now reports each required host capability + its provider and verifies each provider-declared dlopen soname against the resolved runtime library_dirs — fully data-driven. Removes the previous #ifdef __APPLE__/_WIN32 + hardcoded /usr/lib paths: platform knowledge belongs in provider packages, not in mcpp core. why also surfaces capability->provider.
1 parent 074bcdd commit 0d537f6

2 files changed

Lines changed: 55 additions & 32 deletions

File tree

src/build/plan.cppm

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ struct BuildPlan {
5656
std::vector<CompileUnit> compileUnits; // topologically sorted
5757
std::vector<LinkUnit> linkUnits;
5858
std::vector<std::filesystem::path> runtimeLibraryDirs;
59+
// Aggregated host-runtime requirements from dependency packages'
60+
// [runtime] metadata. Capability/provider-driven — no platform special-casing
61+
// in mcpp: providers (e.g. compat.glx-runtime) declare these per platform.
62+
std::vector<std::string> runtimeDlopenLibs; // union of deps' dlopen sonames
63+
std::vector<std::string> runtimeCapabilities; // union of host capabilities
64+
std::vector<std::pair<std::string, std::string>> runtimeProviders; // (capability, provider pkg)
5965
};
6066

6167
// Build a BuildPlan from already-validated inputs.
@@ -222,6 +228,15 @@ BuildPlan make_plan(const mcpp::manifest::Manifest& manifest,
222228
append_unique_path(plan.runtimeLibraryDirs,
223229
dir.is_absolute() ? dir : package.root / dir);
224230
}
231+
for (auto const& lib : package.manifest.runtimeConfig.dlopenLibs) {
232+
if (std::ranges::find(plan.runtimeDlopenLibs, lib) == plan.runtimeDlopenLibs.end())
233+
plan.runtimeDlopenLibs.push_back(lib);
234+
}
235+
for (auto const& cap : package.manifest.runtimeConfig.capabilities) {
236+
if (std::ranges::find(plan.runtimeCapabilities, cap) == plan.runtimeCapabilities.end())
237+
plan.runtimeCapabilities.push_back(cap);
238+
plan.runtimeProviders.emplace_back(cap, package.manifest.package.name);
239+
}
225240
}
226241
// The same private runtime directories embedded as executable RUNPATH are
227242
// also needed in the process environment for libraries reached only via

src/cli.cppm

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4279,41 +4279,41 @@ int cmd_doctor(const mcpplibs::cmdline::ParsedArgs& /*parsed*/) {
42794279

42804280
mcpp::ui::status("Checking", "runtime capabilities");
42814281
{
4282-
#if defined(__APPLE__) || defined(_WIN32)
4283-
ok("host GL/windowing provided by platform framework");
4284-
#else
4285-
if (const char* d = std::getenv("DISPLAY"); d && *d)
4286-
ok(std::format("x11.display: ok ($DISPLAY={})", d));
4287-
else if (const char* w = std::getenv("WAYLAND_DISPLAY"); w && *w)
4288-
ok(std::format("wayland.display: ok ($WAYLAND_DISPLAY={})", w));
4289-
else
4290-
warn("display: none — windowed apps need $DISPLAY or $WAYLAND_DISPLAY");
4291-
4292-
const char* gldirs[] = {"/usr/lib/x86_64-linux-gnu", "/lib/x86_64-linux-gnu",
4293-
"/usr/lib64", "/usr/lib"};
4294-
auto find_lib = [&](std::string_view prefix) -> std::string {
4295-
for (auto* dir : gldirs) {
4296-
std::error_code ec;
4297-
if (!std::filesystem::exists(dir, ec)) continue;
4298-
for (auto& e : std::filesystem::directory_iterator(dir, ec)) {
4299-
auto fn = e.path().filename().string();
4300-
if (fn.rfind(prefix, 0) == 0) return e.path().string();
4282+
// Capability/provider-driven — no platform special-casing in mcpp.
4283+
// Required capabilities and the sonames to probe come entirely from the
4284+
// dependency graph's provider packages (e.g. compat.glx-runtime); the
4285+
// search dirs are the resolved runtime library_dirs. The same code path
4286+
// works on every platform — providers carry the platform knowledge.
4287+
auto pctx = prepare_build(/*print_fingerprint=*/false);
4288+
if (!pctx) {
4289+
ok("(run inside a package to check its runtime capabilities)");
4290+
} else if (pctx->plan.runtimeCapabilities.empty()) {
4291+
ok("no host runtime capabilities required");
4292+
} else {
4293+
auto& plan = pctx->plan;
4294+
for (auto& cap : plan.runtimeCapabilities) {
4295+
std::string provider;
4296+
for (auto& [c, p] : plan.runtimeProviders)
4297+
if (c == cap) { provider = p; break; }
4298+
ok(std::format("{}: required (provider {})",
4299+
cap, provider.empty() ? "?" : provider));
4300+
}
4301+
auto resolves = [&](std::string_view soname) {
4302+
for (auto& dir : plan.runtimeLibraryDirs) {
4303+
std::error_code ec;
4304+
if (!std::filesystem::exists(dir, ec)) continue;
4305+
for (auto& e : std::filesystem::directory_iterator(dir, ec)) {
4306+
auto fn = e.path().filename().string();
4307+
if (fn == soname || fn.rfind(soname, 0) == 0) return true;
4308+
}
43014309
}
4310+
return false;
4311+
};
4312+
for (auto& lib : plan.runtimeDlopenLibs) {
4313+
if (resolves(lib)) ok(std::format("dlopen {}: resolvable on RUNPATH", lib));
4314+
else warn(std::format("dlopen {}: not found on resolved runtime dirs", lib));
43024315
}
4303-
return {};
4304-
};
4305-
auto glx = find_lib("libGLX.so");
4306-
auto gl = find_lib("libGL.so");
4307-
auto vnd = find_lib("libGLX_nvidia.so");
4308-
if (vnd.empty()) vnd = find_lib("libGLX_mesa.so");
4309-
if (!glx.empty() && !gl.empty()) {
4310-
ok(std::format("opengl.glx.driver: ok (provider compat.glx-runtime; {}, {})",
4311-
std::filesystem::path(glx).filename().string(),
4312-
vnd.empty() ? "no GLVND vendor" : std::filesystem::path(vnd).filename().string()));
4313-
} else {
4314-
warn("opengl.glx.driver: host libGL/libGLX not found — `mcpp run` of GL apps may fail");
43154316
}
4316-
#endif
43174317
}
43184318

43194319
std::println("");
@@ -4359,6 +4359,14 @@ int cmd_why(const mcpplibs::cmdline::ParsedArgs& parsed) {
43594359
|| s.find("xim-x-llvm") != std::string::npos) note = " <- toolchain";
43604360
std::println(" - {}{}", s, note);
43614361
}
4362+
if (!plan.runtimeCapabilities.empty()) {
4363+
std::println("runtime capabilities (provider):");
4364+
for (auto& cap : plan.runtimeCapabilities) {
4365+
std::string prov;
4366+
for (auto& [c, p] : plan.runtimeProviders) if (c == cap) { prov = p; break; }
4367+
std::println(" - {} -> {}", cap, prov.empty() ? "?" : prov);
4368+
}
4369+
}
43624370
}
43634371
if (all || topic == "deps") {
43644372
std::println("dependencies (mcpp.lock):");

0 commit comments

Comments
 (0)