From 0ae372daee75e6d5305ec9f934c2adce3074ca5d Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Thu, 15 Feb 2024 13:53:01 -0500
Subject: VS: Factor out common MS tool configuration

De-duplicate code writing `PlatformToolset`.
---
 Source/cmVisualStudio10TargetGenerator.cxx | 31 +++++++++++++++---------------
 Source/cmVisualStudio10TargetGenerator.h   |  2 ++
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index d572f30..ced7acd 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1512,7 +1512,6 @@ void cmVisualStudio10TargetGenerator::WriteCEDebugProjectConfigurationValues(
 void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
   Elem& e1, std::string const& config)
 {
-  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   cmValue mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
   if (mfcFlag) {
     std::string const mfcFlagValue =
@@ -1543,12 +1542,9 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
   } else {
     e1.Element("CharacterSet", "MultiByte");
   }
-  if (cmValue projectToolsetOverride =
-        this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
-    e1.Element("PlatformToolset", *projectToolsetOverride);
-  } else if (const char* toolset = gg->GetPlatformToolset()) {
-    e1.Element("PlatformToolset", toolset);
-  }
+
+  this->WriteMSToolConfigurationValuesCommon(e1, config);
+
   if (this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_COMPONENT") ||
       this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) {
     e1.Element("WindowsAppContainer", "true");
@@ -1579,8 +1575,6 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
     return;
   }
 
-  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
-
   Options& o = *(this->ClOptions[config]);
 
   if (o.IsDebug()) {
@@ -1598,12 +1592,7 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
     o.RemoveFlag("Platform");
   }
 
-  if (cmValue projectToolsetOverride =
-        this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
-    e1.Element("PlatformToolset", *projectToolsetOverride);
-  } else if (const char* toolset = gg->GetPlatformToolset()) {
-    e1.Element("PlatformToolset", toolset);
-  }
+  this->WriteMSToolConfigurationValuesCommon(e1, config);
 
   std::string postfixName =
     cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
@@ -1623,6 +1612,18 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
   oh.OutputFlagMap();
 }
 
+void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesCommon(
+  Elem& e1, std::string const& config)
+{
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+  if (cmValue projectToolsetOverride =
+        this->GeneratorTarget->GetProperty("VS_PLATFORM_TOOLSET")) {
+    e1.Element("PlatformToolset", *projectToolsetOverride);
+  } else if (const char* toolset = gg->GetPlatformToolset()) {
+    e1.Element("PlatformToolset", toolset);
+  }
+}
+
 //----------------------------------------------------------------------------
 void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues(
   Elem& e1, std::string const&)
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 2080e9e..bafd5e9 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -72,6 +72,8 @@ private:
   void WriteCEDebugProjectConfigurationValues(Elem& e0);
   void WriteMSToolConfigurationValuesManaged(Elem& e1,
                                              std::string const& config);
