Kompilieren Sie mit / MT anstelle von / MD mit CMake

69

Ich verwende CMake unter Windows mit dem Windows SDK und NMake Makefiles.

Standardmäßig wird es mit dem /MDCompiler-Schalter kompiliert .

Wie kann ich es ändern, um es /MTstattdessen mit dem Switch zu kompilieren ?

Josh
quelle

Antworten:

87

Sie können die CMAKE_CXX_FLAGS_<Build Type>und / oder CMAKE_C_FLAGS_<Build Type>Variablen ändern :

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

Wenn Ihre CMake-Flags bereits enthalten sind /MD, können Sie sicherstellen, dass die obigen Befehle nach dem Einfügepunkt ausgeführt werden /MD(das spätere Hinzufügen /MTüberschreibt die widersprüchliche vorhandene Option), oder Sie können die Flags von Grund auf neu setzen:

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

Oder alternativ können Sie die bestehenden ersetzen /MDund /MDdWerte mit /MTund /MTdjeweils durch etwas zu tun , wie:

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()
Fraser
quelle
@ Josh Ich habe gerade die Antwort aktualisiert. Wenn es immer noch nicht genau das ist, wonach Sie suchen, zeigen Sie das relevante Bit Ihrer CMakeLists.txt und ich bin sicher, dass es eine gute Antwort geben wird.
Fraser
@Josh Ich habe einen kleinen Fehler im string(REPLACE...)Befehl gemacht - er ist jetzt behoben.
Fraser
29
Diese Anfrage ist sehr häufig - es ist seltsam, dass CMake immer noch kein Makro oder keine Einstellung hat, um dies sofort zu unterstützen. Am Ende mache ich das in fast jedem Projekt - besonders in solchen mit externen Abhängigkeiten wie GoogleMock, die ihre eigenen Standardmeinungen über den Compiler ABI haben
kert
@kert - Es ist mehr als seltsam, es ist mystifizierend.
Jeremy
Kann mir jemand sagen, in welcher Datei in vcpkg diese Änderung vorgenommen werden soll?
Gunnar
55

CMake hat dies in Version 3.15 mit der Zieleigenschaft endlich richtig unterstützt MSVC_RUNTIME_LIBRARY:

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

Sie können auch einen globalen Standard angeben, indem Sie CMAKE_MSVC_RUNTIME_LIBRARYstattdessen die Variable festlegen .

ComicSansMS
quelle
1
Es funktioniert irgendwie ohne das cmake_policy(SET CMP0091 NEW)auf 3.16.3, ist es wirklich erforderlich?
Vladimir Gamalyan
4
@VladimirGamalyan Wie bei Richtlinien üblich cmake_minimum_required, müssen Sie das neue Verhalten nicht explizit anfordern , wenn es neu genug ist. Ich habe die Richtlinie größtenteils in die Antwort aufgenommen, damit die Benutzer wissen, dass für diese Funktion eine Richtlinie vorhanden ist, und sie nachschlagen, wenn sie sich um die Auswirkungen auf die Kompatibilität kümmern.
ComicSansMS
1
Dies sollte die akzeptierte Lösung sein, zumindest für moderne cmake. Dies ist weit weniger undurchsichtig als das Hacken von CMAKE_CXX_FLAGS ...
David Karla
@ DavidKarla Abgesehen von der Tatsache, dass diese Antwort sechs Jahre nach der ursprünglichen Frage gegeben wurde, um nicht zu sagen, dass sich die Person, die sie gestellt hat, seit 2015 nicht mehr angemeldet hat.
John Cvelth
6

Es scheint , dass für Visual Studio 15 2017 und CMake 3.12 die Art und Weise zu ersetzen /MDdurch , /MTindem Sie diesen Schnipsel in die CMakeLists.txt Datei ist:

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

Ich habe diese Lösung im offiziellen CMake-Repository gefunden: https://gitlab.kitware.com/cmake/cmake/issues/18390

Carlos D. Álvaro
quelle
Hinweis: Dieser Block sollte vor dem add_executableoderadd_library
Bernardo Ramos
2

Ich muss verwenden set( ... CACHE ... FORCE), um den Standard-Cache von MSVC zu überschreiben.

Wenn ich diese Methode nicht verwende, gibt MSVC weiterhin /MDOptionen aus.

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
quelle
Nach stundenlanger Zeitverschwendung war dies das einzige, was für mich funktionierte. Vielen Dank!
Miscreant
Obwohl dies immer noch einige der Standardbibliotheken dynamisch zu verknüpfen scheint: MSVCP140.dll, VCRUNTIME140_1.dll, VCRUNTIME140.dll, api-ms-win-crt-string-l1-1-0.dll ...
Miscreant
@Miscreant Das einzige, was ich vorschlagen kann, ist, alle generierten Befehlszeilenargumente im Cache von cmake zu überprüfen. Die Regeln des cmake sind kompliziert, während das MSVC-System chaotisch ist.
Shawn