What use is find_package() when you need to specify CMAKE_MODULE_PATH?
Categories:
Demystifying find_package() and CMAKE_MODULE_PATH in CMake

Explore the nuances of CMake's find_package() command and understand when and why CMAKE_MODULE_PATH becomes essential for locating custom or non-standard packages.
CMake's find_package()
command is a cornerstone for managing external dependencies in C++ projects. It automates the process of locating libraries, headers, and other package components, making your build system robust and portable. However, its behavior can sometimes be a source of confusion, especially when dealing with packages not installed in standard system locations or when creating your own Find<PackageName>.cmake
modules. This article delves into the mechanics of find_package()
and clarifies the critical role of CMAKE_MODULE_PATH
in guiding CMake to the right places.
How find_package() Works: A Search Strategy Overview
At its core, find_package()
attempts to locate a package by searching for specific files. It operates in two main modes: Module mode and Config mode. The search order and the files it looks for differ slightly between these modes, but the general principle involves checking a series of predefined and user-specified paths.
In Module mode, find_package(<PackageName>)
looks for a file named Find<PackageName>.cmake
. This file contains custom logic written by the package maintainer (or you) to locate the package's components. In Config mode, find_package(<PackageName> CONFIG)
or find_package(<PackageName> REQUIRED)
(which implies CONFIG mode if a module is not found) looks for <PackageName>Config.cmake
or <packagename>-config.cmake
files. These files are typically generated by the package's build system and provide direct information about the package's installation.
The search paths include system-wide locations, environment variables, and crucially, paths specified by CMAKE_MODULE_PATH
and CMAKE_PREFIX_PATH
.
flowchart TD A[find_package(PackageName)] --> B{Module Mode?}; B -- Yes --> C[Search CMAKE_MODULE_PATH]; C --> D[Search CMAKE_ROOT/Modules]; D --> E{Find<PackageName>.cmake found?}; E -- Yes --> F[Package Found (Module Mode)]; E -- No --> G{Config Mode?}; B -- No --> G; G -- Yes --> H[Search CMAKE_PREFIX_PATH]; H --> I[Search system paths (e.g., /usr/local, /usr)]; I --> J{<PackageName>Config.cmake found?}; J -- Yes --> K[Package Found (Config Mode)]; J -- No --> L[Package Not Found];
Simplified flow of CMake's find_package() search strategy.
The Role of CMAKE_MODULE_PATH
CMAKE_MODULE_PATH
is a CMake list variable that holds a list of directories where CMake should look for Find<PackageName>.cmake
files. It is specifically relevant when you are using or developing custom Find
modules that are not part of CMake's built-in modules or when a package's Find
module is installed in a non-standard location.
Consider a scenario where you've written a FindMyCustomLib.cmake
module for a proprietary library, or you've downloaded a third-party Find
module that isn't installed system-wide. Without CMAKE_MODULE_PATH
, CMake wouldn't know where to look for this file, leading to find_package()
failures.
By adding your custom module's directory to CMAKE_MODULE_PATH
, you explicitly tell CMake: "Hey, when you're looking for Find<PackageName>.cmake
, also check these directories." This provides a flexible way to extend CMake's package-finding capabilities without modifying system-wide CMake installations.
# In your project's CMakeLists.txt
# Define a directory where your custom Find modules reside
set(MY_FIND_MODULES_DIR "${CMAKE_SOURCE_DIR}/cmake/modules")
# Add this directory to CMAKE_MODULE_PATH
# It's generally good practice to append to avoid overwriting existing paths
list(APPEND CMAKE_MODULE_PATH "${MY_FIND_MODULES_DIR}")
# Now, find_package() will look in MY_FIND_MODULES_DIR for FindMyCustomLib.cmake
find_package(MyCustomLib REQUIRED)
Adding a custom directory to CMAKE_MODULE_PATH.
CMAKE_MODULE_PATH
is for Find<PackageName>.cmake
files, CMAKE_PREFIX_PATH
is used to find <PackageName>Config.cmake
files or general installation prefixes. Often, you might need to set both if you're dealing with non-standard installations of both types of packages.When to Use CMAKE_MODULE_PATH vs. CMAKE_PREFIX_PATH
Understanding the distinction between CMAKE_MODULE_PATH
and CMAKE_PREFIX_PATH
is crucial for effective dependency management:
CMAKE_MODULE_PATH
: Use this when you have aFind<PackageName>.cmake
script that CMake needs to discover. This is common for packages that don't provide their ownConfig
files, or when you're writing your own custom finding logic.CMAKE_PREFIX_PATH
: Use this when a package provides aConfig
file (e.g.,FooConfig.cmake
) and is installed in a non-standard prefix. CMake will search forFooConfig.cmake
withinCMAKE_PREFIX_PATH/<PackageName>/(lib/cmake|share/cmake)
or directly inCMAKE_PREFIX_PATH/<PackageName>
. This is the more common scenario for well-behaved third-party libraries.
In many cases, if you're installing a package to a custom location, you might need to set CMAKE_PREFIX_PATH
to the installation root. If that package also relies on a custom Find
module that isn't in a standard location, then CMAKE_MODULE_PATH
might also be necessary.
# Example: Setting both paths
# Assume a custom installation prefix for a library
set(MY_LIB_INSTALL_PREFIX "/opt/my_custom_libs")
list(APPEND CMAKE_PREFIX_PATH "${MY_LIB_INSTALL_PREFIX}")
# Assume a custom Find module for another dependency
set(MY_CUSTOM_FIND_MODULES "${CMAKE_SOURCE_DIR}/cmake/find_modules")
list(APPEND CMAKE_MODULE_PATH "${MY_CUSTOM_FIND_MODULES}")
find_package(MyConfigLib REQUIRED)
find_package(MyModuleLib REQUIRED)
Demonstrating the use of both CMAKE_PREFIX_PATH and CMAKE_MODULE_PATH.
CMAKE_MODULE_PATH
or CMAKE_PREFIX_PATH
in your main CMakeLists.txt
if your project is meant to be portable. Prefer using relative paths (e.g., ${CMAKE_SOURCE_DIR}/cmake
) or allowing users to set these variables via the command line (cmake -D CMAKE_MODULE_PATH=/path/to/modules ...
).