+  void WriteMSToolConfigurationValuesCommon(Elem& e1,
+                                            std::string const& config);
   void WriteHeaderSource(Elem& e1, cmSourceFile const* sf,
                          ConfigToSettings const& toolSettings);
   void WriteExtraSource(Elem& e1, cmSourceFile const* sf,
-- 
cgit v0.12


From 67de5b7b82c6f61c5d349c70de81dde58bb79dd1 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Tue, 13 Feb 2024 15:16:26 -0500
Subject: VS: Suppress MSBuild default settings affected by UseDebugLibraries

`Microsoft.Cl.Common.props` changes some default settings based on
`UseDebugLibraries`.  CMake models its own controls for these settings,
so if the project does not set them, explicitly suppress them to avoid
letting `UseDebugLibraries` affect them.
---
 Source/cmVisualStudio10TargetGenerator.cxx         | 22 +++++++++++++++++++++-
 Tests/MSVCRuntimeLibrary/CMakeLists.txt            |  4 ----
 .../VS10Project/RuntimeLibrary-check.cmake         |  2 +-
 .../RunCMake/VS10Project/VsJustMyCode-check.cmake  |  2 +-
 4 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index ced7acd..8114b83 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -3155,7 +3155,10 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental(
   Options& linkOptions = *(this->LinkOptions[configName]);
   const std::string cond = this->CalcCondition(configName);
 
-  if (this->IPOEnabledConfigurations.count(configName) == 0) {
+  if (this->IPOEnabledConfigurations.count(configName) > 0) {
+    // Suppress LinkIncremental in favor of WholeProgramOptimization.
+    e1.WritePlatformConfigTag("LinkIncremental", cond, "");
+  } else {
     const char* incremental = linkOptions.GetFlag("LinkIncremental");
     e1.WritePlatformConfigTag("LinkIncremental", cond,
                               (incremental ? incremental : "true"));
@@ -3500,6 +3503,23 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
     clOptions.RemoveFlag("CompileAs");
   }
 
+  if (this->ProjectType == VsProjectType::vcxproj && this->MSTools) {
+    // Suppress Microsoft.Cl.Common.props default settings for which the
+    // project specifies no flags.  Do not let UseDebugLibraries affect them.
+    if (!clOptions.HasFlag("BasicRuntimeChecks")) {
+      clOptions.AddFlag("BasicRuntimeChecks", "Default");
+    }
+    if (!clOptions.HasFlag("Optimization")) {
+      clOptions.AddFlag("Optimization", "");
+    }
+    if (!clOptions.HasFlag("RuntimeLibrary")) {
+      clOptions.AddFlag("RuntimeLibrary", "");
+    }
+    if (!clOptions.HasFlag("SupportJustMyCode")) {
+      clOptions.AddFlag("SupportJustMyCode", "");
+    }
+  }
+
   this->ClOptions[configName] = std::move(pOptions);
   return true;
 }
diff --git a/Tests/MSVCRuntimeLibrary/CMakeLists.txt b/Tests/MSVCRuntimeLibrary/CMakeLists.txt
index f7d9fec..f1ed9b4 100644
--- a/Tests/MSVCRuntimeLibrary/CMakeLists.txt
+++ b/Tests/MSVCRuntimeLibrary/CMakeLists.txt
@@ -57,10 +57,6 @@ function(verify lang src)
       # VS 2005 and above default to multi-threaded.
       target_compile_definitions(empty-${lang} PRIVATE VERIFY_MT)
     endif()
-    if(CMAKE_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])")
-      # VS 2010 and above have a different default runtime library for projects than 'cl'.
-      target_compile_definitions(empty-${lang} PRIVATE VERIFY_DLL)
-    endif()
   endif()
 endfunction()
 
diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake
index 689b35f..b5b195a 100644
--- a/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake
+++ b/Tests/RunCMake/VS10Project/RuntimeLibrary-check.cmake
@@ -9,7 +9,7 @@ macro(RuntimeLibrary_check tgt rtl_expect)
 
   file(STRINGS "${vcProjectFile}" lines)
   foreach(line IN LISTS lines)
-    if(line MATCHES "^ *<RuntimeLibrary>([^<>]+)</RuntimeLibrary>")
+    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}'.")
diff --git a/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake b/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake
index 7119976..e76d931 100644
--- a/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake
+++ b/Tests/RunCMake/VS10Project/VsJustMyCode-check.cmake
@@ -9,7 +9,7 @@ macro(VsJustMyCode_check tgt jmc_expect)
 
   file(STRINGS "${vcProjectFile}" lines)
   foreach(line IN LISTS lines)
-    if(line MATCHES "^ *<SupportJustMyCode>([^<>]+)</SupportJustMyCode>")
+    if(line MATCHES "^ *<SupportJustMyCode>([^<>]*)</SupportJustMyCode>")
       set(jmc_actual "${CMAKE_MATCH_1}")
       if(NOT "${jmc_actual}" STREQUAL "${jmc_expect}")
         set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has <SupportJustMyCode> '${jmc_actual}', not '${jmc_expect}'.")
-- 
cgit v0.12


