find_package

注意

使用依赖项指南对这个通用主题进行了高级介绍。它提供了find_package()命令在更广泛的背景下的概述,包括它与FetchContent模块的关系。建议在深入了解以下细节之前阅读本指南。

查找一个包(通常由项目外部提供),并加载其包特有的详细信息。此命令的调用也可以被依赖项提供者拦截。

典型用法

大多数find_package()调用通常采用以下形式

find_package(<PackageName> [<version>] [REQUIRED] [COMPONENTS <components>...])

<PackageName>是唯一的强制参数。<version>通常被省略,如果项目在没有包的情况下无法成功配置,则应给出REQUIRED。一些更复杂的包支持可以通过COMPONENTS关键字选择的组件,但大多数包没有那么复杂。

上述是基本签名的简化形式。在可能的情况下,项目应使用此形式查找包。这降低了复杂性,并最大限度地增加了包可以被查找或提供的方式。

理解基本签名足以满足find_package()的通用用法。计划提供包配置文件Project维护者应理解整体情况,如本页完整签名和所有后续章节所解释的。

搜索模式

该命令有几种搜索包的模式

模块模式

在此模式下,CMake 搜索名为 Find<PackageName>.cmake 的文件,首先在 CMAKE_MODULE_PATH 中列出的位置,然后是 CMake 安装提供的 查找模块。如果找到该文件,它将由 CMake 读取和处理。它负责查找包、检查版本并生成任何所需的消息。某些查找模块对版本控制的支持有限或没有支持;请查阅查找模块的文档。

Find<PackageName>.cmake 文件通常不是由包本身提供的。相反,它通常由包外部的实体提供,例如操作系统、CMake 本身,甚至调用 find_package() 命令的项目。由于是外部提供的,查找模块往往具有启发性,并且容易过时。它们通常搜索特定的库、文件和其他包工件。

模块模式仅支持基本命令签名

配置模式

在此模式下,CMake 搜索名为 <lowercasePackageName>-config.cmake<PackageName>Config.cmake 的文件。如果指定了版本详细信息,它还会查找 <lowercasePackageName>-config-version.cmake<PackageName>ConfigVersion.cmake(有关这些独立版本文件的使用方式的说明,请参见 配置模式版本选择)。

注意

如果启用了实验性的 CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES,也会考虑名为 <PackageName>.cps<lowercasePackageName>.cps 的文件。这些文件根据 通用包规范 (CPS) 提供包信息,该规范比 CMake 脚本更具可移植性。除了明确指出的例外,任何提及“配置文件”、“配置模式”、“包配置文件”等的说法都同样适用于 CPS 和 CMake 脚本文件。此功能正在开发中,可能缺少一些功能。

搜索的实现方式倾向于在大多数情况下优先使用通用包规范文件而不是 CMake 脚本配置文件。CONFIGS 的指定会抑制对 CPS 文件的考虑。

在配置模式下,命令可以给定要搜索的包名称列表。CMake 搜索配置和版本文件的位置比模块模式复杂得多(参见配置模式搜索过程)。

配置和版本文件通常作为包的一部分安装,因此它们比查找模块更可靠。它们通常包含对包内容的直接了解,因此在配置或版本文件本身中无需搜索或启发式方法。

配置模式同时支持基本完整命令签名。

FetchContent 重定向模式

在 3.24 版本新增:find_package() 的调用可以在内部重定向到由 FetchContent 模块提供的包。对于调用者来说,行为将类似于配置模式,只是搜索逻辑被绕过并且组件信息未被使用。有关更多详细信息,请参阅 FetchContent_Declare()FetchContent_MakeAvailable()

当未重定向到由FetchContent提供的包时,命令参数决定是使用模块模式还是配置模式。当使用基本签名时,命令首先在模块模式下搜索。如果未找到包,则搜索回退到配置模式。用户可以设置CMAKE_FIND_PACKAGE_PREFER_CONFIG变量为true,以反转优先级并指示CMake首先使用配置模式搜索,然后再回退到模块模式。基本签名也可以通过MODULE关键字强制只使用模块模式。如果使用完整签名,命令只在配置模式下搜索。

基本签名

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED|OPTIONAL] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
             [GLOBAL]
             [NO_POLICY_SCOPE]
             [BYPASS_PROVIDER])

基本签名受模块模式和配置模式支持。MODULE 关键字表示只能使用模块模式查找包,不回退到配置模式。

无论使用哪种模式,都会设置一个 <PackageName>_FOUND 变量来指示是否找到了包。当找到包时,可以通过包本身记录的其他变量和 导入目标 提供包特定信息。QUIET 选项禁用信息消息,包括指示未找到包(如果它不是 REQUIRED)的消息。REQUIRED 选项在未找到包时会停止处理并显示错误消息。

