Almost every project depends on other libraries; find_package is the standard way to consume them.
find_package(fmt 10 REQUIRED) asks CMake to find an installed package and fail with a clear message if it's missing. On success the package provides imported targets, usually namespaced, which you link like your own:
target_link_libraries(app PRIVATE fmt::fmt)Imported targets carry the include paths, definitions and transitive dependencies, so one line is all you need.
There are two search modes:
- Config mode: the package ships a
fmtConfig.cmake(orfmt-config.cmake) file, installed with it. This is what modern libraries provide and what package managers generate. - Module mode: CMake (or your project) supplies a
FindXxx.cmakescript that searches for headers and libraries. CMake ships modules for common system libraries:Threads,ZLIB,OpenSSL,CURL,Python,Boost(newer Boost versions provide config files instead).
By default CMake tries module mode first, then config mode. find_package(fmt CONFIG REQUIRED) forces config mode.
If a package is installed in a non-standard location, tell CMake: -DCMAKE_PREFIX_PATH=/opt/fmt (a list of install prefixes), or -Dfmt_DIR=/path/to/dir/containing/fmtConfig.cmake. Package managers such as vcpkg and Conan work by installing packages and pointing CMake at them through a toolchain file or presets.
Example
cmake_minimum_required(VERSION 3.25)
project(fetcher LANGUAGES CXX)
find_package(Threads REQUIRED) # module mode: FindThreads.cmake ships with CMake
find_package(ZLIB 1.2 REQUIRED) # FindZLIB -> ZLIB::ZLIB
find_package(fmt 10 CONFIG REQUIRED) # config mode: fmtConfig.cmake from the install
find_package(OpenSSL) # optional
message(STATUS "zlib ${ZLIB_VERSION}, OpenSSL found: ${OpenSSL_FOUND}")
add_executable(fetcher main.cpp)
target_link_libraries(fetcher PRIVATE fmt::fmt ZLIB::ZLIB Threads::Threads)
if(OpenSSL_FOUND)
target_link_libraries(fetcher PRIVATE OpenSSL::SSL)
target_compile_definitions(fetcher PRIVATE HAVE_OPENSSL=1)
endif()
# $ cmake -S . -B build -DCMAKE_PREFIX_PATH="$HOME/.local;/opt/fmt"Remember
- find_package(Name REQUIRED) then link the imported target Name::Name
- Config mode uses the package's own Config.cmake; module mode a FindXxx.cmake
- Point CMake at custom installs with CMAKE_PREFIX_PATH
Watch out for
- Linking ${ZLIB_LIBRARIES} and adding include dirs by hand when an imported target ZLIB::ZLIB exists and carries everything.