Skip to content

Wiki

Third-party library dependency declaration

About 20 min read

Existing English translations were reused. 34 current source blocks remain in Simplified Chinese, without triggering paid translation.

本节专门讲第三方库如何安装、如何在 CMake 中查找、如何放到模板的 Third-party dependencies 区块里。

The principle of this template is:

# ========================
# Third-party dependencies
# ========================
find_package(Eigen3 REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PUBLIC
    Eigen3::Eigen
)

That is:

  1. Whoever uses a third-party library writes the find_package.
  2. Third-party dependencies are centrally placed in this module's Third-party dependencies section.
  3. Prefer linking modern CMake targets, such as Eigen3::Eigen and OpenCV::opencv_core.
  4. Do not pile all third-party libraries into the top-level CMakeLists.txt.

安装命令按系统选择:Linux 使用系统包管理器,Windows 本教程使用 MSYS2 UCRT64。pacman 命令在 UCRT64 终端执行,日常 CMake 命令可以在配置好 PATH 的 PowerShell 中执行。安装同一个库后,两种平台尽量复用下面的 target 写法。

1.find_package Basic syntax

find_package(<PackageName> [version] [REQUIRED] [COMPONENTS components...])

Common notation:

find_package(Eigen3 REQUIRED)
find_package(OpenCV REQUIRED)
find_package(Boost REQUIRED COMPONENTS system filesystem)
find_package(PCL REQUIRED COMPONENTS common io)

Parameter description:

Parameter Function
<PackageName> Package name, for example Eigen3、OpenCV
version Required minimum version or exact version
REQUIRED If not found, report an error directly
COMPONENTS Only search for certain components

1.1.REQUIRED

find_package(Eigen3 REQUIRED)

If Eigen is not found, the CMake configure phase fails directly.

If not written:

find_package(Eigen3)

you need to determine it yourself:

if(Eigen3_FOUND)
  target_link_libraries(my_target PUBLIC Eigen3::Eigen)
endif()

In engineering templates, REQUIRED is usually written, because the earlier an error is reported when a dependency is missing, the better.

1.2.COMPONENTS

Libraries such as OpenCV, Boost, and PCL usually have multiple modules.

For example:

find_package(OpenCV REQUIRED COMPONENTS core imgproc highgui)

Indicates that only the following is needed:

  1. opencv_core
  2. opencv_imgproc
  3. opencv_highgui

This is clearer than directly importing the entire OpenCV.

When linking third-party libraries, also consider PUBLIC、PRIVATE、INTERFACE.

Keywords When to use
PRIVATE Third-party libraries are only used in .cpp, and the header file does not expose it
PUBLIC The header file includes third-party library types, and users also need to know about it
INTERFACE The current target does not compile itself, and only propagates downstream

For example,lib1 if the header file for is just like this:

#pragma once

namespace lib1 {
void run_eigen_vector_example();
}

The header file does not expose Eigen types, then Eigen can use PRIVATE:

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    Eigen3::Eigen
)

If the header file is written as:

#pragma once

#include <Eigen/Dense>

namespace lib1 {
Eigen::Vector3d make_vector();
}

At this point, when the downstream includes this header file, the Eigen include path is also required, so PUBLIC should be used:

target_link_libraries(${PREFIX}_src_lib
  PUBLIC
    Eigen3::Eigen
)

This template example uses PUBLIC to demonstrate dependency propagation; in actual projects, the choice can be made based on whether the header file exposes third-party types.

3.Eigen3

Eigen is a commonly used linear algebra library, mainly a header-only library.

3.1.Install

Ubuntu/Debian:

sudo apt install libeigen3-dev

Fedora:

sudo dnf install eigen3-devel

Windows,MSYS2 UCRT64:

pacman -S --needed mingw-w64-ucrt-x86_64-eigen3

软件包信息见 MSYS2 官方包页面。

Eigen 是头文件库,重点是让 CMake 找到头文件和 Eigen3Config.cmake。自行安装时,设置安装前缀 CMAKE_PREFIX_PATH,或把 Eigen3_DIR 指向配置文件目录;不需要为 GCC 和 MSVC 分别编译一份 Eigen。

3.2.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(Eigen3 REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PUBLIC
    Eigen3::Eigen
)

3.3.C++ Use

#include <Eigen/Dense>

Eigen::Vector3d v(1.0, 2.0, 3.0);

3.4.Visibility Recommendations

场景 链接方式
Eigen 只在 .cpp 中使用 PRIVATE Eigen3::Eigen
头文件暴露 Eigen::Matrix、Eigen::Vector PUBLIC Eigen3::Eigen

4.OpenCV4

OpenCV is a computer vision library with many modules; it is recommended to include it by component.

4.1.Install

Ubuntu/Debian:

