Dependency

Operations to manipule dependencies. They mainly encapsulate the numerous function calls required to import and export dependencies. It requires CMake 3.20 or newer.

Synopsis

dependency(IMPORT <lib-target-name> [...])
dependency(ADD_INCLUDE_DIRECTORIES <lib-target-name> <SET|APPEND> PUBLIC <gen-expr>...)
dependency(SET_IMPORTED_LOCATION <lib-target-name> [CONFIGURATION <config_type>] PUBLIC <gen-expr>...)
dependency(EXPORT <lib-target-name>... <BUILD_TREE|INSTALL_TREE> [APPEND] OUTPUT_FILE <file_name>)

Usage

dependency(IMPORT <lib-target-name> [...])

Import a depedency:

dependency(IMPORT <lib-target-name>
          <STATIC|SHARED>
          [RELEASE_NAME <raw-filename>]
          [DEBUG_NAME <raw-filename>]
          ROOT_DIR <directory-path>
          INCLUDE_DIR <directory-path>)

Create an imported library target named <lib-target-name>, which should represent the base name of the library (without prefix or suffix), by locating its binary files and setting the necessary target properties. This command combines behavior similar to find_library() and add_library(IMPORTED).

The command requires either the STATIC or SHARED keyword to specify the type of library. Only one may be used. At least one of RELEASE_NAME <raw-filename> or DEBUG_NAME <raw-filename> must be provided. Both can be used. These arguments determine which configurations of the library will be available, typically matching values in the CMAKE_CONFIGURATION_TYPES variable.

The value of <raw-filename> should be the core name of the library file, stripped of:

  • Any version numbers.

  • Platform-specific prefixes (e.g. lib).

  • Platform-specific suffixes (e.g. .so, .dll, .dll.a, .a, .lib).

The file will be resolved by scanning recursively all files in the given ROOT_DIR and attempting to match against expected filename patterns constructed using the relevant CMAKE_<CONFIG>_LIBRARY_PREFIX and CMAKE_<CONFIG>_LIBRARY_SUFFIX, accounting for platform conventions and possible version-number noise in filenames. More specifically, it tries to do a matching between the <raw-filename> in format <CMAKE_STATIC_LIBRARY_PREFIX|CMAKE_SHARED_LIBRARY_PREFIX><raw-filename> <verions-numbers><CMAKE_STATIC_LIBRARY_SUFFIX|CMAKE_SHARED_LIBRARY_SUFFIX> and each filename found striped from their numeric and special character version and their suffix and their prefix based on the plateform and the kind of library STATIC or SHARED. See the command module directory(SCAN), that is used internally, for full details.

If more than one file matches or no file is found, an error is raised.

Once located, an imported target is created using add_library(IMPORTED) and appropriate properties for each available configuration (RELEASE and/or DEBUG) are set, including paths to the binary and import libraries (if applicable), as well as the soname.

The following target properties are configured:

INTERFACE_INCLUDE_DIRECTORIES

Set to the directory given by INCLUDE_DIR. This path is propagated to consumers of the imported target during build and link phases. See the CMake doc for full details.

INTERFACE_INCLUDE_DIRECTORIES_BUILD

Set to an empty value. This is a custom property, not used by CMake natively, intended to track include directories for usage from the build-tree context.

INTERFACE_INCLUDE_DIRECTORIES_INSTALL

Set to an empty value. This is a custom property intended for tracking include paths during installation or packaging, for usage from the install-tree context.

IMPORTED_LOCATION_<CONFIG>

The full path to the actual library file (e.g. .so, .dll, .a, .lib), set separately for each configuration (RELEASE and/or DEBUG). See the CMake doc for full details.

IMPORTED_LOCATION_BUILD_<CONFIG>

Custom property set to an empty value. Intended for build-tree specific overrides of the library path, for usage from the build-tree context. Use dependency(SET_IMPORTED_LOCATION) to initialize this property.

IMPORTED_LOCATION_INSTALL_<CONFIG>

Custom property set to an empty value. Intended for install-time overrides of the library path, for usage from the install-tree context. Use dependency(SET_IMPORTED_LOCATION) to initialize this property.

IMPORTED_IMPLIB_<CONFIG>

On DLL-based platforms (e.g. Windows), set to the full path of the import library file (e.g. .dll.a, .a, .lib) for the corresponding configuration. For static libraries, this property is set to empty, because an import library is only for a shared library. See the CMake doc for full details.

IMPORTED_SONAME_<CONFIG>

Set to the filename of the resolved library (without path), allowing CMake to handle runtime linking and version resolution. See the CMake doc for full details.

IMPORTED_CONFIGURATIONS

Appended with each configuration for which a library was found and configured (e.g. RELEASE, DEBUG). See the CMake doc for full details.

