CMake学习日志之find_package

转载总结自深入理解CMake(3):find_package()的使用

CMake学习日志之find_package

一、首先明确一下默认查找的路径

<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
PATH

二、了解一下find_package()的两种模式

find_package()有Module模式(基本用法,basic signature)Config模式(full signature,完全用法)

在以下三种情况下为Config模式

  • find_package()中指定CONFIG关键字
  • find_package()中指定NO_MODULE关键字
  • find_package()中使用了不在Module模式下支持的配置关键字

三、明确find_package()下的所有关键字

3.1 Module模式

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
                           [REQUIRED] [[COMPONENTS] [components...]]
                           [OPTIONAL_COMPONENTS components...]
                           [NO_POLICY_SCOPE])

注意,在没设置MOUDULE选项的情况下,如果Module模式找不到包则会自动进入Config模式

versionEXACT: 都是可选的,version指定的是版本,如果指定就必须检查找到的包的版本是否和version兼容。如果指定EXACT则表示必须完全匹配的版本而不是兼容版本就可以。

QUIET 可选字段,表示如果查找失败,不会在屏幕进行输出(但是如果指定了REQUIRED字段,则QUIET无效,仍然会输出查找失败提示语)。

MODULE 可选字段。前面提到说“如果Module模式查找失败则回退到Config模式进行查找”,但是假如设定了MODULE选项,那么就只在Module模式查找,如果Module模式下查找失败并不回落到Config模式查找。

REQUIRED可选字段。表示一定要找到包,找不到的话就立即停掉整个cmake。而如果不指定REQUIRED则cmake会继续执行。

COMPONENTS components :可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于REQUIRED,导致cmake停止执行。

OPTIONAL_COMPONENTScomponents:可选的模块,找不到也不会让cmake停止执行。

3.2 Module模式查找顺序

Module模式下是要查找到名为Find.cmake的文件。

先在CMAKE_MODULE_PATH变量对应的路径中查找。如果路径为空,或者路径中查找失败,则在cmake module directorycmake安装时的Modules目录,比如/usr/local/share/cmake/Modules)查找。

不管使用哪一种模式,只要找到包就会定义下面这些变量

    <NAME>_FOUND
    <NAME>_INCLUDE_DIRS or <NAME>_INCLUDES
    <NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS
    <NAME>_DEFINITIONS

这些都在Find.cmake文件中。

现在,在你的代码(要使用库 的代码)的顶层目录中的CMakeLists.txt文件中,我们检查变量<NAME>_FOUND 来确定包是否被找到。大部分包的这些变量中的包名是全大写的,如 LIBFOO_FOUND ,有些包则使用包的实际大小写,如 LibFoo_FOUND 。如果找到这个包,我们用 _INCLUDE_DIRS 调用 include_directories() 命令,用 _LIBRARIES 调用 target_link_libraries() 命令

3.3 Config模式下find_package()的用法

 find_package(<PackageName> [version] [EXACT] [QUIET]
    [REQUIRED] [[COMPONENTS] [components...]]
    [CONFIG|NO_MODULE]
    [NO_POLICY_SCOPE]
    [NAMES name1 [name2 ...]]
    [CONFIGS config1 [config2 ...]]
    [HINTS path1 [path2 ... ]]
    [PATHS path1 [path2 ... ]]
    [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_SYSTEM_PACKAGE_REGISTRY]
    [CMAKE_FIND_ROOT_PATH_BOTH |
    ONLY_CMAKE_FIND_ROOT_PATH |
    NO_CMAKE_FIND_ROOT_PATH])

Config模式下的查找顺序,比Module模式下要多得多。而且,新版本的CMake比老版本的有更多的查找顺序(新增的在最优先的查找顺序)。它要找的文件名字也不一样,Config模式要找<PackageName>Config.cmake<lower-case-package-name>-config.cmake。查找顺序为:

