Тернарный оператор в выражениях генератора CMake

Cmake выражения генератора позволяют мне использовать логические выражения в определенных вызовах функций. Например, если я хочу добавить флаг /MTd компилятора в режиме отладки, могу сказать

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

Если CONFIG равно "Debug", это вызовет add_compile_options со значением "/MTd", в противном случае с пустой строкой.

Но обычно я не хочу выбирать между значением и пустой строкой, но между двумя значениями. В приведенном выше примере, если CONFIG не является "Debug", я хочу передать /MT (без конечного d). Мне бы хотелось иметь такой синтаксис:

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

Обратите внимание, что приведенный выше недействительный код соответствует спецификациям CMake. Самое лучшее, что я придумал, это на самом деле:

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

Это кажется ужасно лишним для меня. Существует ли более короткий и понятный способ выбора между двумя значениями?

Примечание. Я понимаю, что в этом специальном случае я мог бы написать это:

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

Но это кажется довольно хакированным для меня и работает только в тех случаях, когда один параметр является подстрокой другого.

Ответы

Ответ 1

Обратите внимание, что cmake 3.8 добавил именно то, что вы хотите, чтобы генератор выражений...

$<IF:?,true-value...,false-value...>
true-value... if ? is 1, false-value... if ? is 0

Ответ 2

Вот рабочий пример с макросом:

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}
    )

Создайте файл CMakeLists.txt и запустите cmake . && make print (выражения генератора оцениваются только во время сборки).

Попробуйте изменить значение mybool на 0 или 1 и посмотреть, что произойдет.

Следующее определение также работает, и оно яснее:

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)

означает, по сравнению с C/С++:

int var = boolean ? value1 : value2;

Ответ 3

Давайте сделаем это более явным:

add_custom_command(TARGET myProject PRE_BUILD
    COMMAND cd \"D:/projects/$<IF:$<CONFIG:Debug>,Debug,Release>\"
    COMMAND call prebuild.bat)

Затем в сгенерированном Visual Studio Project, в окне свойств проекта "myProject".

Если конфигурация сборки "Отладка", процесс оценки будет следующим:

  1. $<IF:$<CONFIG:Debug>,Debug,Release>
  2. $<IF:1,Debug,Release>
  3. Debug

Если для конфигурации сборки выбрано "Release", процесс оценки будет следующим:

  1. $<IF:$<CONFIG:Debug>,Debug,Release>
  2. $<IF:0,Debug,Release>
  3. Release