Merge topic 'GoogleTest-DISCOVERY_MODE-note'

398a2bddf3 Help: Add release note for GoogleTest module DISCOVERY_MODE feature
2361f4efe1 Help: Update GoogleTest XML_OUTPUT_DIR release note markup

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4550
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cf67a66..b6ef543 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -814,6 +814,10 @@
     PATTERN "*.sh*" PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE
                                 GROUP_READ GROUP_EXECUTE
                                 WORLD_READ WORLD_EXECUTE
+    PATTERN "ExportImportList"
+      PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE
+                  GROUP_READ GROUP_EXECUTE
+                  WORLD_READ WORLD_EXECUTE
     REGEX "Help/(dev|guide)($|/)" EXCLUDE
     )
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index a2bbdcd..cbb2298 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -378,6 +378,7 @@
    /prop_tgt/VS_SCC_PROVIDER
    /prop_tgt/VS_SDK_REFERENCES
    /prop_tgt/VS_SOLUTION_DEPLOY
+   /prop_tgt/VS_SOURCE_SETTINGS_tool
    /prop_tgt/VS_USER_PROPS
    /prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
    /prop_tgt/VS_WINRT_COMPONENT
@@ -487,6 +488,7 @@
    /prop_sf/VS_DEPLOYMENT_LOCATION
    /prop_sf/VS_INCLUDE_IN_VSIX
    /prop_sf/VS_RESOURCE_GENERATOR
+   /prop_sf/VS_SETTINGS
    /prop_sf/VS_SHADER_DISABLE_OPTIMIZATIONS
    /prop_sf/VS_SHADER_ENABLE_DEBUG
    /prop_sf/VS_SHADER_ENTRYPOINT
diff --git a/Help/prop_sf/VS_SETTINGS.rst b/Help/prop_sf/VS_SETTINGS.rst
new file mode 100644
index 0000000..0719406
--- /dev/null
+++ b/Help/prop_sf/VS_SETTINGS.rst
@@ -0,0 +1,18 @@
+VS_SETTINGS
+-----------
+
+Set any item metadata on a non-built file.
+
+Takes a list of ``Key=Value`` pairs. Tells the Visual Studio generator to set
+``Key`` to ``Value`` as item metadata on the file.
+
+For example:
+
+.. code-block:: cmake
+
+  set_property(SOURCE file.hlsl PROPERTY VS_SETTINGS "Key=Value" "Key2=Value2")
+
+will set ``Key`` to ``Value`` and ``Key2`` to ``Value2`` on the
+``file.hlsl`` item as metadata.
+
+Generator expressions are supported.
diff --git a/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst b/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst
new file mode 100644
index 0000000..f706888
--- /dev/null
+++ b/Help/prop_tgt/VS_SOURCE_SETTINGS_tool.rst
@@ -0,0 +1,19 @@
+VS_SOURCE_SETTINGS_<tool>
+-------------------------
+
+Set any item metadata on all non-built files that use <tool>.
+
+Takes a list of ``Key=Value`` pairs. Tells the Visual Studio generator
+to set ``Key`` to ``Value`` as item metadata on all non-built files
+that use ``<tool>``.
+
+For example:
+
+.. code-block:: cmake
+
+  set_property(TARGET main PROPERTY VS_SOURCE_SETTINGS_FXCompile "Key=Value" "Key2=Value2")
+
+will set ``Key`` to ``Value`` and ``Key2`` to ``Value2`` for all
+non-built files that use ``FXCompile``.
+
+Generator expressions are supported.
diff --git a/Help/release/dev/vs-non-built-file-item-metadata.rst b/Help/release/dev/vs-non-built-file-item-metadata.rst
new file mode 100644
index 0000000..26cbad0
--- /dev/null
+++ b/Help/release/dev/vs-non-built-file-item-metadata.rst
@@ -0,0 +1,10 @@
+vs-non-built-file-item-metadata
+-------------------------------
+
+* The :prop_tgt:`VS_SOURCE_SETTINGS_<tool>` target property was added
+  to tell :ref:`Visual Studio Generators` for VS 2010 and above to add
+  metadata to non-built source files using ``<tool>``.
+
+* The :prop_sf:`VS_SETTINGS` source file property was added to tell
+  :ref:`Visual Studio Generators` for VS 2010 and above to add
+  metadata to a non-built source file.
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
index 62ea686..95c3cc9 100644
--- a/Modules/CMakeDetermineCUDACompiler.cmake
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -74,6 +74,7 @@
 
 set(_CMAKE_PROCESSING_LANGUAGE "CUDA")
 include(CMakeFindBinUtils)
