Files
cargoxx/CHANGELOG.md

177 lines
11 KiB
Markdown

# 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<T> = std::expected<T, Error>`, 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<Manifest>`,
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 <name>` and `cargoxx new --lib <name>` 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
`<pkg>_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.resolver::nixpkgs_probe(attr)` — runs
`nix eval nixpkgs#<attr> --json --apply 'p: { version, path }'` via
`exec::run` and returns a `NixpkgsInfo { attr, version, out_path }`.
Distinguishes missing attributes (`ResolutionUnknownPackage`) from
evaluator/network errors (`ResolutionNetworkError`). The `path` field
name avoids nix's `outPath`-driven derivation coercion in `--json`
mode (which would otherwise serialize the result as a bare path
string instead of a JSON object). Pure parser
`parse_nix_eval_json(attr, text)` exposed for unit tests; live tests
in `tests/nixpkgs_probe_live.cpp` are gated behind
`CARGOXX_NETWORK_TESTS=1` (verified locally against `hello`).
- `cargoxx add <pkg>[@<version>] [--components a,b]` edits `Cargoxx.toml`,
validates the new dep against the curated linkdb (so unknown packages
and missing components fail before any disk write), and rejects
already-declared deps. Version is now optional; an omitted version
is stored as `"*"` and resolves against the linkdb's first matching
recipe. Generated `flake.nix` continues to track the `nixos-unstable`
branch when the lockfile carries no rev.
- `util::satisfies` treats `version == "*"` as a match against any
range, mirroring the existing `range == "*"` shortcut.
- `scripts/verify-curated-db.sh` plus per-package using-snippets at
`scripts/curated-snippets/<pkg>.cpp`. For each curated package the
script scaffolds a fresh project, `cargoxx add`s the dep, drops in a
snippet that exercises the library's API, and runs `cargoxx build`,
asserting the binary is produced. 21/25 packages pass against
`nixos-unstable`; the remaining 4 are documented as skipped:
`catch2`/`gtest` (their default linkdb targets ship their own
`main()` which collides with the snippet), `grpc` (needs `protobuf`
declared as a transitive dep — cross-package transitives are out of
v0.1 scope), `abseil-cpp` (nixpkgs builds it against libstdc++ while
our flake uses libc++ → ABI mismatch on the linker step).
- `data/linkdb.json`: `boost` recipe is now header-only —
`find_package(Boost REQUIRED)` + `Boost::headers`. Boost 1.89's
`BoostConfig.cmake` searches for separately-installed
`boost_<comp>Config.cmake` files that nixpkgs doesn't ship, so
the previous `COMPONENTS` form failed at configure time.
Linkdb-component tests now use `abseil-cpp` for component coverage.
- `cargoxx remove <pkg>` drops a declared dep from `Cargoxx.toml`,
errors when the dep is not declared. Other deps are preserved.
- End-to-end verified on a freshly-scaffolded project. `tests/cmd_add.cpp`
and `tests/cmd_remove.cpp` cover 9 cases. Known cosmetic issue:
toml++ writes top-level sections alphabetically, so `[package]` may
end up after `[dependencies]` post-mutation; logged for M6 polish.
- `cargoxx run [--release] [--bin <name>] [-- <args>...]`,
`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/<profile> --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/<profile> -S build -G Ninja
-DCMAKE_BUILD_TYPE=<Profile>` 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).