Как установить определенные флаги компилятора для определенной цели в конкретной конфигурации сборки с помощью CMake?

У меня есть CMakeLists, где я хочу создать некоторые цели, используя динамическую версию среды выполнения C, и некоторые другие цели, использующие статическую версию.

Поскольку это необходимо установить для каждой цели, метод установки по умолчанию CMAKE_CXX_FLAGS_<Config> не работает; это переопределяет для всех целей.

С этой целью я попытался сделать следующее:

# @fn       set_target_dynamic_crt
# @brief    Sets the given target to use the dynamic version of the CRT (/MD or
#           /MDd)
# @param    ...  A list of targets to which this setting should be applied.
function( set_target_dynamic_crt )
    if ( MSVC )
        message (WARNING ${CMAKE_BUILD_TYPE})
        if (CMAKE_BUILD_TYPE STREQUAL "Debug")
            set_target_properties ( ${ARGN} PROPERTIES COMPILE_FLAGS "/MDd" )
        else()
            set_target_properties ( ${ARGN} PROPERTIES COMPILE_FLAGS "/MD" )
        endif()
    endif()
endfunction()

Однако это всегда выбирает версию выпуска (/MD), и когда я запрашиваю тип сборки (вызов message выше), я получаю пустую строку. (Я подозреваю, что это связано с тем, что я использую генератор Visual Studio, я видел несколько ссылок, в которых говорится, что CMAKE_BUILD_TYPE предназначен только для make файлов...)

Как настроить параметры компиляции, например, для каждой цели?

Ответ 1

В CMake 2.8.12 я добавил команду target_compile_options для решения этой проблемы:

http://public.kitware.com/Bug/view.php?id=6493

http://www.cmake.org/cmake/help/git-master/manual/cmake-generator-expressions.7.html

target_compile_options(tgt PRIVATE "/MD$<$<CONFIG:Debug>:d>")

См.

http://www.cmake.org/cmake/help/git-next/manual/cmake-buildsystem.7.html#build-specification-with-generator-expressions

для более подробной информации о CMAKE_BUILD_TYPE и нескольких причинах, по которым выражение генератора лучше (например, IMPORTED target config mapping).

Ответ 2

Единственный вариант, который я знаю для этого сценария, - это разделить проект на подкаталоги на основе каждой цели и использовать add_subdirectory.

В зависимости от того, как ваш проект в настоящее время настроен, это может быть болезненный процесс, я думаю.

Результатом будет файл CMakeLists.txt верхнего уровня, который выглядит, например,

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Test)
add_subdirectory(libB)
add_subdirectory(libA)
add_executable(main_exe "main.cpp")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
target_link_libraries(main_exe lib_a lib_b)

то libA/CMakeLists.txt может указывать флаги MD и MDd:

project(LibA)
add_library(lib_a a.cpp a.hpp)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")

и libB/CMakeLists.txt для флагов MT и MTd:

project(LibB)
add_library(lib_b b.cpp b.hpp)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")

Вы можете, конечно, добавить все цели, которые должны быть связаны со статическим CRT в одном подкаталоге и CMakeLists.txt, и все динамические CRT в другом, если у вас много целей.

Ответ 3

CMAKE_BUILD_TYPE применим только для генераторов с одной конфигурацией. Генераторы с несколькими конфигурациями (MSVC и Xcode) могут строить для нескольких конфигураций в одном каталоге-каталоге, и поэтому флаг CMAKE_BUILD_TYPE не имеет значения.

Свойство target для COMPILE_FLAGS не различает различные конфигурации (подробнее см. kitware bugtracker).

Обходной путь состоял бы в том, чтобы иметь два сборщика, похожий на то, как люди используют генераторы Makefile, и определяют дополнительный флаг при создании двоичных файлов для распространения. (т.е. конфигурации Release)