Example usage:

# Import shared lib
dependency(IMPORT "my_shared_lib"
  SHARED
  RELEASE_NAME "mylib_1.11.0"
  DEBUG_NAME "mylibd_1.11.0"
  ROOT_DIR "${CMAKE_SOURCE_DIR}/lib"
  INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/mylib"
)
# Is more or less equivalent to:
add_library("my_shared_lib" SHARED IMPORTED)
set_target_properties("my_shared_lib" PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/include/mylib"
  INTERFACE_INCLUDE_DIRECTORIES_BUILD ""
  INTERFACE_INCLUDE_DIRECTORIES_INSTALL ""
)
find_library(lib NAMES "mylib_1.11.0")
find_library(implib NAMES "mylibd_1.11.0")
cmake_path(GET lib FILENAME lib_name)
set_target_properties("my_shared_lib" PROPERTIES
  IMPORTED_LOCATION_RELEASE "${lib}"
  IMPORTED_LOCATION_BUILD_RELEASE ""
  IMPORTED_LOCATION_INSTALL_RELEASE ""
  IMPORTED_IMPLIB_RELEASE "${implib}"
  IMPORTED_SONAME_RELEASE "${lib_name}"
)
set_property(TARGET "my_shared_lib"
  APPEND PROPERTY IMPORTED_CONFIGURATIONS "${CMAKE_BUILD_TYPE}"
)

# Import static lib
dependency(IMPORT "my_static_lib"
  STATIC
  RELEASE_NAME "mylib_1.11.0"
  DEBUG_NAME "mylibd_1.11.0"
  ROOT_DIR "${CMAKE_SOURCE_DIR}/lib"
  INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/mylib"
)
# Is more or less equivalent to:
add_library("my_shared_lib" SHARED IMPORTED)
set_target_properties("my_shared_lib" PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/include/mylib"
  INTERFACE_INCLUDE_DIRECTORIES_BUILD ""
  INTERFACE_INCLUDE_DIRECTORIES_INSTALL ""
)
find_library(lib NAMES "mylib_1.11.0")
find_library(implib NAMES "mylibd_1.11.0")
cmake_path(GET lib FILENAME lib_name)
set_target_properties("my_shared_lib" PROPERTIES
  IMPORTED_LOCATION_RELEASE "${lib}"
  IMPORTED_LOCATION_BUILD_RELEASE ""
  IMPORTED_LOCATION_INSTALL_RELEASE ""
  IMPORTED_IMPLIB_RELEASE "${implib}"
  IMPORTED_SONAME_RELEASE "${lib_name}"
)
set_property(TARGET "my_shared_lib"
  APPEND PROPERTY IMPORTED_CONFIGURATIONS "${CMAKE_BUILD_TYPE}"
)
dependency(ADD_INCLUDE_DIRECTORIES <lib-target-name> <SET|APPEND> PUBLIC <gen-expr>...)

Set or append public include directories via INTERFACE_INCLUDE_DIRECTORIES property to the imported target <lib-target-name>. The name should represent the base name of the library (without prefix or suffix). This command works similarly to target_include_directories() in CMake, but introduces a separation between build-time and install-time contexts for imported dependencies.

This command is intended for targets that have been previously declared using dependency(IMPORT), and is typically used in conjunction with dependency(EXPORT) to complete the definition of an imported target for external reuse.

The behavior differs from standard CMake in that it stores build and install include paths separately using generator expressions (see how write build specification with generator expressions).

The PUBLIC keyword indicates that the specified directories apply to the usage requirements of the target (i.e., will be propagated to consumers of the target). The directories following it must use generator expressions like $<BUILD_INTERFACE:...> and $<INSTALL_INTERFACE:...> to distinguish between build and install phases.

The command accepts the following mutually exclusive modifiers:

  • SET: Replaces any existing include directories.

  • APPEND: Adds to the current list of include directories.

This command internally sets or appends the following CMake properties on the target:

INTERFACE_INCLUDE_DIRECTORIES

This standard property determines the public include directories seen by consumers of the library. This will be populated using only the build-specific include paths (i.e., extracted from $<BUILD_INTERFACE:...>). See the CMake doc for full details.

INTERFACE_INCLUDE_DIRECTORIES_BUILD

A custom property used internally to distinguish the build-time include paths. It stores the expanded list of directories extracted from the $<BUILD_INTERFACE:...> portion of the arguments.

INTERFACE_INCLUDE_DIRECTORIES_INSTALL

A custom property used to store include directories intended to be used after installation. It is extracted from the $<INSTALL_INTERFACE:...> expressions.

These custom properties (_BUILD and _INSTALL) are not directly used by CMake itself but are later re-injected into export files generated by dependency(EXPORT).

