16 KiB
C++ Template Design Source of Truth
This document is the implementation-facing source-of-truth index for the C++ project template redesign. It does not replace the detailed drafts; it identifies which parts are normative and records the constraints implementation agents must preserve.
Normative Inputs
.sisyphus/plans/cpp-template-redesign.mdis the read-only executable implementation plan owned by Atlas/Orchestrator..sisyphus/drafts/cpp-template-redesign.mdis normative for consolidated dependency, tooling, style, preset, hook, install/export, FuzzTest, and QA decisions..sisyphus/drafts/cmake-api-design.mdis normative for the CMake helper API, dependency loading policy, install/export behavior, and FuzzTest patch/dependency policy.
Older research notes, review findings, and open-question discussions in the drafts are historical unless their decisions appear in the latest consolidated or final-resolution sections.
Fixed Project Constraints
- Primary standard: C++14.
- C++11: best-effort/smoke compatibility only, not the default blocking path.
- C++17: isolated opt-in path, primarily for the
fuzzpreset and FuzzTest. - Toolchains: Clang/GCC only; no MSVC support.
- Dependency loading: local CPM archives under
3rd/archives/withURL_HASH SHA256=...; no hidden remote fallback. - Offline strategy: local archive/source paths and hash verification, not a global offline mode switch.
- FuzzTest: required by the redesign only in the isolated
fuzzpreset/tree, with pristine upstream archive, patch files, script-driven apply/verify workflow, and no protobuf-backed FuzzTest path. - HTTP baseline: cpp-httplib.
libhvis excluded from v1 unless explicitly re-approved. - Removed/not allowed by default:
magic_enum, protobuf-backed FuzzTest integration, global offline mode, CMakeformat/check_format/run_clang_tidytargets.
Normative Template C++ Style
These template-specific style rules intentionally supersede generic agent C++ defaults wherever they conflict:
- clang-format 17+ is required.
- Indentation: 4 spaces, no tabs.
- Column target: 120.
- Functions, classes, structs, enums, and namespaces use Allman braces.
- Control statements and lambdas use attached braces.
- Include order: corresponding/main header first, then project/generated quoted headers, then C headers, C++ standard headers, known third-party headers, OS/system headers, and other angle headers.
- Private/protected members use
m_+snake_case. - Static non-const members and function-local statics use
s_+snake_case. - Constants, including local constants, use
kCamelCase. - Public struct fields and local variables use
snake_case. - Types use
PascalCase; functions and methods usecamelCase; namespaces uselower_case. - clang-tidy is strict from the start with warnings-as-errors for enabled checks.
.clang-formatis the formatter source-of-truth for enforceable whitespace, brace, column, pointer/reference, return-type, and include-order rules.scripts/format.py --checkverifies selected C/C++ files andscripts/format.py --fixrewrites them; naming rules such asm_,s_, andkCamelCaseremain documented conventions because clang-format cannot enforce identifier names.
Implementation Handoff Rule
Implementation agents must treat the latest consolidated/final-resolution draft sections as authoritative. If an older section conflicts with the constraints above, the older section is historical/superseded and must not drive implementation.
v1 Dependency Inventory (Frozen)
Source of truth: cmake/deps/versions.cmake.
| Name | Version | C++ Gate | CMake Targets | Presets | Archive |
|---|---|---|---|---|---|
| spdlog | 1.15.3 | C++11 | spdlog::spdlog |
debug,release,fuzz | spdlog-1.15.3.tar.gz |
| fmt | 11.0.2 | C++11 | fmt::fmt |
debug,release,fuzz | fmt-11.0.2.tar.gz |
| nlohmann/json | 3.11.3 | C++11 | nlohmann_json::nlohmann_json |
debug,release,fuzz | nlohmann-json-3.11.3.tar.gz |
| toml11 | 4.4.0 | C++11 | toml11::toml11 |
debug,release,fuzz | toml11-4.4.0.tar.gz |
| CLI11 | 2.4.2 | C++11 | CLI11::CLI11 |
debug,release,fuzz | CLI11-2.4.2.tar.gz |
| asio (standalone) | 1.30.2 | C++11 | asio::asio |
debug,release,fuzz | asio-1.30.2.tar.gz |
| concurrentqueue | 1.0.4 | C++11 | concurrentqueue::concurrentqueue |
debug,release,fuzz | concurrentqueue-1.0.4.tar.gz |
| ghc::filesystem | 1.5.14 | C++11 | ghcFilesystem::ghc_filesystem |
debug,release,fuzz | ghc-filesystem-1.5.14.tar.gz |
| expected-lite | 0.8.0 | C++11 | nonstd::expected-lite |
debug,release,fuzz | expected-lite-0.8.0.tar.gz |
| cpp-httplib | 0.18.3 | C++11 | httplib::httplib |
debug,release,fuzz | cpp-httplib-0.18.3.tar.gz |
| GTest/GMock (normal) | 1.16.0 | C++14 | GTest::gtest, GTest::gtest_main, GTest::gmock, GTest::gmock_main |
debug,release | googletest-1.16.0.tar.gz |
| Benchmark | 1.7.1 | C++11 | benchmark::benchmark, benchmark::benchmark_main |
debug,release | benchmark-1.7.1.tar.gz |
| GTest/GMock (fuzz) | 1.17.0 | C++17 | GTest::gtest, GTest::gmock |
fuzz | googletest-1.17.0.tar.gz |
| Abseil | 20260107.1 | C++17 | absl::* |
fuzz | abseil-cpp-20260107.1.tar.gz |
| RE2 | 2025-11-05 | C++17 | re2::re2 |
fuzz | re2-2025-11-05.tar.gz |
| ANTLR4 runtime | 4.13.2 | C++17 | antlr4_static |
fuzz | antlr4-4.13.2.tar.gz |
| FuzzTest | 2026-02-19 | C++17 | fuzztest::fuzztest |
fuzz | fuzztest-2026-02-19.tar.gz |
Excluded from v1
libhv— excluded; cpp-httplib is the v1 HTTP baseline.magic_enum— removed per user request.protobuf— FuzzTest protobuf-backed paths forbidden.oatpp,microprofile,breakpad— removed from default template.crow— C++17-only; cpp-httplib covers C++14 HTTP.BLAKE3— CMake propagatescxx_std_20PUBLIC.bitsery— repo/path verification unresolved.outcome— replaced by expected-lite.OpenSSL— rejected as default dependency; too heavy.
Core Runtime Defaults
The cc_library(), cc_executable(), cc_test(), cc_benchmark(), and cc_fuzz() helpers automatically link the Core runtime defaults listed above from spdlog through cpp-httplib. Static/shared libraries receive the aggregate as PUBLIC, interface libraries as INTERFACE, and executable-like targets as PRIVATE. This includes nlohmann_json::nlohmann_json in the fuzz lane while keeping protobuf-backed FuzzTest integration out of scope.
GTest Version Isolation
Normal C++14 builds use GTest/GMock 1.16.0. Fuzz/C++17 builds use GTest/GMock 1.17.x. These must never coexist in the same build tree. The dependency modules enforce this separation.
Archive & Hash Notes
- All v1 SHA256 hashes are concrete in
3rd/README.mdandcmake/deps/versions.cmake. The table above lists names and versions;3rd/README.mdis the user-facing hash source of truth. - FuzzTest SHA256:
1c6e04065eb988e2c99613369db8294aa58429d392bf479740b237f1255204ef. - CPM
URL_HASH SHA256=...enforcement in per-dependency modules consumesversions.cmakevariables. - Abseil/RE2/ANTLR4 versions must match the pinned FuzzTest release's
BuildDependencies.cmake; re-verify when rebasing.
CMake Preset Contract (T6)
This section defines the visible CMake preset contract that later implementation tasks must preserve. T6 is a contract-only step: the repository currently has no root CMakePresets.json, and T11 owns the full preset implementation and configure/build/test validation. If T11 adds hidden/internal presets, each hidden preset must be minimal, justified in this document, and must not expand the visible user-facing set.
Normative compatibility constraints:
- CMake preset file compatibility is separate from the project CMake code minimum. Project CMake code remains minimum 3.19, but a single root
CMakePresets.jsoncontaining configure, build, and test presets should use CMakePresets schema version 2, which requires CMake 3.20+ for preset users. - If strict CMake 3.19 preset-file compatibility is required, schema version 1 supports configure presets only; build/test behavior must then be invoked manually or documented outside presets. Do not add a
$schemafield while the project supports older preset file versions. - Every visible configure preset must use the Unix Makefiles generator.
- Every visible configure preset must set
CMAKE_EXPORT_COMPILE_COMMANDS=ON. - Every visible configure preset must use
binaryDirequivalent to${sourceDir}/build/${presetName}; the documented shorthand isbuild/${presetName}. - The visible configure preset names are exactly
debug,release,asan, andfuzz. No MSVC presets are part of v1. - Build presets should mirror each visible configure preset name and build its matching configure preset.
- Test presets should exist only where tests are part of the lane contract:
debug,release,asan, andfuzzfor deterministic fuzz smoke.
| Preset | Purpose | C++ standard | Build type | Tests, benchmark, fuzz behavior | Sanitizer flags intent | Build directory | Compile commands | Dependency lane |
|---|---|---|---|---|---|---|---|---|
debug |
Default developer lane and fast local checks. | C++14 | Debug |
Tests and benchmarks enabled; fuzz is requested by default but auto-skips because the lane is not Clang + C++17 + isolated GTest. | None; sanitizer behavior belongs only to asan. |
build/debug |
ON |
Core deps plus normal GTest/GMock 1.16.0 and Benchmark 1.7.1. |
release |
Optimized normal build lane. | C++14 | Release |
Tests and benchmarks enabled; fuzz is requested by default but auto-skips unless the isolated fuzz lane requirements are met. | None. | build/release |
ON |
Core deps plus normal GTest/GMock 1.16.0 and Benchmark 1.7.1. |
asan |
AddressSanitizer validation lane. | C++14 | Debug |
Tests enabled; benchmarks disabled to avoid noisy sanitizer runs; fuzz is requested but auto-skips. | Preset sets CC_ENABLE_ASAN=ON; cc_project() applies AddressSanitizer compile/link flags. |
build/asan |
ON |
Same normal dependency lane as debug; no FuzzTest stack. |
fuzz |
Isolated deterministic fuzz smoke and FuzzTest development lane. | C++17 | Debug |
Normal tests are not the focus; deterministic fuzz smoke is registered in CTest with fixed seed/run count; long fuzzing stays direct executable invocation outside default CTest. Benchmarks disabled. | No default sanitizer requirement in the contract; sanitizer fuzzing, if added later, must be explicit and not affect normal lanes. | build/fuzz |
ON |
Core deps plus isolated FuzzTest lane: GTest/GMock 1.17.0, Abseil 20260107.1, RE2 2025-11-05, ANTLR4 runtime 4.13.2, FuzzTest 2026-02-19. Requires Clang in implementation. |
Implementation notes for T11 and later tasks:
- Preset options make lane behavior explicit through cache variables while keeping user
CMakeLists.txtdeclarative. Normal lanes request tests/benchmarks/fuzz by default; fuzz target creation is capability-gated and auto-skips unless the build is Clang + C++17 with the isolated fuzz GTest lane. debugremains the fast default path for developer checks; it must not silently enable sanitizer flags or materialize FuzzTest when fuzz is unavailable.fuzzis the only v1 lane that materializes FuzzTest. Thefuzzlane may require Clang for its specialized runtime. The fuzz lane must not load normal GoogleTest/GMock 1.16.0 into the same build tree as FuzzTest's GoogleTest/GMock 1.17.0 lane.- Hidden presets are not required by this contract. If T11 uses a hidden base to remove duplication, keep it internal, do not expose extra user presets, and document the reason here and in evidence.
- Lane option cache variables are set in all presets:
CC_ENABLE_BENCHMARKS(ON in debug/release, OFF in asan/fuzz), andCC_ENABLE_ASAN(ON only in asan). cc_project()computesCC_ENABLE_FUZZTEST_AVAILABLEbefore including FuzzTest dependencies. Unsupported fuzz requests skip cleanly instead of failing default configure.- Fuzz targets registered through
cc_fuzz()have labelfuzz_smokeand are created only whenCC_ENABLE_FUZZTEST_AVAILABLEis true. Normalcc_test()targets are skipped in the fuzz lane.
Fuzz Smoke Testing
The fuzz preset runs FuzzTest targets in unit-test mode (FUZZTEST_FUZZING_MODE=OFF), which executes fuzz tests as deterministic GTest-compatible tests rather than continuous fuzzing campaigns.
Deterministic CTest Smoke
All fuzz targets registered via cc_fuzz() appear in CTest with the fuzz_smoke label:
# Run all fuzz smoke tests
ctest --test-dir build/fuzz --output-on-failure -L fuzz_smoke
Determinism is ensured through two mechanisms:
.WithSeeds()in the fuzz test source: provides concrete fixed inputs that always run. In unit-test mode, FuzzTest runs each seed once as a GTest test case.FUZZTEST_PRNG_SEEDenvironment variable: set viaSMOKE_ENVincc_fuzz()registration. Makes any additional PRNG-driven input generation reproducible across runs.
The cc_fuzz() helper supports three smoke-test customization keywords:
| Keyword | Purpose | Example |
|---|---|---|
SMOKE_ARGS |
Arguments for the CTest smoke command | (empty by default) |
SMOKE_ENV |
Environment variables for CTest smoke | FUZZTEST_PRNG_SEED=42 |
SMOKE_TIMEOUT |
CTest timeout in seconds | 30 (default) |
Long-Running Fuzzing (Outside CTest)
Continuous fuzzing campaigns use the fuzz executable directly with --fuzz flags. These are NOT registered in CTest because they run indefinitely.
Important: --fuzz, --fuzz_for, and --time_limit_per_input require a fuzzing-mode build (FUZZTEST_FUZZING_MODE=ON). The default fuzz preset CTest smoke runs in unit-test mode (FUZZTEST_FUZZING_MODE=OFF) using .WithSeeds() and FUZZTEST_PRNG_SEED. To use continuous fuzzing flags, rebuild with FUZZTEST_FUZZING_MODE=ON or invoke a fuzzing-mode binary directly.
# List available fuzz tests
./build/fuzz/calc_fuzz --gtest_list_tests
# Run a specific fuzz test in fuzzing mode with safety limits
# (requires FUZZTEST_FUZZING_MODE=ON build)
./build/fuzz/calc_fuzz \
--fuzz=CalcFuzz.AddNeverCrashes \
--time_limit_per_input=30s \
--fuzz_for=60s
Safety flags for long fuzzing (fuzzing mode only):
--fuzz_for=<duration>: total fuzzing time (e.g.,60s,5m).--time_limit_per_input=<duration>: max time per input before timeout.- These flags have no effect in unit-test mode (
FUZZTEST_FUZZING_MODE=OFF).
T9 clang-tidy Policy
scripts/clang_tidy.pyis the script-first strict clang-tidy entry point; CMake must not definetidy,run_clang_tidy,clang-tidy, orcheck_tidytargets.- The runner requires clang-tidy 17+ and a
compile_commands.jsonin--build-dirbefore real execution. The default build directory isbuild/debug. - Debug fast checks configure with
-DCMAKE_EXPORT_COMPILE_COMMANDS=ONsoscripts/dev_check.py --fastcan feed clang-tidy without relying on CMake-integrated tidy targets. - The runner uses the shared project path filter and checks only project C/C++ files, skipping build outputs, vendored trees, generated/task-state directories,
.sisyphus,.opencode,.git, and3rd/. - Warnings are errors through both
.clang-tidy(WarningsAsErrors: '*') and the runner CLI (--warnings-as-errors=*). Each file is invoked separately so failures report exactfailed_file:paths.
T10 Local Git Hook Workflow
- Git hooks are local and opt-in. The template does not automatically install hooks during configure, build, test, formatting, clang-tidy, or other developer checks.
.githooks/pre-commitis the repository hook entry point. It resolves the repository root withgit rev-parse --show-toplevel, changes to that root, and delegates topython3 scripts/pre_commit.py.scripts/pre_commit.pyprints and runs the exact fast-check delegation:python3 scripts/dev_check.py --fast. Its--dry-runmode prints the same command plan without executing checks.scripts/setup_hooks.pyis the only setup entry point for hook installation. Non-dry-run setup verifies.githooks/pre-commit, ensures it is executable, and runs onlygit config --local core.hooksPath .githooks.scripts/setup_hooks.py --dry-runprints the intended local-only git config command without mutating git config.scripts/setup_hooks.py --statusreports hook file existence, executable state, and the localcore.hooksPathvalue when available.- Global or user git configuration must never be modified by the template hook workflow.