find_package用于查找包(通常是使用三方库),并返回关于包的细节(使用包所依赖的头文件、库文件、编译选项、链接选项等)
与find_libaray直接在指定搜索目录下搜索库不同,find_package命令可以获取更多的信息,那么它的搜索方式也是与find_libaray不一样,它有两种不同的搜索方式,因此在介绍这个命令的细节之前,先简单介绍一下find_package命令的两种搜索模式:模块模式(Module mode)和配置模式(Config mode)。
Module mode)在该模式下,Cmake会搜索一个名为Find的文件,其中为待搜索包的名称。
搜索路径的顺序依次是:
CMAKE_MODULE_PATH指定的路径中进行查找Cmake安装路径中查找。Cmake会在其安装路径下提供很多.cmake文件,例如/XXX/cmake/Modules/目录下(不同的系统安装目录可能不一致)如果找到文件Find,Cmake会读取并处理该文件,简而言之,它负责检查一些条件(如版本号是否满足等)是否满足,并在找到包后,返回给调用者一些变量,用以获取包的详细信息。
一般来说,Find文件不是随包本身一起提供的,更多的是外部针对已有包的重新包装,例如操作系统、Cmake程序、甚至是调用find_package命令的工程针对已有的包提供针对该包的.cmake文件。
Config mode)该模式下,CMake会搜索文件或文件。如果find_package命令中指定了具体的版本,也会搜索或文件,因此配置模式下通常会提供配置文件和版本文件(注意形式上要保持一致),并且作为包的一部分一起提供给使用者。
该模式下对.cmake文件的搜索路径的顺序比较复杂,具体见本文的4.1节。
.cmake后缀文件的作用是什么?
find_package的两种搜索模式都会按照一定规则从路径下搜索.cmake后缀的文件,两种模式下的.cmake文件作用都是为了给find_package命令的调用方返回有关包的信息(头文件路径、库文件路径、编译连接选项、版本信息等等)
find_package命令有两种格式,基本命令格式和完整命令格式。
find_package( [version] [EXACT] [QUIET] [MODULE][REQUIRED] [[COMPONENTS] [components...]][OPTIONAL_COMPONENTS components...][NO_POLICY_SCOPE])
几个重要的参数介绍:
PackageName:待查找包的名称。此外它还决定两种搜索模下的.cmake文件名称:例如模块模式下的名称为Find.cmake ,而配置模式下为-config.cmake /-config-version.cmake 。MODULE:该选项指定find_package命令只使用模块模式搜索方式查找。未指定该选项时,find_package会优先使用模块模式搜索,仍未找到包时,会切换成配置模式搜索。version:待查找包的版本号要求,版本号为点分格式,由四个部分组成,每个部分都是一个数字,均为可选:major[.minor[.patch[.tweak]]],例如1.1.1.1、1.0、等。同样也可以指定版本范围(CMake 3.19及之后才支持),格式为:versionMin...[<]versionMax,versionMin和versionMax均是major[.minor[.patch[.tweak]]]形式的版本号,默认情况下会包含这个指定区间两端的版本号,但如果指定了<,那么会排除掉versionMax,例如1.1.1.1...1.1.2.0、1.1.1.1...<1.1.2.0等。EXACT:该选项要求待查找包的版本必须与指定的版本精确匹配,因此如果指定的是一个版本范围,不能使用该参数。QUIET:禁止输出信息,正常情况当找到包时,CMake会打印一些信息,指定该选项时会禁止掉这些打印。例外是当同时指定QUIET时,如果找不到包,仍然会输出错误信息并终止执行过程。REQUIRED:当未找到满足条件的包(例如版本号不匹配,或指定组件未找到等),会终止CMake的执行过程,并输出一条错误信息。如果未指定该选项,即使未找到满足条件的包,CMake的执行过程也会继续。COMPONENTS:指定要查找的组件。通常一个包可能包含多个组件(可以理解为多个库,例如把C++的std看成一个包的概念,那么vector就是std下的其中一个组件),我们的工程可能会依赖包下的具体某个组件,因此可以通过这个选项来检测这些组件是否存在。通常的约定是,该选项后的组件应该都找到时才认为包找到,否则认为未找到满足条件的包。这个约束会依赖包的.cmake来实现,通过find_package命令传入的COMPONENTS可以通过_FIND_COMPONENTS 这个变量来获得。举个简单的例子: # mymathConfig.cmake,假定它位于./mymath/mymath目录下
# 作用就是校验COMPONENTS是否是test,只有当COMPONENTS为空或者为test时,包mymath才会被找到message(${mymath_FIND_COMPONENTS}) # `find_package`命令的`COMPONENTS`传入的
if(${mymath_FIND_COMPONENTS} STREQUAL "")message("Empty comps.")set(mymath_INCLUDE_DIR "/XXX/mymath")set(mymath_LIBRARY "/XXX/mymath/libmymath.a")
else()foreach(comp ${mymath_FIND_COMPONENTS})if (comp MATCHES "test")message("Find comp test")set(mymath_INCLUDE_DIR "/XXX/mymath")set(mymath_LIBRARY "/XXX/mymath/libmymath.a")endif()endforeach()
endif() # 顶层目录的CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
project(find_package_test)
find_package(mymathCONFIGREQUIREDCOMPONENTS testPATHS ./mymath/mymath
)if(mymath_FOUND)message("Find mymath: ${mymath_INCLUDE_DIR}; ${mymath_LIBRARY};")
endif() # 执行cmake .
cmake .# 输出为
test
Find comp test
Find mymath: /XXX/mymath; /XXX/mymath/libmymath.a; OPTIONAL_COMPONENTS:与COMPONENTS的区别是,不强制要求这些组件必须存在。不影响CMake的执行。find_package( [version] [EXACT] [QUIET][REQUIRED] [[COMPONENTS] [components...]][OPTIONAL_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|NO_MODULE:这两个选项二选一即可,表示强制find_package命令使用配置模式搜索,忽略模块模式搜索。NAMES:默认情况下find_package命令会查找名为的包。如果NAMES选项后指定了名称,则会使用这些名字来查找包而忽略参数。PATHS/HINTS:配置模式下指定.cmake文件的搜索路径。NO_XXX_PATH:配置模式下忽略指定的路径,具体的含义可以参考4.1.2节。
Cmake命令之find_package介绍 - 简书
Cmake中find_package命令的搜索模式之模块模式(Module mode) - 简书
Cmake中find_package命令的搜索模式之配置模式(Config mode) - 简书
上一篇:关于花草树木的古诗
下一篇:地图下载白嫖神器!你该怎么用好它