Modules

JcmAllModules

Module Source on GitHub

When included, includes all of JCM’s CMake modules, excluding any Find Modules.


JcmSetupProject

Module Source on GitHub

Offers utilities to properly setup a CMake project for consumption as both a sub-project and a binary package. Creates target component, COMPONENT, and defines macro jcm_setup_project() used to setup a CMake project.


jcm_setup_project

jcm_setup_project
jcm_setup_project([PREFIX_NAME <project-prefix>])

Sets up a CMake project in the top-level CMakeLists.txt.

This function will:
  • guard against misuse and malpractice, such as PROJECT_NAME being defined, the call-site is in the top-level CMakeLists.txt, preventing in-source builds, and ensuring project naming conventions.

  • set variable JCM_PROJECT_PREFIX_NAME to the upper-case project name, or PREFIX_NAME, if provided. This variable is used as the prefix name to subsequent macros, options, and variables.

  • create options:

    ${JCM_PROJECT_PREFIX_NAME}_ENABLE_TESTS

    Enables/disables building project tests for this specific project. Default: BUILD_TESTING

    ${JCM_PROJECT_PREFIX_NAME}_ENABLE_DOCS

    Enables/disables building project documentation for this specific project. Default: OFF

  • set default values for CMake variables controlling the build when the current project is the top-level project

    • CMAKE_BUILD_TYPE

    • CMAKE_EXPORT_COMPILE_COMMANDS

    • CMAKE_LINK_WHAT_YOU_USE

    • CMAKE_COLOR_DIAGNOSTICS

    • CMAKE_INSTALL_PREFIX

    • CMAKE_DEBUG_POSTFIX

    • CMAKE_OBJECT_PATH_MAX (Windows)

  • set values for variables CMake uses to initialize target properties, only when the current project is top-level

    • CMAKE_INSTALL_RPATH (runtime search path (RPATH) for shared object libraries)

    • CMAKE_ARCHIVE_OUTPUT_DIRECTORY

    • CMAKE_LIBRARY_OUTPUT_DIRECTORY

    • CMAKE_RUNTIME_OUTPUT_DIRECTORY

    • CMAKE_<LANG>_STANDARD

    • CMAKE_<LANG>_STANDARD_REQUIRED

    • CMAKE_<LANG>_EXTENSIONS

    • CMAKE_<LANG>_VISIBILITY_PRESET

    • CMAKE_VISIBILITY_INLINES_HIDDEN

  • enable interprocedural optimization in Release mode

  • always enable testing so testing never fails, even if there are no tests, and includes CTest when ${JCM_PROJECT_PREFIX_NAME}_ENABLE_TESTS is set. The global property CTEST_TARGETS_ADDED is set to disable CTest from producing the often unused CDash targets until the CTest policy changes.

Parameters

Options
WITH_CTEST_TARGETS

When set, skips setting the global property CTEST_TARGETS_ADDED such that CTest creates targets for interoperability with CDash. These targets are commonly unused, so they’re disable by JCM by default. See CTest policy changes

One Value
PREFIX_NAME

Sets variable JCM_PROJECT_PREFIX_NAME, which is used as the prefix for variables, macros, options, etc. specific to this project.

Examples

jcm_setup_project()
jcm_setup_project(PREFIX_NAME STX)

JcmAddExecutable

Module Source on GitHub

jcm_add_executable

jcm_add_executable
jcm_add_executable(
  [WITHOUT_CANONICAL_PROJECT_CHECK]
  [WITHOUT_FILE_NAMING_CHECK]
  [COMPONENT <component>]
  [NAME <name>]
  [OUT_TARGET <out-var>]
  [LIB_SOURCES <source>...]
  SOURCES <source>...)

Adds an executable target to the project, similar to CMake’s add_executable, but with enhancements. It allows creating both the executable and, optionally, an associated object or interface library to allow better automated testing of the executable’s sources. This library will have the same name as the executable, but with ‘-library’ appended (main -> main-library).

This function will:

  • ensure it’s called within a canonical source subdirectory, verify the naming conventions and locations of the input source files, and transform SOURCES and LIB_SOURCES to normalized absolute paths.

  • create an executable target with add_executable(), including an associated alias

  • optionally create an object library, <target>-library, with an associated alias <PROJECT_NAME>::<EXPORT_NAME>-library (<PROJECT_NAME>::<EXPORT_NAME>) - both following JCM’s target naming conventions

  • optionally create an object library, <target>-library, with an associated alias <PROJECT_NAME>::<EXPORT_NAME>-library (<PROJECT_NAME>::<EXPORT_NAME>) - both following JCM’s target naming conventions

  • create header sets with jcm_header_file_sets() for both the main executable target, and the optional library target. PRIVATE header sets will be added to the executable using header files found in SOURCES, while PUBLIC or INTERFACE header sets will be added to the object/interface library using header files found in LIB_SOURCES. This is what sets the INCLUDE_DIRECTORIES properties.

  • set target properties:

    • OUTPUT_NAME

    • EXPORT_NAME

    • COMPILE_OPTIONS

    • INCLUDE_DIRECTORIES

    • COMPONENT (custom property to JCM)

Parameters

Options
WITHOUT_CANONICAL_PROJECT_CHECK

When provided, will forgo the default check that the function is called within an executable source subdirectory, as defined by the Canonical Project Structure.

WITHOUT_FILE_NAMING_CHECK

When provided, will forgo the default check that provided header and source files conform to JCM’s file naming conventions

One Value
COMPONENT

Specifies the component that this executable represents. Used to set COMPONENT property and when naming the target.

NAME

Overrides the target name, output name, and exported name from those automatically created to conform to JCM’s naming conventions

OUT_TARGET

The variable named will be set to the created target’s name

Multi Value
LIB_SOURCES

Sources used to create the executable’s associated object/interface library. When provided, an object or interface library will be created, it will be linked against the executable, and its include directories will be set instead of the executable’s. An object library will be created when any of the file names of LIB_SOURCES match JCM_SOURCE_REGEX, while an interface library will be created otherwise (just header files).

SOURCES

Sources used to create the executable

Examples

jcm_add_executable(SOURCES main.cpp)
target_link_libraries(example::example PRIVATE libthird::party)
# PROJECT_NAME is xml
# target will be xml::xml

jcm_add_executable(
  OUT_TARGET target
  SOURCES main.cpp
  LIB_SOURCES xml.cpp)

jcm_add_test_executable(
  NAME test_parser
  SOURCES test_parser.cpp
  LIBS ${target}-library Boost::ut)
# creates associated interface library, instead of object library

jcm_add_executable(
  OUT_TARGET target
  SOURCES main.cpp
  LIB_SOURCES coffee.hpp)

JcmAddLibrary

Module Source on GitHub

jcm_add_library

jcm_add_library
jcm_add_library(
  [WITHOUT_CANONICAL_PROJECT_CHECK]
  [WITHOUT_FILE_NAMING_CHECK]
  [COMPONENT <component>]
  [NAME <name>]
  [OUT_TARGET <out-var>]
  [TYPE <STATIC | SHARED | MODULE | INTERFACE | OBJECT>]
  <[INTERFACE_HEADERS <header>...]
   [PUBLIC_HEADERS <header>...]
   [PRIVATE_HEADERS <header>...]
   [SOURCES <source>...] >)

Adds a library target to the project, similar to CMake’s add_library, but with enhancements.

This function will:

  • ensure it’s called within a canonical source subdirectory, verify the naming conventions and locations of the input source files, and transform SOURCES to normalized, absolute paths

  • create a library target with add_library(), including an associated alias (<PROJECT_NAME>::<EXPORT_NAME>) - both following JCM’s target naming conventions

  • create PRIVATE, PUBLIC, and INTERFACE header sets with jcm_header_file_sets() using the respective *_HEADERS parameters. This is what sets the *INCLUDE_DIRECTORIES properties

  • Generate a header file, ${CMAKE_CURRENT_BINARY_DIR}/export_macros.hpp, with generate_export_header()

  • create project options to control building the library shared. The precedence of the options increases with their specificity

    BUILD_SHARED_LIBS

    global to entire build; used by almost all projects

    <JCM_PROJECT_PREFIX_NAME>_BUILD_SHARED_LIBS

    specific to the project. Default: BUILD_SHARED_LIBS

    <JCM_PROJECT_PREFIX_NAME>_<UPPERCASE_COMPONENT>_BUILD_SHARED

    specific to component, if COMPONENT is provided. Default: <JCM_PROJECT_PREFIX_NAME>_BUILD_SHARED_LIBS

  • set target properties:

    • OUTPUT_NAME

    • EXPORT_NAME

    • PREFIX

    • COMPILE_OPTIONS

    • INTERFACE_INCLUDE_DIRECTORIES

    • INCLUDE_DIRECTORIES

    • VERSION

    • SOVERSION

    • COMPONENT (custom property to JCM)

Parameters

Options
WITHOUT_CANONICAL_PROJECT_CHECK

When provided, will forgo the default check that the function is called within an executable source subdirectory, as defined by the Canonical Project Structure.

WITHOUT_FILE_NAMING_CHECK

When provided, will forgo the default check that provided header and source files conform to JCM’s file naming conventions

One Value
COMPONENT

Specifies the component that this executable represents. Used to set the target’s COMPONENT property, and when naming the target.

NAME

Overrides the target name, output name, and exported name from those automatically created to conform to JCM’s naming conventions

OUT_TARGET

The variable named will be set to the created target’s name

TYPE

Overrides the library type from the default value. When SOURCES are provided, the default is one of either STATIC or SHARED, dictated by the *_BUILD_SHARED_LIBS configuration options. Otherwise, the default is INTERFACE. When specified, this call will not create any of the *_BUILD_SHARED_LIBS options. Supported values: STATIC SHARED MODULE INTERFACE OBJECT.

Multi Value
INTERFACE_HEADERS

Header files required by consumers of this library, but not this library itself. Required when TYPE is INTERFACE.

PUBLIC_HEADERS

Header files required by both consumers of this library and this library itself. Prohibited when TYPE is INTERFACE.

PRIVATE_HEADERS

Header files required by this library itself, but not any consumers of this library. Prohibited when TYPE is INTERFACE.

SOURCES

Sources used to create the library

Examples

jcm_add_library(PUBLIC_HEADERS engine.hpp SOURCES engine.cpp)
# PROJECT_NAME is car
# Target will be named car::libengine (query through OUT_TARGET)
# Shared options will be BUILD_SHARED_LIBS, CAR_BUILD_SHARED_LIBS, CAR_ENGINE_BUILD_SHARED

jcm_add_library(
  COMPONENT engine
  PUBLIC_HEADERS engine.hpp
  PRIVATE_HEADERS crank.hpp
  SOURCES engine.cpp crank.cpp)

jcm_add_executable(SOURCES main.cpp)
target_link_libraries(car::car PRIVATE car::libengine)

JcmAddTestExecutable

Module Source on GitHub

jcm_add_test_executable

jcm_add_test_executable
jcm_add_test_executable(
  NAME <name>
  [TEST_NAME <test-name>]
  [LIBS <lib>...]
  SOURCES <source>...)

A convenience function to create an executable and add it as a test in one command, while also setting target properties. This function has no affect if ${JCM_PROJECT_PREFIX_NAME}_ENABLE_TESTS is not set.

This function will:

  • verify the input source files using jcm_verify_target_sources(), and use the cleaned sources produced by that function.

  • create an executable with name NAME from SOURCES.

  • register this executable as a test via CTest with name TEST_NAME, which defaults to NAME, if TEST_NAME isn’t provided.

  • creates a private header set

  • set target properties:

    • OUTPUT_NAME

    • COMPILE_OPTIONS

    • LINK_LIBRARIES

Parameters

One Value
NAME

Sets the target name and output name of the created executable. Used as the default test name if TEST_NAME is not provided.

TEST_NAME

Sets the test name to be registered with CTest.