+include(Compiler/${CMAKE_CUDA_COMPILER_ID}-FindBinUtils OPTIONAL)
 unset(_CMAKE_PROCESSING_LANGUAGE)
 
 if(MSVC_CUDA_ARCHITECTURE_ID)
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 38d3bfa..fb8cdeb 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -155,6 +155,10 @@
                              used if multiple compatible suffixes should
                              be tested for, in decreasing order of
                              preference.
+  Boost_LIB_PREFIX         - Set to the platform-specific library name
+                             prefix (e.g. "lib") used by Boost static libs.
+                             This is needed only on platforms where CMake
+                             does not know the prefix by default.
   Boost_ARCHITECTURE       - Set to the architecture-specific library suffix
                              (e.g. "-x64").  Default is auto-computed for the
                              C++ compiler in use.
@@ -1646,15 +1650,17 @@
 #  Prefix initialization
 # ------------------------------------------------------------------------
 
-# Boost's static libraries use a "lib" prefix on DLL platforms
-# to distinguish them from the DLL import libraries.
-if (Boost_USE_STATIC_LIBS AND (
-    (WIN32 AND NOT CYGWIN)
-    OR GHSMULTI
-    ))
-  set(Boost_LIB_PREFIX "lib")
-else()
-  set(Boost_LIB_PREFIX "")
+if ( NOT DEFINED Boost_LIB_PREFIX )
+  # Boost's static libraries use a "lib" prefix on DLL platforms
+  # to distinguish them from the DLL import libraries.
+  if (Boost_USE_STATIC_LIBS AND (
+      (WIN32 AND NOT CYGWIN)
+      OR GHSMULTI
+      ))
+    set(Boost_LIB_PREFIX "lib")
+  else()
+    set(Boost_LIB_PREFIX "")
+  endif()
 endif()
 
 if ( NOT Boost_NAMESPACE )
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 61750d3..b37e1ee 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 17)
-set(CMake_VERSION_PATCH 20200330)
+set(CMake_VERSION_PATCH 20200331)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index e908180..0a78af6 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -2432,11 +2432,9 @@
   }
 
   for (std::string const& config : configsList) {
-    const std::string buildType = cmSystemTools::UpperCase(config);
-
     // FIXME: Refactor collection of sources to not evaluate object libraries.
     std::vector<cmSourceFile*> sources;
-    target->GetSourceFiles(sources, buildType);
+    target->GetSourceFiles(sources, config);
 
     for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
       auto langSources = std::count_if(
@@ -2605,15 +2603,13 @@
     config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
   }
 
-  const std::string buildType = cmSystemTools::UpperCase(config);
-
   std::string filename_base =
     cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/",
              target->GetName(), ".dir/Unity/");
 
   // FIXME: Refactor collection of sources to not evaluate object libraries.
   std::vector<cmSourceFile*> sources;
-  target->GetSourceFiles(sources, buildType);
+  target->GetSourceFiles(sources, config);
 
   auto batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE");
   const size_t unityBatchSize =
@@ -2965,8 +2961,8 @@
   }
   cmStateSnapshot snp = this->StateSnapshot;
   while (snp.IsValid()) {
-    if (const char* value = snp.GetDirectory().GetProperty(featureName)) {
-      return value;
+    if (cmProp value = snp.GetDirectory().GetProperty(featureName)) {
+      return value->c_str();
     }
     snp = snp.GetBuildsystemDirectoryParent();
   }
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 2487f4d..812f922 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -4102,12 +4102,14 @@
     return output.c_str();
   }
 
-  return this->StateSnapshot.GetDirectory().GetProperty(prop);
+  cmProp retVal = this->StateSnapshot.GetDirectory().GetProperty(prop);
+  return retVal ? retVal->c_str() : nullptr;
 }
 
 const char* cmMakefile::GetProperty(const std::string& prop, bool chain) const
 {
-  return this->StateSnapshot.GetDirectory().GetProperty(prop, chain);
+  cmProp retVal = this->StateSnapshot.GetDirectory().GetProperty(prop, chain);
+  return retVal ? retVal->c_str() : nullptr;
 }
 
 bool cmMakefile::GetPropertyAsBool(const std::string& prop) const
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 2ce7530..a4fe663 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -548,32 +548,31 @@
   this->DirectoryState->Properties.AppendProperty(prop, value, asString);
 }
 
