Cmake命令之find_package介绍
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cmake命令之find_package介绍相关的知识,希望对你有一定的参考价值。
参考技术A find_package 用于查找包(通常是使用三方库),并返回关于包的细节(使用包所依赖的头文件、库文件、编译选项、链接选项等)
与 find_libaray 直接在指定搜索目录下搜索库不同, find_package 命令可以获取更多的信息,那么它的搜索方式也是与 find_libaray 不一样,它有两种不同的搜索方式,因此在介绍这个命令的细节之前,先简单介绍一下 find_package 命令的两种搜索模式: 模块模式 ( Module mode )和 配置模式 ( Config mode )。
在该模式下, Cmake 会搜索一个名为 Find<PackageName>.cmake 的文件,其中 <PackageName> 为待搜索包的名称。
搜索路径的顺序依次是:
如果找到文件 Find<PackageName>.cmake , Cmake 会读取并处理该文件,简而言之,它负责检查一些条件(如版本号是否满足等)是否满足,并在找到包后,返回给调用者一些变量,用以获取包的详细信息。
一般来说, Find<PackageName>.cmake 文件不是随包本身一起提供的,更多的是外部针对已有包的重新包装,例如操作系统、 Cmake 程序、甚至是调用 find_package 命令的工程针对已有的包提供针对该包的 .cmake 文件。
该模式下, CMake 会搜索 <lowercasePackageName>-config.cmake 文件或 <PackageName>Config.cmake 文件。如果 find_package 命令中指定了具体的版本,也会搜索 <lowercasePackageName>-config-version.cmake 或 <PackageName>ConfigVersion.cmake 文件,因此配置模式下通常会提供配置文件和版本文件(注意形式上要保持一致),并且作为包的一部分一起提供给使用者。
该模式下对 .cmake 文件的搜索路径的顺序比较复杂,具体见本文的 4.1 节。
find_package 命令有两种格式, 基本命令格式 和 完整命令格式 。
几个重要的参数介绍:
这里介绍一下与基本命令有差异的地方:
<PackageName>_FOUND 变量用来表示包是否找到, True 表示包找到了, False 表示未找到满足条件的包。如果包被找到,那么还会提供其他与这个包相关的变量供调用者使用,例如包的头文件、库文件等。这些变量都是以 <PackageName>_ 开头的,具体的命名格式请参考 Cmake中find_package命令的搜索模式之模块模式(Module mode) 的 四、对标准变量名称的更多说明 章节。
搜索模式有两种:模块模式和配置模式。命令有两种形式:基本命令和完整命令。他们之间的关系是:
我们将以两个例子分别展示两种搜索模式。本例中会利用我自己系统( macOS )已经安装的库 LibLZMA (如何编写自己的库并让 find_package 两种模式能搜索到,请参考另外两篇文章看 Cmake中find_package命令的搜索模式之模块模式(Module mode) 和 Cmake中find_package命令的搜索模式之配置模式(Config mode) ,尝试搜索这个库,并利用这个库提供的接口 lzma_version_string (在头文件 lzma.h 中提供)来获取它的版本号,并打印出来,测试程序如下:
模块模式的 CMakeLists.txt 内容如下:
由于 lzma 库本身未提供 lzmaConfig.cmake ,我们简单的编写一个,内容就是为 find_package 提供 lzma 库所在的头文件和库文件,并在 find_package 中指定查找该 .cmake 所在的路径:
配置模式的 CMakeLists.txt 内容如下:
CMake 会从如下从几个目录中取搜索配置文件,下面列出了将会搜索的目录,每一个目录后面通过字母来标记不同的操作系统( W 表示 Windows , U 表示 UNIX , A 表示 Apple ),目录中的 <prefix> 是目录的前缀,将在 4.1.2 介绍是怎么生成的:
在支持 macOS 的 FRAMEWORK 和 BUNDLE 系统中,会搜索如下框架和应用程序包目录是否包含配置文件:
上面列举的目录中, <name> 是大小写不敏感的,并且会跟 <PackageName> 或者 NAMES 指定的名字进行匹配。
CMAKE_LIBRARY_ARCHITECTURE 变量指定的时候,也会搜索 lib/<arch> 相关的路径,会按照如下顺序搜索:
可以通过 PATH_SUFFIXES 变量指定搜索路径的后缀,会在上述的每一个路径中都添加后缀路径进行查找。
如果 NO_DEFAULT_PATH 选项指定了的话,那么所有以 NO_* 开头的命令都会使能, <prefix> 的查找顺序依次如下:
CMAKE_FIND_ROOT_PATH 用于指定搜索的根路径。
在 find_package 命令调用之前设置 CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS 为 TRUE ,这样如果查找到的路径是一个符号链接,会将符号链接对应的真实路径存起来。
当指定 version 参数,配置模式将仅会查找能兼容指定版本的包,如果指定了 EXACT ,则只会查找精确匹配指定版本的包。 CMake 本身不会对版本号做任何转换,而是通过查找到包的版本校验文件(包自身提供的) <PackageName>ConfigVersion.cmake (或 <PackageName>-config-version.cmake ),调用版本配置文件做校验,版本配置文件可以通过 CMakePackageConfigHelpers 模块来辅助创建。可以参考 Cmake中find_package命令的搜索模式之配置模式(Config mode) 中的例子。
当 find_package 命令中指定 version 参数后,会把 version 参数分解出来,赋值到 PACKAGE_FIND_XXX 中,供版本配置文件校验版本号使用,具体赋值的变量如下:
当指定的版本是一个范围时,上述变量会存放范围中较小的那个版本号,这个主要是为了保证对没有实现版本范围的兼容,此外,也会赋值如下变量:
当版本配置文件完成版本校验后,会设置如下 PACKAGE_VERSION_XXX 变量供 find_package 使用,具体的变量如下:
上面的 PACKAGE_VERSION_XXX 几个变量仅用于 find_package 命令检查配置文件是否提供了一个可接受的版本,一旦 find_package 命令返回后,这些变量就失效了。如果版本校验通过,那么如下 <PackageName>_VERSION_XXX 变量会被设置,供 find_package 调用者使用:
Cmake命令之find_library介绍
参考技术A该命令用于查找库(动态库或者静态库),当构建依赖于第三方库/系统库,可以使用该命令来查找并使用库(Cmake中有另外一个命令 find_package ,能获取库的更多信息,具体可以参考 Cmake命令之find_package介绍 )
通过一个例子来看下基本的使用,假设我们目录和文件树如下,:
我们在 mylib 中生成最终的库 libmymath.a ,然后在顶层的 CMakeLists.txt 中查找这个库文件,几个文件的具体内容如下:
在 ./mylib/ 下执行 cmake . 和 make 以便生成库 libmymath.a ,然后在 ./ 目录下执行 cmake . 和 make ,得到可执行文件 test ,运行 test 的结果为:
库的搜索路径分为两大类: 默认搜索路径 和 附加搜索路径 。
默认搜索 路径包含 cmake 定义的以 CMAKE 开头的一些变量(例如 CMAKE_LIBRARY_ARCHITECTURE 、 CMAKE_PREFIX_PATH 、 CMAKE_LIBRARY_PATH 、 CMAKE_FRAMEWORK_PATH )、标准的系统环境变量(例如系统环境变量 LIB 和 PATH 定义的路径)、系统的默认的库安装路径(例如 /usr 、 /usr/lib 等);
附加搜索路径 即 find_library 命令中通过 HINTS 或 PATHS 指定的路径;
1) 通过命令行使用 -D 指定的 CMAKE_XXX_PATH 变量,也就是形如 cmake . -DCMAKE_XXX_PATH=paths 的格式。其中 CMAKE_XXX_PATH 包含如下几个:
CMAKE_PREFIX_PATH :指定搜索目录的前缀,如果前缀有多个,需要以 分号分割的列表 方式提供,该变量默认为空,一旦该变量非空,那么会搜索该变量提供的目录,以及 $CMAKE_PREFIX_PATH/lib ;例如 CMAKE_PREFIX_PATH=A;B ,那么 find_library 会从 A 、 B 以及 A/lib 、 B/lib 中搜索库是否存在;
CMAKE_LIBRARY_ARCHITECTURE :如果该变量被设置,那么会搜索目录 $CMAKE_PREFIX_PATH/lib/$CMAKE_LIBRARY_ARCHITECTURE ;
CMAKE_LIBRARY_PATH :指定 find_library 的库查找目录,默认值为空,多个值时需要以分号分割列表指定;
CMAKE_FRAMEWORK_PATH *:指定 macOS 的框架作为搜索路径。
2) 通过在 环境变量 中指定 CMAKE_XXX_PATH 变量,例如在 window 的环境变量中增加 CMAKE_XXX_PATH (以 ; 分割多个路径)、 Linux 中 shell 配置文件中添加(以 : 分割多个路径)。用法和 cmake -D 指定类似,例如在我的机器中( macOS ),在 .zshrc (我的命令行配置文件)中增加 export CMAKE_LIBRARY_PATH="/XXX/……/mylib" ,即可在将该目录加入到搜索路径中。
3) HINTS 选项指定的路径。
4) 系统环境变量指定的目录,默认是 LIB 和 PATH 指定的路径。例如在 PATH 中指定库搜索目录;
也可以通过 find_library 中的 PATHS ENV 环境变量名称 ( cmake 中使用环境变量名称的格式为 $ENV环境变量名称 )来指定从哪个环境变量名称中获取路径,例如定义一个 TESTPATH 环境变量并赋值为 ./mylib ,并在 find_library 命令中指定使用该环境变量:
5)跟当前系统相关的平台文件路径,一般来说指的是当前系统安装软件的标准目录,不同的操作系统对应的路径有所不同。 camke 中 find_library 与此相关的也有如下几个, CMAKE_SYSTEM_XXX_PATH 变量,这些:
CMAKE_SYSTEM_PREFIX_PATH :指定安装目录的前缀,例如在 Windows 下的 /XXXX/Program Files , Linux 下的 /usr 或 /usr/local 等。 find_library 命令会搜索这些前缀目录,也会以这些目录加上 lib 进行搜索,例如搜索 /usr/local/lib ;
CMAKE_SYSTEM_LIBRARY_PATH :默认是当前系统的标准目录,不建议修改它;例如在我的系统,这个变量的值是 /usr/lib/X11 ;
CMAKE_SYSTEM_FRAMEWORK_PATH : macOS 框架路径,默认是当前系统的标准目录,不建议修改它;例如在我的系统,这个变量的值包含了路径 /Library/Frameworks ;
6) PATHS 选项指定的路径。
以上是关于Cmake命令之find_package介绍的主要内容,如果未能解决你的问题,请参考以下文章
Cmake中find_package命令的搜索模式之模块模式(Module mode)