包特定的所需组件列表可以列在 COMPONENTS 关键字之后。如果其中任何组件无法满足,则包整体被视为未找到。如果同时存在 REQUIRED 选项,则将其视为致命错误,否则执行仍将继续。作为一种简写形式,如果存在 REQUIRED 选项,则可以省略 COMPONENTS 关键字,并且所需组件可以直接列在 REQUIRED 之后。

可以启用CMAKE_FIND_REQUIRED变量,使此调用默认为REQUIRED。此行为可以通过提供OPTIONAL关键字来覆盖。与REQUIRED选项一样,可以在OPTIONAL之后直接列出组件列表,这等同于在COMPONENTS关键字之后列出它们。当给出OPTIONAL关键字时,未找到包时的警告输出会被抑制。

其他可选组件可以列在 OPTIONAL_COMPONENTS 之后。如果这些组件无法满足,只要所有必需组件都已满足,包仍可被视为已找到。

可用组件的集合及其含义由目标包定义

  • 对于 CMake 脚本包配置文件,如何解释所给组件信息形式上取决于目标包,但它应该遵循上述期望。对于未指定组件的调用,没有单一的预期行为,目标包应明确定义在这种情况下发生的情况。常见的安排包括假定它应该找到所有组件、不找到任何组件或一些明确定义的可用组件子集。

  • 通用包规范包由一个根配置文件和零个或多个附件组成,每个附件都提供组件并可能具有依赖项。CMake 总是尝试加载根配置文件。只有当附件的依赖项能够满足,并且它们提供请求的组件,或者未请求任何组件时,才会加载附件。如果提供必需组件的附件的依赖项无法满足,则认为该包未找到。否则,该附件将被忽略。

在 3.24 版本新增: REGISTRY_VIEW 关键字指定应查询的注册表视图。此关键字仅在 Windows 平台上有效,在所有其他平台上将被忽略。形式上,如何解释所给注册表视图信息取决于目标包。

在 3.24 版本新增: 指定 GLOBAL 关键字会将所有导入的目标提升到导入项目中的全局范围。或者,可以通过设置 CMAKE_FIND_PACKAGE_TARGETS_GLOBAL 变量来启用此功能。

[version] 参数请求一个与找到的包兼容的版本。它有两种可能的指定形式

  • 单个版本,格式为 major[.minor[.patch[.tweak]]],其中每个组件都是一个数值。

  • 版本范围,格式为 versionMin...[<]versionMax,其中 versionMinversionMax 具有相同的格式和组件为整数的限制。默认情况下,两个端点都包含在内。通过指定 <,将排除上限。版本范围仅支持 CMake 3.19 或更高版本。

注意

除 CPS 包外,目前仅按包提供版本支持。当指定版本范围但包仅设计为期望单个版本时,包将忽略范围的上限,并仅考虑范围下限的单个版本。支持版本范围的非 CPS 包以由单个包确定的方式进行。有关详细信息和重要注意事项,请参阅下面的版本选择部分。

EXACT 选项请求版本完全匹配。此选项与指定版本范围不兼容。

如果递归调用在查找模块内部时未给出 [version] 和/或组件列表,则相应的参数会自动从外部调用转发(包括 [version]EXACT 标志)。

有关 NO_POLICY_SCOPE 选项的讨论,请参阅 cmake_policy() 命令文档。

在 3.24 版本新增: BYPASS_PROVIDER 关键字仅在 find_package()依赖项提供程序调用时才允许。提供程序可以使用它直接调用内置的 find_package() 实现,并防止该调用被重新路由回自身。CMake 的未来版本可能会检测到尝试从依赖项提供程序之外的地方使用此关键字并以致命错误停止。

完整签名