-const char* cmStateDirectory::GetProperty(const std::string& prop) const
+cmProp cmStateDirectory::GetProperty(const std::string& prop) const
 {
   const bool chain =
     this->Snapshot_.State->IsPropertyChained(prop, cmProperty::DIRECTORY);
   return this->GetProperty(prop, chain);
 }
 
-const char* cmStateDirectory::GetProperty(const std::string& prop,
-                                          bool chain) const
+cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const
 {
   static std::string output;
   output.clear();
   if (prop == "PARENT_DIRECTORY") {
     cmStateSnapshot parent = this->Snapshot_.GetBuildsystemDirectoryParent();
     if (parent.IsValid()) {
-      return parent.GetDirectory().GetCurrentSource().c_str();
+      return &parent.GetDirectory().GetCurrentSource();
     }
-    return "";
+    return &output;
   }
   if (prop == kBINARY_DIR) {
     output = this->GetCurrentBinary();
-    return output.c_str();
+    return &output;
   }
   if (prop == kSOURCE_DIR) {
     output = this->GetCurrentSource();
-    return output.c_str();
+    return &output;
   }
   if (prop == kSUBDIRECTORIES) {
     std::vector<std::string> child_dirs;
@@ -584,11 +583,11 @@
       child_dirs.push_back(ci.GetDirectory().GetCurrentSource());
     }
     output = cmJoin(child_dirs, ";");
-    return output.c_str();
+    return &output;
   }
   if (prop == kBUILDSYSTEM_TARGETS) {
     output = cmJoin(this->DirectoryState->NormalTargetNames, ";");
-    return output.c_str();
+    return &output;
   }
 
   if (prop == "LISTFILE_STACK") {
@@ -600,38 +599,38 @@
     }
     std::reverse(listFiles.begin(), listFiles.end());
     output = cmJoin(listFiles, ";");
-    return output.c_str();
+    return &output;
   }
   if (prop == "CACHE_VARIABLES") {
     output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";");
-    return output.c_str();
+    return &output;
   }
   if (prop == "VARIABLES") {
     std::vector<std::string> res = this->Snapshot_.ClosureKeys();
     cm::append(res, this->Snapshot_.State->GetCacheEntryKeys());
     std::sort(res.begin(), res.end());
     output = cmJoin(res, ";");
-    return output.c_str();
+    return &output;
   }
   if (prop == "INCLUDE_DIRECTORIES") {
     output = cmJoin(this->GetIncludeDirectoriesEntries(), ";");
-    return output.c_str();
+    return &output;
   }
   if (prop == "COMPILE_OPTIONS") {
     output = cmJoin(this->GetCompileOptionsEntries(), ";");
-    return output.c_str();
+    return &output;
   }
   if (prop == "COMPILE_DEFINITIONS") {
     output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
-    return output.c_str();
+    return &output;
   }
   if (prop == "LINK_OPTIONS") {
     output = cmJoin(this->GetLinkOptionsEntries(), ";");
-    return output.c_str();
+    return &output;
   }
   if (prop == "LINK_DIRECTORIES") {
     output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
-    return output.c_str();
+    return &output;
   }
 
   cmProp retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
@@ -641,15 +640,16 @@
     if (parentSnapshot.IsValid()) {
       return parentSnapshot.GetDirectory().GetProperty(prop, chain);
     }
-    retVal = this->Snapshot_.State->GetGlobalProperty(prop);
+    return this->Snapshot_.State->GetGlobalProperty(prop);
   }
 
-  return retVal ? retVal->c_str() : nullptr;
+  return retVal;
 }
 
 bool cmStateDirectory::GetPropertyAsBool(const std::string& prop) const
 {
-  return cmIsOn(this->GetProperty(prop));
+  cmProp p = this->GetProperty(prop);
+  return p && cmIsOn(*p);
 }
 
 std::vector<std::string> cmStateDirectory::GetPropertyKeys() const
diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h
index 53a2d54..8144160 100644
--- a/Source/cmStateDirectory.h
+++ b/Source/cmStateDirectory.h
@@ -16,6 +16,8 @@
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 
+using cmProp = const std::string*;
+
 class cmStateDirectory
 {
   cmStateDirectory(
@@ -86,8 +88,8 @@
                    cmListFileBacktrace const& lfbt);
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString, cmListFileBacktrace const& lfbt);
-  const char* GetProperty(const std::string& prop) const;
-  const char* GetProperty(const std::string& prop, bool chain) const;
+  cmProp GetProperty(const std::string& prop) const;
+  cmProp GetProperty(const std::string& prop, bool chain) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   std::vector<std::string> GetPropertyKeys() const;
 
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 8b51690..93c168a 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -1779,8 +1779,11 @@
     const bool chain =
       impl->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TARGET);
     if (chain) {
-      return impl->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
+      retVal = impl->Makefile->GetStateSnapshot().GetDirectory().GetProperty(
         prop, chain);
+      if (retVal) {
+        return retVal->c_str();
+      }
     }
     return nullptr;
   }
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 1273308..abc8b6f 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1745,20 +1745,65 @@
   }
 }
 
+void cmVisualStudio10TargetGenerator::ParseSettingsProperty(
+  const char* settingsPropertyValue, ConfigToSettings& toolSettings)
+{
+  if (settingsPropertyValue) {
+    cmGeneratorExpression ge;
+
+    std::unique_ptr<cmCompiledGeneratorExpression> cge =
+      ge.Parse(settingsPropertyValue);
+
+    for (const std::string& config : this->Configurations) {
+      std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+      std::vector<std::string> settings = cmExpandedList(evaluated);
+      for (const std::string& setting : settings) {
+        const std::string::size_type assignment = setting.find('=');
+        if (assignment != std::string::npos) {
+          const std::string propName = setting.substr(0, assignment);
+          const std::string propValue = setting.substr(assignment + 1);
+
+          if (!propValue.empty()) {
+            toolSettings[config][propName] = propValue;
+          }
+        }
+      }
+    }
+  }
+}
+
+bool cmVisualStudio10TargetGenerator::PropertyIsSameInAllConfigs(
+  const ConfigToSettings& toolSettings, const std::string& propName)
+{
+  std::string firstPropValue = "";
+  for (const auto& configToSettings : toolSettings) {
+    const std::unordered_map<std::string, std::string>& settings =
+      configToSettings.second;
+
+    if (firstPropValue.empty()) {
+      if (settings.find(propName) != settings.end()) {
+        firstPropValue = settings.find(propName)->second;
+      }
+    }
+
+    if (settings.find(propName) == settings.end()) {
+      return false;
+    }
+
+    if (settings.find(propName)->second != firstPropValue) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1,
                                                        cmSourceFile const* sf)
 {
   bool toolHasSettings = false;
   const char* tool = "None";
-  std::string shaderType;
-  std::string shaderEntryPoint;
-  std::string shaderModel;
-  std::string shaderAdditionalFlags;
-  std::string shaderDisableOptimizations;
-  std::string shaderEnableDebug;
-  std::string shaderObjectFileName;
-  std::string outputHeaderFile;
-  std::string variableName;
   std::string settingsGenerator;
   std::string settingsLastGenOutput;
   std::string sourceLink;
@@ -1766,6 +1811,11 @@
   std::string copyToOutDir;
   std::string includeInVsix;
   std::string ext = cmSystemTools::LowerCase(sf->GetExtension());
+  ConfigToSettings toolSettings;
+  for (const auto& config : this->Configurations) {
+    toolSettings[config];
+  }
+
   if (this->ProjectType == csproj && !this->InSourceBuild) {
     toolHasSettings = true;
   }
@@ -1773,47 +1823,72 @@
     tool = "FXCompile";
     // Figure out the type of shader compiler to use.
     if (const char* st = sf->GetProperty("VS_SHADER_TYPE")) {
-      shaderType = st;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["ShaderType"] = st;
+      }
     }
     // Figure out which entry point to use if any
     if (const char* se = sf->GetProperty("VS_SHADER_ENTRYPOINT")) {
-      shaderEntryPoint = se;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["EntryPointName"] = se;
+      }
     }
     // Figure out which shader model to use if any
     if (const char* sm = sf->GetProperty("VS_SHADER_MODEL")) {
-      shaderModel = sm;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["ShaderModel"] = sm;
+      }
     }
     // Figure out which output header file to use if any
     if (const char* ohf = sf->GetProperty("VS_SHADER_OUTPUT_HEADER_FILE")) {
-      outputHeaderFile = ohf;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["HeaderFileOutput"] = ohf;
+      }
     }
     // Figure out which variable name to use if any
     if (const char* vn = sf->GetProperty("VS_SHADER_VARIABLE_NAME")) {
-      variableName = vn;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["VariableName"] = vn;
+      }
     }
     // Figure out if there's any additional flags to use
     if (const char* saf = sf->GetProperty("VS_SHADER_FLAGS")) {
-      shaderAdditionalFlags = saf;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["AdditionalOptions"] = saf;
+      }
     }
     // Figure out if debug information should be generated
     if (const char* sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) {
-      shaderEnableDebug = sed;
-      toolHasSettings = true;
+      cmGeneratorExpression ge;
+      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(sed);
+
+      for (const std::string& config : this->Configurations) {
+        std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+        if (!evaluated.empty()) {
+          toolSettings[config]["EnableDebuggingInformation"] =
+            cmIsOn(evaluated) ? "true" : "false";
+        }
+      }
     }
     // Figure out if optimizations should be disabled
     if (const char* sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) {
-      shaderDisableOptimizations = sdo;
-      toolHasSettings = true;
+      cmGeneratorExpression ge;
+      std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(sdo);
+
+      for (const std::string& config : this->Configurations) {
+        std::string evaluated = cge->Evaluate(this->LocalGenerator, config);
+
+        if (!evaluated.empty()) {
+          toolSettings[config]["DisableOptimizations"] =
+            cmIsOn(evaluated) ? "true" : "false";
+        }
+      }
     }
     if (const char* sofn = sf->GetProperty("VS_SHADER_OBJECT_FILE_NAME")) {
-      shaderObjectFileName = sofn;
-      toolHasSettings = true;
+      for (const std::string& config : this->Configurations) {
+        toolSettings[config]["ObjectFileOutput"] = sofn;
+      }
     }
   } else if (ext == "jpg" || ext == "png") {
     tool = "Image";
@@ -1883,11 +1958,55 @@
     }
   }
 
