第十一讲 添加导出配置
在前面几讲中,我们介绍过如何为CMake添加安装库文件和头文件的能力;也介绍过如何添加额外信息,以便发布软件包的内容。
接下来这一讲,我们将在工程中添加一些必要信息,以便其它CMake工程可以利用我们的工程,这可以是从build目录中引引用,也可以本地安装,甚至是软件打包。
首先,修改 install(TARGETS) 命令,让它不仅指定DESTINATION
,还指定EXPORT。关键字EXPORT
生成一个CMake文件,其中包含从安装树导出安装命令目标的相关代码。让我们继续,修改MathFunctions/CMakeLists.txt里的install命令,显式地EXPORT
MathFunctions
库。修改后的代码:
set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)
list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs}
EXPORT MathFunctionsTargets
DESTINATION lib)
# install include headers
install(FILES MathFunctions.h DESTINATION include)
现在,我们已经导出MathFunctions
,我们还需要明确安装所生成的MathFunctionsTargets.cmake
文件。它是这样实现的:在顶层CMakeLists.txt的末尾添加以下代码:
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
这时,你可以尝试执行一下CMake。如果一切正常,你将看到CMake的报错:
CMake想要表达的是:在生成导出信息时,它将导出一个与当前机器绑定的路径,把它用在其它机器上可能是无效的。解决方案是修改MathFunctions
的target_include_directories() ,让它理解:从build工作目录出发,和从安装包出发,它需要不同的INTERFACE位置。这意味着为MathFunctions
转换 target_include_directories() 调用:
MathFunctions/CMakeLists.txt
target_include_directories(MathFunctions
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
修改完毕之后,可以重试CMake,这时警告信息已经消除。
这时,我们的CMake已经能正确打包所要求的目标信息,但是还不够,我们还要生成一个MathFunctionsConfig.cmake
文件,这样 CMake的 find_package() 命令才能发现我们的工程。让我们继续,在工程顶层目录下新增一个名为Config.cmake.in的文件,其内容如下:
Config.cmake.in
@PACKAGE_INIT@
include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
接下来,配置及安装这个文件,在顶层目录的 CMakeLists.txt末尾添加以下内容:
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
include(CMakePackageConfigHelpers)
接下来,执行 configure_package_config_file()。这条命令将配置一个预置的文件,但它与标准的 configure_file() 用法有点差异。要正确应用这一特性,除了所需要的内容之外,输入文件里应当有这样的一个独立行,其内容为: @PACKAGE_INIT@ 。这个变量将被替换为一个代码块,其功能是转换一系列的路径值。这些值的引用名字相同,但是带有
PACKAGE_前缀。
CMakeLists.txt
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
include(CMakePackageConfigHelpers)
# generate the config file that includes the exports
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
INSTALL_DESTINATION "lib/cmake/example"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
下一个命令是write_basic_package_version_file() 。这条令命令会写一个文件,用于find_package()命令,记录软件包的版本及兼容性信息。这里,我们用Tutorial_VERSION_*
变量,说明它与AnyNewerVersion兼容,这表示高于此版本的所有版本都与请求的版本兼容。
CMakeLists.txt
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
COMPATIBILITY AnyNewerVersion
)
最后,生成的文件也是要安装的:
CMakeLists.txt
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
DESTINATION lib/cmake/MathFunctions
)
至此,我们已经为工程生成一个可重定位的CMake配置,在工程安装或打包发布之后,都是可用的。如果我们想让工程在build目录下同样可用,仅需要在顶层CMakeLists.txt文件的末尾添加以下内容:
CMakeLists.txt
export(EXPORT MathFunctionsTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)
通过export调用,将会生成一个MathFunctionsTargets.cmake,它允许其它工程直接使用
build目录下的MathFunctionsConfig.cmake,而无需事先安装库。