Merge topic 'ctest_runtime_labels'

bd38749fd4 ctest: allow test output to add labels

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !6234
diff --git a/Help/release/dev/msvc-isystem.rst b/Help/release/dev/msvc-isystem.rst
new file mode 100644
index 0000000..4a5d79f
--- /dev/null
+++ b/Help/release/dev/msvc-isystem.rst
@@ -0,0 +1,7 @@
+msvc-isystem
+------------
+
+* The MSVC compilers learned to pass the ``-external:I`` flag for system
+  includes when using the :generator:`Ninja` and :generator:`NMake Makefiles`
+  generators. This became available as of Visual Studio 16.10 (toolchain
+  version 14.29.30037).
diff --git a/Modules/CMakeCompilerIdDetection.cmake b/Modules/CMakeCompilerIdDetection.cmake
index 2197790..dd70d82 100644
--- a/Modules/CMakeCompilerIdDetection.cmake
+++ b/Modules/CMakeCompilerIdDetection.cmake
@@ -13,8 +13,8 @@
 
 function(compiler_id_detection outvar lang)
 
-  if (NOT lang STREQUAL Fortran AND NOT lang STREQUAL CSharp
-      AND NOT lang STREQUAL ISPC)
+  if (NOT "x${lang}" STREQUAL "xFortran" AND NOT "x${lang}" STREQUAL "xCSharp"
+      AND NOT "x${lang}" STREQUAL "xISPC")
     file(GLOB lang_files
       "${CMAKE_ROOT}/Modules/Compiler/*-DetermineCompiler.cmake")
     set(nonlang CXX)
@@ -42,7 +42,7 @@
 
     # Order is relevant here. For example, compilers which pretend to be
     # GCC must appear before the actual GCC.
-    if (lang STREQUAL CXX)
+    if ("x${lang}" STREQUAL "xCXX")
       list(APPEND ordered_compilers
         Comeau
       )
@@ -70,7 +70,7 @@
       Fujitsu
       GHS
     )
-    if (lang STREQUAL C)
+    if ("x${lang}" STREQUAL "xC")
       list(APPEND ordered_compilers
         TinyCC
         Bruce
@@ -92,13 +92,13 @@
       ADSP
       IAR
     )
-    if (lang STREQUAL C)
+    if ("x${lang}" STREQUAL "xC")
       list(APPEND ordered_compilers
         SDCC
       )
     endif()
 
-    if(lang STREQUAL CUDA)
+    if("x${lang}" STREQUAL "xCUDA")
       set(ordered_compilers NVIDIA Clang)
     endif()
 
diff --git a/Modules/Compiler/MSVC-C.cmake b/Modules/Compiler/MSVC-C.cmake
index 9a5104b..73cca36 100644
--- a/Modules/Compiler/MSVC-C.cmake
+++ b/Modules/Compiler/MSVC-C.cmake
@@ -63,3 +63,9 @@
 if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
   set(CMAKE_C_COMPILE_OPTIONS_JMC "-JMC")
 endif()
+
+# The `/external:I` flag was made non-experimental in 19.29.30036.3.
+if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30036.3)
+  set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-external:I ")
+  set(_CMAKE_INCLUDE_SYSTEM_FLAG_C_WARNING "-external:W0 ")
+endif ()
diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake
index f1c7450..09fe851 100644
--- a/Modules/Compiler/MSVC-CXX.cmake
+++ b/Modules/Compiler/MSVC-CXX.cmake
@@ -79,3 +79,9 @@
 if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05)
   set(CMAKE_CXX_COMPILE_OPTIONS_JMC "-JMC")
 endif()
+
+# The `/external:I` flag was made non-experimental in 19.29.30036.3.
+if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30036.3)
+  set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-external:I ")
+  set(_CMAKE_INCLUDE_SYSTEM_FLAG_CXX_WARNING "-external:W0 ")
+endif ()
diff --git a/Modules/Internal/CheckCompilerFlag.cmake b/Modules/Internal/CheckCompilerFlag.cmake
index 9eb1bf0..693e28b 100644
--- a/Modules/Internal/CheckCompilerFlag.cmake
+++ b/Modules/Internal/CheckCompilerFlag.cmake
@@ -13,10 +13,12 @@
 
   if(_lang STREQUAL "C")
     set(_lang_src "int main(void) { return 0; }")