+  if (ParsedToolTargetSettings.find(tool) == ParsedToolTargetSettings.end()) {
+    const char* toolTargetProperty =
+      this->GeneratorTarget->Target->GetProperty("VS_SOURCE_SETTINGS_" +
+                                                 std::string(tool));
+    ConfigToSettings toolTargetSettings;
+    ParseSettingsProperty(toolTargetProperty, toolTargetSettings);
+
+    ParsedToolTargetSettings[tool] = toolTargetSettings;
+  }
+
+  for (const auto& configToSetting : ParsedToolTargetSettings[tool]) {
+    for (const auto& setting : configToSetting.second) {
+      toolSettings[configToSetting.first][setting.first] = setting.second;
+    }
+  }
+
+  ParseSettingsProperty(sf->GetProperty("VS_SETTINGS"), toolSettings);
+
+  if (!toolSettings.empty()) {
+    toolHasSettings = true;
+  }
+
   Elem e2(e1, tool);
   this->WriteSource(e2, sf);
   if (toolHasSettings) {
     e2.SetHasElements();
 
+    std::vector<std::string> writtenSettings;
+    for (const auto& configSettings : toolSettings) {
+      for (const auto& setting : configSettings.second) {
+
+        if (std::find(writtenSettings.begin(), writtenSettings.end(),
+                      setting.first) != writtenSettings.end()) {
+          continue;
+        }
+
+        if (PropertyIsSameInAllConfigs(toolSettings, setting.first)) {
+          e2.Element(setting.first, setting.second);
+          writtenSettings.push_back(setting.first);
+        } else {
+          e2.WritePlatformConfigTag(setting.first,
+                                    "'$(Configuration)|$(Platform)'=='" +
+                                      configSettings.first + "|" +
+                                      this->Platform + "'",
+                                    setting.second);
+        }
+      }
+    }
+
     if (!deployContent.empty()) {
       cmGeneratorExpression ge;
       std::unique_ptr<cmCompiledGeneratorExpression> cge =
@@ -1913,73 +2032,7 @@
         }
       }
     }
