[M5+] nix-cmake-scan walks the dev output for multi-output packages

This commit is contained in:
2026-05-10 13:29:45 +00:00
parent 1604b1d5a8
commit 54da546ebc
5 changed files with 80 additions and 8 deletions

View File

@@ -89,9 +89,25 @@ auto discover(const std::string& name, const std::string& version_spec,
if (auto v = vcpkg_probe(name); v) {
candidates.push_back({"vcpkg", recipe_from_vcpkg(*v, name, "vcpkg")});
}
if (auto n = nix_cmake_scan(info->out_path, name); n) {
// Multi-output nix packages keep CMake configs in the `dev` output;
// scan it first when available, fall back to the default `out`.
auto try_scan = [&](const fs::path& root)
-> std::optional<NixCmakeCandidate> {
if (root.empty()) {
return std::nullopt;
}
if (auto r = nix_cmake_scan(root, name); r) {
return std::move(*r);
}
return std::nullopt;
};
auto scan_hit = try_scan(info->dev_path);
if (!scan_hit) {
scan_hit = try_scan(info->out_path);
}
if (scan_hit) {
candidates.push_back(
{"nix-probe", recipe_from_nix_scan(*n, name, "nix-probe")});
{"nix-probe", recipe_from_nix_scan(*scan_hit, name, "nix-probe")});
}
if (candidates.empty()) {

View File

@@ -15,8 +15,14 @@ namespace {
// `outPath` is a magic attribute name that triggers nix's derivation
// coercion in --json mode (the attrset gets serialized as a bare path
// string). Renaming the field to `path` keeps it a proper JSON object.
//
// `dev_path` is captured for multi-output packages (boost, openssl,
// llvm, …) where CMake configs live under the `dev` output rather
// than `out`. `p ? dev` is false for single-output packages, leaving
// the field as the empty string.
constexpr std::string_view APPLY_FN =
"p: { version = p.version or \"\"; path = p.outPath; }";
"p: { version = p.version or \"\"; path = p.outPath; "
"dev_path = if p ? dev then p.dev.outPath else \"\"; }";
auto make_error(util::ErrorCode code, std::string msg) -> util::Error {
return util::Error{code, std::move(msg), "", std::nullopt, std::nullopt};
@@ -48,7 +54,9 @@ auto parse_nix_eval_json(std::string_view attr, std::string_view json)
"nix eval JSON is not an object"));
}
NixpkgsInfo info{.attr = std::string{attr}, .version = {}, .out_path = {}};
NixpkgsInfo info{
.attr = std::string{attr}, .version = {}, .out_path = {}, .dev_path = {},
};
if (j.contains("path") && j["path"].is_string()) {
info.out_path = j["path"].get<std::string>();
@@ -62,6 +70,10 @@ auto parse_nix_eval_json(std::string_view attr, std::string_view json)
info.version = j["version"].get<std::string>();
}
if (j.contains("dev_path") && j["dev_path"].is_string()) {
info.dev_path = j["dev_path"].get<std::string>();
}
return info;
}

View File

@@ -10,11 +10,17 @@ export namespace cargoxx::resolver {
// What `nix eval nixpkgs#<pkg>` reports for a package: a confirmation that
// the attribute exists, a best-effort version string, and the realized
// nix-store path so later probes can scan its installed CMake configs.
// nix-store path(s) so later probes can scan its installed CMake configs.
//
// Multi-output packages (boost, openssl, llvm, ...) expose CMake configs
// in their `dev` output, not in the default `out`. When the package has
// a separate dev output its store path is captured here so callers can
// scan it preferentially.
struct NixpkgsInfo {
std::string attr; // the queried name, e.g. "simdjson"
std::string version; // empty when the derivation has no version
std::string out_path; // absolute /nix/store/... path
std::string attr; // the queried name, e.g. "simdjson"
std::string version; // empty when the derivation has no version
std::string out_path; // default output's absolute /nix/store/... path
std::string dev_path; // dev output's path; empty when no dev output
};
// Pure parser exposed for unit testing. Accepts the raw JSON returned by