14 KiB
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)beforecc_project(); the helper rejects CMake's implicitproject(Project)default. - The primary project standard is C++14. Fuzz lane targets require the fuzz preset or equivalent Clang + C++17 configuration.
INCS,DEPS, andDEFINESuse explicit visibility groups. Every item must followPUBLIC,PRIVATE, orINTERFACE; unqualified items are rejected.- Executable-like targets (
cc_executable,cc_test,cc_benchmark, andcc_fuzz) do not supportINTERFACEvisibility because they are not consumed as link interfaces. UsePUBLICorPRIVATEonly. cc_library(TYPE INTERFACE)supports onlyINTERFACEvisibility forINCS,DEPS, andDEFINES.- Helpers do not acquire external dependencies. Define or load targets such as
GTest::gtest,benchmark::benchmark, andfuzztest::fuzztestbefore calling the corresponding helper. - There are aggregate targets
run_testsandrun_benchmarks, but no per-targetrun_test_<name>,run_benchmark_<name>, orrun_fuzz_<name>wrappers.
cc_project()
Signature:
cc_project()
Use in the root CMakeLists.txt after native project() and after any cache variables that should influence helper options.
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_COMMANDSunless 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: OFF by default; requires the fuzz lane when enabled.CC_WARNINGS_AS_ERRORS: OFF by default.
- Bridges existing lane options into helper options when present:
CPP_TEMPLATE_ENABLE_TESTS,CPP_TEMPLATE_ENABLE_BENCHMARKS, andCPP_TEMPLATE_FUZZ_LANE. - Creates top-level aggregate targets when enabled:
run_tests: runsctest --output-on-failure.run_benchmarks: aggregate target populated bycc_benchmark().
- Defers
cc_finalize_install()at generate time when the install module is included.
cc_library()
Signature:
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:
TYPEis mandatory and must beSTATIC,SHARED, orINTERFACE.OBJECTlibraries are not supported by this helper.TYPE INTERFACEmust not provideSRCSorHDRS.INCS,DEPS, andDEFINESrequire explicit visibility for every item.TYPE INTERFACEonly acceptsINTERFACEvisibility in visibility-grouped arguments.ALIAScreates a real build-tree library alias withadd_library(<alias> ALIAS <target>)and also stores install/export metadata.INSTALLonly marks the target. Install rules are produced later bycc_finalize_install()when install is enabled.
Static library example, mirroring the positive helper fixture pattern:
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:
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:
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.
SRCSmay be omitted, producing an initially empty executable target. - Applies
OPTIONSandFEATURESprivately. - Rejects
INTERFACEvisibility inINCS,DEPS, andDEFINES. ALIASis install/export metadata only. CMake does not supportadd_executable(<alias> ALIAS ...), so no build-tree executable alias is created.INSTALLmarks the target for later install/export finalization.
Example:
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:
cc_executable(my_tool
SRCS main.cpp
ALIAS my_ns::my_tool
INSTALL
)
cc_test()
Signature:
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:
- Skips target creation when
CC_ENABLE_TESTINGis OFF. - Requires
GTest::gtest; if unavailable, warns and skips target creation. - Requires non-empty
SRCS. - Registers
add_test(NAME <target> COMMAND <target> [<ARGS>...]). - Adds the test executable as a dependency of
run_testswhen that aggregate target exists. - Without
NO_MAIN, linksGTest::gtest_main, which impliesGTest::gtest. - With
NO_MAIN, linksGTest::gtestonly; use this when the test source or another dependency suppliesmain(). GTest::gmockmay be listed inDEPSwith or withoutNO_MAIN.GTest::gmock_mainrequiresNO_MAIN; the helper rejects it otherwise because it conflicts with defaultGTest::gtest_main.
Basic example:
include("${CC_PROJECT_ROOT}/cmake/cc_targets.cmake")
include("${CC_PROJECT_ROOT}/cmake/cc_testing.cmake")
enable_testing()
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:
cc_test(mock_test
SRCS test_mock.cpp
NO_MAIN
DEPS PRIVATE GTest::gmock
)
cc_benchmark()
Signature:
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:
- Skips target creation when
CC_ENABLE_BENCHMARKSis OFF. - Requires
benchmark::benchmark; if unavailable, warns and skips target creation. - Without
NO_MAIN, also requires and linksbenchmark::benchmark_main. - With
NO_MAIN, linksbenchmark::benchmarkonly; use this when the benchmark source providesmain(). - Requires non-empty
SRCS. - Does not register the benchmark with default CTest.
- Adds the benchmark target as a dependency of
run_benchmarkswhen that aggregate target exists. - Adds a
POST_BUILDcommand torun_benchmarksthat directly executes the benchmark binary withARGS. ARGSare native Google Benchmark runtime arguments. There is no helper-specificOUTPUTkeyword; use native flags such as--benchmark_out=<path>and--benchmark_out_format=json.
Example with native benchmark arguments, mirroring the positive helper fixture pattern:
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:
cc_benchmark(no_main_bench
SRCS bench_no_main.cc
NO_MAIN
DEPS PRIVATE calc
)
cc_fuzz()
Signature:
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:
- Skips target creation when
CC_ENABLE_FUZZTESTis OFF. - Requires non-empty
SRCS. - Links
fuzztest::fuzztestwhen available, otherwisefuzztest. - Links the available FuzzTest GTest main provider when present.
- If FuzzTest is unavailable, warns and skips by default. With
REQUIRED, configure fails with guidance to use the fuzz lane. - Does not materialize FuzzTest dependencies and does not change compiler standard itself.
- Fuzz targets are intended for the fuzz lane: Clang and C++17 via
cmake --preset fuzzor equivalentCPP_TEMPLATE_FUZZ_LANE=ONsetup. - Registers only a deterministic CTest smoke test named
<target>_smokewith labelfuzz_smoke. SMOKE_ARGSandSMOKE_ENVare for fast deterministic CI smoke execution;SMOKE_TIMEOUTdefaults to 30 seconds.ARGSare stored as_CC_FUZZ_ARGSmetadata for long-running direct executable invocation outside CTest.- There are no
run_fuzz_<name>wrapper targets.
Example based on current root usage:
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:
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:
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.
DEPSlists install-time dependency logical names registered withcc_register_dependency().DEPSis not a link dependency list. Link dependencies belong incc_library(... DEPS ...)orcc_executable(... DEPS ...); install-timeDEPScontrol generatedfind_dependency()calls and static private dependency validation.- Installable targets must have explicit namespaced
ALIASmetadata before finalization. The helpers do not auto-create aliases.
Example using explicit install marking instead of an INSTALL keyword:
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:
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.
PACKAGEis required and becomes thefind_dependency(<PackageName> ...)package name.VERSION,EXACT,COMPONENTS, andOPTIONAL_COMPONENTSare forwarded tofind_dependency().TARGETSrecords 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:
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:
cc_finalize_install()
Behavior:
- Idempotent; repeated calls after the first do nothing.
- Returns without producing install rules when
CC_ENABLE_INSTALLis OFF. - Uses only targets marked by
INSTALLorcc_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_NAMEfrom the alias leaf and installs targets into a single export set named<project>Targets. - Generates and installs
<project>Config.cmakeand<project>ConfigVersion.cmake. - Emits
find_dependency()calls for logical dependencies declared withcc_install(... DEPS ...). - Installs public headers from
include/<project>/when that directory exists. cc_project()schedules this function withcmake_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:
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:
# 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