第 22.4 節

第三方庫依賴寫法

0瀏覽次數0訪問次數--跳出率--平均停留

本節專門講第三方庫如何安裝、如何在 CMake 中查找、如何放到模板的 Third-party dependencies 區塊裏。

本模板的原則是:

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

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

也就是:

  1. 誰使用第三方庫,誰寫 find_package
  2. 第三方依賴集中放在本模塊的 Third-party dependencies 區塊。
  3. 優先鏈接現代 CMake target,例如 Eigen3::EigenOpenCV::opencv_core
  4. 不把所有第三方庫都堆到頂層 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>包名,例如 Eigen3OpenCV
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)

表示只需要:

  1. opencv_core
  2. opencv_imgproc
  3. opencv_highgui

這樣比直接引入全部 OpenCV 更清楚。

第三方庫鏈接時也要考慮 PUBLICPRIVATEINTERFACE

關鍵字什麼時候用
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::MatrixEigen::VectorPUBLIC 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特徵點
dnnDNN 推理模塊

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++ 庫集合。這裏以 systemfilesystem 為例。

安裝

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點類型、基礎工具
ioPCD/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/DebianFedoraCMake 查找常用鏈接目標
Eigen3libeigen3-deveigen3-develfind_package(Eigen3 REQUIRED)Eigen3::Eigen
OpenCVlibopencv-devopencv-develfind_package(OpenCV REQUIRED COMPONENTS ...)opencv_core
Boostlibboost-all-devboost-develfind_package(Boost REQUIRED COMPONENTS ...)Boost::system
PCLlibpcl-devpcl-develfind_package(PCL REQUIRED COMPONENTS ...)${PCL_LIBRARIES}PCL::common
fmtlibfmt-devfmt-develfind_package(fmt REQUIRED)fmt::fmt
spdloglibspdlog-devspdlog-develfind_package(spdlog REQUIRED)spdlog::spdlog
yaml-cpplibyaml-cpp-devyaml-cpp-develfind_package(yaml-cpp REQUIRED)yaml-cpp::yaml-cpp
nlohmann_jsonnlohmann-json3-devjson-develfind_package(nlohmann_json REQUIRED)nlohmann_json::nlohmann_json
Threads通常無需單獨安裝通常無需單獨安裝find_package(Threads REQUIRED)Threads::Threads
OpenMPlibomp-devlibgompfind_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)

問題:

  1. 頂層越來越亂。
  2. 不知道哪個模塊真正用了哪個庫。
  3. 刪除模塊時容易漏刪依賴。
  4. 新人閲讀工程時依賴關係不清楚。

不推薦:全局 include

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

問題:

  1. 影響所有 target。
  2. 依賴關係不明確。
  3. 可能引入意外的 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"

這種情況優先檢查:

  1. 開發包是否安裝。
  2. 包名是否正確。
  3. 是否安裝到了非標準路徑。
音乐页