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 |
| Ninja | any | Generator (required 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.
# 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
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
# 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
# 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
cmake --preset asan && cmake --build --preset asan
ctest --preset asan --output-on-failure
cmake --preset tsan && cmake --build --preset tsan
ctest --preset tsan --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:
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:
./build/fuzz/calc_fuzz --fuzz=CalcFuzz.AddNeverCrashes --fuzz_for=60s
C++11 compatibility smoke
cmake --preset cxx11-smoke && cmake --build --preset cxx11-smoke
This verifies the project configures and compiles under C++11. No tests or benchmarks run in this lane.
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 |
tsan |
C++14 | Debug | yes | ThreadSanitizer |
fuzz |
C++17 | Debug | no | FuzzTest, requires Clang |
cxx11-smoke |
C++11 | Debug | no | Configure+build only |
Example:
cmake --preset release
cmake --build --preset release
ctest --preset release
Offline Build Guarantee
Default build lanes (debug, release, asan, tsan, cxx11-smoke) 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:
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:
python3 scripts/dev_check.py --fast --dry-run
Dependency Management
scripts/fetch_deps.py manages the vendored archive inventory:
# 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 18 dependencies with SHA256 values is in 3rd/README.md.
Git Hooks
Opt-in pre-commit hooks run format checks and fast developer validation:
# 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:
python3 scripts/fetch_deps.py --fetch --force <name>
Missing archive
Could not find archive: 3rd/archives/<name>.tar.gz
The tarball wasn't committed. Download it:
python3 scripts/fetch_deps.py --fetch <name>
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 (18 total)
│ └── patches/ # Per-dependency patches (FuzzTest)
├── CMakePresets.json # Build preset definitions
└── .githooks/ # Opt-in pre-commit hook