Using Dependencies Guide

Introduction

For developers wishing to use CMake to consume a third party binary package, there are multiple possibilities regarding how to optimally do so, depending on how CMake-aware the third-party library is.

CMake files provided with a software package contain instructions for finding each build dependency. Some build dependencies are optional in that the build may succeed with a different feature set if the dependency is missing, and some dependencies are required. CMake searches well-known locations for each dependency, and the provided software may supply additional hints or locations to CMake to find each dependency.

If a required dependency is not found by cmake(1), the cache is populated with an entry which contains a NOTFOUND value. This value can be replaced by specifying it on the command line, or in the ccmake(1) or cmake-gui(1) tool. See the User Interaction Guide for more about setting cache entries.

Libraries providing Config-file packages

The most convenient way for a third-party to provide library binaries for use with CMake is to provide Config-file Packages. These packages are text files shipped with the library which instruct CMake how to use the library binaries and associated headers, helper tools and CMake macros provided by the library.

The config files can usually be found in a directory whose name matches the pattern lib/cmake/<PackageName>, though they may be in other locations instead. The <PackageName> corresponds to use in CMake code with the find_package() command such as find_package(PackageName REQUIRED).

The lib/cmake/<PackageName> directory will contain a file which is either named <PackageName>Config.cmake or <PackageName>-config.cmake. This is the entry point to the package for CMake. A separate optional file named <PackageName>ConfigVersion.cmake may also exist in the directory. This file is used by CMake to determine whether the version of the third party package satisfies uses of the find_package() command which specify version constraints. It is optional to specify a version when using find_package(), even if a ConfigVersion file is present.

If the Config.cmake file is found and the optionally-specified version is satisfied, then the CMake find_package() command considers the package to be found and the entire library package is assumed to be complete as designed.

There may be additional files providing CMake macros or Imported Targets for you to use. CMake does not enforce any naming convention for these files. They are related to the primary Config file by use of the CMake include() command.

Invoking CMake with the intent of using a package of third party binaries requires that cmake find_package() commands succeed in finding the package. If the location of the package is in a directory known to CMake, the find_package() call should succeed. The directories known to cmake are platform-specific. For example, packages installed on Linux with a standard system package manager will be found in the /usr prefix automatically. Packages installed in Program Files on Windows will similarly be found automatically.

Packages which are not found automatically are in locations not predictable to CMake such as /opt/mylib or $HOME/dev/prefix. This is a normal situation and CMake provides several ways for users to specify where to find such libraries.

The CMAKE_PREFIX_PATH variable may be set when invoking CMake. It is treated as a list of paths to search for Config-file Packages. A package installed in /opt/somepackage will typically install config files such as /opt/somepackage/lib/cmake/somePackage/SomePackageConfig.cmake. In that case, /opt/somepackage should be added to CMAKE_PREFIX_PATH.

The environment variable CMAKE_PREFIX_PATH may also be populated with prefixes to search for packages. Like the PATH environment variable, this is a list and needs to use the platform-specific environment variable list item separator (: on Unix and ; on Windows).

The CMAKE_PREFIX_PATH variable provides convenience in cases where multiple prefixes need to be specified, or when multiple different package binaries are available in the same prefix. Paths to packages may also be specified by setting variables matching <PackageName>_DIR, such as SomePackage_DIR. Note that this is not a prefix but should be a full path to a directory containing a config-style package file, such as /opt/somepackage/lib/cmake/SomePackage/ in the above example.

Imported Targets from Packages

A third-party package which provides config-file packages may also provide Imported Targets. These will be specified in files containing configuration-specific file paths relevant to the package, such as debug and release versions of libraries.

Often the third-party package documentation will point out the names of imported targets available after a successful find_package for a library. Those imported target names can be used with the target_link_libraries() command.

A complete example which makes a simple use of a third party library might look like:

cmake_minimum_required(VERSION 3.10)
project(MyExeProject VERSION 1.0.0)

find_package(SomePackage REQUIRED)
add_executable(MyExe main.cpp)
target_link_libraries(MyExe PRIVATE SomePrefix::LibName)

See cmake-buildsystem(7) for further information about developing a CMake buildsystem.

Libraries not Providing Config-file Packages

Third-party libraries which do not provide config-file packages can still be found with the find_package() command, if a FindSomePackage.cmake file is available.

These module-file packages are different to config-file packages in that:

  1. They should not be provided by the third party, except perhaps in the form of documentation

  2. The availability of a Find<PackageName>.cmake file does not indicate the availability of the binaries themselves.

  3. CMake does not search the CMAKE_PREFIX_PATH for Find<PackageName>.cmake files. Instead CMake searches for such files in the CMAKE_MODULE_PATH variable. It is common for users to set the CMAKE_MODULE_PATH when running CMake, and it is common for CMake projects to append to CMAKE_MODULE_PATH to allow use of local module-file packages.

  4. CMake ships Find<PackageName>.cmake files for some third party packages for convenience in cases where the third party does not provide config-file packages directly. These files are a maintenance burden for CMake, so new Find modules are generally not added to CMake anymore. Third-parties should provide config file packages instead of relying on a Find module to be provided by CMake.

Module-file packages may also provide Imported Targets. A complete example which finds such a package might look like:

cmake_minimum_required(VERSION 3.10)
project(MyExeProject VERSION 1.0.0)

find_package(PNG REQUIRED)

# Add path to a FindSomePackage.cmake file
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(SomePackage REQUIRED)

add_executable(MyExe main.cpp)
target_link_libraries(MyExe PRIVATE
    PNG::PNG
    SomePrefix::LibName
)

The <PackageName>_ROOT variable is also searched as a prefix for find_package() calls using module-file packages such as FindSomePackage.