summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2019-04-17 15:01:03 (GMT)
committerKitware Robot <kwrobot@kitware.com>2019-04-17 15:01:37 (GMT)
commit2ed688a863671d58513055ad56ab04d6be05295b (patch)
tree91c01b78176bf39f6058fe3b9c1676dbb57cbcad
parent5cd187147ecbd29a0afc5a6b49f2232b61a1ab8c (diff)
parentfb3370b6a1681190ffd8daf63975c44ce8fc1c49 (diff)
downloadCMake-2ed688a863671d58513055ad56ab04d6be05295b.zip
CMake-2ed688a863671d58513055ad56ab04d6be05295b.tar.gz
CMake-2ed688a863671d58513055ad56ab04d6be05295b.tar.bz2
Merge topic 'msvc-runtime-library'
fb3370b6a1 MSVC: Add abstraction for runtime library selection f621e7fa5d VS: Fix Fortran runtime library flag map special case for '-' options Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: Ben Boeckel <ben.boeckel@kitware.com> Acked-by: Leonid Pospelov <pospelovlm@yandex.ru> Merge-request: !3211
-rw-r--r--Help/command/try_compile.rst1
-rw-r--r--Help/manual/cmake-policies.7.rst1
-rw-r--r--Help/manual/cmake-properties.7.rst1
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/policy/CMP0091.rst47
-rw-r--r--Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt15
-rw-r--r--Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst26
-rw-r--r--Help/release/dev/msvc-runtime-library.rst7
-rw-r--r--Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst27
-rw-r--r--Modules/Platform/Windows-Intel-Fortran.cmake30
-rw-r--r--Modules/Platform/Windows-MSVC.cmake38
-rw-r--r--Source/cmCoreTryCompile.cxx11
-rw-r--r--Source/cmLocalGenerator.cxx37
-rw-r--r--Source/cmPolicies.h5
-rw-r--r--Source/cmTarget.cxx1
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx8
-rw-r--r--Tests/CMakeLists.txt4
-rw-r--r--Tests/MSVCRuntimeLibrary/CMakeLists.txt49
-rw-r--r--Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt50
-rw-r--r--Tests/MSVCRuntimeLibrary/Fortran/verify.F901
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.c1
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.cxx1
-rw-r--r--Tests/MSVCRuntimeLibrary/verify.h29
-rw-r--r--Tests/RunCMake/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt1
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake2
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake37
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/MSVCRuntimeLibrary/empty.c0
-rw-r--r--Tests/RunCMake/VS10Project/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake34
-rw-r--r--Tests/RunCMake/VS10Project/RuntimeLibrary.cmake16
-rw-r--r--Tests/RunCMake/VS10Project/empty.c0
-rw-r--r--Tests/RunCMake/VS10Project/empty.cxx0
38 files changed, 482 insertions, 17 deletions
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst
index ca8fc77..0bc2ca3 100644
--- a/Help/command/try_compile.rst
+++ b/Help/command/try_compile.rst
@@ -135,6 +135,7 @@ default values:
* :variable:`CMAKE_ENABLE_EXPORTS`
* :variable:`CMAKE_LINK_SEARCH_START_STATIC`
* :variable:`CMAKE_LINK_SEARCH_END_STATIC`
+* :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
* :variable:`CMAKE_POSITION_INDEPENDENT_CODE`
If :policy:`CMP0056` is set to ``NEW``, then
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index e89ea3da..043fb5c 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.15
.. toctree::
:maxdepth: 1
+ CMP0091: MSVC runtime library flags are selected by an abstraction. </policy/CMP0091>
CMP0090: export(PACKAGE) does not populate package registry by default. </policy/CMP0090>
CMP0089: Compiler id for IBM Clang-based XL compilers is now XLClang. </policy/CMP0089>
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index bd19ccf..c11496c 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -280,6 +280,7 @@ Properties on Targets
/prop_tgt/MACOSX_RPATH
/prop_tgt/MANUALLY_ADDED_DEPENDENCIES
/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG
+ /prop_tgt/MSVC_RUNTIME_LIBRARY
/prop_tgt/NAME
/prop_tgt/NO_SONAME
/prop_tgt/NO_SYSTEM_FROM_IMPORTED
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 18dd9d7..22e8add 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -386,6 +386,7 @@ Variables that Control the Build
/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT
/variable/CMAKE_MODULE_LINKER_FLAGS_INIT
/variable/CMAKE_MSVCIDE_RUN_PATH
+ /variable/CMAKE_MSVC_RUNTIME_LIBRARY
/variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX
/variable/CMAKE_NO_BUILTIN_CHRPATH
/variable/CMAKE_NO_SYSTEM_FROM_IMPORTED
diff --git a/Help/policy/CMP0091.rst b/Help/policy/CMP0091.rst
new file mode 100644
index 0000000..5b7c4e3
--- /dev/null
+++ b/Help/policy/CMP0091.rst
@@ -0,0 +1,47 @@
+CMP0091
+-------
+
+MSVC runtime library flags are selected by an abstraction.
+
+Compilers targeting the MSVC ABI have flags to select the MSVC runtime library.
+Runtime library selection typically varies with build configuration because
+there is a separate runtime library for Debug builds.
+
+In CMake 3.14 and below, MSVC runtime library selection flags are added to
+the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache entries by CMake
+automatically. This allows users to edit their cache entries to adjust the
+flags. However, the presence of such default flags is problematic for
+projects that want to choose a different runtime library programmatically.
+In particular, it requires string editing of the
+:variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variables with knowledge of the
+CMake builtin defaults so they can be replaced.
+
+CMake 3.15 and above prefer to leave the MSVC runtime library selection flags
+out of the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` values and instead
+offer a first-class abstraction. The :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
+variable and :prop_tgt:`MSVC_RUNTIME_LIBRARY` target property may be set to
+select the MSVC runtime library.
+
+This policy provides compatibility with projects that have not been updated
+to be aware of the abstraction. The policy setting takes effect as of the
+first :command:`project` or :command:`enable_language` command that enables
+a language whose compiler targets the MSVC ABI.
+
+.. note::
+
+ Once the policy has taken effect at the top of a project, that choice
+ must be used throughout the tree. In projects that have nested projects
+ in subdirectories, be sure to convert everything together.
+
+The ``OLD`` behavior for this policy is to place MSVC runtime library
+flags in the default :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` cache
+entries and ignore the :variable:`CMAKE_MSVC_RUNTIME_LIBRARY` abstraction.
+The ``NEW`` behavior for this policy is to *not* place MSVC runtime
+library flags in the default cache entries and use the abstraction instead.
+
+This policy was introduced in CMake version 3.15. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
new file mode 100644
index 0000000..2bf71a9
--- /dev/null
+++ b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
@@ -0,0 +1,15 @@
+``MultiThreaded``
+ Compile with ``-MT`` or equivalent flag(s) to use a multi-threaded
+ statically-linked runtime library.
+``MultiThreadedDLL``
+ Compile with ``-MD`` or equivalent flag(s) to use a multi-threaded
+ dynamically-linked runtime library.
+``MultiThreadedDebug``
+ Compile with ``-MTd`` or equivalent flag(s) to use a multi-threaded
+ statically-linked runtime library.
+``MultiThreadedDebugDLL``
+ Compile with ``-MDd`` or equivalent flag(s) to use a multi-threaded
+ dynamically-linked runtime library.
+
+The value is ignored on non-MSVC compilers but an unsupported value will
+be rejected as an error when using a compiler targeting the MSVC ABI.
diff --git a/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst
new file mode 100644
index 0000000..1e3f5e9
--- /dev/null
+++ b/Help/prop_tgt/MSVC_RUNTIME_LIBRARY.rst
@@ -0,0 +1,26 @@
+MSVC_RUNTIME_LIBRARY
+--------------------
+
+Select the MSVC runtime library for use by compilers targeting the MSVC ABI.
+
+The allowed values are:
+
+.. include:: MSVC_RUNTIME_LIBRARY-VALUES.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>` to
+support per-configuration specification. For example, the code:
+
+.. code-block:: cmake
+
+ add_executable(foo foo.c)
+ set_property(TARGET foo PROPERTY
+ MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+
+selects for the target ``foo`` a multi-threaded statically-linked runtime
+library with or without debug information depending on the configuration.
+
+.. note::
+
+ This property has effect only when policy :policy:`CMP0091` is set to ``NEW``
+ prior to the first :command:`project` or :command:`enable_language` command
+ that enables a language using a compiler targeting the MSVC ABI.
diff --git a/Help/release/dev/msvc-runtime-library.rst b/Help/release/dev/msvc-runtime-library.rst
new file mode 100644
index 0000000..4dddac2
--- /dev/null
+++ b/Help/release/dev/msvc-runtime-library.rst
@@ -0,0 +1,7 @@
+msvc-runtime-library
+--------------------
+
+* The :variable:`CMAKE_MSVC_RUNTIME_LIBRARY` variable and
+ :prop_tgt:`MSVC_RUNTIME_LIBRARY` target property were introduced to
+ select the runtime library used by compilers targeting the MSVC ABI.
+ See policy :policy:`CMP0091`.
diff --git a/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst b/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst
new file mode 100644
index 0000000..6ed68c9
--- /dev/null
+++ b/Help/variable/CMAKE_MSVC_RUNTIME_LIBRARY.rst
@@ -0,0 +1,27 @@
+CMAKE_MSVC_RUNTIME_LIBRARY
+--------------------------
+
+Select the MSVC runtime library for use by compilers targeting the MSVC ABI.
+This variable is used to initialize the :prop_tgt:`MSVC_RUNTIME_LIBRARY`
+property on all targets as they are created. It is also propagated by
+calls to the :command:`try_compile` command into the test project.
+
+The allowed values are:
+
+.. include:: ../prop_tgt/MSVC_RUNTIME_LIBRARY-VALUES.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>` to
+support per-configuration specification. For example, the code:
+
+.. code-block:: cmake
+
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+
+selects for all following targets a multi-threaded statically-linked runtime
+library with or without debug information depending on the configuration.
+
+.. note::
+
+ This variable has effect only when policy :policy:`CMP0091` is set to ``NEW``
+ prior to the first :command:`project` or :command:`enable_language` command
+ that enables a language using a compiler targeting the MSVC ABI.
diff --git a/Modules/Platform/Windows-Intel-Fortran.cmake b/Modules/Platform/Windows-Intel-Fortran.cmake
index 3981a09..f00a8e4 100644
--- a/Modules/Platform/Windows-Intel-Fortran.cmake
+++ b/Modules/Platform/Windows-Intel-Fortran.cmake
@@ -4,8 +4,34 @@ set(_COMPILE_Fortran " /fpp")
set(CMAKE_Fortran_MODDIR_FLAG "-module:")
set(CMAKE_Fortran_STANDARD_LIBRARIES_INIT "user32.lib")
__windows_compiler_intel(Fortran)
-string(APPEND CMAKE_Fortran_FLAGS_INIT " /W1 /nologo /fpp /libs:dll /threads")
-string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " /Od /debug:full /dbglibs")
+if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(_LIBSDLL "")
+ set(_DBGLIBS "")
+ set(_THREADS "")
+else()
+ set(_LIBSDLL " /libs:dll")
+ set(_DBGLIBS " /dbglibs")
+ set(_THREADS " /threads")
+endif()
+string(APPEND CMAKE_Fortran_FLAGS_INIT " /W1 /nologo /fpp${_LIBSDLL}${_THREADS}")
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " /Od /debug:full${_DBGLIBS}")
string(APPEND CMAKE_Fortran_FLAGS_MINSIZEREL_INIT " /O1 /DNDEBUG")
string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " /O2 /DNDEBUG")
string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " /O2 /debug:full /DNDEBUG")
+unset(_LIBSDLL)
+unset(_DBGLIBS)
+unset(_THREADS)
+
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -threads -libs:static)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -threads -libs:dll)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -threads -libs:static -dbglibs)
+set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -threads -libs:dll -dbglibs)
+
+# Intel Fortran for Windows supports single-threaded RTL but it is
+# not implemented by the Visual Studio integration.
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreaded -libs:static)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDLL -libs:dll)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDebug -libs:static -dbglibs)
+ set(CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_SingleThreadedDebugDLL -libs:dll -dbglibs)
+endif()
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index df3bd1e..4279a74 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -298,6 +298,14 @@ endforeach()
string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
unset(_MACHINE_ARCH_FLAG)
+cmake_policy(GET CMP0091 __WINDOWS_MSVC_CMP0091)
+if(__WINDOWS_MSVC_CMP0091 STREQUAL "NEW")
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
+else()
+ set(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT "")
+endif()
+unset(__WINDOWS_MSVC_CMP0091)
+
macro(__windows_compiler_msvc lang)
if(NOT MSVC_VERSION LESS 1400)
# for 2005 make sure the manifest is put in the dll with mt
@@ -351,21 +359,35 @@ macro(__windows_compiler_msvc lang)
if("x${lang}" STREQUAL "xC" OR
"x${lang}" STREQUAL "xCXX")
+ if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ set(_MDd "")
+ set(_MD "")
+ else()
+ set(_MDd " /MDd")
+ set(_MD " /MD")
+ endif()
if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
# note: MSVC 14 2015 Update 1 sets -fno-ms-compatibility by default, but this does not allow one to compile many projects
# that include MS's own headers. CMake itself is affected project too.
string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} -fms-extensions -fms-compatibility -D_WINDOWS -Wall${_FLAGS_${lang}}")
- string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " /MDd -gline-tables-only -fno-inline -O0 ${_RTC1}")
- string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " /MD -O2 -DNDEBUG")
- string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " /MD -gline-tables-only -O2 -fno-inline -DNDEBUG")
- string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " /MD -DNDEBUG") # TODO: Add '-Os' once VS generator maps it properly for Clang
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} -gline-tables-only -fno-inline -O0 ${_RTC1}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} -O2 -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} -gline-tables-only -O2 -fno-inline -DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} -DNDEBUG") # TODO: Add '-Os' once VS generator maps it properly for Clang
else()
string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_${lang}} /D_WINDOWS /W3${_FLAGS_${lang}}")
- string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " /MDd /Zi /Ob0 /Od ${_RTC1}")
- string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " /MD /O2 /Ob2 /DNDEBUG")
- string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " /MD /Zi /O2 /Ob1 /DNDEBUG")
- string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " /MD /O1 /Ob1 /DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT "${_MDd} /Zi /Ob0 /Od ${_RTC1}")
+ string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT "${_MD} /O2 /Ob2 /DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT "${_MD} /Zi /O2 /Ob1 /DNDEBUG")
+ string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT "${_MD} /O1 /Ob1 /DNDEBUG")
endif()
+ unset(_MDd)
+ unset(_MD)
+
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -MT)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -MD)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug -MTd)
+ set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL -MDd)
endif()
set(CMAKE_${lang}_LINKER_SUPPORTS_PDB ON)
set(CMAKE_NINJA_DEPTYPE_${lang} msvc)
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index dcb1ff5..897f7a8 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -20,6 +20,7 @@
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmVersion.h"
+#include "cm_static_string_view.hxx"
#include "cmake.h"
static std::string const kCMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN =
@@ -42,6 +43,8 @@ static std::string const kCMAKE_LINK_SEARCH_END_STATIC =
"CMAKE_LINK_SEARCH_END_STATIC";
static std::string const kCMAKE_LINK_SEARCH_START_STATIC =
"CMAKE_LINK_SEARCH_START_STATIC";
+static std::string const kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT =
+ "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT";
static std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES";
static std::string const kCMAKE_OSX_DEPLOYMENT_TARGET =
"CMAKE_OSX_DEPLOYMENT_TARGET";
@@ -500,6 +503,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
fprintf(fout, "set(CMAKE_MODULE_PATH \"%s\")\n", def);
}
+ /* Set MSVC runtime library policy to match our selection. */
+ if (const char* msvcRuntimeLibraryDefault =
+ this->Makefile->GetDefinition(kCMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)) {
+ fprintf(fout, "cmake_policy(SET CMP0091 %s)\n",
+ *msvcRuntimeLibraryDefault ? "NEW" : "OLD");
+ }
+
std::string projectLangs;
for (std::string const& li : testLangs) {
projectLangs += " " + li;
@@ -660,6 +670,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
vars.insert(kCMAKE_SYSROOT_COMPILE);
vars.insert(kCMAKE_SYSROOT_LINK);
vars.insert(kCMAKE_WARN_DEPRECATED);
+ vars.emplace("CMAKE_MSVC_RUNTIME_LIBRARY"_s);
if (const char* varListStr = this->Makefile->GetDefinition(
kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 67763d4..8b51834 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -6,6 +6,7 @@
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionEvaluationFile.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -1519,8 +1520,40 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags,
flagsVar += "_FLAGS";
this->AddConfigVariableFlags(flags, flagsVar, config);
- // Placeholder for possible future per-target flags.
- static_cast<void>(target);
+ // Add MSVC runtime library flags. This is activated by the presence
+ // of a default selection whether or not it is overridden by a property.
+ const char* msvcRuntimeLibraryDefault =
+ this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT");
+ if (msvcRuntimeLibraryDefault && *msvcRuntimeLibraryDefault) {
+ const char* msvcRuntimeLibraryValue =
+ target->GetProperty("MSVC_RUNTIME_LIBRARY");
+ if (!msvcRuntimeLibraryValue) {
+ msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault;
+ }
+ cmGeneratorExpression ge;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(msvcRuntimeLibraryValue);
+ std::string const msvcRuntimeLibrary =
+ cge->Evaluate(this, config, false, target);
+ if (!msvcRuntimeLibrary.empty()) {
+ if (const char* msvcRuntimeLibraryOptions =
+ this->Makefile->GetDefinition(
+ "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" +
+ msvcRuntimeLibrary)) {
+ this->AppendCompileOptions(flags, msvcRuntimeLibraryOptions);
+ } else if ((this->Makefile->GetSafeDefinition(
+ "CMAKE_" + lang + "_COMPILER_ID") == "MSVC" ||
+ this->Makefile->GetSafeDefinition(
+ "CMAKE_" + lang + "_SIMULATE_ID") == "MSVC") &&
+ !cmSystemTools::GetErrorOccuredFlag()) {
+ // The compiler uses the MSVC ABI so it needs a known runtime library.
+ this->IssueMessage(MessageType::FATAL_ERROR,
+ "MSVC_RUNTIME_LIBRARY value '" +
+ msvcRuntimeLibrary + "' not known for this " +
+ lang + " compiler.");
+ }
+ }
+ }
}
void cmLocalGenerator::AddLanguageFlagsForLinking(
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 02a6295..113dd35 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -267,7 +267,10 @@ class cmMakefile;
15, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0090, \
"export(PACKAGE) does not populate package registry by default.", 3, \
- 15, 0, cmPolicies::WARN)
+ 15, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0091, \
+ "MSVC runtime library flags are selected by an abstraction.", 3, 15, \
+ 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index dc9b6d2..9598a3f 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -304,6 +304,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
InitProperty("AUTORCC_OPTIONS", nullptr);
InitProperty("LINK_DEPENDS_NO_SHARED", nullptr);
InitProperty("LINK_INTERFACE_LIBRARIES", nullptr);
+ InitProperty("MSVC_RUNTIME_LIBRARY", nullptr);
InitProperty("WIN32_EXECUTABLE", nullptr);
InitProperty("MACOSX_BUNDLE", nullptr);
InitProperty("MACOSX_RPATH", nullptr);
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index e8b2668..e1b0c70 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -374,19 +374,19 @@ void cmVisualStudioGeneratorOptions::StoreUnknownFlag(std::string const& flag)
{
// Look for Intel Fortran flags that do not map well in the flag table.
if (this->CurrentTool == FortranCompiler) {
- if (flag == "/dbglibs") {
+ if (flag == "/dbglibs" || flag == "-dbglibs") {
this->FortranRuntimeDebug = true;
return;
}
- if (flag == "/threads") {
+ if (flag == "/threads" || flag == "-threads") {
this->FortranRuntimeMT = true;
return;
}
- if (flag == "/libs:dll") {
+ if (flag == "/libs:dll" || flag == "-libs:dll") {
this->FortranRuntimeDLL = true;
return;
}
- if (flag == "/libs:static") {
+ if (flag == "/libs:static" || flag == "-libs:static") {
this->FortranRuntimeDLL = false;
return;
}
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 2e0902c..bc4812b 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1995,6 +1995,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
ADD_TEST_MACRO(PrecompiledHeader foo)
endif()
+ ADD_TEST_MACRO(MSVCRuntimeLibrary)
+ if(CMAKE_Fortran_COMPILER)
+ ADD_TEST_MACRO(MSVCRuntimeLibrary.Fortran)
+ endif()
endif()
if(MSVC OR
"${CMAKE_GENERATOR}" MATCHES "(MSYS|MinGW) Makefiles")
diff --git a/Tests/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/CMakeLists.txt
new file mode 100644
index 0000000..b7a6e86
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/CMakeLists.txt
@@ -0,0 +1,49 @@
+cmake_minimum_required(VERSION 3.14)
+cmake_policy(SET CMP0091 NEW)
+project(MSVCRuntimeLibrary)
+
+function(verify_combinations threads lang src)
+ set(verify_tc_config_ Release)
+ set(verify_tc_config_Debug Debug)
+ set(verify_def_MultiThreaded -DVERIFY_MT)
+ set(verify_def_Debug -DVERIFY_DEBUG)
+ set(verify_def_DLL -DVERIFY_DLL)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ # Construct the name of this runtime library combination.
+ set(rtl "${threads}${dbg}${dll}")
+
+ # Test that try_compile builds with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "${rtl}")
+ set(CMAKE_TRY_COMPILE_CONFIGURATION "${verify_tc_config_${dbg}}")
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+ try_compile(${rtl}_COMPILES
+ ${CMAKE_CURRENT_BINARY_DIR}/try_compile/${rtl}
+ ${CMAKE_CURRENT_SOURCE_DIR}/${src}
+ COMPILE_DEFINITIONS ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}}
+ OUTPUT_VARIABLE ${rtl}_OUTPUT
+ )
+ if(${rtl}_COMPILES)
+ message(STATUS "try_compile with ${rtl} worked")
+ else()
+ string(REPLACE "\n" "\n " ${rtl}_OUTPUT " ${${rtl}_OUTPUT}")
+ message(SEND_ERROR "try_compile with ${rtl} failed:\n${${rtl}_OUTPUT}")
+ endif()
+
+ # Test that targets build with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${rtl}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>")
+ add_library(${rtl}-${lang} ${src})
+ set_property(TARGET ${rtl}-${lang} PROPERTY BOOL_TRUE TRUE)
+ target_compile_definitions(${rtl}-${lang} PRIVATE ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}})
+ endforeach()
+ endforeach()
+endfunction()
+
+function(verify lang src)
+ add_library(default-${lang} ${src})
+ target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>")
+ verify_combinations(MultiThreaded ${lang} ${src})
+endfunction()
+
+verify(C verify.c)
+verify(CXX verify.cxx)
diff --git a/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt
new file mode 100644
index 0000000..169ba07
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/Fortran/CMakeLists.txt
@@ -0,0 +1,50 @@
+cmake_minimum_required(VERSION 3.14)
+cmake_policy(SET CMP0091 NEW)
+project(MSVCRuntimeLibraryFortran Fortran)
+
+foreach(t MultiThreaded SingleThreaded)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ set(var "CMAKE_Fortran_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_${t}${dbg}${dll}")
+ # ifort does not actually define these, so inject them
+ string(REPLACE "-threads" "-threads;-D_MT" "${var}" "${${var}}")
+ string(REPLACE "-dbglibs" "-dbglibs;-D_DEBUG" "${var}" "${${var}}")
+ endforeach()
+ endforeach()
+endforeach()
+string(APPEND CMAKE_Fortran_FLAGS " -w")
+
+function(verify_combinations threads lang src)
+ set(verify_tc_config_ Release)
+ set(verify_tc_config_Debug Debug)
+ set(verify_def_MultiThreaded -DVERIFY_MT)
+ set(verify_def_Debug -DVERIFY_DEBUG)
+ set(verify_def_DLL -DVERIFY_DLL)
+ foreach(dbg "" Debug)
+ foreach(dll "" DLL)
+ # Construct the name of this runtime library combination.
+ set(rtl "${threads}${dbg}${dll}")
+
+ # Test that targets build with this RTL.
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "$<$<BOOL:$<TARGET_PROPERTY:BOOL_TRUE>>:${rtl}>$<$<BOOL:$<TARGET_PROPERTY:BOOL_FALSE>>:BadContent>")
+ add_library(${rtl}-${lang} ${src})
+ set_property(TARGET ${rtl}-${lang} PROPERTY BOOL_TRUE TRUE)
+ target_compile_definitions(${rtl}-${lang} PRIVATE ${verify_def_${threads}} ${verify_def_${dbg}} ${verify_def_${dll}})
+ endforeach()
+ endforeach()
+endfunction()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+function(verify lang src)
+ add_library(default-${lang} ${src})
+ target_compile_definitions(default-${lang} PRIVATE VERIFY_MT VERIFY_DLL "$<$<CONFIG:Debug>:VERIFY_DEBUG>")
+ verify_combinations(MultiThreaded ${lang} ${src})
+endfunction()
+
+verify(Fortran verify.F90)
+# Intel Fortran for Windows supports single-threaded RTL but it is
+# not implemented by the Visual Studio integration.
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+ verify_combinations(SingleThreaded Fortran verify.F90)
+endif()
diff --git a/Tests/MSVCRuntimeLibrary/Fortran/verify.F90 b/Tests/MSVCRuntimeLibrary/Fortran/verify.F90
new file mode 100644
index 0000000..6fe5e05
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/Fortran/verify.F90
@@ -0,0 +1 @@
+#include "../verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.c b/Tests/MSVCRuntimeLibrary/verify.c
new file mode 100644
index 0000000..741bca6
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.c
@@ -0,0 +1 @@
+#include "verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.cxx b/Tests/MSVCRuntimeLibrary/verify.cxx
new file mode 100644
index 0000000..741bca6
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.cxx
@@ -0,0 +1 @@
+#include "verify.h"
diff --git a/Tests/MSVCRuntimeLibrary/verify.h b/Tests/MSVCRuntimeLibrary/verify.h
new file mode 100644
index 0000000..58d65fe
--- /dev/null
+++ b/Tests/MSVCRuntimeLibrary/verify.h
@@ -0,0 +1,29 @@
+#ifdef VERIFY_DEBUG
+# ifndef _DEBUG
+# error "_DEBUG not defined by debug runtime library selection"
+# endif
+#else
+# ifdef _DEBUG
+# error "_DEBUG defined by non-debug runtime library selection"
+# endif
+#endif
+
+#ifdef VERIFY_DLL
+# ifndef _DLL
+# error "_DLL not defined by DLL runtime library selection"
+# endif
+#else
+# ifdef _DLL
+# error "_DLL defined by non-DLL runtime library selection"
+# endif
+#endif
+
+#ifdef VERIFY_MT
+# ifndef _MT
+# error "_MT not defined by multi-threaded runtime library selection"
+# endif
+#else
+# ifdef _MT
+# error "_MT defined by single-threaded runtime library selection"
+# endif
+#endif
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 68411d6..a8dcb4b 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -195,6 +195,9 @@ add_RunCMake_test(LinkStatic)
if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|XL|XLClang)$")
add_RunCMake_test(MetaCompileFeatures)
endif()
+if(MSVC)
+ add_RunCMake_test(MSVCRuntimeLibrary)
+endif()
add_RunCMake_test(ObjectLibrary)
add_RunCMake_test(ParseImplicitIncludeInfo)
if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt
new file mode 100644
index 0000000..803058d
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error in CMakeLists.txt:
+ MSVC_RUNTIME_LIBRARY value 'BogusValue' not known for this C compiler.$
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake
new file mode 100644
index 0000000..c3ea2fd
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0091 NEW)
+include(CMP0091-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake
new file mode 100644
index 0000000..734cc9f
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0091 OLD)
+include(CMP0091-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake
new file mode 100644
index 0000000..26f86a0
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0091-common.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake
new file mode 100644
index 0000000..7827d2a
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMP0091-common.cmake
@@ -0,0 +1,37 @@
+enable_language(C)
+
+cmake_policy(GET CMP0091 cmp0091)
+if(cmp0091 STREQUAL "NEW")
+ if(NOT CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ message(SEND_ERROR "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT not set under NEW behavior")
+ endif()
+else()
+ if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
+ message(SEND_ERROR "CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT is set under OLD behavior")
+ endif()
+endif()
+
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+ if(CMAKE_C_FLAGS_DEBUG MATCHES "[/-]MDd( |$)")
+ set(have_MDd 1)
+ else()
+ set(have_MDd 0)
+ endif()
+ if(CMAKE_C_FLAGS_RELEASE MATCHES "[/-]MD( |$)")
+ set(have_MD 1)
+ else()
+ set(have_MD 0)
+ endif()
+ if(cmp0091 STREQUAL "NEW")
+ if(have_MDd OR have_MD)
+ message(SEND_ERROR "Have a -MD* flag under NEW behavior.")
+ endif()
+ else()
+ if(NOT (have_MDd AND have_MD))
+ message(SEND_ERROR "Do not have -MD* flags under OLD behavior.")
+ endif()
+ endif()
+endif()
+
+set(CMAKE_MSVC_RUNTIME_LIBRARY BogusValue)
+add_library(foo empty.c)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt
new file mode 100644
index 0000000..3e470a2
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.14)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake b/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake
new file mode 100644
index 0000000..fad18da
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0091-WARN)
+run_cmake(CMP0091-OLD)
+run_cmake(CMP0091-NEW)
diff --git a/Tests/RunCMake/MSVCRuntimeLibrary/empty.c b/Tests/RunCMake/MSVCRuntimeLibrary/empty.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeLibrary/empty.c
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 219e529..0ac589d 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -2,6 +2,7 @@ include(RunCMake)
run_cmake(VsCSharpCompilerOpts)
run_cmake(ExplicitCMakeLists)
+run_cmake(RuntimeLibrary)
run_cmake(SourceGroupCMakeLists)
run_cmake(VsConfigurationType)
diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake
new file mode 100644
index 0000000..6b43d47
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake
@@ -0,0 +1,34 @@
+macro(RuntimeLibrary_check tgt rtl_expect)
+ set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/${tgt}.vcxproj")
+ if(NOT EXISTS "${vcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not exist.")
+ return()
+ endif()
+
+ set(HAVE_Runtimelibrary 0)
+
+ file(STRINGS "${vcProjectFile}" lines)
+ foreach(line IN LISTS lines)
+ if(line MATCHES "^ *<RuntimeLibrary>([^<>]+)</RuntimeLibrary>")
+ set(rtl_actual "${CMAKE_MATCH_1}")
+ if(NOT "${rtl_actual}" STREQUAL "${rtl_expect}")
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has RuntimeLibrary '${rtl_actual}', not '${rtl_expect}'.")
+ return()
+ endif()
+ set(HAVE_Runtimelibrary 1)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT HAVE_Runtimelibrary)
+ set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a RuntimeLibrary field.")
+ return()
+ endif()
+endmacro()
+
+RuntimeLibrary_check(default-C MultiThreadedDebugDLL)
+RuntimeLibrary_check(default-CXX MultiThreadedDebugDLL)
+RuntimeLibrary_check(MTd-C MultiThreadedDebug)
+RuntimeLibrary_check(MTd-CXX MultiThreadedDebug)
+RuntimeLibrary_check(MT-C MultiThreaded)
+RuntimeLibrary_check(MT-CXX MultiThreaded)
diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake
new file mode 100644
index 0000000..6c77a25
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake
@@ -0,0 +1,16 @@
+set(CMAKE_CONFIGURATION_TYPES Debug)
+cmake_policy(SET CMP0091 NEW)
+enable_language(C)
+enable_language(CXX)
+
+add_library(default-C empty.c)
+add_library(default-CXX empty.cxx)
+
+set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebug")
+add_library(MTd-C empty.c)
+add_library(MTd-CXX empty.cxx)
+
+add_library(MT-C empty.c)
+set_property(TARGET MT-C PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
+add_library(MT-CXX empty.cxx)
+set_property(TARGET MT-CXX PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
diff --git a/Tests/RunCMake/VS10Project/empty.c b/Tests/RunCMake/VS10Project/empty.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/empty.c
diff --git a/Tests/RunCMake/VS10Project/empty.cxx b/Tests/RunCMake/VS10Project/empty.cxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/empty.cxx