sudo apt install libopencv-dev

Fedora:

sudo dnf install opencv-devel

4.2.Common components

组件 作用
core 基础数据结构,例如 cv::Mat
imgproc 图像处理
imgcodecs 读写图片
highgui 简单窗口显示
videoio 摄像头和视频读写
calib3d 相机标定、几何
features2d 特征点
dnn DNN 推理模块

Windows,MSYS2 UCRT64:

pacman -S --needed mingw-w64-ucrt-x86_64-opencv

软件包信息见 MSYS2 官方包页面。

MSYS2 软件包随仓库更新,不保证一直提供同一个 OpenCV 主版本。本节的 API 示例沿用 OpenCV 4 的用法;如果项目明确要求 4.x,应安装相应版本并检查 CMake 的版本要求。还要确认下载的 Windows 二进制库是否适合当前 MinGW 工具链,不能直接假定其他编译器生成的库可混用。

4.3.CMake style: recommended by component

# ========================
# Third-party dependencies
# ========================
find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs highgui)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    opencv_core
    opencv_imgproc
    opencv_imgcodecs
    opencv_highgui
)

Some OpenCV installations provide the OpenCV::opencv_core imported target, so you can also write:

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    OpenCV::opencv_core
    OpenCV::opencv_imgproc
    OpenCV::opencv_imgcodecs
    OpenCV::opencv_highgui
)

If your system does not have these OpenCV:: targets, use the previous opencv_core syntax.

4.4.CMake syntax: the simple and brutal version

find_package(OpenCV REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    ${OpenCV_LIBS}
)

This approach works, but it is less clear than the component-based approach. For template teaching, it is recommended to prioritize writing it as components.

4.5.C++ Use

#include <opencv2/opencv.hpp>

cv::Mat image = cv::imread("test.png");

5.Boost

Boost is a large collection of C++ libraries. Here, system and filesystem are used as examples.

5.1.Install

Ubuntu/Debian:

sudo apt install libboost-all-dev

Fedora:

sudo dnf install boost-devel

If you only want to install a small number of components, Ubuntu/Debian can also be installed as needed, similar to:

sudo apt install libboost-system-dev libboost-filesystem-dev

Windows,MSYS2 UCRT64:

pacman -S --needed mingw-w64-ucrt-x86_64-boost

软件包信息见 MSYS2 官方包页面。

5.2.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(Boost REQUIRED COMPONENTS system filesystem)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    Boost::system
    Boost::filesystem
)

5.3.C++ Use

#include <boost/filesystem.hpp>

boost::filesystem::path p{"."};

Note: If using C++17's std::filesystem many scenarios no longer require Boost.Filesystem.

6.PCL

PCL is the Point Cloud Library, commonly used in robotics, 3D perception, and SLAM projects.

6.1.Install

Ubuntu/Debian:

sudo apt install libpcl-dev

Fedora:

sudo dnf install pcl-devel

6.2.Common components

Component Function
common Point types, basic tools
io PCD/PLY and other file reading and writing
filters Filtering
features Features
registration Registration
segmentation Segmentation
visualization Visualization

Windows:

PCL 的依赖较多,先确认是否有适合当前 MinGW-w64 / UCRT64 工具链的安装方式。可以在 UCRT64 中搜索:

pacman -Ss pcl

按搜索结果确认仓库、架构和实际包名,再决定是否安装;没有合适的包时,需要用匹配的工具链构建 PCL 及相关依赖。不要把某个 MSVC 预编译安装包直接当成 MinGW 库使用。源码构建的基本要求见 PCL 官方 Windows 构建说明,其中的编译器示例也要结合当前工具链判断。

6.3.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(PCL REQUIRED COMPONENTS common io filters)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    ${PCL_LIBRARIES}
)

target_include_directories(${PREFIX}_src_lib
  PRIVATE
    ${PCL_INCLUDE_DIRS}
)

target_compile_definitions(${PREFIX}_src_lib
  PRIVATE
    ${PCL_DEFINITIONS}
)

Some PCL versions also provide imported targets. If your environment supports it, you can preferentially use something like:

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    PCL::common
    PCL::io
    PCL::filters
)

The actual choice is subject to the result provided by your local find_package(PCL ...).

7.fmt

fmt is a formatted output library, C++20 std::format style also comes from it.

7.1.Install

Ubuntu/Debian:

sudo apt install libfmt-dev

Fedora:

sudo dnf install fmt-devel

Windows,MSYS2 UCRT64:

pacman -S --needed mingw-w64-ucrt-x86_64-fmt

软件包信息见 MSYS2 官方包页面。

7.2.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(fmt REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    fmt::fmt
)

7.3.C++ Use

#include <fmt/core.h>

auto s = fmt::format("value = {}", 42);

8.spdlog

