在CMake中设置MSVC运行时

时间:2012-04-11 19:58:17

标签: visual-studio cmake

我按照CMake FAQ条目"How can I build my MSVC application with a static runtime?"中的说明集中选择一组嵌套CMake项目的MSVC运行时(它们作为Git子模块引入并使用CMake {添加到主项目中} {1}}指令)。

所以,我写了这个CMake宏:

find_package()

我在我的根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.txtadd_library()调用之前)并添加一些调试打印:

add_executable()

然后,我运行CMake来生成如此的Visual Studio解决方案:

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 -G "Visual Studio 9 2008" ..\.. -DMSVC_RUNTIME=dynamic

现在,当我启动Visual Studio并检查“C / C ++,代码生成”下的项目属性时,我发现“运行时库”设置与shell中打印的选项不一致。在“Release”,“MinSizeRel”和“RelWithDebInfo”配置下,我得到了预期的结果(“多线程DLL / MD”,但“Debug”配置仍然显示“Multi-threaded /MT”)。

此外,当我强制使用静态链接的运行时,我得到类似的结果。如果我跑

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

我得到以下输出:

cmake -G "Visual Studio 9 2008" ..\.. -DMSVC_RUNTIME=static

然而所有配置都为“运行时库”设置生成“多线程/ MT”值。

我做错了什么,或者这是CMake(2.8.7)中的错误还是什么?


对于它的价值,如果我生成Visual Studio 2010项目文件,我会为“Debug”配置获得不同的值,但仍然不是我选择的值。

在所有情况下,设置以“Debug”配置的常规字体显示,而其他配置以粗体字体显示,暗示这些是覆盖。此外,如果我打开XML项目文件,我发现“Debug”配置没有为“Tool”元素的“RuntimeLibrary”属性设置“Name = VCCLCompilerTool”属性。所有其他配置都有明确的设置。

4 个答案:

答案 0 :(得分:12)

似乎我一直在研究这个问题,我忘了删除我想要替换的错误的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运行时的构建标志的结果。

答案 1 :(得分:6)

我接受了你的代码并将其推广到每个现有配置,而不仅仅是Debug / Release / RelWithDebInfo / MinSizeRel。

此外,我也使用了gcc - 请查看here

答案 2 :(得分:1)

随着cmake-3.15的发布,此功能将得到改进。

应该设置CMAKE_MSVC_RUNTIME_LIBRARY,例如(来自docs)设置为“多线程静态链接的运行时库,取决于配置,是否包含调试信息”:

set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

答案 3 :(得分:1)

这是我想出的一个解决方案,应该适用于3.15之前和之后的CMake版本。

# 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),那么也需要添加这些语言。