Multi Value
LIBS

Libraries to privately link against the created executable. Commonly the library that the created executable will test, and a testing framework.

SOURCES

Sources used to create the executable

Examples

jcm_add_test_executable(NAME my_test SOURCES my_test.cpp)
jcm_add_executable(
  OUT_TARGET target
  SOURCES main.cpp
  LIB_SOURCES engine.cpp)

jcm_add_test_executable(
  NAME test_engine
  SOURCES test_engine.cpp
  LIBS ${target}-library Boost::ut)

JcmSourceSubdirectories

Module Source on GitHub

jcm_source_subdirectories

jcm_source_subdirectories
jcm_source_subdirectories(
  [WITH_TESTS_DIR]
  [WITH_DOCS_DIR]
  <[OUT_VAR <out-var>]
   [ADD_SUBDIRS] >
  [LIB_COMPONENTS <component>...]
  [EXEC_COMPONENTS <component>...])

Computes and optionally adds subdirectories following JGD’s project structure, which includes the Canonical Project Structure, which pertains to source subdirectories. These canonical subdirectories are provided by functions in JcmCanonicalStructure, while project directories are provided by JCM_PROJECT_TESTS_DIR and JCM_PROJECT_DOCS_DIR from JcmStandardDirs.

Executable and library subdirectories for non-components will be added first, if they exist. Then, source subdirectories for library and executable components will be added for the components specified, with errors if they don’t exist. Then, the standard tests and docs directory will be optionally added - see Options

This is a function, which prevents added subdirectories from populating variables in the calling list-file’s scope. Bubbling up variables from subdirectories is an anti-pattern to be avoided, and is simply not supported by this function.

Parameters

Options
WITH_TESTS_DIR

Causes the JCM_PROJECT_TESTS_DIR directory to be added when the ${JCM_PROJECT_PREFIX_NAME}_ENABLE_TESTS option is set.

WITH_DOCS_DIR

Causes the JCM_PROJECT_DOCS_DIR directory to be added when the ${JCM_PROJECT_PREFIX_NAME}_ENABLE_DOCS option is set.

ADD_SUBDIRS

Causes this function to add each subdirectory to the project using CMake’s add_subdirectory()

One Value
OUT_VAR

The named variable will be set to the list of resultant subdirectories

Multi Value
LIB_COMPONENTS

A list of library components for which subdirectories will be computed. Components matching PROJECT_NAME will be ignored.

EXEC_COMPONENTS

A list of executable components for which subdirectories will be computed. Components matching PROJECT_NAME will be ignored.

Examples

jcm_source_subdirectories(
  WITH_TESTS_DIR
  WITH_DOCS_DIR
  OUT_VAR mylib_subdirectories)
jcm_source_subdirectories(
  WITH_TESTS_DIR
  WITH_DOCS_DIR
  OUT_VAR mylib_subdirectories
  ADD_SUBDIRS
  LIB_COMPONENTS core extra more)

jcm_collect_subdirectory_targets

jcm_collect_subdirectory_targets
jcm_collect_subdirectory_targets(
  [EXCLUDE_DIRECTORY_REGEX <regex>]
  [START_DIR <directory>]
  <OUT_VAR <out-var> >)

Collects all targets created in and under the current directory, or that named in START_DIR, into a unique list.

This function recursively traverses directories, descending into all subdirectories provided by the directory property SUBDIRECTORIES to collect the targets created in that directory, as indicated by the directory property BUILDSYSTEM_TARGETS. The directories can be optionally excluded from the search by providing a regular expression via EXCLUDE_DIRECTORY_REGEX that will be applied to the directory’s normalized, absolute path. All targets created directly in the directories matching the regex will be omitted, while targets from their subdirectories will still be collected should they not match the regex. The result of this function will always be a unique list, even if the global property ALLOW_DUPLICATE_CUSTOM_TARGETS is set.

Parameters

One Value
OUT_VAR

The named variable will be set to the list of resultant targets

START_DIR

An optional path to an existent directory that will be used as the starting directory in the traversal. A relative path will first be converted to its normalized, absolute form with respect to CMAKE_CURRENT_SOURCE_DIR. Should this be omitted, traversal will begin at ${CMAKE_CURRENT_SOURCE_DIR}.

EXCLUDE_DIRECTORY_REGEX

An optional regular expression that will be used to filter directories from the search.

Examples

jcm_collect_subdirectory_targets(OUT_VAR all_project_targets)

jcm_transform_list(ALIASED_TARGET
  INPUT "${all_project_targets}"
  OUT_VAR all_project_targets)
jcm_collect_subdirectory_targets(
  EXCLUDE_DIRECTORY_REGEX "build.*"
  OUT_VAR all_project_targets)
jcm_collect_subdirectory_targets(
  START_DIR "../code-gen"
  EXCLUDE_REGEX "${PROJECT_SOURCE_DIR}/.*code-gen/.*database"
  OUT_VAR code_gen_targets)

JcmTargetSources

Module Source on GitHub

jcm_add_target_sources

jcm_add_target_sources
jcm_add_target_sources(
  [WITHOUT_FILE_NAMING_CHECK]
  <TARGET <target>>
  <[INTERFACE_HEADERS <header>...]
   [PUBLIC_HEADERS <header>...]
   [PRIVATE_HEADERS <header>...]
   [SOURCES <source>...] >)

After validating and cleaning the paths of the provided sources with jcm_verify_sources(), adds them to the given target, TARGET, using CMake’s built-in target_sources() command and JCM’s jcm_header_file_sets(). Alias targets are supported, unlike target_sources().

This function will:

  • for the detected target type, given by the target’s TYPE property, ensure the appropriate source file types are provided based on the INTERFACE_HEADERS, PUBLIC_HEADERS, and PRIVATE_HEADERS arguments.

  • transform all input file paths into normalized, absolute paths

  • verify the file names as conforming to JCM’s file naming conventions based on the regular expressions in JcmFileNaming.cmake

  • verify the locations of the input files as conforming to the Canonical Project Structure for the given target.

  • create PRIVATE, PUBLIC, and INTERFACE header sets with jcm_header_file_sets() using the respective *_HEADERS parameters and any headers found in SOURCES for executable targets. This is what sets the *INCLUDE_DIRECTORIES properties.

  • Add the files specified by PRIVATE_HEADERS and SOURCES as private target sources via target_sources()

This function is designed for use with both executable and library targets. As such, should the target’s TYPE property be an executable, headers and source files may be provided via the SOURCES argument. For library targets, headers must be provided in the INTERFACE_HEADERS, PUBLIC_HEADERS, and PRIVATE_HEADERS arguments, as header files in SOURCES will be rejected by naming convention filters.

Parameters

Options
WITHOUT_FILE_NAMING_CHECK

When provided, will forgo the default check that provided header and source files conform to JCM’s file naming conventions

One Value
TARGET

Names an existing target onto which the provided source will be added.

Multi Value
INTERFACE_HEADERS

A list of relative or absolute paths to header files required by consumers of the potential target, but not by the target itself. Interface header files, and therefore this parameter, are only meaningful for library targets. Required when TARGET_TYPE is INTERFACE_LIBRARY.

PUBLIC_HEADERS

A list of relative or absolute paths to header files required by consumers of the potential target, and by the target itself. Prohibited when TARGET_TYPE is INTERFACE_LIBRARY.

PRIVATE_HEADERS

A list of relative or absolute paths to header files required exclusively by the target itself; not by consumers of the potential target. Prohibited when TARGET_TYPE is INTERFACE_LIBRARY.

SOURCES

A list of relative or absolute paths to sources files to build the potential target. Prohibited when TARGET_TYPE is INTERFACE_LIBRARY. For executable targets, private header files may be included in this list, and will have the same effect as providing them through PRIVATE_HEADERS. For other target types, any header files found in this parameter will cause an error.

Examples

jcm_add_target_sources(
  TARGET libgeometry::2d
  PUBLIC_HEADERS "shapes.hpp" "intersections.hpp"
  PRIVATE_HEADERS "shape_theory.hpp"
  SOURCES "shapes.cpp" "shape_theory.cpp")
jcm_add_target_sources(
  TARGET netman::netman
  SOURCES
    "main.cpp"
    "cli.hpp"
    "cli.cpp"
    "protocols.hpp"
    "protocols.cpp"
    "buffers.hpp"
    "buffers.cpp"
    "tracing.hpp")

jcm_verify_sources

jcm_verify_sources
jcm_verify_sources(
  [WITHOUT_FILE_NAMING_CHECK]
  [TARGET_TYPE <STATIC_LIBRARY |
                MODULE_LIBRARY |
                SHARED_LIBRARY |
                OBJECT_LIBRARY |
                INTERFACE_LIBRARY |
                EXECUTABLE> ]
  [TARGET_SOURCE_DIR <dir> ]
  [TARGET_BINARY_DIR <dir> ]
  [TARGET_COMPONENT <component>]
  <[INTERFACE_HEADERS <header>...]
   [PUBLIC_HEADERS <header>...]
   [PRIVATE_HEADERS <header>...]
   [SOURCES <source>...] >
  <[OUT_INTERFACE_HEADERS <out-var>]
   [OUT_PUBLIC_HEADERS <out-var>]
   [OUT_PRIVATE_HEADERS <out-var>]
   [OUT_SOURCES <out-var] >)

Primarily an internal function to verify the provided source files for a potential target. Created to factor this repeated verification logic out from jcm_add_library(), jcm_add_executable(), jcm_add_test_executable(), and jcm_add_target_sources(). As such, its operation is important for these “public” functions.

For a potential target of type TARGET_TYPE, source directory TARGET_SOURCE_DIR, and binary directory TARGET_BINARY_DIR, this function will:

  • for the specified target type, ensure the appropriate source file types are provided based on the INTERFACE_HEADERS, PUBLIC_HEADERS, and PRIVATE_HEADERS arguments.

  • transform all input file paths into normalized, absolute paths. The results of which will be available through the output variables specified by OUT_INTERFACE_HEADERS, OUT_PUBLIC_HEADERS, OUT_PRIVATE_HEADERS, and OUT_SOURCES.

  • verify the file names as conforming to JCM’s file naming conventions based on the regular expressions in JcmFileNaming.cmake

  • verify the locations of the input files as within TARGET_SOURCE_DIR or TARGET_BINARY_DIR.

  • remove any headers in SOURCES, appending them to PRIVATE_HEADERS, thereby keeping the OUT_* variable categories pure.

This function is designed for use with both executable and library targets. As such, should the target’s TYPE property be an executable, header files may be provided via the SOURCES argument. For library targets, headers must be provided in the INTERFACE_HEADERS, PUBLIC_HEADERS, and PRIVATE_HEADERS arguments, as header files in SOURCES will be rejected by naming convention filters.

Trusted values for the target’s source and binary directories are taken as opposed to resolving canonical values from a target name to support usage for targets outside of these directories.

Parameters

Options
WITHOUT_FILE_NAMING_CHECK

When provided, will forgo the default check that provided header and source files conform to JCM’s file naming conventions

One Value
TARGET_TYPE

Specifies the type of the potential target - that is, the target’s TYPE property. When omitted, an undefined library will be assumed. This is undefined to allow the various BUILD_SHARED_* options to work as expected. Additionally, this function realistically only changes its behaviour when one of EXECUTABLE or INTERFACE_LIBRARY is specified.

TARGET_SOURCE_DIR

Specifies a relative or absolute path to the the source directory in which the potential target would be created. This surrogates the target’s SOURCE_DIR property. Relative paths are considered with respect to CMAKE_CURRENT_SOURCE_DIR, which is the argument’s default value.

TARGET_BINARY_DIR

Specifies a relative or absolute path to the binary directory for the potential target. This surrogates the target’s BINARY_DIR property. Relative paths are considered CMAKE_CURRENT_BINARY_DIR, which is the argument’s default value.

TARGET_COMPONENT

