103

I'm using CMake on windows with the Windows SDK and NMake Makefiles.

By default it compiles with the /MD compiler switch.

How can I change it to compile with the /MT switch instead?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Josh
  • 6,046
  • 11
  • 52
  • 83

6 Answers6

113

You can modify the CMAKE_<LANG>_FLAGS_<CONFIG> variables:

set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")

If your CMake flags already contain /MD, you can ensure that the above commands are executed after the point at which /MD is inserted (the later addition of /MT overrides the conflicting existing option), or you can set the flags from scratch:

set(CMAKE_CXX_FLAGS_RELEASE "/MT")
set(CMAKE_CXX_FLAGS_DEBUG "/MTd")

Or alternatively, you could replace the existing /MD and /MDd values with /MT and /MTd respectively by doing something like:

set(CompilerFlags
        CMAKE_CXX_FLAGS
        CMAKE_CXX_FLAGS_DEBUG
        CMAKE_CXX_FLAGS_RELEASE
        CMAKE_C_FLAGS
        CMAKE_C_FLAGS_DEBUG
        CMAKE_C_FLAGS_RELEASE
        )
foreach(CompilerFlag ${CompilerFlags})
  string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
endforeach()
starball
  • 20,030
  • 7
  • 43
  • 238
Fraser
  • 74,704
  • 20
  • 238
  • 215
  • @Josh I've just updated the answer. If it's still not exactly what you're after, show the relevant bit of your CMakeLists.txt and I'm sure there'll be a neat answer. – Fraser Jan 05 '13 at 15:01
  • @Josh I made a minor mistake in the `string(REPLACE...)` command - it's fixed now. – Fraser Jan 05 '13 at 15:07
  • 35
    This request is very common - its strange that CMake still doesnt have a macro or setting to support this out of the box. I end up doing this in almost every project - especially ones that have external dependencies like GoogleMock that have their own default opinions about compiler ABI – kert Aug 19 '13 at 15:56
  • @kert - It's more than strange, it's mystifying. – Jeremy Dec 29 '16 at 20:15
  • 1
    Can anyone tell me in which file in vcpkg this change should be made? – Gunnar Sep 02 '17 at 13:13
  • Is there any new official solution for this problem? – sorosh_sabz Mar 15 '19 at 17:32
  • When changing /MD or /MT, be sure to delete all prior CMake output. If binary directory has CMake files from a previous attempt, I found that CMake would appear to have the proper switch through [MESSAGE()](https://stackoverflow.com/questions/9298278/cmake-print-out-all-accessible-variables-in-a-script) inspection, but build command line continued to use the prior stale switch setting. – jws Mar 22 '19 at 19:32
  • @xuhdev please refer to my answer. You should use `set(... CACHE ... FORCE)` – shawn Jun 10 '19 at 05:16
  • 2
    @Fraser can this option be set from the command line using by running `cmake -D CMAKE_CXX_FLAGS="/MT" ..`? – cyrusbehr Dec 03 '20 at 00:13
  • @cyrusbehr Good question. I think the answer is no. How did you manage to solve the issue? – manuell Sep 29 '21 at 19:21
  • I realize this is a nearly 10 year old answer so I should have known better, however BE WARNED: if you do `set(CMAKE_CXX_FLAGS_DEBUG "/MTd")` (or `MT`) on newer versions of CMake, you overwrite some other flags set by the platform module scripts (e.g., `/Zi`). This was entirely my fault, but I was unable to debug in vscode when using this. I couldn't figure out for the life of me why debugging stopped breaking on my breakpoints -- the issue was this setting stepping on the compiler flags. I **highly** recommend using the `MSVC_RUNTIME_LIBRARY` answer instead. – Aelarion Sep 24 '22 at 01:05
106

CMake finally added proper support for this in version 3.15 with the MSVC_RUNTIME_LIBRARY target property:

cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW)
project(my_project)

