From 05eabe7cd4628bfbb9ce10384cb75343eded4d02 Mon Sep 17 00:00:00 2001 From: tqcq Date: Mon, 18 May 2026 09:41:16 +0800 Subject: [PATCH] docs: document template workflows --- README.md | 264 ++++++++++++++++++++++ docs/cmake-api.md | 472 ++++++++++++++++++++++++++++++++++++++++ docs/install-export.md | 316 +++++++++++++++++++++++++++ docs/template-design.md | 204 +++++++++++++++++ 4 files changed, 1256 insertions(+) create mode 100644 README.md create mode 100644 docs/cmake-api.md create mode 100644 docs/install-export.md create mode 100644 docs/template-design.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e03bf38 --- /dev/null +++ b/README.md @@ -0,0 +1,264 @@ +# 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. + +```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 + +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: + +```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 +``` + +### C++11 compatibility smoke + +```bash +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: + +```bash +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: + +```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 18 dependencies with SHA256 values is in `3rd/README.md`. + +## 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 (18 total) +│ └── patches/ # Per-dependency patches (FuzzTest) +├── CMakePresets.json # Build preset definitions +└── .githooks/ # Opt-in pre-commit hook +``` diff --git a/docs/cmake-api.md b/docs/cmake-api.md new file mode 100644 index 0000000..ca2b5b1 --- /dev/null +++ b/docs/cmake-api.md @@ -0,0 +1,472 @@ +# CMake helper API manual + +This manual documents the project helper API implemented under `cmake/`. The examples are intentionally close to the positive helper fixtures and current root usage, but paths and target names are illustrative unless a section explicitly says otherwise. + +## Global conventions + +- Call native `project( LANGUAGES C CXX)` before `cc_project()`; the helper rejects CMake's implicit `project(Project)` default. +- The primary project standard is C++14. Fuzz lane targets require the fuzz preset or equivalent Clang + C++17 configuration. +- `INCS`, `DEPS`, and `DEFINES` use explicit visibility groups. Every item must follow `PUBLIC`, `PRIVATE`, or `INTERFACE`; unqualified items are rejected. +- Executable-like targets (`cc_executable`, `cc_test`, `cc_benchmark`, and `cc_fuzz`) do not support `INTERFACE` visibility because they are not consumed as link interfaces. Use `PUBLIC` or `PRIVATE` only. +- `cc_library(TYPE INTERFACE)` supports only `INTERFACE` visibility for `INCS`, `DEPS`, and `DEFINES`. +- Helpers do not acquire external dependencies. Define or load targets such as `GTest::gtest`, `benchmark::benchmark`, and `fuzztest::fuzztest` before calling the corresponding helper. +- There are aggregate targets `run_tests` and `run_benchmarks`, but no per-target `run_test_`, `run_benchmark_`, or `run_fuzz_` wrappers. + +## `cc_project()` + +Signature: + +```cmake +cc_project() +``` + +Use in the root `CMakeLists.txt` after native `project()` and after any cache variables that should influence helper options. + +```cmake +cmake_minimum_required(VERSION 3.19) +project(my_package LANGUAGES C CXX) + +include(cmake/cc_project.cmake) +cc_project() +``` + +Behavior: + +- Sets C++ defaults: C++14 by default, required standard, extensions off. +- Enables `CMAKE_EXPORT_COMPILE_COMMANDS` unless the caller already set it. +- Enables position-independent code. +- Defines helper options: + - `CC_ENABLE_INSTALL`: ON by default for the top-level project, OFF for subprojects. + - `CC_ENABLE_TESTING`: ON by default. + - `CC_ENABLE_BENCHMARKS`: ON by default. + - `CC_ENABLE_FUZZTEST`: OFF by default; requires the fuzz lane when enabled. + - `CC_WARNINGS_AS_ERRORS`: OFF by default. +- Bridges existing lane options into helper options when present: `CPP_TEMPLATE_ENABLE_TESTS`, `CPP_TEMPLATE_ENABLE_BENCHMARKS`, and `CPP_TEMPLATE_FUZZ_LANE`. +- Creates top-level aggregate targets when enabled: + - `run_tests`: runs `ctest --output-on-failure`. + - `run_benchmarks`: aggregate target populated by `cc_benchmark()`. +- Defers `cc_finalize_install()` at generate time when the install module is included. + +## `cc_library()` + +Signature: + +```cmake +cc_library( + TYPE STATIC|SHARED|INTERFACE + [SRCS ...] + [HDRS ...] + [INCS [PUBLIC|PRIVATE|INTERFACE ...]...] + [DEPS [PUBLIC|PRIVATE|INTERFACE ...]...] + [DEFINES [PUBLIC|PRIVATE|INTERFACE ...]...] + [OPTIONS