CMake與catkin_make的find_package()命令使用說明

在 CMake 中,find_package() 是一個核心函數,用于查找并加載外部依賴庫的配置。它的主要作用是定位頭文件、庫文件,并設置相關變量,以便后續編譯和鏈接。以下是詳細解析:


1. 基本語法

find_package(<PackageName> [version] [REQUIRED] [COMPONENTS components...] [OPTIONAL_COMPONENTS components...] [NO_MODULE] [QUIET] [CONFIG])
  • <PackageName>:要查找的包名(如 BoostEigen3)。
  • version:可選,指定最低版本(如 3.3)。
  • REQUIRED:可選,如果找不到包,則報錯并終止構建。
  • COMPONENTS:指定包的子組件(如 Boost 的 systemfilesystem)。
  • NO_MODULE:跳過模塊模式,直接使用配置模式(Config Mode)。
  • QUIET:靜默模式,不輸出警告信息。

find_package() 中的 REQUIRED 是可選的。如果不指定 REQUIRED,CMake 會嘗試查找包,但即使找不到也不會報錯,而是繼續執行后續的 CMake 腳本。此時,你需要通過檢查 <PackageName>_FOUND 變量來判斷是否成功找到該包,并決定后續邏輯。


1.1 REQUIRED關鍵字

1.1.1 沒有REQUIRED關鍵字的情況
find_package(<PackageName> [version] [COMPONENTS components...])
  • 如果找到包,CMake 會設置 <PackageName>_FOUND=TRUE 和相關變量(如 _INCLUDE_DIRS_LIBRARIES)。
  • 如果未找到包,<PackageName>_FOUND=FALSE,但不會中斷構建。
1.1.2 典型場景
1.1.2.1 可選依賴庫

某些庫可能是可選的(例如,用于增強功能但不影響核心功能):

find_package(OpenCV)  # 不強制要求 OpenCVif(OpenCV_FOUND)message(STATUS "OpenCV found, enabling advanced features")add_definitions(-DUSE_OPENCV)target_link_libraries(my_app PRIVATE ${OpenCV_LIBRARIES})
else()message(WARNING "OpenCV not found, some features will be disabled")
endif()
1.1.2.2 多版本兼容

嘗試查找高版本庫,失敗時回退到低版本或默認路徑:

find_package(Python 3.8)  # 首選 Python 3.8
if(NOT Python_FOUND)find_package(Python 3.6)  # 回退到 Python 3.6
endif()
1.1.2.3 平臺特定依賴

某些庫僅在特定平臺需要(如 Linux 的 libudev):

if(UNIX AND NOT APPLE)find_package(UDEV)  # 僅在 Linux 下查找if(UDEV_FOUND)target_link_libraries(my_app PRIVATE udev)endif()
endif()

1.1.2.4 關鍵注意事項

1.1.2.4.1 必須檢查 _FOUND 變量
如果不檢查,后續使用未找到的庫會導致編譯或鏈接錯誤:

find_package(CURL)
# 錯誤:直接使用 ${CURL_LIBRARIES} 而不檢查 CURL_FOUND

1.1.2.4.2 REQUIRED 的對比

行為REQUIRED 模式REQUIRED 模式
找不到包時報錯并終止 CMake 配置繼續執行,<PackageName>_FOUND=FALSE
適用場景核心依賴(如 ROS、Eigen)可選功能或平臺特定依賴
代碼復雜度無需額外判斷需手動檢查 _FOUND 變量

1.1.2.4.3 組件(COMPONENTS)的非必需性
即使包支持組件,也可以不標記 REQUIRED

find_package(Boost COMPONENTS system)
if(Boost_FOUND AND Boost_SYSTEM_FOUND)target_link_libraries(my_app PRIVATE Boost::system)
endif()
1.1.3 實際案例
1.1.3.1 ROS 中的可選消息依賴
find_package(catkin COMPONENTSroscppsensor_msgs  # 可選依賴
)if(catkin_FOUND AND sensor_msgs_FOUND)add_definitions(-DUSE_SENSOR_MSGS)
endif()
1.1.3.2 多圖形后端支持
find_package(OpenGL)
find_package(Vulkan)if(OpenGL_FOUND)target_link_libraries(my_engine PRIVATE OpenGL::GL)
elseif(Vulkan_FOUND)target_link_libraries(my_engine PRIVATE Vulkan::Vulkan)
else()message(FATAL_ERROR "No supported graphics API found!")
endif()

