Files
cpp-project-template/docs/template-design.md
T
tqcq 05eabe7cd4
cpp-template / format (push) Failing after 3m38s
cpp-template / debug (push) Failing after 5m18s
cpp-template / clang-tidy (push) Failing after 1m26s
cpp-template / release (push) Failing after 1m42s
cpp-template / cxx11-smoke (push) Failing after 1m43s
cpp-template / install-consumer (push) Failing after 1m37s
cpp-template / asan (push) Failing after 1m23s
cpp-template / tsan (push) Failing after 1m26s
cpp-template / fuzz-smoke (push) Failing after 1m15s
cpp-template / no-network-negative (push) Failing after 7m7s
docs: document template workflows
2026-05-18 09:41:16 +08:00

19 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.md is the read-only executable implementation plan owned by Atlas/Orchestrator.
  • .sisyphus/drafts/cpp-template-redesign.md is normative for consolidated dependency, tooling, style, preset, hook, install/export, FuzzTest, and QA decisions.
  • .sisyphus/drafts/cmake-api-design.md is 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 fuzz preset and FuzzTest.
  • Toolchains: Clang/GCC only; no MSVC support.
  • Dependency loading: local CPM archives under 3rd/archives/ with URL_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 fuzz preset/tree, with pristine upstream archive, patch files, script-driven apply/verify workflow, and no protobuf-backed FuzzTest path.
  • HTTP baseline: cpp-httplib. libhv is excluded from v1 unless explicitly re-approved.
  • Removed/not allowed by default: magic_enum, protobuf FuzzTest integration, global offline mode, CMake format/check_format/run_clang_tidy targets.

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 use camelCase; namespaces use lower_case.
  • clang-tidy is strict from the start with warnings-as-errors for enabled checks.
  • .clang-format is the formatter source-of-truth for enforceable whitespace, brace, column, pointer/reference, return-type, and include-order rules. scripts/format.py --check verifies selected C/C++ files and scripts/format.py --fix rewrites them; naming rules such as m_, s_, and kCamelCase remain 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 SHA256
spdlog 1.15.3 C++11 spdlog::spdlog debug,release,fuzz spdlog-1.15.3.tar.gz PENDING_T12
fmt 11.0.2 C++11 fmt::fmt debug,release,fuzz fmt-11.0.2.tar.gz PENDING_T12
nlohmann/json 3.11.3 C++11 nlohmann_json::nlohmann_json debug,release,fuzz nlohmann-json-3.11.3.tar.gz PENDING_T12
toml11 4.4.0 C++11 toml11::toml11 debug,release,fuzz toml11-4.4.0.tar.gz PENDING_T12
CLI11 2.4.2 C++11 CLI11::CLI11 debug,release,fuzz CLI11-2.4.2.tar.gz PENDING_T12
asio (standalone) 1.30.2 C++11 asio::asio debug,release,fuzz asio-1.30.2.tar.gz PENDING_T12
concurrentqueue 1.0.4 C++11 concurrentqueue::concurrentqueue debug,release,fuzz concurrentqueue-1.0.4.tar.gz PENDING_T12
readerwriterqueue 1.0.6 C++11 readerwriterqueue::readerwriterqueue debug,release,fuzz readerwriterqueue-1.0.6.tar.gz PENDING_T12
ghc::filesystem 1.5.14 C++11 ghcFilesystem::ghc_filesystem debug,release,fuzz ghc-filesystem-1.5.14.tar.gz PENDING_T12
expected-lite 0.8.0 C++11 nonstd::expected-lite debug,release,fuzz expected-lite-0.8.0.tar.gz PENDING_T12
cpp-httplib 0.18.3 C++11 httplib::httplib debug,release,fuzz cpp-httplib-0.18.3.tar.gz PENDING_T12
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 PENDING_T12
Benchmark 1.7.1 C++11 benchmark::benchmark, benchmark::benchmark_main debug,release benchmark-1.7.1.tar.gz PENDING_T12
GTest/GMock (fuzz) 1.17.0 C++17 GTest::gtest, GTest::gmock fuzz googletest-1.17.0.tar.gz PENDING_T12
Abseil 20260107.1 C++17 absl::* fuzz abseil-cpp-20260107.1.tar.gz PENDING_T12
RE2 2025-11-05 C++17 re2::re2 fuzz re2-2025-11-05.tar.gz PENDING_T12
ANTLR4 runtime 4.13.2 C++17 antlr4_static fuzz antlr4-4.13.2.tar.gz PENDING_T12
FuzzTest 2026-02-19 C++17 fuzztest::fuzztest fuzz fuzztest-2026-02-19.tar.gz 1c6e04...04ef (pinned T5)

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, tracy, microprofile, breakpad — removed from default template.
  • crow — C++17-only; cpp-httplib covers C++14 HTTP.
  • BLAKE3 — CMake propagates cxx_std_20 PUBLIC.
  • bitsery — repo/path verification unresolved.
  • outcome — replaced by expected-lite.
  • OpenSSL — rejected as default dependency; too heavy.

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

  • SHA256 values marked PENDING_T12 require concrete archive acquisition (T12/T14).
  • FuzzTest SHA256 is pinned from T5: 1c6e04065eb988e2c99613369db8294aa58429d392bf479740b237f1255204ef.
  • CPM URL_HASH SHA256=... enforcement in per-dependency modules (T13) consumes versions.cmake variables.
  • 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.json containing 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 $schema field while the project supports older preset file versions.
  • Every visible configure preset must use the Ninja generator.
  • Every visible configure preset must set CMAKE_EXPORT_COMPILE_COMMANDS=ON.
  • Every visible configure preset must use binaryDir equivalent to ${sourceDir}/build/${presetName}; the documented shorthand is build/${presetName}.
  • The visible configure preset names are exactly debug, release, asan, tsan, fuzz, and cxx11-smoke. 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, tsan, and fuzz for deterministic fuzz smoke. cxx11-smoke is configure/build only unless a compatible C++11 test stack is explicitly proven later.
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 enabled; fast developer checks enabled; benchmarks may be built when the normal benchmark option is enabled; fuzz disabled. None; sanitizer behavior belongs only to asan/tsan. 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 enabled for release validation; benchmarks may be enabled for release performance checks; fuzz disabled. 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; benchmark/fuzz disabled by default so sanitizer runs stay focused on correctness tests. Enable AddressSanitizer compile and link flags in the implementation; do not hide ASan in debug. build/asan ON Same normal dependency lane as debug; no FuzzTest stack.
tsan ThreadSanitizer validation lane. C++14 Debug Tests enabled; benchmark/fuzz disabled by default so sanitizer runs stay focused on correctness tests. Enable ThreadSanitizer compile and link flags in the implementation; do not hide TSan in debug. build/tsan 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.
cxx11-smoke Best-effort compatibility smoke for the C++11-compatible subset. C++11 Debug Configure/build compatible subset only; tests, benchmarks, and fuzz are disabled until a compatible stack is explicitly proven. None. build/cxx11-smoke ON Core dependencies whose inventory gate is C++11 only; excludes normal GTest/GMock 1.16.0, Benchmark, and all FuzzTest-lane dependencies.