spdlog is a commonly used logging library.

8.1.Install

Ubuntu/Debian:

sudo apt install libspdlog-dev

Fedora:

sudo dnf install spdlog-devel

Windows,MSYS2 UCRT64:

pacman -S --needed mingw-w64-ucrt-x86_64-spdlog

软件包信息见 MSYS2 官方包页面。

8.2.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(spdlog REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    spdlog::spdlog
)

8.3.C++ Use

#include <spdlog/spdlog.h>

spdlog::info("hello {}", "spdlog");

9.yaml-cpp

yaml-cpp Commonly used to read configuration files.

9.1.Install

Ubuntu/Debian:

sudo apt install libyaml-cpp-dev

Fedora:

sudo dnf install yaml-cpp-devel

Windows,MSYS2 UCRT64:

pacman -S --needed mingw-w64-ucrt-x86_64-yaml-cpp

软件包信息见 MSYS2 官方包页面。

9.2.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(yaml-cpp REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    yaml-cpp::yaml-cpp
)

In some old environments, the target name may be yaml-cpp. If yaml-cpp::yaml-cpp does not exist, adjust again based on the error.

10.nlohmann_json

nlohmann_json is a commonly used JSON library, usually a header-only library.

10.1.Install

Ubuntu/Debian:

sudo apt install nlohmann-json3-dev

Fedora:

sudo dnf install json-devel

Windows,MSYS2 UCRT64:

pacman -S --needed mingw-w64-ucrt-x86_64-nlohmann-json

软件包信息见 MSYS2 官方包页面。

10.2.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(nlohmann_json REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    nlohmann_json::nlohmann_json
)

10.3.C++ Use

#include <nlohmann/json.hpp>

nlohmann::json data;
data["name"] = "cmake_template";

11.Threads

C++ 标准线程库通常不需要安装额外包,但链接时建议用 CMake 的 Threads 包。

11.1.Install

Generally, it does not need to be installed separately.

If the compiler toolchain is missing:

Ubuntu/Debian:

sudo apt install build-essential

Fedora:

sudo dnf install gcc gcc-c++ make

11.2.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(Threads REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    Threads::Threads
)

11.3.C++ Use

#include <thread>

std::thread worker([] {
    // do work
});
worker.join();

12.OpenMP

OpenMP is used for multithreaded parallel computing.

12.1.Install

Ubuntu/Debian:

sudo apt install libomp-dev

Fedora:

sudo dnf install libgomp

12.2.CMake syntax

# ========================
# Third-party dependencies
# ========================
find_package(OpenMP REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    OpenMP::OpenMP_CXX
)

12.3.C++ Use

#include <omp.h>

#pragma omp parallel for
for (int i = 0; i < 100; ++i) {
    // parallel work
}

13.Sophus

Sophus is a Lie group and Lie algebra library, commonly used in SLAM and robot pose computation.

13.1.Install

Many distribution repositories do not necessarily provide a suitable version; a common practice is to install from source, or rely on ROS / project dependency management.

If provided by the system repository, you can try searching:

apt search sophus
dnf search sophus

13.2.CMake syntax

If it is already installed and a CMake config is provided:

# ========================
# Third-party dependencies
# ========================
find_package(Sophus REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    Sophus::Sophus
)

Sophus often depends on Eigen. If your code also directly uses Eigen, you can also explicitly write:

find_package(Eigen3 REQUIRED)
find_package(Sophus REQUIRED)

target_link_libraries(${PREFIX}_src_lib
  PUBLIC
    Eigen3::Eigen
  PRIVATE
    Sophus::Sophus
)

14.Common Dependencies Quick Reference

library Ubuntu/Debian Fedora CMake find Common link targets
Eigen3 libeigen3-dev eigen3-devel find_package(Eigen3 REQUIRED) Eigen3::Eigen
OpenCV libopencv-dev opencv-devel find_package(OpenCV REQUIRED COMPONENTS ...) opencv_core etc.
Boost libboost-all-dev boost-devel find_package(Boost REQUIRED COMPONENTS ...) Boost::system etc.
PCL libpcl-dev pcl-devel find_package(PCL REQUIRED COMPONENTS ...) ${PCL_LIBRARIES} or PCL::common
fmt libfmt-dev fmt-devel find_package(fmt REQUIRED) fmt::fmt
spdlog libspdlog-dev spdlog-devel find_package(spdlog REQUIRED) spdlog::spdlog
yaml-cpp libyaml-cpp-dev yaml-cpp-devel find_package(yaml-cpp REQUIRED) yaml-cpp::yaml-cpp
nlohmann_json nlohmann-json3-dev json-devel find_package(nlohmann_json REQUIRED) nlohmann_json::nlohmann_json
Threads Usually no separate installation is required Usually no separate installation is required find_package(Threads REQUIRED) Threads::Threads
OpenMP libomp-dev libgomp find_package(OpenMP REQUIRED) OpenMP::OpenMP_CXX

