find_package()
注意:Using Dependencies Guide提供了对该主题的高级解释。它提供了find_package()命令在更大范围的解释概述,包括它和
FetchContent
模块的关系。建议在继续阅读以下详细信息之前先阅读该指南。
用来找到一个包(通常由项目外部的东西提供),并加载其特定于包的详细信息。依赖项提供程序(Dependicies Providers)也可以拦截对此命令的调用。
查找模式
该命令有几种查找包的模式:
-
模块模式
在这种模式下,CMake 搜索一个名为Find<PackageName>.cmake
的文件,首先在CMAKE_MODULE_PATH
,然后在CMake安装提供的Find Modules中。如果找到该文件,CMake 将读取并处理该文件。它负责查找包、检查版本并生成任何需要的消息。一些 Find 模块提供有限的版本控制,或者不提供版本控制,请查阅 Find module的文档。Find<PackageName>.cmake
文件通常不由包本身提供。相反,它通常由包外部的某些东西提供,例如操作系统、CMake 本身,甚至是调用find_package()
命令的项目。由于是外部提供的,查找模块在本质上往往是试探式的,并且很容易变得过时。他们通常搜索某些库、文件和其他包工件。模块模式仅受基本命令签名(basic command signature)支持。
-
配置模式
在这种模式下,CMake 搜索名为<lowercasePackageName>-config.cmake
或<PackageName>Config.cmake
的文件。如果指定了版本详细信息,它还将查找<lowercasePackageName>-config-version.cmake
或<PackageName>ConfigVersion.cmake
(有关如何使用这些单独的版本文件,请参阅配置模式版本选择(Config Mode Version Selection))。在配置模式下,可以为该命令提供一个名称列表,以作为包名称进行搜索。CMake 搜索配置和版本文件的位置比模块模式复杂得多(请参阅配置模式搜索过程(Config Mode Search Procedure))。
配置和版本文件通常作为包的一部分安装,因此它们往往比查找模块更可靠。它们通常包含包内容的直接知识,因此不需要在配置或版本文件本身中进行搜索或试探。
-
FetchCnotent 重定向模式
3.24 新版功能:对find_package()
的调用可以在内部重定向到一个由FetchContent
模块提供的包。对于调用者来说,行为将类似于 Config 模式,除了搜索逻辑是绕过的并且不使用组件信息。看 FetchContent_Declare()和FetchContent_MakeAvailable() 了解更多详情。
当未重定向到由FetchContent
提供的包时,命令参数确定是使用 Module 还是 Config 模式。当使用 基本签名时,该命令首先以Module 模式搜索。如果未找到包,则搜索返回到配置模式。
用户可以设置CMAKE_FIND_PACKAGE_PREFER_CONFIG
变量为 true 以反转优先级并指示 CMake 在回退到Module模式之前首先使用Config模式进行搜索。
对于基本签名,可以通过MODULE
关键字来强制仅使用Module模式。如果使用 完整签名,则该命令仅在Config 模式下搜索。
在可能的情况下,用户代码通常应该使用 基本签名查找包,因为这允许使用任何模式找到包。希望提供配置包的项目维护者应该了解全局,如完整签名和本页所有后续部分中所述。
基本签名
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 和 Config 模式都支持基本签名。MODULE
关键字意味着只能使用Module模式来查找包,而不能回退到Config模式。
无论使用何种模式,都会设置一个<PackageName>_FOUND
变量来指示是否找到包。找到包后,包的特定信息通过 其他变量 和 包本身记录的导入目标(Imported Targets)来提供。QUIET
选项禁用信息性消息,包括那些指示非REQUIRED
包无法找到的消息。如果找不到包,REQUIRED
选项将停止处理并显示一条错误消息。
COMPONENTS
关键字后可能会列出特定于包的所需组件列表 。如果无法满足这些组件中的任何一个,则认为整个包未找到。如果该 REQUIRED
选项也存在,这将被视为致命错误,否则执行仍将继续。作为一种简写形式,如果存在 REQUIRED
选项,则COMPONENTS
关键字可以省略,所需的组件可以直接列在 之后REQUIRED
。
其他可选组件列在OPTIONAL_COMPONENTS
之后。如果这些都不能满足,只要满足所有要求的组件,仍然可以认为包整体找到了。
可用组件集及其含义由目标包定义。形式上,目标包如何解释提供给它的组件信息取决于目标包,但它应该遵循上述期望。对于没有指定组件的调用,没有单一的预期行为,目标包应该清楚地定义在这种情况下会发生什么。常见的安排包括假设它应该找到所有组件、没有组件或可用组件的一些明确定义的子集。
3.24 版新功能:关键字REGISTRY_VIEW
指定应查询哪些注册表视图。此关键字仅在Windows平台上有意义,在所有其他平台上将被忽略。形式上,目标包如何解释提供给它的注册表视图信息由目标包决定。
3.24 新版功能:指定GLOBAL
关键字会将所有导入的目标提升到导入项目的全局范围。或者,可以通过设置CMAKE_FIND_PACKAGE_TARGETS_GLOBAL
变量。
[version]
参数要求找到的包应该兼容的版本。有两种可能的形式可以指定它:- 格式为
major[.minor[.patch[.tweak]]]
的单一版本,其中每个部分都是一个数值。 - 具有格式
versionMin...[<]versionMax
的版本范围,其中整数部分作为单一版本约束,versionMin
和versionMax
对整数部分具有相同的格式和约束。默认情况下,两端的点.
都需要包含。通过指定<
,上限点.
将被排除。仅 CMake 3.19 或更高版本支持版本范围。
- 格式为
EXACT
选项要求版本完全匹配。此选项与指定版本范围不兼容。
如果没有[version]
和/或组件列表提供给查找模块内的递归调用,则相应的参数会自动从外部调用转发(包括[version]
的EXACT
标志 )。目前仅在逐个软件包的基础上提供版本支持(请参阅下面的版本选择(Version Selection)部分)。当指定了版本范围但包设计为仅期望单个版本时,包将忽略范围的上限点,而仅考虑范围下限的单个版本。
关于NO_POLICY_SCOPE
选项的讨论,请阅读cmake_policy()文档。
3.24 新版功能:仅在find_package()
被一个依赖提供者调用时,允许使用BYPASS_PROVIDER
关键字。提供者可以使用它来直接调用内置实现的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
选项,或者是不在基本签名中的选项,将强制纯Config模式。在纯Config模式下,命令将跳过Module模式查找,并立即进行Conifg模式查找。
Config模式查找尝试定位一个配置文件,该配置文件由要查找的包提供。创建名为·_DIR、的缓存条目以保存包含该文件的目录。默认情况下,该命令搜索名称为<PackageName>
的包。如果给出NAMES
选项,则使用它后面的名称而不是<PackageName>
。在决定是否重定向到一个提供的包时,名字也可以由FetchContent
指定。
对指定的每个名称,命令搜索名为<PackageName>Config.cmake
或 <lowercasePackageName>-config.cmake
的文件。可以使用CONFIG
选项给出一组可能的配置文件名的替换。配置模式搜索过程(Config Mode Search Procedure)在下文指出。一旦找到,将检查所有版本约束,如果满足,则由 CMake 读取和处理配置文件。由于文件是由包提供的,它已经知道包内容的位置。配置文件的完整路径存储在 cmake 变量<PackageName>_CONFIG
中。
CMake 在搜索具有适当版本的包时考虑过的所有配置文件都存储在 <PackageName>_CONSIDERED_CONFIGS
变量中,相关版本存储在<PackageName>_CONSIDERED_VERSIONS
变量中。
如果找不到包配置文件,除非指定QUIET
参数,否则 CMake 将生成一个描述问题的错误。如果指定REQUIRED
并且未找到包,则会生成致命错误并且配置步骤将停止执行。如果设置的<PackageName>_DIR
目录中不包含配置文件,CMake 将忽略它并从头开始搜索。
鼓励提供 CMake 包配置文件的包维护者命名和安装包配置文件,以便下面概述的配置模式搜索过程( Config Mode Search Procedure )无需使用其他选项即可找到它们。
配置模式查找过程
注意: 当使用 Config 模式时,无论给出的是完整签名还是基本签名,都会应用此搜索过程。
3.24 版新功能:所有find_package()
调用(即使在模块模式下)首先在CMAKE_FIND_PACKAGE_REDIRECTS_DIR
目录中查找包配置文件。FetchContent
模块,甚至是项目本身,都可以将文件写入那个目录,以将find_package()
调用重定向到项目已经提供的内容。如果在该位置没有找到配置包文件,则搜索将按照下面描述的逻辑继续进行。
CMake 为包构建了一组可能的安装前缀。在每个前缀下的几个目录中搜索配置文件。下表显示了搜索的目录。每个条目都适用于遵循 Windows ( W)、UNIX ( U) 或 Apple ( A) 约定的安装树:
入口 | 惯例 |
---|---|
<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)/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 |
[1]3.25 版中的新功能。
在支持 macOS FRAMEWORK
和BUNDLE
的系统上,将在以下目录中搜索包含配置文件的框架或应用程序包:
入口 | 惯例 |
---|---|
<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/ | A |
<prefix>/<name>.app/Contents/Resources/CMake/ | A |
在所有情况下, <name>
都被视为不区分大小写,并且对应于任何指定的名称(<PackageName>
或由NAMES
给出的名称)。
如果设置了CMAKR_LIBRARY_ARCHITECTURE
变量,会启用带有lib/<arch>
的路径。lib*
包含lib64
,lib32
,libx32
,lib
中的一个或多个值(按该顺序搜索)。
- 当
FIND_LIBRARY_USE_LIB64_PATHS
属性设置为TRUE
时,带有lib64
的路径在64位平台上被搜索。 - 当
FIND_LIBRARY_USE_LIB32_PATHS
属性设置为TRUE
时,带有lib32
的路径在32位平台上被搜索。 - 当
FIND_LIBRARY_USE_LIBX32_PATHS
属性设置为TRUE
时,带有libx32
的路径在使用x32 ABI的平台上 被搜索。 lib
路径总是会被搜索。
在 3.24 版更改:在Windows平台上,通过HINTS
和PATHS
关键字,可以使用专用语法将注册表查询作为指定的目录的一部分。此类规范将在所有其他平台上被忽略。
3.24 新版功能:可以指定REGISTRY_VIEW
,以管理指定的Windows注册表查询,作为PATHS
和HINTS
的一部分。
指定那些注册表视图必须被查询。此选项仅在Windows平台上有意义,在其他平台上将被忽略。如果未指定,当CMP0134
政策是NEW
时,TARGET
视图会被使用。对于策略为OLD
时的默认视图,参考CMP0134。
64
- 查询 64 位注册表。在 32 位 Windows 上,它始终返回字符串
/REGISTRY-NOTFOUND
。
- 查询 64 位注册表。在 32 位 Windows 上,它始终返回字符串
32
- 查询 32 位注册表。
64-32
- 查询两个视图 (64和32) 并为每个视图生成一个路径。
32-64
- 查询两个视图 (32和64) 并为每个视图生成一个路径。
HOST
- 查询与主机架构匹配的注册表:在64 位Windows是
64
,32 位 Windows 上是32
。
- 查询与主机架构匹配的注册表:在64 位Windows是
TARGET
- 查询与指定架构相匹配的注册表 ,架构由
CMAKE_SIZEOF_VOID_P
变量指定。如果未定义,则回退到HOST
视图。
- 查询与指定架构相匹配的注册表 ,架构由
BOTH
- 查询两个视图 (32和64)。该顺序取决于以下规则:如果定义了
CMAKE_SIZEOF_VOID_P
变量,根据这个变量的内容使用如下视图:8
:64_32
4
:32_64
- 如果
CMAKE_SIZEOF_VOID_P
变量未定义,取决于主机的架构:- 64 位:
64_32
- 32 位:
32
- 64 位:
- 查询两个视图 (32和64)。该顺序取决于以下规则:如果定义了
如果指定了PATH_SUFFIXES
,后缀将逐一附加到每个 ( W) 或 ( U) 目录条目。
这组目录旨在与在其安装树中提供配置文件的项目合作。上面标有 ( W) 的目录用于在 Windows 上安装,其中前缀可能指向应用程序安装目录的顶部。标有 ( U) 的用于在 UNIX 平台上安装,其中前缀由多个包共享。这只是一个约定,所以仍然会在所有平台上搜索所有 ( W) 和 ( U ) 目录。标有 ( A) 的目录用于在 Apple 平台上安装。 CMAKE_FIND_FRAMEWORK
和CMAKE_FIND_APPBUNDLE
变量决定优先顺序。
…略(感觉是次要的)