-    set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C")
+    set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C"
+                         FAIL_REGEX "-Werror=.* argument .* is not valid for C")
   elseif(_lang STREQUAL "CXX")
     set(_lang_src "int main() { return 0; }")
-    set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+")
+    set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+"
+                         FAIL_REGEX "-Werror=.* argument .* is not valid for C\\+\\+")
   elseif(_lang STREQUAL "CUDA")
     set(_lang_src "__host__ int main() { return 0; }")
     set(_lang_fail_regex FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+" # Host GNU
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 521aa20..c615a6b 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 21)
-set(CMake_VERSION_PATCH 20210617)
+set(CMake_VERSION_PATCH 20210621)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index fa51092..fc2665b 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -1361,10 +1361,8 @@
 
 namespace {
 
-unsigned long long const vsVer16_10_0 = 4503644629696790;
-
-cmIDEFlagTable const* cmLoadFlagTableJson(
-  std::string const& flagJsonPath, cm::optional<unsigned long long> vsver)
+cmIDEFlagTable const* cmLoadFlagTableJson(std::string const& flagJsonPath,
+                                          cm::optional<std::string> vsVer)
 {
   cmIDEFlagTable* ret = nullptr;
   auto savedFlagIterator = loadedFlagJsonFiles.find(flagJsonPath);
@@ -1380,17 +1378,22 @@
       if (reader.parse(stream, flags, false) && flags.isArray()) {
         std::vector<cmIDEFlagTable> flagTable;
         for (auto const& flag : flags) {
+          Json::Value const& vsminJson = flag["vsmin"];
+          if (vsminJson.isString()) {
+            std::string const& vsmin = vsminJson.asString();
+            if (!vsmin.empty()) {
+              if (!vsVer ||
+                  cmSystemTools::VersionCompareGreater(vsmin, *vsVer)) {
+                continue;
+              }
+            }
+          }
           cmIDEFlagTable flagEntry;
           flagEntry.IDEName = cmLoadFlagTableString(flag, "name");
           flagEntry.commandFlag = cmLoadFlagTableString(flag, "switch");
           flagEntry.comment = cmLoadFlagTableString(flag, "comment");
           flagEntry.value = cmLoadFlagTableString(flag, "value");
           flagEntry.special = cmLoadFlagTableSpecial(flag, "flags");
-          // FIXME: Port this version check to a Json field.
-          if (vsver && *vsver < vsVer16_10_0 &&
-              flagEntry.IDEName == "ExternalWarningLevel") {
-            continue;
-          }
           flagTable.push_back(flagEntry);
         }
         cmIDEFlagTable endFlag{ "", "", "", "", 0 };
@@ -1466,8 +1469,8 @@
     }
   }
 
-  cm::optional<unsigned long long> vsver = this->GetVSInstanceVersion();
-  if (cmIDEFlagTable const* ret = cmLoadFlagTableJson(filename, vsver)) {
+  cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
+  if (cmIDEFlagTable const* ret = cmLoadFlagTableJson(filename, vsVer)) {
     return ret;
   }
 
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 48fe465..b7ae1ee 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -128,10 +128,7 @@
   std::string Encoding() override;
   const char* GetToolsVersion() const;
 
-  virtual cm::optional<unsigned long long> GetVSInstanceVersion() const
-  {
-    return {};
-  }
+  virtual cm::optional<std::string> GetVSInstanceVersion() const { return {}; }
 
   bool GetSupportsUnityBuilds() const { return this->SupportsUnityBuilds; }
 
@@ -141,6 +138,8 @@
 
   virtual bool IsStdOutEncodingSupported() const { return false; }
 
+  virtual bool IsUtf8EncodingSupported() const { return false; }
+
   static std::string GetInstalledNsightTegraVersion();
 
   /** Return the first two components of CMAKE_SYSTEM_VERSION.  */
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index 50dc30b..c8213c5 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -391,11 +391,11 @@
   return vsSetupAPIHelper.GetVSInstanceInfo(dir);
 }
 
-cm::optional<unsigned long long>
+cm::optional<std::string>
 cmGlobalVisualStudioVersionedGenerator::GetVSInstanceVersion() const
 {
-  cm::optional<unsigned long long> result;
-  unsigned long long vsInstanceVersion;
+  cm::optional<std::string> result;
+  std::string vsInstanceVersion;
   if (vsSetupAPIHelper.GetVSInstanceVersion(vsInstanceVersion)) {
     result = vsInstanceVersion;
   }
@@ -411,10 +411,25 @@
   if (this->Version < cmGlobalVisualStudioGenerator::VSVersion::VS16) {
     return false;
   }
-  unsigned long long const vsInstanceVersion16_7_P2 = 4503631666610212;
-  cm::optional<unsigned long long> vsInstanceVersion =
-    this->GetVSInstanceVersion();
-  return (vsInstanceVersion && *vsInstanceVersion > vsInstanceVersion16_7_P2);
+  static std::string const vsVer16_7_P2 = "16.7.30128.36";
+  cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
+  return (vsVer &&
+          cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer16_7_P2));
+}
+
+bool cmGlobalVisualStudioVersionedGenerator::IsUtf8EncodingSupported() const
+{
+  // Supported from Visual Studio 16.10 Preview 2.
+  if (this->Version > cmGlobalVisualStudioGenerator::VSVersion::VS16) {
+    return true;
+  }
+  if (this->Version < cmGlobalVisualStudioGenerator::VSVersion::VS16) {
+    return false;
+  }
+  static std::string const vsVer16_10_P2 = "16.10.31213.239";
+  cm::optional<std::string> vsVer = this->GetVSInstanceVersion();
+  return (vsVer &&
+          cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer16_10_P2));
 }
 
 const char*
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h
index 105e495..e6c19e4 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.h
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.h
@@ -28,13 +28,15 @@
 
   bool GetVSInstance(std::string& dir) const;
 
