project-local.cmake: How To Hook Into LIBRA
To hook into LIBRA, you define a cmake/project-local.cmake. Basically, you
can put WHATEVER you want in this file–all the usual cmake stuff–drawing on
predefined things in LIBRA to make your life easier:
Note
All cmake functions which LIBRA exposes are prefixed with libra_;
all other functions should be considered not part of the API and can
change at any time.
Target Declaration Wrappers
- libra_add_library
Thin wrapper around
add_library()which forwards all arguments to the built in function, and adds the target name toLIBRA_TARGETS. You don’t have to use this function, but if you don’t then much of the LIBRA magic w.r.t. compilers/compilation can only be applied to thePROJECT_NAMEtarget.
- libra_add_executable
Thin wrapper around
add_executable()which forwards all arguments to the built in function, and adds the target name toLIBRA_TARGETS. You don’t have to use this function, but if you don’t then much of the LIBRA magic w.r.t. compilers/compilation can only be applied to thePROJECT_NAMEtarget.
Variables
The variables listed in this section are generally for configuring various LIBRA
features, and therefore are intended to be set via
project-local.cmake. However, many of the cmdline interface variables
detailed in Configure-Time can be set permanently in
project-local.cmake too, but not all of them. Exceptions are:
- LIBRA_ANALYSIS_LANGUAGE
Defines the language that the different static analysis checkers/formatters/fixers will use for checking the project. This should be specified BEFORE any subdirectories, external projects, etc. are specified. Only used if
LIBRA_ANALYSISis true. If used, value must be one of:C
CXX
You should only ever need to set this if your project contains both C and C++ code, to switch between which is checked.
- 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-format 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 a each category of checks that LIBRA creates targets for. Defaults to:,-clang-diagnostic-*
Added in version 0.8.15.
- 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.
- 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`.
- 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`.
- 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_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}.
- ${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.
Build And Configure-time Diagnostics
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_config_summary_prepare_fields
Prepare configuration fields for display by adding padding and colorization.
Given a list of configurable fields in a project as strings, this function defines a set of new variables, one per field, with the prefix
EMIT_. The value of each new variable is right-padded with spaces so that any extra content on each line (when the variables are printed to the screen) can be left-aligned. Additionally, common values like ON/OFF and YES/NO are colorized for easier visual parsing.This function is typically used in conjunction with
libra_config_summary()to create nicely formatted configuration summaries.- Param FIELDS:
List of field names (variable names) to prepare for display. Each field will have a corresponding
EMIT_<field>variable created in the parent scope that contains the padded and colorized value.
Colorization Rules:
ON,on,YES,yes- Displayed in greenOFF,off,NO,no- Displayed in redSpecial strings (
NONE,ALL,CONAN) - No colorizationVersion numbers (
x.y.zformat) - No colorization
Example:
set(MY_FIELDS CMAKE_BUILD_TYPE LIBRA_TESTS LIBRA_CODE_COV) libra_config_summary_prepare_fields("${MY_FIELDS}") # Now you can use EMIT_CMAKE_BUILD_TYPE, EMIT_LIBRA_TESTS, etc. message(STATUS "Build type: ${EMIT_CMAKE_BUILD_TYPE}") message(STATUS "Tests: ${EMIT_LIBRA_TESTS}")
- libra_config_summary
Print a comprehensive summary of LIBRA configuration variables to the terminal.
Displays a nicely formatted, colorized summary of all LIBRA configuration variables and their current values. This helps debug the inevitable “Did I actually set the variable I thought I did?” questions. Using this function, you can see EXACTLY what variable values will be when you invoke your chosen build engine.
The summary includes:
LIBRA version and driver mode
Generator and build system information
Installation paths
Build type and architecture
Compiler information and standards
All LIBRA feature flags (tests, sanitizers, optimizations, etc.)
Available make targets for each enabled feature
Usage Patterns:
You can put this at the end of
project-local.cmakeif you want to control when LIBRA’s configuration summary vs. your project’s configuration summary is emitted. Otherwise, LIBRA will run it automatically at the end of the configure step, as determined byLIBRA_SUMMARY.Example:
# In your CMakeLists.txt or project-local.cmake libra_config_summary() # Output will show something like: # -------------------------------------------------------------------------------- # LIBRA Configuration Summary # -------------------------------------------------------------------------------- # LIBRA version.........................: 0.9.25 # Build type............................: Release # Build tests...........................: ON # ...
Note
This function only displays the summary once per configure run. Subsequent calls in the same configure will be ignored.
See Also:
libra_config_summary_prepare_fields()- Prepare fields for display
- 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 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 Template:
The following variables are available for use in your
INFILEtemplate: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_BUILD- The configured C compiler flags relevant for building (excludes diagnostic flags like-W*).
You can also use any standard CMake variables (e.g.,
CMAKE_C_FLAGS_RELEASE,PROJECT_VERSION,CMAKE_BUILD_TYPE, etc.).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_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.To use,
include(libra/package/install.cmake).- 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).To use,
include(libra/package/install.cmake).- 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.To use,
include(libra/package/install.cmake).- 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.To use,
include(libra/package/install.cmake).- Param DIRECTORY:
The directory containing header files to install. Searched recursively for
.hppand.hfiles.
Example:
# Install headers from include/ to ${CMAKE_INSTALL_PREFIX}/include 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.To use,
include(libra/package/install.cmake).- 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_PREFIX}/includeExport 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.
To use,
include(libra/package/deploy.cmake).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_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