CMake find_package for C++ | Boost, OpenSSL, pkg-config & Custom Find Modules

CMake find_package for C++ | Boost, OpenSSL, pkg-config & Custom Find Modules

이 글의 핵심

Use find_package to locate libraries portably: versions, components, CONFIG vs MODULE, and production patterns for optional dependencies.

What is find_package? why you need it

Problem: I’m trying to use the Boost library. The header path is /usr/include/boost and the library is /usr/lib/libboost_filesystem.so. However, on macOS, it is installed with Homebrew and is located in /opt/homebrew/include, and on Windows, it is located in C:\boost. Hardcoding paths for each platform makes maintenance impossible.

Solution: find_package automatically finds libraries installed on your system and provides header path, library path, and version information. Just use find_package(Boost REQUIRED) and CMake will automatically find it and create a target such as Boost::filesystem.

flowchart LR
    subgraph find["find_package(Boost)"]
        search["Search system path"]
    end
    subgraph system["system"]
        linux["/usr/lib/libboost*.so"]
        mac["/opt/homebrew/lib"]
        win["C:/boost/lib"]
    end
    subgraph result["Result"]
        target["Create Boost filesystem target"]
        vars["Boost_FOUND, Boost_VERSION variables"]
    end
    search --> linux
    search --> mac
    search --> win
    linux --> target
    mac --> target
    win --> target
    search --> vars

index

  1. Basic usage
  2. Main library examples
  3. Config vs Module mode
  4. Write a custom FindModule
  5. Frequently occurring problems and solutions
  6. Production Patterns
  7. Complete example: Multi-library integration

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()

Specify version

# 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)

Specify component

find_package(Boost REQUIRED COMPONENTS
    filesystem
    system
    thread
)

target_link_libraries(myapp PRIVATE
    Boost::filesystem
    Boost::system
    Boost::thread
)

2. Main library examples

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
)

# Autorun 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

This is if the 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)

Browse Path:

  • <prefix>/lib/cmake/<name>/
  • <prefix>/share/<name>/
  • Path specified in CMAKE_PREFIX_PATH

Module mode

This is the case when using the Find<Name>.cmake module provided by CMake.

find_package(CURL REQUIRED)
# Use CMake's FindCURL.cmake module
target_link_libraries(myapp PRIVATE CURL::libcurl)

Browse Path:

  • CMAKE_MODULE_PATH
  • CMake built-in module path

Select mode

# Config mode only
find_package(SomeLib CONFIG REQUIRED)

# Module mode only
find_package(SomeLib MODULE REQUIRED)

# Automatic (Config first, if not, Module)
find_package(SomeLib REQUIRED)

4. Writing a custom FindModule

FindMyLib.cmake example

# cmake/FindMyLib.cmake

# Find header
find_path(MyLib_INCLUDE_DIR
    NAMES mylib/mylib.h
    PATHS /usr/include /usr/local/include
)

# Find library
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()

# Process 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()

use

# 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. Frequently occurring problems and solutions

Problem 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 in a location that CMake cannot find.

# Solution 1: Install 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: Environment variables
export CMAKE_PREFIX_PATH=/usr/local:$CMAKE_PREFIX_PATH
cmake ..

# Solution 4: 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: The 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: Conditional after version check
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: Component not installed.

# Linux
sudo apt install libboost-filesystem-dev

# macOS
brew install boost

# Windows (vcpkg)
vcpkg install boost-filesystem

Problem 4: Config vs Module confusion

Symptom: find_package succeeds, but target is not created.

Cause: Searched in Module mode, but the variable name is different.

# 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: Wrong version selected.

# Specify a specific version path
cmake -DBoost_ROOT=/usr/local/boost-1.80 ..

# Or add priority path to CMAKE_PREFIX_PATH
cmake -DCMAKE_PREFIX_PATH="/usr/local/boost-1.80;/usr/local" ..

6. production pattern

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 checking 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: Select one of several packages

# OpenSSL first, if not 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: Print 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 navigation path

# Add project local FindModule path
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")

# custom prefix path
list(APPEND CMAKE_PREFIX_PATH "/opt/mylibs")

find_package(MyLib REQUIRED)

7. Complete example: multi-library integration

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 package
find_package(spdlog)

