CMake 学习笔记

CMake 学习笔记

本文学习路线取自https://github.com/ttroy50/cmake-examples

参考文章:https://blog.csdn.net/qq_38410730/article/details/102837401

https://blog.csdn.net/sinat_34109743/article/details/111832126?spm=1001.2014.3001.5502

一:什么是CMake

“Write once, run everywhere”

​ 在学习cmake之前我也很好奇什么是cmake。习惯性地看词只看半边,再加上对百科里注解的懵懂印象,我认为cmake是新一代的 C/C++ 的编译器,对标 gcc。在实际学习后我才明白 cmake 绝对不是取代 gcc 的新一代编译器套装,而是一个跨平台的安装(编译)工具。这里扒一段网上的解释:

CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CMakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。

​ 看完以后捕捉一下关键词:跨平台。cmake需要我们自己写一个能被 cmake 处理的与平台无关的 txt 文件 CMakeList.txt 来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。

二:CMake 平台搭建

​ 最近一直在用 mac,就简单记录一下 mac 上的搭建过程。

首先从 cmake 官网下载 cmake:https://cmake.org/download/

然后打开 cmake,选择上方菜单栏的工具(Tools)一栏,查看:How to Install For Command Line Use。一般来说它会给你三个方法,第一个方法是暂时性的,在关闭当前的 Terminal 后就失效了,下一次打开还需要重新键入。所以后两个命令选择其一使用,即可永久添加环境变量。

在命令执行成功后,在工具栏中键入:cmake --version

得到输出:

1
2
cmake version 3.25.0-rc2
CMake suite maintained and supported by Kitware (kitware.com/cmake).

即搭建完成。

三:cmake-examples 学习

学习链接:https://github.com/ttroy50/cmake-examples

CMakeList 编写

  • 默认已经安装了 Homebrew。用brew install tree命令安装 tree。通过 tree 命令可以显示目录结构。

CMakeList:
CMakeLists.txt 是应该存储所有 CMake 命令的文件。什么时候 cmake 在一个文件夹中运行,它会查找这个文件,如果它不存在,cmake 将退出并出现错误。

编写CMakeList.txt:

Minimum CMake version

​ 首先指定支持 cmake 的最低版本。

命令:cmake_minimum_required(VERSION #.#)

Projects

创建可执行文件。CMake build 可以包含一个项目名称以使引用某些使用多个项目时变量更容易。

命令:project (project_name)

Creating an Executable

+add_executable()+ 命令指定一个可执行文件应该是
从指定的源文件构建,在本例中为 main.cpp。
add_executable() 函数的第一个参数是要构建的可执行文件,也就是project,第二个参数是要编译的源文件列表。

命令:add_executable(project_name main.cpp)

所以最基本的CMakeList的写法就是:
cmake_minimum_required(VERSION 3.5)
project (hello_cmake)
add_executable(hello_cmake main.cpp)

在写好 CMakeList 后,建立一个新目录,然后进行编译:

1
2
3
mkdir build
cmake ..
make

如果要编译的源文件较多的话,可以使用set创建一个源变量,包含所需编译源文件的路径,如:

1
2
3
4
set(SOURCES
src/Hello.cpp
src/main.cpp
)

在最后add的时候只需要:add_executable(${PROJECT_NAME} ${SOURCES})即可。

Adding a Static Library

add_library() 函数用于从一些源文件创建库。参数为库名,属性(STATIC(静态库)/SHARED(动态库)/MODULE(模块库))还有所用到的源文件。

STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被动态链接,在运行时被加载。MODULE库是不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数动态链接。如果没有类型被显式指定,这个选项将会根据变量BUILD_SHARED_LIBS的当前值是否为真决定是STATIC还是SHARED。

大致用法为:

1
2
3
add_library(hello_library STATIC 
src/Hello.cpp
)

可以为给定library添加一个别名,后续可使用<name>来替代<target>

add_library(<name> ALIAS <target>)

这样就可以允许您在将目标链接到其他目标时使用别名来引用目标。

Including Directories

target_include_directories():指定目标包含的头文件路径,相当于是把需要使用到的所有库整合成一个库。

1
2
3
4
target_include_directories(hello_library
PUBLIC
${PROJECT_SOURCE_DIR}/include
)

在源代码中要引用这些库,应该建议使用当前根目录到库目录的路径。如:#include "static/Hello.h"

使用这种方法的话意味着头文件名冲突的可能性较小,这样就可以在项目中使用多个库。

这里的范围的含义是:

  • +PRIVATE+ - 目录被添加到这个目标的包含目录中
  • +INTERFACE+ - 该目录被添加到链接该库的任何目标的包含目录中。
  • +PUBLIC+ - 如上所述,它包含在此库中,也包含在链接此库的任何目标中。

Linking a Library

创建将使用目标库的可执行文件时,必须将库传达给编译器。这将使用 target_link_libraries() 函数来完成。如:

1
2
3
4
5
#此语句要写在add_executable之后
target_link_libraries( hello_binary
PRIVATE
hello_library
)

链接共享库与链接静态库相同。创建可执行文件使用 +target_link_library()+ 函数指向你的库

target_link_libraries(hello_binary
PRIVATE
hello::library #用alias替换过的库名
)

Installing

CMake 提供了添加“make install”目标的能力,以允许用户安装二进制文件、库和其他文件。如果不对 install 指令进行配置,那么系统会使用默认值进行安装。install用于指定在安装时运行的规则:

1
2
3
4
5
6
install(TARGETS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])

