生成器表达式允许 CMake 在构建过程中根据不同的配置(如 Debug、Release)、平台(如 Windows、Linux)、目标类型(如静态库、动态库)等条件,动态调整编译或链接的行为。它们在处理复杂的条件逻辑时非常有用,尤其是在需要支持多配置或多平台时。
生成器表达式的基本语法:
$<condition:expression>
- condition:生成器表达式中的条件,决定 expression 是否被使用。
- expression:当条件成立时返回的值或操作。
可以把生成器表达式应用在许多不同的目标属性上,例如:LINK_LIBRARIES、INCLUDE_DIRECTORIES 和 COMPILE_DEFINITIONS 等等。这些属性可以使用一些指令来传播这些属性,例如指令 target_link_libraries() 、target_include_directories() 和 target_compile_definitions()。
生成器表达式可用于启用条件链接、编译时使用的条件定义、条件包含目录等。这些条件可能基于构建配置、目标属性、平台信息或任何其他可查询的信息。
有几种不同类型的生成器表达式,例如:逻辑、信息(Informational)和输出生成器表达式。
逻辑表达式用于创建条件输出。基本的表达式是 0 和 1 表达式。$<0:...> 会产生空字符串,$<1:...> 会生成 ...。生成器表达式可以嵌套,例如 $<$<>>
本节的练习是使用生成器表达式添加编译器警告标志。
生成器表达式的一个常见用法是有条件地添加编译器标志,例如用于语言级别或警告的标志。一个好的模式是将此信息与 INTERFACE 目标相关联,从而允许此信息传播。
本节练习使用的源代码是官网提供的 Step4。
编辑 Step4/CMakeLists.txt 文件,并完成 TODO 1 到 TODO 4。下面是详细的步骤:
首先,修改 CMake 文件中对 CMake 版本的最小要求为 3.15。
cmake_minimum_required(VERSION 3.15)
接着,使用 COMPILE_LANG_AND_ID 生成器表达式根据不同的编译器设置对应的警告标志。我们需要确定系统当前正在使用哪个编译器进行构建,因为警告标志会根据我们使用的编译器而变化。这是通过COMPILE_LANG_AND_ID 生成器表达式完成的。我们在变量 gcc_like_cxx 和 msvc_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_cxx 和 msvc_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}"
)
各位道友,码字不易,如有收获,记得一键三连啊。
看完觉得有帮助的道友,可以关注我的公众号,里面会分享一些高质量的个人成长类读书笔记、生活随笔以及职场经验等等。


1559

被折叠的 条评论
为什么被折叠?