From b81464144468e930acc5bf55243dbb0a0f3ae0fb Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 16 Feb 2024 12:15:23 -0500
Subject: VS: Add [CMAKE_]VS_USE_DEBUG_LIBRARIES options to control
 UseDebugLibraries

This indicates to MSBuild which configurations are considered debug
configurations.  This is useful for reference both by humans and tools.

Issue: #25327
---
 Help/manual/cmake-properties.7.rst                 |  1 +
 Help/manual/cmake-variables.7.rst                  |  1 +
 Help/prop_tgt/VS_USE_DEBUG_LIBRARIES-PURPOSE.txt   | 18 ++++++++++
 Help/prop_tgt/VS_USE_DEBUG_LIBRARIES.rst           | 27 ++++++++++++++
 Help/release/dev/vs-UseDebugLibraries.rst          |  6 ++++
 Help/variable/CMAKE_VS_USE_DEBUG_LIBRARIES.rst     | 28 +++++++++++++++
 Source/cmCoreTryCompile.cxx                        |  1 +
 Source/cmTarget.cxx                                |  1 +
 Source/cmVisualStudio10TargetGenerator.cxx         | 19 ++++++++++
 Tests/RunCMake/CMakeLists.txt                      |  1 +
 .../VS10ProjectUseDebugLibraries/CMakeLists.txt    |  3 ++
 .../Default-check.cmake                            |  8 +++++
 .../VS10ProjectUseDebugLibraries/Default.cmake     | 10 ++++++
 .../Explicit-check.cmake                           | 10 ++++++
 .../VS10ProjectUseDebugLibraries/Explicit.cmake    | 20 +++++++++++
 .../RunCMakeTest.cmake                             |  5 +++
 .../check-common.cmake                             | 42 ++++++++++++++++++++++
 .../VS10ProjectUseDebugLibraries/empty.cxx         |  0
 18 files changed, 201 insertions(+)
 create mode 100644 Help/prop_tgt/VS_USE_DEBUG_LIBRARIES-PURPOSE.txt
 create mode 100644 Help/prop_tgt/VS_USE_DEBUG_LIBRARIES.rst
 create mode 100644 Help/release/dev/vs-UseDebugLibraries.rst
 create mode 100644 Help/variable/CMAKE_VS_USE_DEBUG_LIBRARIES.rst
 create mode 100644 Tests/RunCMake/VS10ProjectUseDebugLibraries/CMakeLists.txt
 create mode 100644 Tests/RunCMake/VS10ProjectUseDebugLibraries/Default-check.cmake
 create mode 100644 Tests/RunCMake/VS10ProjectUseDebugLibraries/Default.cmake
 create mode 100644 Tests/RunCMake/VS10ProjectUseDebugLibraries/Explicit-check.cmake
 create mode 100644 Tests/RunCMake/VS10ProjectUseDebugLibraries/Explicit.cmake
 create mode 100644 Tests/RunCMake/VS10ProjectUseDebugLibraries/RunCMakeTest.cmake
 create mode 100644 Tests/RunCMake/VS10ProjectUseDebugLibraries/check-common.cmake
 create mode 100644 Tests/RunCMake/VS10ProjectUseDebugLibraries/empty.cxx

diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 0d1046a..8d2d202 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -445,6 +445,7 @@ Properties on Targets
    /prop_tgt/VS_SDK_REFERENCES
    /prop_tgt/VS_SOLUTION_DEPLOY
    /prop_tgt/VS_SOURCE_SETTINGS_tool
+   /prop_tgt/VS_USE_DEBUG_LIBRARIES
    /prop_tgt/VS_USER_PROPS
    /prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
    /prop_tgt/VS_WINRT_COMPONENT
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 8a5ab30..c7efdcf 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -137,6 +137,7 @@ Variables that Provide Information
    /variable/CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER
    /variable/CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION
    /variable/CMAKE_VS_TARGET_FRAMEWORK_VERSION
