# Changelog All notable changes to cargoxx will be documented in this file. ## [Unreleased] ### Added - M0 repo skeleton: hand-written `CMakeLists.txt`, bootstrap `flake.nix`, empty C++23 module units for every component listed in `TECH_SPEC.md` §1 (`util`, `exec`, `manifest`, `lockfile`, `layout`, `linkdb`, `resolver`, `codegen`, `cli`), root module `cargoxx`, and a stub `main.cpp` that builds an empty `cargoxx` binary. - `.clang-format` (LLVM, 100-column) and `.gitignore`. - `SPEC.md`, `TECH_SPEC.md`. - M1 foundation in `cargoxx.util`: `ErrorCode` (numbers per `TECH_SPEC.md` §4), `Error`, `Result = std::expected`, and `format(Error)` rendering `error[Ennnn]: ...` with optional `--> path:line:col` and `hint:` lines. `format` lives in `src/util/error.cpp` as a module implementation unit. - `Catch2 v3` wired through `flake.nix` (libc++-built override) and registered in CMake; `tests/util_error.cpp` covers six format cases via `catch_discover_tests`. - `cargoxx.manifest` public types (`Package`, `Dependency`, `BuildSettings`, `Edition`, `Manifest`) and `parse(path)` returning `Result`, backed by toml++ vendored as `third_party/toml.hpp`. Unknown keys in `[package]` / `[build]` and unknown top-level keys are rejected; reserved fields (`description`, `repository`, `[dev-dependencies]`, `[features]`, `[workspace]`) are accepted. `tests/manifest_parse.cpp` covers 17 cases. - `manifest::write(m, path)` serializes a `Manifest` as TOML using toml++. Dependencies are emitted alphabetically (matches Cargo). Round-trip property is exercised by `tests/manifest_write.cpp` (9 cases). Defaulted `operator==` on the manifest structs supports comparison. - `cargoxx.layout` public types (`Target`, `TargetKind`, `DiscoveredLayout`) and `discover(project_root, package_name)`. Walks `src/` recursively for the library (excluding the `src/bin/` subtree), enumerates `src/main.cpp`, `src/bin/*.cpp`, `tests/*.cpp`, `examples/*.cpp` flat, sorts results for deterministic output, and returns `LayoutNoTarget` when neither a library nor any binary is present. `tests/layout_discovery.cpp` covers 12 cases. - `cargoxx new ` and `cargoxx new --lib ` scaffold a project directory with `Cargoxx.toml`, `src/main.cpp` or `src/lib.cppm`, and a minimal `.gitignore`. Hyphens in the package name are mapped to underscores when generating the module/namespace identifier. Codegen of `flake.nix` / `CMakeLists.txt` is intentionally deferred to M3. CLI11 v2.6.2 vendored at `third_party/CLI11.hpp`; entry point is now `cargoxx::cli::run(argc, argv)`. `tests/cmd_new.cpp` covers 9 cases. - `util::satisfies(version, range)` — minimal semver range matcher supporting `*`, `==/>=/<=/>/<` operators, and comma-separated AND clauses. Versions are zero-padded to three components. `tests/semver_satisfies.cpp` covers 7 cases. - `cargoxx.linkdb`: `Recipe`, `Database::open()`, `Database::resolve(...)` for curated lookups. The curated database ships at `data/linkdb.json` with all 25 packages from `SPEC.md` §11. Component-substitution helpers expand `{{components}}` (space-joined) in `find_package` and fan out `{{component}}` per-target. Path is injected via the `CARGOXX_LINKDB_DEFAULT_PATH` compile definition. nlohmann/json 3.12.0 vendored at `third_party/json.hpp`. SQLite overlay and `add_manual` are deferred to the M2 follow-up commit. `tests/linkdb_lookup.cpp` covers 13 cases including a smoke test that resolves all 25 curated packages. - `cargoxx.lockfile`: `Lockfile`, `LockfilePackage` types and `parse(path)` / `write(lock, path)` matching the format in `SPEC.md` §5. Also `Lockfile::nixpkgs_rev()` returns the shared revision (codegen will consume this in M3). `tests/lockfile_round_trip.cpp` covers 9 cases. - `cargoxx.codegen`: `GenerateInputs` plus the pure function `flake_nix(in) -> std::string`. Substitutes the package name, the resolved nixpkgs revision (defaulting to `nixos-unstable` when the lockfile pins none), and a deduplicated list of dep `nixpkgs_attr` entries into `buildInputs`. Output is byte-deterministic. `tests/codegen_flake.cpp` covers 7 cases. Note: SPEC §7's template did not show `buildInputs`; we add one between `nativeBuildInputs` and the `env.NIX_CFLAGS_COMPILE` block as the natural slot for the deps that TECH_SPEC §10 says we splice in. - `codegen::cmake_lists(in) -> std::string` per `SPEC.md` §8 and `TECH_SPEC.md` §9: `find_package` per dep, optional library target with module units + private impl sources, primary binary `_bin` linked against the library, additional binaries from `src/bin/`, tests with `enable_testing()` + `add_test`, examples, and `[build]` honoring `warnings_as_errors` and `sanitizers`. Source paths emitted relative to `build/` (i.e. prefixed with `../`). Output is deterministic. `tests/codegen_cmake.cpp` covers 11 cases. - `cargoxx run [--release] [--bin ] [-- ...]`, `cargoxx test [--release]`, and `cargoxx clean`. `run` builds first, picks the binary (errors with the available list when the project has multiple bins and `--bin` is omitted), and execs it with the process exit code propagated. `test` invokes `nix develop -c ctest --test-dir build/ --output-on-failure`. `clean` removes `build/` while leaving `Cargoxx.lock` and `flake.lock` intact. End-to-end verified against a freshly-scaffolded project. `tests/cmd_run.cpp` and `tests/cmd_clean.cpp` cover 6 cases. - `cargoxx build` (without `--no-build`) now drives the full build: `nix develop -c cmake -B build/ -S build -G Ninja -DCMAKE_BUILD_TYPE=` then `nix develop -c cmake --build` with optional `--target`, both with `inherit_stdio = true` so the user sees compilation output live. Non-zero cmake exit returns `BuildCmakeFailed`. End-to-end verified: `cargoxx new myapp && cargoxx build` produces a working `build/debug/myapp` that prints `Hello from myapp!`. - Generated `build/CMakeLists.txt` now opts into the experimental `import std;` UUID + `CMAKE_CXX_MODULE_STD ON`, and sets `CMAKE_CXX_EXTENSIONS ON` (deviation from SPEC §8 — required for libc++'s std module to load without `module-file-config-mismatch` on clang 21). Without these the templates from `cargoxx new` fail to compile. - `cargoxx.exec`: `ExecResult`, `ExecOptions`, and `run(program, args, opts)` — argv-only subprocess wrapper around reproc 14.2.4. Captures stdout/stderr (or inherits stdio when `opts.inherit_stdio` is set), supports `cwd`, `env_overrides`, and a `timeout` (enforced via `reproc_options.deadline` so drains return `REPROC_ETIMEDOUT` instead of blocking on long-lived streams). On destruction reproc terminates and then kills any still-running child. Returns `ExecToolNotFound` for `ENOENT` and `ExecCommandFailed` for other failures including timeouts. `tests/exec_run.cpp` covers 9 cases. - `cargoxx build --no-build` end-to-end. Reads `Cargoxx.toml`, discovers the layout, opens the curated linkdb, resolves a `Recipe` per manifest dep, synthesizes a fresh `Cargoxx.lock`, and writes `flake.nix`, `build/CMakeLists.txt`, and `Cargoxx.lock`. With no resolver yet (M5), `nixpkgs_rev` is left null and the generated flake falls back to the `nixos-unstable` branch. Without `--no-build`, the command still generates files but returns a `NotImplemented` error pointing at M4. `tests/cmd_build.cpp` covers 8 cases. - SQLite overlay: `Database::open(overlay_path)` now opens (and creates, if missing) a per-user `linkdb.sqlite` cache, applying the schema from `SPEC.md` §9 idempotently. Default path is `$XDG_CACHE_HOME/cargoxx/linkdb.sqlite` (falling back to `$HOME/.cache/cargoxx/...`); tests pass an explicit temp path so they never touch the user cache. `Database::add_manual(pkg, range, recipe)` inserts a row with `source = 'manual'` and `verified_at = now()`; `resolve()` consults the overlay first and falls back to curated when no overlay row matches the requested version range. Manual entries never expire; `nix-probe` (v0.2) entries respect a 30-day freshness window. `tests/linkdb_overlay.cpp` covers 7 cases (insert/persist, override-curated, version-range gating, components rejection, move semantics).