Importing dependencies#

This section covers both how to import a project in another CMake project (importing), and how a user can control where a project is found (finding).

Importing dependencies in a CMake project#

Tl;dr

include(FetchContent)
FetchContent_Declare(awesome-project
        GIT_REPOSITORY https://github.com/user/awesome-project
        GIT_TAG main
        FIND_PACKAGE_ARGS CONFIG
)
FetchContent_MakeAvailable(awesome-project)

The best way to consume a project is within CMake, using the FetchContent/find_package integration. This will run find_package first to try and import the system installed packaged version, and if none is available it will git clone the source project and include it as add_subdirectory. See the configuration section on how to configure the included project.

From there, navigate the dependency’s top-level CMakeLists.txt to find the available targets you can use.

If you need to overwrite the upstream project’s options, simply add the option before the FetchContent_MakeAvailable call, e.g.:

option(PROJECT2_TESTS "Project1: Override" OFF)

FetchContent_MakeAvailable(Project2)

Making a dependency optional#

Currently, the only clear design for supporting optional dependencies is by avoiding FetchContent and using find_package only:

find_package(awesome-project)

See the controlling section on how to disable or make it a required dependency.

Todo

Make the optional dependency work with FetchContent. Currently, there is no clear way how to combine find_package and FetchContent fallthrough. Key part is the interaction with CMAKE_REQUIRE_FIND_PACKAGE_<PackageName> and CMAKE_DISABLE_FIND_PACKAGE_<PackageName>.

How dependencies are found#

Here we assume that all projects in the chain use the modern importing approach to define their dependencies.

Default behavior#

By default, the project will first try to find the <PackageName>Config.cmake file from the system installed packaged, and if that fails, it would either use FetchContent to download the source project if it is a required dependency, or simply disable the feature if it is an optional dependency.

Controlling how dependencies are imported#

Option

Effect

Notes

CMAKE_PREFIX_PATH

Where to look for system installed package

<PackageName>_ROOT

Where to look for system installed package

It can happen that this is not enforced

FETCHCONTENT_TRY_FIND_PACKAGE_MODE

If NEVER, will use downloaded version

FETCHCONTENT_SOURCE_DIR_<PACKAGENAME>

Path to package source to use (instead of downloading)

Takes precedence of any other option

CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>

Make optional dependency required

If dependency is already required via FetchContent, it ensure the system package is used

CMAKE_DISABLE_FIND_PACKAGE_<PackageName>

Disable finding system installed package

Here <PackageName> is the case-sensitive name of the dependency, and <PACKAGENAME> is the equivalent uppercase name.

Caution

CMAKE_REQUIRE_FIND_PACKAGE_<PackageName> and CMAKE_DISABLE_FIND_PACKAGE_<PackageName> options propagate to other dependencies in the chain. Normally this would not be an issue, unless a project uses Find<PackageName>.cmake and do not take this into account [1].