Skip to content
Sean Bryan edited this page Sep 23, 2025 · 1 revision

CMake

Exporting CMake Targets

Acknowledgement: big thanks to Micael Oliveira for his work on exporting CMake targets in ACCESS-OM3 and providing a starting point for the organisation on this topic

Motivation

CMake projects which provide targets should install a CMake package configuration file. This is currently the best practice for library authors and has the benefit that projects can find and import targets out of the box via find_package() without needing a find module.

This talk given by Daniel Pfeifer gives a great introduction to the topic:

Resources

Here are examples where we have done this at ACCESS-NRI:

Other useful material:

What is find_dependency and why do we need it?

When a CMake package config file is installed, the targets which are exported often require dependencies on other packages - these dependencies must be available for consumers of your exported targets. For example, this may be necessary if any targets declare a PUBLIC dependency, or if the dependency may be provided as a static library. This is because for these cases, the INTERFACE_* target properties of your exported targets will contain a reference to these dependencies and CMake will error if these dependencies cannot be found (see target usage requirements for more details on these properties).

find_dependency() facilitates this by ensuring that the necessary dependencies are found when the package itself is found by the consuming project via find_package(). It also forwards the correct parameters for QUIET and REQUIRED which were passed to the original find_package() call.

How do I export my targets when my projects relies on find modules?

If your project requires using find modules (Find<project>.cmake files) to find its dependencies, then these find modules should be installed along with your package config file so that these dependencies can be found using find_dependency(). Once the find modules are installed (typically in CMAKE_CURRENT_LIST_DIR), we can make these find modules discoverable in the package config file:

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})

find_dependency(foo)
find_dependency(bar)

list(REMOVE_ITEM CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})

See the following for more details:

Relocatable targets

See Creating Relocatable Packages.

Relocatability has the benefit that the installed package will not break if the location of any installed dependencies and/or the package itself changes.

Common pitfalls which break relocatability:

  1. Hardcoded paths to third-party dependencies
    • Be careful to not populate any properties which may contain paths, such as INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_LINK_LIBRARIES (see target usage requirements for more details), with paths relevant to dependencies. This will result in hard coded paths to dependencies for your exported targets.
    • This can happen when using variables such as Foo_LIBRARIES or Foo_INCLUDE_DIRS to link against third party dependencies. Instead, link against a Foo imported target with target_link_libraries to avoid populating paths to dependencies in the exported targets. However, this may not always be possible and the CMake manual suggests two workarounds here.
Clone this wiki locally