Specifies the component of the potential target - whether that’s a library component or an executable component, but is only used in this function for executable components. Within JCM, a target’s component is stored in the custom target property, COMPONENT.

OUT_INTERFACE_HEADERS

The variable named will be set to a list of cleaned paths to interface headers for the potential target. This will contain the same number of entries as provided in INTERFACE_HEADERS.

OUT_PUBLIC_HEADERS

The variable named will be set to a list of cleaned paths to public headers for the potential target. This will contain the same number of entries as provided in PUBLIC_HEADERS.

OUT_PRIVATE_HEADERS

The variable named will be set to a list of cleaned paths to private headers for the potential target. For library targets (TARGET_TYPE != EXECUTABLE), this will contain the same number of entries as provided in PRIVATE_HEADERS. For executable targets, this will contain a cleaned path for the entries in SOURCES, and a cleaned path for every header file found in SOURCES.

SOURCES

The variable named will be set to a list of cleaned paths to sources for the potential target. For library targets (TARGET_TYPE != EXECUTABLE), this will contain the same number of entries as provided in SOURCES. For executable targets, this will contain a cleaned path for the entries in SOURCES, excluding the cleaned paths for header files found in SOURCES, which are moved to OUT_PRIVATE_HEADERS.

Multi Value
INTERFACE_HEADERS

A list of relative or absolute paths to header files required by consumers of the potential target, but not by the target itself. Interface header files, and therefore this parameter, are only meaningful for library targets. Required when the target property TYPE of the target TARGET is INTERFACE_LIBRARY.

PUBLIC_HEADERS

A list of relative or absolute paths to header files required by consumers of the potential target, and by the target itself. Prohibited when the target property TYPE of the target TARGET is INTERFACE_LIBRARY.

PRIVATE_HEADERS

A list of relative or absolute paths to header files required exclusively by the target itself; not by consumers of the potential target. Prohibited when the target property TYPE of the target TARGET is INTERFACE_LIBRARY.

SOURCES

A list of relative or absolute paths to sources files to build the potential target. Prohibited when the target property TYPE of the target TARGET is INTERFACE_LIBRARY. For executable targets, private header files may be included in this list, and will have the same effect as providing them through PRIVATE_HEADERS. For other target types, any header files found in this parameter will cause an error.

Examples

# for some library target
jcm_verify_sources(
  INTERFACE_HEADERS "wrappers_windows.hpp" "wrappers.hpp"
  PUBLIC_HEADERS "async_io.hpp" "ply_parser.hpp"
  PRIVATE_HEADERS "os_abstractions.hpp"
  SOURCES "ply_parser.cpp" "os_abstractions.cpp"
  OUT_INTERFACE_HEADERS interface_headers
  OUT_PUBLIC_HEADERS public_headers
  OUT_PRIVATE_HEADERS private_headers
  OUT_SOURCES sources)
# for some executable target
jcm_verify_sources(
  TARGET_TYPE "EXECUTABLE"
  TARGET_SOURCE_DIR "../"
  TARGET_BINARY_DIR "../"
  PRIVATE_HEADERS "game_logic.hpp" "static_assets.hpp"
  SOURCES "main.cpp" "game_logic.cpp" "static_assets.cpp"
  OUT_PRIVATE_HEADERS private_headers
  OUT_SOURCES sources)
# for some executable component target
jcm_verify_sources(
  TARGET_TYPE "EXECUTABLE"
  TARGET_COMPONENT "gui"
  TARGET_SOURCE_DIR "${PROJECT_SOURCE_DIR}/netcat/gui"
  TARGET_BINARY_DIR "${PROJECT_BINARY_DIR}/netcat/gui"
  SOURCES
    "main.cpp"
    "widgets.hpp"
    "widgets.cpp"
    "pages.hpp"
    "pages.cpp"
  OUT_PRIVATE_HEADERS private_headers
  OUT_SOURCES sources)

JcmCreateAccessoryTargets

Module Source on GitHub

Offers functions to create custom, “accessory” targets in a project. Here, “accessory” refers to targets that run development operations, which could be formatting, static analysis, document generation, etc. These targets are not targets offered by a projects, like a library or executable target.


jcm_create_message_target

jcm_create_message_target
jcm_create_message_target(
  NAME <name>
  LEVEL <TRACE|DEBUG|VERBOSE|STATUS|NOTICE|AUTHOR_WARNING|WARNING|SEND_ERROR|FATAL_ERROR>
  MESSAGES <message>...)

Creates a custom target with the name specified by NAME that will emit all of the messages provided to MESSAGES at the given log level, LEVEL. This function and the generated target are used to easily report messages to users from a target at a specific log level. This differs from a target running the echo cmake command (cmake -E echo) because echo only emits messages to stdout, and without log levels. Alternative solutions are to use JcmArbitraryScript directly, or generate a script file in project configuration and create a target that parses it as the command.

Parameters

Options
ALL

Indicate that the created target should be added to the default build target.

One Value
NAME

The name of the custom command to create by invoking this function.

LEVEL

The log level of the messages emitted by the created command.

Multi Value
MESSAGES

The string messages that will be emitted by the created command at the given log level.

Examples

# messages will only be emitted when target is built, not when project is configured
if(MYLIB_SCHEMA_FILES_FOUND)
  add_custom_target(mylib_generate_sources
    COMMAND "command to actually generate sources")
else()
  jcm_create_message_target(
    NAME mylib_generate_sources
    LEVEL FATAL_ERROR
    MESSAGES "Failed to generate sources with the given schema. Schema error ${err_message}")
endif()

jcm_create_clang_format_targets

jcm_create_clang_format_targets
jcm_create_clang_format_targets(
  [QUIET]
  [WITHOUT_TOP_LEVEL_CHECK]
  [SKIP_NONEXISTENT_TARGETS]
  [STYLE_FILE <path>]
  [EXCLUDE_REGEX <regex>]
  [COMMAND <command|target>]
  [ADDITIONAL_PATHS <path>...]
  SOURCE_TARGETS <target>...)

Creates custom targets “clang-format” and “clang-format-check” that invoke the clang::format target, or the provided COMMAND, on all the sources for the provided SOURCE_TARGETS and any additional files within ADDITIONAL_PATHS. All styling is provided by the file STYLE_FILE, which must exist, whether the default value or an explicit value is used.

The created “clang-format” target will format the files in-place, while “clang-format-check” will report any formatting errors to the console and exit with an error. EXCLUDE_REGEX can filter out unwanted source files of targets SOURCE_TARGETS, and will be applied to the files’ absolute paths.

Call find_package(ClangFormat) in order to introduce the clang::format target before using this function. However, clang::format need not be available to use this function. In this situation, the generated “clang-format” and “clang-format-check” targets will emit errors when built, but CMake configuration will not be hindered.

This function has no effect when it is not called in the top-level project, unless WITHOUT_TOP_LEVEL_CHECK is provided.

Parameters

Options
QUIET

Omits the –verbose option to the underlying clang-format executable.

WITHOUT_TOP_LEVEL_CHECK

Causes this function not check if it’s being called in the top-level project.

SKIP_NONEXISTENT_TARGETS

Causes the function to skip over any non-existent targets named in SOURCE_TARGETS. Otherwise, all source targets must exist.

One Value
STYLE_FILE

An optional path to clang-format style file containing the rules used to format the files in the created targets. By default, ${PROJECT_SOURCE_DIR}/.clang-format will be used. The named path will be converted to an absolute, normalized path, and any symlinks will be resolved before providing it to the underlying clang-format command.

EXCLUDE_REGEX

A regular expression used to filter out the sources extracted from the targets named in SOURCE_TARGETS. Paths matching this regex are not provided to clang-format. The regular expression is applied to the absolute, normalized version of the source file paths.

COMMAND

An alternative target or command for clang-format that will be used to format the files. By default, the target clang::format will be used.

Multi Value
ADDITIONAL_PATHS

Additional relative or absolute paths to files or directories which will be provided as input to clang-format. All paths will be converted to absolute paths with respect to CMAKE_CURRENT_SOURCE_DIR. Directories will be expanded into a list of the enclosed files.

SOURCE_TARGETS

Targets whose sources, both header and source files, will be formatted by clang-format.

Examples

jcm_create_clang_format_targets(SOURCE_TARGETS libbbq::libbbq)
jcm_create_clang_format_targets(
  QUIET
  STYLE_FILE .clang-format-14
  COMMAND libbbq::customClangFormat
  SOURCE_TARGETS libbbq:libbbq
  EXCLUDE_REGEX "libbbq_config.hpp$"
  ADDITIONAL_PATHS
    completely/separate/file.hpp
    completely/separate/file.cpp)

jcm_create_doxygen_target

jcm_create_doxygen_target
jcm_create_doxygen_target(
  [README_MAIN_PAGE]
  [SKIP_NONEXISTENT_TARGETS]
  [EXCLUDE_REGEX <regex>]
  [OUTPUT_DIRECTORY <dir>]
  <[SOURCE_TARGETS <target>...]
   [ADDITIONAL_PATHS <path>...] >)

Creates a target, “doxygen-docs”, that generates documentation of the provided SOURCE_TARGETS’s header files and any ADDITIONAL_PATHS using Doxygen. All of the header files in all of the interface header sets of the targets are gathered for Doxygen, with the exception of those that match EXCLUDE_REGEX, if provided.

Doxygen will strip include directories from these paths such that the displayed include commands have the proper include paths and not absolute paths. This function will provide all of the include targets’ INTERFACE_INCLUDE_DIRECTORIES, with any generator expressions removed, as include directories for Doxygen to strip.

The following Doxygen related variables are set by this function:

  • DOXYGEN_STRIP_FROM_INC_PATH

  • DOXYGEN_OUTPUT_DIRECTORY

  • DOXYGEN_USE_MDFILE_AS_MAINPAGE

This function has no effect when <JCM_PROJECT_PREFIX>_ENABLE_DOCS is not set. Ensure to call find_package(Doxygen) before using this function.

Parameters

Options
README_MAIN_PAGE

Sets DOXYGEN_USE_MDFILE_AS_MAINPAGE to the project’s root README.md file, such that Doxygen will use the project’s readme as the main page.

SKIP_NONEXISTENT_TARGETS

Causes the function to skip over any non-existent targets named in SOURCE_TARGETS. Otherwise, all source targets must exist.

One Value
EXCLUDE_REGEX

A regular expression used to filter out the headers extracted from the targets named in SOURCE_TARGETS. The header file absolute paths matching this regex are not provided to Doxygen.

OUTPUT_DIRECTORY

Directory where the documentation will be placed. By default, this is is ${CMAKE_CURRENT_BINARY_DIR}/doxygen.

Multi Value
SOURCE_TARGETS

Targets whose interface header files will be documented by Doxygen

ADDITIONAL_PATHS

Additional relative or absolute paths to files or directories which will be provided as input to Doxygen. All paths will be converted to absolute paths with respect to CMAKE_CURRENT_SOURCE_DIRECTORY. Directories will be passed directly to Doxygen.

Examples

jcm_create_doxygen_target(
  README_MAIN_PAGE
  SOURCE_TARGETS libbbq::libbbq)
jcm_create_doxygen_target(
  README_MAIN_PAGE
  SOURCE_TARGETS libbbq::libbbq libbbq::vegetarian
  EXCLUDE_REGEX "export_macros.hpp$"
  ADDITIONAL_PATHS ../completely/separate/file.hpp)

jcm_create_sphinx_target

jcm_create_sphinx_target
jcm_create_sphinx_target(
  [CONFIGURE_CONF_PY]
  [BUILDER <builder>]
  [COMMAND <command|target>]
  [SOURCE_DIRECTORY <dir>]
  [BUILD_DIRECTORY <dir>])

