C++ CMake find_package Complete Guide | Integrating External Libraries
이 글의 핵심
CMake find_package: locate Boost, OpenSSL, Qt with imported targets, CONFIG vs Module mode, and custom Find*.cmake—dependency integration for C++ builds.
What is find_package? Why is it needed?
Problem Scenario: The External Library Linking Nightmare
The Problem: You want to use the Boost library. The header path is /usr/include/boost, and the library is located at /usr/lib/libboost_filesystem.so. However, on macOS, it’s installed via Homebrew at /opt/homebrew/include, and on Windows, it’s in C:\boost. Hardcoding paths for each platform makes maintenance impossible.
The Solution: find_package automatically locates libraries installed on the system and provides header paths, library paths, and version information. By simply using find_package(Boost REQUIRED), CMake finds the library and creates targets like Boost::filesystem for you.
flowchart LR
subgraph find["find_package(Boost)"]
search["Search system paths"]
end
subgraph system["System"]
linux["/usr/lib/libboost*.so"]
mac["/opt/homebrew/lib"]
win["C:/boost/lib"]
end
subgraph result["Result"]
target["Creates Boost::filesystem target"]
vars["Boost_FOUND, Boost_VERSION variables"]
end
search --> linux
search --> mac
search --> win
linux --> target
mac --> target
win --> target
search --> vars
Table of Contents
- Basic Usage
- Examples for Common Libraries
- Config vs Module Mode
- Writing a Custom FindModule
- Common Issues and Solutions
- Production Patterns
- Complete Example: Integrating Multiple Libraries
1. Basic Usage
Required Packages
find_package(Boost REQUIRED)
if(Boost_FOUND)
message(STATUS "Boost found: ${Boost_VERSION}")
else()
message(FATAL_ERROR "Boost not found")
endif()
Optional Packages
find_package(SomeLib)
if(SomeLib_FOUND)
target_link_libraries(myapp PRIVATE SomeLib::SomeLib)
else()
message(WARNING "SomeLib not found, using fallback")
endif()
Specifying Versions
# Minimum version
find_package(Boost 1.70 REQUIRED)
# Exact version
find_package(Boost 1.75 EXACT REQUIRED)
# Version range (CMake 3.19+)
find_package(Boost 1.70...1.80 REQUIRED)
Specifying Components
find_package(Boost REQUIRED COMPONENTS
filesystem
system
thread
)
target_link_libraries(myapp PRIVATE
Boost::filesystem
Boost::system
Boost::thread
)
2. Examples for Common Libraries
Boost
find_package(Boost 1.70 REQUIRED COMPONENTS filesystem system)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE
Boost::filesystem
Boost::system
)
OpenSSL
find_package(OpenSSL REQUIRED)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE
OpenSSL::SSL
OpenSSL::Crypto
)
Qt5
find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE
Qt5::Core
Qt5::Widgets
)
# Automatically run Qt MOC
set_target_properties(myapp PROPERTIES
AUTOMOC ON
AUTOUIC ON
AUTORCC ON
)
Google Test
find_package(GTest REQUIRED)
add_executable(tests test.cpp)
target_link_libraries(tests PRIVATE
GTest::gtest
GTest::gtest_main
)
OpenCV
find_package(OpenCV REQUIRED)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE ${OpenCV_LIBS})
target_include_directories(myapp PRIVATE ${OpenCV_INCLUDE_DIRS})
Using pkg-config
find_package(PkgConfig REQUIRED)
pkg_check_modules(CURL REQUIRED libcurl)
pkg_check_modules(SQLITE REQUIRED sqlite3)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE
${CURL_LIBRARIES}
${SQLITE_LIBRARIES}
)
target_include_directories(myapp PRIVATE
${CURL_INCLUDE_DIRS}
${SQLITE_INCLUDE_DIRS}
)
3. Config vs Module Mode
Config Mode (Recommended)
This mode is used when a library provides a SomeLibConfig.cmake or somelib-config.cmake file. Most modern libraries provide Config files.
find_package(fmt REQUIRED)
# If fmt provides fmtConfig.cmake, it will be found automatically
target_link_libraries(myapp PRIVATE fmt::fmt)
Search Paths:
<prefix>/lib/cmake/<name>/<prefix>/share/<name>/- Paths specified in
CMAKE_PREFIX_PATH
Module Mode
This mode uses CMake’s built-in Find<Name>.cmake module.
find_package(CURL REQUIRED)
# Uses CMake's FindCURL.cmake module
target_link_libraries(myapp PRIVATE CURL::libcurl)
Search Paths:
CMAKE_MODULE_PATH- Built-in CMake module paths
Choosing a Mode
# Config mode only
find_package(SomeLib CONFIG REQUIRED)
# Module mode only
find_package(SomeLib MODULE REQUIRED)
# Automatic (Config first, fallback to Module)
find_package(SomeLib REQUIRED)
4. Writing a Custom FindModule
Example: FindMyLib.cmake
# cmake/FindMyLib.cmake
# Find headers
find_path(MyLib_INCLUDE_DIR
NAMES mylib/mylib.h
PATHS /usr/include /usr/local/include
)
# Find libraries
find_library(MyLib_LIBRARY
NAMES mylib
PATHS /usr/lib /usr/local/lib
)
# Check version (optional)
if(MyLib_INCLUDE_DIR)
file(READ "${MyLib_INCLUDE_DIR}/mylib/version.h" VERSION_CONTENT)
string(REGEX MATCH "MYLIB_VERSION \"([0-9.]+)\"" _ "${VERSION_CONTENT}")
set(MyLib_VERSION ${CMAKE_MATCH_1})
endif()
# Handle results
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib
REQUIRED_VARS MyLib_LIBRARY MyLib_INCLUDE_DIR
VERSION_VAR MyLib_VERSION
)
# Create target
if(MyLib_FOUND AND NOT TARGET MyLib::MyLib)
add_library(MyLib::MyLib UNKNOWN IMPORTED)
set_target_properties(MyLib::MyLib PROPERTIES
IMPORTED_LOCATION "${MyLib_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${MyLib_INCLUDE_DIR}"
)
endif()
Usage
# CMakeLists.txt
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(MyLib REQUIRED)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE MyLib::MyLib)
5. Common Issues and Solutions
Issue 1: Could not find package
Symptom: CMake Error: Could not find a package configuration file provided by "SomeLib".
Cause: The library is not installed or is located in an unknown path.
# Solution 1: Install the package
sudo apt install libboost-dev # Linux
brew install boost # macOS
vcpkg install boost # vcpkg
# Solution 2: Specify CMAKE_PREFIX_PATH
cmake -DCMAKE_PREFIX_PATH=/custom/install/path ..
# Solution 3: Use environment variables
export CMAKE_PREFIX_PATH=/usr/local:$CMAKE_PREFIX_PATH
cmake ..
# Solution 4: Use package-specific hint variables
cmake -DBoost_ROOT=/usr/local/boost ..
Issue 2: Version Mismatch
Symptom: Could not find a configuration file for package "Boost" that is compatible with requested version "1.80".
Cause: Installed version is lower than the required version.
# Solution 1: Relax version requirements
find_package(Boost 1.70 REQUIRED) # 1.80 → 1.70
# Solution 2: Check version and conditionally proceed
find_package(Boost 1.70)
if(Boost_VERSION VERSION_LESS 1.80)
message(WARNING "Boost 1.80+ recommended, found ${Boost_VERSION}")
endif()
Issue 3: Missing Components
Symptom: Unable to find the requested Boost libraries. Boost component "filesystem" not found.
Cause: The required component is not installed.
# Linux
sudo apt install libboost-filesystem-dev
# macOS
brew install boost
# Windows (vcpkg)
vcpkg install boost-filesystem
Issue 4: Config vs Module Confusion
Symptom: find_package succeeds, but no target is created.
Cause: Found the package in Module mode, but variable names differ.
# Module mode (FindCURL.cmake)
find_package(CURL REQUIRED)
# Variables: CURL_INCLUDE_DIRS, CURL_LIBRARIES
target_include_directories(myapp PRIVATE ${CURL_INCLUDE_DIRS})
target_link_libraries(myapp PRIVATE ${CURL_LIBRARIES})
# Config mode (CURLConfig.cmake)
find_package(CURL REQUIRED)
# Target: CURL::libcurl
target_link_libraries(myapp PRIVATE CURL::libcurl)
Issue 5: Multiple Versions Installed
Symptom: The wrong version is selected.
# Specify the path to the desired version
cmake -DBoost_ROOT=/usr/local/boost-1.80 ..
# Or add priority paths to CMAKE_PREFIX_PATH
cmake -DCMAKE_PREFIX_PATH="/usr/local/boost-1.80;/usr/local" ..
6. Production Patterns
Pattern 1: Optional Dependencies
option(USE_OPENSSL "Use OpenSSL for encryption" ON)
if(USE_OPENSSL)
find_package(OpenSSL)
if(OpenSSL_FOUND)
target_link_libraries(myapp PRIVATE OpenSSL::SSL)
target_compile_definitions(myapp PRIVATE USE_OPENSSL)
else()
message(WARNING "OpenSSL not found, using fallback")
endif()
endif()
Pattern 2: Version Check and Feature Branching
find_package(Boost 1.70 REQUIRED COMPONENTS filesystem)
if(Boost_VERSION VERSION_GREATER_EQUAL 1.75)
message(STATUS "Using Boost 1.75+ features")
target_compile_definitions(myapp PRIVATE BOOST_NEW_API)
endif()
Pattern 3: Choosing Between Multiple Packages
# Prefer OpenSSL, fallback to mbedTLS
find_package(OpenSSL)
if(OpenSSL_FOUND)
target_link_libraries(myapp PRIVATE OpenSSL::SSL)
target_compile_definitions(myapp PRIVATE USE_OPENSSL)
else()
find_package(mbedTLS REQUIRED)
target_link_libraries(myapp PRIVATE mbedTLS::mbedtls)
target_compile_definitions(myapp PRIVATE USE_MBEDTLS)
endif()
Pattern 4: Printing Package Information
find_package(Boost REQUIRED COMPONENTS filesystem)
message(STATUS "Boost version: ${Boost_VERSION}")
message(STATUS "Boost include: ${Boost_INCLUDE_DIRS}")
message(STATUS "Boost libraries: ${Boost_LIBRARIES}")
Pattern 5: Custom Search Paths
# Add local FindModule path for the project
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Add custom prefix paths
list(APPEND CMAKE_PREFIX_PATH "/opt/mylibs")
find_package(MyLib REQUIRED)
7. Complete Example: Integrating Multiple Libraries
Project: HTTP Server (Boost + OpenSSL + spdlog)
cmake_minimum_required(VERSION 3.20)
project(HttpServer VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Required packages
find_package(Boost 1.70 REQUIRED COMPONENTS
system
thread
filesystem
)
find_package(OpenSSL REQUIRED)
# Optional packages
find_package(spdlog)
# Executable
add_executable(http_server
src/main.cpp
src/server.cpp
src/request_handler.cpp
)
# Linking
target_link_libraries(http_server PRIVATE
Boost::system
Boost::thread
Boost::filesystem
OpenSSL::SSL
OpenSSL::Crypto
)
# Use spdlog if available
if(spdlog_FOUND)
target_link_libraries(http_server PRIVATE spdlog::spdlog)
target_compile_definitions(http_server PRIVATE USE_SPDLOG)
else()
message(WARNING "spdlog not found, using std::cout")
endif()
# Include directories
target_include_directories(http_server PRIVATE
${CMAKE_SOURCE_DIR}/include
)
main.cpp
#include <boost/asio.hpp>
#include <openssl/ssl.h>
#ifdef USE_SPDLOG
#include <spdlog/spdlog.h>
#define LOG(msg) spdlog::info(msg)
#else
#include <iostream>
#define LOG(msg) std::cout << msg << '\n'
#endif
int main() {
LOG("HTTP Server starting...");
boost::asio::io_context io;
// Server logic...
return 0;
}
Variables for Each Package
| Package | Target | Variables (Module Mode) |
|---|---|---|
| Boost | Boost::filesystem | Boost_FOUND, Boost_INCLUDE_DIRS, Boost_LIBRARIES |
| OpenSSL | OpenSSL::SSL, OpenSSL::Crypto | OPENSSL_FOUND, OPENSSL_INCLUDE_DIR, OPENSSL_LIBRARIES |
| CURL | CURL::libcurl | CURL_FOUND, CURL_INCLUDE_DIRS, CURL_LIBRARIES |
| ZLIB | ZLIB::ZLIB | ZLIB_FOUND, ZLIB_INCLUDE_DIRS, ZLIB_LIBRARIES |
| GTest | GTest::gtest, GTest::gtest_main | GTEST_FOUND, GTEST_INCLUDE_DIRS, GTEST_LIBRARIES |
Recommendation: Always use targets (e.g., Boost::filesystem) when available. They are type-safe and automatically propagate PUBLIC/PRIVATE properties.
Summary
| Concept | Description |
|---|---|
| find_package | Automatically finds external libraries |
| REQUIRED | Marks a package as mandatory (errors if not found) |
| COMPONENTS | Specifies library components |
| Config Mode | Uses <Name>Config.cmake (recommended) |
| Module Mode | Uses Find<Name>.cmake |
| Targets | Use Boost::filesystem style (recommended) |
| Variables | Use ${Boost_LIBRARIES} style (legacy) |
find_package is a core feature of CMake that allows you to find and link external libraries in a platform-independent way.
FAQ
Q1: find_package vs pkg-config?
A: find_package is the native CMake method for finding Config/Module files, while pkg-config is a Unix-specific tool for reading .pc files. Most modern libraries provide CMake Config files, so find_package is recommended.
Q2: Targets vs Variables?
A: Use targets (e.g., Boost::filesystem) whenever possible. They are more robust and automatically handle PUBLIC/PRIVATE propagation. Config mode typically provides targets, while Module mode often provides variables.
Q3: What happens if I omit REQUIRED?
A: If the package is not found, no error is raised, but the <Name>_FOUND variable is set to FALSE. This is useful for optional dependencies.
Q4: What is CMAKE_PREFIX_PATH?
A: It is an additional search path for CMake to find packages. Use it to locate libraries installed in non-standard locations. Separate multiple paths with a semicolon: -DCMAKE_PREFIX_PATH="/opt/lib1;/opt/lib2".
Q5: What if find_package fails?
A:
- Check if the library is installed (
apt list --installed,brew list). - Add the installation path to
CMAKE_PREFIX_PATH. - Use package-specific hint variables (
Boost_ROOT,Qt5_DIR, etc.). - Enable debug mode with
CMAKE_FIND_DEBUG_MODE=ONto trace the search process.
Q6: Where can I learn more about find_package?
A:
- CMake find_package Official Documentation
- “Professional CMake: A Practical Guide”
- CMake Package Registry
TL;DR: Use find_package to automatically locate and link external libraries. Next, consider reading about Conan Package Manager for more advanced dependency management.