Example usage:

# Import libs
dependency(IMPORT "my_shared_lib"
  SHARED
  RELEASE_NAME "mylib_1.11.0"
  DEBUG_NAME "mylibd_1.11.0"
  ROOT_DIR "${CMAKE_SOURCE_DIR}/lib"
  INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/mylib"
)
dependency(IMPORT "my_static_lib"
  STATIC
  RELEASE_NAME "mylib_1.11.0"
  DEBUG_NAME "mylibd_1.11.0"
  ROOT_DIR "${CMAKE_SOURCE_DIR}/lib"
  INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/mylib"
)

# Set include directories for shared lib
dependency(ADD_INCLUDE_DIRECTORIES "my_shared_lib" SET
  PUBLIC
    "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/mylib>"
    "$<INSTALL_INTERFACE:include/mylib>"
)
# Is more or less equivalent to:
target_include_directories(static_mock_lib
  PUBLIC
      "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/mylib>"
      "$<INSTALL_INTERFACE:include/mylib>"
)

# Set include directories for static lib
dependency(ADD_INCLUDE_DIRECTORIES "my_static_lib" SET
  PUBLIC
    "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/mylib>"
    "$<INSTALL_INTERFACE:include/mylib>"
)
# Is more or less equivalent to:
target_include_directories(static_mock_lib
  PUBLIC
      "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/mylib>"
      "$<INSTALL_INTERFACE:include/mylib>"
)

This example sets my_shared_lib and my_static_lib to expose:

  • ${CMAKE_SOURCE_DIR}/include/mylib during the build.

  • <CMAKE_INSTALL_PREFIX>/include/mylib after installation (where <CMAKE_INSTALL_PREFIX> is resolved when imported via dependency(EXPORT)).

dependency(SET_IMPORTED_LOCATION <lib-target-name> [CONFIGURATION <config_type>] PUBLIC <gen-expr>...)

Set the IMPORTED_LOCATION_<CONFIG> property of the imported target <lib-target-name> using generator expressions to provide the full path to the library file. The name should represent the base name of the library (without prefix or suffix).

This command is intended for targets that have been previously declared using dependency(IMPORT). It allows specifying a different location for each build configuration type, or for all configurations if no configuration is specified. Also, this command is typically used in conjunction with dependency(EXPORT) to complete the definition of an imported target for external reuse.

If CONFIGURATION is given, the property is only set for that configuration. Otherwise, the property is set for all configurations supported by the target. Configuration types must match one of the values listed in the target's IMPORTED_CONFIGURATIONS property.

The PUBLIC keyword must be followed by one or more generator expressions that define the path to the library file during build and install phases. The paths following it must use generator expressions like $<BUILD_INTERFACE:...> and $<INSTALL_INTERFACE:...> to distinguish between build and install phases. (see how write build specification with generator expressions).

These expressions are evaluated to determine the value of the following CMake properties set by this command:

IMPORTED_LOCATION_<CONFIG>

The full path to the actual library file (e.g. .so, .dll, .a, .lib), set separately for each configuration (RELEASE and/or DEBUG). See the CMake doc for full details. The command directory(FIND_LIB) can be used to find the library file.

IMPORTED_LOCATION_BUILD_<CONFIG>

Custom property set to the full path to the actual library file, set separately for each configuration (RELEASE and/or DEBUG), and for usage from the build-tree context. This property is used by dependency(EXPORT) to complete the definition of an imported target for external reuse.

IMPORTED_LOCATION_INSTALL_<CONFIG>

Custom property set to the full path to the actual library file, set separately for each configuration (RELEASE and/or DEBUG), and for usage from the install-tree context. This property is used by dependency(EXPORT) to complete the definition of an imported target for external reuse.

Example usage:

# Import libs
dependency(IMPORT "my_shared_lib"
  SHARED
  RELEASE_NAME "mylib_1.11.0"
  DEBUG_NAME "mylibd_1.11.0"
  ROOT_DIR "${CMAKE_SOURCE_DIR}/lib"
  INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/mylib"
)
dependency(IMPORT "my_static_lib"
  STATIC
  RELEASE_NAME "mylib_1.11.0"
  DEBUG_NAME "mylibd_1.11.0"
  ROOT_DIR "${CMAKE_SOURCE_DIR}/lib"
  INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/mylib"
)

# Set imported location for shared lib
dependency(SET_IMPORTED_LOCATION "my_shared_lib"
  CONFIGURATION RELEASE
  PUBLIC
    "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/lib/mylib_1.11.0.dll>"
    "$<INSTALL_INTERFACE:lib/mylib_1.11.0.dll>"
)
dependency(SET_IMPORTED_LOCATION "my_shared_lib"
  CONFIGURATION DEBUG
  PUBLIC
    "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/lib/mylibd_1.11.0.dll>"
    "$<INSTALL_INTERFACE:lib/mylibd_1.11.0.dll>"
)