Creates custom target “sphinx-docs” which invokes the Sphinx::build target, or the provided COMMAND, to generate Sphinx documentation from the default source directory, or SOURCE_DIRECTORY if provided. When CONFIGURE_CONF_PY is set, Sphinx’s configuration file, conf.py, will be generated by configuring an input template, conf.py.in, from the source directory to CMAKE_CURRENT_BINARY_DIR. This will then be provided as configuration directory path to the sphinx command with its -c option.

Call find_package(Sphinx) in order to introduce the Sphinx::build target before using this function. However, Sphinx::build need not be available to use this function. In this situation, the generated “sphinx-docs” target will emit errors when built, but CMake configuration will not be hindered.

This function has no effect when <JCM_PROJECT_PREFIX>_ENABLE_DOCS is not set.

Parameters

Options
CONFIGURE_CONF_PY

When provided, this function will configure Sphinx’s configuration file, conf.py, as described above.

One Value
BUILDER

Sphinx builders specify which type of documentation should be generated. Options include ‘html’, ‘text’, ‘latex’, and more. The default is html.

COMMAND

An alternative target or command that will be used to format the files. By default, the target Sphinx::build will be used.

SOURCE_DIRECTORY

The source directory, where the documentation files live, provided to the sphinx command/target. A relative path will be treated as relative with respect to CMAKE_CURRENT_SOURCE_DIR. Default value is CMAKE_CURRENT_SOURCE_DIR.

BUILD_DIRECTORY

The build directory, where the documentation will be generated, provided to the sphinx command/target. A relative path will be treated as relative with respect to CMAKE_CURRENT_BINARY_DIR. Default value is ${CMAKE_CURRENT_BINARY_DIR}/sphinx

Examples

jcm_create_sphinx_targets(CONFIGURE_CONF_PY)
jcm_create_sphinx_targets(
  CONFIGURE_CONF_PY
  BUILDER "latex"
  BUILD_DIRECTORY "sphinx/latex")

JcmAddOption

Module Source on GitHub

jcm_add_option

jcm_add_option
jcm_add_option(
  [WITHOUT_NAME_PREFIX_CHECK]
  NAME <option-name>
  DESCRIPTION <description>
  TYPE <BOOL|FILEPATH|PATH|STRING|INTERNAL>
  DEFAULT <default-value>
  [CONDITION <condition>
   CONDITION_MET_DEFAULT <default-value-when-met>]
  [ACCEPT_VALUES <value>...])

Adds a project build-option using either set() or cmake_dependent_option(), while providing better type support and validation. Like the CMake built-ins to add options, option() and cmake_dependent_option(), the options introduced by this function are just CACHE variables that can be used to control the project’s configuration. As opposed to using either of those CMake built-ins, this function provides:

  1. Named arguments

  2. Access to both independent and dependent build-options from a single function

  3. Option types including those for dependent options, which cmake_dependent_option() does not support, and types beyond BOOL, which is all that option() supports.

  4. Validation of the option name being both prefixed by ${JCM_PROJECT_PREFIX_NAME}_, and being in SCREAMING_SNAKE_CASE. These provide consistency, clarity, and exclusivity of build options between projects. However, this prefix check can be avoided with WITHOUT_NAME_PREFIX_CHECK, for cases described in the below Parameters.

  5. Restrict the option’s value to one of ACCEPT_VALUES.

Parameters

Options
WITHOUT_NAME_PREFIX_CHECK

Skips the internal assertion that the provided option name, NAME, is prefixed with ${JCM_PROJECT_PREFIX_NAME}_. This would be used to create project agnostic options, like the common BUILD_TESTING. BUILD_TESTING is merely an example, as JCM will handle this specific option internally.

One Value
NAME

The name of the option to create.

DESCRIPTION

A description of the option for builders of the project.

TYPE

The type of the option to create. Must be one of the types available for cache entries: BOOL, FILEPATH, PATH, STRING, or INTERNAL.

DEFAULT

The default value of the option should it not already be set in the CMake cache. This value is also used if CONDITION is provided to this function but is not met.

CONDITION

An optional condition that will make the option a dependent option; dependent upon the provided condition. When provided, CMake’s cmake_dependent_option will be used in place of set() to create the option.

CONDITION_MET_DEFAULT

The default value of the option when CONDITION is provided to this function and the condition is met. Like DEFAULT, when a value for the option already exists in the cache, it will be used in place of this default.

Multi Value
ACCEPT_VALUES

Acceptable values of the created option. When provided, the STRINGS property on the created cache entry will be set, and a fatal error will be emitted if the value of this option is not one of these declared values.

Examples

jcm_add_option(
  NAME ${PROJECT_NAME}_ENABLE_INTEGRATION_TESTS
  DESCRIPTION "Enables the automated integration tests"
  TYPE BOOL
  DEFAULT ${PROJECT_NAME})
jcm_add_option(
  NAME ${PROJECT_NAME}_COMPRESSION_BACKEND
  DESCRIPTION "Selects the compression backend to use for transport compression"
  TYPE STRING
  DEFAULT "NONE"
  CONDITION "${PROJECT_NAME}_ENABLE_TRANSPORT_LAYER"
  ACCEPT_VALUES "NONE;ZIP;BROTLI;LZ")
jcm_add_option(
  NAME BUILD_SHARED_LIBS
  DESCRIPTION "Build libraries with unspecified types shared."
  WITHOUT_NAME_PREFIX_CHECK
  TYPE BOOL
  DEFAULT OFF)

jcm_add_option(
  NAME ${JCM_PROJECT_PREFIX_NAME}_BUILD_SHARED_LIBS
  DESCRIPTION "Build libraries of project ${PROJECT_NAME} with unspecified types shared."
  TYPE BOOL
  DEFAULT ${BUILD_SHARED_LIBS})

jcm_add_component_options

jcm_add_component_options
jcm_add_component_options(
  [REQUIRED_COMPONENTS <component>...]
  [DEFAULT_OFF_COMPONENTS <component>...]
  <OPTIONAL_COMPONENTS <component>...>
  <[OUT_COMPONENTS <out-var>] >
   [OUT_TARGETS <out-targets>] >
  [<COMPONENT_DEPENDENCIES_JSON <json> 
  <MISSING_DEPENDENCY_ACTION <ENABLE|ERROR> > ])

Creates build options with jcm_add_option() named ${JCM_PROJECT_PREFIX_NAME}_ENABLE_<component>, where component is the name of a standard project component, i.e a library or executable component. An option will be for every component in the list OPTIONAL_COMPONENTS. The result variables will contain all optional components that have been enabled by their respective build option, and all required components; those named in REQUIRED_COMPONENTS.

Every project component produces a single installed target. Targets can be selectively built by CMake with the command-line option –target, such as cmake –build build –target libcomponents_libcomponents-core, which will exclusively build the core component of project libcomponents. However, the configuration of undesired components may also be worth avoiding if their configuration is very long or introduces additional dependencies. For example, if the extra component of libcomponents requires eight dependencies that aren’t required by core, users of core may not want to acquire dependencies they don’t use. For this purpose, project options can be introduced to selectively configure project components.

This function is merely a wrapper around :cmake:command`jcm_add_option` adding simplicity and consistency for the use-case. Using this function does not preclude creating any project options through other means, nor do all project components need to be provided to this function.

Component names cannot have any regex characters in them

Parameters

Option
OUT_COMPONENTS

The variable named will be set to the list of enabled components.

One Value
OUT_COMPONENTS

The variable named will be set to the list of enabled components.

OUT_TARGETS

The variable named will be set to the list of enabled targets derived from the enabled components by prefixing each with ${PROJECT_NAME}::.

COMPONENT_DEPENDENCIES_JSON

Optional string containing a JSON document detailing the components dependencies on one another. The document structure is an object where keys are names of optional components, and values are arrays of component names. When the component named by one of the object entries is enabled by its respective build option, all the build options for the components named in the value array will also be enabled. Although unnecessary, required component can be named in the value array.

This argument must be accompanied by MISSING_DEPENDENCY_ACTION.

MISSING_DEPENDENCY_ACTION

Optional literal of either ERROR or ENABLE indicating what action will be taken when a component named in COMPONENT_DEPENDENCIES_JSON is enabled but a dependency in its dependency array is not. A value of ENABLE will set the project option of the disabled dependency component to enable it. A value of ERROR will emit a fatal error.

This argument must be accompanied by COMPONENT_DEPENDENCIES_JSON.

Multi Value
OPTIONAL_COMPONENTS

Required list of optional project components that will have build options created for them.

REQUIRED_COMPONENTS

Optional list of project components that are always configured and do not have respective options to disable them. The components named are always considered “enabled” and will appear unaltered in the variable named by OUT_COMPONENTS. This option is included to declaratively indicate which components are required by a project, and make downstream handling of enabled components simpler.

DEFAULT_OFF_COMPONENTS

Optional list of optional project components who’s associated project option will be created with a default value of OFF instead of ON. As such, configuring a project using its default options will not enable the components named in this list. Builders will have to explicitly enable them through their respective project option.

Examples

jcm_add_component_options(
  REQUIRED_COMPONENTS "core"
  OPTIONAL_COMPONENTS "io" "extra"
  DEFAULT_OFF_COMPONENTS "extra"
  OUT_COMPONENTS enabled_components)
jcm_add_component_options(
  REQUIRED_COMPONENTS "core"
  OPTIONAL_COMPONENTS "io" "extra"
  DEFAULT_OFF_COMPONENTS "extra"
  OUT_COMPONENTS enabled_components
  MISSING_DEPENDENCY_ACTION "ENABLE"
  COMPONENT_DEPENDENCIES_JSON [=[ 
    {
      "extra": [ "io", "core" ],
      "io": [ "core" ]
    }
  ]=])

JcmBasicPackageConfig

Module Source on GitHub

Provides macros to create Config-file Packages. Offers the jcm_basic_package_config() macro for top-level config-files, and the jcm_basic_component_config() macro for config-files of individual components.

The utilities here follow a pattern of each target providing its on config-file and targets-file. This makes managing inter-project dependencies very easy and simplifies overall logic.


jcm_basic_package_config

jcm_basic_package_config
jcm_basic_package_config(
  <project>
  [NO_TARGETS])

Provides all CMake commands that are required in a package config-files to create relocatable, config-file packages. Call this macro at the end of your package config-file template (<project>-config.cmake.in), after @PACKAGE_INIT@.

This macro will:

  • include the associated targets file from the current list directory, if NO_TARGETS is omitted

  • include the config files for the components requested by the consumer’s find_package() call, or all of those installed, if no components are explicitly requested. Requested components of ${project} are ignored.

  • if any CMake modules not corresponding to config-file packages (not config files, targets files, or version files…) exist in CMAKE_CURRENT_LIST_DIR, the directory will be appended to CMAKE_MODULE_PATH so consumers have access to these additional modules.

  • call check_required_components(), as KitWare recommends at the end of every package config-file. To get this macro in PACKAGE_INIT, ensure your config-file template is configured through configure_package_config_file(), or preferrably enable configuring in jcm_install_config_file_package().

Parameters

Positional
project

The name of the project being packaged. Don’t use ${PROJECT_NAME}, as this will resolve to the consuming project’s name.

One Value
NO_TARGETS

Indicates that this package does not provide any CMake targets at the top-level, causing this macro to skip inclusion of a targets file (<project>-targets.cmake). Consider a CMake library, for instance, or a library with components providing their own targets files.

Examples

Most package config files will take this form.

libvideo-config.cmake.in
@PACKAGE_INIT@

include(CMakeFindDependencyMacro)
find_dependency(jgd-cmake-modules CONFIG REQUIRED)

include(JcmBasicPackageConfig)
jcm_basic_package_config(@PROJECT_NAME@)

jcm_basic_component_config

jcm_basic_component_config
jcm_basic_component_config(
  <project>
  <component>
  [REQUIRED_COMPONENTS <component>...]
  [NO_TARGETS])

Provides all CMake commands that are required in a package config-file of an individual project component (<project>-<component>-config.cmake).