3.3.1 <PackageName>_ROOT的cmake变量或环境变量

名为<PackageName>_ROOT的cmake变量或环境变量。CMake3.12新增。设定CMP0074 Policy来关闭。

注意:如果定义了<PackageName>_DIR cmake变量,那么<PackageName>_ROOT不起作用。举例:

cmake_minimum_required(VERSION 3.13)

project(fk_cmk)

set(OpenCV_ROOT "F:/zhangzhuo/lib/opencv_249/build")

set(OpenCV_DIR "F:/zhangzhuo/lib/opencv_300/build")

find_package(OpenCV QUIET
    NO_MODULE
    NO_DEFAULT_PATH
    NO_CMAKE_PATH
    NO_CMAKE_ENVIRONMENT_PATH
    NO_SYSTEM_ENVIRONMENT_PATH
    NO_CMAKE_PACKAGE_REGISTRY
    NO_CMAKE_BUILDS_PATH
    NO_CMAKE_SYSTEM_PATH
    NO_CMAKE_SYSTEM_PACKAGE_REGISTRY
)

message(STATUS "OpenCV library status:")
message(STATUS "    version: ${OpenCV_VERSION}")
message(STATUS "    libraries: ${OpenCV_LIBS}")
message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")


实际上会找到opencv300,也就是OpenCV_DIR这一cmake变量的值最先起作用

3.3.2 cmake特定的缓存变量:
    CMAKE_PREFIX_PATH
    CMAKE_FRAMEWORK_PATH
    CMAKE_APPBUNDLE_PATH
  

可以通过设定NO_CMAKE_PATH关闭这一查找顺序

3.3.3 cmake特定的环境变量
    <PackageName>_DIR
    CMAKE_PREFIX_PATH
    CMAKE_FRAMEWORK_PATH
    CMAKE_APPBUNDLE_PATH
    
3.3.4 HINT字段指定的路径
3.3.5 搜索标准的系统环境变量PATH

其中如果是以/bin或者/sbin结尾的,会自动转化为其父目录。通过指定NO_SYSTEM_ENVIRONMENT_PATH来跳过

3.3.6 其他

其他

四、思路总结

4.1 判断find_package()实际执行的是module模式还是config模式

  1. find_package()这样的用法并不能看出是module模式还是config模式。要看CMAKE_MODULE_PATHcmake安装路径下是否有Find<PackageName>.cmake脚本存在,并且这个脚本是否能正确的找到包。如果上述两个位置不存在Find.cmake,或者这个Find.cmake执行失败,则进入config模式。

  2. 可以通过CONFIG、NO_MODULE、CONFIG模式特有字段,来设定为config模式

  3. 明确<PackageName>_DIRconfig模式特有的缓存变量

可以在find_package()前设定<PackageName>_DIR,指向包含<PackageName>Config.cmake<lower-case-package-name>-config.cmake的目录。

<PackageName>_ROOT先设定,再设定<PackageName>_DIR,最后find_package(<PackageName>);并且两个都能找到包,则<PackageName>_DIR起作用

<PackageName>_DIR也可在find_package()后使用例如打印

module模式下在find_package()前使用==_DIR==,并不能用来帮助find_package()找到包;并且在find_package()后,也并没有_DIR缓存变量自动存在

  1. 明确<PackageName>_ROOTcmake3.12起支持的变量

<PackageName>_ROOT变量被find_package, find_library, find_path, find_program, find_file支持。因此,尽管从find_package()文档页看会以为<PackageName>_ROOT只被config模式支持而不被module模式支持,但是module模式下通过另外4个find命令会间接的使用到<PackageName>_ROOT从而find_package命令的module模式间接的支持<PackageName>_ROOT变量
<PackageName>_ROOT设定后,find_package()的config模式会在<PackageName>_ROOT目录及其子目录下寻找cmake的config文件;而_DIR则很傻,不会在子目录中寻找

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值