1.2 COMPONENTS:指定子組件

1.2.1 作用
  • 用于聲明需要查找的包的子模塊或組件(例如 Boost 的 systemfilesystem,或 ROS 的 roscpptf)。
  • 如果某個組件未找到,且標記了 REQUIRED,CMake 會報錯。
1.2.2 示例
find_package(Boost REQUIRED COMPONENTS system filesystem)
  • 查找 Boost 庫,并明確要求 systemfilesystem 兩個組件。
  • 成功后,變量 Boost_SYSTEM_FOUNDBoost_FILESYSTEM_FOUND 會被設為 TRUE
1.2.3 關鍵點
  • 需要包本身支持組件化(如 Boost、Qt、ROS)。
  • 每個組件可能有獨立的變量(如 Boost_SYSTEM_LIBRARY)。

1.3 NO_MODULE:強制跳過模塊模式

1.3.1 作用
  • 強制 CMake 跳過傳統的 Find<Package>.cmake 模塊模式,直接使用包的現代配置模式(即查找 <Package>Config.cmake 文件)。
  • 適用于明確知道包提供了 Config.cmake 文件的情況(如 Eigen3、現代 Qt)。
1.3.2 示例
find_package(Eigen3 3.3 REQUIRED NO_MODULE)
  • 跳過 FindEigen3.cmake,直接查找 Eigen3Config.cmake
  • 避免因舊版模塊文件與新版本庫不兼容導致的問題。
1.3.3 關鍵點
  • 通常用于現代 CMake 兼容的庫(如 Eigen3、VTK)。
  • 如果包沒有提供 Config.cmake 文件,使用 NO_MODULE 會導致查找失敗。

1.3.4 COMPONENTSNO_MODULE兩者關系總結
特性COMPONENTSNO_MODULE
用途指定包的子組件強制使用配置模式(跳過模塊模式)
依賴包的支持包需支持組件化(如 Boost、Qt)包需提供 Config.cmake 文件
典型場景find_package(Boost COMPONENTS system)find_package(Eigen3 NO_MODULE)
是否互斥可與 NO_MODULE 同時使用可與 COMPONENTS 同時使用
1.3.5 同時使用的例子
find_package(Qt6 REQUIRED COMPONENTS Core Gui NO_MODULE)
  • 強制使用 Qt6Config.cmake(跳過 FindQt6.cmake),并指定需要 CoreGui 組件。
1.3.6 為什么有些包需要同時用 COMPONENTSNO_MODULE
  • 例如 Qt6 既提供了 Config.cmake 文件,又將功能拆分為多個組件(Core、Gui、Widgets 等)。此時:
    find_package(Qt6 REQUIRED COMPONENTS Core NO_MODULE)
    
    • NO_MODULE:確保使用 Qt6Config.cmake(現代方式)。
    • COMPONENTS:明確要求 Core 組件。
1.3.7 如果包不支持組件,但用了 COMPONENTS 會怎樣?
  • CMake 會報錯,例如:
    find_package(Eigen3 COMPONENTS Core)  # Eigen3 無組件,會報錯
    
    錯誤信息類似:
    Could not find a configuration file for package "Eigen3" that specifies component "Core".
1.3.8 如何知道一個包是否支持組件?
  • 查看官方文檔或包的 Config.cmake 文件。
  • 例如 Boost 的組件列表見:Boost Libraries。

1.3.9 對比示例
案例 1:僅用 COMPONENTS
find_package(Boost REQUIRED COMPONENTS system)
  • 查找 Boost 的 system 組件,使用默認的模塊模式(FindBoost.cmake)。
案例 2:僅用 NO_MODULE
find_package(Eigen3 NO_MODULE)
  • 跳過 FindEigen3.cmake,直接查找 Eigen3Config.cmake
案例 3:同時使用
find_package(Qt5 COMPONENTS Widgets NO_MODULE)
  • 強制使用 Qt5Config.cmake,并指定 Widgets 組件。

1.3.10 總結
  • COMPONENTS:用于指定包的子模塊,與包的功能拆分相關
  • NO_MODULE:用于控制查找模式,與包的配置方式相關
  • 兩者可獨立或組合使用,具體取決于包的支持情況。

2. 工作模式

find_package 有兩種查找模式:

(1) 模塊模式(Module Mode)

  • 查找 <PackageName>Config.cmakeFind<PackageName>.cmake 文件。
  • 通常用于傳統庫(如 FindBoost.cmake)。
  • 優先級低于配置模式

