CMakeTargetsFile

Provide operations to configure binary targets using a JSON configuration file. It requires CMake 3.20 or newer.

Introduction

In a CMake build project, there is no native and straightforward way to separate the declaration of a binary target from its definition. Both are typically performed together when writing commands in a CMakeLists.txt file. However, in many use cases, the sequence of commands used to define targets is identical across projects, with only the data changing. The definition logic for the binary target remains the same, while only its declarations (i.e., its configuration) change.

The purpose of this module is to simplify the automated creation of binary targets by allowing their settings to be declared in a standardized JSON configuration file. The structure of this file is defined using a JSON schema. Various commands are provided to read and interpret this configuration file.

The configuration file must be named CMakeTargets.json and can reside anywhere in the project's directory.

Note

CMake is currently developing the Common Package Specification to standardize the way packages are declared and to improve their integration via the System Package Registry. It is therefore possible that this module may become obsolete in the future. In the meantime, it will continue to evolve to reflect updates introduced in upcoming versions.

Format

The CMake targets declaration file is a JSON document with an object as the root (click to download):

{
  "$schema": "schema.json",
  "$id": "schema.json",
  "targets": {
    "src": {
      "name": "fruit-salad",
      "type": "executable",
      "build": {
        "compileFeatures": ["cxx_std_20"],
        "compileDefinitions": ["MY_DEFINE=42", "MY_OTHER_DEFINE", "MY_OTHER_DEFINE=42"],
        "compileOptions": [],
        "linkOptions": []
      },
      "mainFile": "src/main.cpp",
      "pchFile": "include/fruit_salad_pch.h",
      "headerPolicy": {
        "mode": "split",
        "includeDir": "include"
      },
      "dependencies": {
        "AppleLib": {
          "rulesFile": "FindAppleLib.cmake",
          "minVersion": 2,
          "autodownload": true,
          "optional": false
        },
        "BananaLib": {
          "rulesFile": "FindBananaLib.cmake",
          "minVersion": 4,
          "autodownload": false,
          "optional": true
        }
      }
    },
    "src/apple": {
      "name": "apple",
      "type": "staticLib",
      "build": {
        "compileFeatures": [],
        "compileDefinitions": [],
        "compileOptions": [],
        "linkOptions": []
      },
      "mainFile": "src/apple/main.cpp",
      "pchFile": "src/apple/apple_pch.h",
      "headerPolicy": {
        "mode": "merged"
      },
      "dependencies": {}
    },
    "src/banana": {
      "name": "banana",
      "type": "staticLib",
      "build": {
        "compileFeatures": [],
        "compileDefinitions": [],
        "compileOptions": [],
        "linkOptions": []
      },
      "mainFile": "src/banana/main.cpp",
      "pchFile": "src/banana/banana_pch.h",
      "headerPolicy": {
        "mode": "merged"
      },
      "dependencies": {}
    }
  }
}

The JSON document must be conformed to the CMakeTargets.json schema described below.

The root object recognizes the following fields:

$schema

An optional string that provides a URI to the JSON schema that describes the structure of this JSON document. This field is used for validation and autocompletion in editors that support JSON schema. It doesn't affect the behavior of the document itself. If this field is not specified, the JSON document will still be valid, but tools that use JSON schema for validation and autocompletion may not function correctly. The module does not perform schema validation automatically. Use $schema to document the schema version or to enable external validation and tooling workflows.

$id

An optional string that provides a unique identifier for the JSON document or the schema resource. The value must be a valid URI or a relative URI reference. When present, $id can be used by external tooling to disambiguate or resolve the schema/resource and to avoid collisions between different schema documents. The module stores this property but does not interpret or enforce any semantics associated with $id.

targets

The required root property containing the set of targets defined in the file. Its value is an object whose keys are unique directory paths that identify the parent folder containing the source files for each target. For example: src, src/apple.

Each path must be relative to the project root and must not include a trailing slash. The directory path serves as the unique identifier for the target within the file because it is assumed that there can be no more than one target defined per folder.

The value for each key is a target definition object as described in the following subsections. The key name (directory path) can be used internally to organize and retrieve target configurations during the CMake building process.

Each entry of a targets is a JSON object that may contain the following properties:

name

A required string specifying the human-meaningful name of the target. This name must be unique across all targets listed in the same targets object. Two targets within the same file must not share the same name, even if their directory paths differ. The name is used to create a CMake target.

type

A required string specifying the kind of binary to generate for this target. Valid values are:

  • staticLib - a static library.

  • sharedLib - a shared (dynamic) library.

  • interfaceLib - a header-only library.

  • executable - an executable program.

The type influences how the target is built and linked by the consuming CMake logic.

build

A required object describing build settings. It contains the following array properties:

compileFeatures

A list of optional compile features to pass to the target. It is used as a parameter for the target_compile_features() command. The property is required, but the array can be empty.

compileDefinitions

A list of optional preprocessor definitions applied when compiling this target. It is used as a parameter for the target_compile_definitions() command. The property is required, but the array can be empty.

compileOptions

A list of compiler options to pass when building this target. It is used as a parameter for the target_compile_options() command. The property is required, but the array can be empty.

linkOptions

A list of linker options to pass when building this target. It is used as a parameter for the target_link_options() command. The property is required, but the array can be empty.

All four properties must be present. Lists may be empty to indicate no entries.

mainFile

A required string specifying the path to the main source file for this target. The path must be relative to the project root. The file must exist and have a .cpp, .cc, or .cxx extension.

pchFile

An optional string specifying the path to the precompiled header file (PCH) for this target. The path must be relative to the project root. If present, it must have one of the following extensions: .h, .hpp, .hxx, .inl, .tpp. If not specified, the target is considered to have no PCH.

headerPolicy

A required object describing how header files are organized within the project. It has the following properties:

mode

A required string specifying whether all header files are grouped in a a single common folder or whether public headers are separated from private headers. Valid values are:

  • split - public headers are stored in a different folder (e.g., include/) than private headers (e.g., src/).

  • merged - public and private headers are in the same folder (e.g., src/).

includeDir

Required only if mode is split. A path relative to the project root specifying the folder in include/ where the public headers are located. The path must start with include (e.g., include, include/mylib) and must not include a trailing slash.

dependencies

The required object property specifying the set of dependencies needed by the target. Its value is an object whose keys are the names of the dependencies. Each name must be unique within the dependencies object.

Each entry of a dependencies object is a JSON object that may contain the following properties:

rulesFile

A required path to a CMake file ending in .cmake that defines how to integrate the dependency into the build system.

minVersion

A required integer specifying the minimum acceptable version of the dependency. This value is used as the VERSION argument to find_package() calls for that dependency.

autodownload

A required boolean indicating whether the dependency may be automatically downloaded if not found locally.

optional

A required boolean indicating whether the dependency is optional. If true and the dependency cannot be found, it is ignored and not linked. If false and the dependency is missing, the build will fail.

Schema

This file provides a machine- readable JSON schema for the CMakeTargets.json format.

Synopsis

cmake_targets_file(LOAD <json-file-path>)
cmake_targets_file(IS_LOADED <output-var>)
cmake_targets_file(GET_LOADED_FILE <output-var>)
cmake_targets_file(HAS_CONFIG <output-var> TARGET <target-dir-path>)
cmake_targets_file(GET_SETTINGS <output-map-var> TARGET <target-dir-path>)
cmake_targets_file(GET_KEYS <output-list-var> TARGET <target-dir-path>)
cmake_targets_file(GET_VALUE <output-var> TARGET <target-dir-path> KEY <setting-name>)
cmake_targets_file(PRINT_CONFIGS [])
cmake_targets_file(PRINT_TARGET_CONFIG <target-dir-path>)

Usage

cmake_targets_file(LOAD <json-file-path>)

Load and parses a targets configuration file in JSON format.

Note

During loading, no checks are performed on property values to ensure that they comply with the CMakeTargets.json schema. The command only verifies that the expected JSON structure is present and that the properties are defined.

This behavior is intended to give users more flexibility and to avoid code duplication in cases where both syntactic and semantic validation may be required.

The <json-file-path> specifies the location of the configuration file to load. It must refer to an existing file on disk and must have a .json extension. The file must conform to the CMakeTargets.json schema.

When this command is invoked, the JSON content is read into memory and stored in global properties for later retrieval. Each target entry described in the JSON file is parsed into an independent configuration Map, keyed by its directory path. Both the original raw JSON and the list of target directory paths are preserved.

The following global properties are initialized:

TARGETS_CONFIG_<target-dir-path>

For each target directory path in the configuration file, stores the serialized key-value Map of its parsed properties.

TARGETS_CONFIG_RAW_JSON

Contains the loaded JSON file as text.

TARGETS_CONFIG_LIST

Holds the list of all target directory paths defined in the file. They serve as value to get the target configurations stored in TARGETS_CONFIG_<target-dir-path>.

TARGETS_CONFIG_LOADED

Set to on once the configuration is successfully loaded, otherwise to off.

This command must be called exactly once before using any other module operation. If the configuration is already loaded, calling cmake_targets_file(LOAD) again will replace the current configuration in memory.

Each target's configuration is stored separately in a global property named TARGETS_CONFIG_<target-dir-path>. These properties are of type Map, where each JSON block is represented as a flat tree list.

