cmake Importing and Exporting Guide
参考:https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html
Importing
IMPORTED targets 将cmake工程外部的库,可执行文件引入到当前的cmake工程中,被引入的内容会关联到一个cmake 中一个
逻辑上的target。
创建方式,调用add_executable(),add_library()命令创建target, 但是要添加IMPORTED参数。
这个IMPORTED target不产生任何构建文件,因为他们引入的都是现成的库或者可执行文件。
一旦IMPORTED target 被创建好了,就可以像工程中的其他target一样被引用了。 通过这种方式,就可以方便,灵活引用外部可执行文件和库了。
Importing Executables
使用磁盘上的可执行文件。
1 | add_executable(myexe IMPORTED) |
- 创建一个IMPORTED target
- 设置target相关属性,这里指定其关联的可执行文件路径
- 添加了一个custom command, 用target myexe指定的可执行文件来生成文件
main.cc - 创建一个正常的可执行target, 使用上一步生成的
main.cc作为源文件
Importing Libraries
导入已经构建好的库作为一个target来使用。
1 | add_library(foo STATIC IMPORTED) |
- 创建一个IMPORTED target
- 设置target相关属性,这里指定其关联的静态库路径
- 创建一个正常的可执行target myexe,链接上面创建的target foo
考虑到可能会有debug,release 等不同配置,引入具有不同配置的同一个库,可以使用下面的形式
1 | find_library(math_REL NAMES m) |
Exporting Targets
While IMPORTED targets on their own are useful, they still require that the project that imports them knows the locations of the target files on disk. The real power of IMPORTED targets is when the project providing the target files also provides a CMake file to help import them. A project can be setup to produce the necessary information so that it can easily be used by other CMake projects be it from a build directory, a local install or when packaged.
- IMPORTED targets 要求使用这些target的工程,知道相关文件在磁盘上的位置。
- 要想屏蔽这些细节,库的提供方,同时提供一个导入这个库的帮助文件
xxxTargets.cmake - 要想生成的库,可以通过
find_package()命令来索引使用的话,可以在cmake工程中配置,在构建工程的时候,同时生成对应的帮助文件xxxTargets.cmakexxxConfig.cmakexxxConfigVersion.cmake
xxxTargets.cmake
1 | cmake_minimum_required(VERSION 3.15) |
- 创建一个正常的静态库
- 设置静态库头文件搜索路径,分别指定构建时和安装后的路径
- 创建一个install命令,指定生成二进制文件的安装路径。其中
EXPORT MathFunctionsTargets,指定了导出target文件对应的文件名字是MathFunctionsTargets.cmake - 指定头文件如何安装
- 指定
MathFunctionsTargets.cmake文件如何安装,NAMESPACE MathFunctions::给导出的target添加前缀命名空间,一般带有命名空间的target,都是IMPORTED target - 创建一个
IMPORTED target,名字是MathFunctions::MathFunctions - 设置
MathFunctions::MathFunctions的属性,此处是头文件路径
如何使用导出的target文件, 在CMakeLists.txt文件中
1 | include(${INSTALL_PREFIX}/lib/cmake/MathFunctionTargets.cmake) |
- 首先包含
/MathFunctionTargets.cmake文件 - 创建一个可执行目标myexe
- 链接MathFunctions::MathFunctions到myexe
支持find_package()
使用示例:
1 | find_package(Stats 2.6.4 REQUIRED) |
find_package() 支持两种搜索模式
- module mode, 针对非cmake构建的库,搜索
Find<PackageName>.cmake文件 - config mode, 针对cmake构建的库,相关文件为
- target相关:
<lowercasePackageName>-config.cmake或者<PackageName>Config.cmake - 版本相关:
<lowercasePackageName>-config-version.cmake或<PackageName>ConfigVersion.cmake
- target相关:
因此,cmake构建的库,想要支持find_package()的config模式,需要提供
xxxConfig.cmakexxConfigVersion.cmake
首先包含CMakePackageConfigHelpers模块
1 | include(CMakePackageConfigHelpers) |
Creating a Package Configuration File
使用CMakePackageConfigHelpers模块中的configure_package_config_file命令来生成MathFunctionsConfig.cmake文件,蓝本是Config.cmake.in,同时指定生成后的路径。
1 | configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in |
通过isntall命令指定xxxConfig.cmake和xxxConfigVersion.cmake文件安装规则
1 | install(FILES |
关于Config.cmake.in文件
1 | @PACKAGE_INIT@ |
@PACKAGE_INIT@ 在配置的时候,会被替换和展开,展开后包含
- 以
PACKAGE_为前缀的相对路径 set_and_check()和heck_required_components()两个宏定义。
check_required_components 针对所有的组件,给<Package>_<Component>_FOUND变量赋值, 找到为TRUE,找不到为FALSE。 同时给<Package>_FOUND变量赋值, 如果结果为FALSE,认为该package没有找到。
set_and_check主要给对应的目录和文件路径赋值,如果引用的文件或路径没有找到,该宏执行失败。
Creating a Package Version File
CMakePackageConfigHelpers模块,提供了write_basic_package_version_file()命令来生成xxConfigVersion.cmake文件。 当find_package()命令指定了版本号的时候, cmake 会读取该文件来获取版本号信息做匹配
1 | set(version 3.4.1) |
- 设置target的版本号相关的变量
- 将版本号信息,写入
MathFunctionsConfigVersion.cmake文件
此时已经配置好如何生成xxxConfig.cmake和xxxConfigVersion.cmake文件.
执行构建,安装
1 | mkdir build |
观察输出, 对应的文件已经生成
1 | MathFunctionsConfig.cmake |
使用find_package()来使用生成config文件, 此时需要通过CMAKE_PREFIX_PATH来指定config文件的搜罗路径。
1 | cmake_minimum_required(VERSION 3.15) |
注意:
导出配置,不应该引用绝对路径,应当关联相对路径,这样,无论安装在哪里,都可以通过config文件正确索引到库。
- 不应当显示的依赖
CMAKE_INSTALL_PREFIX
1 | target_include_directories(tgt INTERFACE |
- 可以使用
$<INSTALL_PREFIX> generator expression
1 | target_include_directories(tgt INTERFACE |