(2) 配置模式(Config Mode)

  • 查找 <PackageName>Config.cmake 文件(通常由庫的開發者提供)。
  • 現代庫(如 Eigen3Qt5)優先使用此模式。
  • 通過 NO_MODULE 強制啟用。

3. 關鍵變量

成功調用 find_package 后,CMake 會設置以下變量(以 Eigen3 為例):

變量名作用示例值
<PackageName>_FOUND是否找到包Eigen3_FOUND = TRUE
<PackageName>_INCLUDE_DIR頭文件目錄Eigen3_INCLUDE_DIRS = /usr/include/eigen3
<PackageName>_LIBRARIES庫文件路徑Boost_LIBRARIES = /usr/lib/libboost_system.so
<PackageName>_VERSION版本號Eigen3_VERSION = 3.4.0

4. 具體示例解析

(1) ROS 的 catkin

find_package(catkin REQUIRED COMPONENTSroscpp tf
)
  • 作用:查找 ROS 的 catkin 構建系統,并加載 roscpptf 的依賴。
  • 生成的變量
    • catkin_INCLUDE_DIRS:ROS 包的頭文件路徑。
    • catkin_LIBRARIES:ROS 包的庫文件路徑。
  • 后續用法
    include_directories(${catkin_INCLUDE_DIRS})
    target_link_libraries(my_node ${catkin_LIBRARIES})
    

(2) Boost 庫

find_package(Boost REQUIRED COMPONENTSsystem filesystem
)
  • 作用:查找 Boost 庫,并指定需要 systemfilesystem 組件。
  • 生成的變量
    • Boost_INCLUDE_DIRS:Boost 頭文件路徑(如 /usr/include)。
    • Boost_LIBRARIES:組件庫路徑(如 boost_systemboost_filesystem)。
  • 后續用法
    target_include_directories(my_app PRIVATE ${Boost_INCLUDE_DIRS})
    target_link_libraries(my_app ${Boost_LIBRARIES})
    

(3) Eigen3 線性代數庫

find_package(Eigen3 3.3 REQUIRED NO_MODULE)
  • 作用:查找 Eigen3 庫,要求版本 ≥ 3.3,并強制使用配置模式(NO_MODULE)。
  • 生成的變量
    • Eigen3_INCLUDE_DIRS:Eigen 頭文件路徑(如 /usr/include/eigen3)。
    • Eigen3_VERSION:版本號。
  • 后續用法
    target_include_directories(my_app PRIVATE ${Eigen3_INCLUDE_DIRS})
    

(4) PkgConfig 工具

find_package(PkgConfig REQUIRED)
  • 作用:啟用 pkg-config 支持(用于查找沒有 CMake 配置文件的庫)。
  • 后續用法
    pkg_search_module(GLIB REQUIRED glib-2.0)
    include_directories(${GLIB_INCLUDE_DIRS})
    target_link_libraries(my_app ${GLIB_LIBRARIES})
    

5. 常見問題

(1) 為什么有些包需要 NO_MODULE

  • 例如 Eigen3 只有 Eigen3Config.cmake,沒有 FindEigen3.cmake,因此需強制使用配置模式。

(2) REQUIRED 的作用是什么?

  • 如果找不到包,CMake 會報錯并停止構建。避免后續鏈接時出現未定義錯誤。

(3) 可以沒有REQUIRED關鍵字嗎

  • 是的,



5. 調試技巧

  • 查看查找結果
    find_package(Foo)
    message(STATUS "Foo_FOUND = ${Foo_FOUND}, Foo_INCLUDE_DIRS = ${Foo_INCLUDE_DIRS}")
    
  • 手動指定路徑(用于調試):
    set(Foo_DIR "/path/to/FooConfig.cmake")  # 提示 CMake 查找路徑
    