Keys in the map are derived from the JSON property names. Nested properties are flattened by concatenating their successive parent keys, separated by a dot (.). For example, the JSON key rulesFile from the above example is stored in the map as dependencies.AppleLib.rulesFile. The list of all keys for a target's map can be retrieved using the cmake_targets_file(GET_KEYS) command.

Since CMake does not support two-dimensional arrays, and because a Map is itself a particular type of list, JSON arrays are serialized before being stored. Elements in a serialized array are separated by a pipe (|) character. For example, the JSON array ["MY_DEFINE=42", "MY_OTHER_DEFINE", "MY_OTHER_DEFINE=42"] become MY_DEFINE=42|MY_OTHER_DEFINE|MY_OTHER_DEFINE=42. And to avoid conflicts, pipe characters (|) are first escaped with a slash (\|).

Example usage:

cmake_targets_file(LOAD "${CMAKE_SOURCE_DIR}/CMakeTargets.json")
get_property(raw_json GLOBAL PROPERTY "TARGETS_CONFIG_RAW_JSON")
get_property(is_loaded GLOBAL PROPERTY "TARGETS_CONFIG_LOADED")
get_property(paths_list GLOBAL PROPERTY "TARGETS_CONFIG_LIST")
get_property(apple_config GLOBAL PROPERTY "TARGETS_CONFIG_src/apple")
get_property(banana_config GLOBAL PROPERTY "TARGETS_CONFIG_src/banana")
get_property(src_config GLOBAL PROPERTY "TARGETS_CONFIG_src")
message("'src' array is: ${src_config}")
# output is:
#   'src' array is: name:fruit-salad;type:executable;mainFile:src/main.cpp;
#   pchFile:include/fruit_salad_pch.h;build.compileFeatures:cxx_std_20;
#   build.compileDefinitions:MY_DEFINE=42|MY_OTHER_DEFINE|
#   MY_OTHER_DEFINE=42;build.compileOptions:;build.linkOptions:;
#   headerPolicy.mode:split;headerPolicy.includeDir:include;dependencies:
#   AppleLib|BananaLib;dependencies.AppleLib.rulesFile:FindAppleLib.cmake;
#   dependencies.AppleLib.minVersion:2;dependencies.AppleLib.autodownload:
#   ON;dependencies.AppleLib.optional:OFF;dependencies.BananaLib.rulesFile
#   :FindBananaLib.cmake;dependencies.BananaLib.minVersion:4;dependencies.
#   BananaLib.autodownload:OFF;dependencies.BananaLib.optional:ON
cmake_targets_file(IS_LOADED <output-var>)

Set <output-var> to on if a targets configuration file has been loaded with success, or off otherwise. This checks the global property TARGETS_CONFIG_LOADED set by a successful invocation of the cmake_targets_file(LOAD) command.

Example usage:

cmake_targets_file(LOAD "${CMAKE_SOURCE_DIR}/CMakeTargets.json")
cmake_targets_file(IS_LOADED is_file_loaded)
message("file_loaded: ${is_file_loaded}")
# output is:
#   file_loaded: on
cmake_targets_file(GET_LOADED_FILE <output-var>)

Set <output-var> to the full JSON content of the currently loaded targets configuration file. The content is retrieved from the global property TARGETS_CONFIG_RAW_JSON, which is set by a successful invocation of the cmake_targets_file(LOAD) command.

An error is raised if no configuration file is loaded.

Example usage:

cmake_targets_file(GET_LOADED_FILE json_file_content)
message("json_file_content: ${json_file_content}")
# output is:
#   json_file_content: {
#     "$schema": "schema.json",
#     "$id": "schema.json",
#     "targets": {
#       ...
#     }
#   }
cmake_targets_file(HAS_CONFIG <output-var> TARGET <target-dir-path>)

Set <output-var> to on if a configuration exists for the given target directory path <target-dir-path>, or off otherwise.

Example usage :

cmake_targets_file(HAS_CONFIG is_target_configured TARGET "src")
message("is_target_configured (src): ${is_target_configured}")
# output is:
#   is_target_configured (src): on
cmake_targets_file(GET_SETTINGS <output-map-var> TARGET <target-dir-path>)

Retrieves the list of all settings defined for a given target configuration in the global property TARGETS_CONFIG_<target-dir-path>.

The <target-dir-path> specifies the directory path of the target whose configuration settings should be retrieved. This must correspond to a path listed in the global property TARGETS_CONFIG_LIST, and must match one of the keys in the targets JSON object of the loaded configuration file.

The result is stored in <output-var> as a Map.

An error is raised if no configuration file has been previously loaded with the cmake_targets_file(LOAD) command or if the TARGET does not exist in the loaded configuration file.

Example usage:

