# C++ Project Template A CMake-based C++ project template with vendored dependencies, offline builds, and developer checks. ## Prerequisites | Tool | Minimum Version | Notes | | ------------ | --------------- | ------------------------------- | | CMake | 3.20 | Build system | | make | system | Generator used by presets | | Python | 3.8+ | Helper scripts | | C++ compiler | C++14 | GCC or Clang for default lanes | | clang-format | 17+ | Format checking | | clang-tidy | 14+ | Static analysis | | Clang | C++17 capable | Fuzz lane only | The fuzz preset requires Clang and C++17. All other presets work with any C++14 compiler. ## Quick Start After a fresh clone, all dependencies are already vendored in `3rd/archives/`. No network access is needed for the default build. ```bash # Configure and build cmake --preset debug cmake --build --preset debug # Run tests ctest --preset debug # Run the full fast check (format, build, test, clang-tidy) python3 scripts/dev_check.py --fast ``` ## Daily Workflow ### First-time setup ```bash python3 scripts/setup_hooks.py cmake --preset debug cmake --build --preset debug ``` The hook runs `python3 scripts/dev_check.py --fast` on every commit. Build at least once so `compile_commands.json` exists for clang-tidy. ### Edit and test loop ```bash # Build and run tests (pick one) cmake --build --preset debug && ctest --preset debug --output-on-failure cmake --build --preset debug --target run_tests # Run benchmarks cmake --build --preset debug --target run_benchmarks ``` `run_tests` and `run_benchmarks` are aggregate targets that drive all registered test and benchmark executables. See `docs/cmake-api.md` for helper API details. ### Fast and full checks ```bash # Format + build + test + clang-tidy python3 scripts/dev_check.py --fast # Individual verification subcommands python3 scripts/dev_check.py cmake-helper-fixtures python3 scripts/dev_check.py no-network-default ``` Run `python3 scripts/dev_check.py --help` for the full list. CI runs all subcommands independently; see the Developer Checks table below for details. ### Sanitizer builds ```bash cmake --preset asan && cmake --build --preset asan ctest --preset asan --output-on-failure ``` Sanitizer presets disable benchmarks to avoid false positives from instrumented benchmark code. ### Fuzz smoke and long fuzzing The fuzz preset requires Clang. Smoke tests run in deterministic unit-test mode: ```bash cmake --preset fuzz && cmake --build --preset fuzz ctest --preset fuzz --output-on-failure -L fuzz_smoke ``` Continuous fuzzing requires a separate build with `FUZZTEST_FUZZING_MODE=ON` and runs the executable directly: ```bash ./build/fuzz/calc_fuzz --fuzz=CalcFuzz.AddNeverCrashes --fuzz_for=60s ``` ## Build Presets | Preset | Standard | Type | Tests | Notes | | ------------- | -------- | ------- | ----- | ------------------------ | | `debug` | C++14 | Debug | yes | Default developer lane | | `release` | C++14 | Release | yes | Optimized build | | `asan` | C++14 | Debug | yes | AddressSanitizer | | `fuzz` | C++17 | Debug | fuzz smoke | FuzzTest, requires Clang | Example: ```bash cmake --preset release cmake --build --preset release ctest --preset release ``` ## Offline Build Guarantee Default build lanes (`debug`, `release`, `asan`) and the `fuzz` lane resolve all dependencies from committed archives in `3rd/archives/`. CPM loads each dependency via `URL` pointing at the local tarball with `URL_HASH SHA256=...` integrity verification. No remote fetch occurs during the build. This is enforced by the `no-network-default` and `no-network-fuzztest-lane` checks, which run CMake under invalid HTTP/HTTPS proxies with an isolated CPM source cache: ```bash python3 scripts/dev_check.py no-network-default python3 scripts/dev_check.py no-network-fuzztest-lane ``` There is no global offline mode or `CMAKE_DISABLE_FIND_PACKAGE` flag. The offline guarantee comes from CPM archive mode, not from suppressing network access at the CMake level. See `3rd/README.md` for archive policy, the full inventory table, and update instructions. ## Developer Checks `scripts/dev_check.py` runs structured verification subcommands: | Command | What it checks | | ---------------------------- | -------------------------------------------------- | | `--fast` | Format, debug configure/build/test, clang-tidy | | `no-network-default` | Configure (optionally build) under invalid proxies | | `no-network-missing-archive` | Negative check for missing archive detection | | `no-network-fuzztest-lane` | Fuzz lane configure+build under invalid proxies | | `gtest-isolation` | GTest version isolation (normal=1.16, fuzz=1.17) | | `fuzztest-optional-features` | FuzzTest optional deps stay disabled | | `install-consumer` | Install and consume as a subproject | | `cmake-helper-fixtures` | CMake helper API fixture tests | Dry-run any command to see the plan without executing: ```bash python3 scripts/dev_check.py --fast --dry-run ``` ## Dependency Management `scripts/fetch_deps.py` manages the vendored archive inventory: ```bash # List dependency status python3 scripts/fetch_deps.py --list # Verify all archives match recorded hashes (offline) python3 scripts/fetch_deps.py --check # Download a specific dependency python3 scripts/fetch_deps.py --fetch spdlog # Update pending hashes in versions.cmake python3 scripts/fetch_deps.py --update-hashes ``` Hashes and URLs are defined in `cmake/deps/versions.cmake`. The full inventory of 26 dependencies with SHA256 values is in `3rd/README.md`. ## Project-local CMake Project-local CMake binaries are committed under architecture-specific directories: - `scripts/bin/linux-x86_64/cmake/` for Linux amd64/x86_64 - `scripts/bin/linux-aarch64/cmake/` for Linux arm64/aarch64 The `scripts/bin/cmake` wrapper selects the current Linux architecture and runs the matching bundled CMake. Put `scripts/bin` at the front of `PATH` when you want the project-local CMake to take precedence over system installations: ```bash export PATH="$PWD/scripts/bin:$PATH" cmake --version ``` Presets use the `Unix Makefiles` generator and therefore use the system `make` selected by CMake. Only Linux amd64 and arm64 are supported by the bundled CMake layout. Other platforms should use system-installed CMake. ## Git Hooks Opt-in pre-commit hooks run format checks and fast developer validation: ```bash # Install hooks python3 scripts/setup_hooks.py # Check status python3 scripts/setup_hooks.py --status # Preview without installing python3 scripts/setup_hooks.py --dry-run ``` ## Troubleshooting ### Hash mismatch on configure ``` CMake Error: hash mismatch for ... ``` The archive doesn't match the SHA256 in `cmake/deps/versions.cmake`. Re-download: ```bash python3 scripts/fetch_deps.py --fetch --force ``` ### Missing archive ``` Could not find archive: 3rd/archives/.tar.gz ``` The tarball wasn't committed. Download it: ```bash python3 scripts/fetch_deps.py --fetch ``` ### Unsupported compiler for fuzz lane The fuzz preset requires C++17 and Clang. If you don't have Clang, skip the fuzz preset. All other presets work with any C++14 compiler. ### clang-format not found Format checks require clang-format 17 or newer. Install it and ensure it's on your `PATH` as `clang-format`. ## Project Layout ``` ├── cmake/ # CMake modules, dependency versions, helper API ├── scripts/ # Developer tooling (format, tidy, checks, hooks) ├── src/ # Application and library source ├── tests/ # Test sources ├── 3rd/ │ ├── archives/ # Vendored dependency tarballs (26 total) │ └── patches/ # Per-dependency patches (FuzzTest) ├── CMakePresets.json # Build preset definitions └── .githooks/ # Opt-in pre-commit hook ```