-  cm::optional<unsigned long long> GetVSInstanceVersion() const override;
+  cm::optional<std::string> GetVSInstanceVersion() const override;
 
   AuxToolset FindAuxToolset(std::string& version,
                             std::string& props) const override;
 
   bool IsStdOutEncodingSupported() const override;
 
+  bool IsUtf8EncodingSupported() const override;
+
   const char* GetAndroidApplicationTypeRevision() const override;
 
 protected:
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 3b282de..a14f085 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -878,9 +878,12 @@
   // Support special system include flag if it is available and the
   // normal flag is repeated for each directory.
   cmProp sysIncludeFlag = nullptr;
+  cmProp sysIncludeFlagWarning = nullptr;
   if (repeatFlag) {
     sysIncludeFlag = this->Makefile->GetDefinition(
       cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang));
+    sysIncludeFlagWarning = this->Makefile->GetDefinition(
+      cmStrCat("_CMAKE_INCLUDE_SYSTEM_FLAG_", lang, "_WARNING"));
   }
 
   cmProp fwSearchFlag = this->Makefile->GetDefinition(
@@ -889,6 +892,7 @@
     cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG"));
 
   bool flagUsed = false;
+  bool sysIncludeFlagUsed = false;
   std::set<std::string> emitted;
 #ifdef __APPLE__
   emitted.insert("/System/Library/Frameworks");
@@ -915,6 +919,7 @@
       if (sysIncludeFlag && target &&
           target->IsSystemIncludeDirectory(i, config, lang)) {
         includeFlags << *sysIncludeFlag;
+        sysIncludeFlagUsed = true;
       } else {
         includeFlags << includeFlag;
       }
@@ -931,6 +936,9 @@
     }
     includeFlags << sep;
   }