cmake_targets_file(GET_SETTINGS target_config_map TARGET "src")
message("target_config (src): ${target_config_map}")
# output is:
#   target_config (src): name:fruit-salad;type:executable;mainFile:
#   src/main.cpp;pchFile:include/fruit_salad_pch.h;...
cmake_targets_file(GET_KEYS <output-list-var> TARGET <target-dir-path>)

Retrieves the list of all setting keys defined for a given target configuration in the global property TARGETS_CONFIG_<target-dir-path>.

The <target-dir-path> specifies the directory path of the target whose configuration settings should be retrieved. This must correspond to a path listed in the global property TARGETS_CONFIG_LIST, and must match one of the keys in the targets JSON object of the loaded configuration file.

The result is stored in <output-var> as a semicolon-separated list.

An error is raised if no configuration file has been previously loaded with the cmake_targets_file(LOAD) command or if the TARGET does not exist in the loaded configuration file.

Example usage:

cmake_targets_file(GET_KEYS setting_keys TARGET "src")
message("setting_keys: ${setting_keys}")
# With the JSON example above, output is:
#   setting_keys: name;type;mainFile;pchFile;build.compileFeatures;build.
#   compileDefinitions;build.compileOptions;build.linkOptions;headerPolicy.
#   mode;headerPolicy.includeDir;dependencies;dependencies.AppleLib.
#   rulesFile;dependencies.AppleLib.minVersion;dependencies.AppleLib.
#   autodownload;dependencies.AppleLib.optional;dependencies.BananaLib.
#   rulesFile;dependencies.BananaLib.minVersion;dependencies.BananaLib.
#   autodownload;dependencies.BananaLib.optional
cmake_targets_file(GET_VALUE <output-var> TARGET <target-dir-path> KEY <setting-name>)

Retrieves the value associated to a specific setting key <setting-name> defined for a given target configuration in the global property TARGETS_CONFIG_<target-dir-path>.

The <target-dir-path> specifies the directory path of the target whose configuration setting should be retrieved. This must correspond to a path listed in the global property TARGETS_CONFIG_LIST, and must match one of the keys in the targets JSON object of the loaded configuration file.

The <setting-name> specifies the flattened key name as stored in the Map TARGETS_CONFIG_<target-dir-path>. Nested JSON properties are concatenated using a dot (.) separator (e.g., build.compileDefinitions).

The result is stored in <output-var> as a value or a deserialized list.

An error is raised if no configuration file has been previously loaded with the cmake_targets_file(LOAD) command or if the TARGET does not exist in the loaded configuration file or if the KEY does not exist in the target configuration.

Example usage:

cmake_targets_file(GET_VALUE setting_value TARGET "src" KEY "type")
message("setting_value (type): ${setting_value}")
# output is:
#   setting_value (type): executable
cmake_targets_file(GET_VALUE setting_value TARGET "src" KEY "build.compileDefinitions")
message("setting_value (build.compileDefinitions): ${setting_value}")
# output is:
#   setting_value (build.compileDefinitions): MY_DEFINE=42;MY_OTHER_DEFINE;
#   MY_OTHER_DEFINE=42
cmake_targets_file(GET_VALUE setting_value TARGET "src" KEY "dependencies")
message("setting_value (dependencies): ${setting_value}")
# output is:
#   setting_value (dependencies): AppleLib;BananaLib

Prints the configuration of all targets defined in the currently loaded configuration file. It is primarily intended for debugging or inspecting the parsed target settings after loading a configuration file.

An error is raised if no configuration file has been previously loaded with the cmake_targets_file(LOAD) command

Example usage:

cmake_targets_file(PRINT_CONFIGS)
# output is:
#   -- Target: fruit-salad
#   --   type: executable
#   --   mainFile: src/main.cpp
#   --   pchFile: include/fruit_salad_pch.h
#   --   build.compileFeatures: cxx_std_20
#   ...

Prints the configuration of a given target configuration in the global property TARGETS_CONFIG_<target-dir-path>. It is primarily intended for debugging or inspecting a parsed target settings after loading a configuration file.

The <target-dir-path> specifies the directory path of the target whose configuration setting should be retrieved. This must correspond to a path listed in the global property TARGETS_CONFIG_LIST, and must match one of the keys in the targets JSON object of the loaded configuration file.

An error is raised if no configuration file has been previously loaded with the cmake_targets_file(LOAD) command.

Example usage:

cmake_targets_file(PRINT_TARGET_CONFIG "src")
# output is:
#   -- Target: fruit-salad
#   --   type: executable
#   --   mainFile: src/main.cpp
#   --   pchFile: include/fruit_salad_pch.h
#   --   build.compileFeatures: cxx_std_20
#   ...