Настройка времени выполнения MSVC в CMake
Я следую инструкциям в разделе часто задаваемых вопросов CMake "Как я могу создать свое приложение MSVC со статической средой выполнения?" централизовать выбор среды выполнения MSVC для нескольких вложенных проектов CMake (они извлекаются как подмодули Git и добавляются в главный проект с использованием CMake find_package()
Директива).
Итак, я написал этот макрос CMake:
macro(configure_msvc_runtime)
if(MSVC)
# Default to statically-linked runtime.
if("${MSVC_RUNTIME}" STREQUAL "")
set(MSVC_RUNTIME "static")
endif()
# Set compiler options.
set(variables
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELWITHDEBINFO
)
if(${MSVC_RUNTIME} STREQUAL "static")
message(STATUS
"MSVC -> forcing use of statically-linked runtime."
)
foreach(variable ${variables})
if(${variable} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${variable} "${${variable}}")
endif()
endforeach()
else()
message(STATUS
"MSVC -> forcing use of dynamically-linked runtime."
)
foreach(variable ${variables})
if(${variable} MATCHES "/MT")
string(REGEX REPLACE "/MT" "/MD" ${variable} "${${variable}}")
endif()
endforeach()
endif()
endif()
endmacro()
Я называю этот макрос в начале моего корня CMakeLists.txt
(перед любым add_library()
или же add_executable()
вызов сделан) и добавим немного отладочных отпечатков:
configure_msvc_runtime()
set(variables
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELWITHDEBINFO
)
message(STATUS "Initial build flags:")
foreach(variable ${variables})
message(STATUS " '${variable}': ${${variable}}")
endforeach()
message(STATUS "")
Затем я запускаю CMake, чтобы сгенерировать решение Visual Studio следующим образом:
cmake -G "Visual Studio 9 2008" ..\.. -DMSVC_RUNTIME=dynamic
и я получаю следующие выводы:
-- MSVC -> forcing use of dynamically-linked runtime.
-- Initial build flags:
-- 'CMAKE_C_FLAGS_DEBUG': /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1
-- 'CMAKE_C_FLAGS_MINSIZEREL': /MD /O1 /Ob1 /D NDEBUG
-- 'CMAKE_C_FLAGS_RELEASE': /MD /O2 /Ob2 /D NDEBUG
-- 'CMAKE_C_FLAGS_RELWITHDEBINFO': /MD /Zi /O2 /Ob1 /D NDEBUG
-- 'CMAKE_CXX_FLAGS_DEBUG': /D_DEBUG /MDd /Zi /Ob0 /Od /RTC1
-- 'CMAKE_CXX_FLAGS_MINSIZEREL': /MD /O1 /Ob1 /D NDEBUG
-- 'CMAKE_CXX_FLAGS_RELEASE': /MD /O2 /Ob2 /D NDEBUG
-- 'CMAKE_CXX_FLAGS_RELWITHDEBINFO': /MD /Zi /O2 /Ob1 /D NDEBUG
Дело в том, что когда я запускаю Visual Studio и проверяю свойства проекта в "C/C++, Генерация кода", я вижу, что параметр "Библиотека времени выполнения" не согласуется с параметрами, напечатанными в оболочке. В конфигурациях "Release", "MinSizeRel" и "RelWithDebInfo" я получаю ожидаемые результаты ("Многопоточная DLL /MD", но в конфигурации "Debug" по-прежнему отображается "Многопоточная /MT").
Кроме того, когда я принудительно использую статически связанную среду выполнения, я получаю аналогичные результаты. Если я бегу
cmake -G "Visual Studio 9 2008" ..\.. -DMSVC_RUNTIME=static
Я получаю следующие выводы:
-- MSVC -> forcing use of statically-linked runtime.
-- Initial build flags:
-- 'CMAKE_C_FLAGS_DEBUG': /D_DEBUG /MTd /Zi /Ob0 /Od /RTC1
-- 'CMAKE_C_FLAGS_MINSIZEREL': /MT /O1 /Ob1 /D NDEBUG
-- 'CMAKE_C_FLAGS_RELEASE': /MT /O2 /Ob2 /D NDEBUG
-- 'CMAKE_C_FLAGS_RELWITHDEBINFO': /MT /Zi /O2 /Ob1 /D NDEBUG
-- 'CMAKE_CXX_FLAGS_DEBUG': /D_DEBUG /MTd /Zi /Ob0 /Od /RTC1
-- 'CMAKE_CXX_FLAGS_MINSIZEREL': /MT /O1 /Ob1 /D NDEBUG
-- 'CMAKE_CXX_FLAGS_RELEASE': /MT /O2 /Ob2 /D NDEBUG
-- 'CMAKE_CXX_FLAGS_RELWITHDEBINFO': /MT /Zi /O2 /Ob1 /D NDEBUG
И все же все конфигурации выдают значение "Многопоточный / MT" для параметра "Библиотека времени выполнения".
Что я делаю не так, или это ошибка в CMake (2.8.7) или что-то в этом роде?
Для чего стоит, если я генерирую файлы проекта Visual Studio 2010, я получаю другое значение для конфигурации "Отладка", но все равно не то, которое я выбрал.
Во всех случаях параметр отображается обычным шрифтом для конфигурации "Отладка", тогда как для других конфигураций он выделяется жирным шрифтом, указывая на то, что это переопределения. Более того, если я открою файлы проекта XML, то обнаружу, что в конфигурации "Отладка" нет настройки для атрибута "Runtime Library" элемента "Инструмент" с атрибутом "Name=VCCLCompilerTool". Все остальные конфигурации имеют явную настройку.
2 ответа
Кажется, все время, пока я работал над этим, я забыл удалить плохую конфигурацию CMake, которую я пытаюсь заменить.
Далее, вниз по сценарию сборки, я оставил небольшую ошибку:
set(CMAKE_CXX_FLAGS_DEBUG
"/DWIN32 /D_WINDOWS /EHsc /WX /wd4355 /wd4251 /wd4250 /wd4996"
CACHE STRING "Debug compiler flags" FORCE
)
В основном я переопределял результаты configure_msvc_runtime()
макрос с флагами сборки, который не устанавливал время выполнения MSVC.
Эта функциональность будет улучшена с выпуском cmake-3.15.
Это должен быть вопрос настройки CMAKE_MSVC_RUNTIME_LIBRARY
, например (из документации), чтобы установить "многопоточную статически связанную библиотеку времени выполнения с или без отладочной информации в зависимости от конфигурации":
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
Вот решение, которое я придумал, которое должно работать для версий CMake до и после 3.15.
# This logic needs to be considered before project()
set(_change_MSVC_flags FALSE)
if(WIN32)
if(CMAKE_VERSION VERSION_LESS 3.15.0)
set(_change_MSVC_flags TRUE)
else()
# Set MSVC runtime to MultiThreaded (/MT)
cmake_policy(SET CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
endif()
project(MyProj ....)
if(_change_MSVC_flags)
# Modify compile flags to change MSVC runtime from /MD to /MT
set(_re_match "([\\/\\-]M)D")
set(_re_replace "\\1T")
string(REGEX REPLACE ${_re_match} ${_re_replace}
CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REGEX REPLACE ${_re_match} ${_re_replace}
CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REGEX REPLACE ${_re_match} ${_re_replace}
CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
string(REGEX REPLACE ${_re_match} ${_re_replace}
CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
string(REGEX REPLACE ${_re_match} ${_re_replace}
CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
endif()
Если используются другие языки (т.е. C
), то их тоже нужно будет добавить.
Я взял ваш код и обобщил его, чтобы он работал для каждой существующей конфигурации, а не только для Debug/Release/RelWithDebInfo/MinSizeRel.
Также я сделал это, чтобы работать с gcc тоже - проверить это здесь