find_package

注意

使用 依赖项 指南 提供了对这个一般主题的高级介绍。它提供了更广泛的概述,说明 find_package() 命令如何融入更大的图景,包括它与 FetchContent 模块的关系。建议在继续阅读以下细节之前先阅读该指南。

查找包(通常由项目外部的东西提供),并加载其特定于包的详细信息。对此命令的调用也可以被 依赖项提供程序 拦截。

典型用法

大多数对 find_package() 的调用通常具有以下形式

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

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

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

理解 基本签名 应该足以用于 find_package() 的一般用法。打算提供包配置文件的项目维护者应理解更大的图景,如 完整签名 以及此页面上的所有后续章节中所述。

搜索模式

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

模块模式

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

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 在其中搜索配置和版本文件的位置比模块模式复杂得多(请参阅 配置模式搜索过程)。

配置和版本文件通常作为包的一部分安装,因此它们往往比 Find 模块更可靠。它们通常包含包内容的直接知识,因此在配置或版本文件本身内不需要搜索或启发式方法。

配置模式受 基本完整 命令签名的支持。

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] [[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 之后列出。

附加的可选组件可以列在 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] [[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 变量中。

如果找不到包配置文件,除非指定了 QUIET 参数,否则 CMake 将生成一个描述问题的错误。如果指定了 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

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

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 变量。如果传递了 NO_CMAKE_INSTALL_PREFIX 或通过将 CMAKE_FIND_USE_INSTALL_PREFIX 设置为 FALSE,则可以跳过对 CMAKE_INSTALL_PREFIXCMAKE_STAGING_PREFIX 的搜索。如果传递了 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 表达式(*)的搜索路径,除非设置了 CMAKE_FIND_PACKAGE_SORT_ORDER 变量,否则搜索与 glob 匹配的目录的顺序是不确定的。此变量以及 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,以便解析符号链接并存储文件的真实路径。

每个非 REQUIRED 的 find_package 调用都可以禁用或设置为 REQUIRED

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

配置模式版本选择

注意

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

当给出 [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.6.0 且声明“相同主版本”兼容性的包可能满足对版本 1.4.0 的请求,但如果请求的版本范围是 1.4.0...1.5.0,则将拒绝相同的包。

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

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

通用包规范

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

simple

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

custom

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

有关每个模式的更详细说明以及如何执行每个模式的比较,请参阅 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 约定,否则检查将认为找不到该包。