CMakePackageConfigHelpers

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

生成软件包配置文件

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() 命令。它通过避免在已安装的 <PackageName>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@" )

上面显示的所有四个选项都不够充分。前三个硬编码了绝对目录位置。第四种情况仅在确定 installedPrefix 的逻辑正确,并且 CONFIG_INSTALL_DIR 包含相对路径时才有效,而这通常无法保证。这导致生成的 FooConfig.cmake 文件在 Windows 和 macOS 下表现不佳,在这些系统中,用户习惯于在安装时选择二进制软件包的安装位置,而这与构建/cmake 时设置的 CMAKE_INSTALL_PREFIX 无关。

使用 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.30 版本新增: 变量 PACKAGE_PREFIX_DIR 将始终在 @PACKAGE_INIT@ 行之后定义。它将保存基本安装位置的值。通常,应该使用通过 PATH_VARS 机制定义的变量,但 PACKAGE_PREFIX_DIR 可用于那些不容易被 PATH_VARS 处理的情况,例如直接安装到基本安装位置而不是其子目录的文件。

注意

当生成的文件的使用者使用 CMake 3.29 或更旧版本时,PACKAGE_PREFIX_DIR 的值可以通过调用 find_dependency()find_package() 来更改。如果项目依赖于 PACKAGE_PREFIX_DIR,则项目有责任确保 PACKAGE_PREFIX_DIR 的值在任何此类调用或任何可能包含由 configure_package_config_file() 生成的另一个文件的调用中保持不变。

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

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

set_and_check() 应该用于代替普通的 set() 命令来设置目录和文件位置。除了设置变量外,它还会检查引用的文件或目录是否实际存在,如果不存在,则会发生致命错误。这确保了生成的 FooConfig.cmake 文件不包含错误的引用。添加 NO_SET_AND_CHECK_MACRO 选项以阻止在 FooConfig.cmake 文件中生成 set_and_check() 宏。

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

另请参阅 生成软件包文件示例

生成软件包版本文件

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 兼容。此模式适用于没有兼容性保证的软件包。如果您的项目具有更精细的版本匹配规则,则需要编写自己的自定义 <PackageName>ConfigVersion.cmake 文件,而不是使用此宏。

3.11 版本新增: SameMinorVersion 兼容性模式。

3.14 版本新增: 如果给定 ARCH_INDEPENDENT,则即使安装的软件包版本是为与请求的体系结构不同的体系结构构建的,也会被视为兼容。否则,将执行体系结构检查,并且仅当体系结构完全匹配时,软件包才被视为兼容。例如,如果软件包是为 32 位体系结构构建的,则仅当在 32 位体系结构上使用时,该软件包才被视为兼容,除非给定 ARCH_INDEPENDENT,在这种情况下,该软件包在任何体系结构上都被视为兼容。

注意

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

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

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

生成 Apple 平台选择文件

generate_apple_platform_selection_file

3.29 版本新增。

创建 Apple 平台选择文件

generate_apple_platform_selection_file(<filename>
  INSTALL_DESTINATION <path>
  [INSTALL_PREFIX <path>]
  [MACOS_INCLUDE_FILE <file>]
  [IOS_INCLUDE_FILE <file>]
  [IOS_SIMULATOR_INCLUDE_FILE <file>]
  [IOS_CATALYST_INCLUDE_FILE <file>]
  [TVOS_INCLUDE_FILE <file>]
  [TVOS_SIMULATOR_INCLUDE_FILE <file>]
  [WATCHOS_INCLUDE_FILE <file>]
  [WATCHOS_SIMULATOR_INCLUDE_FILE <file>]
  [VISIONOS_INCLUDE_FILE <file>]
  [VISIONOS_SIMULATOR_INCLUDE_FILE <file>]
  [ERROR_VARIABLE <variable>]
  )

写入一个包含 Apple 平台特定的 .cmake 文件,例如用作 <PackageName>Config.cmake 的文件。这可以与 export(SETUP)XCFRAMEWORK_LOCATION 参数结合使用,以导出软件包,以便为任何 Apple 平台构建的项目都可以使用它们。

INSTALL_DESTINATION <path>

调用者将生成的文件安装到的路径,例如通过 install(FILES)。路径可以是相对于 INSTALL_PREFIX 的相对路径,也可以是绝对路径。

