CMake中find_package指令的實(shí)現(xiàn)
1.簡(jiǎn)介
查找模塊(find module)是一系列用于搜索第三方依賴軟件包(包括庫(kù)或可執(zhí)行文件)的模塊。對(duì)查找模塊的引用一般不使用include命令,而是使用find_package命令。
基本語(yǔ)法
find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
[REQUIRED] [[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[CONFIG|NO_MODULE]
[HINTS path1 [path2 ... ]]
[PATHS path1 [path2 ... ]]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_PACKAGE_REGISTRY]
[NO_CMAKE_BUILDS_PATH]
[NO_CMAKE_SYSTEM_PATH]
[CMAKE_FIND_ROOT_PATH_BOTH|ONLY_CMAKE_FIND_ROOT_PATH|NO_CMAKE_FIND_ROOT_PATH])常用簡(jiǎn)化形式:
find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem) find_package(OpenCV REQUIRED)
2.搜索模式
find_package 支持兩種搜索模式:
1. 模塊模式(Module Mode)
- 使用 CMake 內(nèi)置的模塊文件(位于 Modules/Find<PackageName>.cmake)來(lái)完成對(duì)軟件包的搜索。它首先在CMAKE_MODULE_PATH變量定義的路徑列表中搜索查找模塊,若找不到,則從CMake安裝目錄中搜索符合該名稱的CMake預(yù)制的查找模塊。如果任未找到對(duì)應(yīng)的查找模塊,該命令會(huì)切換到配置模式再進(jìn)行處理。
- 適用于沒(méi)有提供 CMake 配置文件的舊庫(kù)(如 OpenGL、Boost 部分組件)。
- 模塊文件由用戶或 CMake 官方編寫,通過(guò)手動(dòng)邏輯查找?guī)斓念^文件目錄(find_path)、庫(kù)文件(find_library),并定義 <PackageName>_FOUND、<PackageName>_INCLUDE_DIRS、<PackageName>_LIBRARIES 等變量。
2.配置模式(Config Mode)
- 查找?guī)熳詭У?CMake 配置文件(如 <PackageName>Config.cmake 或<PackageName>-config.cmake 或 <PackageName>ConfigVersion.cmake)。
- 適用于現(xiàn)代庫(kù)(如 OpenCV、Qt、Eigen)。
- 配置文件由庫(kù)的編譯安裝流程生成,會(huì)自動(dòng)導(dǎo)出導(dǎo)入目標(biāo)(如 <PackageName>::<TargetName>),并封裝頭文件、庫(kù)文件、編譯選項(xiàng)等信息,無(wú)需手動(dòng)定義變量。
模式選擇規(guī)則:
- 默認(rèn)優(yōu)先嘗試 配置模式,失敗后嘗試 模塊模式。
- 通過(guò) CONFIG 或 NO_MODULE 參數(shù)強(qiáng)制使用配置模式。
- 通過(guò) MODULE 參數(shù)強(qiáng)制使用模塊模式。如:
find_package(PackageName MODULE) # 強(qiáng)制使用模塊模式
3.常用參數(shù)
| 參數(shù) | 作用 |
|---|---|
| REQUIRED | 表示該軟件包是構(gòu)建過(guò)程中所必須的,找不到包時(shí)終止配置并報(bào)錯(cuò)。 |
| QUIET | 用于啟用靜默模式,找不到包時(shí)不顯示警告(默認(rèn)會(huì)顯示警告)。 |
| EXACT | 要求版本嚴(yán)格匹配(如 3.14.1)。 |
| COMPONENTS | 指定需要的組件(如 Boost 的 system、filesystem)。 |
| HINTS | 手動(dòng)指定可能的搜索路徑(優(yōu)先級(jí)高于默認(rèn)路徑)。 |
| PATHS | 強(qiáng)制搜索特定路徑(優(yōu)先級(jí)最高)。 |
| NO_DEFAULT_PATH | 不搜索任何默認(rèn)路徑(僅使用 HINTS 和 PATHS)。 |
4.工作流程
1.確定搜索路徑
- 系統(tǒng)默認(rèn)路徑(如 /usr/lib/cmake、C:/Program Files/<PackageName>)。
- CMAKE_PREFIX_PATH 環(huán)境變量指定的路徑。
- HINTS 和 PATHS 參數(shù)指定的路徑。
2.查找配置文件
- 配置模式:查找 <PackageName>Config.cmake 或 <lowercase-package-name>-config.cmake。
- 模塊模式:查找 CMake 內(nèi)置的 Find<PackageName>.cmake 模塊。
這里也可以自定義搜索路徑:
find_package(MyLib REQUIRED
HINTS ${CMAKE_SOURCE_DIR}/../mylib/install # 優(yōu)先搜索此路徑
PATHS /opt/mylib /usr/local/mylib # 備選路徑
)3.驗(yàn)證版本(若指定)
- 檢查庫(kù)版本是否滿足要求(如 >=3.10 或 EXACT 3.14.1)。
4.導(dǎo)入目標(biāo)
成功后,CMake 會(huì)定義一系列變量和導(dǎo)入目標(biāo)(如 <PackageName>::<Component>)。
設(shè)置結(jié)果變量
通過(guò) find_package_handle_standard_args 命令,根據(jù)搜索結(jié)果設(shè)置以下關(guān)鍵變量:
- <PackageName>_FOUND:是否找到庫(kù)(TRUE/FALSE)。
- <PackageName>_INCLUDE_DIRS 或 <PackageName>_INCLUDES:頭文件路徑。
- <PackageName>_LIBRARIES 或 <PackageName>_LIBS:庫(kù)文件路徑。
- <PackageName>_VERSION:庫(kù)版本號(hào)。
創(chuàng)建導(dǎo)入目標(biāo)(配置模式推薦)
現(xiàn)代模塊文件(如 FindBoost.cmake)會(huì)額外創(chuàng)建導(dǎo)入目標(biāo)(如 Boost::system),允許通過(guò) target_link_libraries 直接鏈接。
find_package(OpenCV REQUIRED)
target_link_libraries(myapp PRIVATE ${OpenCV_LIBS}) # 模塊模式
# 或
target_link_libraries(myapp PRIVATE OpenCV::opencv_core) # 配置模式5.內(nèi)置模塊示例:FindBoost.cmake
以查找 Boost 庫(kù)為例,模塊模式的典型用法如下:
1. 調(diào)用 find_package
find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem)
2. 模塊文件的行為
FindBoost.cmake 會(huì):
- 搜索 Boost 的頭文件路徑(如 /usr/include/boost)。
- 搜索指定組件的庫(kù)文件(如 libboost_system.so、libboost_filesystem.so)。
- 設(shè)置變量:
Boost_FOUND # 是否找到所有必需組件 Boost_INCLUDE_DIRS # 頭文件路徑 Boost_LIBRARIES # 庫(kù)文件列表(如 boost_system;boost_filesystem) Boost_VERSION # 版本號(hào)(如 1.70.0)
3.在項(xiàng)目中使用結(jié)果
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(myapp PRIVATE ${Boost_LIBRARIES})
# 或使用導(dǎo)入目標(biāo)(若模塊支持)
# target_link_libraries(myapp PRIVATE Boost::system Boost::filesystem)
endif()6.自定義模塊文件(Find<PackageName>.cmake)
若依賴庫(kù)沒(méi)有內(nèi)置的 Find<PackageName>.cmake,可手動(dòng)編寫模塊文件。以下是一個(gè)簡(jiǎn)化的 FindMyLib.cmake 示例:
# 1. 定義緩存變量,允許用戶手動(dòng)指定路徑
set(MYLIB_ROOT "" CACHE PATH "MyLib installation root")
# 2. 查找頭文件
find_path(MYLIB_INCLUDE_DIR
NAMES mylib.h
HINTS ${MYLIB_ROOT}/include
PATHS /usr/local/include /opt/mylib/include
)
# 3. 查找?guī)煳募o態(tài)庫(kù))
find_library(MYLIB_LIBRARY
NAMES mylib mylib_static
HINTS ${MYLIB_ROOT}/lib
PATHS /usr/local/lib /opt/mylib/lib
)
# 4. 驗(yàn)證版本(示例:從頭文件中提取版本)
if(MYLIB_INCLUDE_DIR)
file(STRINGS "${MYLIB_INCLUDE_DIR}/mylib.h" MYLIB_VERSION_LINE
REGEX "#define MYLIB_VERSION \"[0-9.]+\"")
string(REGEX REPLACE "#define MYLIB_VERSION \"([0-9.]+)\"" "\\1"
MYLIB_VERSION "${MYLIB_VERSION_LINE}")
endif()
# 5. 設(shè)置標(biāo)準(zhǔn)結(jié)果變量
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib
REQUIRED_VARS MYLIB_LIBRARY MYLIB_INCLUDE_DIR
VERSION_VAR MYLIB_VERSION
)
# 6. 可選:創(chuàng)建導(dǎo)入目標(biāo)(現(xiàn)代 CMake 推薦)
if(MYLIB_FOUND)
add_library(MyLib::MyLib UNKNOWN IMPORTED)
set_target_properties(MyLib::MyLib PROPERTIES
IMPORTED_LOCATION "${MYLIB_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${MYLIB_INCLUDE_DIR}"
)
endif()使用自定義模塊:
# 添加模塊路徑到 CMAKE_MODULE_PATH
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules")
# 調(diào)用 find_package
find_package(MyLib 2.0 REQUIRED)
# 鏈接導(dǎo)入目標(biāo)(或使用變量)
target_link_libraries(myapp PRIVATE MyLib::MyLib)7.模塊模式 vs 配置模式
| 特性 | 模塊模式 | 配置模式 |
|---|---|---|
| 依賴文件 | CMake 內(nèi)置 / 用戶自定義的 Find<>.cmake | 庫(kù)自身提供的 <>.cmake 或 <>.Config.cmake |
| 維護(hù)者 | CMake 社區(qū)或用戶 | 庫(kù)開(kāi)發(fā)者 |
| 變量命名 | 不統(tǒng)一(如 Boost_LIBRARIES vs OpenCV_LIBS) | 統(tǒng)一(通過(guò)導(dǎo)入目標(biāo)) |
| 推薦場(chǎng)景 | 舊庫(kù)、無(wú) CMake 支持的庫(kù) | 現(xiàn)代庫(kù)(如 Qt、Eigen) |
| 集成度 | 較低(需手動(dòng)處理變量) | 較高(自動(dòng)生成導(dǎo)入目標(biāo)) |
8.總結(jié)
1.優(yōu)先使用配置模式:現(xiàn)代庫(kù)通常提供自己的 CMake 配置文件(如 Qt5Config.cmake),通過(guò)導(dǎo)入目標(biāo)(如 Qt5::Core)可自動(dòng)處理頭文件路徑和鏈接依賴,避免變量污染。
2.模塊模式的局限性:模塊文件由第三方維護(hù)(如 CMake 社區(qū)),可能存在版本滯后或配置不完整的問(wèn)題(如缺少某些組件)。
3.自定義模塊的注意事項(xiàng)
- 使用 find_package_handle_standard_args 統(tǒng)一結(jié)果變量。
- 為庫(kù)創(chuàng)建導(dǎo)入目標(biāo)(IMPORTED 目標(biāo)),與現(xiàn)代 CMake 風(fēng)格兼容。
- 通過(guò) CACHE 變量允許用戶手動(dòng)指定路徑(如 MYLIB_ROOT)。
模塊模式是 CMake 兼容舊庫(kù)或無(wú) CMake 支持庫(kù)的重要機(jī)制,通過(guò) Find<PackageName>.cmake 模塊文件實(shí)現(xiàn)依賴查找。盡管配置模式更現(xiàn)代,但模塊模式在兼容傳統(tǒng)項(xiàng)目時(shí)仍不可替代。在實(shí)際開(kāi)發(fā)中,建議優(yōu)先使用配置模式,僅在必要時(shí)通過(guò)自定義模塊支持舊庫(kù)。
相關(guān)鏈接
- CMake 官網(wǎng) CMake - Upgrade Your Software Build System
- CMake 官方文檔:CMake Tutorial — CMake 4.0.2 Documentation
- CMake 源碼:https://github.com/Kitware/CMake
- CMake 源碼:CMake · GitLab
- 中文版基礎(chǔ)介紹: CMake 入門實(shí)戰(zhàn) | HaHack
- wiki: Home · Wiki · CMake / Community · GitLab
到此這篇關(guān)于CMake中find_package指令的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)CMake find_package指令內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言鏈表實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)程序設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言鏈表實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)程序設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
手把手帶你學(xué)習(xí)C++的數(shù)據(jù)類型
這篇文章主要為大家介紹了C++的數(shù)據(jù)類型,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助,希望能夠給你帶來(lái)幫助2021-11-11
C語(yǔ)言實(shí)現(xiàn)全排列算法模板的方法
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)全排列算法模板的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
Qt實(shí)現(xiàn)小功能之復(fù)雜抽屜效果詳解
在Qt自帶的控件中,也存在抽屜控件:QToolBar。但是,該控件有個(gè)缺點(diǎn):一次只能展開(kāi)一個(gè)抽屜信息,無(wú)法實(shí)現(xiàn)多個(gè)展開(kāi)。所以本文將自定義實(shí)現(xiàn)復(fù)雜抽屜效果,需要的可以參考一下2022-10-10
C++實(shí)現(xiàn)的大數(shù)相乘算法示例
這篇文章主要介紹了C++實(shí)現(xiàn)的大數(shù)相乘算法,結(jié)合實(shí)例形式分析了C++大數(shù)相乘的概念、原理及代碼實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-08-08
c語(yǔ)言實(shí)現(xiàn)數(shù)組循環(huán)左移m位
這篇文章主要介紹了c語(yǔ)言實(shí)現(xiàn)數(shù)組循環(huán)左移m位,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07