This macro will:

  • include the config-files of any dependent components

  • include the current component’s associated targets file from the current list directory

  • set the component’s associated <project>_<component>_FOUND variables that check_required_components() uses.

Parameters

Positional
project

The name of the project being packaged. Don’t use ${PROJECT_NAME}, as this will resolve to the consuming project name.

component

The name of the component provided by this config-file.

One Value
NO_TARGETS

Indicates that this package does not provide any CMake targets, causing this macro to skip inclusion of a targets file (<project>-<component>-targets.cmake). The requirement for the presence of the expected target will also be skipped before setting <project>_<component>_FOUND to TRUE.

Multi Value
REQUIRED_COMPONENTS

Other components of the same project that this component depends upon.

Examples

Most package config files will take this form. Examples represent the components’ config-files for a fantasy project, libvideo, offering components core, compression, stream, and freemium.

libvideo-core-config.cmake.in
jcm_basic_component_config(@PROJECT_NAME@ core)
libvideo-compression-config.cmake.in
jcm_basic_component_config(@PROJECT_NAME@ compression REQUIRED_COMPONENTS core)
libvideo-stream-config.cmake.in
jcm_basic_component_config(@PROJECT_NAME@ stream REQUIRED_COMPONENTS core compression)
libvideo-freemium-config.cmake.in
jcm_basic_component_config(@PROJECT_NAME@ freemium REQUIRED_COMPONENTS core)

JcmInstallConfigFilePackage

Module Source on GitHub

jcm_install_config_file_package

jcm_install_config_file_package
jcm_install_config_file_package(
  [CONFIGURE_PACKAGE_CONFIG_FILES]
  <[TARGETS <target>...]
   [CMAKE_MODULES <path>...]
   [INSTALL_LICENSES] >)

Provides ability to consistently and reliably create a project’s config-file package install rules in one command. All of the named TARGETS, CMAKE_MODULES, and licenses will be installed to paths provided by GNUInstallDirs with appropriate package config-files, version file, and targets files. Package config-files will be installed from JCM_PROJECT_CMAKE_DIR or JCM_INSTALL_CMAKE_DESTINATION if they were configured with some derivative of configure_file().

Each target will be installed with an associated targets file. The target will be exported within the namespace ${PROJECT_NAME}::, which includes the key “::” characters and follows common conventions. Executables and shared libraries will be installed under the install component ${PROJECT_NAME}_runtime, while static libraries and headers in the target’s INTERFACE and PUBLIC header sets will be installed under the ${PROJECT_NAME}_devel install component. This supports separate runtime and development packages often distributed by package managers. Alias targets are supported (libsample::libsample).

CMAKE_MODULES will be installed under the ${PROJECT_NAME}_devel install component. If any of the paths in this list name a directory, the directory will be expanded to a list of all enclosed files ending in .cmake. Relative paths are converted to absolute paths with respect to CMAKE_CURRENT_SOURCE_DIR.

Licenses are installed under JCM_INSTALL_DOC_DIR. Both a root LICENSE.* file and licenses within JCM_PROJECT_LICENSES_DIR will be installed. Symlinks are followed until a file is reached, ensuring to install the license file with the original name of the symlink. Intermediate symlinks are not installed.

The following project options are created:

<JCM_PROJECT_PREFIX_NAME>_ENABLE_INSTALL

Boolean controlling whether the install rules produced by this function are generated or not. The default value is that of PROJECT_IS_TOP_LEVEL, meaning installation rules are generated when the project is top-level. Whether or not the project is top-level, use this option to override this behaviour, such as generating install rules when the project is not top-level.

<JCM_PROJECT_PREFIX_NAME>_INSTALL_VERSIONED_PATHS

Boolean controlling whether the install rules produced by this function will install to versioned paths or not. This does not affect the config-file package’s version-file which is always installed. The default value is ON, meaning installation paths will include the project’s version (supported by CMake’s find_package). This allows installing multiple versions of the same project in the same installation root, and prevents overwriting existing installations of the same project. When turned OFF, the UNVERSIONED variants of the variables dictating install destinations from JcmStandardDirs will be used in place of those mentioned above. For example: JCM_INSTALL_DOC_DIR -> JCM_UNVERSIONED_INSTALL_DOC_DIR.

Parameters

Options
CONFIGURE_PACKAGE_CONFIG_FILES

When provided, the config-files will be configured using jcm_configure_package_config_file()

INSTALL_LICENSES

Causes this function to install licenses from the paths described above. Should there be no licenses in these paths, an author warning will be emitted and installation of other files will continue without hindrance.

Multi Value
TARGETS

A list of targets to install.

CMAKE_MODULES

Relative or absolute paths to additional CMake modules, or directories containing CMake modules, to install.

Examples

jcm_install_config_file_package(TARGETS libbbq::libbbq)
jcm_install_config_file_package(
  CONFIGURE_PACKAGE_CONFIG_FILES
  INSTALL_LICENSES
  TARGETS libbbq::core libbbq::meat libbbq::veg
  CMAKE_MODULES "${JCM_PROJECT_CMAKE_DIR}")

JcmDefaultCompileOptions

Module Source on GitHub

Defines variables with default compile options for common compilers. These are used to initialize the COMPILE_OPTIONS properties when library or executable targets are created with JCM functions. Of course, like any of the defaults introduced by JCM, these can easily be overridden on the target after it’s created.

Note

Only CXX_COMPILER_ID and C_COMPILER_ID are currently considered. This is to be extended to other languages

The following variables are defined:

JCM_DEFAULT_CXX_COMPILE_OPTIONS_GNU

-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Weffc++ -Wno-non-virtual-dtor

JCM_DEFAULT_C_COMPILE_OPTIONS_GNU

-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion

JCM_DEFAULT_CXX_COMPILE_OPTIONS_CLANG

Same as JCM_DEFAULT_CXX_COMPILE_OPTIONS_GNU

JCM_DEFAULT_C_COMPILE_OPTIONS_CLANG

Same as JCM_DEFAULT_C_COMPILE_OPTIONS_GNU

JCM_DEFAULT_CXX_COMPILE_OPTIONS_MSVC

/W4 /WX

JCM_DEFAULT_C_COMPILE_OPTIONS_MSVC

Same as JCM_DEFAULT_CXX_COMPILE_OPTIONS_MSVC

JCM_DEFAULT_COMPILE_OPTIONS

A generator expression that will resolve to the appropriate set of the variables above based on the compiler and language. This is used to initialize targets’ COMPILE_OPTIONS.


JcmTargetNaming

Module Source on GitHub

jcm_library_naming

jcm_library_naming
jcm_library_naming(
  [PROJECT <project-name>]
  [COMPONENT <component>]
  <[OUT_TARGET <target>]
   [OUT_EXPORT_NAME <out-var>]
   [OUT_OUTPUT_NAME <out-var>] >)

Sets the output variable specified by the OUT_* arguments to default, consistent, unique library names that libraries can use to initialize their naming properties.

Parameters

One Value
PROJECT

The project to which the library belongs. The project name is used in the library names to ensure uniqueness in super-builds. PROJECT_NAME will be used by default.

COMPONENT

The project component that this library represents. The component is used in the library names.

OUT_TARGET

The variable named will be set to the resultant target name for a library of the specified project that provides the specified component.

OUT_EXPORT_NAME

The variable named will be set to the resultant export name for the library, that should be used to initialize the EXPORT_NAME target property.

OUT_OUTPUT_NAME

The variable named will be set to the resultant export name for the library, that should be used to initialize the OUTPUT_NAME target property.


jcm_executable_naming

jcm_executable_naming
jcm_executable_naming(
  [PROJECT <project-name>]
  [COMPONENT <component>]
  <OUT_TARGET <target>
   OUT_EXPORT_NAME <out-var>
   OUT_OUTPUT_NAME <out-var>>)

Sets the output variable specified by the OUT_* arguments to default, consistent, unique executables names that executables can use to initialize their naming properties.

Parameters

One Value
PROJECT

The project to which the executable belongs. The project name is used in the executable names to ensure uniqueness in super-builds. PROJECT_NAME will be used by default.

COMPONENT

The project component that this executable represents. The component is used in the executable names.

OUT_TARGET

The variable named will be set to the resultant target name for an executable of the specified project that provides the specified component.

OUT_EXPORT_NAME

The variable named will be set to the resultant export name for the executable, that should be used to initialize the EXPORT_NAME target property.

OUT_OUTPUT_NAME

The variable named will be set to the resultant export name for the executable, that should be used to initialize the OUTPUT_NAME target property.


jcm_target_type_component_from_name

jcm_target_type_component_from_name
jcm_target_type_component_from_name(
  [PROJECT <project-name>]
  TARGET_NAME <target>
  <[OUT_TYPE <target>]
   [OUT_COMPONENT <out-var>] >)

JCM’s target naming conventions denote both the the target’s type and component within the naming structure. This function will, considering the project name, compute the target type and component from a given target name. The named target doesn’t have to exist.

Parameters

One Value
PROJECT

The project to which the target belongs. Since project names are embedded within target names, it must be known in deduction. PROJECT_NAME will be used by default.

TARGET_NAME

A target name following JCM’s target naming conventions that the target type and component will be computed from.

OUT_TYPE

The variable named will store the computed target type

OUT_COMPONENT

The variable named will store the computed component or an empty string if the target is not a project component.

Examples

jcm_target_type_component_from_name(
  PROJECT libssh
  TARGET_NAME libssh::libssh
  TARGET_TYPE type
  TARGET_COMPONENT component)

jcm_aliased_target

jcm_aliased_target
jcm_aliased_target(
  TARGET <target>
  OUT_TARGET <out-var>)

Recursively searches the chain of alias targets named by TARGET until a non-alias target is found. The name of the first non-alias target encountered in this search will be placed in the variable specified by OUT_TARGET. Consequently, the resulting target name will be that of a non-alias target. Should TARGET not be an alias target, it’s name will simply be the result. A fatal error will be emitted if any target name in this search does not name an actual target.

Parameters

One Value

TARGET

OUT_TARGET

Examples

jcm_aliased_target(
  TARGET libformat::io
  OUT_TARGET aliased_target)

message(STATUS "libformat_libformat-io == ${aliased_target}")

JcmFileNaming

Module Source on GitHub

Provides variables and functions to help enforce file naming conventions.

For each of the enabled languages at the point of inclusion, as per the global ENABLED_LANGUAGES property, the following variables are defined. These contain regular expressions for suitable file names for the given language. Supported languages are currently C,CXX,CUDA,OBJC,OBJCXX,HIP

  • JCM_<LANG>_HEADER_REGEX

  • JCM_<LANG>_SOURCE_REGEX

  • JCM_<LANG>_UTEST_SOURCE_REGEX

The following variables provide cumulative regular expressions for all the enabled languages encountered to the point of inclusion. These are built by joining the variables above with the ‘|’ character.

  • JCM_HEADER_REGEX

  • JCM_SOURCE_REGEX

  • JCM_UTEST_SOURCE_REGEX

Additional, non-languages specific variables with regular expressions for file names are introduced:

  • JCM_CMAKE_MODULE_REGEX. This is for normal CMake modules, not package-config files.

  • JCM_IN_FILE_REGEX

  • JCM_CXX_MODULE_REGEX


jcm_package_config_file_name

jcm_package_config_file_name
jcm_package_config_file_name(
  [PROJECT <project>]
  [COMPONENT <component>]
  OUT_VAR <out-var>
)

Constructs a consistent kebab-case package configuration file name based on the PROJECT, which defaults to PROJECT_NAME, and COMPONENT, if provided. The resulting file name will be placed in the variable specified by OUT_VAR. Result will be <PROJECT>-[COMPONENT-]config.cmake.

Parameters

One Value
PROJECT

The project that the config-file packages, if the default value of PROJECT_NAME is not correct.

COMPONENT