+   /variable/CMAKE_VS_USE_DEBUG_LIBRARIES
    /variable/CMAKE_VS_VERSION_BUILD_NUMBER
    /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
    /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
diff --git a/Help/prop_tgt/VS_USE_DEBUG_LIBRARIES-PURPOSE.txt b/Help/prop_tgt/VS_USE_DEBUG_LIBRARIES-PURPOSE.txt
new file mode 100644
index 0000000..8d3714e
--- /dev/null
+++ b/Help/prop_tgt/VS_USE_DEBUG_LIBRARIES-PURPOSE.txt
@@ -0,0 +1,18 @@
+Indicate to :ref:`Visual Studio Generators` what configurations are considered
+debug configurations.  This controls the ``UseDebugLibraries`` setting in
+each configuration of a ``.vcxproj`` file.
+
+The "Use Debug Libraries" setting in Visual Studio projects, despite its
+specific-sounding name, is a general-purpose indicator of what configurations
+are considered debug configurations.  In standalone projects, this may affect
+MSBuild's default selection of MSVC runtime library, optimization flags,
+runtime checks, and similar settings.  In CMake projects those settings are
+typically generated explicitly based on the project's specification, e.g.,
+the MSVC runtime library is controlled by |MSVC_RUNTIME_LIBRARY|.  However,
+the ``UseDebugLibraries`` indicator is useful for reference by both humans
+and tools, and may also affect the behavior of platform-specific SDKs.
+
+Set |VS_USE_DEBUG_LIBRARIES| to a true or false value to indicate whether
+each configuration is considered a debug configuration.  The value may also
+be the empty string (``""``) in which case no ``UseDebugLibraries`` will be
+added explicitly by CMake, and MSBuild will use its default value, ``false``.
diff --git a/Help/prop_tgt/VS_USE_DEBUG_LIBRARIES.rst b/Help/prop_tgt/VS_USE_DEBUG_LIBRARIES.rst
new file mode 100644
index 0000000..78ad36a
--- /dev/null
+++ b/Help/prop_tgt/VS_USE_DEBUG_LIBRARIES.rst
@@ -0,0 +1,27 @@
+VS_USE_DEBUG_LIBRARIES
+----------------------
+
+.. versionadded:: 3.30
+
+.. |VS_USE_DEBUG_LIBRARIES| replace:: ``VS_USE_DEBUG_LIBRARIES``
+.. |MSVC_RUNTIME_LIBRARY| replace:: :prop_tgt:`MSVC_RUNTIME_LIBRARY`
+
+.. include:: VS_USE_DEBUG_LIBRARIES-PURPOSE.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>`
+for per-configuration specification.  For example, the code:
+
+.. code-block:: cmake
+
+  add_executable(foo foo.c)
+  set_property(TARGET foo PROPERTY
+    VS_USE_DEBUG_LIBRARIES "$<CONFIG:Debug,Custom>")
+
+indicates that target ``foo`` considers its "Debug" and "Custom"
+configurations to be debug configurations, and its other configurations
+to be non-debug configurations.
+
+The property is initialized from the value of the
+:variable:`CMAKE_VS_USE_DEBUG_LIBRARIES` variable, if it is set.
+If the property is not set, then CMake does not generate any
+``UseDebugLibraries`` indicator.
diff --git a/Help/release/dev/vs-UseDebugLibraries.rst b/Help/release/dev/vs-UseDebugLibraries.rst
new file mode 100644
index 0000000..477c385
--- /dev/null
+++ b/Help/release/dev/vs-UseDebugLibraries.rst
@@ -0,0 +1,6 @@
+vs-UseDebugLibraries
+--------------------
+
+* The :variable:`CMAKE_VS_USE_DEBUG_LIBRARIES` variable and corresponding
+  :prop_tgt:`VS_USE_DEBUG_LIBRARIES` target property were added to explicitly
+  control ``UseDebugLibraries`` indicators in ``.vcxproj`` files.
diff --git a/Help/variable/CMAKE_VS_USE_DEBUG_LIBRARIES.rst b/Help/variable/CMAKE_VS_USE_DEBUG_LIBRARIES.rst
new file mode 100644
index 0000000..45d3eff
--- /dev/null
+++ b/Help/variable/CMAKE_VS_USE_DEBUG_LIBRARIES.rst
@@ -0,0 +1,28 @@
+CMAKE_VS_USE_DEBUG_LIBRARIES
+----------------------------
+
+.. versionadded:: 3.30
+
+.. |VS_USE_DEBUG_LIBRARIES| replace:: ``CMAKE_VS_USE_DEBUG_LIBRARIES``
+.. |MSVC_RUNTIME_LIBRARY| replace:: :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
+
+.. include:: ../prop_tgt/VS_USE_DEBUG_LIBRARIES-PURPOSE.txt
+
+Use :manual:`generator expressions <cmake-generator-expressions(7)>`
+for per-configuration specification.  For example, the code:
+
+.. code-block:: cmake
+
+  set(CMAKE_VS_USE_DEBUG_LIBRARIES "$<CONFIG:Debug,Custom>")
+
+indicates that all following targets consider their "Debug" and "Custom"
+configurations to be debug configurations, and their other configurations
+to be non-debug configurations.
+
+This variable is used to initialize the :prop_tgt:`VS_USE_DEBUG_LIBRARIES`
+property on all targets as they are created.  It is also propagated by
+calls to the :command:`try_compile` command into its test project.
+
+If this variable is not set then the :prop_tgt:`VS_USE_DEBUG_LIBRARIES`
+property will not be set automatically.  If that property is not set
+then CMake does not generate any ``UseDebugLibraries`` indicator.
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index a4f36cc..25fc52f 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -1151,6 +1151,7 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
     vars.emplace("CMAKE_WATCOM_RUNTIME_LIBRARY"_s);
     vars.emplace("CMAKE_MSVC_DEBUG_INFORMATION_FORMAT"_s);
     vars.emplace("CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS"_s);
+    vars.emplace("CMAKE_VS_USE_DEBUG_LIBRARIES"_s);
 
     if (cmValue varListStr = this->Makefile->GetDefinition(
           kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) {
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index e6e1ac4..e13e667 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -404,6 +404,7 @@ TargetProperty const StaticTargetProperties[] = {
   { "VS_DEBUGGER_COMMAND_ARGUMENTS"_s, IC::ExecutableTarget },
   { "VS_DEBUGGER_ENVIRONMENT"_s, IC::ExecutableTarget },
   { "VS_DEBUGGER_WORKING_DIRECTORY"_s, IC::ExecutableTarget },
+  { "VS_USE_DEBUG_LIBRARIES"_s, IC::NonImportedTarget },
   // ---- OpenWatcom
   { "WATCOM_RUNTIME_LIBRARY"_s, IC::CanCompileSources },
   // -- Language
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 8114b83..38a2ed8 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1622,6 +1622,25 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesCommon(
   } else if (const char* toolset = gg->GetPlatformToolset()) {
     e1.Element("PlatformToolset", toolset);
   }
+
+  cm::optional<bool> maybeUseDebugLibraries;
+  if (cmValue useDebugLibrariesProp =
+        this->GeneratorTarget->GetProperty("VS_USE_DEBUG_LIBRARIES")) {
+    // The project explicitly specified a value for this target.
+    // An empty string suppresses generation of the setting altogether.
+    std::string const useDebugLibraries = cmGeneratorExpression::Evaluate(
+      *useDebugLibrariesProp, this->LocalGenerator, config);
+    if (!useDebugLibraries.empty()) {
+      maybeUseDebugLibraries = cmIsOn(useDebugLibraries);
+    }
+  }
+  if (maybeUseDebugLibraries) {
+    if (*maybeUseDebugLibraries) {
+      e1.Element("UseDebugLibraries", "true");
+    } else {
+      e1.Element("UseDebugLibraries", "false");
+    }
+  }
 }
 
 //----------------------------------------------------------------------------
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index d9090d6..a2a9ee9 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -731,6 +731,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Visual Studio ([^9]|9[0-9])")
     -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
     -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION}
     )
+  add_RunCMake_test(VS10ProjectUseDebugLibraries)
   if( vs12 AND wince )
     add_RunCMake_test( VS10ProjectWinCE "-DRunCMake_GENERATOR_PLATFORM=${wince_sdk}")
   endif()
diff --git a/Tests/RunCMake/VS10ProjectUseDebugLibraries/CMakeLists.txt b/Tests/RunCMake/VS10ProjectUseDebugLibraries/CMakeLists.txt
new file mode 100644
index 0000000..94e43ba
--- /dev/null
+++ b/Tests/RunCMake/VS10ProjectUseDebugLibraries/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.29)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/VS10ProjectUseDebugLibraries/Default-check.cmake b/Tests/RunCMake/VS10ProjectUseDebugLibraries/Default-check.cmake
new file mode 100644
index 0000000..673144e
--- /dev/null
+++ b/Tests/RunCMake/VS10ProjectUseDebugLibraries/Default-check.cmake
@@ -0,0 +1,8 @@
+include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
+
+UseDebugLibraries_check(default "" "")
+UseDebugLibraries_check(defaultCLR "" "")
+UseDebugLibraries_check(defaultUtil "" "")
+UseDebugLibraries_check(defaultRTL "" "")
+UseDebugLibraries_check(ALL_BUILD "" "")
+UseDebugLibraries_check(ZERO_CHECK "" "")
diff --git a/Tests/RunCMake/VS10ProjectUseDebugLibraries/Default.cmake b/Tests/RunCMake/VS10ProjectUseDebugLibraries/Default.cmake
new file mode 100644
index 0000000..6afcfb6
--- /dev/null
+++ b/Tests/RunCMake/VS10ProjectUseDebugLibraries/Default.cmake
@@ -0,0 +1,10 @@
+set(CMAKE_CONFIGURATION_TYPES Debug Release)
+enable_language(CXX)
+
+# Test several generator code paths covering different target types.
+add_library(default empty.cxx)
+add_library(defaultCLR empty.cxx)
+set_property(TARGET defaultCLR PROPERTY COMMON_LANGUAGE_RUNTIME "")
+add_library(defaultRTL empty.cxx)
+set_property(TARGET defaultRTL PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
+add_custom_target(defaultUtil)
diff --git a/Tests/RunCMake/VS10ProjectUseDebugLibraries/Explicit-check.cmake b/Tests/RunCMake/VS10ProjectUseDebugLibraries/Explicit-check.cmake
new file mode 100644
index 0000000..385b798
--- /dev/null
+++ b/Tests/RunCMake/VS10ProjectUseDebugLibraries/Explicit-check.cmake
@@ -0,0 +1,10 @@
+include(${CMAKE_CURRENT_LIST_DIR}/check-common.cmake)
+
+UseDebugLibraries_check(empty "" "")
+UseDebugLibraries_check(emptyCLR "" "")
+UseDebugLibraries_check(emptyUtil "" "")
+UseDebugLibraries_check(genex "true" "false")
+UseDebugLibraries_check(genexCLR "true" "false")
+UseDebugLibraries_check(genexUtil "true" "false")
+UseDebugLibraries_check(ALL_BUILD "false" "false")
+UseDebugLibraries_check(ZERO_CHECK "false" "false")
diff --git a/Tests/RunCMake/VS10ProjectUseDebugLibraries/Explicit.cmake b/Tests/RunCMake/VS10ProjectUseDebugLibraries/Explicit.cmake
new file mode 100644
index 0000000..3433745
--- /dev/null
+++ b/Tests/RunCMake/VS10ProjectUseDebugLibraries/Explicit.cmake
@@ -0,0 +1,20 @@
+set(CMAKE_CONFIGURATION_TYPES Debug Release)
+enable_language(CXX)
+
+# An empty string suppresses generation of the setting.
+set(CMAKE_VS_USE_DEBUG_LIBRARIES "")
+add_library(empty empty.cxx)
+add_library(emptyCLR empty.cxx)
+set_property(TARGET emptyCLR PROPERTY COMMON_LANGUAGE_RUNTIME "")
+add_custom_target(emptyUtil)
+
+# A generator expression can encode per-config values.
+set(CMAKE_VS_USE_DEBUG_LIBRARIES "$<CONFIG:Debug>")
+add_library(genex empty.cxx)
+add_library(genexCLR empty.cxx)
+set_property(TARGET genexCLR PROPERTY COMMON_LANGUAGE_RUNTIME "")
+add_custom_target(genexUtil)
+
+# The last setting in the top-level directcory affects
+# the builtin targets like ALL_BUILD and ZERO_CHECK.
+set(CMAKE_VS_USE_DEBUG_LIBRARIES 0)
diff --git a/Tests/RunCMake/VS10ProjectUseDebugLibraries/RunCMakeTest.cmake b/Tests/RunCMake/VS10ProjectUseDebugLibraries/RunCMakeTest.cmake
new file mode 100644
index 0000000..8db2028
--- /dev/null
+++ b/Tests/RunCMake/VS10ProjectUseDebugLibraries/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.29)
+include(RunCMake)
+
+run_cmake(Default)
+run_cmake(Explicit)
diff --git a/Tests/RunCMake/VS10ProjectUseDebugLibraries/check-common.cmake b/Tests/RunCMake/VS10ProjectUseDebugLibraries/check-common.cmake
new file mode 100644
index 0000000..311c8a7
--- /dev/null
+++ b/Tests/RunCMake/VS10ProjectUseDebugLibraries/check-common.cmake
@@ -0,0 +1,42 @@
+cmake_policy(SET CMP0140 NEW)
+function(UseDebugLibraries_check tgt udl_expect_debug udl_expect_release)
+  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_udl_debug 0)
+  set(have_udl_release 0)
+  set(inConfig "")
+
+  file(STRINGS "${vcProjectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES [[^ *<PropertyGroup Condition="'\$\(Configuration\)\|\$\(Platform\)'=='([^"|]+)\|[^"]+" Label="Configuration">.*$]])
+      string(TOLOWER "${CMAKE_MATCH_1}" inConfig)
+    elseif(inConfig)
+      if(line MATCHES "^ *</PropertyGroup>.*$")
+        set(inConfig "")
+      elseif(line MATCHES "^ *<UseDebugLibraries>([^<>]+)</UseDebugLibraries>")
+        set(udl_actual "${CMAKE_MATCH_1}")
+        set(have_udl_${inConfig} 1)
+        if (NOT "${udl_expect_${inConfig}}" STREQUAL "")
+          if(NOT "${udl_actual}" STREQUAL "${udl_expect_${inConfig}}")
+            string(APPEND RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has ${inConfig} UseDebugLibraries '${udl_actual}', not '${udl_expect_${inConfig}}'.\n")
+          endif()
+        else()
+          string(APPEND RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has ${inConfig} UseDebugLibraries '${udl_actual}', but should not have one.\n")
+        endif()
+        unset(udl_actual)
+      endif()
+    endif()
+  endforeach()
+
+  if(NOT have_udl_debug AND NOT "${udl_expect_debug}" STREQUAL "")
+    string(APPEND RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a debug UseDebugLibraries field, but should have one.\n")
+  endif()
+  if(NOT have_udl_release AND NOT "${udl_expect_release}" STREQUAL "")
+    string(APPEND RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a release UseDebugLibraries field, but should have one.\n")
+  endif()
+  return(PROPAGATE RunCMake_TEST_FAILED)
+endfunction()
diff --git a/Tests/RunCMake/VS10ProjectUseDebugLibraries/empty.cxx b/Tests/RunCMake/VS10ProjectUseDebugLibraries/empty.cxx
new file mode 100644
index 0000000..e69de29
-- 
cgit v0.12