CMakePackageConfigHelpers

用于创建可以被其他项目包含以查找和使用包的配置文件的帮助函数。

添加 configure_package_config_file()write_basic_package_version_file() 命令。

生成包配置文件

configure_package_config_file

为项目创建配置文件

configure_package_config_file(<input> <output>
  INSTALL_DESTINATION <path>
  [PATH_VARS <var1> <var2> ... <varN>]
  [NO_SET_AND_CHECK_MACRO]
  [NO_CHECK_REQUIRED_COMPONENTS_MACRO]
  [INSTALL_PREFIX <path>]
  )

在创建 <PackageName>Config.cmake<PackageName>-config.cmake 文件时,应该使用 configure_package_config_file() 而不是普通的 configure_file() 命令安装项目或库。它通过避免在已安装的 Config.cmake 文件中使用硬编码路径,帮助使生成的包可重定位。

在``FooConfig.cmake`` 文件中可能有这样的代码来让使用的项目知道安装目的地:

set(FOO_INCLUDE_DIR   "@CMAKE_INSTALL_FULL_INCLUDEDIR@" )
set(FOO_DATA_DIR   "@CMAKE_INSTALL_PREFIX@/@RELATIVE_DATA_INSTALL_DIR@" )
set(FOO_ICONS_DIR   "@CMAKE_INSTALL_PREFIX@/share/icons" )
#...logic to determine installedPrefix from the own location...
set(FOO_CONFIG_DIR  "${installedPrefix}/@CONFIG_INSTALL_DIR@" )

上面显示的所有 4 个选项都不够,因为前 3 个硬编码绝对目录位置,而第 4 种情况仅在确定 installedPrefix 的逻辑正确且 CONFIG_INSTALL_DIR 包含相对路径时才有效,这通常无法保证。这会导致生成的 FooConfig.cmake 文件在 Windows 和 OSX 下运行不佳,其中用户习惯于在安装时选择二进制包的安装位置,与 CMAKE_INSTALL_PREFIX 的方式无关在构建/cmake 时设置。

使用 configure_package_config_file 有帮助。如果使用正确,它会使生成的“FooConfig.cmake”文件可重定位。用法:

  1. 像你习惯的那样写一个``FooConfig.cmake.in``文件

  2. 插入一行只包含字符串``@PACKAGE_INIT@``

  3. 而不是``set(FOO_DIR "@SOME_INSTALL_DIR@")``,使用``set(FOO_DIR "@PACKAGE_SOME_INSTALL_DIR@")``(这必须在``@PACKAGE_INIT@``行之后)

  4. 而不是使用正常的 configure_file()(),使用``configure_package_config_file()``

<input><output> 参数是输入和输出文件,与 configure_file() 中的方式相同。

INSTALL_DESTINATION<path> 必须是 FooConfig.cmake 文件将被安装到的目的地。此路径可以是绝对路径,也可以是相对于“INSTALL_PREFIX”路径的相对路径。

作为 PATH_VARS 给出的变量 <var1><varN> 是包含安装目的地的变量。对于它们中的每一个,宏都会创建一个辅助变量``PACKAGE_<var...>``。这些辅助变量必须在 FooConfig.cmake.in 文件中使用以设置安装位置。它们由 configure_package_config_file 计算,因此它们始终与包的安装位置相关。这既适用于相对位置,也适用于绝对位置。对于绝对位置,它仅在绝对位置是 INSTALL_PREFIX 的子目录时才有效。

在 3.1 版本加入: 如果传递了 INSTALL_PREFIX 参数,这将用作计算所有相对路径的基本路径。 <path> 参数必须是绝对路径。如果未传递此参数,则将使用 CMAKE_INSTALL_PREFIX 变量。生成 FooConfig.cmake 文件以使用安装树中的包时,默认值很好。当生成 FooConfig.cmake 文件以使用构建树中的包时,应使用此选项。

默认情况下,configure_package_config_file 还会在``FooConfig.cmake`` 文件中生成两个辅助宏,set_and_check() 和``check_required_components()``。

set_and_check() 应该用来代替普通的 set() 命令来设置目录和文件位置。除了设置变量之外,它还会检查引用的文件或目录是否实际存在,否则会失败并返回“致命错误”。这确保创建的“FooConfig.cmake”文件不包含错误的引用。使用 NO_SET_AND_CHECK_MACRO 时,该宏不会生成到 FooConfig.cmake 文件中。