+  if (sysIncludeFlagUsed && sysIncludeFlagWarning) {
+    includeFlags << *sysIncludeFlagWarning;
+  }
   std::string flags = includeFlags.str();
   // remove trailing separators
   if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) {
diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx
index 9626599..969a2c2 100644
--- a/Source/cmVSSetupHelper.cxx
+++ b/Source/cmVSSetupHelper.cxx
@@ -258,15 +258,13 @@
   return isInstalled;
 }
 
-bool cmVSSetupAPIHelper::GetVSInstanceVersion(
-  unsigned long long& vsInstanceVersion)
+bool cmVSSetupAPIHelper::GetVSInstanceVersion(std::string& vsInstanceVersion)
 {
-  vsInstanceVersion = 0;
+  vsInstanceVersion.clear();
   bool isInstalled = this->EnumerateAndChooseVSInstance();
 
   if (isInstalled) {
-    vsInstanceVersion =
-      static_cast<unsigned long long>(chosenInstanceInfo.ullVersion);
+    vsInstanceVersion = cmsys::Encoding::ToNarrow(chosenInstanceInfo.Version);
   }
 
   return isInstalled;
diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h
index 04ea46d..61a3ac7 100644
--- a/Source/cmVSSetupHelper.h
+++ b/Source/cmVSSetupHelper.h
@@ -88,7 +88,7 @@
   std::wstring VSInstallLocation;
   std::wstring Version;
   std::string VCToolsetVersion;
-  ULONGLONG ullVersion = 0;
+  ULONGLONG ullVersion = 0; // A.B.C.D = (A<<48)|(B<<32)|(C<<16)|D
   bool IsWin10SDKInstalled = false;
   bool IsWin81SDKInstalled = false;
 
@@ -105,7 +105,7 @@
 
   bool IsVSInstalled();
   bool GetVSInstanceInfo(std::string& vsInstallLocation);
-  bool GetVSInstanceVersion(unsigned long long& vsInstanceVersion);
+  bool GetVSInstanceVersion(std::string& vsInstanceVersion);
   bool GetVCToolsetVersion(std::string& vsToolsetVersion);
   bool IsWin10SDKInstalled();
   bool IsWin81SDKInstalled();
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index b79c6fd..82880a9 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -3543,8 +3543,6 @@
   }
   Elem e2(e1, "NASM");
 
-  std::vector<std::string> includes =
-    this->GetIncludes(configName, "ASM_NASM");
   OptionsHelper nasmOptions(*(this->NasmOptions[configName]), e2);
   nasmOptions.OutputAdditionalIncludeDirectories("ASM_NASM");
   nasmOptions.OutputFlagMap();