# executable file
add_executable(http_server
    src/main.cpp
    src/server.cpp
    src/request_handler.cpp
)

# link
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()

# header path
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;
}

Package-specific variable names

packagetargetVariable (Module mode)
BoostBoost::filesystemBoost_FOUND, Boost_INCLUDE_DIRS, Boost_LIBRARIES
OpenSSLOpenSSL::SSL, OpenSSL::CryptoOPENSSL_FOUND, OPENSSL_INCLUDE_DIR, OPENSSL_LIBRARIES
CURLCURL::libcurlCURL_FOUND, CURL_INCLUDE_DIRS, CURL_LIBRARIES
ZLIBZLIB::ZLIBZLIB_FOUND, ZLIB_INCLUDE_DIRS, ZLIB_LIBRARIES
GTestGTest::gtest, GTest::gtest_mainGTEST_FOUND, GTEST_INCLUDE_DIRS, GTEST_LIBRARIES

Recommended: Use target (Boost::filesystem) whenever possible. It is more type safe than variables, and PUBLIC/PRIVATE propagation is automatic.


organize

conceptDescription
find_packageAutomatic discovery of external libraries
REQUIREDRequired packages (error if missing)
COMPONENTSSpecifying library components
Config ModeUse <Name>Config.cmake (recommended)
Module modeUsing Find<Name>.cmake
TargetBoost::filesystem format (recommended)
VariableBoost_LIBRARIES format (legacy)

find_package is a core feature of CMake that allows you to find and link external libraries platform-independent.


FAQ

Q1: find_package vs pkg-config?

A: find_package finds Config/Module files in a CMake native way, and pkg-config reads .pc files on Unix. Find_package is recommended because newer libraries provide CMake Config files.

Q2: Target vs variable?

A: Use target (Boost::filesystem). It is more type safe than variables (${Boost_LIBRARIES}), and PUBLIC/PRIVATE propagation is automatic. Config mode provides targets, and Module mode often provides variables.

Q3: What if we leave out REQUIRED?

A: No error is generated if the package is not found, and the <Name>_FOUND variable is set to FALSE. Use for optional dependencies.

Q4: What is CMAKE_PREFIX_PATH?

A: Additional paths where CMake will look for the package. Used to find 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:

  1. Check if the library is installed (apt list --installed, brew list)
  2. Add installation path to CMAKE_PREFIX_PATH
  3. Use package-specific hint variables (Boost_ROOT, Qt5_DIR, etc.)
  4. Debugging the search process with CMAKE_FIND_DEBUG_MODE=ON

Q6: What is the find_package learning resource?

A:

One line summary: find_package allows you to automatically find and link external libraries. Next, you might want to read Conan Package Management.


Good article to read together (internal link)

Here’s another article related to this topic.

  • C++ CMake Complete Guide | Cross-platform build·latest CMake 3.28+ features·presets·modules
  • C++ CMake Targets Complete Guide | Target-based build system
  • C++ Conan Complete Guide | Modern C++ package management
  • C++ vcpkg complete guide | Microsoft C++ Package Manager

Practical tips

These are tips that can be applied right away in practice.

Debugging tips

  • If you run into a problem, check the compiler warnings first.
  • Reproduce the problem with a simple test case

Performance Tips

  • Don’t optimize without profiling
  • Set measurable indicators first

Code review tips

  • Check in advance for areas that are frequently pointed out in code reviews.
  • Follow your team’s coding conventions

Practical checklist

This is what you need to check when applying this concept in practice.

Before writing code

  • Is this technique the best way to solve the current problem?
  • Can team members understand and maintain this code?
  • Does it meet the performance requirements?

Writing code

  • Have you resolved all compiler warnings?
  • Have you considered edge cases?
  • Is error handling appropriate?

When reviewing code

  • Is the intent of the code clear?
  • Are there enough test cases?
  • Is it documented?

Use this checklist to reduce mistakes and improve code quality.


Keywords covered in this article (related search terms)

This article will be helpful if you search for C++, cmake, find-package, dependency, build, library, etc.


  • C++ CMake Targets Complete Guide | Target-based build system
  • C++ CMake |
  • C++ CMake Complete Guide | Cross-platform build·latest CMake 3.28+ features·presets·modules
  • C++ Conan Complete Guide | Modern C++ package management
  • CMake error |
... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3