Specifies the component that the file will describe. A COMPONENT that matches PROJECT_NAME or PROJECT will be ignored.

OUT_VAR

The variable named will be set to the resultant file name

Examples

# PROJECT_NAME is libgarden
# file_name will be libgarden-config.cmake
jcm_package_config_file_name(OUT_VAR file_name)
# file_name will be libimage-core-config.cmake
jcm_package_config_file_name(
  PROJECT libimage
  COMPONENT core
  OUT_VAR file_name
)

jcm_package_version_file_name

jcm_package_version_file_name
jcm_package_version_file_name(
  [PROJECT <project>]
  OUT_VAR <out-var>
)

Constructs a consistent kebab-case package version file name based on the PROJECT, which defaults to PROJECT_NAME. The resulting file name will be placed in the variable specified by OUT_VAR. Result will be <PROJECT>-version.cmake.

Parameters

One Value
PROJECT

The project that the version file represents, if the default value of PROJECT_NAME is not correct.

OUT_VAR

The variable named will be set to the resultant file name

Examples

# PROJECT_NAME is libgarden
# file_name will be libgarden-version.cmake
jcm_package_version_file_name(OUT_VAR file_name)

jcm_package_targets_file_name

jcm_package_targets_file_name
jcm_package_targets_file_name(
  [PROJECT <project>]
  [COMPONENT <component>]
  OUT_VAR <out-var>
)

Constructs a consistent kebab-case package targets file name based on the PROJECT, which defaults to PROJECT_NAME, and COMPONENT, if provided. The resulting file name will be placed in the variable specified by OUT_VAR. Result will be <PROJECT>-[COMPONENT-]targets.cmake. The target’s file naming scheme includes a component because JCM installs one targets file per target for simpler management.

Parameters

One Value
PROJECT

The project that the targets file contains targets for, if the default value of PROJECT_NAME is not correct.

COMPONENT

Specifies the component that the file will describe. A COMPONENT that matches PROJECT_NAME or PROJECT will be ignored.

OUT_VAR

The variable named will be set to the resultant file name

Examples

# PROJECT_NAME is libgarden
# file_name will be libgarden-targets.cmake
jcm_package_targets_file_name(OUT_VAR file_name)
# file_name will be libimage-core-targets.cmake
jcm_package_targets_file_name(
  PROJECT libimage
  COMPONENT core
  OUT_VAR file_name
)

JcmCanonicalStructure

Module Source on GitHub

Specifications in Canonical Project Structure, implemented in CMake. This modules concerns itself with source subdirectories, include directories, the ‘lib’ prefix, and file extensions. Actual file naming is implemented in JcmFileNaming, which uses the file extensions defined here.

Note

This module is often just an implementation detail of JCM, and doesn’t need to be used directly.

Variables

The file extensions specified by the Canonical Project Structure have been extended for the CMake recognized languages of CXX, C, CUDA, OBJC, OBJCXX, and HIP.

JCM_LIB_PREFIX

The prefix used throughout JCM for libraries. Used in project names and when naming targets. Set as ‘lib’ from Canonical Project Structure.

JCM_IN_FILE_EXTENSION

File extension used for input files that will undergo substitution through some version of configure_file(). This is a custom file extension for JCM, placed here for unity.

JCM_<LANG>_HEADER_EXTENSION

File extension for header files. ‘.hpp’ option selected from Canonical Project Structure for C++

JCM_<LANG>_SOURCE_EXTENSION

File extension for source files. ‘.cpp’ option selected from Canonical Project Structure for C++

JCM_<LANG>_UTEST_SOURCE_EXTENSION

File extension for unit testing source files. ‘.test.cpp’ option selected from Canonical Project Structure for C++

JCM_CXX_MODULE_EXTENSION

File extension for module interface files. ‘.mpp’ option selected from Canonical Project Structure

JCM_PROJECT_CANONICAL_SUBDIR_PREFIX_REGEX

A regular expression describing the path prefix for every canonical subdirectory for the current project, given by PROJECT_NAME. An absolute, normalized path matching this regular expression is a canonical subdirectory for the current project.


jcm_canonical_subdir

jcm_canonical_subdir
jcm_canonical_subdir(
  OUT_VAR <out-var>
  TARGET <target>)

Sets the variable specified by OUT_VAR to the canonical source subdirectory for either an executable or library of project PROJECT_NAME. Calls either jcm_canonical_lib_subdir() or jcm_canonical_exec_subdir() based on the target TYPE property, or the deduced type from the target name, if the target is not yet created.

Parameters

One Value
OUT_VAR

The variable named will be set to the computed subdirectory

TARGET

The name of the target for which the path will be computed.

Examples

ssh/CMakeLists.txt
project(ssh VERSION 0.0.0)
...
jcm_canonical_subdir(OUT_VAR ssh_subdir TARGET ssh::ssh)
message(STATUS "${ssh_subdir}") # ssh/ssh
ssh/CMakeLists.txt
project(ssh VERSION 0.0.0)
...
jcm_canonical_subdir(OUT_VAR cli_subdir TARGET ssh::cli)
message(STATUS "${cli_subdir}") # ssh/ssh/cli

jcm_canonical_lib_subdir

jcm_canonical_lib_subdir
jcm_canonical_lib_subdir(
  OUT_VAR <out-var>
  [COMPONENT <component>])

Sets the variable specified by OUT_VAR to the canonical source subdirectory for a library of project PROJECT_NAME. In the following descriptions, name is the PROJECT_NAME without any lib prefix (libproj -> proj).

When COMPONENT is omitted, the output will be the canonical project path for a single library of PROJECT_NAME, regardless of if PROJECT_NAME names a library or executable. The resulting path is absolute, and will be /<JCM_LIB_PREFIX><name>, with respect to PROJECT_SOURCE_DIR.

When COMPONENT is provided, the output will name a library component, considering the PROJECT_NAME and the COMPONENT argument. The resulting path is absolute, and will be /<JCM_LIB_PREFIX><name>-<COMPONENT>/<JCM_LIB_PREFIX><name>/<COMPONENT>, with respect to the PROJECT_SOURCE_DIR.

Parameters

One Value
OUT_VAR

The variable named will be set to the computed subdirectory

COMPONENT

The name of the library component for which the path will be computed.

Examples

libdecorate/CMakeLists.txt
project(libdecorate VERSION 0.0.0)
...
jcm_canonical_lib_subdir(OUT_VAR main_library_subdir)
message(STATUS "${main_library_subdir}") # libdecorate/libdecorate
libdecorate/CMakeLists.txt
project(libdecorate VERSION 0.0.0)
...
jcm_canonical_lib_subdir(OUT_VAR paint_subdir COMPONENT paint)
message(STATUS "${paint_subdir}") # libdecorate/libdecorate-paint/libdecorate/paint

jcm_canonical_lib_subdir(OUT_VAR restore_subdir COMPONENT restore)
message(STATUS "${restore_subdir}") # libdecorate/libdecorate-restore/libdecorate/restore
decorate/CMakeLists.txt
project(decorate VERSION 0.0.0)
...
jcm_canonical_lib_subdir(OUT_VAR library_subdir)
message(STATUS "${library_subdir}") # libdecorate/libdecorate
decorate/CMakeLists.txt
project(decorate VERSION 0.0.0)
...
jcm_canonical_lib_subdir(OUT_VAR paint_subdir COMPONENT paint)
message(STATUS "${paint_subdir}") # libdecorate/libdecorate-paint/libdecorate/paint

jcm_canonical_lib_subdir(OUT_VAR restore_subdir COMPONENT restore)
message(STATUS "${restore_subdir}") # libdecorate/libdecorate-restore/libdecorate/restore

jcm_canonical_exec_subdir

jcm_canonical_exec_subdir
jcm_canonical_exec_subdir(
  OUT_VAR <out-var>
  [COMPONENT <component>])

Sets the variable specified by OUT_VAR to the canonical source subdirectory for an executable of project PROJECT_NAME. In the following descriptions, name is the PROJECT_NAME without any lib prefix (libproj -> proj).

When COMPONENT is omitted, the output is the canonical project path for a single executable of PROJECT_NAME, regardless of if PROJECT_NAME names a library or executable. The resulting path is absolute, and will be /<name>, with respect to PROJECT_SOURCE_DIR,

When COMPONENT is provided, the output is the canonical project path for an executable component, considering the PROJECT_NAME and the COMPONENT argument, regardless of if PROJECT_NAME names a library or executable. The resulting path is absolute, and will be /<name>/<COMPONENT>, with respect to PROJECT_SOURCE_DIR.

Parameters

One Value
OUT_VAR

The variable named will be set to the computed subdirectory

COMPONENT

The name of the executable component for which the path will be computed.

Examples

ssh/CMakeLists.txt
project(ssh VERSION 0.0.0)
...
jcm_canonical_exec_subdir(OUT_VAR ssh_subdir)
message(STATUS "${ssh_subdir}") # ssh/ssh
libdecorate/CMakeLists.txt
project(libdecorate VERSION 0.0.0)
...
jcm_canonical_exec_subdir(OUT_VAR decorate_subdir)
message(STATUS "${decorate_subdir}") # libdecorate/decorate

jcm_canonical_include_dirs

jcm_canonical_include_dirs
jcm_canonical_include_dirs(
  [WITH_BINARY_INCLUDE_DIRS]
  OUT_VAR <out-var>
  TARGET <target>)

Sets the variable specified by OUT_VAR to a list containing the canonical include directories for the target named by TARGET.

The provided target’s SOURCE_DIR, TYPE, and COMPONENT properties will be queried to resolve the target’s include directory in the source tree. This will be one or two parent directories above the target’s canonical source directory to establish the include prefix of <PROJECT_NAME>, or <PROJECT_NAME>/<COMPONENT> when the target is a component. Binary directories PROJECT_BINARY_DIR and, when the target is a component, ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-<COMPONENT> can be appended to the result for generated headers by providing WITH_BINARY_INCLUDE_DIRS

Parameters

Options
WITH_BINARY_INCLUDE_DIRS

Append the appropriate binary include directories for the provided TARGET, while considering its COMPONENT property, to the result.

One Value
OUT_VAR

The variable named will be set to a list of the computed include directories.

TARGET

The name of the target to resolve the canonical include directories for.

Examples

jcm_canonical_include_dirs(
  TARGET libcup::libcup
  OUT_VAR source_include_dirs)

message(STATUS "${source_include_dirs} == ${PROJECT_SOURCE_DIR}")
jcm_canonical_include_dirs(
  TARGET libcup::mug
  OUT_VAR source_include_dirs)

message(STATUS "${source_include_dirs} == ${PROJECT_SOURCE_DIR}/libcup-mug")
jcm_canonical_include_dirs(
  WITH_BINARY_INCLUDE_DIRS
  TARGET libcup::mug
  OUT_VAR include_dirs)

message(STATUS
  "${include_dirs} MATCHES ${PROJECT_SOURCE_DIR}/libcup-mug"
  "${include_dirs} MATCHES ${PROJECT_BINARY_DIR}/libcup-mug"
  "${include_dirs} MATCHES ${PROJECT_BINARY_DIR}")

JcmConfigureFiles

Module Source on GitHub

Use-case specific configure functions, like CMake’s configure_file() (link), but with features for their respective use-case.

All input file names are simply the output file name with JCM_IN_FILE_EXTENSION (.in) appended.


jcm_configure_package_config_file

jcm_configure_package_config_file
jcm_configure_package_config_file(
  [TARGET <target> | COMPONENT <component>]
  [OUT_FILE_VAR <out-var>])

Configures the package config-file for the project or for a project component when either TARGET or COMPONENT is provided. The input and out config file names and locations are internally determined from jcm_package_config_file_name(), JCM_PROJECT_CMAKE_DIR, and JCM_CMAKE_DESTINATION.

Configuration occurs via CMake’s configure_package_config_file(), such that the configured files have access to the PACKAGE_INIT variable substitution.