@@ -5115,7 +5113,9 @@
 
 void cmVisualStudio10TargetGenerator::WriteStdOutEncodingUtf8(Elem& e1)
 {
-  if (this->GlobalGenerator->IsStdOutEncodingSupported()) {
+  if (this->GlobalGenerator->IsUtf8EncodingSupported()) {
+    e1.Element("UseUtf8Encoding", "Always");
+  } else if (this->GlobalGenerator->IsStdOutEncodingSupported()) {
     e1.Element("StdOutEncoding", "UTF-8");
   }
 }
diff --git a/Templates/MSBuild/FlagTables/v142_CL.json b/Templates/MSBuild/FlagTables/v142_CL.json
index 650ff6c..c21a3de 100644
--- a/Templates/MSBuild/FlagTables/v142_CL.json
+++ b/Templates/MSBuild/FlagTables/v142_CL.json
@@ -572,6 +572,7 @@
     "switch": "external:W0",
     "comment": "Turn Off All Warnings",
     "value": "TurnOffAllWarnings",
+    "vsmin": "16.10.31321.278",
     "flags": []
   },
   {
@@ -579,6 +580,7 @@
     "switch": "external:W1",
     "comment": "Level1",
     "value": "Level1",
+    "vsmin": "16.10.31321.278",
     "flags": []
   },
   {
@@ -586,6 +588,7 @@
     "switch": "external:W2",
     "comment": "Level2",
     "value": "Level2",
+    "vsmin": "16.10.31321.278",
     "flags": []
   },
   {
@@ -593,6 +596,7 @@
     "switch": "external:W3",
     "comment": "Level3",
     "value": "Level3",
+    "vsmin": "16.10.31321.278",
     "flags": []
   },
   {
@@ -600,6 +604,7 @@
     "switch": "external:W4",
     "comment": "Level4",
     "value": "Level4",
+    "vsmin": "16.10.31321.278",
     "flags": []
   },
   {
@@ -1141,6 +1146,7 @@
     "switch": "external:anglebrackets",
     "comment": "Treat Files Included with Angle Brackets as External",
     "value": "true",
+    "vsmin": "16.10.31321.278",
     "flags": []
   },
   {
@@ -1148,6 +1154,7 @@
     "switch": "external:templates-",
     "comment": "Template Diagnostics in External Headers",
     "value": "true",
+    "vsmin": "16.10.31321.278",
     "flags": []
   },
   {
@@ -1277,6 +1284,7 @@
     "switch": "external:env:",
     "comment": "External Directories Environment Variables",
     "value": "",
+    "vsmin": "16.10.31321.278",
     "flags": [
       "UserValue",
       "SemicolonAppendable"
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
index d4c19c7..4c488e6 100644
--- a/Tests/IncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -2,17 +2,25 @@
 project(IncludeDirectories)
 
 if (((CMAKE_C_COMPILER_ID STREQUAL GNU AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.4)
-    OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") OR CMAKE_C_COMPILER_ID STREQUAL AppleClang)
+    OR (CMAKE_C_COMPILER_ID STREQUAL Clang AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+    OR CMAKE_C_COMPILER_ID STREQUAL AppleClang
+    OR ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC" AND
+       CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "19.29.30036.3" AND
+       NOT CMAKE_GENERATOR MATCHES "Visual Studio")) # No support for VS generators yet.
     AND (CMAKE_GENERATOR STREQUAL "Unix Makefiles"
       OR CMAKE_GENERATOR STREQUAL "Ninja"
       OR (CMAKE_GENERATOR STREQUAL "Xcode" AND NOT XCODE_VERSION VERSION_LESS 6.0)))
-  include(CheckCXXCompilerFlag)
-  check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
-  if(run_sys_includes_test)
-    # The Bullseye wrapper appears to break the -isystem effect.
-    execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out)
-    if("x${out}" MATCHES "Bullseye")
-      set(run_sys_includes_test 0)
+  if ("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC")
+    set(run_sys_includes_test 1)
+  else ()
+    include(CheckCXXCompilerFlag)
+    check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
+    if(run_sys_includes_test)
+      # The Bullseye wrapper appears to break the -isystem effect.
+      execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out)
+      if("x${out}" MATCHES "Bullseye")
+        set(run_sys_includes_test 0)
+      endif()
     endif()
   endif()
   if (run_sys_includes_test)
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
index dee39c8..a746a68 100644
--- a/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/CMakeLists.txt
@@ -6,9 +6,17 @@
 add_library(systemlib systemlib.cpp)
 target_include_directories(systemlib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/systemlib")
 
+function (apply_error_flags target)
+  if (MSVC)
+    target_compile_options(${target} PRIVATE /we4101)
+  else ()
+    target_compile_options(${target} PRIVATE -Werror=unused-variable)
+  endif ()
+endfunction ()
+
 add_library(upstream upstream.cpp)
 target_link_libraries(upstream LINK_PUBLIC systemlib)
-target_compile_options(upstream PRIVATE -Werror=unused-variable)
+apply_error_flags(upstream)
 
 target_include_directories(upstream SYSTEM PUBLIC
   $<TARGET_PROPERTY:systemlib,INTERFACE_INCLUDE_DIRECTORIES>
@@ -29,7 +37,7 @@
 
 add_library(consumer consumer.cpp)
 target_link_libraries(consumer upstream config_specific)
-target_compile_options(consumer PRIVATE -Werror=unused-variable)
+apply_error_flags(consumer)
 
 add_library(iface IMPORTED INTERFACE)
 set_property(TARGET iface PROPERTY INTERFACE_INCLUDE_DIRECTORIES
@@ -38,21 +46,21 @@
 
 add_library(imported_consumer imported_consumer.cpp)
 target_link_libraries(imported_consumer iface)
-target_compile_options(imported_consumer PRIVATE -Werror=unused-variable)
+apply_error_flags(imported_consumer)
 
 add_library(imported_consumer2 imported_consumer.cpp)
 target_link_libraries(imported_consumer2 imported_consumer)
-target_compile_options(imported_consumer2 PRIVATE -Werror=unused-variable)
+apply_error_flags(imported_consumer2)
 
 # add a target which has a relative system include
 add_library(somelib imported_consumer.cpp)
 target_include_directories(somelib SYSTEM PUBLIC "systemlib_header_only")
-target_compile_options(somelib PRIVATE -Werror=unused-variable)
+apply_error_flags(somelib)
 
 # add a target which consumes a relative system include
 add_library(otherlib upstream.cpp)
 target_link_libraries(otherlib PUBLIC somelib)
-target_compile_options(somelib PRIVATE -Werror=unused-variable)
+apply_error_flags(otherlib)
 
 macro(do_try_compile error_option)
   set(TC_ARGS
@@ -61,7 +69,11 @@
     LINK_LIBRARIES iface
   )
   if (${error_option} STREQUAL WITH_ERROR)
-    list(APPEND TC_ARGS COMPILE_DEFINITIONS -Werror=unused-variable)
+    if (MSVC)
+      list(APPEND TC_ARGS COMPILE_DEFINITIONS /we4101)
+    else ()
+      list(APPEND TC_ARGS COMPILE_DEFINITIONS -Werror=unused-variable)
+    endif ()
   endif()
   try_compile(${TC_ARGS})
 endmacro()
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp
index a13f08f..3da308d 100644
--- a/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/consumer.cpp
@@ -1,5 +1,6 @@
 
-#include "config_iface.h"
+#include <config_iface.h>
+
 #include "upstream.h"
 
 int consumer()
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp b/Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp
index 1dbe819..53759b1 100644
--- a/Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/imported_consumer.cpp
@@ -1,5 +1,5 @@
 
-#include "systemlib.h"
+#include <systemlib.h>
 
 int main()
 {
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h
index a670c2a..3daf69e 100644
--- a/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h
+++ b/Tests/IncludeDirectories/SystemIncludeDirectories/upstream.h
@@ -2,7 +2,7 @@
 #ifndef UPSTREAM_H
 #define UPSTREAM_H
 
-#include "systemlib.h"
+#include <systemlib.h>
 
 #ifdef _WIN32
 __declspec(dllexport)
diff --git a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt
index 70dfa01..5d58633 100644
--- a/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt
+++ b/Tests/IncludeDirectories/SystemIncludeDirectoriesPerLang/CMakeLists.txt
@@ -7,14 +7,14 @@
   INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}>"
   INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:${CMAKE_CURRENT_SOURCE_DIR}>"
 )
-target_compile_options(c_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:C,GNU,Clang>:-Werror=unused-variable>")
+target_compile_options(c_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:C,GNU,Clang>:-Werror=unused-variable>;$<$<COMPILE_LANG_AND_ID:C,MSVC>:/we4101>")
 
 add_library(cxx_interface INTERFACE)
 set_target_properties(cxx_interface PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_system_include>"
   INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_system_include>"
 )
-target_compile_options(cxx_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang>:-Werror=unused-variable>")
+target_compile_options(cxx_interface INTERFACE "$<$<COMPILE_LANG_AND_ID:CXX,GNU,Clang>:-Werror=unused-variable>;$<$<COMPILE_LANG_AND_ID:C,MSVC>:/we4101>")
 
 # The C header must come before the C++ header for this test to smoke out the
 # failure. The order of sources is how CMake determines the include cache