CMakePackageConfigHelpers¶
该模块提供了用于创建 配置文件 (config files) 的辅助命令,其他项目可以包含这些文件以查找并使用该软件包。
在 CMake 项目中加载此模块,使用
include(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>] )
configure_package_config_file() 应该用来代替普通的 configure_file() 命令,用于在安装项目或库时创建 <PackageName>Config.cmake 或 <PackageName>-config.cmake 文件。它通过避免在已安装的 <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 文件具有可重定位性。用法:
像往常一样编写一个
FooConfig.cmake.in文件。在文件顶部插入一行,仅包含字符串
@PACKAGE_INIT@。使用
set(FOO_DIR "@PACKAGE_SOME_INSTALL_DIR@")代替set(FOO_DIR "@SOME_INSTALL_DIR@")(此行必须位于@PACKAGE_INIT@之后)。使用
configure_package_config_file()代替普通的configure_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] )
将文件写入 <filename>,用作 <PackageName>ConfigVersion.cmake 文件。有关此类文件的详细信息,请参阅 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 新增:由 COMPATIBILITY 的 AnyNewerVersion、SameMajorVersion 和 SameMinorVersion 参数生成的版本文件会处理版本范围(如果指定了版本范围,请参阅 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)