Implementation notes for T11 and later tasks:

  • Preset options must make lane behavior explicit through cache variables rather than implicit hidden magic. Suggested option intent: enable tests for normal and sanitizer lanes, enable deterministic fuzz smoke only in fuzz, and disable tests/benchmark/fuzz in cxx11-smoke.
  • debug remains the fast default path for developer checks; it must not silently enable sanitizer flags or FuzzTest.
  • fuzz is the only v1 lane allowed to require C++17 and Clang for FuzzTest. It 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.

T11 Implementation Status

  • A hidden _base preset provides generator: "Ninja" and CMAKE_EXPORT_COMPILE_COMMANDS=ON to avoid repetition across six visible presets. It does not appear in cmake --list-presets. Rationale: the only shared state is the generator and compile-commands export; build type, C++ standard, and sanitizer flags are per-lane.
  • Each visible preset sets its own explicit binaryDir rather than relying on ${presetName} expansion from the hidden base, because ${presetName} behavior with inherited presets can be ambiguous in older CMake 3.20.x patch levels.
  • Sanitizer flags are set directly in preset cacheVariables (CMAKE_CXX_FLAGS, CMAKE_EXE_LINKER_FLAGS). Later tasks (T16+) may add CMake-level option gating (e.g., CC_ENABLE_SANITIZERS) that consumes or overrides these; the preset contract remains the user-facing surface.
  • Three lane option cache variables are set in all presets: CPP_TEMPLATE_ENABLE_TESTS (ON in debug/release/asan/tsan, OFF in fuzz/cxx11-smoke), CPP_TEMPLATE_ENABLE_BENCHMARKS (ON in debug/release, OFF in asan/tsan/fuzz/cxx11-smoke), CPP_TEMPLATE_FUZZ_LANE (ON only in fuzz, OFF everywhere else).
  • fuzz preset enforces Clang at configure time: CMakeLists.txt contains if(CPP_TEMPLATE_FUZZ_LANE) guard that calls message(FATAL_ERROR ...) on non-Clang compilers. Verified: GCC 13.3.0 fails with clear message; Clang 18.1.3 configures successfully.
  • A deterministic fuzz smoke CTest placeholder fuzz_lane.config_check is registered via cmake -E echo inside the CPP_TEMPLATE_FUZZ_LANE guard. It has label fuzz_smoke and is gated to the fuzz preset only. Normal calc_test is not registered in the fuzz lane.
  • cxx11-smoke disables tests, benchmarks, and fuzz via cache variables. Verified: configure produces 0 CTest registrations.
  • debug, release, asan, and tsan configure successfully with tests enabled. Verified: calc_test registered in each; sanitizer presets keep benchmarks disabled.
  • cxx11-smoke has no test preset; configure/build only per contract.

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:

  1. .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.
  2. FUZZTEST_PRNG_SEED environment variable: set via SMOKE_ENV in cc_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.py is the script-first strict clang-tidy entry point; CMake must not define tidy, run_clang_tidy, clang-tidy, or check_tidy targets.
  • The runner requires clang-tidy 17+ and a compile_commands.json in --build-dir before real execution. The default build directory is build/debug.
  • Debug fast checks configure with -DCMAKE_EXPORT_COMPILE_COMMANDS=ON so scripts/dev_check.py --fast can 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, 3rd/, and third_party/.
  • Warnings are errors through both .clang-tidy (WarningsAsErrors: '*') and the runner CLI (--warnings-as-errors=*). Each file is invoked separately so failures report exact failed_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-commit is the repository hook entry point. It resolves the repository root with git rev-parse --show-toplevel, changes to that root, and delegates to python3 scripts/pre_commit.py.
  • scripts/pre_commit.py prints and runs the exact fast-check delegation: python3 scripts/dev_check.py --fast. Its --dry-run mode prints the same command plan without executing checks.
  • scripts/setup_hooks.py is the only setup entry point for hook installation. Non-dry-run setup verifies .githooks/pre-commit, ensures it is executable, and runs only git config --local core.hooksPath .githooks.
  • scripts/setup_hooks.py --dry-run prints the intended local-only git config command without mutating git config. scripts/setup_hooks.py --status reports hook file existence, executable state, and the local core.hooksPath value when available.
  • Global or user git configuration must never be modified by the template hook workflow.