-    if (!shaderType.empty()) {
-      e2.Element("ShaderType", shaderType);
-    }
-    if (!shaderEntryPoint.empty()) {
-      e2.Element("EntryPointName", shaderEntryPoint);
-    }
-    if (!shaderModel.empty()) {
-      e2.Element("ShaderModel", shaderModel);
-    }
-    if (!outputHeaderFile.empty()) {
-      for (size_t i = 0; i != this->Configurations.size(); ++i) {
-        e2.WritePlatformConfigTag("HeaderFileOutput",
-                                  "'$(Configuration)|$(Platform)'=='" +
-                                    this->Configurations[i] + "|" +
-                                    this->Platform + "'",
-                                  outputHeaderFile);
-      }
-    }
-    if (!variableName.empty()) {
-      for (size_t i = 0; i != this->Configurations.size(); ++i) {
-        e2.WritePlatformConfigTag("VariableName",
-                                  "'$(Configuration)|$(Platform)'=='" +
-                                    this->Configurations[i] + "|" +
-                                    this->Platform + "'",
-                                  variableName);
-      }
-    }
-    if (!shaderEnableDebug.empty()) {
-      cmGeneratorExpression ge;
-      std::unique_ptr<cmCompiledGeneratorExpression> cge =
-        ge.Parse(shaderEnableDebug);
 
-      for (size_t i = 0; i != this->Configurations.size(); ++i) {
-        const std::string& enableDebug =
-          cge->Evaluate(this->LocalGenerator, this->Configurations[i]);
-        if (!enableDebug.empty()) {
-          e2.WritePlatformConfigTag("EnableDebuggingInformation",
-                                    "'$(Configuration)|$(Platform)'=='" +
-                                      this->Configurations[i] + "|" +
-                                      this->Platform + "'",
-                                    cmIsOn(enableDebug) ? "true" : "false");
-        }
-      }
-    }
-    if (!shaderDisableOptimizations.empty()) {
-      cmGeneratorExpression ge;
-      std::unique_ptr<cmCompiledGeneratorExpression> cge =
-        ge.Parse(shaderDisableOptimizations);
-
-      for (size_t i = 0; i != this->Configurations.size(); ++i) {
-        const std::string& disableOptimizations =
-          cge->Evaluate(this->LocalGenerator, this->Configurations[i]);
-        if (!disableOptimizations.empty()) {
-          e2.WritePlatformConfigTag(
-            "DisableOptimizations",
-            "'$(Configuration)|$(Platform)'=='" + this->Configurations[i] +
-              "|" + this->Platform + "'",
-            (cmIsOn(disableOptimizations) ? "true" : "false"));
-        }
-      }
-    }
-    if (!shaderObjectFileName.empty()) {
-      e2.Element("ObjectFileOutput", shaderObjectFileName);
-    }
-    if (!shaderAdditionalFlags.empty()) {
-      e2.Element("AdditionalOptions", shaderAdditionalFlags);
-    }
     if (!settingsGenerator.empty()) {
       e2.Element("Generator", settingsGenerator);
     }
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 25b3d02..e588de8 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 class cmComputeLinkInformation;
@@ -234,6 +235,15 @@
 
   using ToolSourceMap = std::map<std::string, ToolSources>;
   ToolSourceMap Tools;
+
+  using ConfigToSettings =
+    std::unordered_map<std::string,
+                       std::unordered_map<std::string, std::string>>;
+  std::unordered_map<std::string, ConfigToSettings> ParsedToolTargetSettings;
+  bool PropertyIsSameInAllConfigs(const ConfigToSettings& toolSettings,
+                                  const std::string& propName);
+  void ParseSettingsProperty(const char* settingsPropertyValue,
+                             ConfigToSettings& toolSettings);
   std::string GetCMakeFilePath(const char* name) const;
 };
 
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 3ca7cc0..5ccca01 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -31,6 +31,8 @@
 run_cmake(VsPrecompileHeaders)
 run_cmake(VsPrecompileHeadersReuseFromCompilePDBName)
 run_cmake(VsDeployEnabled)
+run_cmake(VsSettings)
+run_cmake(VsSourceSettingsTool)
 
 run_cmake(VsWinRTByDefault)
 