有时候,也会用到一个非常有用的变量CMAKE_INSTALL_PREFIX用于指定cmake install时的相对地址前缀。用法如:

1
cmake -DCMAKE_INSTALL_PREFIX=/usr ..

目标文件的安装:

1
2
3
4
5
6
7
8
9
10
11
12
13
install(TARGETS targets... [EXPORT <export-name>]
[[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[NAMELINK_COMPONENT <component>]
[OPTIONAL] [EXCLUDE_FROM_ALL]
[NAMELINK_ONLY|NAMELINK_SKIP]
] [...]
[INCLUDES DESTINATION [<dir> ...]]
)

参数中的TARGET可以是很多种目标文件,最常见的是通过ADD_EXECUTABLE或者ADD_LIBRARY定义的目标文件,即可执行二进制、动态库、静态库

目标文件 内容 安装目录变量 默认安装文件夹
ARCHIVE 静态库 ${CMAKE_INSTALL_LIBDIR} lib
LIBRARY 动态库 ${CMAKE_INSTALL_LIBDIR} lib
RUNTIME 可执行二进制文件 ${CMAKE_INSTALL_BINDIR} bin
PUBLIC_HEADER 与库关联的PUBLIC头文件 ${CMAKE_INSTALL_INCLUDEDIR} include
PRIVATE_HEADER 与库关联的PRIVATE头文件 ${CMAKE_INSTALL_INCLUDEDIR} include

为了符合一般的默认安装路径,如果设置了DESTINATION参数,推荐配置在安装目录变量下的文件夹。

例如:

1
2
3
4
5
INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR
)

上面的例子会将:可执行二进制myrun安装到${CMAKE_INSTALL_BINDIR}目录,动态库libmylib.so安装到${CMAKE_INSTALL_LIBDIR}目录,静态库libmystaticlib.a安装到${CMAKE_INSTALL_LIBDIR}目录。

该命令的其他一些参数的含义:

DESTINATION:指定磁盘上要安装文件的目录;
PERMISSIONS:指定安装文件的权限。有效权限是OWNER_READ,OWNER_WRITE,OWNER_EXECUTE,GROUP_READ,GROUP_WRITE,GROUP_EXECUTE,WORLD_READ,WORLD_WRITE,WORLD_EXECUTE,SETUID和SETGID;
CONFIGURATIONS:指定安装规则适用的构建配置列表(DEBUG或RELEASE等);
EXCLUDE_FROM_ALL:指定该文件从完整安装中排除,仅作为特定于组件的安装的一部分进行安装;
OPTIONAL:如果要安装的文件不存在,则指定不是错误。

CONFIGURATIONS参数,此选项指定的值仅适用于此选项之后列出的选项:例如,要为调试和发布配置设置单独的安装路径,请执行以下操作:

1
2
3
4
5
6
install(TARGETS target
CONFIGURATIONS Debug
RUNTIME DESTINATION Debug/bin)
install(TARGETS target
CONFIGURATIONS Release
RUNTIME DESTINATION Release/bin)

也就是说,DEBUG和RELEASE版本的DESTINATION安装路径不同,那么DESTINATION必须在CONFIGUATIONS后面。

普通文件的安装:

1
2
3
4
5
6
install(<FILES|PROGRAMS> files...
TYPE <type> | DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])

FILES|PROGRAMS若为相对路径给出的文件名,将相对于当前源目录进行解释。其中,FILES为普通的文本文件,PROGRAMS指的是非目标文件的可执行程序(如脚本文件)。

