Optional CTest/CDash reporting is documented in Dashboard.md.
Linux / macOS (Bash 3.2+):
./setup.sh --run
# Or create a renamed project and run it in the same invocation:
./setup.sh --init MyProject --output ../MyProject --runWindows (Windows PowerShell 5.1+ or PowerShell 7):
.\setup.ps1 -Run
# Or generate, configure, build, test and launch a new project:
.\setup.ps1 -Init MyProject -Output ..\MyProject -Runsetup detects installed tools, provisions missing supported host dependencies,
activates the toolchain for its own process, configures with the default
app-release preset, builds and runs CTest. --run / -Run additionally launches
the program through its CMake target; omit it for services/GUI programs you do not
want to start automatically. No Python, pip, venv, user-shell configuration or
manual invocation of CMake is needed. Tool installation can request administrator
permissions, downloads, or a reboot/Command Line Tools approval.
Use --profile dev, --preset app-debug, --jobs 8, --no-tests,
--setup-only, or --dry-run as needed; PowerShell also accepts -Profile,
-Preset, -Jobs, -NoTests, -SetupOnly and -DryRun. --run-target NAME
builds an arbitrary CMake target but does not launch it. --install-artifacts
installs built artifacts to the preset-specific output directory.
To rebuild later without provisioning host packages, run ./build.sh --run or
.\build.ps1 -Run. Configuration, build, tests, launch, and optional install
remain available individually with CMake/CTest for advanced users.
setup.sh is included in generated projects, along with both activation and
entry-option modules; copying the generated project does not require retaining
this template checkout.
OUTPUT defaults to ./<NAME> and must be absent or empty. Names start with a
letter, followed by alphanumeric groups separated by single underscores or hyphens.
Build-system names such as install, TEST and All_Build are reserved regardless
of case.
The initializer renames the project/application, application test target,
standalone library workspace, vcpkg package and container image defaults.
MyProject becomes my-project for package/image names. The boilerplate_* API,
presets, example libraries library1/library2 and license remain intact.
An explicit file manifest excludes Git history, generated docs, local build trees,
SDK checkouts and personal configuration. No files are downloaded or installed.
See initializer maintenance and tests.
CMake 3.26+, Ninja for the supplied presets, GCC/Clang or MSVC for ordinary builds.
The default application and two example libraries require no downloaded packages.
C++23 is the default; BOILERPLATE_CXX_STANDARD=17|20|23 selects the language level.
Project defaults live in CMake/presets; per-target policies compose owned-target settings. Optional
Google Benchmark, GoogleTest and libFuzzer integrations coexist with a small
independent process harness and dependency-free correctness tests.
Cross compilation is selected by toolchain presets: linux-arm64,
windows-x64-from-linux, android-arm64, wasm32-emscripten. Capabilities and
target policies remain independent. See SDK requirements, host tools and emulator
execution.
Run from the repository root:
cmake --workflow --preset app-debug
# Equivalent individual steps:
cmake --preset app-release
cmake --build --preset app-release --parallel 4
ctest --preset app-releaseFor a library/runtime project:
cmake --preset lib-release
cmake --build --preset lib-release --parallel 4
ctest --preset lib-release
cmake --build --preset lib-release --target boilerplate_check_cmakelib-* presets also work from lib/ as a standalone source tree. Root and lib/
have separate out/build directories; stay in the same directory for all steps.
cmake --list-presets=all lists configurations. Configure/build/test presets have
the same names for all app-* and lib-* profiles. Old application preset names
are retained. Use fresh build trees when migrating from the older global flags.
Workspace / project configure
├─ Capabilities -> one project-wide workflow/lifecycle
├─ Components -> optional scale boundary for source-tree ownership
│ └─ Targets
│ ├─ Library
│ ├─ Runtime
│ ├─ Application
│ │ └─ Host(s)
│ └─ Plugin(s)
└─ Unscoped targets -> small projects may skip components entirely
Target
└─ Policies -> compile/link/build semantics
There are now two deliberate reusable layers:
lib/cmake/— standalone library/tool core. It has no application, host, plugin-hosting or application-deployment dependency and can be extracted withlib/as an independent project. See the library/core API.cmake/+lib/cmake/— full component/execution framework. The root layer addsRuntime,Application,Host,Pluginand deployment semantics on top of the same core. Keep the checked-in relative layout, or setBOILERPLATE_CORE_MODULE_DIRbefore including the full facade.
Library-only project:
cmake_minimum_required(VERSION 3.26)
include(cmake/Bootstrap.cmake)
boilerplate_bootstrap()
project(MyLibrary VERSION 1.0.0 LANGUAGES CXX)
include(cmake/Boilerplate.cmake)
boilerplate_project(CAPABILITIES developer)
boilerplate_add_library(core SOURCES src/core.cpp INCLUDE_DIR include)
boilerplate_finalize_project()Full hosted application, with the repository layout preserved:
cmake_minimum_required(VERSION 3.26)
include(cmake/Bootstrap.cmake)
boilerplate_bootstrap()
project(MyProduct VERSION 1.0.0 LANGUAGES CXX)
include(cmake/Boilerplate.cmake)
boilerplate_project(CAPABILITIES developer)
boilerplate_add_library(core SOURCES lib/core.cpp INCLUDE_DIR include)
boilerplate_add_runtime(engine SOURCES src/engine.cpp LIBRARIES core::core)
boilerplate_add_application(editor SOURCES src/editor.cpp RUNTIMES engine)
# Additional process realization of the same application image.
boilerplate_add_host(editor_cli KIND CONSOLE)
boilerplate_host_application(editor_cli editor)
boilerplate_finalize_project()The library header includes core_export.h and uses CORE_EXPORT on its public
functions/classes. Targets core::shared, core::static, core::core are provided;
core::core prefers shared when both variants exist. Installation generates
relocatable find_package(core CONFIG REQUIRED) packages and unique export headers.
PUBLIC_LIBRARIES, PRIVATE_LIBRARIES and custom PACKAGE_CONFIG support dependencies.
No allocator implementation, runtime API or benchmark CLI is assumed by the modules.
The two checked-in example libraries are intentionally not clones. library1
is dependency-free and owns a local policy pack with different shared/static
variant policies. library2 has a public Threads::Threads dependency, its own
installed package config with find_dependency(Threads), a different local policy
pack and target PCH. boilerplate_check_cmake installs and relocates both packages
and builds separate consumers, so per-library customization is a regression fixture
rather than README-only syntax.
Pass -DNAME=value at configure time. Lists use semicolons; quote the whole argument.
| Knob | Default / purpose |
|---|---|
BOILERPLATE_LIBRARIES_ONLY |
OFF; root entry point skips application/examples/fuzz/docs when ON |
BOILERPLATE_BUILD_APPLICATION |
ON; sample application |
BOILERPLATE_BUILD_SHARED, BOILERPLATE_BUILD_STATIC |
Shared ON, static OFF by default; presets may select both |
<NAME>_BUILD_SHARED, <NAME>_BUILD_STATIC |
Per-library overrides, e.g. LIBRARY1_BUILD_STATIC |
BOILERPLATE_BUILD_TESTS, BUILD_TESTING |
Dependency-free checks; root defaults ON, standalone lib presets enable them |
BOILERPLATE_BUILD_GOOGLE_TESTS |
OFF; optional GoogleTest suites |
BOILERPLATE_BUILD_BENCHMARKS |
OFF; custom benchmark examples |
BOILERPLATE_BUILD_GOOGLE_BENCHMARKS |
OFF; Google Benchmark examples; may be ON together with custom benchmarks |
BOILERPLATE_BENCHMARK_GROUPS |
all; select custom;google or project-defined groups |
BOILERPLATE_BUILD_<TARGET> |
Per-benchmark switch, e.g. BOILERPLATE_BUILD_LIBRARY1_BENCH |
BOILERPLATE_BUILD_EXAMPLES |
OFF; explicit application/example targets |
BOILERPLATE_BUILD_QT_EXAMPLE |
OFF; Qt 6 Widgets example, enabled by app-qt-* presets |
BOILERPLATE_BUILD_PROPERTY_TESTS |
OFF; RapidCheck property-test example |
BOILERPLATE_BUILD_FUZZERS |
OFF; byte-fuzz harness example (`libfuzzer |
BOILERPLATE_BUILD_FUZZTESTS |
OFF; Google FuzzTest example |
BOILERPLATE_CXX_STANDARD |
23; 17/20/23 supported |
BOILERPLATE_WARNINGS, BOILERPLATE_WARNINGS_AS_ERRORS |
ON / OFF; target-scoped warnings |
BOILERPLATE_HARDENING |
OFF; stack protector, Linux RELRO; avoids forcing executable PIE flags onto libraries |
BOILERPLATE_COVERAGE |
OFF; gcov-compatible instrumentation, requires GCC/Clang without LTO/PGO |
BOILERPLATE_CCACHE, BOILERPLATE_CLANG_TIDY, BOILERPLATE_UNITY_BUILD |
OFF; use the corresponding existing tools / CMake feature |
BOILERPLATE_FRAME_POINTERS |
OFF; preserve frame pointers for profiling/unwinding |
BOILERPLATE_INSTALL |
ON; package exports and application installation |
BOILERPLATE_PROJECT_CAPABILITIES |
developer; top-level project capability composition |
BOILERPLATE_EMBEDDED_PROJECT_CAPABILITIES |
project-minimal; behavior under add_subdirectory() |
BOILERPLATE_DEPENDENCY_PROVIDER |
system; `none |
BOILERPLATE_COMPILER_CACHE |
auto; `sccache |
BOILERPLATE_DIAGNOSTICS_VERBOSE |
OFF; keep configure output compact, full graph stays in boilerplate-project.txt / boilerplate_config |
BUILD_DOCS, ENABLE_PACKAGING |
OFF; append docs / packaging project capabilities in this example root |
BOILERPLATE_FETCH_DEPENDENCIES |
OFF; explicitly permit pinned FetchContent fallback |
BOILERPLATE_PBT_BACKEND |
rapidcheck; property-testing backend |
BOILERPLATE_FUZZ_BACKEND |
libfuzzer; `libfuzzer |
BOILERPLATE_FUZZ_SANITIZER |
address-undefined; fuzz-harness instrumentation |
BOILERPLATE_FUZZTEST_MODE |
unit; `unit |
The checked-in vcpkg.json exposes optional manifest features tests, pbt,
benchmarks, graphics, and qt; byte-fuzz engines remain host tools/compiler
wrappers rather than library dependencies. The manifest baseline is pinned, so
CI/local installs resolve the same port graph; package versions come from that
baseline unless a feature genuinely needs a separate minimum constraint.
Find installed packages with CMAKE_PREFIX_PATH or use a package-manager toolchain
via CMAKE_TOOLCHAIN_FILE on the initial configure. Default presets do not
require vcpkg. Disabled components do not search for their optional dependencies.
There are no unconditional clang-tidy/IWYU/ccache invocations or global optimization
flags. The reusable core lives in lib/cmake/; the root cmake/ directory is now a
thin higher-level execution layer rather than a duplicate build implementation.
With BOILERPLATE_DEPENDENCY_PROVIDER=vcpkg, an explicit CMAKE_TOOLCHAIN_FILE
takes priority. Otherwise bootstrap and build_all.* resolve vcpkg in this order:
BOILERPLATE_VCPKG_ROOT, CMake variable VCPKG_ROOT, environment VCPKG_ROOT,
vcpkg/, external/vcpkg/ or third_party/vcpkg/ under the source directory,
the vcpkg executable in PATH (following symlinks), vcpkg/ under HOME,
USERPROFILE or LOCALAPPDATA, then VSINSTALLDIR/VC/vcpkg.
Candidates must contain scripts/buildsystems/vcpkg.cmake; an invalid explicit
root fails instead of silently selecting another installation. The selected root
is printed during configuration. By default nothing is downloaded by discovery.
BOILERPLATE_VCPKG_BOOTSTRAP=ON instead provisions a pinned checkout when no
explicit root/toolchain is supplied. The revision comes from the manifest
builtin-baseline or BOILERPLATE_VCPKG_REVISION (a full Git commit). Managed
checkouts live in BOILERPLATE_VCPKG_CACHE (default <build>/_deps), are locked
while provisioning and reused offline. BOILERPLATE_VCPKG_REPOSITORY accepts a
local mirror. The official vcpkg toolchain bootstraps its executable and installs
manifest features. Applications must set VCPKG_MANIFEST_FEATURES before
project() and opt into bootstrap; dependency-free builds never call it.
Use a fresh build directory when
switching an already cached toolchain.
Project capabilities own project lifecycle and workflows, not target compile/link
semantics. They compose independently from POLICIES and have configure/finalize hooks:
boilerplate_project(
TOP_LEVEL_CAPABILITIES developer docs
EMBEDDED_CAPABILITIES project-minimal)
# targets are registered here
boilerplate_finalize_project() # analysis/docs/package/diagnostic finalizers see the complete graphPrimitive capabilities: project-minimal, compile-commands, compiler-cache,
formatting, static-analysis, testing, property-testing, fuzzing, coverage-report, docs,
packaging, reproducible-build, build-info, diagnostics, cuda, and
web-deployment. Convenience compositions are developer, quality, distribution,
ci, and full; they are only named lists, not mutually exclusive rails.
developer gives compile commands, optional compiler cache, format/analyze workflows,
CTest, build metadata and diagnostics. Missing optional developer tools are skipped unless
BOILERPLATE_REQUIRE_PROJECT_TOOLS=ON. distribution adds reproducible source-path
mapping, build metadata and component-aware CPack packaging. build-info exposes both
build-info-<config>.json and boilerplate::build_info / <boilerplate/build_info.hpp>.
Bootstrap concerns that must precede project() stay separate. Bootstrap.cmake rejects
in-source builds and can discover an installed vcpkg toolchain; it deliberately does
not choose a compiler/generator. Embedded mode defaults to project-minimal, so consuming
a library with add_subdirectory() does not acquire the parent's docs, analysis, packaging,
fuzzing or developer workflows.
Instrumentation and workflows are deliberately split: target policy coverage adds
compiler/linker instrumentation, while project capability coverage-report creates the
CTest/lcov report pipeline. Likewise Qt/graphics/runtime remain target policies; packaging
is project lifecycle. boilerplate_enable_qt_deployment(target) attaches Qt's native deploy
script when available.
PCH and shaders remain explicit source-aware helpers instead of artificial
boolean capabilities; unity builds are a target policy.
Components are an optional grouping layer, not another project lifecycle. A large
monorepo still calls boilerplate_project() once, configures many component subtrees,
and calls boilerplate_finalize_project() once. Small projects can keep ordinary
add_subdirectory() and do not pay for or learn this layer.
boilerplate_project(CAPABILITIES developer)
boilerplate_add_component(core
SOURCE_DIR libs/core
FOLDER "components/core")
boilerplate_add_component(network
SOURCE_DIR libs/network
FOLDER "components/network")
boilerplate_add_component(server
SOURCE_DIR apps/server
FOLDER "components/apps/server")
boilerplate_finalize_project()Targets created by the framework inside a component are registered automatically and
receive BOILERPLATE_COMPONENT. FOLDER supplies IDE grouping for Visual Studio and
other folder-aware generators. boilerplate_list_components() and
boilerplate_component_targets() expose the registry to diagnostics or project-local
tooling. A raw add_library() / add_executable() remains an escape hatch; call
boilerplate_register_target(target [COMPONENT name]) when a raw target should join the
component ownership registry. Project-wide finalizers still see the complete CMake graph,
including unregistered escape-hatch targets; once finalization begins that graph is frozen
and its recursive target walk is cached for subsequent analysis/diagnostic hooks.
A component that must also build standalone owns a lifecycle only when it is the CMake root:
cmake_minimum_required(VERSION 3.26)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
project(Storage VERSION 1.0 LANGUAGES CXX)
include(cmake/Boilerplate.cmake)
boilerplate_project(CAPABILITIES developer)
boilerplate_component(storage FOLDER "components/storage")
endif()
boilerplate_add_library(storage ...)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
boilerplate_finalize_project()
endif()When embedded through boilerplate_add_component(storage SOURCE_DIR libs/storage), the
parent lifecycle is reused and the component identity is inherited by the whole subtree.
This keeps the scale model one workspace lifecycle -> many components -> many targets
instead of creating a second capability/hook engine per directory.
Project presets choose the toolchain/configuration and provide defaults. Targets are
the composition unit. POLICIES can reset or layer build capabilities without
creating a preset for every combination:
# Small std-only denominator even inside a heavily tuned parent build.
boilerplate_add_library(core
SOURCES src/core.cpp INCLUDE_DIR include
POLICIES minimal)
# Built-in runtime archetypes are already compositions of orthogonal pieces.
boilerplate_add_library(runtime_core
SOURCES src/runtime.cpp INCLUDE_DIR include
POLICIES runtime-dagflow)
# Capabilities remain composable: Qt/graphics do not reset runtime tuning.
boilerplate_add_executable(inspector
SOURCES tools/inspector.cpp
POLICIES runtime-dagflow qt-widgets)Policies compose left-to-right. POLICY_OPTIONS KEY value ... is the final per-target
override. Policy hooks are the extension point for non-flag mechanics. Built-ins now include
runtime-dagflow, runtime-webserver, diagnostic runtime policies, Qt6 capability
policies, and Vulkan/GLFW/GLEW/GLM/ImGui capability policies. Shader compilation is
an explicit source-aware helper. See lib/README.md
for the full composition model.
Control-flow policies are also reusable: cfi, cfi-icall, cfi-vcall and
windows-cfg. runtime-hardened composes runtime, hardening and cfi.
For example, POLICIES runtime-hardened enables Clang CFI with ThinLTO/lld on Linux;
Windows uses POLICIES runtime hardening windows-cfg. CFI traps by default;
POLICY_OPTIONS CFI_DIAGNOSTICS ON enables fatal diagnostics. The backend validates
the compiler and link requirements during configuration. See the
control-flow API and DLL/plugin limits.
cmake --preset app-debug
cmake --build --preset app-debug --target boilerplate_check_control_flowThe reusable testing layer now separates RapidCheck property tests, byte-oriented
LLVMFuzzerTestOneInput fuzzing (libFuzzer/AFL++/honggfuzz), and Google FuzzTest.
See lib/README.md for the helper API,
compiler-wrapper requirements and vcpkg pbt feature.
The app-qt-debug and app-qt-release presets build the Qt 6 Widgets example
with matching configure, build, test and workflow presets:
cmake --workflow --preset app-qt-debug
# Equivalent individual steps:
cmake --preset app-qt-release
cmake --build --preset app-qt-release --parallel 4
ctest --preset app-qt-release
# Launch the window on a desktop:
./out/build/app-qt-release/examples/qt/qt_widgets_exampleInstall Qt 6 Core/Gui/Widgets development packages and tools. For a separate Qt
SDK, pass -DCMAKE_PREFIX_PATH=/path/to/Qt/6.x/platform on configuration.
The example uses the qt-widgets target policy and exercises AUTOMOC, AUTOUIC
and AUTORCC. Its smoke test uses QT_QPA_PLATFORM=offscreen and exits automatically,
so CTest requires no display server. Ordinary presets keep the Qt example disabled.
QML/Quick applications can use the existing qt-qml-app policy on their targets;
these two presets select the Widgets example.
CUDA targets use cuda, cuda-debug, cuda-profiled, cuda-fast-math, or the
runtime-cuda composition after enabling the cuda project capability.
The app-cuda-debug and app-cuda-release presets enable that capability with
Debug/Release configuration and provide matching build, test and workflow presets:
cmake --workflow --preset app-cuda-release
# Or configure explicitly (choose architectures for your deployment):
cmake --preset app-cuda-debug -DBOILERPLATE_CUDA_ARCHITECTURES=75
cmake --build --preset app-cuda-debug --parallel 4
ctest --preset app-cuda-debug
cmake --build --preset app-cuda-debug --target boilerplate_check_cudaThese presets require NVIDIA nvcc and default to native GPU architectures.
Without a working GPU/driver, override the architecture as above. CUDA policies
are still selected per target; the Debug preset alone does not enable device
debugging (cuda-debug). The sample application remains CPU-only; the explicit
boilerplate_check_cuda target builds the CUDA fixtures.
See CUDA profiles and checks for device architectures,
runtime linkage, compatibility limits and a real nvcc regression check.
Shader helpers support GLSL/SPIR-V and HLSL/DXC, named variants and transitive
include dependencies. The full application layer is semantic rather than CMake-type
driven: boilerplate_add_application() creates a hosted application image,
boilerplate_add_runtime() creates a private linkable runtime image, and
boilerplate_add_plugin() creates a runtime-loaded extension. HOST is an
orthogonal execution role: create one with boilerplate_add_host() and attach a
typed edge with boilerplate_host_application() or boilerplate_host_plugin().
The compatibility helper boilerplate_add_apphost() remains sugar for the common
application case.
Plugin composition and plugin placement are deliberately separate. An
APPLICATION -> PLUGIN edge says that the plugin belongs to the application's
extension set. With no explicit plugin host it follows the application's hosts
(the normal in-process/co-hosted case); a HOST -> PLUGIN edge gives it explicit
execution placement, for example a dedicated sandbox/plugin process. The framework
deploys the resulting topology but does not impose a universal plugin callback ABI:
the application/runtime or custom plugin host owns loading and negotiation.
Ordinary boilerplate_add_library() targets stay consumer-facing and belong to the
standalone core slice; boilerplate_add_executable() remains available for genuine
standalone tools. boilerplate_install_application() deploys from the application
root into a private module graph (bin/, lib/<app>/, lib/<app>/plugins/,
share/<app>/), while boilerplate_install_host() supports standalone/custom host
roots such as plugin hosts. See the delivery API and the
boilerplate_check_execution_model regression target.
BOILERPLATE_PROFILE is the project/configuration default; target policies may override its optimization choices.
BOILERPLATE_PROFILE: custom, debug, relwithdebinfo, release, lto
(ThinLTO), full-lto, native-thinlto, native-full-lto, o3 (release + symbols),
o3-lto, pgo-generate, pgo-use, lto-pgo-generate, lto-pgo-use,
native-full-lto-pgo-generate, native-full-lto-pgo-use.
Individual knobs remain available: BOILERPLATE_LTO_MODE=none|thin|full,
BOILERPLATE_ENABLE_NATIVE, BOILERPLATE_DEBUG_SYMBOLS,
BOILERPLATE_ENABLE_NO_SEMANTIC_INTERPOSITION, BOILERPLATE_ENABLE_NO_PLT,
BOILERPLATE_ENABLE_GC_SECTIONS, BOILERPLATE_USE_LLD, BOILERPLATE_ENABLE_ICF,
BOILERPLATE_ARTIFACT_SUFFIX. ELF-specific switches are applied only on Linux.
BOILERPLATE_SANITIZER=none|address|undefined|address-undefined|thread|leak.
Useful presets: lib-static, lib-shared, lib-aggressive (native Full LTO,
section GC, no-PLT, no semantic interposition, lld/ICF), lib-address-undefined,
lib-thread, app-asan, app-tsan, app-hardening, app-coverage, app-fuzz.
Named profiles own build type/LTO/PGO and select the corresponding configuration
for both single-config and multi-config generators. With Visual Studio or Ninja
Multi-Config, pass the matching --config. Use custom to retain several configs.
Requested GNU-style optimization/instrumentation flags are compile-and-link
probed, including required runtimes. LTO tries the system linker first and can
fall back to LLD after a successful probe; ARM native optimization uses -mcpu.
Unsupported explicit policies fail at configure time.
Native profiles target the build CPU; use ordinary release for portable distribution.
MSVC supports ordinary builds/full IPO; GNU-style Clang is required for ThinLTO
and the supplied PGO/fuzzer profiles. Unsupported combinations fail at configure time.
For repeatable runtime/server experiments, lib/cmake/benchmark/Harness.cmake exposes a
self-contained CMake process harness shipped inside the reusable lib/cmake/ tree.
Running the harness does not require Python.
boilerplate_add_harness(runtime_matrix
TARGET runtime_bench
CASES "${CMAKE_CURRENT_SOURCE_DIR}/bench/cases.json"
ROUNDS 9 WARMUP_RUNS 2 TIMEOUT 120
AFFINITY physical RANDOMIZE
METRICS run_p50_us payload_tasks_per_second
INVARIANTS checksum)The generic runner owns subprocess lifecycle, process-group timeout/kill, CPU topology
and affinity, SHA256 provenance, raw logs, randomized rounds, JSON metric summaries,
invariant checks and optional Linux perf stat parsing. Domain semantics stay in the
project adapter/cases file. See the
harness guide and
CMake module map.
Both can be enabled together:
# Uses installed benchmark package. Add the last switch to permit downloading it.
cmake --preset lib-bench-both -DBOILERPLATE_FETCH_DEPENDENCIES=ON
cmake --build --preset lib-bench-both --parallel 4
ctest --preset lib-bench-bothNormal builds never execute measurements. CTest runs small correctness cases and Google Benchmark registration listing. Explicit measurement commands:
cmake --build --preset lib-bench-both --target run_sum_small
cmake --build --preset lib-bench-both --target run_library1_google_bench
cmake --build --preset lib-bench-both --target run_group_customboilerplate_benchmarks builds all enabled benchmarks; benchmarks_custom and
benchmarks_google build individual groups. A run_group_* executes its scenarios
sequentially even with --parallel; running one scenario does not run its siblings.
Independent groups/manual invocations can still overlap; avoid that for comparisons.
Select a group with -DBOILERPLATE_BENCHMARK_GROUPS=custom or disable a binary with
-DBOILERPLATE_BUILD_LIBRARY1_GOOGLE_BENCH=OFF; this also avoids finding Google Benchmark.
The process harness accepts any executable. Knobs:
BOILERPLATE_RUN_REPEATS=5, BOILERPLATE_RUN_WARMUP=1,
BOILERPLATE_RUN_TIMEOUT=60, BOILERPLATE_RESULTS_DIR,
BOILERPLATE_<SCENARIO>_ARGS (CMake argument list), BOILERPLATE_COMMAND_PREFIX.
Example Linux prefix: '-DBOILERPLATE_COMMAND_PREFIX=taskset;-c;2' or
'-DBOILERPLATE_COMMAND_PREFIX=perf;stat;--'. Tools are supplied by the caller;
CMake does not change CPU governor, affinity or privileges automatically.
Each run creates a unique result directory with stdout/stderr per invocation, exit/timeout status, arguments, executable SHA256, source revision when available, profile/compiler settings and min/median/mean/p95 in microseconds. Environment variable names are recorded, not their values. The timer is CMake wall time for the entire subprocess, including startup; warmups launch separate processes. Use it for end-to-end workloads. Short timings and wall-clock adjustments are not a basis for microbenchmark claims. Failed runs fail the target and retain logs.
Google Benchmark provides
in-process timing, repetitions and JSON/CSV reporting. Its example runs once through
the process wrapper and uses its own repetitions; its native JSON is under
results/google/ (same target/config overwrites that native file on another run).
The independent process wrapper logs remain unique. The sample uses
DoNotOptimize; replace its operation with your workload. Fallback versions are
pinned to Google Benchmark v1.9.5 and GoogleTest v1.17.0 and can be overridden via
BOILERPLATE_GOOGLE_BENCHMARK_TAG / BOILERPLATE_GOOGLETEST_TAG.
Offline checkouts work through standard FETCHCONTENT_SOURCE_DIR_GOOGLEBENCHMARK
and FETCHCONTENT_SOURCE_DIR_GOOGLETEST overrides with fetching enabled.
cmake --workflow --preset app-google-tests
cmake --build --preset app-debug --target boilerplate_check
ctest --preset app-debug -L smoke
ctest --preset app-google-tests -L google
cmake --preset app-fuzz
cmake --build --preset app-fuzz
ctest --preset app-fuzz -L fuzz # bounded -runs=1 smoke
# Explicit longer fuzzing:
cmake --build --preset app-fuzz --target fuzz_fuzz_targetPlain checks return nonzero on failure (work with NDEBUG). GoogleTest uses CMake's
GoogleTest discovery module. libFuzzer uses Clang's sanitizer runtime, keeps corpus
under the build tree and has bounded explicit run targets. To fuzz a linked library,
build a separate instrumented archive with boilerplate_add_fuzz_library() and
link it into boilerplate_add_fuzzer(). The normal library stays separate;
instrumenting the fuzz entry alone does not cover compiled dependencies. Sanitizer smoke validation in restricted
ptrace environments may need ASAN_OPTIONS=detect_leaks=0; this disables leak
checking only for that invocation, not in the presets.
Documentation is generated directly by CMake's doxygen_add_docs() in
lib/cmake/project/Documentation.cmake; Python is not required. CMake generates
the Doxyfile in the build directory. Install Doxygen and optionally Graphviz
(dot) for diagrams, then run:
cmake -S . -B out/build/docs -G Ninja -DBUILD_DOCS=ON
cmake --build out/build/docs --target docsOpen out/build/docs/html/index.html. The documentation includes the project
guides and the public proj, lib1 and lib2 APIs, with parameters, return
values, integer-overflow preconditions and worker-thread behavior. Tests,
benchmarks and generated build trees are excluded from the API inputs.
BOILERPLATE_DOC_INPUTS overrides the input paths. Doxygen warnings fail the
docs target by default; BOILERPLATE_DOC_WARN_AS_ERROR=OFF makes them nonfatal.
Generation does not require compiling the application or downloading packages.
cmake --preset lib-native-full-lto-pgo-generate
cmake --build --preset lib-native-full-lto-pgo-generate --target boilerplate_pgo_merge
cmake --preset lib-native-full-lto-pgo-use
cmake --build --preset lib-native-full-lto-pgo-use
ctest --preset lib-native-full-lto-pgo-useTraining is explicit. boilerplate_pgo_train trains; boilerplate_pgo_merge_only
merges existing profiles; boilerplate_pgo_merge does both. Register realistic
bounded training via boilerplate_pgo_workload or scenario PGO_ARGS.
BOILERPLATE_PGO_DIR, BOILERPLATE_PGO_MERGED_PROFILE, BOILERPLATE_PGO_PROFILE,
BOILERPLATE_LLVM_PROFDATA control paths/tools. Updated profiles invalidate object
files, including later target_sources() additions in their target directory.
Use fresh raw profile directories after changing code. GCC manual PGO uses the same
build/object paths for generate/use, with no LLVM merge step.
cmake '-DPRESETS=app-debug;app-release;lib-static;lib-shared' -DJOBS=4 \
-P lib/cmake/build/BuildMatrix.cmake
# Or the thin shell/PowerShell wrapper:
./build_all.sh '-DPRESETS=app-debug;app-release' -DJOBS=4build_all.sh defaults to MATRIX_PROFILE=all: core debug/release plus app-vcpkg-all. It discovers vcpkg automatically; set VCPKG_ROOT to override or use -DMATRIX_PROFILE=core to skip package-manager coverage.
The matrix configures, builds, tests and installs each preset to
out/artifacts/<preset>. Set ARTIFACT_DIR, RUN_TESTS=OFF,
INSTALL_ARTIFACTS=OFF, or CONFIGURE_ARGS as needed. CMake install handles native
filenames/symlinks/export packages; there is no filename globbing for a specific
project. Packages include share/<project>/build-info-<config>.json with public
build settings and source revision/dirty state at configuration time.
For a Clang PGO pair, list generate before use and add -DTRAIN_PGO=ON explicitly.
Without it the matrix never trains; a fresh use preset fails without its profile.
Workflow presets use native cmake --workflow for one configure/build/test chain.
Examples are first-class executable workloads rather than a separate build model:
boilerplate_add_example(allocator_example
SOURCES examples/allocator.cpp
SMOKE
PGO
LABELS allocator)The helper creates the executable, adds it to boilerplate_examples, registers
run_<name> and the shared run_group_examples scenario target, and optionally
adds a bounded CTest smoke check and PGO workload. Building examples never runs
them implicitly.
cmake --preset app-examples -DBOILERPLATE_ALLOCATOR=mimalloc
cmake --build --preset app-examples --target boilerplate_examples
cmake --build --preset app-examples --target run_allocator_example
cmake --build --preset app-examples --target run_group_examples
ctest --preset app-examples -L allocatorsystem, mimalloc, tbbmalloc select an explicit allocation adapter.
boilerplate_use_allocator(target) links the selected dependency and defines
BOILERPLATE_USE_MIMALLOC / BOILERPLATE_USE_TBBMALLOC. The example shows matching
allocation/free calls. This does not globally replace malloc/new. Libraries using
such dependencies must also expose the appropriate installed find_dependency().
For an old version or another implementation:
cmake --preset app-debug -DBOILERPLATE_REFERENCE_SOURCE_DIR=/path/to/reference \
'-DBOILERPLATE_REFERENCE_CMAKE_ARGS=-DCMAKE_BUILD_TYPE=Release;-DBUILD_TESTING=OFF'
cmake --build --preset app-debug --target referenceThis uses CMake ExternalProject with a separate cache and target namespace.
Reference builds are excluded from ALL; sources are explicit and not downloaded.
The API also supports explicit reference tests/installation. The project's adapter
must provide comparable workloads; CMake cannot infer equivalent APIs or settings.
For two successful process-harness outputs with matching scenario/arguments:
cmake -DBASELINE=/path/before/result.json -DCANDIDATE=/path/after/result.json \
-DMAX_REGRESSION_PERCENT=10 -P lib/cmake/benchmark/CompareResults.cmakeThis compares median end-to-end time; the threshold is optional and must account for
noise. Google Benchmark results use its official tools/compare.py through
boilerplate_add_google_comparison() (API); Python and upstream
Python requirements are needed only for that optional comparison tool. Build policy,
process harness, matrix and simple comparison are implemented in CMake.
Docker is deliberately outside the CMake capability graph. Two independent Dockerfiles serve deployment and development:
Dockerfile:build,test, andruntimestages consume the public CMake presets/install rules. The build stage provides GCC/Clang/CMake/Ninja and packaging prerequisites; the runtime image contains the installed application and runtime libraries..devcontainer/Dockerfile: thedevstage provides the development toolchain, debuggers, analysis, coverage, and AFL++ tools. Thedevcontainerstage adds the non-root VS Code user, LLVM/Rust editor tooling, and zsh. It can be built independently of the deployment image.
Both default to debian:trixie-slim, keeping build and runtime on the same glibc
family. Override DEBIAN_IMAGE at Docker build time if another Debian 13-compatible
base is desired. Optional presets may require adding their dependencies to the
corresponding Dockerfile.
Native Bash and PowerShell wrappers keep common container commands short. The host only needs Bash or PowerShell and Docker (or Podman); CMake and compiler tools run inside the image.
bash tools/container.sh dev
bash tools/container.sh dev --base-image debian:trixie-slim
bash tools/container.sh shell
bash tools/container.sh test --preset app-release
bash tools/container.sh build --preset app-release
bash tools/container.sh run --no-build -- --example "argument with spaces"
bash tools/container.sh cleanPowerShell uses native parameter names:
./tools/container.ps1 dev
./tools/container.ps1 test -Preset app-release
./tools/container.ps1 shell -NoBuild
./tools/container.ps1 run -NoBuild -AppArgs @('--example', 'argument with spaces')
./tools/container.ps1 cleanBoth wrappers support an image name (--image / -Image), an engine executable
(--docker / -Docker), and build flags (--pull / -Pull, --no-cache / -NoCache).
The default image name is cmake-boilerplate; the devcontainer and test
stages use its :dev/:test tags. shell and run build their image
first unless --no-build / -NoBuild is set.
clean removes these three local image tags. Engine failures return a nonzero exit code.
build, test, and run use the root Dockerfile; dev and shell build
the full devcontainer stage of .devcontainer/Dockerfile (including Rust and zsh).
Compose uses the same split for its app and dev services, with a dedicated
dev-out volume for container-only build artifacts. shell starts zsh by default
(pass --shell bash / -Shell bash to override). For deployment/test images,
--preset is forwarded as CMAKE_PRESET. Use another preset when the image
contains the corresponding toolchain/dependencies. .dockerignore
keeps host build trees, profiles and a local vcpkg checkout out of the context. Docker
is optional; no configure/build/test target requires a Docker daemon.
Install Docker and the VS Code Dev Containers extension
(ms-vscode-remote.remote-containers). Open this repository's root folder (or a
generated project's root) in VS Code, then run Dev Containers: Reopen in
Container from the Command Palette. See the
VS Code setup guide
for host prerequisites.
The checked-in .devcontainer/devcontainer.json builds the devcontainer stage
of .devcontainer/Dockerfile. It runs as vscode with Clang/Clang++, LLD, clangd,
clang-tidy, clang-format, and LLDB. VS Code installs CMake Tools, clangd, CodeLLDB,
and rust-analyzer. Clangd provides C/C++ completion, formatting, and clang-tidy
diagnostics using the repository's existing configuration.
Creation configures app-debug with Clang and LLD, refreshing its container-only
CMake cache to replace older GCC selections. CMake Tools copies the active
configuration's compile commands to out/compile_commands.json for clangd.
After configuring a different preset manually, copy its compile_commands.json
there too, or configure through CMake Tools. Use CMake: Debug on the selected
target to launch CodeLLDB; Rust's debug code lenses use the same debugger.
Stable Rust is installed through rustup with Cargo, Clippy, rustfmt, and rust-src.
The Docker build argument RUST_TOOLCHAIN can select a specific toolchain.
Rust-analyzer uses Clippy for checks; the CMake framework's rust capability
remains opt-in. For a crate outside the opened workspace root, use rust-analyzer's
linkedProjects setting to select its Cargo.toml.
The default terminal is zsh with history, completion, autosuggestions, syntax
highlighting, fzf history/file search, and zoxide's z navigation. The small
.devcontainer/zshrc includes navigation/Git aliases and a plain prompt, with
no plugin managers, startup downloads, host paths, or replacements for cd/cat.
Customize that file and rebuild to change the container's shell defaults.
On Linux, Dev Containers aligns the user's UID/GID with the host. The first image
build and extension installation require network access.
From the container terminal:
cmake --build --preset app-debug --parallel 2
ctest --preset app-debug --output-on-failure
cmake --build --preset app-debug --target boilerplate_runFor editor build/debug commands, use CMake: Select Configure Preset to select
app-debug. Choose another checked-in preset when needed. Builds and tests run
on demand; opening the container only configures the initial build.
Sources are mounted at /workspace. A persistent volume specific to this Dev
Container stores /workspace/out, keeping container CMake caches separate from
host builds. The creation command sets ownership of that volume before configuring;
host out/ contents are hidden inside the container. Standalone builds from lib/
use lib/out/ and are outside this volume.
The project initializer includes both Dockerfiles and the Dev Container configuration.
Debugging uses SYS_PTRACE and an unconfined seccomp profile for LLDB; this
additional privilege applies to the development container, not the
deployment image. Use a trusted codebase and Docker host.
After changing .devcontainer/, run Dev Containers: Rebuild Container. The default image
provides LLVM and stable Rust; nightly Rust sanitizers/fuzzing, CUDA, Qt, and
cross-compilation workflows still require their documented tools.
boilerplate_check_cmake builds a differently named generic fixture, tests installed
shared/static packages after relocation, checks late PGO source dependencies, configures
a 128-component workspace regression, and then runs the two intentionally different
example-library package/relocation consumers.
boilerplate_harness_checks covers quoted arguments, environment, cwd, warmups,
repetitions, JSON output, process failures and timeout propagation.
Linux/Clang/GCC are exercised locally. Windows/macOS paths and custom multi-config
builds are supported by design; they still need native platform CI before claiming
platform validation. Docs, packaging and the external container workflow remain optional.
build_all.* validates the manifest builtin-baseline against the Git checkout at
the resolved vcpkg root before configuring a vcpkg preset. A shallow or stale checkout is
reported with a concrete git fetch repair command instead of failing later from
inside vcpkg.cmake.
library1 and library2 also have portable, versioned release ports in the
repository's Git registry: pinned source commit + SHA512, versions/baseline.json,
and per-version git-tree entries. An independent project installs them with
vcpkg and links library1::library1 / library2::library2 through find_package().
See registry consumption, CI and release instructions.
The library boilerplate can generate local or archive-backed overlay ports with
boilerplate_vcpkg_port(), including triplet-controlled shared/static builds and
CMake package fixups. See vcpkg packaging
for the API and ready-to-install library1 / library2 examples.
Project-owned overlays live in vcpkg/ports/ and vcpkg/triplets/, registered by
vcpkg-configuration.json. Existing vcpkg presets pick them up through the root
manifest; vcpkg-linux-shared demonstrates the custom Linux shared triplet.
See the overlay layout and commands.
After extracting the template, use one entry point for host preparation, configure,
compile, tests and platform packages (no Python, no separate cpack command):
./setup.sh --package # Linux/macOS
./setup.sh --init NewApp --package # create + package in one command
./setup.sh --package --package-format TGZ # request a specific CPack format.\setup.ps1 -Package # Windows
.\setup.ps1 -Init NewApp -Package # create + package in one commandPackages land under out/packages/<preset>/. --install-artifacts is separate:
packaging stages install() rules into the package, not the user's system.
Default formats: Linux TGZ plus DEB/RPM when their native tools are present;
Windows ZIP plus NSIS when makensis is present; macOS TGZ plus DMG when
hdiutil is present. --package selects the package host-tools profile by
default, which provisions supported native packagers and deployment tools. The
--package-format option forces one generator; unavailable tools then cause a
clear failure instead of a silent format downgrade. Signing/notarization of
installers is deliberately a separate release step.
Use ./setup-host.sh --install --profile dev on Linux/macOS or
./setup-host.ps1 -Install -Profile dev on Windows to install missing build,
editor, analysis, formatting, documentation and packaging tools plus vcpkg. Activate
out/host-tools/env.sh (Unix) or out/host-tools/env.ps1 (PowerShell) afterwards.
The installers use only Bash/PowerShell; there is no Python, pip or venv bootstrap.
--dry-run / -DryRun shows commands; --check / -Check reports missing tools.
Profiles minimal, dev (default), and ci share one tool matrix. Every run reports
what was already available, what was installed and what is still missing.
The same entry points are available under scripts/.
The benchmark/process harness runs in CMake; bootstrap does not check Python.
See host setup for package managers, the tool matrix and
separately provisioned Python/SDK workflows.
flowchart LR
subgraph Build["Build artifacts"]
APP["TEST_PROJECT"]
L1["library1_shared"]
L2["library2_shared"]
L1S["library1_shared_smoke"]
L2S["library2_shared_smoke"]
AC["application_checks"]
APP --> L1
APP --> L2
L1S --> L1
L2S --> L2
end
subgraph Testing["Testing"]
CHECK["check"]
BCHECK["boilerplate_check"]
BTESTS["boilerplate_tests"]
CHECK --> BCHECK
BCHECK --> BTESTS
BTESTS --> APP
BTESTS --> AC
BTESTS --> L1S
BTESTS --> L2S
end
subgraph Regression["Infrastructure regressions"]
FULL["boilerplate_check_full"]
CMAKE["boilerplate_check_cmake"]
EXEC["boilerplate_check_execution_model"]
DELIVERY["boilerplate_check_delivery"]
CUDA["boilerplate_check_cuda"]
SHADERS["boilerplate_check_shaders"]
FLOW["boilerplate_check_control_flow"]
FULL --> CMAKE
FULL --> EXEC
FULL --> DELIVERY
end
subgraph Infrastructure["Project infrastructure"]
CONFIG["boilerplate_config"]
BUILDINFO["boilerplate_build_info<br/>INTERFACE"]
end
flowchart TB
FULL["full"]
DEV["developer"]
QUALITY["quality"]
DIST["distribution"]
CI["ci"]
FULL --> DEV
FULL --> QUALITY
FULL --> DOCS
FULL --> DIST
DEV --> COMPILE["compile-commands"]
DEV --> CACHE["compiler-cache"]
DEV --> FORMAT["formatting"]
DEV --> STATIC["static-analysis"]
DEV --> TEST["testing"]
DEV --> BUILDINFO["build-info"]
DEV --> DIAG["diagnostics"]
QUALITY --> TEST
QUALITY --> PROP["property-testing"]
QUALITY --> FUZZ["fuzzing"]
QUALITY --> STATIC
PROP --> TEST
FUZZ --> TEST
COVERAGE["coverage-report"] --> TEST
DIST --> BUILDINFO
DIST --> REPRO["reproducible-build"]
DIST --> PACKAGE["packaging"]
DIST --> DIAG
CI --> COMPILE
CI --> TEST
CI --> STATIC
CI --> BUILDINFO
CI --> DIAG
MIN["project-minimal"]
CUDA["cuda"]
WEB["web-deployment"]
DOCS["docs"]
flowchart LR
subgraph Configure["configure phase"]
CC["compile-commands"]
CACHE["compiler-cache"]
SA["static-analysis"]
TEST["testing"]
REPRO["reproducible-build"]
INFO["build-info"]
CUDA["cuda"]
end
subgraph Targets["project target graph"]
TARGETS["add_library / add_executable / policies / registration"]
end
subgraph Finalize["finalize phase"]
FORMAT["formatting"]
SA2["static-analysis"]
TEST2["testing"]
PROP["property-testing"]
FUZZ["fuzzing"]
COV["coverage-report"]
DOCS["docs"]
PACKAGE["packaging"]
DIAG["diagnostics"]
WEB["web-deployment"]
end
Configure --> TARGETS
TARGETS --> Finalize
./setup.sh --init MyApp --run --package (Windows: ./setup.ps1 -Init MyApp -Run -Package) now creates a project, prepares tools, builds, runs CTest, launches the sample application, and produces packages in out/packages/app-release/ of the new project. Without --init, it packages the current project. No Python is required.
| Host | Automatic output (when native tools are available) | Explicit option |
|---|---|---|
| Debian, Ubuntu and ID_LIKE=debian | .tar.gz, .deb |
--package-format DEB |
| Fedora, RHEL and ID_LIKE=fedora/rhel | .tar.gz, .rpm |
--package-format RPM |
| Arch, CachyOS, Manjaro and ID_LIKE=arch | .tar.gz, .pkg.tar.zst |
--package-format ARCH |
| macOS | .tar.gz, .dmg |
--package-format DragNDrop |
| Windows | .zip, NSIS .exe |
-PackageFormat NSIS |
On Arch the .pkg.tar.zst is built with makepkg, not CPack. Run the bootstrap as a normal user, never root; sudo is used for system dependencies, while makepkg stages cmake --install into its own pkgdir. The build is not repeated. The package tool profile ensures fakeroot, zstd, and makepkg prerequisites are present. Package dependencies/signatures, Windows code signing, and Apple notarization remain release policy owned by the application; the boilerplate does not invent them.
Linux detection reads /etc/os-release (ID, ID_LIKE); installed rpm or dpkg-deb executables do not change the family. If the native tool is missing during a build-only invocation, CPack falls back to TGZ and emits a warning. setup.sh --package installs supported native tooling first. Explicit formats override automatic selection, except that ARCH is only supported on Linux with makepkg. The Bootstrap E2E workflow runs the one-command path on Windows/macOS/Ubuntu and in Fedora/Arch containers, verifies the native artifacts, and uploads them. These checks require an actual CI run to establish portability.