Package names may differ slightly across distributions and versions. If installation fails, first use:

apt search <关键字>
dnf search <关键字>

Confirm the package name.

14.1.Windows 常用安装包

在 UCRT64 终端中使用下表的软件包名称。具体版本以对应官方包页面为准。

库 UCRT64 软件包
Eigen mingw-w64-ucrt-x86_64-eigen3
OpenCV mingw-w64-ucrt-x86_64-opencv
Boost mingw-w64-ucrt-x86_64-boost
fmt mingw-w64-ucrt-x86_64-fmt
spdlog mingw-w64-ucrt-x86_64-spdlog
yaml-cpp mingw-w64-ucrt-x86_64-yaml-cpp
nlohmann_json mingw-w64-ucrt-x86_64-nlohmann-json

Threads 优先使用工具链自带支持和 Threads::Threads。GCC 的 OpenMP 支持通常随工具链安装,先用 find_package(OpenMP) 检查;安装后还要验证 OpenMP 运行环境。PCL、Sophus 等按具体依赖和工具链单独确认,不在这里假设存在某个安装包。

15.A module imports both Eigen and OpenCV at the same time

For example lib1 Use Eigen and OpenCV together:

# ========================
# Third-party dependencies
# ========================
find_package(Eigen3 REQUIRED)
find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs)

target_link_libraries(${PREFIX}_src_lib
  PUBLIC
    Eigen3::Eigen
  PRIVATE
    opencv_core
    opencv_imgproc
    opencv_imgcodecs
)

如果头文件不暴露 Eigen 类型,也可以把 Eigen 改成 PRIVATE:

target_link_libraries(${PREFIX}_src_lib
  PRIVATE
    Eigen3::Eigen
    opencv_core
    opencv_imgproc
    opencv_imgcodecs
)

16.Not recommended approach

16.1.Not recommended: Looking up all libraries centrally at the top level

# 顶层 CMakeLists.txt
find_package(Eigen3 REQUIRED)
find_package(OpenCV REQUIRED)
find_package(PCL REQUIRED)

Question:

  1. The upper layers are becoming increasingly chaotic.
  2. It is unclear which module actually uses which library.
  3. When deleting a module, it is easy to miss deleting dependencies.
  4. When newcomers read the project, the dependency relationships are unclear.

16.2.Not recommended: global include

include_directories(${OpenCV_INCLUDE_DIRS})
link_libraries(${OpenCV_LIBS})

Question:

  1. Affects all targets.
  2. Dependency relationships are unclear.
  3. May introduce unexpected include order issues.

Modern CMake recommends:

target_link_libraries(my_target
  PRIVATE
    opencv_core
)

If the library provides an imported target, the include paths and linked libraries will automatically propagate with the target.

17.Troubleshoot find_package Library not found

17.1.Step 1: Confirm whether the system package is installed

dpkg -l | grep eigen
rpm -qa | grep eigen

17.2.Step 2: Confirm that CMake can see the config file

Common file names:

Eigen3Config.cmake
OpenCVConfig.cmake
PCLConfig.cmake
fmtConfig.cmake

17.3.Step 3: Manually specify the search path

If the library is installed in a non-standard directory, you can add this when running configure:

cmake --preset linux-debug -DCMAKE_PREFIX_PATH=/opt/some_library

Or add it in the preset:

"CMAKE_PREFIX_PATH": "/opt/some_library"

Multiple paths can be separated by semicolons:

"CMAKE_PREFIX_PATH": "/opt/lib_a;/opt/lib_b"

17.4.Step 4: Check the CMake error information

CMake usually tells you which config file is missing, for example:

Could not find a package configuration file provided by "OpenCV"

In this case, prioritize checking:

  1. Whether the development package is installed.
  2. Whether the package name is correct.
  3. Whether it is installed to a non-standard path.

18.Windows 的查找路径和运行环境

已经安装库但 CMake 仍然找不到时,可以在 PowerShell 中指定安装前缀:

$env:CMAKE_PREFIX_PATH = "C:/deps/eigen;C:/deps/opencv"
cmake --preset windows-debug

这里填安装根目录,多个 Windows 前缀用分号分隔。也可以使用本地 CMakeUserPresets.json 保存这些路径。项目包配置仍应优先提供可复用的 imported target。

find_package 成功后,还要实际运行程序。开发时可以把依赖的 bin/ 加入 PATH;验证安装结果时,按所用第三方库的安装要求准备运行环境。

模板只处理自己的目标和常用 GCC 运行库。添加新的第三方依赖后,还要补齐相应安装步骤,并检查安装后的程序能否运行。