Merge topic 'enhanced-UseSWIG-Module'

0bef9eb4 UseSWIG: modernize module
d6048bd1 UseSWIG: Re-work test framework

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !1707
diff --git a/Help/command/string.rst b/Help/command/string.rst
index fb3893f..d8da7be 100644
--- a/Help/command/string.rst
+++ b/Help/command/string.rst
@@ -282,6 +282,18 @@
 
 Transform a string like :command:`configure_file` transforms a file.
 
+MAKE_C_IDENTIFIER
+"""""""""""""""""
+
+::
+
+  string(MAKE_C_IDENTIFIER <input string> <output variable>)
+
+Convert each non-alphanumeric character in the ``<input string>`` to an
+underscore and store the result in the ``<output variable>``.  If the first
+character of the string is a digit, an underscore will also be prepended to
+the result.
+
 RANDOM
 """"""
 
@@ -346,13 +358,6 @@
    %Y-%m-%dT%H:%M:%S    for local time.
    %Y-%m-%dT%H:%M:%SZ   for UTC.
 
-
-::
-
-  string(MAKE_C_IDENTIFIER <input string> <output variable>)
-
-Write a string which can be used as an identifier in C.
-
 .. note::
 
   If the ``SOURCE_DATE_EPOCH`` environment variable is set,
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 0f6d4cf..13948d3 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -289,7 +289,8 @@
 ``$<UPPER_CASE:...>``
   Content of ``...`` converted to upper case.
 ``$<MAKE_C_IDENTIFIER:...>``
-  Content of ``...`` converted to a C identifier.
+  Content of ``...`` converted to a C identifier.  The conversion follows the
+  same behavior as :command:`string(MAKE_C_IDENTIFIER)`.
 ``$<TARGET_OBJECTS:objLib>``
   List of objects resulting from build of ``objLib``. ``objLib`` must be an
   object of type ``OBJECT_LIBRARY``.
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 00a932f..d3e58d0 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -84,6 +84,7 @@
    /prop_dir/RULE_LAUNCH_LINK
    /prop_dir/SOURCE_DIR
    /prop_dir/SUBDIRECTORIES
+   /prop_dir/TESTS
    /prop_dir/TEST_INCLUDE_FILES
    /prop_dir/VARIABLES
    /prop_dir/VS_GLOBAL_SECTION_POST_section
diff --git a/Help/prop_dir/TESTS.rst b/Help/prop_dir/TESTS.rst
new file mode 100644
index 0000000..c6e1d88
--- /dev/null
+++ b/Help/prop_dir/TESTS.rst
@@ -0,0 +1,7 @@
+TESTS
+-----
+
+List of tests.
+
+This read-only property holds a :ref:`;-list <CMake Language Lists>` of tests
+defined so far by the :command:`add_test` command.
diff --git a/Help/release/dev/directory-property-TESTS.rst b/Help/release/dev/directory-property-TESTS.rst
new file mode 100644
index 0000000..9de2531
--- /dev/null
+++ b/Help/release/dev/directory-property-TESTS.rst
@@ -0,0 +1,5 @@
+directory-property-TESTS
+------------------------
+
+* The :prop_dir:`TESTS` directory property was added to hold the list of tests defined by
+  command :command:`add_test`.
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index c42b5d2..6d0108d 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 11)
-set(CMake_VERSION_PATCH 20180214)
+set(CMake_VERSION_PATCH 20180215)
 #set(CMake_VERSION_RC 1)
diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx
index 6f31a2d..817b5d9 100644
--- a/Source/cmExportBuildAndroidMKGenerator.cxx
+++ b/Source/cmExportBuildAndroidMKGenerator.cxx
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorTarget.h"
 #include "cmLinkItem.h"
 #include "cmLocalGenerator.h"
@@ -101,12 +102,21 @@
         os << "LOCAL_CPP_FEATURES += ";
         os << (property.second) << "\n";
       } else if (property.first == "INTERFACE_LINK_LIBRARIES") {
+        // evaluate any generator expressions with the current
+        // build type of the makefile
+        cmGeneratorExpression ge;
+        cmGeneratorExpressionDAGChecker dagChecker(
+          target->GetName(), "INTERFACE_LINK_LIBRARIES", nullptr, nullptr);
+        std::unique_ptr<cmCompiledGeneratorExpression> cge =
+          ge.Parse(property.second);
+        std::string evaluated = cge->Evaluate(
+          target->GetLocalGenerator(), config, false, target, &dagChecker);
         // need to look at list in pi->second and see if static or shared
         // FindTargetToLink
         // target->GetLocalGenerator()->FindGeneratorTargetToUse()
         // then add to LOCAL_CPPFLAGS
         std::vector<std::string> libraries;
-        cmSystemTools::ExpandListArgument(property.second, libraries);
+        cmSystemTools::ExpandListArgument(evaluated, libraries);
         std::string staticLibs;
         std::string sharedLibs;
         std::string ldlibs;
@@ -122,12 +132,6 @@
               staticLibs += " " + lib;
             }
           } else {
-            // evaluate any generator expressions with the current
-            // build type of the makefile
-            cmGeneratorExpression ge;
-            std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(lib);
-            std::string evaluated =
-              cge->Evaluate(target->GetLocalGenerator(), config);
             bool relpath = false;
             if (type == cmExportBuildAndroidMKGenerator::INSTALL) {
               relpath = lib.substr(0, 3) == "../";
@@ -135,12 +139,12 @@
             // check for full path or if it already has a -l, or
             // in the case of an install check for relative paths
             // if it is full or a link library then use string directly
-            if (cmSystemTools::FileIsFullPath(evaluated) ||
-                evaluated.substr(0, 2) == "-l" || relpath) {
-              ldlibs += " " + evaluated;
+            if (cmSystemTools::FileIsFullPath(lib) ||
+                lib.substr(0, 2) == "-l" || relpath) {
+              ldlibs += " " + lib;
               // if it is not a path and does not have a -l then add -l
-            } else if (!evaluated.empty()) {
-              ldlibs += " -l" + evaluated;
+            } else if (!lib.empty()) {
+              ldlibs += " -l" + lib;
             }
           }
         }
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 8c889fc..c1af92f 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <utility>
 
+#include "cmCryptoHash.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmGeneratedFileStream.h"
@@ -24,6 +25,7 @@
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
+#include "cmsys/FStream.hxx"
 
 cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg,
                                              cmMakefile* mf)
@@ -286,8 +288,51 @@
   }
 }
 
+std::string cmLocalNinjaGenerator::WriteCommandScript(
+  std::vector<std::string> const& cmdLines, std::string const& customStep,
+  cmGeneratorTarget const* target) const
+{
+  std::string scriptPath;
+  if (target) {
+    scriptPath = target->GetSupportDirectory();
+  } else {
+    scriptPath = this->GetCurrentBinaryDirectory();
+    scriptPath += cmake::GetCMakeFilesDirectory();
+  }
+  cmSystemTools::MakeDirectory(scriptPath);
+  scriptPath += '/';
+  scriptPath += customStep;
+#ifdef _WIN32
+  scriptPath += ".bat";
+#else
+  scriptPath += ".sh";
+#endif
+
+  cmsys::ofstream script(scriptPath.c_str());
+
+#ifndef _WIN32
+  script << "set -e\n\n";
+#endif
+
+  for (auto const& i : cmdLines) {
+    std::string cmd = i;
+    // The command line was built assuming it would be written to
+    // the build.ninja file, so it uses '$$' for '$'.  Remove this
+    // for the raw shell script.
+    cmSystemTools::ReplaceString(cmd, "$$", "$");
+#ifdef _WIN32
+    script << cmd << " || exit /b" << '\n';
+#else
+    script << cmd << '\n';
+#endif
+  }
+
+  return scriptPath;
+}
+
 std::string cmLocalNinjaGenerator::BuildCommandLine(
-  const std::vector<std::string>& cmdLines)
+  std::vector<std::string> const& cmdLines, std::string const& customStep,
+  cmGeneratorTarget const* target) const
 {
   // If we have no commands but we need to build a command anyway, use noop.
   // This happens when building a POST_BUILD value for link targets that
@@ -296,6 +341,35 @@
     return cmGlobalNinjaGenerator::SHELL_NOOP;
   }
 
+  // If this is a custom step then we will have no '$VAR' ninja placeholders.
+  // This means we can deal with long command sequences by writing to a script.
+  // Do this if the command lines are on the scale of the OS limit.
+  if (!customStep.empty()) {
+    size_t cmdLinesTotal = 0;
+    for (std::string const& cmd : cmdLines) {
+      cmdLinesTotal += cmd.length() + 6;
+    }
+    if (cmdLinesTotal > cmSystemTools::CalculateCommandLineLengthLimit() / 2) {
+      std::string const scriptPath =
+        this->WriteCommandScript(cmdLines, customStep, target);
+      std::string cmd
+#ifndef _WIN32
+        = "/bin/sh "
+#endif
+        ;
+      cmd += this->ConvertToOutputFormat(
+        this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(scriptPath),
+        cmOutputConverter::SHELL);
+
+      // Add an unused argument based on script content so that Ninja
+      // knows when the command lines change.
+      cmd += " ";
+      cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+      cmd += hash.HashFile(scriptPath).substr(0, 16);
+      return cmd;
+    }
+  }
+
   std::ostringstream cmd;
   for (std::vector<std::string>::const_iterator li = cmdLines.begin();
        li != cmdLines.end(); ++li)
@@ -406,10 +480,16 @@
       "Phony custom command for " + ninjaOutputs[0], ninjaOutputs, ninjaDeps,
       cmNinjaDeps(), orderOnlyDeps, cmNinjaVars());
   } else {
+    std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
+    // Hash full path to make unique.
+    customStep += '-';
+    cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+    customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
+
     this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild(
-      this->BuildCommandLine(cmdLines), this->ConstructComment(ccg),
-      "Custom command for " + ninjaOutputs[0], cc->GetDepfile(),
-      cc->GetUsesTerminal(),
+      this->BuildCommandLine(cmdLines, customStep),
+      this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
+      cc->GetDepfile(), cc->GetUsesTerminal(),
       /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, ninjaDeps,
       orderOnlyDeps);
   }
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index 95d8a61..f772fb0 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -59,7 +59,10 @@
     return this->HomeRelativeOutputPath;
   }
 
-  std::string BuildCommandLine(const std::vector<std::string>& cmdLines);
+  std::string BuildCommandLine(
+    std::vector<std::string> const& cmdLines,
+    std::string const& customStep = std::string(),
+    cmGeneratorTarget const* target = nullptr) const;
 
   void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs);
   void AppendTargetDepends(
@@ -98,6 +101,10 @@
 
   std::string MakeCustomLauncher(cmCustomCommandGenerator const& ccg);
 
+  std::string WriteCommandScript(std::vector<std::string> const& cmdLines,
+                                 std::string const& customStep,
+                                 cmGeneratorTarget const* target) const;
+
   std::string HomeRelativeOutputPath;
 
   typedef std::map<cmCustomCommand const*, std::set<cmGeneratorTarget*>>
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index b468208..82c6e81 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -3641,6 +3641,20 @@
 
 const char* cmMakefile::GetProperty(const std::string& prop) const
 {
+  // Check for computed properties.
+  static std::string output;
+  if (prop == "TESTS") {
+    std::vector<std::string> keys;
+    // get list of keys
+    std::transform(this->Tests.begin(), this->Tests.end(),
+                   std::back_inserter(keys),
+                   [](decltype(this->Tests)::value_type const& pair) {
+                     return pair.first;
+                   });
+    output = cmJoin(keys, ";");
+    return output.c_str();
+  }
+
   return this->StateSnapshot.GetDirectory().GetProperty(prop);
 }
 
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index ddbc772..f1fb2d2 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -976,8 +976,10 @@
     preLinkCmdLines.push_back("cd " + homeOutDir);
   }
 
-  vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines);
-  std::string postBuildCmdLine = localGen.BuildCommandLine(postBuildCmdLines);
+  vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines, "pre-link",
+                                               this->GeneratorTarget);
+  std::string postBuildCmdLine = localGen.BuildCommandLine(
+    postBuildCmdLines, "post-build", this->GeneratorTarget);
 
   cmNinjaVars symlinkVars;
   bool const symlinkNeeded =
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
index 7adeb8e..cc6d4b9 100644
--- a/Source/cmNinjaUtilityTargetGenerator.cxx
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -96,8 +96,8 @@
       this->GetBuildFileStream(),
       "Utility command for " + this->GetTargetName(), outputs, deps);
   } else {
-    std::string command =
-      this->GetLocalGenerator()->BuildCommandLine(commands);
+    std::string command = this->GetLocalGenerator()->BuildCommandLine(
+      commands, "utility", this->GeneratorTarget);
     const char* echoStr =
       this->GetGeneratorTarget()->GetProperty("EchoString");
     std::string desc;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index ec31bd6..92d67db 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -84,16 +84,15 @@
 
 cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
   cmGeneratorTarget* target, cmGlobalVisualStudio10Generator* gg)
+  : GeneratorTarget(target)
+  , Makefile(target->Target->GetMakefile())
+  , Platform(gg->GetPlatformName())
+  , Name(target->GetName())
+  , GUID(gg->GetGUID(this->Name))
+  , GlobalGenerator(gg)
+  , LocalGenerator((cmLocalVisualStudio7Generator*)target->GetLocalGenerator())
 {
-  this->GlobalGenerator = gg;
-  this->GeneratorTarget = target;
-  this->Makefile = target->Target->GetMakefile();
   this->Makefile->GetConfigurations(this->Configurations);
-  this->LocalGenerator =
-    (cmLocalVisualStudio7Generator*)this->GeneratorTarget->GetLocalGenerator();
-  this->Name = this->GeneratorTarget->GetName();
-  this->GUID = this->GlobalGenerator->GetGUID(this->Name);
-  this->Platform = gg->GetPlatformName();
   this->NsightTegra = gg->IsNsightTegra();
   for (int i = 0; i < 4; ++i) {
     this->NsightTegraVersion[i] = 0;
@@ -602,8 +601,7 @@
       if (!name.empty()) {
         std::string path = i.second.GetValue();
         if (!cmsys::SystemTools::FileIsFullPath(path)) {
-          path = std::string(this->GeneratorTarget->Target->GetMakefile()
-                               ->GetCurrentSourceDirectory()) +
+          path = std::string(this->Makefile->GetCurrentSourceDirectory()) +
             "/" + path;
         }
         ConvertToWindowsSlash(path);
@@ -994,11 +992,8 @@
 void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues(
   std::string const& config)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
-  const char* mfcFlag =
-    this->GeneratorTarget->Target->GetMakefile()->GetDefinition(
-      "CMAKE_MFC_FLAG");
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
+  const char* mfcFlag = this->Makefile->GetDefinition("CMAKE_MFC_FLAG");
   if (mfcFlag) {
     std::string const mfcFlagValue = mfcFlag;
 
@@ -1046,8 +1041,7 @@
 void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged(
   std::string const& config)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
 
   Options& o = *(this->ClOptions[config]);
 
@@ -1100,8 +1094,7 @@
 void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues(
   std::string const&)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   const char* toolset = gg->GetPlatformToolset();
   std::string ntv = "<NdkToolchainVersion>";
   ntv += toolset ? toolset : "Default";
@@ -1226,7 +1219,7 @@
   for (std::vector<std::string>::const_iterator i =
          this->Configurations.begin();
        i != this->Configurations.end(); ++i) {
-    cmCustomCommandGenerator ccg(command, *i, this->LocalGenerator);
+    cmCustomCommandGenerator ccg(command, *i, lg);
     std::string comment = lg->ConstructComment(ccg);
     comment = cmVS10EscapeComment(comment);
     std::string script = cmVS10EscapeXML(lg->ConstructScript(ccg));
@@ -1236,7 +1229,7 @@
     for (std::vector<std::string>::const_iterator d = ccg.GetDepends().begin();
          d != ccg.GetDepends().end(); ++d) {
       std::string dep;
-      if (this->LocalGenerator->GetRealDependency(*d, *i, dep)) {
+      if (lg->GetRealDependency(*d, *i, dep)) {
         ConvertToWindowsSlash(dep);
         inputs << ";" << cmVS10EscapeXML(dep);
       }
@@ -1334,6 +1327,7 @@
     pos++;
   }
 }
+
 void cmVisualStudio10TargetGenerator::WriteGroups()
 {
   if (this->ProjectType == csproj) {
@@ -2110,8 +2104,7 @@
       (*this->BuildFileStream) << firstString;
       firstString = ""; // only do firstString once
       hasFlags = true;
-      cmGlobalVisualStudio10Generator* gg =
-        static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+      cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
       cmIDEFlagTable const* flagtable = nullptr;
       const std::string& srclang = source->GetLanguage();
       if (srclang == "C" || srclang == "CXX") {
@@ -2374,8 +2367,7 @@
   // copied from cmLocalVisualStudio7Generator.cxx 805
   // TODO: Integrate code below with cmLocalVisualStudio7Generator.
 
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   std::unique_ptr<Options> pOptions;
   switch (this->ProjectType) {
     case vcxproj:
@@ -2422,15 +2414,11 @@
     std::string baseFlagVar = "CMAKE_";
     baseFlagVar += langForClCompile;
     baseFlagVar += "_FLAGS";
-    flags =
-      this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition(
-        baseFlagVar);
+    flags = this->Makefile->GetRequiredDefinition(baseFlagVar);
     std::string flagVar =
       baseFlagVar + std::string("_") + cmSystemTools::UpperCase(configName);
     flags += " ";
-    flags +=
-      this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition(
-        flagVar);
+    flags += this->Makefile->GetRequiredDefinition(flagVar);
     this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
                                             langForClCompile, configName);
   }
@@ -2446,8 +2434,7 @@
   this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName);
 
   // Get preprocessor definitions for this directory.
-  std::string defineFlags =
-    this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags();
+  std::string defineFlags = this->Makefile->GetDefineFlags();
   if (this->MSTools) {
     if (this->ProjectType == vcxproj) {
       clOptions.FixExceptionHandlingDefault();
@@ -2605,8 +2592,7 @@
 bool cmVisualStudio10TargetGenerator::ComputeRcOptions(
   std::string const& configName)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   auto pOptions = cm::make_unique<Options>(
     this->LocalGenerator, Options::ResourceCompiler, gg->GetRcFlagTable());
   Options& rcOptions = *pOptions;
@@ -2666,8 +2652,7 @@
 bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
   std::string const& configName)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   auto pOptions = cm::make_unique<Options>(
     this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable());
   Options& cudaOptions = *pOptions;
@@ -2683,8 +2668,7 @@
                                           configName);
 
   // Get preprocessor definitions for this directory.
-  std::string defineFlags =
-    this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags();
+  std::string defineFlags = this->Makefile->GetDefineFlags();
 
   cudaOptions.Parse(flags.c_str());
   cudaOptions.Parse(defineFlags.c_str());
@@ -2804,8 +2788,7 @@
 bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
   std::string const& configName)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   auto pOptions = cm::make_unique<Options>(
     this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable());
   Options& cudaLinkOptions = *pOptions;
@@ -2873,8 +2856,7 @@
 bool cmVisualStudio10TargetGenerator::ComputeMasmOptions(
   std::string const& configName)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   auto pOptions = cm::make_unique<Options>(
     this->LocalGenerator, Options::MasmCompiler, gg->GetMasmFlagTable());
   Options& masmOptions = *pOptions;
@@ -2933,8 +2915,7 @@
 bool cmVisualStudio10TargetGenerator::ComputeNasmOptions(
   std::string const& configName)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   auto pOptions = cm::make_unique<Options>(
     this->LocalGenerator, Options::NasmCompiler, gg->GetNasmFlagTable());
   Options& nasmOptions = *pOptions;
@@ -2994,8 +2975,7 @@
     libflags, cmSystemTools::UpperCase(config), this->GeneratorTarget);
   if (!libflags.empty()) {
     this->WriteString("<Lib>\n", 2);
-    cmGlobalVisualStudio10Generator* gg =
-      static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+    cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
     cmVisualStudioGeneratorOptions libOptions(
       this->LocalGenerator, cmVisualStudioGeneratorOptions::Linker,
       gg->GetLibFlagTable(), 0, this);
@@ -3185,8 +3165,7 @@
 bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
   std::string const& config)
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   auto pOptions =
     cm::make_unique<Options>(this->LocalGenerator, Options::Linker,
                              gg->GetLinkFlagTable(), nullptr, this);
@@ -3217,12 +3196,10 @@
   linkFlagVarBase += linkType;
   linkFlagVarBase += "_LINKER_FLAGS";
   flags += " ";
-  flags += this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition(
-    linkFlagVarBase);
+  flags += this->Makefile->GetRequiredDefinition(linkFlagVarBase);
   std::string linkFlagVar = linkFlagVarBase + "_" + CONFIG;
   flags += " ";
-  flags += this->GeneratorTarget->Target->GetMakefile()->GetRequiredDefinition(
-    linkFlagVar);
+  flags += this->Makefile->GetRequiredDefinition(linkFlagVar);
   const char* targetLinkFlags =
     this->GeneratorTarget->GetProperty("LINK_FLAGS");
   if (targetLinkFlags) {
@@ -3679,8 +3656,7 @@
     }
     // skip fortran targets as they can not be processed by MSBuild
     // the only reference will be in the .sln file
-    if (static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)
-          ->TargetIsFortranOnly(dt)) {
+    if (this->GlobalGenerator->TargetIsFortranOnly(dt)) {
       continue;
     }
     this->WriteString("<ProjectReference Include=\"", 2);
@@ -3706,8 +3682,7 @@
     (*this->BuildFileStream) << name << "</Name>\n";
     this->WriteDotNetReferenceCustomTags(name);
     if (csproj == this->ProjectType) {
-      if (!static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator)
-             ->TargetCanBeReferenced(dt)) {
+      if (!this->GlobalGenerator->TargetCanBeReferenced(dt)) {
         this->WriteString(
           "<ReferenceOutputAssembly>false</ReferenceOutputAssembly>\n", 3);
       }
@@ -3921,8 +3896,7 @@
 
 void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings()
 {
-  cmGlobalVisualStudio10Generator* gg =
-    static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator);
+  cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
   bool isAppContainer = false;
   bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone();
   bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore();
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 33d4fb7..adef127 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -190,19 +190,19 @@
   bool InSourceBuild;
   std::vector<std::string> Configurations;
   std::vector<TargetsFileAndConfigs> TargetsFileAndConfigsVec;
-  cmGeneratorTarget* GeneratorTarget;
-  cmMakefile* Makefile;
-  std::string Platform;
-  std::string GUID;
-  std::string Name;
+  cmGeneratorTarget* const GeneratorTarget;
+  cmMakefile* const Makefile;
+  std::string const Platform;
+  std::string const Name;
+  std::string const GUID;
   bool MSTools;
   bool Managed;
   bool NsightTegra;
   int NsightTegraVersion[4];
   bool TargetCompileAsWinRT;
-  cmGlobalVisualStudio10Generator* GlobalGenerator;
+  cmGlobalVisualStudio10Generator* const GlobalGenerator;
   cmGeneratedFileStream* BuildFileStream;
-  cmLocalVisualStudio7Generator* LocalGenerator;
+  cmLocalVisualStudio7Generator* const LocalGenerator;
   std::set<cmSourceFile const*> SourcesVisited;
   std::set<std::string> CSharpCustomCommandNames;
   bool IsMissingFiles;
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 08bfebe..62157bb 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -816,6 +816,8 @@
 
   ADD_TEST_MACRO(CustomCommandByproducts CustomCommandByproducts)
 
+  ADD_TEST_MACRO(CommandLength CommandLength)
+
   ADD_TEST_MACRO(EmptyDepends ${CMAKE_CTEST_COMMAND})
 
   add_test(CustomCommandWorkingDirectory  ${CMAKE_CTEST_COMMAND}
diff --git a/Tests/CommandLength/CMakeLists.txt b/Tests/CommandLength/CMakeLists.txt
new file mode 100644
index 0000000..6836051
--- /dev/null
+++ b/Tests/CommandLength/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.10)
+project(CommandLength C)
+
+add_executable(CommandLength test.c)
+add_custom_command(TARGET CommandLength POST_BUILD VERBATIM
+  COMMAND ${CMAKE_COMMAND} -E make_directory log)
+
+set(msg "xxxx $$$$ yyyy")
+set(msg "${msg} ${msg}")
+set(msg "${msg} ${msg}")
+set(msg "${msg} ${msg}")
+set(msg "${msg} ${msg}")
+foreach(i RANGE 1 1000)
+  add_custom_command(TARGET CommandLength POST_BUILD VERBATIM
+    COMMAND ${CMAKE_COMMAND} -E echo "${i} ${msg}" > log/${i}
+    )
+endforeach()
diff --git a/Tests/CommandLength/test.c b/Tests/CommandLength/test.c
new file mode 100644
index 0000000..f8b643a
--- /dev/null
+++ b/Tests/CommandLength/test.c
@@ -0,0 +1,4 @@
+int main()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/AndroidMK/AndroidMK.cmake b/Tests/RunCMake/AndroidMK/AndroidMK.cmake
index 2596e8c..3fbb2cf 100644
--- a/Tests/RunCMake/AndroidMK/AndroidMK.cmake
+++ b/Tests/RunCMake/AndroidMK/AndroidMK.cmake
@@ -4,7 +4,7 @@
 add_library(car foo.cxx)
 add_library(bar bar.c)
 add_library(dog  foo.cxx)
-target_link_libraries(foo car bar dog debug -lm)
+target_link_libraries(foo PRIVATE car bar dog debug -lm)
 export(TARGETS bar dog car foo  ANDROID_MK
   ${build_BINARY_DIR}/Android.mk)
 install(TARGETS bar dog car foo DESTINATION lib EXPORT myexp)
diff --git a/Tests/RunCMake/get_property/directory_properties-stderr.txt b/Tests/RunCMake/get_property/directory_properties-stderr.txt
index 6d5bcdb..89f5618 100644
--- a/Tests/RunCMake/get_property/directory_properties-stderr.txt
+++ b/Tests/RunCMake/get_property/directory_properties-stderr.txt
@@ -19,4 +19,12 @@
 get_directory_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties-build/directory_properties<--
 get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties-build/directory_properties<--
 get_directory_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties<--
-get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties<--$
+get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties<--
+get_directory_property: --><--
+get_property: --><--
+get_directory_property: -->test1;test2<--
+get_property: -->test1;test2<--
+get_directory_property: -->test1;test2;test3<--
+get_property: -->test1;test2;test3<--
+get_directory_property: -->Sub/test1;Sub/test2<--
+get_property: -->Sub/test1;Sub/test2<--$
diff --git a/Tests/RunCMake/get_property/directory_properties.cmake b/Tests/RunCMake/get_property/directory_properties.cmake
index 4e68738..9b978fd 100644
--- a/Tests/RunCMake/get_property/directory_properties.cmake
+++ b/Tests/RunCMake/get_property/directory_properties.cmake
@@ -28,3 +28,12 @@
 check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" SOURCE_DIR)
 check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" BINARY_DIR)
 check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" SOURCE_DIR)
+
+check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" TESTS)
+add_test(NAME test1 COMMAND "${CMAKE_COMMAND}" -E echo "test1")
+add_test(NAME test2 COMMAND "${CMAKE_COMMAND}" -E echo "test2")
+check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" TESTS)
+add_test(NAME test3 COMMAND "${CMAKE_COMMAND}" -E echo "test3")
+check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" TESTS)
+
+check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" TESTS)
diff --git a/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt b/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt
index 7318b97..95106ad 100644
--- a/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt
+++ b/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt
@@ -4,3 +4,6 @@
 add_custom_target(CustomSub)
 add_library(InterfaceSub INTERFACE)
 add_library(my::InterfaceSub ALIAS InterfaceSub)
+
+add_test(Sub/test1 COMMAND "${CMAKE_COMMAND}" -E echo "Sub/test1")
+add_test(Sub/test2 COMMAND "${CMAKE_COMMAND}" -E echo "Sub/test2")