Fundamentally find_package
is a mechanism to find a library, it's header files, etc. all in 1 convenient method.
As is somewhat implied by the name find_package works best with package managers. Either system package managers
or language package managers
.
- system package managers:
APT
, yum
, etc.
- language package managers:
vcpkg
, conan
, etc.
find_package
streamlines using a library from a package manager.
Here is a step by step example using a very popular c++ library (https://github.com/fmtlib/fmt)
1.) Install the library
# Note I'm using APT but it doesn't really matter
sudo apt install libfmt-dev
2.) Find the library in your CMakeLists.txt
project(example_project)
add_executable(foobar PRIVATE main.cpp)
# Find your library and link to it.
find_package(fmt CONFIG REQUIRED)
target_link_libraries(foobar PRIVATE fmt::fmt)
You should now be good to go. If you are using a system
package manager.
That's because find_*
calls in CMake check default system locations.
To see how CMake found your package you can use --debug-find-pkg
.
cmake -S . -B build --debug-find-pkg=fmt --fresh
This was show you all the places CMake is looking for a file called fmt-config.cmake
.
On my machine it was found here:
/usr/lib/x86_64-linux-gnu/cmake/fmt/fmt-config.cmake
--debug-find
is a VERY useful tool for figuring out how CMake is looking for things.
What about non-system package managers?
There are other ways to describe where packages are located. A very common one is modifying CMAKE_PREFIX_PATH
.
From the documentation
CMAKE_PREFIX_PATH is a semicolon-separated list of directories specifying installation prefixes to be searched by the find_package(), find_program(), find_library(), find_file(), and find_path() commands. Each command will add appropriate subdirectories (like bin, lib, or include) as specified in its own documentation. By default CMAKE_PREFIX_PATH is empty. It is intended to be set by the project.
Package managers like vcpkg handle this automatically for you. Making it as seamless as if you were using a system package manger.
Config vs module searching
Now as your original question alludes to there is some confusion in finding things.
There are 2 main modes for finding things.
In this mode, CMake searches for a file called Find.cmake, looking first in the locations listed in the CMAKE_MODULE_PATH, then among the Find Modules provided by the CMake installation.
In this mode, CMake searches for a file called -config.cmake or Config.cmake.
Now as you may notice are above example used Config
mode.
Config
mode is generally the desirable solution IF available. Since it's basically requires no work from you. Module
mode requires a CMake module be written to help you find things.
CMake actually has a few built in Module
mode helpers.
https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html#find-modules
Like the FindPython3 module. Here is a tiny example
find_package(Python3 REQUIRED)
message(STATUS "${Python3_EXECUTABLE}")
As shown in this python example, find_package
is more generically speaking a way to find multiple files that belong together in an easy to consume way.
NOTE:
Because these modules are built in you don't need to modify your CMAKE_MODULE_PATH. They are already provided for you. Of course you can make your own if you need to.
Final Notes
I'm hoping my answer is more illuminating than confusing and helped you better understand find_package.
For more details on finding behavior in CMake I recommend Craig Scott's book Professional CMake.
https://crascit.com/professional-cmake/