check_required_components(<PackageName>) 应该在 FooConfig.cmake 文件的末尾调用。此宏检查是否已找到所有请求的非可选组件,如果未找到,则将“Foo_FOUND”变量设置为“FALSE”,以便认为未找到包。它通过测试所有请求的必需组件的 Foo_<Component>_FOUND 变量来做到这一点。即使包没有提供任何组件,也应该调用这个宏以确保用户没有错误地指定组件。使用 NO_CHECK_REQUIRED_COMPONENTS_MACRO 选项时,该宏不会生成到 FooConfig.cmake 文件中。

有关示例,请参见下面的 write_basic_package_version_file() 文档。

生成包版本文件

write_basic_package_version_file

为项目创建版本文件

write_basic_package_version_file(<filename>
  [VERSION <major.minor.patch>]
  COMPATIBILITY <AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion>
  [ARCH_INDEPENDENT] )

将用作 <PackageName>ConfigVersion.cmake 文件的文件写入 <filename>。有关详细信息,请参阅 find_package() 的文档。

<filename> 是输出文件名,它应该在构建树中。 <major.minor.patch> 是要安装的项目的版本号。

如果未给出 VERSION,则使用 PROJECT_VERSION 变量。如果尚未设置,则会出错。

COMPATIBILITY 模式 AnyNewerVersion 意味着安装的包版本将被认为是兼容的,如果它更新或与请求的版本完全相同。这种模式应用于完全向后兼容的包,也适用于主要版本。如果改为使用“SameMajorVersion”,则行为不同于“AnyNewerVersion”,因为主版本号必须与请求的相同,例如如果请求 1.0,则 2.0 版将被视为不兼容。此模式应用于保证在同一主要版本中向后兼容的包。如果使用“SameMinorVersion”,行为与“SameMajorVersion”相同,但主要版本和次要版本必须与请求的相同,例如,如果请求 0.1,则版本 0.2 将不兼容。如果使用“ExactVersion”,则仅当请求的版本与它自己的版本号完全匹配时才认为该包兼容(不考虑调整版本)。例如,包的 1.2.3 版仅被认为与请求的 1.2.3 版兼容。此模式适用于没有兼容性保证的包。如果您的项目有更详细的版本匹配规则,您将需要编写自己的自定义 ConfigVersion.cmake 文件,而不是使用此宏。

在 3.11 版本加入: SameMinorVersion 兼容模式。

在 3.14 版本加入: 如果给出 ARCH_INDEPENDENT,安装的包版本将被认为是兼容的,即使它是为与请求的体系结构不同的体系结构构建的。否则,将执行体系结构检查,只有在体系结构完全匹配时才会认为包兼容。例如,如果包是为 32 位架构构建的,则只有在 32 位架构上使用该包才被认为是兼容的,除非给出 ARCH_INDEPENDENT,在这种情况下,该包被认为是兼容的任何架构。

备注

ARCH_INDEPENDENT 适用于只有头文件的库或没有二进制文件的类似包。

在 3.19 版本加入: COMPATIBILITYAnyNewerVersionSameMajorVersionSameMinorVersion 参数生成的版本文件处理版本范围(如果指定)(有关详细信息,请参阅:command:find_package 命令) . ExactVersion 模式与版本范围不兼容,如果指定,将显示作者警告。

在内部,此宏执行 configure_file() 以创建生成的版本文件。根据 COMPATIBILITY,使用相应的``BasicConfigVersion-<COMPATIBILITY>.cmake.in`` 文件。请注意,这些文件是 CMake 的内部文件,您不应该自己调用 configure_file(),但它们可以用作创建更复杂的自定义 ConfigVersion.cmake 文件的起点。

示例生成包文件

同时使用 configure_package_config_file()write_basic_package_version_file() 的示例:

CMakeLists.txt

include(GNUInstallDirs)
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}/Foo
    CACHE PATH "Location of header files" )
set(SYSCONFIG_INSTALL_DIR ${CMAKE_INSTALL_SYSCONFDIR}/foo
    CACHE PATH "Location of configuration files" )
#...
include(CMakePackageConfigHelpers)
configure_package_config_file(FooConfig.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Foo
  PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR)
write_basic_package_version_file(
  ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
  VERSION 1.2.3
  COMPATIBILITY SameMajorVersion )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
              ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Foo )

FooConfig.cmake.in:

set(FOO_VERSION x.y.z)
...
@PACKAGE_INIT@
...
set_and_check(FOO_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(FOO_SYSCONFIG_DIR "@PACKAGE_SYSCONFIG_INSTALL_DIR@")

check_required_components(Foo)