CMake教程(四):生成器表达式

生成器表达式允许 CMake 在构建过程中根据不同的配置(如 Debug、Release)、平台(如 Windows、Linux)、目标类型(如静态库、动态库)等条件,动态调整编译或链接的行为。它们在处理复杂的条件逻辑时非常有用,尤其是在需要支持多配置或多平台时。

生成器表达式的基本语法:

$<condition:expression>
  • condition:生成器表达式中的条件,决定 expression 是否被使用。
  • expression:当条件成立时返回的值或操作。

可以把生成器表达式应用在许多不同的目标属性上,例如:LINK_LIBRARIESINCLUDE_DIRECTORIESCOMPILE_DEFINITIONS 等等。这些属性可以使用一些指令来传播这些属性,例如指令 target_link_libraries()target_include_directories()target_compile_definitions()

生成器表达式可用于启用条件链接、编译时使用的条件定义、条件包含目录等。这些条件可能基于构建配置、目标属性、平台信息或任何其他可查询的信息。

有几种不同类型的生成器表达式,例如:逻辑、信息(Informational)和输出生成器表达式。

逻辑表达式用于创建条件输出。基本的表达式是 01 表达式。$<0:...> 会产生空字符串,$<1:...> 会生成 ...。生成器表达式可以嵌套,例如 $<$<>>

本节的练习是使用生成器表达式添加编译器警告标志。

生成器表达式的一个常见用法是有条件地添加编译器标志,例如用于语言级别或警告的标志。一个好的模式是将此信息与 INTERFACE 目标相关联,从而允许此信息传播。

本节练习使用的源代码是官网提供的 Step4

编辑 Step4/CMakeLists.txt 文件,并完成 TODO 1TODO 4。下面是详细的步骤:
首先,修改 CMake 文件中对 CMake 版本的最小要求为 3.15。

cmake_minimum_required(VERSION 3.15)

接着,使用 COMPILE_LANG_AND_ID 生成器表达式根据不同的编译器设置对应的警告标志。我们需要确定系统当前正在使用哪个编译器进行构建,因为警告标志会根据我们使用的编译器而变化。这是通过COMPILE_LANG_AND_ID 生成器表达式完成的。我们在变量 gcc_like_cxxmsvc_cxx 中设置结果如下:

set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")

接下来,使用变量 gcc_like_cxxmsvc_cxx 为项目添加所需的编译器警告标志。,我们可以使用另一个生成器表达式仅在变量为真时应用相应的标志。我们使用 target_compile_options()将这些标志应用于我们的接口库。

target_compile_options(tutorial_compiler_flags INTERFACE
  "$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>"
  "$<${msvc_cxx}:-W3>"
)

最后,我们只希望在构建过程中使用这些警告标志。已安装项目的用户不应继承我们的警告标志。为了指定这一点,我们使用BUILD_INTERFACE 条件将 TODO 3 中的标志包装在生成器表达式中。生成的完整代码如下:

target_compile_options(tutorial_compiler_flags INTERFACE
  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)

下面是完整的 CMake 文件:

# TODO 1: Update the minimum required version to 3.15

cmake_minimum_required(VERSION 3.15)

# set the project name and version
project(Tutorial VERSION 1.0)

# specify the C++ standard
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)

# TODO 2: Create helper variables to determine which compiler we are using:
# * Create a new variable gcc_like_cxx that is true if we are using CXX and
#   any of the following compilers: ARMClang, AppleClang, Clang, GNU, LCC
# * Create a new variable msvc_cxx that is true if we are using CXX and MSVC
# Hint: Use set() and COMPILE_LANG_AND_ID
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
# TODO 3: Add warning flag compile options to the interface library
# tutorial_compiler_flags.
# * For gcc_like_cxx, add flags -Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused
# * For msvc_cxx, add flags -W3
# Hint: Use target_compile_options()
target_compile_options(tutorial_compiler_flags INTERFACE
  "$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>"
  "$<${msvc_cxx}:-W3>"
)
# TODO 4: With nested generator expressions, only use the flags for the
# build-tree
# Hint: Use BUILD_INTERFACE
target_compile_options(tutorial_compiler_flags INTERFACE
  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file(TutorialConfig.h.in TutorialConfig.h)

# add the MathFunctions library
add_subdirectory(MathFunctions)

# add the executable
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

各位道友,码字不易,如有收获,记得一键三连啊。
看完觉得有帮助的道友,可以关注我的公众号,里面会分享一些高质量的个人成长类读书笔记、生活随笔以及职场经验等等。
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值