第三方庫依賴寫法
本節專門講第三方庫如何安裝、如何在 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"
這種情況優先檢查:
- 開發包是否安裝。
- 包名是否正確。
- 是否安裝到了非標準路徑。