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
2
3
4
5
add_executable(myexe IMPORTED)
set_property(TARGET myexe PROPERTY
IMPORTED_LOCATION "../InstallMyExe/bin/myexe")
add_custom_command(OUTPUT main.cc COMMAND myexe)
add_executable(mynewexe main.cc)
STYLUS
  1. 创建一个IMPORTED target
  2. 设置target相关属性,这里指定其关联的可执行文件路径
  3. 添加了一个custom command, 用target myexe指定的可执行文件来生成文件main.cc
  4. 创建一个正常的可执行target, 使用上一步生成的main.cc作为源文件

Importing Libraries

导入已经构建好的库作为一个target来使用。

1
2
3
4
5
add_library(foo STATIC IMPORTED)
set_property(TARGET foo PROPERTY
IMPORTED_LOCATION "/path/to/libfoo.a")
add_executable(myexe src1.c src2.c)
target_link_libraries(myexe PRIVATE foo)
STYLUS
  1. 创建一个IMPORTED target
  2. 设置target相关属性,这里指定其关联的静态库路径
  3. 创建一个正常的可执行target myexe,链接上面创建的target foo

考虑到可能会有debug,release 等不同配置,引入具有不同配置的同一个库,可以使用下面的形式

1
2
3
4
5
6
7
8
9
10
find_library(math_REL NAMES m)
find_library(math_DBG NAMES md)
add_library(math STATIC IMPORTED GLOBAL)
set_target_properties(math PROPERTIES
IMPORTED_LOCATION "${math_REL}"
IMPORTED_LOCATION_DEBUG "${math_DBG}"
IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
)
add_executable(myexe src1.c src2.c)
target_link_libraries(myexe PRIVATE math)
STYLUS

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.

  1. IMPORTED targets 要求使用这些target的工程,知道相关文件在磁盘上的位置。
  2. 要想屏蔽这些细节,库的提供方,同时提供一个导入这个库的帮助文件 xxxTargets.cmake
  3. 要想生成的库,可以通过find_package()命令来索引使用的话,可以在cmake工程中配置,在构建工程的时候,同时生成对应的帮助文件
    • xxxTargets.cmake
    • xxxConfig.cmake
    • xxxConfigVersion.cmake

xxxTargets.cmake

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
cmake_minimum_required(VERSION 3.15)
project(MathFunctions)

# make cache variables for install destinations
include(GNUInstallDirs)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# create library
add_library(MathFunctions STATIC MathFunctions.cxx)

# add include directories
target_include_directories(MathFunctions
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)

# install the target and create export-set
install(TARGETS MathFunctions
EXPORT MathFunctionsTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

# install header file
install(FILES MathFunctions.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

# generate and install export file
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
NAMESPACE MathFunctions::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)
# create IMPORTED target, set target property
add_library(MathFunctions::MathFunctions STATIC IMPORTED)
set_target_properties(MathFunctions::MathFunctions PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
)
CMAKE
  1. 创建一个正常的静态库
  2. 设置静态库头文件搜索路径,分别指定构建时和安装后的路径
  3. 创建一个install命令,指定生成二进制文件的安装路径。其中EXPORT MathFunctionsTargets,指定了导出target文件对应的文件名字是MathFunctionsTargets.cmake
  4. 指定头文件如何安装
  5. 指定MathFunctionsTargets.cmake文件如何安装,NAMESPACE MathFunctions:: 给导出的target添加前缀命名空间,一般带有命名空间的target,都是IMPORTED target
  6. 创建一个IMPORTED target,名字是MathFunctions::MathFunctions
  7. 设置MathFunctions::MathFunctions的属性,此处是头文件路径

如何使用导出的target文件, 在CMakeLists.txt文件中

1
2
3
include(${INSTALL_PREFIX}/lib/cmake/MathFunctionTargets.cmake)
add_executable(myexe src1.c src2.c )
target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions)
STYLUS
  1. 首先包含/MathFunctionTargets.cmake文件
  2. 创建一个可执行目标myexe
  3. 链接MathFunctions::MathFunctions到myexe

支持find_package()

使用示例:

1
2
find_package(Stats 2.6.4 REQUIRED)
target_link_libraries(MathFunctions PUBLIC Stats::Types)
STYLUS

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

因此,cmake构建的库,想要支持find_package()的config模式,需要提供

  • xxxConfig.cmake
  • xxConfigVersion.cmake

首先包含CMakePackageConfigHelpers模块

1
include(CMakePackageConfigHelpers)
STYLUS

Creating a Package Configuration File

使用CMakePackageConfigHelpers模块中的configure_package_config_file命令来生成MathFunctionsConfig.cmake文件,蓝本是Config.cmake.in,同时指定生成后的路径。

1
2
3
4
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)
BASH

通过isntall命令指定xxxConfig.cmakexxxConfigVersion.cmake文件安装规则

1
2
3
4
5
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)
BASH

关于Config.cmake.in文件

1
2
3
4
5
@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake")

check_required_components(MathFunctions)
STYLUS

@PACKAGE_INIT@ 在配置的时候,会被替换和展开,展开后包含

  1. PACKAGE_为前缀的相对路径
  2. 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
set(version 3.4.1)

set_property(TARGET MathFunctions PROPERTY VERSION ${version})
set_property(TARGET MathFunctions PROPERTY SOVERSION 3)
set_property(TARGET MathFunctions PROPERTY
INTERFACE_MathFunctions_MAJOR_VERSION 3)
set_property(TARGET MathFunctions APPEND PROPERTY
COMPATIBLE_INTERFACE_STRING MathFunctions_MAJOR_VERSION
)

# generate the version file for the config file
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
VERSION "${version}"
COMPATIBILITY AnyNewerVersion
)
CRMSH
  1. 设置target的版本号相关的变量
  2. 将版本号信息,写入MathFunctionsConfigVersion.cmake文件

此时已经配置好如何生成xxxConfig.cmakexxxConfigVersion.cmake文件.
执行构建,安装

1
2
3
4
5
mkdir build 
cd build
cmake ..
cmake --build .
cmake --install . --prefix `<prefix>`
JBOSS-CLI

观察输出, 对应的文件已经生成

1
2
3
4
MathFunctionsConfig.cmake
MathFunctionsConfigVersion.cmake
MathFunctionsTargets-noconfig.cmake
MathFunctionsTargets.cmake
STYLUS

使用find_package()来使用生成config文件, 此时需要通过CMAKE_PREFIX_PATH来指定config文件的搜罗路径。

1
2
3
4
5
6
7
8
9
10
11
cmake_minimum_required(VERSION 3.15)
project(Downstream)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

find_package(MathFunctions 3.4.1 EXACT)

add_executable(myexe main.cc)
target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions)
SCSS

注意:
导出配置,不应该引用绝对路径,应当关联相对路径,这样,无论安装在哪里,都可以通过config文件正确索引到库。

  1. 不应当显示的依赖CMAKE_INSTALL_PREFIX
1
2
3
4
5
6
7
8
9
target_include_directories(tgt INTERFACE
# Wrong, not relocatable:
$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/TgtName>
)

target_include_directories(tgt INTERFACE
# Ok, relocatable:
$<INSTALL_INTERFACE:include/TgtName>
)
RUBY
  1. 可以使用$<INSTALL_PREFIX> generator expression
1
2
3
4
target_include_directories(tgt INTERFACE
# Ok, relocatable:
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/TgtName>
)
CRYSTAL

cmake Importing and Exporting Guide
https://yxibng.github.io/2022/10/24/cmake/2022-10-24-cmake Importing and Exporting Guide/
作者
yxibng
发布于
2022年10月24日
许可协议