project-local.cmake: How To Hook Into LIBRA#
cmake/project-local.cmake is the file where you define your project’s
targets, configure LIBRA features, and hook into LIBRA’s build machinery. You
can put standard CMake in this file alongside LIBRA-specific calls.
For an introduction to what this file should contain and a minimal working example, see project-local.cmake. This page covers the full reference: target declaration wrappers, all available variables, configure-time utilities, and installation/deployment helpers.
Note
All cmake functions which LIBRA exposes are prefixed with libra_;
anything else should be considered non-API and may change at any time.
Target Declaration Wrappers#
- libra_add_library#
Register a library target.
Thin wrapper around
add_library()which forwards all arguments to the built in function, and adds the target name to the list of targets to apply the LIBRA magic to.
- libra_add_executable#
Register an executable target.
Thin wrapper around
add_executable()which forwards all arguments to the built in function, and adds the target name to the list of targets to apply the LIBRA magic to.
Variables#
The variables listed in this section are generally for configuring various LIBRA
features on a per-project basis, and are stable for the duration of the
project. However, they are NOT defined as cache variables because (a) they don’t
need to be, and (b) so the user doesn’t need to remember to set(VAR "value"
CACHE FORCE) them instead of just set(VAR "value") them.
Note
Many of the cmdline interface variables detailed in
Variable reference can be set permanently in project-local.cmake
too, but not all of them. Exceptions are:
If you do set any, you will need to add CACHE FORCE when setting or
things may break in subtle ways.
General#
- LIBRA_C_DIAG_CANDIDATES#
The list of compiler warning options you want to pass to the C compiler. This can be a superset of the options supported by the minimum C compiler version you target; each option in the list is checked to see if the current C compiler supports it. If not defined, uses LIBRA’s internal C diagnostic option set, which is fairly comprehensive. If you don’t want to compile with any warnings, set this to
"".Added in version 0.8.6.
- LIBRA_CXX_DIAG_CANDIDATES#
The list of compiler warning options you want to pass to the compiler. This can be a superset of the options supported by the minimum compiler version you target; each option in the list is checked to see if the current CXX compiler supports it. If not defined, uses LIBRA’s internal CXX diagnostic option set, which is fairly comprehensive. If you don’t want to compile with any warnings, set this to
"".Added in version 0.8.6.
Source Discovery#
- ${PROJECT_NAME}_C_SRC#
Glob containing all C source files.
- ${PROJECT_NAME}_CXX_SRC#
Glob containing all C++ source files.
- ${PROJECT_NAME}_C_HEADERS#
Glob containing all C header files.
- ${PROJECT_NAME}_CXX_HEADERS#
Glob containing all C++ header files.
Note
See Using cmake Globbing for rationale on why globs are used, contrary to common cmake guidance.
Analysis#
- LIBRA_CPPCHECK_IGNORES#
A list of files to totally ignore when running
cppcheck. Only used ifLIBRA_ANALYSISis enabled andcppcheckis found. The-iseparators are added by LIBRA–this should just be a raw list.Added in version 0.8.5.
- LIBRA_CPPCHECK_SUPPRESSIONS#
A list of categories of warnings to suppress for matching patterns
cppcheck. Only used ifLIBRA_ANALYSISis enabled andcppcheckis found. The--suppress=separators are added by LIBRA–this should just be a raw list.Added in version 0.8.5.
- LIBRA_CPPCHECK_EXTRA_ARGS#
A list of extra arguments to pass to cppcheck. If you want to pass suppressions or ignores, use the above variables; this is for other things which don’t fit in those buckets. Passed as-is to cppcheck.
Added in version 0.8.5.
- LIBRA_CLANG_FORMAT_FILEPATH#
The path to the
.clang-formatfile you want to use. If not defined, LIBRA will use its internal .clang-format file.Added in version 0.8.8.
- LIBRA_CLANG_TIDY_FILEPATH#
The path to the
.clang-tidyfile you want to use. If not defined, LIBRA will use its internal .clang-tidy file.Added in version 0.8.8.
- LIBRA_CLANG_TIDY_CHECKS_CONFIG#
Any additional things to pass to
--checks. If non empty, must start with,. Useful to disable certain checks within each category of checks that LIBRA creates targets for.Added in version 0.8.15.
- LIBRA_CLANG_TIDY_EXTRA_ARGS#
Additional flags appended verbatim to every clang-tidy invocation. Useful for flags that LIBRA does not otherwise expose, such as
--allow-enabling-analyzer-alpha-checkers. Passed as-is; no separators are added.Added in version 0.8.15.
Testing#
- LIBRA_TEST_HARNESS_LIBS#
Defines the link libraries that all tests/test harnesses need to link with, if any. Goes hand in hand with
LIBRA_TEST_HARNESS_PACKAGES. Does not apply to interpreted tests.
- LIBRA_TEST_HARNESS_PACKAGES#
Defines the packages that contain the libraries that all tests/test harnesses need to link with, if any. Goes hand in hand with
LIBRA_TEST_HARNESS_LIBS. Does not apply to interpreted tests.
- LIBRA_UNIT_TEST_MATCHER#
The common suffix before the
.cppthat all unit tests undertests/will have so LIBRA can glob them. If not specified, defaults to-utest; a valid unit test would then be, e.g.,tests/myclass-utest.cpp.
- LIBRA_INTEGRATION_TEST_MATCHER#
The common suffix before the
.cppthat all integration tests undertests/will have so LIBRA can glob them. If not specified, defaults to-itest; a valid integration test would then be, e.g.,tests/thing-itest.cpp.
- LIBRA_REGRESSION_TEST_MATCHER#
The common suffix before the
.cppthat all regression tests undertests/will have so LIBRA can glob them. If not specified, defaults to-rtest; a valid integration test would then be, e.g.,tests/thing-rtest.cpp.
- LIBRA_NEGATIVE_TEST_INCLUDE_DIRS#
Knob for additional include directories that need to be passed to negative compile tests.
-Iis added to each directory by LIBRA. Because these tests do not depend on the main target, we can only extract the dirs from the main target itself, not from its transitive dependencies. This is a limitation of CMake.
- LIBRA_NEGATIVE_TEST_COMPILE_FLAGS#
Knob for additional compile flags that need to be passed to negative compile tests. Because these tests do not depend on the main target, we can only extract the flags, definitions, etc. from the main target itself, not from its transitive dependencies. This is a limitation of CMake.
- LIBRA_TEST_HARNESS_MATCHER#
The common suffix before the
{.cpp,.hpp}that all test harness files tests undertests/will have so LIBRA can glob them. If not specified, defaults to_test; valid test harness would then be, e.g.,tests/thing_test{.cpp,.hpp}. Does not apply to interpreted tests.
Configure-time Utilities#
LIBRA provides a number of functions/macros to simplify the complexity of cmake,
and answer questions such as “am I really building/running what I think I
am?”. Some useful functions available in project-local.cmake are:
- libra_require_compiler#
Enforce a minimum major version for a given compiler and language. Can be called multiple times to enforce requirements for different compilers or languages independently.
Signature:
libra_require_compiler( [LANG <C|CXX> ...] # Languages to check. Defaults to both C and CXX. ID <compiler-id> # Compiler ID: GNU, Clang, AppleClang, IntelLLVM VERSION <major> # Minimum required major version (integer) )
- Param LANG:
Accepts one or more languages. If omitted, both
CandCXXare checked. Languages not enabled in the project are silently skipped.- Param ID:
The ID of the compiler to check. If the active compiler ID does not match
ID, the check is silently skipped. This allows callinglibra_require_compileronce per supported compiler without needingif()guards around each call. Basically, if and only if the active compiler ID matches the argument is the version checked.- Param VERSION:
Compiler major version to check against. If the active compiler ID matches and its major version is less than this, a fatal error is issued immediately.
Examples:
# Require GCC >= 13 for both C and C++ libra_require_compiler(ID GNU VERSION 13) # Require Clang >= 17 for C++ only libra_require_compiler(LANG CXX ID Clang VERSION 17) # Require GCC >= 13 for C, IntelLLVM >= 2024 for C++ libra_require_compiler(LANG C ID GNU VERSION 13) libra_require_compiler(LANG CXX ID IntelLLVM VERSION 2024)
Fatal error format:
[LIBRA] C compiler version requirement not met: Required: GNU >= 13 Found: GNU 12.3.1
- libra_config_summary_row#
Add a custom row to the LIBRA configuration summary feature table.
Intended for use in
project-local.cmaketo extend the LIBRA summary with project-specific configuration options, displayed in the same style and column alignment as built-in LIBRA rows.Must be called after
libra_config_summary()has been called (or from within aproject-local.cmakethat is included before LIBRA emits the summary), so thatlibra_config_summary_prepare_fields()has already run and theEMIT_variable for the status field is populated.Signature:
libra_config_summary_row( LABEL <string> STATUS <variable-name> VARIABLE <string> )
- Param LABEL:
Feature description shown in column 1. Will be truncated/padded to the column width.
- Param STATUS:
Name of an
EMIT_<X>variable (prepared vialibra_config_summary_prepare_fields()) whose value is shown in column 2.- Param VARIABLE:
Variable name shown in column 3, e.g.
[MY_OPTION]. Pass""to leave blank.
Example:
set(my_fields MY_BACKEND MY_FEATURE_X) libra_config_summary_prepare_fields("${my_fields}") libra_config_summary() libra_config_summary_row( LABEL "Backend type........................." STATUS EMIT_MY_BACKEND VARIABLE "[MY_BACKEND]") libra_config_summary_row( LABEL "Enable feature X....................." STATUS EMIT_MY_FEATURE_X VARIABLE "[MY_FEATURE_X]")
Notes:
LABELshould use trailing.characters to reach the column width (_LIBRA_SUMMARY_COL_FEATURE= 37), matching the style of built-in rows. Shorter labels are right-padded with spaces automatically; longer labels are truncated to fit.STATUSis the name of a variable, not its value — passEMIT_MY_VAR, not${EMIT_MY_VAR}.Call
libra_config_summary_prepare_fields()on your custom fields before calling this function so theEMIT_variables exist and are colorized.
See Also:
libra_config_summary_prepare_fields()libra_help_targets_block()
- libra_config_summary#
Print a summary of the current LIBRA configuration to the terminal during
cmakeconfigure. Displays the feature table (table 1) only: all LIBRA options with their current values and controlling variable names.For additional information available after configure:
make help-targets— shows all LIBRA make targets with YES/NO availability status and the reason each unavailable target is disabled.make help-vars— shows all enumerated LIBRA option variables with their valid values.
Note
This function only displays the summary once per configure run.
See Also:
libra_config_summary_prepare_fields()libra_help_targets_block()
- libra_configure_source_file#
Populate a source file template with build and git information.
Use build information from LIBRA and your project to populate a source file template. LIBRA automatically adds the generated file to the list of files for the main
PROJECT_NAMEtarget. This is useful for printing information when your library loads or application starts as a sanity check during debugging to help ensure that you are running what you think you are. Must be called after thePROJECT_NAMEtarget is defined.- Param TARGET:
The target the the configured source file should be added to.
- Param INFILE:
The input template file. Should contain CMake variable references like
@LIBRA_GIT_REV@that will be replaced with actual values.- Param OUTFILE:
The output file path where the configured file will be written.
Available Variables for INFILE Template:
LIBRA_GIT_REV- Git SHA of the current tip. Result ofgit log --pretty=format:%H -n 1.LIBRA_GIT_DIFF- Indicates if the build is “dirty” (contains local changes not in git). Result ofgit diff --quiet --exit-code || echo +. Will be+if dirty, empty otherwise.LIBRA_GIT_TAG- The current git tag for the git rev, if any. Result ofgit describe --exact-match --tags.LIBRA_GIT_BRANCH- The current git branch, if any. Result ofgit rev-parse --abbrev-ref HEAD.LIBRA_TARGET_FLAGS_COMPILE- The configured compiler flags relevant for building (excludes diagnostic flags like-W).LIBRA_TARGET_FLAGS_LINK- The configured linker flags relevant for building (excludes diagnostic flags like-W). Note that IPO related flags for GCC/clang do not appear here, because CMake relies on the compiler driver to inject those into actual compiler commands during the final link if the compiler sees that IPO is active at compile time. This is not true for the Intel compilers.
You can also use any standard CMake variables (e.g.,
CMAKE_C_FLAGS_RELEASE,PROJECT_VERSION,CMAKE_BUILD_TYPE, etc.). Note that if you consume LIBRA in a chained fashion via CPM (i.e., have multiple local repos which are built using LIBRA), then the version info will correspond to the top-level repo for all sub-repos, since when they are poplated into the build/ directory in the root repo, they are not git repos, and so versioning info can’t be extracted.Example:
# In CMakeLists.txt set(MY_SOURCES src/main.cpp src/foo.cpp) libra_add_executable(${PROJECT_NAME} ${MY_SOURCES}) libra_configure_source_file( ${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/src/version.cpp.in ${CMAKE_BINARY_DIR}/version.cpp)
// In src/version.cpp.in #include <iostream> void print_version() { std::cout << "Git Rev: @LIBRA_GIT_REV@@LIBRA_GIT_DIFF@" << std::endl; std::cout << "Branch: @LIBRA_GIT_BRANCH@" << std::endl; std::cout << "Tag: @LIBRA_GIT_TAG@" << std::endl; std::cout << "Build Type: @CMAKE_BUILD_TYPE@" << std::endl; }
Note
If your code is not in a git repository, all git-related fields will be stubbed out with
N/Aand will not be very useful. A warning will be emitted during configuration.
Installation#
All functions in this section are only available if
LIBRA_DRIVER is SELF.
- libra_configure_exports#
Configure the exports for a TARGET to be installed at
CMAKE_INSTALL_PREFIX.Enables the installed project to be used with
find_package()by downstream projects. This function requires acmake/config.cmake.intemplate file in your project root.- Param TARGET:
The target name for which to configure exports. This will be used to generate
<TARGET>-config.cmakeand must match the name used infind_package(). You may need to call this on header-only dependencies to get them into the export set for your project. If you do, make sure you do not add said dependencies to yourconfig.cmake.infile viafind_dependency(), as that will cause an infinite loop.
Requirements:
The function expects a template file at
${PROJECT_SOURCE_DIR}/cmake/config.cmake.in. This template is processed byconfigure_package_config_file()to generate the final config file that defines everything necessary to use the project withfind_package().Example:
libra_configure_exports(mylib)
- libra_register_extra_configs_for_install#
Register extra .cmake files for a TARGET to be installed at
${CMAKE_INSTALL_PREFIX}.Configure additional
.cmakefiles/directories for export. Useful if your project provides reusable CMake functionality that you want downstream projects to access. Supports both individual files and directories (processed recursively).- Param TARGET:
The target name (used for install destination). Must be a target for which
libra_configure_exports()has already been called.- Param FILES_OR_DIRS:
One or more .cmake files or directories containing .cmake files. Directories are searched recursively, and the directory structure is preserved during installation (not flattened).
Examples:
# Install individual files libra_register_extra_configs_for_install(mylib cmake/MyLibHelpers.cmake cmake/MyLibUtils.cmake) # Install entire directory (recursive, structure preserved) libra_register_extra_configs_for_install(mylib cmake/modules) # Mix files and directories libra_register_extra_configs_for_install(mylib cmake/special.cmake cmake/modules)
Changed in version 0.9.26: Can now handle files OR directories of extra configs.
- libra_register_copyright_for_install#
Register a copyright notice file to be installed at
CMAKE_INSTALL_DOCDIR.The file is automatically renamed to
copyrightduring installation, which is the standard name expected by Debian package tools (lintian). This function is useful when configuring CPack to generate .deb/.rpm packages.- Param TARGET:
The target name (used for the installation directory path).
- Param FILE:
Path to the copyright file (typically LICENSE, COPYING, etc.). Can be any filename; it will be renamed to
copyrightduring installation.
Installation Path:
The file is installed to:
${CMAKE_INSTALL_DATAROOTDIR}/doc/${TARGET}/copyrightExample:
libra_register_copyright_for_install(mylib ${PROJECT_SOURCE_DIR}/LICENSE)
- libra_register_headers_for_install#
Register header files from a DIRECTORY to be installed at
${CMAKE_INSTALL_PREFIX}.Recursively finds and installs all
.hppand.hfiles from the specified directory, preserving the directory structure. These can be from your project, a header-only dependency, etc.- Param DIRECTORY:
The directory containing header files to install. Searched recursively for
.hppand.hfiles.
Example:
# Install headers from include/ to ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} libra_register_headers_for_install( ${PROJECT_SOURCE_DIR}/include ) # This installs: include/mylib/foo.hpp -> ${CMAKE_INSTALL_PREFIX}/include/mylib/foo.hpp
- libra_register_target_for_install#
Register a TARGET for installation with proper export configuration.
Installs the target’s library files (.so, .a) and public headers, and creates an export file (
<TARGET>-exports.cmake) that allows downstream projects to use the target withfind_package(). The target is associated with the necessary exports file so child projects can find it.- Param TARGET:
The CMake target to install. Must be a valid library target created with
add_library()oradd_executable(). Must be a target for whichlibra_configure_exports()has already been called.
The target is installed with:
Libraries:
${CMAKE_INSTALL_LIBDIR}Public headers:
${CMAKE_INSTALL_INCLUDEDIR}Export file:
${CMAKE_INSTALL_LIBDIR}/cmake/${TARGET}/${TARGET}-exports.cmake
What Gets Installed:
Shared libraries (.so, .dylib, .dll)
Static libraries (.a, .lib)
Executables (if applicable)
Public headers (as specified by target properties)
CMake export file for use with
find_package()
Example:
add_library(mylib src/mylib.cpp) set_target_properties(mylib PROPERTIES PUBLIC_HEADER "include/mylib.hpp") libra_register_target_for_install(mylib) # Downstream projects can now use: # find_package(mylib REQUIRED) # target_link_libraries(their_target mylib::mylib)
Deployment#
All functions in this section are only available if LIBRA_DRIVER
is SELF.
- libra_configure_cpack#
Configure CPack to generate packages via
make package.Supports multiple package formats including Debian archives (.deb), RPM packages (.rpm), and various compressed archives (tar.gz, zip, etc.). Automatically detects license type, configures package metadata, and sets up format-specific options.
This is a MACRO (not function) intentionally so that all CPACK_* variables propagate to parent scope as required by CPack.
libra_configure_cpack(<GENERATORS> <SUMMARY> <DESCRIPTION> <VENDOR> <HOMEPAGE> <CONTACT>)
- Param GENERATORS:
One or more CPack generators, separated by semicolons. Valid options are:
DEB- Debian archive. Packages are set to always install into/usrunlessCPACK_PACKAGE_INSTALL_DIRECTORYis set prior to calling this function.RPM- RPM archive. Packages are set to always install into/usrunlessCPACK_PACKAGE_INSTALL_DIRECTORYis set prior to calling this function.TGZ- Compressed tar archive (.tar.gz)ZIP- ZIP archiveSTGZ- Self-extracting tar.gz archiveTBZ2- Compressed tar archive (.tar.bz2)TXZ- Compressed tar archive (.tar.xz)
Multiple generators can be specified, e.g.,
"DEB;RPM;TGZ".- Param SUMMARY:
One line package summary.
- Param DESCRIPTION:
Detailed package description.
- Param VENDOR:
Package vendor/maintainer organization.
- Param HOMEPAGE:
Project home page URL.
- Param CONTACT:
Project contact. Email address for DEB packages, name for RPM packages.
Automatic Features:
License type detection from LICENSE file (supports MIT, Apache, GPL, BSD)
Version information from
PROJECT_VERSION_*variablesAutomatic dependency detection (
SHLIBDEPSfor DEB,AUTOREQ/AUTOPROVfor RPM)Standard directory permissions to satisfy lintian/rpmlint
Architecture detection
Respects Pre-set Variables:
CPACK_PACKAGE_FILE_NAME- If set, used as-is. Otherwise defaults to${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_PROCESSOR}CPACK_PACKAGE_INSTALL_DIRECTORY- If set, used as-is. Otherwise defaults to${CMAKE_INSTALL_PREFIX}CPACK_DEBIAN_PACKAGE_SECTION- Package section (defaults to “devel”)CPACK_DEBIAN_PACKAGE_PRIORITY- Package priority (defaults to “optional”)CPACK_RPM_PACKAGE_GROUP- RPM group (defaults to “Development/Libraries”)CPACK_RPM_PACKAGE_LICENSE- RPM license (auto-detected if not set)CPACK_RPM_PACKAGE_RELEASE- RPM release number (defaults to “1”)
Expected Files:
The function automatically searches for these files in
CMAKE_CURRENT_SOURCE_DIR:LICENSE*- License file (used for package and license detection)README*- README file
Warnings are emitted if these files are not found, but package generation continues.
Example:
project(mylib VERSION 1.0.0) libra_configure_cpack( "DEB;RPM" "A short project description" "Long description of the project features and capabilities." "John Doe" "https://example.com/mylib" "John Doe <john@example.com>") # Generate packages with: make package
DEB-Specific Configuration:
File naming:
DEB-DEFAULT(includes architecture)Automatic shared library dependency detection
Strict control file permissions
Debug output enabled for troubleshooting
RPM-Specific Configuration:
File naming:
RPM-DEFAULT(includes version, release, architecture)Relocatable packages (allows installation to different prefixes)
Standard system directories excluded from package
Complete Example#
Here’s a full-featured cmake/project-local.cmake showing common patterns:
# Library target
libra_add_library(my_library STATIC
src/core.cpp
src/utils.cpp
)
target_include_directories(my_library PUBLIC include)
# Application target
libra_add_executable(my_app src/main.cpp)
target_link_libraries(my_app PRIVATE my_library)