# Set include directories for static lib
dependency(SET_IMPORTED_LOCATION "my_static_lib"
  CONFIGURATION RELEASE
  PUBLIC
    "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/lib/mylib_1.11.0.lib>"
    "$<INSTALL_INTERFACE:lib/mylib_1.11.0.lib>"
)
dependency(SET_IMPORTED_LOCATION "my_static_lib"
  CONFIGURATION DEBUG
  PUBLIC
    "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/lib/mylibd_1.11.0.lib>"
    "$<INSTALL_INTERFACE:lib/mylibd_1.11.0.lib>"
)
dependency(EXPORT <lib-target-name>... <BUILD_TREE|INSTALL_TREE> [APPEND] OUTPUT_FILE <file_name>)

Creates a file <file_name> that may be included by outside projects to import targets in <lib-target-name> list from the current project's build-tree or install-tree. This command is functionally similar to using export(TARGETS) in a BUILD_TREE context and install(EXPORT) in an INSTALL_TREE context, but is designed specifically to export imported targets with dependency(IMPORT) instead of build targets.

The targets in <lib-target-name> list must be previously created imported targets. The names should match exactly the target names used during import.

One of BUILD_TREE or INSTALL_TREE must be specified to indicate the context in which the file is generated:

  • When BUILD_TREE is used, the command generates the file in CMAKE_CURRENT_BINARY_DIR/<file_name>, similar to how export(TARGETS) produces a file to be included by other build projects. This file enables other projects to import the specified targets directly from the build-tree . It can be included from a <PackageName>Config.cmake file to provide usage information for downstream projects.

  • When INSTALL_TREE is used, the file is generated in CMAKE_CURRENT_BINARY_DIR/cmake/export/<file_name> and an install rule is added to copy the file to CMAKE_INSTALL_PREFIX/cmake/export/ <file_name>. This is similar to combining install(TARGETS) with install(EXPORT), but applies to imported rather than built targets. This makes the export file available post-install and allows downstream projects to include the file from a package configuration file.

Note that no install rules are created for the actual binary files of the imported targets; only the export script OUTPUT_FILE itself is installed.

If the APPEND keyword is specified, the generated code is appended to the existing file instead of overwriting it. This is useful for exporting multiple targets incrementally to a single file.

The generated file defines all necessary target properties so that the imported targets can be used as if they were defined locally. The properties are identical to those set by the dependency(IMPORT) command; see its documentation for additional details.

Example usage:

# Import libs before exporting
dependency(IMPORT "my_shared_lib"
  SHARED
  RELEASE_NAME "mylib_1.11.0"
  DEBUG_NAME "mylibd_1.11.0"
  ROOT_DIR "${CMAKE_SOURCE_DIR}/lib"
  INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/mylib"
)
dependency(ADD_INCLUDE_DIRECTORIES "my_shared_lib" SET
  PUBLIC
    "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/mylib>"
    "$<INSTALL_INTERFACE:include/mylib>"
)
dependency(IMPORT "my_static_lib"
  STATIC
  RELEASE_NAME "mylib_1.11.0"
  DEBUG_NAME "mylibd_1.11.0"
  ROOT_DIR "${CMAKE_SOURCE_DIR}/lib"
  INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include/mylib"
)
dependency(ADD_INCLUDE_DIRECTORIES "my_static_lib" SET
  PUBLIC
    "$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include/mylib>"
    "$<INSTALL_INTERFACE:include/mylib>"
)

# Export from Build-Tree
dependency(EXPORT "myimportedlib-1" "myimportedlib-2"
  BUILD_TREE
  OUTPUT_FILE "InternalDependencyTargets.cmake"
)
# Is more or less equivalent to:
export(TARGETS "myimportedlib-1" "myimportedlib-2"
  APPEND
  FILE "InternalDependencyTargets.cmake"
)

# Exporting from Install-Tree
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/install")
dependency(EXPORT "myimportedlib-1" "myimportedlib-2"
  INSTALL_TREE
  OUTPUT_FILE "InternalDependencyTargets.cmake"
)
# Is more or less equivalent to:
install(TARGETS "myimportedlib-1" "myimportedlib-2"
  EXPORT "LibExport"
)
install(EXPORT "LibExport"
  DESTINATION "cmake/export"
  FILE "InternalDependencyTargets.cmake"
)

The resulting file InternalDependencyTargets.cmake may then be included by a package configuration file <PackageName>Config.cmake.in to be used by configure_package_config_file() command:

include("${CMAKE_CURRENT_LIST_DIR}/InternalDependencyTargets.cmake")