Ternary operator in CMake's generator expressi

2019-04-18 06:06发布

问题:

Cmake's generator expressions allow me to use logical expressions within certain function calls. For instance, if I want to add the /MTd compiler flag in Debug mode, I can say

add_compile_options($<$<CONFIG:Debug>:/MTd>)

If CONFIG equals "Debug", this will call add_compile_options with the value "/MTd", otherwise with an empty string.

But usually, I don't want to decide between a value and the empty string, but between two values. In the example above, if CONFIG is not "Debug", I want to pass /MT (without the trailing d). I'd love to have a syntax like this:

add_compile_options($<$<CONFIG:Debug>:/MTd:/MT>)

Note that the above is not valid code according to the CMake specs. The best I have come up with that actually works is this:

add_compile_options($<$<CONFIG:Debug>:/MTd>$<$<NOT:$<CONFIG:Debug>>:/MT>)

This seems awfully redundant to me. Is there a shorter, more readable way to decide between two values?

Note: I realize that in this special case, I could write this:

add_compile_options(/MT$<$<CONFIG:Debug>:d>)

But this seems rather hacky to me and only works in those cases where one option is a substring of the other.

回答1:

Here's a working example, with a macro:

cmake_minimum_required(VERSION 2.8.12)

macro(ternary var boolean value1 value2)
    set(${var} $<${${boolean}}:${value1}>$<$<NOT:${${boolean}}>:${value2}>)
endmacro()

set(mybool 0)
ternary(myvar mybool hello world)

add_custom_target(print
    ${CMAKE_COMMAND} -E echo ${myvar}
    )

Create a CMakeLists.txt file and run cmake . && make print (generator expressions are only evaluated at build time).

Try changing the value of mybool to 0 or 1 and see what happens.

The following definition also works, and it is clearer:

cmake_minimum_required(VERSION 2.8.12)

macro(ternary var boolean value1 value2)
    if(${boolean})
        set(${var} ${value1})
    else()
        set(${var} ${value2})
    endif()
endmacro()

set(mybool 0)
ternary(myvar mybool hello world)

add_custom_target(print
    ${CMAKE_COMMAND} -E echo ${myvar}
    )

TL;DR

ternary(var boolean value1 value2)

means, comparing to C/C++:

int var = boolean ? value1 : value2;