我已经使用了以下生成器表达式,如果编译器是MSVC,它会设置/GS
标志,并为构建配置RelWithDebInfo
和Release
设置它:< / p>
target_compile_options(mytarget PRIVATE "$<$<CONFIG:Release>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>")
现在我也想让用户配置这个,我添加了option
:
option(MYTARGET_ENABLE_GS "Enable /GS" OFF)
所以现在,我(显然)想要启用/GS
标志如果用户启用了此选项,如果他们这样做了,我想添加它 if 编译器是MSVC,应该添加到Release
和RelWithDebInfo
配置中。
这是非常嵌套的,我似乎无法做到这一点。这是我得到的:
target_compile_options(mytarget PRIVATE "$<$<BOOL:MYTARGET_ENABLE_GS>:$<$<CONFIG:Release>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>>")
编辑:已修复,请参见下文。
我必须使用$<$<BOOL:...>>
,因为&#34;翻译&#34; option
(可以是开/关或真/假,到0
或1
,生成器表达式需要它。
但是上面的行不起作用:它不会添加(或不添加)/GS
。
我想知道:
1)我的错误在哪里?这该怎么做?和
2)这样的东西导致了非常复杂的嵌套表达式,这些表达式真的难以阅读 - 想象一下,在读取该行代码的6个月之后,即使它已被记录下来。并且很容易错位>
或类似的东西。
我可以使用&#34;手册&#34; if
使这更具可读性,但想象一下有5-10个这样的选项 - 用if
写end
/ target_compile_options
会产生类似15-30行的结果if
/ end
代码的代码,看起来也不是很漂亮。最好的方法是什么?
编辑:我快到了。变量必须在生成器表达式中用${...}
括起来。所以它就是这样的:
target_compile_options(mytarget PRIVATE "$<$<BOOL:${MYTARGET_ENABLE_GS}>:$<$<CONFIG:Release>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>>")
这很有效。
仍然留下了点&#34; 2)&#34;,我希望能够深入了解。
答案 0 :(得分:3)
生成MSVC解决方案时,构建类型(发布,调试等)在实际运行构建之前是未知的。因此,使用生成器表达式是正确的。
但是对于其他2个变量(用户将MYTARGET_ENABLE_GS设置为OFF并且是为MSVC执行生成),它们将在配置时解析。因此,您不必在生成器表达式中检查它们。你可以简单地写:
if(MSVC AND MYTARGET_ENABLE_GS)
target_compile_options(mytarget PRIVATE "$<$<OR:$<CONFIG:Release>, $<CONFIG:RelWithDebInfo>>:/GS>")
endif()
此解决方案还使用$<OR:?[,?]...>
生成器表达式在同一表达式下重新组合您在Release或RelWithDebInfo中构建的两种情况
答案 1 :(得分:2)
每当您使用if
命令时,请使用它。生成器表达式不替换if
命令。
生成器表达式允许使用依赖于构建类型的条件。因为在多配置构建系统(如Visual Studio)上,构建类型在配置阶段是不可知的,所以不能在if
命令中使用这样的条件。
但是生成器表达式丑陋,因此在不需要时不要使用它们。
没什么不好的
if(MYTARGET_ENABLE_GS)
target_compile_options(mytarget PRIVATE "$<$<CONFIG:Release>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>")
endif()
如果要在开头检查选项,但稍后创建目标,则可以将生成器表达式存储在变量中,并稍后使用此变量:
set(additional_options)
# Depending on parameters, add options to 'additional_options' list.
if(MYTARGET_ENABLE_GS)
list(APPEND additional_options "$<$<CONFIG:Release>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>")
endif()
if(<other option>)
list(APPEND additional_options <...>)
endif()
# ...
target_compile_options(mytarget PRIVATE ${additional_options})
答案 2 :(得分:0)
如果您的配置与 CONFIG:
之后列出的任何配置匹配,CMake 的文档生成器表达式就可以工作,但我找不到任何地方记录的语法。试验和错误显示以下工作正常:
if(MSVC AND MYTARGET_ENABLE_GS)
target_compile_options(mytarget PRIVATE "$<$<CONFIG:Release,RelWithDebInfo>:/GS>")
endif()