INSTALL_PREFIX <path>

调用者将软件包安装到的路径前缀。<path> 参数必须是绝对路径。如果未传递此参数,则将使用 CMAKE_INSTALL_PREFIX 变量。

MACOS_INCLUDE_FILE <file>

如果平台是 macOS,则包含的文件。

IOS_INCLUDE_FILE <file>

如果平台是 iOS,则包含的文件。

IOS_SIMULATOR_INCLUDE_FILE <file>

如果平台是 iOS 模拟器,则包含的文件。

IOS_CATALYST_INCLUDE_FILE <file>

3.31 版本新增。

如果平台是 iOS Catalyst,则包含的文件。

TVOS_INCLUDE_FILE <file>

如果平台是 tvOS,则包含的文件。

TVOS_SIMULATOR_INCLUDE_FILE <file>

如果平台是 tvOS 模拟器,则包含的文件。

WATCHOS_INCLUDE_FILE <file>

如果平台是 watchOS,则包含的文件。

WATCHOS_SIMULATOR_INCLUDE_FILE <file>

如果平台是 watchOS 模拟器,则包含的文件。

VISIONOS_INCLUDE_FILE <file>

如果平台是 visionOS,则包含的文件。

VISIONOS_SIMULATOR_INCLUDE_FILE <file>

如果平台是 visionOS 模拟器,则包含的文件。

ERROR_VARIABLE <variable>

如果使用项目是为不受支持的平台构建的,则将 <variable> 设置为错误消息。包含器可以使用此信息来假装未找到软件包。如果未提供此选项,则默认行为是发出致命错误。

如果未指定任何可选的包含文件,并且使用项目是为其相应的平台构建的,则生成的文件将认为该平台不受支持。行为由 ERROR_VARIABLE 选项确定。

生成 Apple 体系结构选择文件

generate_apple_architecture_selection_file

3.29 版本新增。

创建 Apple 体系结构选择文件

generate_apple_architecture_selection_file(<filename>
  INSTALL_DESTINATION <path>
  [INSTALL_PREFIX <path>]
  [SINGLE_ARCHITECTURES <arch>...
   SINGLE_ARCHITECTURE_INCLUDE_FILES <file>...]
  [UNIVERSAL_ARCHITECTURES <arch>...
   UNIVERSAL_INCLUDE_FILE <file>]
  [ERROR_VARIABLE <variable>]
  )

写入一个基于 CMAKE_OSX_ARCHITECTURES 包含 Apple 体系结构特定的 .cmake 文件,例如,从 Apple 特定的 <PackageName>Config.cmake 文件中包含。

INSTALL_DESTINATION <path>

调用者将生成的文件安装到的路径,例如通过 install(FILES)。路径可以是相对于 INSTALL_PREFIX 的相对路径,也可以是绝对路径。

INSTALL_PREFIX <path>

调用者将软件包安装到的路径前缀。<path> 参数必须是绝对路径。如果未传递此参数,则将使用 CMAKE_INSTALL_PREFIX 变量。

SINGLE_ARCHITECTURES <arch>...

SINGLE_ARCHITECTURE_INCLUDE_FILES 条目提供的体系结构。

SINGLE_ARCHITECTURE_INCLUDE_FILES <file>...

体系结构特定的文件。当 CMAKE_OSX_ARCHITECTURES 包含与 SINGLE_ARCHITECTURES 的相应条目匹配的单个体系结构时,将加载其中一个文件。

UNIVERSAL_ARCHITECTURES <arch>...

UNIVERSAL_INCLUDE_FILE 提供的体系结构。

列表可以包含 $(ARCHS_STANDARD) 以支持使用 Xcode 生成器进行消费,但体系结构也应始终单独列出。

UNIVERSAL_INCLUDE_FILE <file>

CMAKE_OSX_ARCHITECTURES 包含 UNIVERSAL_ARCHITECTURES 的(非严格)子集,并且与 SINGLE_ARCHITECTURES 中的任何一个都不匹配时,要加载的文件。

ERROR_VARIABLE <variable>

如果使用项目是为不受支持的体系结构构建的,则将 <variable> 设置为错误消息。包含器可以使用此信息来假装未找到软件包。如果未提供此选项,则默认行为是发出致命错误。

生成软件包文件示例

使用 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)