Directly use this function to configure package config-files, or commission it from jcm_install_config_file_package() with parameter CONFIGURE_PACKAGE_CONFIG_FILES.

Parameters

One Value
TARGET

Target which the configured config-file represents. This target’s COMPONENT property will be extracted to compute the appropriate config-file name. Prefer this if the target is available.

COMPONENT

Project component which the configured config-file represents, used in conjunction with PROJECT_NAME to compute the appropriate config-file name. Use this if the respective target is unavailable.

OUT_FILE_VAR

The named variable will be set to the absolute path of the output file.

Examples

# configure's project's top-level config-file using PROJECT_NAME

jcm_configure_package_config_file()
# configure's libiceream::toppings's config-file

jcm_configure_package_config_file(TARGET libicecream::toppings)
# same as above - PROJECT_NAME is libicecream

jcm_configure_package_config_file(COMPONENT toppings)

jcm_configure_file

jcm_configure_file
jcm_configure_file(
  IN_FILE <file>
  [OUT_FILE_VAR <out-var>]
  [DEST_DIR <dest-dir>])

Configures the file specified by IN_FILE, just like CMake’s configure_file(), but follows JCM’s input-file naming conventions, has richer error checks and messages, uses @ uses substitution only.

The output file will be computed by removing the file extension JCM_IN_FILE_EXTENSION from IN_FILE and configuring the file to DEST_DIR (default CMAKE_CURRENT_BINARY_DIR), replacing @ variables, only. Like configure_file(), relative input paths are treated with respect to CMAKE_CURRENT_SOURCE_DIR.

Use this function when configuring various files for which there is not a specific configure function for, such as headers and sources.

Parameters

One Value
IN_FILE

A relative or absolute path to the input config-file template. Relative paths will be computed relative to CMAKE_CURRENT_SOURCE_DIR, and all paths will be normalized.

OUT_FILE_VAR

The variable named will be set to the absolute, normalized file path of the output file

DEST_DIR

A relative or absolute path to the directory into which the configured file will be placed. Relative paths will be computed relative to CMAKE_CURRENT_BINARY_DIR, and all paths will be normalized. When omitted, the default value of CMAKE_CURRENT_BINARY_DIR will be used.

Examples

jcm_configure_file(IN_FILE my_config.hpp.in)
jcm_configure_file(
  IN_FILE my_config.hpp.in # WRT CMAKE_CURRENT_SOURCE_DIR
  DEST_DIR "gen"           # WRT CMAKE_CURRENT_BINARY_DIR
  OUT_FILE_VAR generated_file)
jcm_configure_file(
  IN_FILE my_config.hpp.in # WRT CMAKE_CURRENT_SOURCE_DIR
  DEST_DIR "gen"           # WRT CMAKE_CURRENT_BINARY_DIR
  OUT_FILE_VAR generated_file)

jcm_configure_vcpkg_manifest_file

jcm_configure_vcpkg_manifest_file
jcm_configure_vcpkg_manifest_file()

Configures a config template of a vcpkg manifest file located in JCM_PROJECT_CMAKE_DIR to PROJECT_SOURCE_DIR, using @ substitution, only. This function provides consistency of configuring vcpkg manifests across projects, and has no effect if the project is not the top-level project. Furthermore, seeing as this function merely configures a file, it doesn’t prescribe vcpkg as the dependency manager, or the use of vcpkg in any capacity.

Using the vcpkg toolchain file to operate in manifest mode will invoke vcpkg with the project’s manifest file before configuring the project. As such, adding dependencies to the template won’t be found by find_package() because vcpkg will have already run by the time this function configures the manifest file, and will therefore not have installed them. Simply configure the project again, and the updated manifest file will be available for vcpkg.

Examples

jcm_configure_vcpkg_manifest_file()

JcmParseArguments

Module Source on GitHub

jcm_parse_arguments

jcm_parse_arguments
jcm_parse_arguments(
  [WITHOUT_MISSING_VALUES_CHECK]
  [WITHOUT_UNPARSED_CHECK]
  [PREFIX <prefix>]
  <[OPTIONS <keyword>...]
   [ONE_VALUE_KEYWORDS <keyword>..]
   [MULTI_VALUE_KEYWORDS <keyword>...] >
  [REQUIRES_ALL <keyword>...]
  [REQUIRES_ANY <keyword>...]
  [REQUIRES_ANY_<n> <keyword>...]
  [MUTUALLY_EXCLUSIVE <keyword>..]
  [MUTUALLY_EXCLUSIVE_<n> <keyword>..]
  [MUTUALLY_INCLUSIVE <keyword>..]
  [MUTUALLY_INCLUSIVE_<n> <keyword>..]
  ARGUMENTS <arg>...)

A wrapper around CMake’s cmake_parse_arguments() that provides sensible defaults, named arguments, and handles argument validation. Errors will result in fatal errors being emitted.

Parameters

Options
WITHOUT_MISSING_VALUES_CHECK

When provided, this macro will not check for keywords with missing values in ARGUMENTS

WITHOUT_UNPARSED_CHECK

When provided, this macro will not check for unparsed keywords in ARGUMENTS. That is keywords that were provided but not included in the following lists of keywords.

One Value
PREFIX

The prefix for result variables from cmake_parse_arguments(), which includes parsed arguments. Default is “ARGS”, so parsed arguments will begin with “ARGS_”.

Multi Value
OPTIONS

A list of keywords for arguments that operate as flags. Either they are provided, or they aren’t, but don’t accept values. These argument variables will be defined as FALSE if they aren’t provided. Keyword list.

ONE_VALUE_KEYWORDS

A list of keywords for arguments that require a single value. These argument variables will not be defined if they aren’t provided. Keywords list.

MULTI_VALUE_KEYWORDS

A list of keywords for arguments that require one or more values. These argument variables will not be defined if they aren’t provided. Keyword list.

REQUIRES_ALL

A list of keywords from any of the above keyword lists that are mandatory. If ARGUMENTS does not include the keywords listed here, parsing will emit an error.

REQUIRES_ANY

A list of keywords from any of the above keyword lists that must have at least one keyword present. If ARGUMENTS does not include at least one of the keywords listed here, parsing will emit an error.

REQUIRES_ANY_<n>

Where n is an integer in the range [1,3], these three parameters provide the exact same functionality as REQUIRES_ANY, but through separate variables so multiple independent constraints can be enforced simultaneously. Each constraints is independently verified.

MUTUALLY_EXCLUSIVE

A list of keywords from any of the above keyword lists that are restricted from being provided simultaneously. If ARGUMENTS includes more than one of the keywords listed here, parsing will emit an error.

MUTUALLY_EXCLUSIVE_<n>

Where n is an integer in the range [1,3], these three parameters provide the exact same functionality as MUTUALLY_EXCLUSIVE, but through separate variables so multiple exclusivity constraints can be enforced simultaneously. Each constraint is independently verified.

MUTUALLY_INCLUSIVE

A list of keywords from any of the above keyword lists that must be provided together; the presence of any keyword in this list triggers the requirement of every keyword in this list. Should ARGUMENTS include one of the keywords listed here but not all of them, parsing will emit an error.

MUTUALLY_INCLUSIVE_<n>

Where n is an integer in the range [1,3], these three parameters provide the exact same functionality as MUTUALLY_INCLUSIVE, but through separate variables so multiple inclusivity constraints can be enforced simultaneously. Each constraint is independently verified.

Examples

function(separate_list)
  jcm_parse_arguments(
    OPTIONS "USE_PERL_REGEX" "USE_EXTENDED"
    ONE_VALUE_KEYWORDS "REGEX;OUT_MATCHED;OUT_MISMATCHED"
    MULTI_VALUE_KEYWORDS "INPUT"
    REQUIRES_ALL "REGEX;INPUT"
    REQUIRES_ANY "OUT_MATCHED;OUT_MISMATCHED"
    MUTUALLY_EXCLUSIVE "USE_PERL_REGEX" "USE_EXTENDED"
    ARGUMENTS "${ARGN}")

  if(ARGS_USE_PERL_REGEX)
    # example usage of option
  endif()

  if(DEFINED ARGS_OUT_MATCHED)
    # example usage of one-value argument
  endif()

  foreach(input IN LISTS ARGS_INPUT)
    # example usage of multi-value argument
  endforeach()

  # ...
endfunction()

# Ok
separate_list(
  INPUT "first" "second" "third"
  REGEX ".*$d"
  OUT_MATCHED ends_with_d)

# Error, INPUT not provided
separate_list(
  REGEX ".*$d"
  OUT_MATCHED ends_with_d
  OUT_MISMATCHED doesnt_end_with_d)

# Error, OUT_MATCHED nor OUT_MISMATCHED provided
separate_list(
  INPUT "first" "second" "third"
  REGEX ".*$d")

# Error, USE_PERL_REGEX **and** USE_EXTENDED provided
separate_list(
  USE_PERL_REGEX
  USE_EXTENDED
  INPUT "first" "second" "third"
  REGEX ".*$d")

JcmStandardDirs

Module Source on GitHub

Provides variables defining standard project directories for the source, build, and install trees. All installation paths are versioned such that multiple versions of the same project can be installed in the same location. The following variables are set:

  • JCM_PROJECT_CMAKE_DIR Location where CMake code, such as config-files and modules, reside.

  • JCM_PROJECT_DATA_DIR Location where non-code files that still need to be tracked by revision control reside

  • JCM_PROJECT_TESTS_DIR Location where tests that are not unit-tests reside. For example, integration, performance, smoke tests, etc.

  • JCM_PROJECT_DOCS_DIR Location where project documentation resides

  • JCM_PROJECT_LICENSES_DIR Location where project licenses reside. A single license single file can be placed at the project root, though.

  • JCM_CMAKE_DESTINATION Destination in the build tree for cmake modules. For example, configured cmake modules are configured to this location.

  • JCM_HEADER_DESTINATION Destination in the build tree for header files. For example, configured header files are configured to this location. This variable is updated based on CMAKE_CURRENT_BINARY_DIR, and therefore depends on the location of its inclusion.

  • JCM_INSTALL_CMAKE_DESTINATION Destination in the install tree for cmake modules.

  • JCM_INSTALL_INCLUDE_DIR Base directory for installed headers. This path is what should be added to consumer’s include paths to use the installed headers. jcm_install_config_file_package() automatically does this. Refers to a versioned form of CMAKE_INSTALL_DOCDIR from GNUInstallDirs.

  • JCM_INSTALL_DOC_DIR Root directory for installed docs and related files. Refers to a versioned form of CMAKE_INSTALL_DOCDIR from GNUInstallDirs.

  • JCM_UNVERSIONED_INSTALL_CMAKE_DESTINATION Unversioned variant of JCM_INSTALL_CMAKE_DESTINATION.

  • JCM_UNVERSIONED_INSTALL_INCLUDE_DIR Unversioned variant of JCM_INSTALL_INCLUDE_DIR with the same semantics.

  • JCM_UNVERSIONED_INSTALL_DOC_DIR Unversioned variant of JCM_UNVERSIONED_INSTALL_DOC_DIR. Contains same value as CMAKE_INSTALL_DOCDIR from GNUInstallDirs.

JcmHeaderFileSet

Module Source on GitHub

jcm_header_file_sets

jcm_header_file_sets
jcm_header_file_sets(
  <INTERFACE | PUBLIC | PRIVATE>
  [TARGET <target>]
  [HEADERS <file-path>...])

Creates header file-sets of the provided scope containing the files in HEADERS for the possibly alias target, TARGET.

For each header file-path, the closest canonical include directory, one of those provided by jcm_canonical_include_dirs(), will be found. For each canonical include directory matched, a new header file-set will be created on the TARGET using the provided scope if it doesn’t already exist. The original header file will be added to that file-set.

