CMake: find_package()
What You Should Know & Your Actions
When we need to add an external project as the dependency, we will use command find_package
in CMakeLists.txt
to let CMake know where the header files and libraries are located, such that they can be found and linked properly later on.
It is ideal that the developer of the external project provides a <package>Config.cmake
file (or a <lower-case-name>-config.cmake
file) for us/users, and this file will be cached into database (in the default installation path) after we sudo make install
this external project. You can check if they are available by the locate
command.
If they are available, you only need to write one single line in the CMakeLists.txt
file. For example,
Unfortunately, there are certain packages that do not provide (they should!) this CMake configuration file (or the files are not adopted by Ubuntu/apt). In this case, we need to use Find<package>.cmake
file instead to locate this external project. We can write it on our own, but it is often the case that someone has done it before. So go ahead and find an available one to use.
After you find a good Find<package>.cmake
file, we often place it under a folder named cmake
or cmake-modules
in the root directory of the current project (in parallel to include
, src
, etc.), and then add the path to this folder to a CMake variable CMAKE_MODULE_PATH
(which is empty by default). With this setup, CMake will be able to look for your customized Find<package>.cmake
file according to this CMake module path. What you need to do in CMakeLists.txt
file is the following two lines of code.
Summary
The CMake command
find_package
has two modes (Config mode and Module mode) to find and load the CMake configuration of an external project.In Config mode, it will look for a
<package>Config.cmake
or<lower-case-name>-config.cmake
file in the default install path in Ubuntu system.In Module mode, it will look for a
Find<package>.cmake
file in the path specified by variableCMAKE_MODULE_PATH
; this variable is empty unless set by user.Module mode has higher priority than Config mode, which means that you can overwrite the default Config file by providing your own FindXXX file.
More Technical Details
According to the official documentation and this stackoverflow answer, find_package() has two modes: "Module" mode and "Config" mode. If no module is found and the MODULE option is not given, the command proceeds to Config mode.
Module mode
It will look for a file called
Find<package>.cmake
, first in CMAKE_MODULE_PATH (empty by default), and then under cmake installation path<CMAKE_ROOT>/Modules
(e.g.,/usr/share/cmake-3.5/Modules
). Some example default modules includeFindCUDA.cmake
orFindOpenGL.cmake
.Therefore, to add our own cmake modules or overwrite system cmake modules, we can add
Find<package>.cmake
files in a folder calledcmake
and do the following in CMakeLists.txt, to make the best use of CMAKE_MODULE_PATH.
Config mode
It will look for a file called
<package>Config.cmake
or<lower-case-name>-config.cmake
under CMAKE_INSTALL_PREFIX (default to/usr/local
). These cmake files are installed when we dosudo make install
for 3rd party libraries. Examples are as follows (excerpts from command output).
References
Commands
Commonly used commands to figure out where packages are installed.
dpkg -L <package-name>
apt list <package-name>
locate <package>Config.cmake
To set flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_BUILD_TYPE RelWithDebInfo)
cmake -DCMAKE_BUILD_TYPE=Debug
Note that all names marked by <xxx> should be replaced by their actual file names or package names. Case sensitive!
Actions Needed After A Package Is Found
In general, once a package is found, a new variable <package>_FOUND
will be generated and set to true. Also, there will be a few more variables loaded into the compilation process, such as <package>_INCLUDE_DIR
, <package>_INCLUDE_DIRS
, <package>_LIBRARIES
, <package>_LIBS
. Then you can use them to let CMake know where to look for header files and libraries. For example,
Note that different projects may adopt different variable names. You need to make sure the spelling is completely correct. (Should it be LIBRARIES
or LIBS
?)
Typically, the variable names are expected to be documented in the official documentation of this external project. (They should!) If not, you will need to dig into <lower-case-name>-config.cmake
or <package>Config.cmake
or Find<package>.cmake
files, which is where they are defined.
Last updated