diff --git a/Tests/RunCMake/VS10Project/VsSettings-check.cmake b/Tests/RunCMake/VS10Project/VsSettings-check.cmake
new file mode 100644
index 0000000..0f8b26c
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsSettings-check.cmake
@@ -0,0 +1,23 @@
+macro(ensure_props_set projectFile)
+  if(NOT EXISTS "${projectFile}")
+    set(RunCMake_TEST_FAILED "Project file ${projectFile} does not exist.")
+    return()
+  endif()
+
+  set(SettingFound FALSE)
+
+  file(STRINGS "${projectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES "<SourceProperty1.*Debug.*>SourceProperty1Value</SourceProperty1>")
+      message("SourceProperty1 setting found")
+      set(SettingFound TRUE)
+    endif()
+  endforeach()
+
+  if (NOT SettingFound)
+    set(RunCMake_TEST_FAILED "SourceProperty1 setting was not found")
+    return()
+  endif()
+endmacro()
+
+ensure_props_set("${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
diff --git a/Tests/RunCMake/VS10Project/VsSettings.cmake b/Tests/RunCMake/VS10Project/VsSettings.cmake
new file mode 100644
index 0000000..a4b321b
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsSettings.cmake
@@ -0,0 +1,5 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp shader.hlsl)
+set_property(SOURCE shader.hlsl PROPERTY VS_SETTINGS
+  "$<$<CONFIG:DEBUG>:SourceProperty1=SourceProperty1Value>")
diff --git a/Tests/RunCMake/VS10Project/VsSourceSettingsTool-check.cmake b/Tests/RunCMake/VS10Project/VsSourceSettingsTool-check.cmake
new file mode 100644
index 0000000..29a89c3
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsSourceSettingsTool-check.cmake
@@ -0,0 +1,34 @@
+macro(ensure_props_set projectFile)
+  if(NOT EXISTS "${projectFile}")
+    set(RunCMake_TEST_FAILED "Project file ${projectFile} does not exist.")
+    return()
+  endif()
+
+  set(FirstSettingFound FALSE)
+  set(SecondSettingFound FALSE)
+
+  file(STRINGS "${projectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES "<TargetProperty1.*Debug.*>TargetProperty1ValueDebug</TargetProperty1>")
+      if (FirstSettingFound)
+        message("TargetProperty1 setting found twice")
+        set(SecondSettingFound TRUE)
+      else()
+        message("TargetProperty1 setting found once")
+        set(FirstSettingFound TRUE)
+      endif()
+    endif()
+  endforeach()
+
+  if (NOT FirstSettingFound)
+    set(RunCMake_TEST_FAILED "TargetProperty1 setting not found at all")
+    return()
+  endif()
+
+  if (NOT SecondSettingFound)
+    set(RunCMake_TEST_FAILED "TargetProperty1 setting found once when it should be found twice")
+    return()
+  endif()
+endmacro()
+
+ensure_props_set("${RunCMake_TEST_BINARY_DIR}/foo.vcxproj")
diff --git a/Tests/RunCMake/VS10Project/VsSourceSettingsTool.cmake b/Tests/RunCMake/VS10Project/VsSourceSettingsTool.cmake
new file mode 100644
index 0000000..498962f
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsSourceSettingsTool.cmake
@@ -0,0 +1,5 @@
+enable_language(CXX)
+
+add_library(foo foo.cpp shader.hlsl shader2.hlsl)
+set_property(TARGET foo PROPERTY VS_SOURCE_SETTINGS_FXCompile
+  "$<$<CONFIG:DEBUG>:TargetProperty1=TargetProperty1ValueDebug>")
diff --git a/Tests/RunCMake/VS10Project/shader.hlsl b/Tests/RunCMake/VS10Project/shader.hlsl
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/shader.hlsl
@@ -0,0 +1 @@
+
diff --git a/Tests/RunCMake/VS10Project/shader2.hlsl b/Tests/RunCMake/VS10Project/shader2.hlsl
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/shader2.hlsl
@@ -0,0 +1 @@
+
diff --git a/Tests/RunCMake/target_link_libraries/ConfigCase-result.txt b/Tests/RunCMake/target_link_libraries/ConfigCase-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/ConfigCase-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_link_libraries/ConfigCase-stderr.txt b/Tests/RunCMake/target_link_libraries/ConfigCase-stderr.txt
new file mode 100644
index 0000000..953c972
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/ConfigCase-stderr.txt
@@ -0,0 +1,13 @@
+^CMake Error at ConfigCase.cmake:[0-9]+ \(add_library\):
+  Target "impl" links to target "config::impl-Debug" but the target was not
+  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
+  an ALIAS target is missing\?
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Error at ConfigCase.cmake:[0-9]+ \(add_library\):
+  Target "impl" links to target "config::iface-Debug" but the target was not
+  found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
+  an ALIAS target is missing\?
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/target_link_libraries/ConfigCase.cmake b/Tests/RunCMake/target_link_libraries/ConfigCase.cmake
new file mode 100644
index 0000000..fc39478
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/ConfigCase.cmake
@@ -0,0 +1,6 @@
+cmake_policy(VERSION 3.15)
+enable_language(C)
+add_library(iface INTERFACE)
+target_link_libraries(iface INTERFACE "config::iface-$<CONFIG>")
+add_library(impl empty.c)
+target_link_libraries(impl PRIVATE "config::impl-$<CONFIG>" iface)
diff --git a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
index c7feb5f..fb223ab 100644
--- a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
@@ -1,5 +1,13 @@
 include(RunCMake)
 
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
+else()
+  set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+endif()
+run_cmake(ConfigCase)
+unset(RunCMake_TEST_OPTIONS)
+
 run_cmake(CMP0023-WARN)
 run_cmake(CMP0023-NEW)
 run_cmake(CMP0023-WARN-2)
diff --git a/Tests/VSWinStorePhone/CMakeLists.txt b/Tests/VSWinStorePhone/CMakeLists.txt
index b8e157d..558d5de 100644
--- a/Tests/VSWinStorePhone/CMakeLists.txt
+++ b/Tests/VSWinStorePhone/CMakeLists.txt
@@ -127,7 +127,7 @@
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_MODEL 4.0_level_9_3)
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_FLAGS "/DFLAGS_ADDED")
 set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SHADER_OUTPUT_HEADER_FILE "$(OutDir)%(Filename).h")