總結

  • **省略 REQUIRED** 時,find_package()變為“嘗試查找”,需配合_FOUND` 變量使用。
  • 適用場景:可選功能、多版本回退、平臺特定依賴。
  • 優勢:靈活控制構建流程,避免因非核心依賴缺失導致構建失敗。

(4) 如何調試 find_package 失敗?

  • 檢查路徑是否在 CMAKE_PREFIX_PATH 中:
    message(STATUS "CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}")
    
  • 手動指定路徑:
    set(Eigen3_DIR "/path/to/eigen3/share/eigen3/cmake")
    

6. 總結

場景示例命令關鍵變量
ROS 包依賴find_package(catkin REQUIRED COMPONENTS roscpp)catkin_INCLUDE_DIRS
Boost 組件find_package(Boost REQUIRED COMPONENTS system)Boost_LIBRARIES
強制配置模式find_package(Eigen3 NO_MODULE)Eigen3_INCLUDE_DIRS
使用 pkg-configfind_package(PkgConfig)PKG_CONFIG_FOUND

通過 find_package,CMake 可以靈活地集成第三方庫,而 ROS 的 catkin 進一步擴展了這一機制,使其支持 ROS 特有的依賴管理。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92121.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92121.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92121.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring--BeanFactoryPostProcessor的用法

原文網址&#xff1a;Spring--BeanFactoryPostProcessor的用法_IT利刃出鞘的博客-CSDN博客 簡介 說明 本文介紹Spring的BeanFactoryPostProcessor的用法。 BeanPostProcessor和BeanFactoryPostProcessor的區別 項BeanPostProcessorBeanFactoryPostProcessor處理的對象處理…

了解類加載器嗎?類加載器的類型有哪些?

一、什么是類加載器&#xff08;ClassLoader&#xff09; 類加載器是 Java 虛擬機中的一部分&#xff0c;負責將 .class 文件加載到 JVM 內存中&#xff0c;生成對應的 Class 對象。 Java 程序中所有的類在使用前都必須通過類加載器加載進 JVM&#xff0c;才能被執行。二、類加…

PHP面向對象高級特性:魔術方法、對象迭代器與設計模式應用

引言 在前一篇文章中,我們探討了PHP的Traits、匿名類和對象比較機制。本文將深入PHP面向對象編程的更多高級特性,包括魔術方法、對象迭代器以及常用設計模式的實際應用,這些特性能夠幫助開發者構建更加靈活和強大的面向對象系統。 魔術方法深度解析 魔術方法是PHP中一組以…

【Java基礎】一個月教你輕松掌握Java——第三篇Git

一、Java概述&#xff08;之前的文章&#xff09;二、版本控制工具Git其實這個與Java基礎關系不大&#xff0c;但是這個工具還是很重要的&#xff0c;不管是團隊之間打比賽還是就業都應該學會它&#xff0c;秉持著學的早一些&#xff0c;用的時間長一點&#xff0c;會更熟練。&…

【C# in .NET】16. 探秘類成員-索引器:通過索引訪問對象

探秘類成員-索引器:通過索引訪問對象 在 C# 中,索引器(Indexer)是一種獨特的類成員,它允許類或結構的實例像數組一樣被索引訪問,為數據訪問提供了極大的靈活性。本文將從基礎概念出發,深入.NET 框架底層,剖析索引器的實現機制,并通過實戰案例展示其強大的應用價值。 …

idea出現:java: Target level ‘1.7‘ is incompatible with source level ‘1.8‘.解決辦法

在文件->設置->java編譯器&#xff0c;把這里版本對應上。這里用的是8版本

ssms(SQL 查詢編輯器) 添加快捷鍵 Ctrl+D(功能等于Ctrl+C + Ctrl+V),一步到位

1,打開ssms 工具&#xff0c;打開對應添加快捷鍵得地方2&#xff0c;分配 快捷鍵3&#xff0c;看效果

數學建模--層次分析法

層次分析法&#xff08;AHP&#xff09;筆記 一、核心概念 &#xff08;一&#xff09;問題本質 面對多方案、多準則決策&#xff0c;將復雜問題分層拆解&#xff0c;通過定性與定量結合&#xff0c;確定各因素權重&#xff0c;選出最優方案&#xff0c;比如選“微博之星”時綜…

人工智能教研室暑期培訓flask全棧開發培訓

人工智能教研室暑期培訓flask全棧開發培訓第一天&#xff1a;Flask 基礎入門與環境搭建實踐項目&#xff1a;搭建個人博客首頁&#xff0c;包含文章列表與詳情頁上午&#xff1a;環境搭建與 Flask 基礎1. 安裝 Python 與虛擬環境配置2. Flask 框架簡介與第一個 "Hello Wor…

MySQL(141)如何處理重復數據問題?

處理重復數據問題是數據管理中的一個常見挑戰。重復數據會影響數據庫的性能、占用資源&#xff0c;并且可能導致數據分析結果的偏差。以下是處理重復數據問題的詳細步驟以及結合代碼的示例。 一、識別重復數據 首先&#xff0c;需要識別數據庫中的重復數據。可以使用 SQL 查詢來…

MySQL 核心知識點梳理(3)

目錄 SQL優化 23什么是慢SQL 如何優化呢? 如何利于覆蓋索引 如何使用聯合索引 如何進行分頁優化 Join代替子查詢 為什么要小表驅動大表? 為什么避免join太多的表? 如何進行排序優化 什么是filesort 全字段排序和rowid排序 條件下推 索引 索引為什么能提高MyS…

關于注冊登錄功能制作的步驟(文件IO存儲+LVGL彈窗提示)

按你的需求&#xff08;文件IO存儲LVGL彈窗提示&#xff09;&#xff0c;工程需創建以下文件&#xff0c;代碼按功能模塊化存放&#xff0c;清晰明了&#xff1a;一、需要創建的文件清單 文件名 作用 存放內容 main.c 程序入口 主函數、硬件初始化、LVGL初始化、啟動界面 ui.…

自媒體端后臺設計指南:從注冊認證到內容管理的全流程搭建

自媒體端后臺設計指南&#xff1a;從注冊認證到內容管理的全流程搭建自媒體端后臺是專業創作者管理內容、粉絲和數據的核心陣地&#xff0c;其設計直接影響創作效率和平臺運營質量。一個功能清晰、操作便捷的后臺系統&#xff0c;能讓創作者專注于內容生產&#xff0c;而非被復…

uniapp掃描二維碼反色處理

在開發掃描二維碼過程中&#xff0c;發現白底黑碼可以直接用uni.scanCode掃描出來&#xff0c;但是黑底白碼就掃不出來&#xff0c;于是就試試反色后的二維碼能不能掃描出來&#xff0c;沒想到真的可以&#xff0c;下面附上完整代碼&#xff1a; <u-icon name"scan&quo…

C語言定義fixed_t什么意思

在 C 語言中&#xff0c;fixed_t 通常是一個自定義的類型別名&#xff08;typedef&#xff09;&#xff0c;用于表示固定點數&#xff08;Fixed-Point Number&#xff09;&#xff0c;而非 C 語言標準庫中的原生類型。它主要用于需要高效實數運算但無法使用浮點數的場景&#x…

音頻3A處理簡介之ANS(自動噪聲抑制)

我們常用的手機、消費類攝像頭等產品的麥克風所采集的原始聲音信號中往往包含了比較多的背景噪音&#xff0c;不僅影響用戶錄音和回放的使用體驗&#xff0c;而且這些噪聲數據還會降低音頻編碼的壓縮效率&#xff0c;因此有必要對音頻底噪進行抑制處理&#xff0c;這就是ANS&am…

Python 使用期物處理并發(使用concurrent.futures模塊啟動 進程)

使用concurrent.futures模塊啟動進程 concurrent.futures 模塊的文檔 &#xff08;https://docs.python.org/3/library/concurrent.futures.html&#xff09;副標題 是“Launching parallel tasks”&#xff08;執行并行任務&#xff09;。這個模塊實現的是真正 的并行計算&…

【系統全面】Linux內核原理——基礎知識介紹

理解內核&#xff1a;內核原理 計算機系統的軟件分層 不同于單片機中使用代碼直接與硬件交互&#xff0c;對于這種方式的缺點深有&#xff1a; &#xff08;1&#xff09;復雜度高&#xff0c;調用難度高&#xff0c;需要深入理解硬件的工作原理和細節。 &#xff08;2&#xf…

Oracle自治事務——從問題到實踐的深度解析

一、引言&#xff1a;當“關鍵操作”遇上主事務的“生死綁定”?先問大家一個問題&#xff1a;假設你在開發一個用戶管理系統&#xff0c;核心功能是“用戶注冊”&#xff0c;同時需要記錄“操作日志”。某天&#xff0c;用戶提交注冊信息時&#xff0c;數據庫突然因磁盤空間不…

廣播(Broadcast)和組播(Multicast)對比

概述 廣播&#xff08;Broadcast&#xff09;和組播&#xff08;Multicast&#xff09;是計算機網絡中兩種重要的一對多通信方式&#xff0c;用于高效地將數據同時分發給多個接收者&#xff0c;它們的核心區別在于目標接收者的范圍和控制精度&#xff0c;基于業務對效率、規模和…