展开菜单
首页 精品内容 本月促销 装机必备 Windows macOS软件 IOS软件 Android AI PDF教程 专题
全部分类

当前位置:

首页 > 编程开发 > CMake中find_package指令的实现

CMake中find_package指令的实现

CMake的find_package指令用于搜索第三方依赖包,支持模块模式(依赖Find.cmake文件)和配置模式(依赖库自带Config.cmake)。配置模式通过导入目标自动管理头文件和链接,是推荐方式;模块模式适用于未提供CMake配置的旧库。常用参数包括REQUIRED、QUIET、COMPONENTS等,搜索路径可自定义。

1.简介

说到 CMake 中的查找模块(find module),它本质上是一系列用于搜索第三方依赖包(包括库或可执行文件)的工具。和普通模块不同,我们通常不会用 include 去加载它,而是通过 find_package 这条命令来触发搜索流程。

CMake中find_package指令的实现

基本语法看起来有点长,但日常使用往往只需要记住几个关键参数:

find_package( [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])

不过实际项目中更常见的简化写法是这样的:

find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem)
find_package(OpenCV REQUIRED)

2.搜索模式

find_package 查找包的方式有两种,理解它们的区别是正确使用的关键。

模块模式(Module Mode)

  • 借助 CMake 内置的模块文件(位于 Modules/Find.cmake)来完成搜索。它会先沿着 CMAKE_MODULE_PATH 变量指定的路径列表寻找,找不到再回到 CMake 安装目录的预制模块中查找。如果仍然没找到对应的模块,命令会自动切换到配置模式继续处理。
  • 主要适用于那些没有提供 CMake 配置文件的旧库(比如 OpenGL、Boost 的早期组件)。
  • 模块文件通常由用户或 CMake 官方编写,靠手动逻辑去定位头文件目录(find_path)和库文件(find_library),然后定义 _FOUND_INCLUDE_DIRS_LIBRARIES 等变量。

配置模式(Config Mode)

  • 直接查找库自带的 CMake 配置文件,比如 Config.cmake-config.cmake,以及版本文件 ConfigVersion.cmake
  • 这是现代库的标配(例如 OpenCV、Qt、Eigen),配置文件由库的编译安装流程自动生成,内部已经定义好了导入目标(如 ::),头文件路径、库文件路径、编译选项等全部封装好了,不需要我们手动去设置变量。

模式选择规则:默认情况下,CMake 会优先尝试配置模式,失败后再回退到模块模式。当然也可以通过参数强制指定:

  • CONFIGNO_MODULE:强制使用配置模式
  • MODULE:强制使用模块模式

例如:

find_package(PackageName MODULE)  # 强制使用模块模式

3.常用参数

参数作用
REQUIRED表示该包是编译必需的,找不到就会直接报错终止配置。
QUIET静默模式,找不到时不显示警告(默认会打印警告信息)。
EXACT要求版本号严格匹配(比如必须是 3.14.1)。
COMPONENTS指定需要哪些子组件(例如 Boost 的 system、filesystem)。
HINTS手动提示一些可能的搜索路径,优先级高于默认路径。
PATHS强制指定搜索路径,优先级最高。
NO_DEFAULT_PATH完全忽略默认路径,只使用 HINTSPATHS 提供的路径。

4.工作流程

整个查找过程可以分为几个步骤,理解之后就能更好地调试找不到包的问题了。

第一步:确定搜索路径

  • 系统默认路径,比如 /usr/lib/cmake、Windows 下的 C:/Program Files/
  • CMAKE_PREFIX_PATH 环境变量指定的路径
  • HINTSPATHS 参数中明确给出的路径

第二步:查找配置文件

  • 配置模式下:寻找 Config.cmake-config.cmake
  • 模块模式下:寻找 CMake 内置的 Find.cmake 模块

当然也可以自定义搜索路径,比如下面这个例子:

find_package(MyLib REQUIRED
    HINTS ${CMAKE_SOURCE_DIR}/../mylib/install  # 优先搜索这个位置
    PATHS /opt/mylib /usr/local/mylib           # 备选路径
)

第三步:验证版本(如果指定了版本要求)

  • 检查库的实际版本是否满足要求(比如 >=3.10EXACT 3.14.1)。

第四步:导入目标与设置结果变量

搜索成功后,CMake 会定义一系列变量和导入目标。其中,find_package_handle_standard_args 这个命令负责设置关键的状态变量:

  • _FOUND:布尔值,表示是否找到。
  • _INCLUDE_DIRS_INCLUDES:头文件路径。
  • _LIBRARIES_LIBS:库文件路径。
  • _VERSION:版本号。

对于配置模式,更推荐直接使用导入目标。比如:

find_package(OpenCV REQUIRED)
target_link_libraries(myapp PRIVATE ${OpenCV_LIBS})  # 模块模式
# 或者用导入目标(配置模式更常见)
target_link_libraries(myapp PRIVATE OpenCV::opencv_core)

5.内置模块示例:FindBoost.cmake

拿 Boost 库来说,模块模式的典型用法很能说明问题。

1. 调用 find_package

find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem)

2. 模块文件背后的动作