-
+set_property(SOURCE ${VERTEXSHADER_FILES} PROPERTY VS_SETTINGS "$<$<CONFIG:DEBUG>:SourceProperty1=SourceProperty1Value>")
 
 source_group("Source Files" FILES ${SOURCE_FILES})
 source_group("Header Files" FILES ${HEADER_FILES})
@@ -135,6 +135,11 @@
 
 add_executable(${EXE_NAME} WIN32 ${SOURCE_FILES} ${HEADER_FILES} ${RESOURCE_FILES})
 set_property(TARGET ${EXE_NAME} PROPERTY VS_WINRT_COMPONENT TRUE)
+set_property(TARGET ${EXE_NAME} PROPERTY VS_SOURCE_SETTINGS_FXCompile
+  "TargetProperty1=$<$<CONFIG:DEBUG>:TargetProperty1ValueDebug>$<$<CONFIG:RELEASE>:TargetProperty1ValueRelease>")
+
+add_custom_command(TARGET ${EXE_NAME} POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -Dvcxproj="${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.vcxproj" -P "${CMAKE_CURRENT_SOURCE_DIR}/EnsurePropertiesSet.cmake")
 
 string(SUBSTRING "${CMAKE_SYSTEM_VERSION}" 0, 4, SHORT_VERSION)
 
diff --git a/Tests/VSWinStorePhone/EnsurePropertiesSet.cmake b/Tests/VSWinStorePhone/EnsurePropertiesSet.cmake
new file mode 100644
index 0000000..528c46f
--- /dev/null
+++ b/Tests/VSWinStorePhone/EnsurePropertiesSet.cmake
@@ -0,0 +1,45 @@
+macro(ensure_props_set projectFile)
+  if(NOT EXISTS "${projectFile}")
+    message(FATAL_ERROR "Project file ${projectFile} does not exist.")
+    return()
+  endif()
+
+  set(SourcePropertyFound FALSE)
+  set(DebugTargetPropertyFound FALSE)
+  set(ReleaseTargetPropertyFound FALSE)
+
+  file(STRINGS "${projectFile}" lines)
+  foreach(line IN LISTS lines)
+    if(line MATCHES "<SourceProperty1.*Debug.*>SourceProperty1Value</SourceProperty1>")
+      message("SourceProperty1 setting found")
+      set(SourcePropertyFound TRUE)
+    endif()
+
+    if(line MATCHES "<TargetProperty1.*Debug.*>TargetProperty1ValueDebug</TargetProperty1>")
+      message("Debug TargetProperty1 setting found")
+      set(DebugTargetPropertyFound TRUE)
+    endif()
+
+    if(line MATCHES "<TargetProperty1.*Release.*>TargetProperty1ValueRelease</TargetProperty1>")
+      message("Release TargetProperty1 setting found")
+      set(ReleaseTargetPropertyFound TRUE)
+    endif()
+  endforeach()
+
+  if (NOT SourcePropertyFound)
+    message(FATAL_ERROR "SourceProperty1 setting not found")
+    return()
+  endif()
+
+  if (NOT DebugTargetPropertyFound)
+    message(FATAL_ERROR "Debug TargetProperty1 setting not found")
+    return()
+  endif()
+
+  if (NOT ReleaseTargetPropertyFound)
+    message(FATAL_ERROR "Release TargetProperty1 setting not found")
+    return()
+  endif()
+endmacro()
+
+ensure_props_set("${vcxproj}")