273 lines
8.2 KiB
Markdown
273 lines
8.2 KiB
Markdown
# 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 <name>
|
|
```
|
|
|
|
### Missing archive
|
|
|
|
```
|
|
Could not find archive: 3rd/archives/<name>.tar.gz
|
|
```
|
|
|
|
The tarball wasn't committed. Download it:
|
|
|
|
```bash
|
|
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 (26 total)
|
|
│ └── patches/ # Per-dependency patches (FuzzTest)
|
|
├── CMakePresets.json # Build preset definitions
|
|
└── .githooks/ # Opt-in pre-commit hook
|
|
```
|