FindBoost.cmake 会帮助我们做以下几件事:

  • 搜索 Boost 的头文件路径(比如 /usr/include/boost)。
  • 找到指定组件的库文件(例如 libboost_system.solibboost_filesystem.so)。
  • 设置以下变量供我们使用:
Boost_FOUND         # 是否找到了所有必需的组件
Boost_INCLUDE_DIRS  # 头文件路径
Boost_LIBRARIES     # 库文件列表(如 boost_system;boost_filesystem)
Boost_VERSION       # 版本号(如 1.70.0)

3. 在项目中如何使用

if(Boost_FOUND)
    include_directories(${Boost_INCLUDE_DIRS})
    target_link_libraries(myapp PRIVATE ${Boost_LIBRARIES})
    # 如果模块支持导入目标,也可以这样写(更现代)
    # target_link_libraries(myapp PRIVATE Boost::system Boost::filesystem)
endif()

6.自定义模块文件(Find.cmake)

如果依赖的库没有现成的 Find.cmake,我们可以自己动手写一个。下面是一个简化的 FindMyLib.cmake 示例:

# 1. 定义缓存变量,允许用户在 CMake 界面中手动指定路径
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. 查找库文件(这里以静态库为例)
find_library(MYLIB_LIBRARY
    NAMES mylib mylib_static
    HINTS ${MYLIB_ROOT}/lib
    PATHS /usr/local/lib /opt/mylib/lib
)

# 4. 从文件中提取版本号(示例,从头文件中正则匹配)
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. 调用标准结果变量处理函数
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib
    REQUIRED_VARS MYLIB_LIBRARY MYLIB_INCLUDE_DIR
    VERSION_VAR MYLIB_VERSION
)

# 6. 可选:创建导入目标(现代 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")

# 然后正常调用 find_package
find_package(MyLib 2.0 REQUIRED)

# 链接时用导入目标(或直接用变量)
target_link_libraries(myapp PRIVATE MyLib::MyLib)

7.模块模式 vs 配置模式

特性模块模式配置模式
依赖文件CMake 内置或用户自定义的 Find<>.cmake库自身提供的 <>.cmake<>.Config.cmake
维护者CMake 社区或用户自己库的开发者
变量命名不统一(比如 Boost 用 Boost_LIBRARIES,OpenCV 用 OpenCV_LIBS统一,通过导入目标来管理
推荐场景旧库、没有 CMake 支持的库现代库(如 Qt、Eigen)
集成度相对较低,需要手动处理变量高,导入目标自动封装一切

8.总结

关于 find_package,有几个核心建议值得记住:

  1. 优先考虑配置模式。现代库都会提供自己的 CMake 配置文件(比如 Qt5Config.cmake),通过导入目标(如 Qt5::Core)就能自动搞定头文件和链接依赖,避免变量满天飞。
  2. 模块模式有其历史使命。它由第三方(CMake 社区或用户)维护,难免存在版本滞后或组件缺失的问题。但对于那些没有 CMake 支持的旧库,它仍然是救命稻草。
  3. 自定义模块时要规范化:用 find_package_handle_standard_args 统一结果变量;尽量创建 IMPORTED 导入目标以兼容现代 CMake 风格;通过 CACHE 变量允许用户手工指定路径(例如 MYLIB_ROOT)。

模块模式是 CMake 兼容旧库的重要机制,即使在配置模式大行其道的今天,它仍然不可或缺。实际开发中,建议优先使用配置模式,只在处理那些“老旧”依赖时才编写自定义模块。

相关链接

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
精品专题 更多
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

PDF教程

PDF教程适合刚接触PDF文件的用户,本文整理PDF打开、编辑、转换、合并、压缩等常见基础操作。通过这些教程可以快速了解PDF文件怎么处理,解决办公、学习和资料科整理中的常见问题。使用极轻PDF可在线完成多种PDF操作,适合新手快速上手。

Mac软件 更多
灵活计算器
灵活计算器

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

图几
图几

图几是一款适用于 macOS 的截图、标注与美化工具,支持离线操作保障隐私。界面整理和高频系统操作被放到一起考虑,桌面或窗口内容一多时,管理起来会更省心。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Menuist
Menuist

Menuist 是一款面向 macOS 的 Finder 右键菜单增强工具,主要用来补充新建文件、快捷导航等常用操作,让日常文件管理和访问路径时更高效、更顺手。

Mole
Mole

Mole 是一款专为 Mac 设计的深度清理优化工具,涵盖缓存清理、应用管理及实时状态监控等功能。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

WINDOWS 更多
Windows 10
Windows 10

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

傲梅轻松备份
傲梅轻松备份

傲梅轻松备份是一款专业易用的数据备份软件,为重要数据提供安全保障。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

Wise Folder Hider Pro
Wise Folder Hider Pro

Wise Folder Hider Pro 是一款专业级文件和文件夹隐藏加密软件,为私密数据添加多重保护。高频操作更强调就近处理,浏览、整理和跨目录移动文件时,来回切换和重复点击都会少很多。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

PinStack
PinStack

PinStack是一款轻量级的Windows平台剪贴板管理工具,优化您的剪贴板使用体验。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Seer
Seer

Seer是一款在Win平台下的空格键功能增强效率工具,只需轻敲空格键,就能预览几乎任何格式的文件。它更适合把零散的小功能集中起来使用,处理高频琐碎任务时会更省事。