Header file-sets are an excellent way to manage header files for libraries because they support installing INTERFACE and HEADER files when the target is installed and support modifying the target’s respective *INCLUDE_DIRECTORIES properties, as is done by this function. The subset of canonical include directories that are matched by the provided HEADERS are added to the target’s respective *INCLUDE_DIRECTORIES properties, based on the scope, and are wrapped in the :cmake:$<BUILD_INTERFACE:…> generator expression.

jcm_add_library() uses this function, and it is often not necessary to use directly, unless supplementary headers sets are to be added to a target, like in a nested directory.

TODO: support separately creating header sets for integration tests

Note

Use a target’s HEADER_SETS and INTERFACE_HEADER_SETS properties to query its header sets.

Parameters

Positional
scope

The desired scope of the created file-set. One of INTERFACE, PUBLIC, or PRIVATE

One Value
TARGET

The target on which the created header file-sets will be created and *INCLUDE_DIRECTORIES properties will be manipulated.

Multi Value
HEADERS

Header file paths to add to the created header file-sets. Each file path will be converted to a normalized, absolute path, with respect to CMAKE_CURRENT_SOURCE_DIR.

Examples

jcm_header_file_sets(
  PUBLIC
  TARGET libimage_libimage
  HEADERS image.hpp)

# canonical include directory of image.hpp added PUBLICally to libimage_libimage
# now it's available when linking against libimage_libimage

jcm_add_test_executable(
  NAME use_image_hpp
  SOURCES use_image_hpp.cpp
  LIBS libimage_libimage)

JcmListTransformations

Module Source on GitHub

jcm_separate_list

jcm_separate_list
jcm_separate_list(
  INPUT <item>...
  <[OUT_MATCHED <out-var>]
   [OUT_MISMATCHED <out-var>] >
  <REGEX <regex> | IS_DIRECTORY | IS_SYMLINK | IS_ABSOLUTE | IS_TARGET | EVAL_TRUE>
  [TRANSFORM <FILENAME|ALIASED_TARGET>])

Separates the elements of list INPUT into two groups: OUT_MATCHED if the element matches the provided filter, and OUT_MISMATCHED otherwise. Before matching, the elements can optionally be transformed by the selected TRANSFORM, but the elements in the out-variables are always identical to those provided via INPUT.

Parameters

One Value
OUT_MATCHED

The variable named will be set to a list of elements from INPUT that matched REGEX.

OUT_MISMATCHED

The variable named will be set to a list of elements from INPUT that did not match REGEX.

REGEX

When present, this provided regular expression will be the filter used to separate the input elements.

IS_DIRECTORY

When present, the filter used to separate the input elements will match when an element is a directory.

IS_SYMLINK

When present, the filter used to separate the input elements will match when an element is a symlink.

IS_ABSOLUTE

When present, the filter used to separate the input elements will match when an element is an absolute path

IS_TARGET

When present, the filter used to separate the input elements will match when an element names an existent target

EVAL_TRUE

When present, the filter used to separate the input elements will match when an element interpreted as a condition evaluates to true using CMake’s if clause. This is primarily useful for testing a batch of conditions, such as which elements in a list of options are 1/ON/TRUE/YES… vs. 0/OFF/FALSE/NO/NOTFOUND…

TRANSFORM

A transformation to apply to the input before matching. The outputs will not contain this transformation. Currently, only FILENAME or ALIASED_TARGET is supported.

Multi Value
INPUT

List of elements to split based on REGEX.

Examples

jcm_separate_list(
  REGEX "${JCM_HEADER_REGEX}"
  TRANSFORM "FILENAME"
  OUT_MISMATCHED improperly_named
  INPUT
    "${CMAKE_CURRENT_SOURCE_DIR}/thing.hpp"
    "${CMAKE_CURRENT_SOURCE_DIR}/thINg.hxx")
jcm_separate_list(
  IS_DIRECTORY
  OUT_MATCHED directories
  OUT_MISMATCHED non_directories
  INPUT
    "/path/to/my/file.txt"
    "/path/to/my")
    "/path/to/")

 message(STATUS "${directories}" == "/path/to/my;/path/to/")
 message(STATUS "${non_directories}" == "/path/to/my/file.txt")

jcm_transform_list

jcm_transform_list
jcm_transform_list(
  <ABSOLUTE_PATH [BASE <path>] | NORMALIZE_PATH | PARENT_PATH | FILENAME | ALIASED_TARGET>
  INPUT <item>...
  OUT_VAR <out-var>)

Transforms the items in INPUT with the given transformation into the list specified by OUT_VAR.

Parameters

Options
ABSOLUTE_PATH

A transformation that treats each input item as a path, and converts it to an absolute path, relative to CMAKE_CURRENT_SOURCE_DIR or BASE, if provided. Excludes other transformation options.

NORMALIZE_PATH

A transformation that treats each input item as a path, and converts it to a normalized (canonical) path. Excludes other transformation options.

PARENT_PATH

A transformation that treats each input item as a path, and transforms it to its parent path. Excludes other transformation options.

FILENAME

A transformation that treats each input item as a path, and transform it to its file name; the last component in the path. Excludes other transformation options.

ALIASED_TARGET

A transformation that treats each input item as a target name or target alias, and transform it to the target being aliased with jcm_aliased_target(). Excludes other transformation options.

One Value
OUT_VAR

The variable named will be set to a list of transformed input elements.

BASE

When the selected transformation is ABSOLUTE_PATH, this names the absolute path to the directory upon which relative paths will be made absolute. When omitted, the default is CMAKE_CURRENT_SOURCE_DIR

Multi Value
INPUT

List of elements to transform.

Examples

jcm_transform_list(
  ABSOLUTE_PATH
  INPUT image.hpp readers.hpp viewer.hpp
  OUT_VAR absolute_headers)
jcm_transform_list(
  FILENAME
  INPUT libimage/image.hpp libimage/readers.hpp libimage/viewer.hpp
  OUT_VAR header_file_names)

message(STATUS "${header_file_names} == image.hpp;readers.hpp;viewer.hpp")
jcm_transform_list(
  ALIASED_TARGET 
  INPUT libimage::core  libimage::libimage-viewer libimage_libimage-readers
  OUT_VAR aliased_targets)

message(STATUS 
  "${header_file_names} == libimage_libimage-core;libimage_libimage-viewer;libimage_libimage-readers")

jcm_regex_find_list

jcm_regex_find_list
jcm_regex_find_list(
  [MISMATCH]
  REGEX <regex>
  <[OUT_IDX <out-var>]
   [OUT_ELEMENT <out-var>] >
  INPUT <item>...)

Searches INPUT for an item that either matches or mismatches (when MISMATCH is provided) the regular expression REGEX.

Parameters

Options
MISMATCH

Converts the search to find an element that does not match the provided REGEX instead of the default.

One Value
REGEX

A regular expression to match against the items in INPUT.

OUT_IDX

The variable named will be set to the found index or -1 if no element could be found.

OUT_ELEMENT

The variable named will be set to the found element or NOTFOUND if no element could be found.

Multi Value
INPUT

List of elements to search for a matching item.

Examples

file(
  GLOB private_dir_files
  LIST_DIRECTORIES false
  RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/private"
  "${CMAKE_CURRENT_SOURCE_DIR}/private/*")

jcm_regex_find_list(
  MISMATCH
  REGEX ".*(${JCM_CXX_HEADER_EXTENSION}|${JCM_CXX_SOURCE_EXTENSION})$"
  OUT_IDX misextensioned_idx
  INPUT "${private_dir_files}")

JcmExpandDirectories

Module Source on GitHub

jcm_expand_directories

jcm_expand_directories
jcm_expand_directories(
  OUT_VAR <out-var>
  GLOB <glob>
  PATHS <path>...)

For each path in PATHS, if the path is a directory, the enclosed files matching GLOB will be expanded into the list specified by OUT_VAR. Paths in PATHS that refer directly to files will be directly added to the result. However, all of the resulting paths will be absolute with respect to CMAKE_CURRENT_SOURCE_DIR.

Parameters

One Value
OUT_VAR

The variable named will be set to the resultant list of file paths

GLOB

The globbing expression for files within directory paths. The directory path currently being expanded will be prepended to this, such that only files within the current path are used.

Multi Value
PATHS

List of file and directory paths to expand

Examples

jcm_expand_directories(
  OUT_VAR cmake_module_paths
  GLOB *.cmake
  PATHS "${JCM_PROJECT_CMAKE_DIR}" "additional/path/special.cmake")

JcmArbitraryScript

Module Source on GitHub

In most cases, CMake will reconfigure as necessary to update targets and files when it detects changes. However, it’s sometimes necessary to enact some action as part of the project’s build phase as opposed to its configure phase. This is often achieved in multiple steps by first generating the desired script at configure time, and then creating targets with commands that invoke an interpreter on that script, like cmake -P …, bash, or python.

This module is designed to act as the generated script from configure time, but instead of containing specific code, it directly evaluates the CMake code provided in a command-line argument, thereby allowing it to evaluate any arbitrary CMake code. Executing cmake -P /path/to/JcmArbitraryScript.cmake – ‘<cmake code>’ provides behaviour equivalent to bash -c ‘<bash code>’ or node -e ‘<javascript code>’. Although this module was created with the intention of simplifying invocations of scripts in the generated buildsystem, it fundamentally allows cmake -P to accept code as a string instead of from a file.

Additionally provided in this module is jcm_form_arbitrary_script_command(), which allows easily and consistently creating a CMake command at configure-time to invoke arbitrary CMake code at build-time by interpreting this file in script mode. That function should be the primary interface through which this module is used. Examples of direct use follows. Note that escape sequences are interpreted by this script.

cmake -P /path/to/jgd-cmake-modules/JcmArbitraryScript.cmake --
  'message("first\ command")\n\ message("second\ command")'

jcm_form_arbitrary_script_command

jcm_form_arbitrary_script_command
jcm_form_arbitrary_script_command(
  OUT_VAR <out-var>
  CODE <cmake-code>...)

Forms a command that is suitable for use as a COMMAND argument to functions such as add_custom_command() that will evaluate the provided CODE when executed. This is useful to invoke arbitrary code in the build-phase of a project without having to generate intermediate script files or the commands to invoke interpreters on them.

Escape sequences in the CODE strings will be preserved by escaping their backslash and control characters will be escaped to become escape sequences. This ensures control characters aren’t interpreted by CMake as it generates the buildsystem or the buildsystem itself, as these would create malformed build files. Escape sequences are then interpreted by JcmArbitraryScript.cmake to unwind the escaping introduced here.

Parameters

One Value
OUT_VAR

The variable named will be set to the resultant command that is suitable for use as a COMMAND argument to functions such as add_custom_command(). This will always be a semicolon separated list.

Multi Value
CODE

Collection of CMake code that will be joined and evaluated by CMake when the command is executed

Examples

# adapted from `jcm_create_message_target`_ to emit a message at build-time
set(log_level "WARNING")
set(message_text "hello")
list(APPEND message_text ", goodby")

jcm_form_arbitrary_script_command(
  OUT_VAR message_command
  CODE "message(${log_level}" "${messages})")

add_custom_target(build_time_message ALL COMMAND "${message_command}")
# a contrived example invoking JCM modules in a command at build-time

jcm_form_arbitrary_script_command(
  OUT_VAR ensure_symlink_command 
  CODE [[
  cmake_minimum_required(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
  set(jgd-cmake-modules_DIR "${jgd-cmake-modules_DIR}")
  find_package(jgd-cmake-modules CONFIG REQUIRED)
  include(JcmSymlinks)
  jcm_check_symlinks_available(OUT_ERROR_MESSAGE symlink_err_message)
  if(symlink_err_message)
    message(FATAL_ERROR "${symlink_err_message}")
  endif()
]])

add_custom_target(do_configure 
  COMMAND "${ensure_symlink_command}"
  COMMAND 
    "${CMAKE_COMMAND}" -E create_symlink 
    /usr/local/lib/node_modules /usr/local/lib/node_modules)