第三方库依赖写法
本节专门讲第三方库如何安装、如何在 CMake 中查找、如何放到模板的 Third-party dependencies 区块里。
本模板的原则是:
# ========================
# Third-party dependencies
# ========================
find_package(Eigen3 REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PUBLIC
Eigen3::Eigen
)
也就是:
- 谁使用第三方库,谁写
find_package。 - 第三方依赖集中放在本模块的
Third-party dependencies区块。 - 优先链接现代 CMake target,例如
Eigen3::Eigen、OpenCV::opencv_core。 - 不把所有第三方库都堆到顶层
CMakeLists.txt。
find_package 基本语法
find_package(<PackageName> [version] [REQUIRED] [COMPONENTS components...])
常见写法:
find_package(Eigen3 REQUIRED)
find_package(OpenCV REQUIRED)
find_package(Boost REQUIRED COMPONENTS system filesystem)
find_package(PCL REQUIRED COMPONENTS common io)
参数说明:
| 参数 | 作用 |
|---|---|
<PackageName> | 包名,例如 Eigen3、OpenCV |
version | 要求的最低版本或精确版本 |
REQUIRED | 找不到就直接报错 |
COMPONENTS | 只查找某些组件 |
REQUIRED
find_package(Eigen3 REQUIRED)
如果没找到 Eigen,CMake configure 阶段直接失败。
如果不写:
find_package(Eigen3)
则需要自己判断:
if(Eigen3_FOUND)
target_link_libraries(my_target PUBLIC Eigen3::Eigen)
endif()
工程模板里通常写 REQUIRED,因为依赖缺失时越早报错越好。
COMPONENTS
OpenCV、Boost、PCL 这类库通常有多个模块。
例如:
find_package(OpenCV REQUIRED COMPONENTS core imgproc highgui)
表示只需要:
opencv_coreopencv_imgprocopencv_highgui
这样比直接引入全部 OpenCV 更清楚。
target_link_libraries 里的依赖可见性
第三方库链接时也要考虑 PUBLIC、PRIVATE、INTERFACE。
| 关键字 | 什么时候用 |
|---|---|
PRIVATE | 第三方库只在 .cpp 里使用,头文件不暴露它 |
PUBLIC | 头文件里包含了第三方库类型,使用者也需要知道它 |
INTERFACE | 当前 target 自己不编译,只向下游传递 |
例如,lib1 的头文件如果只是这样:
#pragma once
namespace lib1 {
void run_eigen_vector_example();
}
头文件没有暴露 Eigen 类型,那么 Eigen 可以用 PRIVATE:
target_link_libraries(${PREFIX}_src_lib
PRIVATE
Eigen3::Eigen
)
如果头文件写成:
#pragma once
#include <Eigen/Dense>
namespace lib1 {
Eigen::Vector3d make_vector();
}
此时下游包含这个头文件时也需要 Eigen include 路径,所以应该用 PUBLIC:
target_link_libraries(${PREFIX}_src_lib
PUBLIC
Eigen3::Eigen
)
本模板示例用 PUBLIC,是为了展示依赖传播;实际项目中可以按头文件是否暴露第三方类型来选择。
Eigen3
Eigen 是常用线性代数库,主要是头文件库。
安装
Ubuntu/Debian:
sudo apt install libeigen3-dev
Fedora:
sudo dnf install eigen3-devel
CMake 写法
# ========================
# Third-party dependencies
# ========================
find_package(Eigen3 REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PUBLIC
Eigen3::Eigen
)
C++ 使用
#include <Eigen/Dense>
Eigen::Vector3d v(1.0, 2.0, 3.0);
可见性建议
| 场景 | 链接方式 |
|---|---|
Eigen 只在 .cpp 中使用 | PRIVATE Eigen3::Eigen |
头文件暴露 Eigen::Matrix、Eigen::Vector | PUBLIC Eigen3::Eigen |
OpenCV4
OpenCV 是计算机视觉库,模块很多,建议按组件引入。
安装
Ubuntu/Debian:
sudo apt install libopencv-dev
Fedora:
sudo dnf install opencv-devel
常用组件
| 组件 | 作用 |
|---|---|
core | 基础数据结构,例如 cv::Mat |
imgproc | 图像处理 |
imgcodecs | 读写图片 |
highgui | 简单窗口显示 |
videoio | 摄像头和视频读写 |
calib3d | 相机标定、几何 |
features2d | 特征点 |
dnn | DNN 推理模块 |
CMake 写法:推荐按组件
# ========================
# 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
)
有些 OpenCV 安装会提供 OpenCV::opencv_core 这种 imported target,也可以写:
target_link_libraries(${PREFIX}_src_lib
PRIVATE
OpenCV::opencv_core
OpenCV::opencv_imgproc
OpenCV::opencv_imgcodecs
OpenCV::opencv_highgui
)
如果你的系统没有这些 OpenCV:: target,就使用前一种 opencv_core 写法。
CMake 写法:简单粗暴版
find_package(OpenCV REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
${OpenCV_LIBS}
)
这种写法能用,但不如组件写法清楚。模板教学推荐优先按组件写。
C++ 使用
#include <opencv2/opencv.hpp>
cv::Mat image = cv::imread("test.png");
Boost
Boost 是大型 C++ 库集合。这里以 system 和 filesystem 为例。
安装
Ubuntu/Debian:
sudo apt install libboost-all-dev
Fedora:
sudo dnf install boost-devel
如果只想安装少量组件,Ubuntu/Debian 也可以按需安装类似:
sudo apt install libboost-system-dev libboost-filesystem-dev
CMake 写法
# ========================
# Third-party dependencies
# ========================
find_package(Boost REQUIRED COMPONENTS system filesystem)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
Boost::system
Boost::filesystem
)
C++ 使用
#include <boost/filesystem.hpp>
boost::filesystem::path p{"."};
注意:如果使用 C++17 的 std::filesystem,很多场景已经不需要 Boost.Filesystem。
PCL
PCL 是点云库,机器人、三维感知、SLAM 项目中常用。
安装
Ubuntu/Debian:
sudo apt install libpcl-dev
Fedora:
sudo dnf install pcl-devel
常用组件
| 组件 | 作用 |
|---|---|
common | 点类型、基础工具 |
io | PCD/PLY 等文件读写 |
filters | 滤波 |
features | 特征 |
registration | 配准 |
segmentation | 分割 |
visualization | 可视化 |
CMake 写法
# ========================
# 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}
)
有些 PCL 版本也提供 imported targets。如果你的环境支持,可以优先使用类似:
target_link_libraries(${PREFIX}_src_lib
PRIVATE
PCL::common
PCL::io
PCL::filters
)
实际选择以你本机 find_package(PCL ...) 提供的结果为准。
fmt
fmt 是格式化输出库,C++20 std::format 的风格也来自它。
安装
Ubuntu/Debian:
sudo apt install libfmt-dev
Fedora:
sudo dnf install fmt-devel
CMake 写法
# ========================
# Third-party dependencies
# ========================
find_package(fmt REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
fmt::fmt
)
C++ 使用
#include <fmt/core.h>
auto s = fmt::format("value = {}", 42);
spdlog
spdlog 是常用日志库。
安装
Ubuntu/Debian:
sudo apt install libspdlog-dev
Fedora:
sudo dnf install spdlog-devel
CMake 写法
# ========================
# Third-party dependencies
# ========================
find_package(spdlog REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
spdlog::spdlog
)
C++ 使用
#include <spdlog/spdlog.h>
spdlog::info("hello {}", "spdlog");
yaml-cpp
yaml-cpp 常用于读取配置文件。
安装
Ubuntu/Debian:
sudo apt install libyaml-cpp-dev
Fedora:
sudo dnf install yaml-cpp-devel
CMake 写法
# ========================
# Third-party dependencies
# ========================
find_package(yaml-cpp REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
yaml-cpp::yaml-cpp
)
有些旧环境可能 target 名是 yaml-cpp,如果 yaml-cpp::yaml-cpp 不存在,再根据报错调整。
nlohmann_json
nlohmann_json 是常用 JSON 库,通常是头文件库。
安装
Ubuntu/Debian:
sudo apt install nlohmann-json3-dev
Fedora:
sudo dnf install json-devel
CMake 写法
# ========================
# Third-party dependencies
# ========================
find_package(nlohmann_json REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
nlohmann_json::nlohmann_json
)
C++ 使用
#include <nlohmann/json.hpp>
nlohmann::json data;
data["name"] = "cmake_template";
Threads
C++ 标准线程库通常不需要安装额外包,但链接时建议用 CMake 的 Threads 包。
安装
一般不需要单独安装。
如果缺少编译器工具链:
Ubuntu/Debian:
sudo apt install build-essential
Fedora:
sudo dnf install gcc gcc-c++ make
CMake 写法
# ========================
# Third-party dependencies
# ========================
find_package(Threads REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
Threads::Threads
)
C++ 使用
#include <thread>
std::thread worker([] {
// do work
});
worker.join();
OpenMP
OpenMP 用于多线程并行计算。
安装
Ubuntu/Debian:
sudo apt install libomp-dev
Fedora:
sudo dnf install libgomp
CMake 写法
# ========================
# Third-party dependencies
# ========================
find_package(OpenMP REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
OpenMP::OpenMP_CXX
)
C++ 使用
#include <omp.h>
#pragma omp parallel for
for (int i = 0; i < 100; ++i) {
// parallel work
}
Sophus
Sophus 是李群李代数库,在 SLAM、机器人位姿计算中常用。
安装
很多发行版仓库不一定提供合适版本,常见做法是从源码安装,或者由 ROS / 项目依赖管理。
如果系统仓库提供,可以尝试搜索:
apt search sophus
dnf search sophus
CMake 写法
如果已经安装并提供 CMake config:
# ========================
# Third-party dependencies
# ========================
find_package(Sophus REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PRIVATE
Sophus::Sophus
)
Sophus 常依赖 Eigen。如果你的代码同时直接使用 Eigen,也可以显式写:
find_package(Eigen3 REQUIRED)
find_package(Sophus REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PUBLIC
Eigen3::Eigen
PRIVATE
Sophus::Sophus
)
常用依赖速查表
| 库 | Ubuntu/Debian | Fedora | CMake 查找 | 常用链接目标 |
|---|---|---|---|---|
| Eigen3 | libeigen3-dev | eigen3-devel | find_package(Eigen3 REQUIRED) | Eigen3::Eigen |
| OpenCV | libopencv-dev | opencv-devel | find_package(OpenCV REQUIRED COMPONENTS ...) | opencv_core 等 |
| Boost | libboost-all-dev | boost-devel | find_package(Boost REQUIRED COMPONENTS ...) | Boost::system 等 |
| PCL | libpcl-dev | pcl-devel | find_package(PCL REQUIRED COMPONENTS ...) | ${PCL_LIBRARIES} 或 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 | 通常无需单独安装 | 通常无需单独安装 | find_package(Threads REQUIRED) | Threads::Threads |
| OpenMP | libomp-dev | libgomp | find_package(OpenMP REQUIRED) | OpenMP::OpenMP_CXX |
不同发行版和版本的包名可能略有差异。如果安装失败,先用:
apt search <关键字>
dnf search <关键字>
确认包名。
一个模块同时引入 Eigen 和 OpenCV
例如 lib1 同时使用 Eigen 和 OpenCV:
# ========================
# 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
)
不推荐的写法
不推荐:顶层集中查找所有库
# 顶层 CMakeLists.txt
find_package(Eigen3 REQUIRED)
find_package(OpenCV REQUIRED)
find_package(PCL REQUIRED)
问题:
- 顶层越来越乱。
- 不知道哪个模块真正用了哪个库。
- 删除模块时容易漏删依赖。
- 新人阅读工程时依赖关系不清楚。
不推荐:全局 include
include_directories(${OpenCV_INCLUDE_DIRS})
link_libraries(${OpenCV_LIBS})
问题:
- 影响所有 target。
- 依赖关系不明确。
- 可能引入意外的 include 顺序问题。
现代 CMake 推荐:
target_link_libraries(my_target
PRIVATE
opencv_core
)
如果库提供 imported target,include 路径和链接库会自动跟着 target 传播。
排查 find_package 找不到库
第一步:确认系统包是否安装
dpkg -l | grep eigen
rpm -qa | grep eigen
第二步:确认 CMake 能看到 config 文件
常见文件名:
Eigen3Config.cmake
OpenCVConfig.cmake
PCLConfig.cmake
fmtConfig.cmake
第三步:手动指定搜索路径
如果库安装在非标准目录,可以在 configure 时添加:
cmake --preset linux-debug -DCMAKE_PREFIX_PATH=/opt/some_library
或在 preset 中添加:
"CMAKE_PREFIX_PATH": "/opt/some_library"
多个路径可以用分号:
"CMAKE_PREFIX_PATH": "/opt/lib_a;/opt/lib_b"
第四步:查看 CMake 报错信息
CMake 通常会告诉你缺少哪个 config 文件,例如:
Could not find a package configuration file provided by "OpenCV"
这种情况优先检查:
- 开发包是否安装。
- 包名是否正确。
- 是否安装到了非标准路径。