add_executable(foo foo.c)
set_property(TARGET foo PROPERTY
             MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

You can also specify a global default by setting the CMAKE_MSVC_RUNTIME_LIBRARY variable instead.

ComicSansMS
  • 51,484
  • 14
  • 155
  • 166
  • 2
    It works somehow w/o the `cmake_policy(SET CMP0091 NEW)` on 3.16.3, is it really required? – Vladimir Gamalyan Jan 28 '20 at 03:41
  • 6
    @VladimirGamalyan As usual with policies, if your `cmake_minimum_required` is new enough, you don't need to request the new behavior explicitly. I mostly included the policy in the answer so that people are aware that a policy exists for this feature and look it up if they care about the compatibility implications. – ComicSansMS Jan 28 '20 at 06:53
  • 3
    this should be the accepted solution, at least for modern cmake. this is far less opaque than hacking CMAKE_CXX_FLAGS... – David Karla May 13 '20 at 12:14
  • 2
    @DavidKarla Except for the fact that this answer was given six years after the original question was asked, not to say that the person who's asked it hasn't logged in since 2015. – John Cvelth Nov 30 '20 at 09:40
  • 2
    This doesn't work. – scx Feb 05 '22 at 07:47
  • And make sure you cleared your build folder before cmake sync, or you will get a `D9025` warning. – Kotori0 Sep 23 '22 at 08:02
21

It seems that for Visual Studio 15 2017 and CMake 3.12 the way to replace /MD by /MT is by adding this snippet to the CMakeLists.txt file:

if(MSVC)
    add_compile_options(
        $<$<CONFIG:>:/MT> #---------|
        $<$<CONFIG:Debug>:/MTd> #---|-- Statically link the runtime libraries
        $<$<CONFIG:Release>:/MT> #--|
    )
endif()

I found this solution in the official CMake repository: https://gitlab.kitware.com/cmake/cmake/issues/18390

Edit: As commented by @bernardo-ramos, this block should be added before the add_executable or add_library.

Carlos D. Álvaro
  • 561
  • 1
  • 6
  • 12
4

I have to use set( ... CACHE ... FORCE) to overwrite MSVC's default cache.

If I do not use this method, MSVC still outputs /MD options.

set(CompilerFlags
        CMAKE_CXX_FLAGS
        CMAKE_CXX_FLAGS_DEBUG
        CMAKE_CXX_FLAGS_RELEASE
        CMAKE_CXX_FLAGS_MINSIZEREL
        CMAKE_CXX_FLAGS_RELWITHDEBINFO
        CMAKE_C_FLAGS
        CMAKE_C_FLAGS_DEBUG
        CMAKE_C_FLAGS_RELEASE
        CMAKE_C_FLAGS_MINSIZEREL
        CMAKE_C_FLAGS_RELWITHDEBINFO
        )
foreach(CompilerFlag ${CompilerFlags})
    string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
    set(${CompilerFlag} "${${CompilerFlag}}" CACHE STRING "msvc compiler flags" FORCE)
    message("MSVC flags: ${CompilerFlag}:${${CompilerFlag}}")
endforeach()
shawn
  • 4,305
  • 1
  • 17
  • 25
  • After hours of wasted time, this was the only thing that worked for me. Thanks! – Miscreant Oct 15 '20 at 12:36
  • Though this still seems to link some of the standard libraries dynamically: MSVCP140.dll, VCRUNTIME140_1.dll, VCRUNTIME140.dll, api-ms-win-crt-string-l1-1-0.dll ... – Miscreant Oct 15 '20 at 13:33
  • 1
    @Miscreant the only thing I can suggest is that to check all generated command line arguments in cmake's cache. The cmake's rules are complicated, while the MSVC's system is messy. – shawn Oct 15 '20 at 17:22
3

Since cmacke 3.15, you can use MSVC_RUNTIME_LIBRARY. See https://cmake.org/cmake/help/latest/prop_tgt/MSVC_RUNTIME_LIBRARY.html

2

Check out ucm_set_runtime - this macro will replace the flags for static or dynamic runtime - to see the effects, use ucm_print_flags (also checkout this Stack Overflow question).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
onqtam
  • 4,356
  • 2
  • 28
  • 50