如果未提供PERMISSIONS参数,默认情况下,普通的文本文件将具有OWNER_WRITE,OWNER_READ,GROUP_READ和WORLD_READ权限,即644权限;而非目标文件的可执行程序将具有OWNER_EXECUTE, GROUP_EXECUTE,和WORLD_EXECUTE,即755权限。

其中,不同的TYPE,cmake也提供了默认的安装路径,如下表:

TYPE类型 安装目录变量 默认安装文件夹
BIN ${CMAKE_INSTALL_BINDIR} bin
SBIN ${CMAKE_INSTALL_SBINDIR} sbin
LIB ${CMAKE_INSTALL_LIBDIR} lib
INCLUDE ${CMAKE_INSTALL_INCLUDEDIR} include
SYSCONF ${CMAKE_INSTALL_SYSCONFDIR} etc
SHAREDSTATE ${CMAKE_INSTALL_SHARESTATEDIR} com
LOCALSTATE ${CMAKE_INSTALL_LOCALSTATEDIR} var
RUNSTATE ${CMAKE_INSTALL_RUNSTATEDIR} /run
DATA ${CMAKE_INSTALL_DATADIR}
INFO ${CMAKE_INSTALL_INFODIR} /info
LOCALE ${CMAKE_INSTALL_LOCALEDIR} /locale
MAN ${CMAKE_INSTALL_MANDIR} /man
DOC ${CMAKE_INSTALL_DOCDIR} /doc

某些类型的内置默认值使用DATAROOT目录作为前缀,以CMAKE_INSTALL_DATAROOTDIR变量值为内容。

该命令的其他一些参数的含义:

DESTINATION:指定磁盘上要安装文件的目录;
PERMISSIONS:指定安装文件的权限。有效权限是OWNER_READ,OWNER_WRITE,OWNER_EXECUTE,GROUP_READ,GROUP_WRITE,GROUP_EXECUTE,WORLD_READ,WORLD_WRITE,WORLD_EXECUTE,SETUID和SETGID;
CONFIGURATIONS:指定安装规则适用的构建配置列表(DEBUG或RELEASE等);
EXCLUDE_FROM_ALL:指定该文件从完整安装中排除,仅作为特定于组件的安装的一部分进行安装;
OPTIONAL:如果要安装的文件不存在,则指定不是错误;
RENAME:指定已安装文件的名称,该名称可能与原始文件不同。仅当命令安装了单个文件时,才允许重命名。

目录的安装:

1
2
3
4
5
6
7
8
9
10
install(DIRECTORY dirs...
TYPE <type> | DESTINATION <dir>
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] [EXCLUDE_FROM_ALL]
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]] [...])

​ 命令将一个或多个目录的内容安装到给定的目的地,目录结构被逐个复制到目标位置。每个目录名称的最后一个组成部分都附加到目标目录中,但是可以使用后跟斜杠来避免这种情况,因为它将最后一个组成部分留空。比如,DIRECTORY后面如果是abc意味着abc这个目录会安装在目标路径下,abc/意味着abc这个目录的内容会被安装在目标路径下,而abc目录本身却不会被安装。即,如果目录名不以/结尾,那么这个目录将被安装为目标路径下的abc,如果目录名以/结尾,代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。

​ FILE_PERMISSIONS和DIRECTORY_PERMISSIONS选项指定对目标中文件和目录的权限。如果指定了USE_SOURCE_PERMISSIONS而未指定FILE_PERMISSIONS,则将从源目录结构中复制文件权限。如果未指定权限,则将为文件提供在命令的FILES形式中指定的默认权限(644权限),而目录将被赋予在命令的PROGRAMS形式中指定的默认权限(755权限)。

​ 可以使用PATTERNREGEX选项以精细的粒度控制目录的安装,可以指定一个通配模式或正则表达式以匹配输入目录中遇到的目录或文件PATTERN仅匹配完整的文件名,而REGEX将匹配文件名的任何部分,但它可以使用/和$模拟PATTERN行为

某些跟随PATTERN或REGEX表达式后的参数,仅应用于满足表达式的文件或目录。如:EXCLUDE选项将跳过匹配的文件或目录。PERMISSIONS选项将覆盖匹配文件或目录的权限设置。

例如:

1
2
3
4
5
install(DIRECTORY icons scripts/ DESTINATION share/myproj
PATTERN "CVS" EXCLUDE
PATTERN "scripts/*"
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
GROUP_EXECUTE GROUP_READ)

