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].