前言:
学习笔记,随时更新。如有谬误,欢迎指正。
说明:
- 红色字体为较为重要部分。
- 绿色字体为个人理解部分。
19 依赖使用指南
19.1 介绍
对于希望使用 CMake 来使用第三方二进制包的开发人员来说,有多种可能的最佳方式,这取决于 CMake 对第三方库的感知程度。
与软件包一起提供的 CMake 文件包含查找每个构建依赖项的说明。有些构建依赖项是可选的,因为如果缺少依赖项,使用不同的特性集构建可能会成功,而有些依赖项是必需的。 CMake 为每个依赖项搜索已知的位置,并且提供的软件可能会为 CMake 提供额外的提示或位置来查找每个依赖项。
如果 cmake 没有找到所需的依赖项,则用包含 NOTFOUND 值的项填充缓存。该值可以通过在命令行或 ccmake 或 cmake-gui 工具中指定来替换。有关设置缓存项的更多信息,请参阅用户交互指南。
19.2 提供配置文件包的库
第三方提供库二进制文件以供 CMake 使用的最方便的方法是提供配置文件包。这些包是与库一起发布的文本文件,指导 CMake 如何使用库二进制文件和相关的头文件、辅助工具和库提供的 CMake 宏。
配置文件通常可以在名称与 lib/cmake/<PackageName> 模式相匹配的目录中找到,尽管它们也可能在其他位置。 <PackageName> 对应于在 CMake 中使用 find_package 命令的代码,如 find_package(PackageName REQUIRED) 。
lib/cmake/<PackageName> 目录将包含一个名为 <PackageName>Config.cmake 或 <PackageName>-config.cmake 的文件。这是 CMake 包的入口点。一个单独的可选文件 <PackageName>ConfigVersion.cmake 也可能存在于该目录中。 CMake 使用该文件来确定第三方包的版本是否满足指定了版本约束的 find_package 命令的使用。使用 find_package 时指定版本是可选的,即使存在 ConfigVersion 文件。
如果找到 Config.cmake 文件并且满足可选指定的版本,则 CMake 的 find_package 命令确认了要找到的包,并且假定整个库包按照设计完成的。
可能有其他文件提供 CMake 宏或导入的目标供你使用。 CMake 对这些文件不强制任何命名约定。它们通过 CMake 的 include 命令与主配置文件相关联。
出于使用第三方二进制文件包的目的而调用 CMake (的前提条件是)需要 CMake 的 find_package 命令能成功地找到包。如果包的位置在 CMake 已知的目录中,则 find_package 调用应该会成功。CMake 已知的目录是特定于平台的。例如,使用标准系统包管理器安装在 Linux 上的包将自动在 /usr 前缀中寻找。类似地,安装在 Windows 上的Program Files 中的包也会自动被寻找。
不能自动找到的包位于 CMake 无法预测的位置,例如 /opt/mylib 或 $HOME/dev/prefix 。这是一种正常的情况, CMake 为用户提供了几种方法来指定在哪里找到这样的库。
CMAKE_PREFIX_PATH 变量可以在调用 CMake 时设置。它被当作搜索配置文件包的路径列表。安装在 /opt/somepackage 中的包通常会安装配置文件,如 /opt/somepackage/lib/cmake/somepackage/SomePackageConfig.cmake 。在这种情况下, /opt/somepackage 应该被添加到 CMAKE_PREFIX_PATH 中。
环境变量 CMAKE_PREFIX_PATH 也可以用前缀填充以搜索包。与 PATH 环境变量一样,这是一个列表,需要使用特定于平台的环境变量列表项分隔符(在 Unix 上是 : ,在 Windows 上是 ; )。
当需要指定多个前缀,或者当多个不同的包二进制文件在同一个前缀中可用时, CMAKE_PREFIX_PATH 变量为此提供了方便。包的路径也可以通过设置与 <PackageName>_DIR 匹配的变量来指定,比如 SomePackage_DIR 。注意,这不是一个前缀,而应该是一个包含配置风格的包文件的目录的完整路径,比如上面的例子中的 /opt/somepackage/lib/cmake/somepackage/ 。
19.3 从包中导入目标
提供配置文件包的第三方包也可能提供被导入目标。这些将在包含与包相关的特定于配置的文件路径的文件中指定,例如库的 Debug 和 Release 版本。
通常,第三方包文档会指出在对库成功执行 find_package 后可用的导入目标的名称。这些导入的目标器名称可以被 target_link_libraries 命令使用。
简单使用第三方库的完整示例如下:
cmake_minimum_required(VERSION 3.10)
project(MyExeProject VERSION 1.0.0)
find_package(SomePackage REQUIRED)
add_executable(MyExe main.cpp)
target_link_libraries(MyExe PRIVATE SomePrefix::LibName)
有关开发 CMake 构建系统的更多信息,请参见 CMake 构建系统 。
19.3.1 不提供配置文件包的库
如果 FindSomePackage.cmake 文件可用,则不提供配置文件包的第三方库仍然可以使用 find_package 命令找到。
这些模块文件包与配置文件包的不同之处在于:
- 它们不应该由第三方提供,除非可能以文档的形式提供。
- Find<PackageName>.cmake 文件的可用性并不代表二进制文件本身的可用性。
- CMake 不搜索 CMAKE_PREFIX_PATH 来查找 Find<PackageName>.cmake 文件。相反, CMake 在 CMAKE_MODULE_PATH 变量中搜索这些文件。用户通常在运行 CMake 时设置 CMAKE_MODULE_PATH ,并且 CMake 项目通常会附加到 CMAKE_MODULE_PATH 以允许使用本地模块文件包。
- 在第三方没有直接提供配置文件包的情况下,为了方便, CMake 为一些第三方包提供了 Find<PackageName>.cmake 文件。这些文件是 CMake 的维护负担,所以新的 Find 模块通常不会再添加到 CMake 中。第三方应该提供配置文件包,而不是依赖于 CMake 提供的查找模块。
模块文件包也可以提供导入的目标。找到这样一个包的完整示例如下:
cmake_minimum_required(VERSION 3.10)
project(MyExeProject VERSION 1.0.0)
find_package(PNG REQUIRED)
# 向 FindSomePackage.cmake 文件添加路径
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(SomePackage REQUIRED)
add_executable(MyExe main.cpp)
target_link_libraries(MyExe PRIVATE
PNG::PNG
SomePrefix::LibName
)
<PackageName>_ROOT 变量也作为使用模块文件包(如 FindSomePackage )的 find_package 的调用的前缀进行搜索。