这条命令的执行结果是:将icons目录安装到share/myproj,将scripts/中的内容安装到share/myproj,两个目录均不包含目录名为CVS的子目录,对于scripts/*的文件指定权限为OWNER_EXECUTE,OWNER_WRITE,OWNER_READ,GROUP_EXECUTE,GROUP_READ。

安装时脚本的运行:

有时候需要在install的过程中打印一些语句,或者执行一些cmake指令:

1
2
install([[SCRIPT <file>] [CODE <code>]]
[COMPONENT <component>] [EXCLUDE_FROM_ALL] [...])

SCRIPT参数将在安装过程中调用给定的CMake脚本文件(即.cmake脚本文件),如果脚本文件名是相对路径,则将相对于当前源目录进行解释。CODE参数将在安装过程中调用给定的CMake代码。将代码指定为双引号字符串内的单个参数

例如:

1
install(CODE "MESSAGE(\"Sample install message.\")")

这条命令将会在install的过程中执行cmake代码,打印语句。

Build Type

编译过程中,CMake提供了一系列内置的构建选项,它们可以用来指定优化级别以及调试信息是否被包含在可执行文件中。本例展示了在CMake中配置相关信息。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 3.5)

# 设置默认构建选项
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
# 设置cmake-gui的构建选项
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()

project (build_type)
add_executable(cmake_examples_build_type main.cpp)

如上所述,在编译器中设置优化级别可以通过在编译指令中添加相应标志做到:

Release —— 添加”-O3 -DNDEBUG”标志
Debug —— 添加”-g”标志
MinSizeRel —— 添加”-Os -DNDEBUG”标志
RelWithDebInfo —— 添加”-O2 -g -DNDEBUG”标志

也可以在命令行中使用命令:cmake .. -DCMAKE_BUILD_TYPE=Release来选择优化级别。

CMake的默认设置是不在编译命令中加任何标志。对与某些项目,如果你希望设置一个默认的优化级别,可以在CMakeLists.txt中加入以下命令:

1
2
3
4
5
6
7
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()

设置默认优化级别为RelWithDebInfo,并设置了CMake gui中优化级别的选项值。

Set Per-Target C++ Flags

CMake提供了两张设置编译标志的方法:

  • 使用target_compile_definitions()函数
  • 使用CMAKE_C_FLAGS和CMAKE_CXX_FLAGS变量

首先是为每个目标设置单独的C++ Flags:

1
2
3
target_compile_definitions(cmake_examples_compile_flags
PRIVATE EX3
)

​ 上述语句告诉编译器,编译cmake_examples_compile_flags目标时,添加-DEX3标志。此处的PRIVATE与添加包含目录时的scope含义相似。如果目标是库并且选择了范围 +PUBLIC+ 或 +INTERFACE+,则定义也将包含在链接此目标的任何可执行文件中。也可以使用target_compile_options()函数。

Set Default C++ Flags

1
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)

设置CMAKE_CXX_FLAGS变量,强制写入缓存变量。

设置c flags使用CMAKE_C_FLAGS

设置linker flags使用CMAKE_LINKER_FLAGS

一旦设置了 +CMAKE_C_FLAGS+ 和 +CMAKE_CXX_FLAGS+ 将为该目录或任何包含的子目录中的所有目标全局设置编译器标志/定义。现在不建议将此方法用于一般用途,并且首选 +target_compile_definitions+ 函数。

Set CMake Flags

与构建类型类似,可以使用以下方法设置全局 C++ 编译器标志。

  • 使用 ccmake / cmake-gui 等 gui 工具

image::cmake-gui-set-cxx-flag.png[cmake-gui set cxx flag]

  • 传入 cmake

cmake .. -DCMAKE_CXX_FLAGS="-DEX3"


Finding a Package

​ 使用find_package() 函数将从 CMAKE_MODULE_PATH 中的文件夹列表中搜索“FindXXX.cmake”中的 CMake 模块。最正确
find_package 的参数格式将取决于你正在查找的模块,这通常记录在 FindXXX.cmake 文件的顶部。

find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)

其中:

  • Boost - 库的名称。这是用于查找模块文件 FindBoost.cmake 的一部分
  • 1.46.1 - 要查找的最低版本的 boost
  • REQUIRED - 告诉模块这是必需的,如果找不到则失败
  • COMPONENTS - 要在库中找到的组件列表。

Checking if the package is found

大多数包含的包都会设置一个变量XXX_FOUND,可以用来检查该软件包在系统上可用。

在下面的例子中,变量是Boost_FOUND

1
2
3
4
5
6
if(Boost_FOUND)
message ("boost found")
include_directories(${Boost_INCLUDE_DIRS})
else()
message (FATAL_ERROR "Cannot find Boost")
endif()

Exported Variables

​ 找到一个包后,它通常会导出变量,这些变量可以通知用户在哪里可以找到库、头文件或可执行文件。类似于 XXX_FOUND 变量,这些是特定于包的,通常记录在 FindXXX.cmake 文件的顶部。

例如:

Boost_INCLUDE_DIRS - The path to the boost header files.

在某些情况下,还可以通过使用 ccmake 或 cmake-gui 检查缓存来检查这些变量。

在 Boost 的情况下,所有目标都使用 Boost:: 标识符导出,然后是子系统的名称。

例如,可以使用:

  • Boost::boost 仅用于标头库
  • Boost::system 用于 boost 系统库。
  • Boost::filesystem 用于文件系统库。

与您自己的目标一样,这些目标包含它们的依赖项,因此链接到 Boost::filesystem 将自动添加 Boost::boostBoost::system 依赖项。

要链接到导入的目标,可以使用以下命令:

1
2
3
4
target_link_libraries( third_party_include
PRIVATE
Boost::filesystem
)

Non-alias targets

虽然大多数现代库都使用导入的目标,但并非所有模块都已更新。在库尚未更新的情况下,您通常会发现以下可用变量:

  • xxx_INCLUDE_DIRS - A variable pointing to the include directory for the library.
  • xxx_LIBRARY - A variable pointing to the library path.

然后可以将这些添加到您的 +target_include_directories+ 和 +target_link_libraries+ 中:

1
2
3
4
5
6
7
8
9
10
11
# Include the boost headers
target_include_directories( third_party_include
PRIVATE ${Boost_INCLUDE_DIRS}
)

# link against the boost libraries
target_link_libraries( third_party_include
PRIVATE
${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
)

Adding a Sub-Directory

CMakeLists.txt 文件可以包含和调用包含 CMakeLists.txt 的子目录文件。

例如:

1
2
3
add_subdirectory(sublibrary1)
add_subdirectory(sublibrary2)
add_subdirectory(subbinary)

Referencing Sub-Project Directories

​ 当使用 project() 命令创建项目时,CMake 将自动创建许多变量,这些变量可用于引用有关项目的详细信息。然后这些变量可以被其他子项目或主项目使用。例如,要引用可以使用的不同项目的源目录。

1
2
${sublibrary1_SOURCE_DIR}
${sublibrary2_SOURCE_DIR}

Header only Libraries

​ 如果您有一个作为仅标头库创建的库,cmake 支持 +INTERFACE+ 目标以允许在没有任何构建输出的情况下创建目标。

例如:

1
add_library(${PROJECT_NAME} INTERFACE)

创建目标时,您还可以使用 +INTERFACE+ 范围包含该目标的目录。 +INTERFACE+ 范围用于生成在链接此目标的任何库中使用的目标要求,但不在目标本身的编译中。

1
2
3
4
target_include_directories(${PROJECT_NAME}
界面
${PROJECT_SOURCE_DIR}/包括
)

Referencing Libraries from Sub-Projects

如果一个子项目创建了一个库,它可以被其他项目通过在target_link_libraries()命令中调用目标的名称来引用。 这意味着不必引用新库的完整路径,而是将其添加为依赖项。

1
2
3
4
target_link_libraries(subbinary
PUBLIC
sublibrary1
)

或者,您可以创建一个别名目标,它允许您在只读上下文中引用目标:

1
2
add_library(sublibrary2)
add_library(sub::lib2 ALIAS sublibrary2)

要引用别名,只需如下:

1
2
3
target_link_libraries(subbinary
sub::lib2
)

Include directories from sub-projects

从子项目添加库时,从 cmake v3 开始,不需要在使用它们的二进制文件的包含目录中添加项目包含目录。

这由创建库时 target_include_directories() 命令中的范围控制。在这个例子中,因为 subbinary 可执行文件链接了 sublibrary1 和 sublibrary2 库,它会自动包含${sublibrary1_SOURCE_DIR}/include
${sublibrary2_SOURCE_DIR}/include 文件夹,因为它们是使用库的 +PUBLIC+ 和 +INTERFACE+ 范围导出的。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2022-2023 Syclover.Kama
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信