[M6] populate Cargoxx.toml; add 'cargoxx linkdb add' CLI; codegen fixes for self-host

This commit is contained in:
2026-05-14 00:17:56 +00:00
parent a757149f99
commit 4f9b6f1827
8 changed files with 104 additions and 14 deletions

View File

@@ -64,6 +64,7 @@ target_sources(cargoxx
src/cli/cmd_clean.cpp
src/cli/cmd_add.cpp
src/cli/cmd_remove.cpp
src/cli/cmd_linkdb_add.cpp
src/cli/run.cpp
PUBLIC
FILE_SET CXX_MODULES FILES

View File

@@ -9,7 +9,8 @@ sqlite3 = "*"
reproc = "*"
[dev-dependencies]
catch2 = "*"
catch2_3 = "*"
[build]
warnings_as_errors = false
include_dirs = ["third_party"]

View File

@@ -53,6 +53,17 @@ auto cmd_add(const std::filesystem::path& project_root, const std::string& name,
auto cmd_remove(const std::filesystem::path& project_root, const std::string& name)
-> util::Result<void>;
// Inserts a manual recipe into the SQLite linkdb overlay. Equivalent to
// the auto-discover path's confirmed row, but user-provided. Use it
// when nixpkgs ships a CMake FindModule (no <X>Config.cmake) or when the
// scanner can't pick the right target automatically.
auto cmd_linkdb_add(const std::string& package, const std::string& version_range,
const std::string& find_package_text,
std::vector<std::string> targets,
const std::string& nixpkgs_attr,
std::optional<std::filesystem::path> overlay_path = std::nullopt)
-> util::Result<void>;
auto run(int argc, char** argv) -> int;
} // namespace cargoxx::cli

View File

@@ -0,0 +1,31 @@
module cargoxx.cli;
import std;
import cargoxx.linkdb;
import cargoxx.util;
namespace cargoxx::cli {
auto cmd_linkdb_add(const std::string& package, const std::string& version_range,
const std::string& find_package_text,
std::vector<std::string> targets,
const std::string& nixpkgs_attr,
std::optional<std::filesystem::path> overlay_path)
-> util::Result<void> {
auto db = linkdb::Database::open(std::move(overlay_path));
if (!db) {
return std::unexpected(db.error());
}
if (auto r = db->evict_auto_recipes(package); !r) {
return std::unexpected(r.error());
}
linkdb::Recipe r{
.nixpkgs_attr = nixpkgs_attr,
.find_package = find_package_text,
.targets = std::move(targets),
.source = "manual",
};
return db->add_manual(package, version_range, r);
}
} // namespace cargoxx::cli

View File

@@ -58,6 +58,28 @@ auto run(int argc, char** argv) -> int {
std::string remove_name;
remove_cmd->add_option("name", remove_name, "Package name to remove")->required();
auto* linkdb_cmd =
app.add_subcommand("linkdb", "Manage the link database");
linkdb_cmd->require_subcommand(1);
auto* linkdb_add_cmd =
linkdb_cmd->add_subcommand("add", "Insert a manual recipe");
std::string ldb_package;
std::string ldb_version = "*";
std::string ldb_find_package;
std::string ldb_targets;
std::string ldb_nixpkgs_attr;
linkdb_add_cmd->add_option("package", ldb_package, "Package name")->required();
linkdb_add_cmd->add_option("--version", ldb_version, "Version range (default: *)");
linkdb_add_cmd->add_option("--find-package", ldb_find_package,
"Body of the find_package(...) call (e.g. \"fmt CONFIG REQUIRED\")")
->required();
linkdb_add_cmd->add_option("--targets", ldb_targets,
"Comma-separated CMake targets (e.g. fmt::fmt)")
->required();
linkdb_add_cmd->add_option("--nixpkgs-attr", ldb_nixpkgs_attr,
"nixpkgs attribute name (e.g. fmt_10)")
->required();
try {
app.parse(argc, argv);
} catch (const CLI::ParseError& e) {
@@ -175,6 +197,31 @@ auto run(int argc, char** argv) -> int {
return 0;
}
if (*linkdb_add_cmd) {
std::vector<std::string> targets;
std::size_t pos = 0;
while (pos <= ldb_targets.size()) {
auto comma = ldb_targets.find(',', pos);
auto piece = ldb_targets.substr(
pos, comma == std::string::npos ? ldb_targets.size() - pos : comma - pos);
if (!piece.empty()) {
targets.push_back(std::move(piece));
}
if (comma == std::string::npos) {
break;
}
pos = comma + 1;
}
auto r = cmd_linkdb_add(ldb_package, ldb_version, ldb_find_package,
std::move(targets), ldb_nixpkgs_attr);
if (!r) {
std::cerr << util::format(r.error());
return 1;
}
std::cout << std::format(" Added manual recipe for {}\n", ldb_package);
return 0;
}
return 0;
}

View File

@@ -111,7 +111,7 @@ auto emit_library(const layout::Target& lib, const std::string& package_name,
out += std::format("add_library({} STATIC)\n", package_name);
out += std::format("target_sources({}\n", package_name);
out += " PUBLIC\n";
out += " FILE_SET CXX_MODULES FILES\n";
out += " FILE_SET CXX_MODULES BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/.. FILES\n";
for (const auto& m : lib.module_units) {
out += std::format(" {}\n", rel_to_build(m, project_root));
}

View File

@@ -59,25 +59,24 @@ auto find_lockfile_ref(const lockfile::Lockfile& lock, const std::string& name,
auto build_bindings(const GenerateInputs& in) -> std::vector<DepBinding> {
std::vector<DepBinding> out;
out.reserve(in.manifest.dependencies.size());
for (std::size_t i = 0; i < in.manifest.dependencies.size(); ++i) {
const auto& dep = in.manifest.dependencies[i];
const auto& rec = in.recipes[i];
out.reserve(in.manifest.dependencies.size() + in.manifest.dev_dependencies.size());
auto push = [&](const manifest::Dependency& dep, const linkdb::Recipe& rec) {
auto ref = find_lockfile_ref(in.lock, dep.name, dep.version_spec);
// For pinned deps the lockfile's nixpkgs_attr is authoritative
// (it came from devbox's attr_paths for this specific rev). The
// curated recipe's attr only applies to nixos-unstable, so it's
// wrong when the dep pulls from a different rev.
std::string attr = (ref.attr && !ref.attr->empty()) ? *ref.attr
: rec.nixpkgs_attr;
DepBinding b{
out.push_back(DepBinding{
.name = dep.name,
.version = dep.version_spec,
.nixpkgs_attr = std::move(attr),
.sanitized = sanitize_input_attr(dep.name, dep.version_spec),
.rev = std::move(ref.rev),
};
out.push_back(std::move(b));
});
};
for (std::size_t i = 0; i < in.manifest.dependencies.size(); ++i) {
push(in.manifest.dependencies[i], in.recipes[i]);
}
for (std::size_t i = 0; i < in.manifest.dev_dependencies.size(); ++i) {
push(in.manifest.dev_dependencies[i], in.dev_recipes[i]);
}
return out;
}

View File

@@ -95,7 +95,7 @@ TEST_CASE("cmake_lists for a library-only project", "[codegen][cmake]") {
auto out = cmake_lists(in);
REQUIRE(out.find("add_library(widget STATIC)") != std::string::npos);
REQUIRE(out.find("FILE_SET CXX_MODULES FILES") != std::string::npos);
REQUIRE(out.find("FILE_SET CXX_MODULES") != std::string::npos);
REQUIRE(out.find("../src/lib.cppm") != std::string::npos);
REQUIRE(out.find("add_executable") == std::string::npos);
}