CMake:如何基于选项(和编译器/构建配置)设置生成器表达式

时间:2018-05-19 22:52:35

标签: cmake

我已经使用了以下生成器表达式,如果编译器是MSVC,它会设置/GS标志,并为构建配置RelWithDebInfoRelease设置它:< / p>

target_compile_options(mytarget PRIVATE "$<$<CONFIG:Release>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>")

现在我也想让用户配置这个,我添加了optionoption(MYTARGET_ENABLE_GS "Enable /GS" OFF)

所以现在,我(显然)想要启用/GS标志如果用户启用了此选项,如果他们这样做了,我想添加它 if 编译器是MSVC,应该添加到ReleaseRelWithDebInfo配置中。

这是非常嵌套的,我似乎无法做到这一点。这是我得到的:

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(可以是开/关或真/假,到01,生成器表达式需要它。 但是上面的行不起作用:它不会添加(或不添加)/GS

我想知道:

1)我的错误在哪里?这该怎么做?和

2)这样的东西导致了非常复杂的嵌套表达式,这些表达式真的难以阅读 - 想象一下,在读取该行代码的6个月之后,即使它已被记录下来。并且很容易错位>或类似的东西。 我可以使用&#34;手册&#34; if使这更具可读性,但想象一下有5-10个这样的选项 - 用ifend / 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;,我希望能够深入了解。

3 个答案:

答案 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()