find_package(<PackageName> [version] [EXACT] [QUIET]
             [REQUIRED|OPTIONAL] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [CONFIG|NO_MODULE]
             [GLOBAL]
             [NO_POLICY_SCOPE]
             [BYPASS_PROVIDER]
             [NAMES name1 [name2 ...]]
             [CONFIGS config1 [config2 ...]]
             [HINTS path1 [path2 ...]]
             [PATHS path1 [path2 ...]]
             [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [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] # Deprecated; does nothing.
             [NO_CMAKE_SYSTEM_PATH]
             [NO_CMAKE_INSTALL_PREFIX]
             [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH])

CONFIG 选项、同义的 NO_MODULE 选项,或使用 基本签名 中未指定的选项,都会强制执行纯配置模式。在纯配置模式下,命令跳过模块模式搜索,并立即进行配置模式搜索。

配置模式搜索尝试定位要查找的包提供的配置文件。会创建一个名为 <PackageName>_DIR 的缓存条目,用于保存包含该文件的目录。默认情况下,命令搜索名称为 <PackageName> 的包。如果给定了 NAMES 选项,则使用其后的名称代替 <PackageName>。在确定是否将调用重定向到由 FetchContent 提供的包时,也会考虑这些名称。

对于每个指定的名称,命令都会搜索名为 <PackageName>Config.cmake<lowercasePackageName>-config.cmake 的文件。可以使用 CONFIGS 选项给定一组替换的可能配置文件名。下文指定了 配置模式搜索过程。找到后,会检查任何 版本约束,如果满足,配置文件将由 CMake 读取和处理。由于该文件由包提供,因此它已经知道包内容的位置。配置文件的完整路径存储在 CMake 变量 <PackageName>_CONFIG 中。

注意

如果启用了实验性的 CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES,并且没有给出 CONFIGS,则也会考虑名为 <PackageName>.cps<lowercasePackageName>.cps 的文件。

所有在搜索具有适当版本的包时被 CMake 考虑过的配置文件都存储在 <PackageName>_CONSIDERED_CONFIGS 变量中,相关版本存储在 <PackageName>_CONSIDERED_VERSIONS 变量中。

如果找不到包配置文件,CMake 将生成一个描述问题的错误,除非指定了 QUIET 参数。如果指定了 REQUIRED 并且未找到包,则会生成致命错误并停止执行配置步骤。如果 <PackageName>_DIR 已设置为不包含配置文件的目录,CMake 将忽略它并从头开始搜索。

鼓励提供包配置文件的包维护者对其进行命名和安装,以使下文概述的配置模式搜索过程能够在无需使用附加选项的情况下找到它们。

配置模式搜索过程

注意

当使用配置模式时,无论给定的是完整签名还是基本签名,都将应用此搜索过程。

在 3.24 版本新增: 所有 find_package() 调用(即使在模块模式下)都会首先在 CMAKE_FIND_PACKAGE_REDIRECTS_DIR 目录中查找配置包文件。FetchContent 模块,甚至项目本身,都可能在该位置写入文件,以将 find_package() 调用重定向到项目已提供的内容。如果该位置未找到配置包文件,则搜索将继续执行下述逻辑。

CMake 构造了一组可能的包安装前缀。在每个前缀下,会在多个目录中搜索配置文件。下表显示了搜索的目录。每个条目都适用于遵循 Windows (W)、UNIX (U) 或 Apple (A) 约定的安装树

条目

约定

<prefix>/<name>/cps/ [2]

W

<prefix>/<name>/*/cps/ [2]

W

<prefix>/cps/<name>/ [2]

W

<prefix>/cps/<name>/*/ [2]

W

<prefix>/cps/ [2]

W

<prefix>/

W

<prefix>/(cmake|CMake)/

W

<prefix>/<name>*/

W

<prefix>/<name>*/(cmake|CMake)/

W

<prefix>/<name>*/(cmake|CMake)/<name>*/ [1]

W

<prefix>/(lib/<arch>|lib*|share)/cps/<name>/ [2]

U

<prefix>/(lib/<arch>|lib*|share)/cps/<name>/*/ [2]

U

<prefix>/(lib/<arch>|lib*|share)/cps/ [2]

U

<prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/

U

<prefix>/(lib/<arch>|lib*|share)/<name>*/

U

<prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/

U

<prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/

W/U

<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/

W/U

<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/

W/U

在支持 macOS FRAMEWORKBUNDLE 的系统上,将在以下目录中搜索包含配置文件的 Frameworks 或 Application Bundles

条目

约定

<prefix>/<name>.framework/Versions/*/Resources/CPS/ [3]

A

<prefix>/<name>.framework/Resources/CPS/ [3]

A

<prefix>/<name>.framework/Resources/

A

<prefix>/<name>.framework/Resources/CMake/

A

<prefix>/<name>.framework/Versions/*/Resources/

A

<prefix>/<name>.framework/Versions/*/Resources/CMake/

A

<prefix>/<name>.app/Contents/Resources/CPS/ [3]

A

<prefix>/<name>.app/Contents/Resources/

A

<prefix>/<name>.app/Contents/Resources/CMake/

A

在搜索上述路径时,find_package 将只在包含 /cps/ 的搜索路径中查找 .cps 文件,否则将只查找 .cmake 文件。(这仅适用于指定路径,不考虑 <prefix><name> 的内容。)

在所有情况下,<name> 都被视为不区分大小写,并对应于指定的任何名称(<PackageName> 或由 NAMES 给定的名称)。

如果至少启用了一种编译语言,则可能会根据编译器的目标架构按以下顺序搜索特定于架构的 lib/<arch>lib* 目录

lib/<arch>

如果设置了 CMAKE_LIBRARY_ARCHITECTURE 变量,则搜索。

lib64

在 64 位平台(CMAKE_SIZEOF_VOID_P 为 8)上搜索,并且 FIND_LIBRARY_USE_LIB64_PATHS 属性设置为 TRUE

lib32

在 32 位平台(CMAKE_SIZEOF_VOID_P 为 4)上搜索,并且 FIND_LIBRARY_USE_LIB32_PATHS 属性设置为 TRUE

libx32

在使用 x32 ABI 的平台上搜索,如果 FIND_LIBRARY_USE_LIBX32_PATHS 属性设置为 TRUE

lib

始终搜索。

在 3.24 版本更改:Windows 平台上,可以将注册表查询作为通过 HINTSPATHS 关键字指定的目录的一部分,使用 专用语法。此类规范将在所有其他平台上被忽略。

在 3.24 版本新增: 可以指定 REGISTRY_VIEW 来管理作为 PATHSHINTS 一部分指定的 Windows 注册表查询。

指定必须查询哪些注册表视图。此选项仅在 Windows 平台上有效,在其他平台上将被忽略。未指定时,当 CMP0134 策略为 NEW 时,使用 TARGET 视图。有关策略为 OLD 时的默认视图,请参阅 CMP0134

64

查询64位注册表。在32位Windows上,它始终返回字符串 /REGISTRY-NOTFOUND

32

查询32位注册表。

64_32

查询两个视图(6432)并为每个视图生成一个路径。

32_64

查询两个视图(3264)并为每个视图生成一个路径。

HOST

查询与主机架构匹配的注册表:64 位 Windows 上为 64,32 位 Windows 上为 32

TARGET

查询与CMAKE_SIZEOF_VOID_P变量指定的体系结构匹配的注册表。如果未定义,则回退到HOST视图。

BOTH

查询两个视图(3264)。顺序取决于以下规则:如果定义了 CMAKE_SIZEOF_VOID_P 变量,则根据此变量的内容使用以下视图

  • 8: 64_32

  • 4: 32_64

如果未定义 CMAKE_SIZEOF_VOID_P 变量,则依赖于主机的架构

  • 64位: 64_32

  • 32位: 32

如果指定了 PATH_SUFFIXES,则后缀会逐一附加到每个 (W) 或 (U) 目录条目。

这组目录旨在与在其安装树中提供配置文件的项目协同工作。上面标记为 (W) 的目录适用于 Windows 上的安装,其中前缀可能指向应用程序安装目录的顶部。标记为 (U) 的目录适用于 UNIX 平台上的安装,其中前缀由多个包共享。这仅仅是一种约定,因此所有 (W) 和 (U) 目录仍在所有平台上搜索。标记为 (A) 的目录适用于 Apple 平台上的安装。CMAKE_FIND_FRAMEWORKCMAKE_FIND_APPBUNDLE 变量决定了优先顺序。

警告

CMAKE_FIND_FRAMEWORKCMAKE_FIND_APPBUNDLE 设置为 FIRST(默认值)以外的值将导致 CMake 以与规范中设定的顺序不同的顺序搜索通用包规范文件。

安装前缀的集合是按照以下步骤构建的。如果指定了 NO_DEFAULT_PATH,则所有 NO_* 选项都将启用。

  1. 搜索当前正在查找的 <PackageName> 独有的前缀。请参阅策略 CMP0074

    3.12 版本新增。

    具体而言,按以下顺序搜索由以下变量指定的前缀

    1. <PackageName>_ROOT CMake 变量,其中 <PackageName> 是大小写保留的包名。

    2. <PACKAGENAME>_ROOT CMake 变量,其中 <PACKAGENAME> 是大写包名。请参阅策略 CMP0144

      在 3.27 版本中新增。

    3. <PackageName>_ROOT 环境变量,其中 <PackageName> 是大小写保留的包名。

    4. <PACKAGENAME>_ROOT 环境变量,其中 <PACKAGENAME> 是大写包名。请参阅策略 CMP0144

      在 3.27 版本中新增。

    包根变量以栈的形式维护,因此如果从查找模块内部调用,则在当前包的路径之后也会搜索父查找模块的根路径。如果传递 NO_PACKAGE_ROOT_PATH 或将 CMAKE_FIND_USE_PACKAGE_ROOT_PATH 设置为 FALSE,则可以跳过此操作。

  2. 在 CMake 特定缓存变量中指定的搜索路径。这些路径旨在与 -DVAR=VALUE 一起在命令行上使用。这些值被解释为 分号分隔的列表。如果传递 NO_CMAKE_PATH 或将 CMAKE_FIND_USE_CMAKE_PATH 设置为 FALSE,则可以跳过此操作

  3. 在 CMake 特定环境变量中指定的搜索路径。这些路径旨在在用户的 shell 配置中设置,因此使用主机的本机路径分隔符(Windows 上为 ;,UNIX 上为 :)。如果传递 NO_CMAKE_ENVIRONMENT_PATH 或将 CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH 设置为 FALSE,则可以跳过此操作

  4. HINTS 选项指定的搜索路径。这些路径应该是通过系统自省计算出来的路径,例如由另一个已找到项的位置提供的提示。硬编码的猜测应使用 PATHS 选项指定。

  5. 搜索标准系统环境变量。如果传递了 NO_SYSTEM_ENVIRONMENT_PATH,或者将 CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH 设置为 FALSE,则可以跳过此步骤。以 /bin/sbin 结尾的路径条目会自动转换为其父目录

    • PATH

  6. 存储在 CMake 用户包注册表中的搜索路径。如果传递 NO_CMAKE_PACKAGE_REGISTRY,或者将变量 CMAKE_FIND_USE_PACKAGE_REGISTRY 设置为 FALSE,或者将已弃用的变量 CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY 设置为 TRUE,则可以跳过此步骤。

    有关用户包注册表的详细信息,请参阅 cmake-packages(7) 手册。

  7. 搜索为当前系统平台文件定义的 CMake 变量。对 CMAKE_INSTALL_PREFIXCMAKE_STAGING_PREFIX 的搜索可以跳过,如果传递了 NO_CMAKE_INSTALL_PREFIX 或将 CMAKE_FIND_USE_INSTALL_PREFIX 设置为 FALSE。所有这些位置都可以跳过,如果传递了 NO_CMAKE_SYSTEM_PATH 或将 CMAKE_FIND_USE_CMAKE_SYSTEM_PATH 设置为 FALSE

    这些变量包含的平台路径通常包括已安装的软件位置。例如,UNIX 平台上的 /usr/local

  8. 存储在 CMake 系统包注册表中的搜索路径。如果传递 NO_CMAKE_SYSTEM_PACKAGE_REGISTRY,或者将 CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY 变量设置为 FALSE,或者将已弃用的变量 CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY 设置为 TRUE,则可以跳过此步骤。

    有关系统包注册表的详细信息,请参阅 cmake-packages(7) 手册。

  9. PATHS 选项指定的搜索路径。这些通常是硬编码的猜测。

CMAKE_IGNORE_PATHCMAKE_IGNORE_PREFIX_PATHCMAKE_SYSTEM_IGNORE_PATHCMAKE_SYSTEM_IGNORE_PREFIX_PATH 变量也可以导致忽略上述某些位置。

路径按上述顺序搜索。找到的第一个可用的包配置文件将被使用,即使列表中稍后位置存在更新版本的包。

对于包含 glob 表达式 (*) 的搜索路径,匹配 glob 的目录的搜索顺序未指定,除非设置了 CMAKE_FIND_PACKAGE_SORT_ORDER 变量。此变量以及 CMAKE_FIND_PACKAGE_SORT_DIRECTION 变量,确定了 CMake 考虑 glob 匹配的顺序。例如,如果文件系统包含包配置文件

<prefix>/example-1.2/example-config.cmake
<prefix>/example-1.10/example-config.cmake
<prefix>/share/example-2.0/example-config.cmake

(当上述变量未设置时)find_package(example) 是找到 example-1.2 还是 example-1.10(假设两者都可用)是未指定的,但 find_package 将 *不* 找到 example-2.0,因为其他两个中的一个会先被找到。

要控制 find_package 搜索与 glob 表达式匹配的目录的顺序,请使用 CMAKE_FIND_PACKAGE_SORT_ORDERCMAKE_FIND_PACKAGE_SORT_DIRECTION。例如,要使上述示例选择 example-1.10,可以设置

set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)

在调用 find_package 之前。

在 3.16 版本新增: 添加了 CMAKE_FIND_USE_<CATEGORY> 变量以全局禁用各种搜索位置。

在 4.0 版本更改: 变量 CMAKE_FIND_PACKAGE_SORT_ORDERCMAKE_FIND_PACKAGE_SORT_DIRECTION 现在也控制 find_package 在搜索路径 <prefix>/<name>.framework/Versions/*/Resources/<prefix>/<name>.framework/Versions/*/Resources/CMake 中匹配 glob 表达式的目录的顺序。在 CMake 的早期版本中,此顺序未指定。

CMake 变量 CMAKE_FIND_ROOT_PATH 指定一个或多个目录,这些目录将附加到所有其他搜索目录之前。这实际上“重新根植”了给定位置下的整个搜索。属于 CMAKE_STAGING_PREFIX 后代的路径被排除在此重新根植之外,因为该变量始终是主机系统上的路径。默认情况下,CMAKE_FIND_ROOT_PATH 为空。

CMAKE_SYSROOT 变量也可以用来指定一个目录作为前缀。设置 CMAKE_SYSROOT 也有其他影响。更多信息请参阅该变量的文档。

这些变量在交叉编译时特别有用,可以指向目标环境的根目录,CMake 也会在那里搜索。默认情况下,首先搜索 CMAKE_FIND_ROOT_PATH 中列出的目录,然后搜索 CMAKE_SYSROOT 目录,然后搜索非根目录。可以通过设置 CMAKE_FIND_ROOT_PATH_MODE_PACKAGE 来调整默认行为。此行为可以使用选项在每次调用时手动覆盖

CMAKE_FIND_ROOT_PATH_BOTH

按上述顺序搜索。

NO_CMAKE_FIND_ROOT_PATH

不使用 CMAKE_FIND_ROOT_PATH 变量。

ONLY_CMAKE_FIND_ROOT_PATH

仅搜索重新根植的目录和 CMAKE_STAGING_PREFIX 下的目录。

默认搜索顺序旨在针对常见用例从最具体到最不具体。项目可以通过多次调用命令并使用 NO_* 选项来覆盖顺序

find_package (<PackageName> PATHS paths... NO_DEFAULT_PATH)
find_package (<PackageName>)

一旦其中一个调用成功,结果变量将被设置并存储在缓存中,这样就不会再次搜索。

默认情况下,存储在结果变量中的值将是找到文件的路径。在调用 find_package 之前,可以将 CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS 变量设置为 TRUE,以解析符号链接并存储文件的真实路径。

每个非 REQUIREDfind_package 调用都可以被禁用或设置为 REQUIRED

同时将两个变量设置为 TRUE 是一个错误。

CMAKE_REQUIRE_FIND_PACKAGE_<PackageName> 变量优先于 OPTIONAL 关键字,以确定包是否必需。

配置模式版本选择

注意

当使用配置模式时,无论给定的是完整签名还是基本签名,都将应用此版本选择过程。

当给出 [version] 参数时,配置模式将仅查找声称与请求版本兼容的包版本(参见 格式规范)。如果给出 EXACT 选项,则仅能找到声称与请求版本完全匹配的包版本。CMake 不为版本号的含义建立任何约定。

CMake 脚本

对于 CMake 脚本包配置文件,包版本号由包本身或由 FetchContent 提供的“版本”文件进行检查。对于候选包配置文件 <config-file>.cmake,相应的版本文件位于其旁边,名称为 <config-file>-version.cmake<config-file>Version.cmake。如果没有可用的此类版本文件,则假定该配置文件与任何请求的版本都不兼容。可以使用 CMakePackageConfigHelpers 模块创建包含通用版本匹配代码的基本版本文件。当找到版本文件时,它会被加载以检查请求的版本号。版本文件在嵌套作用域中加载,其中已定义以下变量

PACKAGE_FIND_NAME

<PackageName>

PACKAGE_FIND_VERSION

完整请求版本字符串

PACKAGE_FIND_VERSION_MAJOR

如果已请求,则为主版本,否则为 0

PACKAGE_FIND_VERSION_MINOR

如果已请求,则为次版本,否则为 0

PACKAGE_FIND_VERSION_PATCH

如果已请求,则为补丁版本,否则为 0

PACKAGE_FIND_VERSION_TWEAK

如果已请求,则为修订版本,否则为 0

PACKAGE_FIND_VERSION_COUNT

版本组件数量,0 到 4

当指定版本范围时,上述版本变量将根据版本范围的下限保留值。这是为了保留与尚未实现预期版本范围的包的兼容性。此外,版本范围将由以下变量描述

PACKAGE_FIND_VERSION_RANGE

完整请求版本范围字符串

PACKAGE_FIND_VERSION_RANGE_MIN

这指定了版本范围的下限是应该包含还是排除。目前,此变量唯一支持的值是 INCLUDE

PACKAGE_FIND_VERSION_RANGE_MAX

这指定了版本范围的上限是应该包含还是排除。此变量支持的值是 INCLUDEEXCLUDE

PACKAGE_FIND_VERSION_MIN

范围下限的完整请求版本字符串

PACKAGE_FIND_VERSION_MIN_MAJOR

如果已请求,则为下限的主版本,否则为 0

PACKAGE_FIND_VERSION_MIN_MINOR

如果已请求,则为下限的次版本,否则为 0

PACKAGE_FIND_VERSION_MIN_PATCH

如果已请求,则为下限的补丁版本,否则为 0

PACKAGE_FIND_VERSION_MIN_TWEAK

如果已请求,则为下限的修订版本,否则为 0

PACKAGE_FIND_VERSION_MIN_COUNT

下限的版本组件数量,0 到 4

PACKAGE_FIND_VERSION_MAX

范围上限的完整请求版本字符串

PACKAGE_FIND_VERSION_MAX_MAJOR

如果已请求,则为上限的主版本,否则为 0

PACKAGE_FIND_VERSION_MAX_MINOR

如果已请求,则为上限的次版本,否则为 0

PACKAGE_FIND_VERSION_MAX_PATCH

如果已请求,则为上限的补丁版本,否则为 0

PACKAGE_FIND_VERSION_MAX_TWEAK

如果已请求,则为上限的修订版本,否则为 0

PACKAGE_FIND_VERSION_MAX_COUNT

上限的版本组件数量,0 到 4

无论指定单个版本还是版本范围,变量 PACKAGE_FIND_VERSION_COMPLETE 都将被定义并保存所指定的完整请求版本字符串。

版本文件检查它是否满足请求的版本并设置这些变量

PACKAGE_VERSION

提供的完整版本字符串

PACKAGE_VERSION_EXACT

如果版本完全匹配,则为 True

PACKAGE_VERSION_COMPATIBLE

如果版本兼容,则为 True

PACKAGE_VERSION_UNSUITABLE

如果作为任何版本都不合适,则为 True

这些变量由 find_package 命令检查,以确定配置文件是否提供可接受的版本。它们在 find_package 调用返回后不可用。如果版本可接受,则设置以下变量

<PackageName>_VERSION

提供的完整版本字符串

<PackageName>_VERSION_MAJOR

如果提供,则为主版本,否则为 0

<PackageName>_VERSION_MINOR

如果提供,则为次版本,否则为 0

<PackageName>_VERSION_PATCH

如果提供,则为补丁版本,否则为 0

<PackageName>_VERSION_TWEAK

如果提供,则为修订版本,否则为 0

<PackageName>_VERSION_COUNT

版本组件数量,0 到 4

并加载相应的包配置文件。

注意

虽然版本匹配的确切行为由各个包决定,但许多包使用 write_basic_package_version_file() 来提供此逻辑。此版本检查脚本在版本范围方面有一些值得注意的注意事项

  • 版本范围的上限是对可接受版本的硬性限制。因此,尽管对版本 1.4.0 的请求可能由版本为 1.6.0 并声明“相同主版本”兼容性的包满足,但如果请求的版本范围是 1.4.0...1.5.0,则相同的包将被拒绝。

  • 版本范围的两端都必须与包声明的兼容性级别匹配。例如,如果一个包声明“相同主版本和次版本”兼容性,则请求版本范围 1.4.0...<1.5.51.4.0...1.5.0 将导致该包被拒绝,即使包版本是 1.4.1

因此,不可能使用版本范围来扩展将被接受的兼容包版本的范围。

通用包规范

对于通用包规范包配置文件,CMake 根据一组已识别的版本模式检查包版本号。目前,已识别以下模式

简单

版本号是一个整数元组,后跟一个可选的尾部段,该段在版本比较中被忽略。

自定义

解释版本号的机制未指定。版本字符串必须完全匹配才能接受包。

有关每个模式的更详细解释以及如何执行每个模式的比较,请参阅 version_schema。请注意,规范可能包含 CMake 不支持的模式。

除了包的 version 之外,CPS 允许包可选地指定 compat_version,这是包提供兼容性的最旧版本。也就是说,包保证期望 compat_version 的使用者应该能够使用该包,即使包的实际版本较新。如果未指定,则 compat_version 隐式等于包版本,即不提供向后兼容性。

当包使用已识别的模式时,CMake 将根据以下规则确定包的可接受性

  • 如果指定了 EXACT,或者包未提供 compat_version,则包的 version 必须等于请求的版本。

  • 否则

    • 包的 version 必须大于或等于请求的(最小)版本,并且

    • 包的 compat_version 必须小于或等于请求的(最小)版本,并且

    • 如果给定了请求的最大版本,它必须大于(或等于,取决于最大版本是指定为包含还是排他)包的 version

注意

选择这种范围匹配实现是为了最接近 write_basic_package_version_file() 的行为,尽管没有过于宽泛的范围什么都不匹配的情况。

对于使用 simple 版本模式的包,如果版本可接受,则设置以下变量

<PackageName>_VERSION

提供的完整版本字符串

<PackageName>_VERSION_MAJOR

如果提供,则为主版本,否则为 0

<PackageName>_VERSION_MINOR

如果提供,则为次版本,否则为 0

<PackageName>_VERSION_PATCH

如果提供,则为补丁版本,否则为 0

<PackageName>_VERSION_TWEAK

如果提供,则为修订版本,否则为 0

<PackageName>_VERSION_COUNT

版本组件数量,非负数

包文件接口变量

加载查找模块或 CMake 脚本包配置文件时,find_package 定义变量以提供有关调用参数的信息(并在返回前恢复其原始状态)

CMAKE_FIND_PACKAGE_NAME

正在搜索的 <PackageName>

<PackageName>_FIND_REQUIRED

如果给定了 REQUIRED 选项,则为 True

<PackageName>_FIND_QUIETLY

如果给定了 QUIET 选项,则为 True

<PackageName>_FIND_REGISTRY_VIEW

如果给定了 REGISTRY_VIEW 选项,则为请求的视图

<PackageName>_FIND_VERSION

完整请求版本字符串

<PackageName>_FIND_VERSION_MAJOR

如果已请求,则为主版本,否则为 0

<PackageName>_FIND_VERSION_MINOR

如果已请求,则为次版本,否则为 0

<PackageName>_FIND_VERSION_PATCH

如果已请求,则为补丁版本,否则为 0

<PackageName>_FIND_VERSION_TWEAK

如果已请求,则为修订版本,否则为 0

<PackageName>_FIND_VERSION_COUNT

版本组件数量,0 到 4

<PackageName>_FIND_VERSION_EXACT

如果给定了 EXACT 选项,则为 True

<PackageName>_FIND_COMPONENTS

指定组件列表(必需和可选)

<PackageName>_FIND_REQUIRED_<c>

如果组件 <c> 是必需的,则为 True;如果组件 <c> 是可选的,则为 False

当指定版本范围时,上述版本变量将根据版本范围的下限保留值。这是为了保留与尚未实现预期版本范围的包的兼容性。此外,版本范围将由以下变量描述

<PackageName>_FIND_VERSION_RANGE

完整请求版本范围字符串

<PackageName>_FIND_VERSION_RANGE_MIN

这指定版本范围的下限是包含还是排除。目前,INCLUDE 是唯一支持的值。

<PackageName>_FIND_VERSION_RANGE_MAX

这指定版本范围的上限是包含还是排除。此变量的可能值为 INCLUDEEXCLUDE

<PackageName>_FIND_VERSION_MIN

范围下限的完整请求版本字符串

<PackageName>_FIND_VERSION_MIN_MAJOR

如果已请求,则为下限的主版本,否则为 0

<PackageName>_FIND_VERSION_MIN_MINOR

如果已请求,则为下限的次版本,否则为 0

<PackageName>_FIND_VERSION_MIN_PATCH

如果已请求,则为下限的补丁版本,否则为 0

<PackageName>_FIND_VERSION_MIN_TWEAK

如果已请求,则为下限的修订版本,否则为 0

<PackageName>_FIND_VERSION_MIN_COUNT

下限的版本组件数量,0 到 4

<PackageName>_FIND_VERSION_MAX

范围上限的完整请求版本字符串

<PackageName>_FIND_VERSION_MAX_MAJOR

如果已请求,则为上限的主版本,否则为 0

<PackageName>_FIND_VERSION_MAX_MINOR

如果已请求,则为上限的次版本,否则为 0

<PackageName>_FIND_VERSION_MAX_PATCH

如果已请求,则为上限的补丁版本,否则为 0

<PackageName>_FIND_VERSION_MAX_TWEAK

如果已请求,则为上限的修订版本,否则为 0

<PackageName>_FIND_VERSION_MAX_COUNT

上限的版本组件数量,0 到 4

无论指定单个版本还是版本范围,变量 <PackageName>_FIND_VERSION_COMPLETE 都将被定义并保存所指定的完整请求版本字符串。

在模块模式下,加载的查找模块负责遵守这些变量所详述的请求;有关详细信息,请参阅查找模块。在配置模式下,find_package 自动处理 REQUIREDQUIET[version] 选项,但由包配置文件以对包有意义的方式处理组件。包配置文件可以将 <PackageName>_FOUND 设置为 false,以告知 find_package 组件要求未满足。

CPS 传递依赖

通用包规范包描述包含一个或多个组件,这些组件又可能依赖于包内部或外部的其他组件。当需要外部组件时,提供包被记为包的包级要求。此外,所需的组件集通常在所述外部包要求中注明。

当 CMake 脚本包描述使用 find_dependency() 命令来处理传递依赖时,CMake 使用内部嵌套的 find_package 调用本身处理 CPS 的传递依赖。此调用可以通过另一个 CPS 包或通过 CMake 脚本包解析 CPS 包依赖项。处理 CPS 组件依赖项的方式受到一些注意事项的影响。

当解析传递依赖的候选是另一个 CPS 包时,事情很简单;COMPONENTS 和 CPS“组件”可以直接比较(并且与 CMake“导入目标”有效同义)。然而,CMake 脚本包被鼓励(并且经常)检查是否找到了必需的组件,无论包是否描述了单独的组件。此外,即使那些确实描述组件的包通常也与 CPS 通常的导入目标没有相同的关联。因此,将 CPS 包声明的所需组件集传递给 COMPONENTS 将导致解析依赖项的虚假失败。

为了解决这个问题,如果解析 CPS 传递依赖的候选是 CMake 脚本包,CMake 将由消费 CPS 包声明的所需组件作为 OPTIONAL_COMPONENTS 传递,并执行单独的内部检查,以确认候选包提供了所需的导入目标。这些目标必须命名为 <PackageName>::<ComponentName>,以符合 CPS 约定,否则检查将认为包未找到。