From e067a227af87f650a6e93a7c952971ded0374d3d Mon Sep 17 00:00:00 2001 From: leftibot Date: Sat, 2 May 2026 11:54:06 -0600 Subject: [PATCH] Fix #95: Add README_design.md documenting template design choices New top-level doc explains the rationale behind the template's CMake layout, C++23 default, warning/sanitizer/hardening flags, CPM-based dependencies, dual top-level/subdir behavior, and the myproject_ENABLE_* knobs. Wording is kept short and specific so beginners and veterans can adapt the defaults knowingly. Co-Authored-By: Claude Opus 4.7 (1M context) --- README_design.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 README_design.md diff --git a/README_design.md b/README_design.md new file mode 100644 index 00000000..270a9aed --- /dev/null +++ b/README_design.md @@ -0,0 +1,98 @@ +# Design Choices + +This template starts a C++ project with safe, modern defaults. Each choice +below explains *why*, so you can keep it, swap it, or turn it off. + +## Goals + +1. Catch bugs at compile time, not in production. +2. Stay portable across GCC, Clang, MSVC, and Emscripten. +3. Work the same way as a top-level project or as a subdirectory dependency. + +## Layout + +| File | Role | +| --- | --- | +| `CMakeLists.txt` | Top-level wiring. | +| `ProjectOptions.cmake` | All `myproject_*` options and setup macros. | +| `Dependencies.cmake` | CPM package fetch, gated by `if(NOT TARGET ...)`. | +| `cmake/*.cmake` | One concern per file (warnings, sanitizers, hardening, ...). | + +`PROJECT_IS_TOP_LEVEL` flips defaults: strict when you own the build, quiet +when you are a dependency. + +## C++ standard + +C++23, set only if a parent project has not chosen one. `CMAKE_CXX_EXTENSIONS` +is off so the standard flag is `-std=c++23`, not `-std=gnu++23`. This avoids +`-Wpedantic` conflicts with precompiled headers. + +## Warnings + +`cmake/CompilerWarnings.cmake` enables a curated set per compiler — `/W4` +plus extras on MSVC, and `-Wall -Wextra -Wshadow -Wconversion -Wpedantic ...` +on GCC/Clang. Top-level builds add `-Werror` / `/WX`. Source: +[cppbestpractices](https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md). + +## Sanitizers + +ASan and UBSan are on by default for top-level GCC/Clang builds when a link +probe shows them working. TSan, LSan, and MSan are off — they conflict with +each other and MSan needs an instrumented standard library. Emscripten and +MSVC skip the sanitizer pass. + +## Hardening + +`cmake/Hardening.cmake` adds `_FORTIFY_SOURCE=3` (release builds), +`_GLIBCXX_ASSERTIONS`, `-fstack-protector-strong`, `-fcf-protection`, and +`-fstack-clash-protection` when supported. MSVC gets `/sdl /DYNAMICBASE +/guard:cf /NXCOMPAT /CETCOMPAT`. When no full sanitizer is active, the UBSan +minimal runtime is layered on top. + +## Static analysis + +clang-tidy and cppcheck run as part of the build, on by default at top level. +They are separate options because one tool may not be installed in every +environment. + +## Link-time optimization + +IPO/LTO is on by default at top level. It is gated through +`check_ipo_supported` so unsupported toolchains skip it. + +## Dependencies + +[CPM](https://github.com/cpm-cmake/CPM.cmake) fetches sources at configure +time. Each package is gated by `if(NOT TARGET ...)`, so a parent project can +supply its own version. `SYSTEM YES` silences warnings from third-party +headers. Default set: fmt, spdlog, Catch2, CLI11, FTXUI, lefticus/tools. + +## Testing + +* `test/tests.cpp` — Catch2 unit tests. +* `test/constexpr_tests.cpp` — the same checks at compile time, so bugs + become build errors. +* `fuzz_test/` — libFuzzer harness, auto-enabled when ASan/TSan/UBSan and + libFuzzer are all available. + +## Targets and packaging + +`myproject_options` and `myproject_warnings` are `INTERFACE` libraries that +hold flags. Real targets link them to inherit the configuration without +touching global state. `CPack` package names embed compiler, version, and +short Git SHA, so a binary maps to one build. + +## Defaults for daily use + +The default build type is `RelWithDebInfo` — debuggable and fast. +`compile_commands.json` is always exported, for editors and clang tooling. + +## Changing the defaults + +Every knob is a CMake option named `myproject_ENABLE_`. Flip it on +the configure line, for example: + + cmake -B build -S . -Dmyproject_ENABLE_CLANG_TIDY=OFF + +The `myproject_` prefix is the placeholder the rename workflow replaces, so +renaming the project is one search-and-replace.