85a0ff93c2
cpp-template / format (ubuntu-22.04) (push) Successful in 57s
cpp-template / format (ubuntu-24.04) (push) Successful in 56s
cpp-template / build-test (asan, ubuntu-22.04) (push) Successful in 1m34s
cpp-template / build-test (asan, ubuntu-24.04) (push) Successful in 1m35s
cpp-template / build-test (debug, ubuntu-22.04) (push) Successful in 1m55s
cpp-template / build-test (debug, ubuntu-24.04) (push) Successful in 1m50s
cpp-template / build-test (fuzz, ubuntu-22.04) (push) Successful in 6m18s
cpp-template / build-test (fuzz, ubuntu-24.04) (push) Successful in 7m0s
cpp-template / build-test (release, ubuntu-22.04) (push) Successful in 1m49s
cpp-template / build-test (release, ubuntu-24.04) (push) Successful in 1m53s
cpp-template / clang-tidy (ubuntu-22.04) (push) Successful in 1m37s
cpp-template / clang-tidy (ubuntu-24.04) (push) Successful in 1m52s
cpp-template / install-consumer (ubuntu-22.04) (push) Successful in 1m41s
cpp-template / install-consumer (ubuntu-24.04) (push) Successful in 1m36s
cpp-template / no-network-negative (ubuntu-22.04) (push) Successful in 6m50s
cpp-template / no-network-negative (ubuntu-24.04) (push) Successful in 7m32s
cpp-template / format (ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (asan, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (debug, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (fuzz, ubuntu-20.04) (push) Has been cancelled
cpp-template / build-test (release, ubuntu-20.04) (push) Has been cancelled
cpp-template / clang-tidy (ubuntu-20.04) (push) Has been cancelled
cpp-template / install-consumer (ubuntu-20.04) (push) Has been cancelled
cpp-template / no-network-negative (ubuntu-20.04) (push) Has been cancelled
479 lines
15 KiB
Markdown
479 lines
15 KiB
Markdown
# 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(<name> 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 automatically link the framework Core runtime defaults: `spdlog::spdlog`, `fmt::fmt`, `nlohmann_json::nlohmann_json`, `toml11::toml11`, `CLI11::CLI11`, `asio::asio`, `concurrentqueue::concurrentqueue`, `ghcFilesystem::ghc_filesystem`, `nonstd::expected-lite`, and `httplib::httplib`. Static/shared libraries receive these defaults as `PUBLIC`, interface libraries as `INTERFACE`, and executable-like targets as `PRIVATE`.
|
|
- Helpers do not acquire lane-specific external dependencies directly. The template infrastructure loads `GTest::gtest`, `benchmark::benchmark`, and `fuzztest::fuzztest` from the committed archive model when the corresponding helper lane is enabled.
|
|
- There are aggregate targets `run_tests` and `run_benchmarks`, but no per-target `run_test_<name>`, `run_benchmark_<name>`, or `run_fuzz_<name>` 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`: ON by default as a capability-gated request; actual fuzz targets are created only for the isolated Clang + C++17 fuzz lane.
|
|
- `CC_ENABLE_ASAN`: OFF by default; adds AddressSanitizer compile/link flags.
|
|
- `CC_WARNINGS_AS_ERRORS`: OFF by default.
|
|
- Uses public lane options only: `CC_ENABLE_TESTING`, `CC_ENABLE_BENCHMARKS`, `CC_ENABLE_FUZZTEST`, and `CC_ENABLE_ASAN`. Users do not need lane `if()` wrappers around `cc_test()`, `cc_benchmark()`, or `cc_fuzz()`.
|
|
- 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(<target>
|
|
TYPE STATIC|SHARED|INTERFACE
|
|
[SRCS <src>...]
|
|
[HDRS <hdr>...]
|
|
[INCS [PUBLIC|PRIVATE|INTERFACE <dir>...]...]
|
|
[DEPS [PUBLIC|PRIVATE|INTERFACE <dep>...]...]
|
|
[DEFINES [PUBLIC|PRIVATE|INTERFACE <define>...]...]
|
|
[OPTIONS <option>...]
|
|
[FEATURES <feature>...]
|
|
[ALIAS <alias>]
|
|
[INSTALL]
|
|
)
|
|
```
|
|
|
|
Required contract:
|
|
|
|
- `TYPE` is mandatory and must be `STATIC`, `SHARED`, or `INTERFACE`.
|
|
- `OBJECT` libraries are not supported by this helper.
|
|
- `TYPE INTERFACE` must not provide `SRCS` or `HDRS`.
|
|
- `INCS`, `DEPS`, and `DEFINES` require explicit visibility for every item.
|
|
- `TYPE INTERFACE` only accepts `INTERFACE` visibility in visibility-grouped arguments.
|
|
- `ALIAS` creates a real build-tree library alias with `add_library(<alias> ALIAS <target>)` and also stores install/export metadata.
|
|
- `INSTALL` only marks the target. Install rules are produced later by `cc_finalize_install()` when install is enabled.
|
|
- Automatically links Core runtime defaults `PUBLIC` for `STATIC`/`SHARED` libraries and `INTERFACE` for `INTERFACE` libraries.
|
|
|
|
Static library example, mirroring the positive helper fixture pattern:
|
|
|
|
```cmake
|
|
include("${CC_PROJECT_ROOT}/cmake/cc_targets.cmake")
|
|
|
|
cc_library(my_static_lib
|
|
TYPE STATIC
|
|
SRCS lib.cpp
|
|
HDRS lib.h
|
|
INCS PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
|
DEPS PUBLIC m
|
|
DEFINES PUBLIC MY_STATIC_BUILD
|
|
OPTIONS -Wall
|
|
FEATURES cxx_std_14
|
|
ALIAS my_static_lib::my_static_lib
|
|
INSTALL
|
|
)
|
|
```
|
|
|
|
Interface library example:
|
|
|
|
```cmake
|
|
cc_library(my_headers
|
|
TYPE INTERFACE
|
|
INCS INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
DEFINES INTERFACE MY_HEADERS_ONLY=1
|
|
FEATURES cxx_std_14
|
|
)
|
|
```
|
|
|
|
## `cc_executable()`
|
|
|
|
Signature:
|
|
|
|
```cmake
|
|
cc_executable(<target>
|
|
[SRCS <src>...]
|
|
[HDRS <hdr>...]
|
|
[INCS [PUBLIC|PRIVATE <dir>...]...]
|
|
[DEPS [PUBLIC|PRIVATE <dep>...]...]
|
|
[DEFINES [PUBLIC|PRIVATE <define>...]...]
|
|
[OPTIONS <option>...]
|
|
[FEATURES <feature>...]
|
|
[ALIAS <alias>]
|
|
[INSTALL]
|
|
)
|
|
```
|
|
|
|
Behavior:
|
|
|
|
- Creates an executable target. `SRCS` may be omitted, producing an initially empty executable target.
|
|
- Applies `OPTIONS` and `FEATURES` privately.
|
|
- Rejects `INTERFACE` visibility in `INCS`, `DEPS`, and `DEFINES`.
|
|
- `ALIAS` is install/export metadata only. CMake does not support `add_executable(<alias> ALIAS ...)`, so no build-tree executable alias is created.
|
|
- `INSTALL` marks the target for later install/export finalization.
|
|
- Automatically links Core runtime defaults `PRIVATE`.
|
|
|
|
Example:
|
|
|
|
```cmake
|
|
include("${CC_PROJECT_ROOT}/cmake/cc_targets.cmake")
|
|
|
|
cc_executable(hello_exe
|
|
SRCS main.cpp
|
|
DEPS PRIVATE my_static_lib
|
|
OPTIONS -Wall
|
|
FEATURES cxx_std_14
|
|
)
|
|
```
|
|
|
|
Installable executable example:
|
|
|
|
```cmake
|
|
cc_executable(my_tool
|
|
SRCS main.cpp
|
|
ALIAS my_ns::my_tool
|
|
INSTALL
|
|
)
|
|
```
|
|
|
|
## `cc_test()`
|
|
|
|
Signature:
|
|
|
|
```cmake
|
|
cc_test(<target>
|
|
[NO_MAIN]
|
|
SRCS <src>...
|
|
[HDRS <hdr>...]
|
|
[INCS [PUBLIC|PRIVATE <dir>...]...]
|
|
[DEPS [PUBLIC|PRIVATE <dep>...]...]
|
|
[DEFINES [PUBLIC|PRIVATE <define>...]...]
|
|
[OPTIONS <option>...]
|
|
[FEATURES <feature>...]
|
|
[ARGS <arg>...]
|
|
)
|
|
```
|
|
|
|
Behavior:
|
|
|
|
- When `CC_ENABLE_TESTING` is OFF, logs a status message and returns without creating a target.
|
|
- Requires `GTest::gtest` when target creation is enabled.
|
|
- Requires non-empty `SRCS`.
|
|
- Registers `add_test(NAME <target> COMMAND <target> [<ARGS>...])`.
|
|
- Adds the test executable as a dependency of `run_tests` when that aggregate target exists.
|
|
- Without `NO_MAIN`, links `GTest::gtest_main` and `GTest::gmock`, which implies `GTest::gtest`.
|
|
- With `NO_MAIN`, links `GTest::gtest` and `GTest::gmock`; use this when the test source or another dependency supplies `main()`.
|
|
- `GTest::gmock` is linked by default; listing it in `DEPS` is unnecessary but harmless.
|
|
- `GTest::gmock_main` requires `NO_MAIN`; the helper rejects it otherwise because it conflicts with default `GTest::gtest_main`.
|
|
- Automatically links Core runtime defaults `PRIVATE`.
|
|
Basic example:
|
|
|
|
```cmake
|
|
include("${CC_PROJECT_ROOT}/cmake/cc_project.cmake")
|
|
include("${CC_PROJECT_ROOT}/cmake/cc_targets.cmake")
|
|
include("${CC_PROJECT_ROOT}/cmake/cc_testing.cmake")
|
|
|
|
cc_project()
|
|
cc_test(calc_test
|
|
SRCS calc_test.cpp
|
|
DEPS PRIVATE calc
|
|
ARGS --gtest_filter=CalcTest.*
|
|
)
|
|
```
|
|
|
|
GMock custom-main example, mirroring the positive helper fixture pattern:
|
|
|
|
```cmake
|
|
cc_test(mock_test
|
|
SRCS test_mock.cpp
|
|
NO_MAIN
|
|
DEPS PRIVATE my_mock_framework
|
|
)
|
|
```
|
|
|
|
## `cc_benchmark()`
|
|
|
|
Signature:
|
|
|
|
```cmake
|
|
cc_benchmark(<target>
|
|
[NO_MAIN]
|
|
SRCS <src>...
|
|
[HDRS <hdr>...]
|
|
[INCS [PUBLIC|PRIVATE <dir>...]...]
|
|
[DEPS [PUBLIC|PRIVATE <dep>...]...]
|
|
[DEFINES [PUBLIC|PRIVATE <define>...]...]
|
|
[OPTIONS <option>...]
|
|
[FEATURES <feature>...]
|
|
[ARGS <arg>...]
|
|
)
|
|
```
|
|
|
|
Behavior:
|
|
|
|
- When `CC_ENABLE_BENCHMARKS` is OFF, logs a status message and returns without creating a target.
|
|
- Requires `benchmark::benchmark` when target creation is enabled.
|
|
- Without `NO_MAIN`, also requires and links `benchmark::benchmark_main`.
|
|
- With `NO_MAIN`, links `benchmark::benchmark` only; use this when the benchmark source provides `main()`.
|
|
- Requires non-empty `SRCS`.
|
|
- Does not register the benchmark with default CTest.
|
|
- Adds the benchmark target as a dependency of `run_benchmarks` when that aggregate target exists.
|
|
- Adds a `POST_BUILD` command to `run_benchmarks` that directly executes the benchmark binary with `ARGS`.
|
|
- `ARGS` are native Google Benchmark runtime arguments. There is no helper-specific `OUTPUT` keyword; use native flags such as `--benchmark_out=<path>` and `--benchmark_out_format=json`.
|
|
- Automatically links Core runtime defaults `PRIVATE`.
|
|
|
|
Example with native benchmark arguments, mirroring the positive helper fixture pattern:
|
|
|
|
```cmake
|
|
include("${CC_PROJECT_ROOT}/cmake/cc_targets.cmake")
|
|
include("${CC_PROJECT_ROOT}/cmake/cc_benchmark.cmake")
|
|
|
|
add_custom_target(run_benchmarks
|
|
COMMENT "Running all benchmarks"
|
|
VERBATIM
|
|
)
|
|
|
|
cc_benchmark(args_bench
|
|
SRCS bench_args.cc
|
|
ARGS --benchmark_out=${CMAKE_BINARY_DIR}/bench_output.json
|
|
--benchmark_out_format=json
|
|
)
|
|
```
|
|
|
|
Custom-main example:
|
|
|
|
```cmake
|
|
cc_benchmark(no_main_bench
|
|
SRCS bench_no_main.cc
|
|
NO_MAIN
|
|
DEPS PRIVATE calc
|
|
)
|
|
```
|
|
|
|
## `cc_fuzz()`
|
|
|
|
Signature:
|
|
|
|
```cmake
|
|
cc_fuzz(<target>
|
|
[REQUIRED]
|
|
SRCS <src>...
|
|
[HDRS <hdr>...]
|
|
[INCS [PUBLIC|PRIVATE <dir>...]...]
|
|
[DEPS [PUBLIC|PRIVATE <dep>...]...]
|
|
[DEFINES [PUBLIC|PRIVATE <define>...]...]
|
|
[OPTIONS <option>...]
|
|
[FEATURES <feature>...]
|
|
[SMOKE_ARGS <arg>...]
|
|
[SMOKE_ENV <key=value>...]
|
|
[SMOKE_TIMEOUT <seconds>]
|
|
[ARGS <arg>...]
|
|
)
|
|
```
|
|
|
|
Behavior:
|
|
|
|
- When fuzz is requested but unavailable, logs a status message and returns without creating a target. This is the normal behavior for default C++14/test lanes.
|
|
- Fuzz targets are created only when `CC_ENABLE_FUZZTEST_AVAILABLE` is true: Clang, C++17, and the isolated fuzz GTest lane via `cmake --preset fuzz` or equivalent setup.
|
|
- Requires non-empty `SRCS`.
|
|
- Links `fuzztest::fuzztest` when available, otherwise `fuzztest`.
|
|
- Links the available FuzzTest GTest main provider when present.
|
|
- With `REQUIRED`, configure fails if FuzzTest is unavailable with guidance to use the fuzz lane.
|
|
- Materializes FuzzTest dependencies only when target creation is enabled.
|
|
- Registers only a deterministic CTest smoke test named `<target>_smoke` with label `fuzz_smoke`.
|
|
- `SMOKE_ARGS` and `SMOKE_ENV` are for fast deterministic CI smoke execution; `SMOKE_TIMEOUT` defaults to 30 seconds.
|
|
- `ARGS` are stored as `_CC_FUZZ_ARGS` metadata for long-running direct executable invocation outside CTest.
|
|
- There are no `run_fuzz_<name>` wrapper targets.
|
|
- Automatically links Core runtime defaults `PRIVATE`, including `nlohmann_json::nlohmann_json`.
|
|
|
|
Example based on current root usage:
|
|
|
|
```cmake
|
|
include(cmake/cc_targets.cmake)
|
|
include(cmake/cc_fuzz.cmake)
|
|
|
|
cc_fuzz(calc_fuzz
|
|
SRCS src/calc_fuzz.cc
|
|
DEPS PRIVATE calc
|
|
SMOKE_ENV FUZZTEST_PRNG_SEED=42
|
|
)
|
|
```
|
|
|
|
Example with explicit smoke and long-run arguments:
|
|
|
|
```cmake
|
|
cc_fuzz(parser_fuzz
|
|
REQUIRED
|
|
SRCS parser_fuzz.cc
|
|
DEPS PRIVATE parser
|
|
FEATURES cxx_std_17
|
|
SMOKE_ARGS --fuzz_for=1s
|
|
SMOKE_ENV FUZZTEST_PRNG_SEED=42
|
|
SMOKE_TIMEOUT 10
|
|
ARGS --fuzz_for=600s
|
|
)
|
|
```
|
|
|
|
## `cc_install()`
|
|
|
|
Signature:
|
|
|
|
```cmake
|
|
cc_install(<target> [DEPS <logical-name>...])
|
|
```
|
|
|
|
Behavior:
|
|
|
|
- Marks an existing target for install/export by setting `_CC_INSTALL TRUE`.
|
|
- Fails if the target does not exist.
|
|
- `DEPS` lists install-time dependency logical names registered with `cc_register_dependency()`.
|
|
- `DEPS` is not a link dependency list. Link dependencies belong in `cc_library(... DEPS ...)` or `cc_executable(... DEPS ...)`; install-time `DEPS` control generated `find_dependency()` calls and static private dependency validation.
|
|
- Installable targets must have explicit namespaced `ALIAS` metadata before finalization. The helpers do not auto-create aliases.
|
|
|
|
Example using explicit install marking instead of an `INSTALL` keyword:
|
|
|
|
```cmake
|
|
cc_library(core
|
|
TYPE STATIC
|
|
SRCS core.cpp
|
|
INCS PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
DEPS PRIVATE ZLIB::ZLIB
|
|
ALIAS mypkg::core
|
|
)
|
|
|
|
cc_register_dependency(zlib
|
|
PACKAGE ZLIB
|
|
TARGETS ZLIB::ZLIB
|
|
)
|
|
|
|
cc_install(core DEPS zlib)
|
|
```
|
|
|
|
## `cc_register_dependency()`
|
|
|
|
Signature:
|
|
|
|
```cmake
|
|
cc_register_dependency(<logical-name>
|
|
PACKAGE <PackageName>
|
|
[VERSION <version-or-range>]
|
|
[EXACT]
|
|
[COMPONENTS <component>...]
|
|
[OPTIONAL_COMPONENTS <component>...]
|
|
[TARGETS <target>...]
|
|
)
|
|
```
|
|
|
|
Behavior:
|
|
|
|
- Registers package metadata for generated package config files.
|
|
- `PACKAGE` is required and becomes the `find_dependency(<PackageName> ...)` package name.
|
|
- `VERSION`, `EXACT`, `COMPONENTS`, and `OPTIONAL_COMPONENTS` are forwarded to `find_dependency()`.
|
|
- `TARGETS` records the imported targets provided by the package. It is metadata used by install/export validation.
|
|
- Duplicate logical names are allowed only when all metadata matches exactly; conflicting re-registration fails at configure time.
|
|
- Reference registered logical names from `cc_install(<target> DEPS <logical-name>...)`.
|
|
|
|
Example:
|
|
|
|
```cmake
|
|
cc_register_dependency(fmt
|
|
PACKAGE fmt
|
|
VERSION 10.0
|
|
TARGETS fmt::fmt
|
|
)
|
|
|
|
cc_library(formatting
|
|
TYPE STATIC
|
|
SRCS formatting.cpp
|
|
DEPS PUBLIC fmt::fmt
|
|
ALIAS mypkg::formatting
|
|
INSTALL
|
|
)
|
|
|
|
cc_install(formatting DEPS fmt)
|
|
```
|
|
|
|
## `cc_finalize_install()`
|
|
|
|
Signature:
|
|
|
|
```cmake
|
|
cc_finalize_install()
|
|
```
|
|
|
|
Behavior:
|
|
|
|
- Idempotent; repeated calls after the first do nothing.
|
|
- Returns without producing install rules when `CC_ENABLE_INSTALL` is OFF.
|
|
- Uses only targets marked by `INSTALL` or `cc_install()`.
|
|
- Validates that every install target has an explicit namespaced alias of the form `namespace::name`.
|
|
- Requires all installed targets to use the same namespace.
|
|
- Sets `EXPORT_NAME` from the alias leaf and installs targets into a single export set named `<project>Targets`.
|
|
- Generates and installs `<project>Config.cmake` and `<project>ConfigVersion.cmake`.
|
|
- Emits `find_dependency()` calls for logical dependencies declared with `cc_install(... DEPS ...)`.
|
|
- Installs public headers from `include/<project>/` when that directory exists.
|
|
- `cc_project()` schedules this function with `cmake_language(DEFER)` for top-level projects, so most projects should not need to call it manually.
|
|
|
|
Manual finalization example for a narrow fixture or custom project layout:
|
|
|
|
```cmake
|
|
include(cmake/cc_project.cmake)
|
|
include(cmake/cc_targets.cmake)
|
|
include(cmake/cc_install.cmake)
|
|
|
|
cc_project()
|
|
|
|
cc_library(core
|
|
TYPE STATIC
|
|
SRCS core.cpp
|
|
ALIAS mypkg::core
|
|
INSTALL
|
|
)
|
|
|
|
cc_finalize_install()
|
|
```
|
|
|
|
## Unsupported helper patterns
|
|
|
|
Do not use these patterns through the helper API:
|
|
|
|
```cmake
|
|
# Unsupported: OBJECT library type.
|
|
cc_library(obj TYPE OBJECT SRCS obj.cpp)
|
|
|
|
# Unsupported: missing visibility before dependency.
|
|
cc_library(core TYPE STATIC SRCS core.cpp DEPS fmt::fmt)
|
|
|
|
# Unsupported: executable build-tree aliases.
|
|
add_executable(mypkg::tool ALIAS tool)
|
|
|
|
# Unsupported: helper-specific benchmark output keyword.
|
|
cc_benchmark(core_bench SRCS bench.cc OUTPUT bench.json)
|
|
|
|
# Unsupported: expected per-target run wrappers; use run_fuzz_tests or ctest labels instead.
|
|
# Do not run: cmake --build build --target run_fuzz_core_fuzz
|
|
```
|