[Cmake-commits] CMake branch, master, updated. v3.13.2-854-g6092a77

Kitware Robot kwrobot at kitware.com
Thu Jan 10 09:43:06 EST 2019


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, master has been updated
       via  6092a770f66bff959749170141d44188f4b6f3f1 (commit)
       via  143fbde17b5b22355a372bac774b26e75eba574a (commit)
       via  18ca9d082072f90eb8412565dbaa242ad0a56c14 (commit)
       via  dd71b683e5ba86708d301cb42affebcdd558dcd4 (commit)
       via  91fa6a472cd262014a74d765b003bb1cc9d7ab8a (commit)
       via  a1b3d79f728f2c626d3aac2e68dbab524baa4634 (commit)
       via  cd32886b2f5c8f6bdcc9185274a934102c821a20 (commit)
       via  163cc8bbdd20fceaa6958a071e3d15f53b224864 (commit)
       via  6d99406e698a3d1b0b69b0fc0f6e09e93fc4ed79 (commit)
       via  03f74a16cde9e2e7e3433054970cc7cadd31388f (commit)
       via  d07f453f39b477d687dd87aad2e1cd766598b434 (commit)
       via  67209a9291c672f7c6d6cc36f28e6adbc9c42b8c (commit)
       via  fc41a95f0803abb2b5daa4f0eb21cf38c625bd26 (commit)
       via  2ec3363ea5f5c569063a9094959cf166a54f8ce2 (commit)
       via  6d53a60f007b0a1a1c03ce5f9373eddc55f49d5a (commit)
       via  757737075a3f998c9ecc93f5c467dabe4b005fee (commit)
       via  5395c526fc0066aad302298ab9ad46cc19b771ab (commit)
       via  7b81d8c21e0a0d8756f0afdc0530c2d06ee3bcd4 (commit)
       via  00530d74d5d07a320c998d6caccc00cf4e59b06d (commit)
       via  9045f6a30fc8ce21d2b2298c27ba1da41c23bbf3 (commit)
      from  ecf3c5c6f322168e11aa37d899b076ef4abc5625 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6092a770f66bff959749170141d44188f4b6f3f1
commit 6092a770f66bff959749170141d44188f4b6f3f1
Merge: 143fbde 163cc8b
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 10 14:38:07 2019 +0000
Commit:     Kitware Robot <kwrobot at kitware.com>
CommitDate: Thu Jan 10 09:38:14 2019 -0500

    Merge topic 'vs-refactor'
    
    163cc8bbdd VS: Convert WriteSLNHeader to non-virtual lookup table
    6d99406e69 VS: Move ExpressEdition member to top-level generator
    03f74a16cd VS: Convert GetIDEVersion to non-virtual table lookup
    d07f453f39 VS: Convert GetToolsVersion to non-virtual table lookup
    757737075a VS: Remove unused MSBuild XML parsing script
    5395c526fc cmake: Drop unused table entry for selecting default generator
    
    Acked-by: Kitware Robot <kwrobot at kitware.com>
    Merge-request: !2780


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=143fbde17b5b22355a372bac774b26e75eba574a
commit 143fbde17b5b22355a372bac774b26e75eba574a
Merge: 18ca9d0 67209a9
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 10 14:37:14 2019 +0000
Commit:     Kitware Robot <kwrobot at kitware.com>
CommitDate: Thu Jan 10 09:37:25 2019 -0500

    Merge topic 'ctest-show-as-json'
    
    67209a9291 Tests: Add cases for ctest --show-only=json-v1
    fc41a95f08 CTest: Add --show-only[=format] option to print test info
    7b81d8c21e TestGenerator: Record support file and line where test was added
    00530d74d5 Tests: Pass python interpreter into RunCMake.CTestCommandLine
    
    Acked-by: Kitware Robot <kwrobot at kitware.com>
    Acked-by: Brad King <brad.king at kitware.com>
    Merge-request: !2499


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=18ca9d082072f90eb8412565dbaa242ad0a56c14
commit 18ca9d082072f90eb8412565dbaa242ad0a56c14
Merge: dd71b68 91fa6a4
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 10 09:36:20 2019 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 10 09:36:20 2019 -0500

    Merge branch 'release-3.13'


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=dd71b683e5ba86708d301cb42affebcdd558dcd4
commit dd71b683e5ba86708d301cb42affebcdd558dcd4
Merge: a1b3d79 2ec3363
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 10 14:35:34 2019 +0000
Commit:     Kitware Robot <kwrobot at kitware.com>
CommitDate: Thu Jan 10 09:35:40 2019 -0500

    Merge topic 'cmake-CDU-option-parsing'
    
    2ec3363ea5 Tests: Add cases for -{C,D,U} without a source tree
    6d53a60f00 cmake: distinguish '-Cpath' from '-C path' in source dir parsing
    
    Acked-by: Kitware Robot <kwrobot at kitware.com>
    Merge-request: !2783


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a1b3d79f728f2c626d3aac2e68dbab524baa4634
commit a1b3d79f728f2c626d3aac2e68dbab524baa4634
Merge: ecf3c5c cd32886
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 10 14:33:30 2019 +0000
Commit:     Kitware Robot <kwrobot at kitware.com>
CommitDate: Thu Jan 10 09:33:48 2019 -0500

    Merge topic 'autogen-qt6'
    
    cd32886b2f Autogen: Add AUTO(MOC|RCC|UIC)_EXECUTABLE target properties
    9045f6a30f Autogen: Prepare for Qt 6
    
    Acked-by: Kitware Robot <kwrobot at kitware.com>
    Merge-request: !2679


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd32886b2f5c8f6bdcc9185274a934102c821a20
commit cd32886b2f5c8f6bdcc9185274a934102c821a20
Author:     Tobias Hunger <tobias.hunger at qt.io>
AuthorDate: Wed Nov 28 16:00:50 2018 +0100
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 10 08:03:24 2019 -0500

    Autogen: Add AUTO(MOC|RCC|UIC)_EXECUTABLE target properties
    
    Allow to force moc/rcc/uic compiler used for AUTO(MOC|RCC|UIC).
    
    Setting these properties is only necessary if you are going to do
    strange things like build these tools as part of your own build system.
    
    Setting these properties will also prevent cmake from testing the
    binary: It is user-provided and assumed to be valid.

diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 047859d..df8f12c 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -129,13 +129,16 @@ Properties on Targets
    /prop_tgt/AUTOGEN_TARGET_DEPENDS
    /prop_tgt/AUTOMOC_COMPILER_PREDEFINES
    /prop_tgt/AUTOMOC_DEPEND_FILTERS
+   /prop_tgt/AUTOMOC_EXECUTABLE
    /prop_tgt/AUTOMOC_MACRO_NAMES
    /prop_tgt/AUTOMOC_MOC_OPTIONS
    /prop_tgt/AUTOMOC
    /prop_tgt/AUTOUIC
+   /prop_tgt/AUTOUIC_EXECUTABLE
    /prop_tgt/AUTOUIC_OPTIONS
    /prop_tgt/AUTOUIC_SEARCH_PATHS
    /prop_tgt/AUTORCC
+   /prop_tgt/AUTORCC_EXECUTABLE
    /prop_tgt/AUTORCC_OPTIONS
    /prop_tgt/BINARY_DIR
    /prop_tgt/BUILD_RPATH
diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst
index 7a3fd48..3e6d560 100644
--- a/Help/prop_tgt/AUTOMOC.rst
+++ b/Help/prop_tgt/AUTOMOC.rst
@@ -58,6 +58,9 @@ source files at build time and invoke moc accordingly.
 This property is initialized by the value of the :variable:`CMAKE_AUTOMOC`
 variable if it is set when a target is created.
 
+The ``moc`` executable will be detected automatically, but can be forced to
+a certain binary using the :prop_tgt:`AUTOMOC_EXECUTABLE` property.
+
 Additional command line options for ``moc`` can be set via the
 :prop_tgt:`AUTOMOC_MOC_OPTIONS` property.
 
diff --git a/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst b/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst
new file mode 100644
index 0000000..6b66ce8
--- /dev/null
+++ b/Help/prop_tgt/AUTOMOC_EXECUTABLE.rst
@@ -0,0 +1,15 @@
+AUTOMOC_EXECUTABLE
+------------------
+
+:prop_tgt:`AUTOMOC_EXECUTABLE` is file path pointing to the ``moc``
+executable to use for :prop_tgt:`AUTOMOC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``moc`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``moc`` can not work -- e.g. because
+you are building the ``moc`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTORCC.rst b/Help/prop_tgt/AUTORCC.rst
index 27fb149..5db6ed0 100644
--- a/Help/prop_tgt/AUTORCC.rst
+++ b/Help/prop_tgt/AUTORCC.rst
@@ -21,6 +21,9 @@ If the ``.qrc`` file is :prop_sf:`GENERATED` though, a
 Additional command line options for rcc can be set via the
 :prop_sf:`AUTORCC_OPTIONS` source file property on the ``.qrc`` file.
 
+The ``rcc`` executable will be detected automatically, but can be forced to
+a certain binary using the :prop_tgt:`AUTORCC_EXECUTABLE` property.
+
 The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group
 the autorcc targets together in an IDE, e.g. in MSVS.
 
diff --git a/Help/prop_tgt/AUTORCC_EXECUTABLE.rst b/Help/prop_tgt/AUTORCC_EXECUTABLE.rst
new file mode 100644
index 0000000..ca0fbd7
--- /dev/null
+++ b/Help/prop_tgt/AUTORCC_EXECUTABLE.rst
@@ -0,0 +1,15 @@
+AUTORCC_EXECUTABLE
+------------------
+
+:prop_tgt:`AUTORCC_EXECUTABLE` is file path pointing to the ``rcc``
+executable to use for :prop_tgt:`AUTORCC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``rcc`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``rcc`` can not work -- e.g. because
+you are building the ``rcc`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst
index 4f58b35..85226c1 100644
--- a/Help/prop_tgt/AUTOUIC.rst
+++ b/Help/prop_tgt/AUTOUIC.rst
@@ -30,6 +30,9 @@ Additional command line options for ``uic`` can be set via the
 The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the
 autouic targets together in an IDE, e.g. in MSVS.
 
+The ``uic`` executable will be detected automatically, but can be forced to
+a certain binary using the :prop_tgt:`AUTOUIC_EXECUTABLE` property.
+
 Source files can be excluded from :prop_tgt:`AUTOUIC` processing by
 enabling :prop_sf:`SKIP_AUTOUIC` or the broader :prop_sf:`SKIP_AUTOGEN`.
 
diff --git a/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst b/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst
new file mode 100644
index 0000000..03bd554
--- /dev/null
+++ b/Help/prop_tgt/AUTOUIC_EXECUTABLE.rst
@@ -0,0 +1,15 @@
+AUTOUIC_EXECUTABLE
+------------------
+
+:prop_tgt:`AUTOUIC_EXECUTABLE` is file path pointing to the ``uic``
+executable to use for :prop_tgt:`AUTOUIC` enabled files. Setting
+this property will make CMake skip the automatic detection of the
+``uic`` binary as well as the sanity-tests normally run to ensure
+that the binary is available and working as expected.
+
+Usually this property does not need to be set. Only consider this
+property if auto-detection of ``uic`` can not work -- e.g. because
+you are building the ``uic`` binary as part of your project.
+
+See the :manual:`cmake-qt(7)` manual for more information on using CMake
+with Qt.
diff --git a/Help/release/dev/autogen_executables.rst b/Help/release/dev/autogen_executables.rst
new file mode 100644
index 0000000..5e967ea
--- /dev/null
+++ b/Help/release/dev/autogen_executables.rst
@@ -0,0 +1,9 @@
+AUTO*_EXECUTABLE
+----------------
+
+* The :prop_tgt:`AUTOMOC_EXECUTABLE`, :prop_tgt:`AUTORCC_EXECUTABLE` and
+  :prop_tgt:`AUTOUIC_EXECUTABLE` target properties all take a path to an
+  executable and force automoc/autorcc/autouic to use this executable.
+
+  Setting these will also prevent the configure time testing for these
+  executables. This is mainly useful when you build these tools yourself.
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 0ed8af4..678ff14 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -75,14 +75,26 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
       bool const uic = target->GetPropertyAsBool("AUTOUIC");
       bool const rcc = target->GetPropertyAsBool("AUTORCC");
       if (moc || uic || rcc) {
-        // We support Qt4 and Qt5
+        std::string const mocExec =
+          target->GetSafeProperty("AUTOMOC_EXECUTABLE");
+        std::string const uicExec =
+          target->GetSafeProperty("AUTOUIC_EXECUTABLE");
+        std::string const rccExec =
+          target->GetSafeProperty("AUTORCC_EXECUTABLE");
+
+        // We support Qt4, Qt5 and Qt6
         auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
-        if ((qtVersion.Major == 4) || (qtVersion.Major == 5) ||
-            (qtVersion.Major == 6)) {
+        bool const validQt = (qtVersion.Major == 4) ||
+          (qtVersion.Major == 5) || (qtVersion.Major == 6);
+        bool const mocIsValid = moc && (validQt || !mocExec.empty());
+        bool const uicIsValid = uic && (validQt || !uicExec.empty());
+        bool const rccIsValid = rcc && (validQt || !rccExec.empty());
+
+        if (mocIsValid || uicIsValid || rccIsValid) {
           // Create autogen target initializer
           Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
-            this, target, qtVersion, moc, uic, rcc, globalAutoGenTarget,
-            globalAutoRccTarget));
+            this, target, qtVersion, mocIsValid, uicIsValid, rccIsValid,
+            globalAutoGenTarget, globalAutoRccTarget));
         }
       }
     }
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index ffa6a35..e4d2c82 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -9,6 +9,7 @@
 #include "cmCustomCommandLines.h"
 #include "cmDuration.h"
 #include "cmFilePathChecksum.h"
+#include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmLinkItem.h"
@@ -398,8 +399,16 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
     }
 
     // Init uic specific settings
-    if (this->Uic.Enabled && !InitUic()) {
-      return false;
+    if (this->Uic.Enabled) {
+      if (InitUic()) {
+        auto* uicTarget = makefile->FindTargetToUse(
+          GetQtExecutableTargetName(this->QtVersion, "uic"));
+        if (uicTarget != nullptr) {
+          this->AutogenTarget.DependTargets.insert(uicTarget);
+        }
+      } else {
+        return false;
+      }
     }
 
     // Autogen target name
@@ -440,6 +449,12 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
       this->AutogenTarget.DependOrigin =
         this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
 
+      auto* mocTarget = makefile->FindTargetToUse(
+        GetQtExecutableTargetName(this->QtVersion, "moc"));
+      if (mocTarget != nullptr) {
+        this->AutogenTarget.DependTargets.insert(mocTarget);
+      }
+
       std::string const deps =
         this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
       if (!deps.empty()) {
@@ -1095,6 +1110,7 @@ bool cmQtAutoGenInitializer::InitRccTargets()
 {
   cmMakefile* makefile = this->Target->Target->GetMakefile();
   cmLocalGenerator* localGen = this->Target->GetLocalGenerator();
+  auto rccTargetName = GetQtExecutableTargetName(this->QtVersion, "rcc");
 
   for (Qrc const& qrc : this->Rcc.Qrcs) {
     // Register info file as generated by CMake
@@ -1105,6 +1121,11 @@ bool cmQtAutoGenInitializer::InitRccTargets()
     std::vector<std::string> ccOutput;
     ccOutput.push_back(qrc.RccFile);
 
+    std::vector<std::string> ccDepends;
+    // Add the .qrc and info file to the custom command dependencies
+    ccDepends.push_back(qrc.QrcFile);
+    ccDepends.push_back(qrc.InfoFile);
+
     cmCustomCommandLines commandLines;
     if (this->MultiConfig) {
       // Build for all configurations
@@ -1140,15 +1161,12 @@ bool cmQtAutoGenInitializer::InitRccTargets()
           ccName += "_";
           ccName += qrc.PathChecksum;
         }
-        std::vector<std::string> ccDepends;
-        // Add the .qrc and info file to the custom target dependencies
-        ccDepends.push_back(qrc.QrcFile);
-        ccDepends.push_back(qrc.InfoFile);
 
         cmTarget* autoRccTarget = makefile->AddUtilityCommand(
           ccName, cmMakefile::TargetOrigin::Generator, true,
           this->Dir.Work.c_str(), ccOutput, ccDepends, commandLines, false,
           ccComment.c_str());
+
         // Create autogen generator target
         localGen->AddGeneratorTarget(
           new cmGeneratorTarget(autoRccTarget, localGen));
@@ -1157,6 +1175,9 @@ bool cmQtAutoGenInitializer::InitRccTargets()
         if (!this->TargetsFolder.empty()) {
           autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str());
         }
+        if (!rccTargetName.empty()) {
+          autoRccTarget->AddUtility(rccTargetName, makefile);
+        }
       }
       // Add autogen target to the origin target dependencies
       this->Target->Target->AddUtility(ccName, makefile);
@@ -1169,16 +1190,15 @@ bool cmQtAutoGenInitializer::InitRccTargets()
       // Create custom rcc command
       {
         std::vector<std::string> ccByproducts;
-        std::vector<std::string> ccDepends;
-        // Add the .qrc and info file to the custom command dependencies
-        ccDepends.push_back(qrc.QrcFile);
-        ccDepends.push_back(qrc.InfoFile);
 
         // Add the resource files to the dependencies
         for (std::string const& fileName : qrc.Resources) {
           // Add resource file to the custom command dependencies
           ccDepends.push_back(fileName);
         }
+        if (!rccTargetName.empty()) {
+          ccDepends.push_back(rccTargetName);
+        }
         makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends,
                                            /*main_dependency*/ std::string(),
                                            commandLines, ccComment.c_str(),
@@ -1421,21 +1441,36 @@ std::pair<bool, std::string> GetQtExecutable(
   const cmQtAutoGen::IntegerVersion& qtVersion, cmGeneratorTarget* target,
   const std::string& executable, bool ignoreMissingTarget, std::string* output)
 {
+  const std::string upperExecutable = cmSystemTools::UpperCase(executable);
+  std::string result =
+    target->Target->GetSafeProperty("AUTO" + upperExecutable + "_EXECUTABLE");
+  if (!result.empty()) {
+    cmListFileBacktrace lfbt = target->Target->GetMakefile()->GetBacktrace();
+    cmGeneratorExpression ge(lfbt);
+    std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(result);
+    result = cge->Evaluate(target->GetLocalGenerator(), "");
+
+    return std::make_pair(true, result);
+  }
+
   std::string err;
-  std::string result;
 
   // Find executable
   {
     const std::string targetName =
       GetQtExecutableTargetName(qtVersion, executable);
     if (targetName.empty()) {
-      err = "The AUTOMOC, AUTOUIC and AUTORCC feature ";
+      err = "The AUTO" + upperExecutable + " feature ";
       err += "supports only Qt 4, Qt 5 and Qt 6.";
     } else {
       cmLocalGenerator* localGen = target->GetLocalGenerator();
       cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName);
       if (tgt != nullptr) {
-        result = tgt->ImportedGetLocation("");
+        if (tgt->IsImported()) {
+          result = tgt->ImportedGetLocation("");
+        } else {
+          result = tgt->GetLocation("");
+        }
       } else {
         if (ignoreMissingTarget) {
           return std::make_pair(true, "");

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=163cc8bbdd20fceaa6958a071e3d15f53b224864
commit 163cc8bbdd20fceaa6958a071e3d15f53b224864
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Jan 9 11:51:12 2019 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 10 07:52:51 2019 -0500

    VS: Convert WriteSLNHeader to non-virtual lookup table

diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 6be1e23..4709194 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -488,16 +488,6 @@ std::string cmGlobalVisualStudio10Generator::SelectWindowsCEToolset() const
   return "";
 }
 
-void cmGlobalVisualStudio10Generator::WriteSLNHeader(std::ostream& fout)
-{
-  fout << "Microsoft Visual Studio Solution File, Format Version 11.00\n";
-  if (this->ExpressEdition) {
-    fout << "# Visual C++ Express 2010\n";
-  } else {
-    fout << "# Visual Studio 2010\n";
-  }
-}
-
 ///! Create a local generator appropriate to this Global Generator
 cmLocalGenerator* cmGlobalVisualStudio10Generator::CreateLocalGenerator(
   cmMakefile* mf)
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 7a071e2..1e72959 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -43,7 +43,6 @@ public:
    */
   void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
                       bool optional) override;
-  void WriteSLNHeader(std::ostream& fout) override;
 
   bool IsCudaEnabled() const { return this->CudaEnabled; }
 
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
index 4cde874..499ae32 100644
--- a/Source/cmGlobalVisualStudio11Generator.cxx
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -188,16 +188,6 @@ bool cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset(
     toolset);
 }
 
-void cmGlobalVisualStudio11Generator::WriteSLNHeader(std::ostream& fout)
-{
-  fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
-  if (this->ExpressEdition) {
-    fout << "# Visual Studio Express 2012 for Windows Desktop\n";
-  } else {
-    fout << "# Visual Studio 2012\n";
-  }
-}
-
 bool cmGlobalVisualStudio11Generator::UseFolderProperty() const
 {
   // Intentionally skip up to the top-level class implementation.
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
index f7ae0d6..6346da2 100644
--- a/Source/cmGlobalVisualStudio11Generator.h
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -26,8 +26,6 @@ public:
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
-  void WriteSLNHeader(std::ostream& fout) override;
-
 protected:
   bool InitializeWindowsPhone(cmMakefile* mf) override;
   bool InitializeWindowsStore(cmMakefile* mf) override;
diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx
index 3be7d24..2cec48c 100644
--- a/Source/cmGlobalVisualStudio12Generator.cxx
+++ b/Source/cmGlobalVisualStudio12Generator.cxx
@@ -186,16 +186,6 @@ bool cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset(
     toolset);
 }
 
-void cmGlobalVisualStudio12Generator::WriteSLNHeader(std::ostream& fout)
-{
-  fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
-  if (this->ExpressEdition) {
-    fout << "# Visual Studio Express 2013 for Windows Desktop\n";
-  } else {
-    fout << "# Visual Studio 2013\n";
-  }
-}
-
 bool cmGlobalVisualStudio12Generator::IsWindowsDesktopToolsetInstalled() const
 {
   const char desktop81Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h
index d392280..1b7bbc9 100644
--- a/Source/cmGlobalVisualStudio12Generator.h
+++ b/Source/cmGlobalVisualStudio12Generator.h
@@ -24,8 +24,6 @@ public:
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
-  void WriteSLNHeader(std::ostream& fout) override;
-
 protected:
   bool ProcessGeneratorToolsetField(std::string const& key,
                                     std::string const& value) override;
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index ac969e8..a6dbc23 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -174,17 +174,6 @@ bool cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
     toolset);
 }
 
-void cmGlobalVisualStudio14Generator::WriteSLNHeader(std::ostream& fout)
-{
-  // Visual Studio 14 writes .sln format 12.00
-  fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
-  if (this->ExpressEdition) {
-    fout << "# Visual Studio Express 14 for Windows Desktop\n";
-  } else {
-    fout << "# Visual Studio 14\n";
-  }
-}
-
 bool cmGlobalVisualStudio14Generator::IsWindowsDesktopToolsetInstalled() const
 {
   const char desktop10Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h
index 9494681..4be21e0 100644
--- a/Source/cmGlobalVisualStudio14Generator.h
+++ b/Source/cmGlobalVisualStudio14Generator.h
@@ -24,8 +24,6 @@ public:
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
-  void WriteSLNHeader(std::ostream& fout) override;
-
 protected:
   bool InitializeWindows(cmMakefile* mf) override;
   bool InitializeWindowsStore(cmMakefile* mf) override;
diff --git a/Source/cmGlobalVisualStudio15Generator.cxx b/Source/cmGlobalVisualStudio15Generator.cxx
index 4a08352..2af17e8 100644
--- a/Source/cmGlobalVisualStudio15Generator.cxx
+++ b/Source/cmGlobalVisualStudio15Generator.cxx
@@ -97,17 +97,6 @@ bool cmGlobalVisualStudio15Generator::MatchesGeneratorName(
   return false;
 }
 
-void cmGlobalVisualStudio15Generator::WriteSLNHeader(std::ostream& fout)
-{
-  // Visual Studio 15 writes .sln format 12.00
-  fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
-  if (this->ExpressEdition) {
-    fout << "# Visual Studio Express 15 for Windows Desktop\n";
-  } else {
-    fout << "# Visual Studio 15\n";
-  }
-}
-
 bool cmGlobalVisualStudio15Generator::SetGeneratorInstance(
   std::string const& i, cmMakefile* mf)
 {
diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h
index 5a3fa20..233f3bc 100644
--- a/Source/cmGlobalVisualStudio15Generator.h
+++ b/Source/cmGlobalVisualStudio15Generator.h
@@ -24,8 +24,6 @@ public:
 
   bool MatchesGeneratorName(const std::string& name) const override;
 
-  void WriteSLNHeader(std::ostream& fout) override;
-
   bool SetGeneratorInstance(std::string const& i, cmMakefile* mf) override;
 
   bool GetVSInstance(std::string& dir) const;
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
index 3be09b0..8694df2 100644
--- a/Source/cmGlobalVisualStudio71Generator.cxx
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -217,9 +217,3 @@ void cmGlobalVisualStudio71Generator::WriteProjectConfigurations(
     }
   }
 }
-
-// output standard header for dsw file
-void cmGlobalVisualStudio71Generator::WriteSLNHeader(std::ostream& fout)
-{
-  fout << "Microsoft Visual Studio Solution File, Format Version 8.00\n";
-}
diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h
index b634b95..85755af 100644
--- a/Source/cmGlobalVisualStudio71Generator.h
+++ b/Source/cmGlobalVisualStudio71Generator.h
@@ -34,7 +34,6 @@ protected:
   void WriteExternalProject(std::ostream& fout, const std::string& name,
                             const char* path, const char* typeGuid,
                             const std::set<BT<std::string>>& depends) override;
-  void WriteSLNHeader(std::ostream& fout) override;
 
   // Folders are not supported by VS 7.1.
   bool UseFolderProperty() const override { return false; }
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index 12a86f2..f092b56 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -134,7 +134,6 @@ protected:
   virtual void WriteSLNGlobalSections(std::ostream& fout,
                                       cmLocalGenerator* root);
   virtual void WriteSLNFooter(std::ostream& fout);
-  virtual void WriteSLNHeader(std::ostream& fout) = 0;
   std::string WriteUtilityDepend(const cmGeneratorTarget* target) override;
 
   virtual void WriteTargetsToSolution(
diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx
index 7ac3a6f..760cce4 100644
--- a/Source/cmGlobalVisualStudio9Generator.cxx
+++ b/Source/cmGlobalVisualStudio9Generator.cxx
@@ -94,12 +94,6 @@ cmGlobalVisualStudio9Generator::cmGlobalVisualStudio9Generator(
     vc9Express, cmSystemTools::KeyWOW64_32);
 }
 
-void cmGlobalVisualStudio9Generator::WriteSLNHeader(std::ostream& fout)
-{
-  fout << "Microsoft Visual Studio Solution File, Format Version 10.00\n";
-  fout << "# Visual Studio 2008\n";
-}
-
 std::string cmGlobalVisualStudio9Generator::GetUserMacrosDirectory()
 {
   std::string base;
diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h
index 5b50f77..e537a3d 100644
--- a/Source/cmGlobalVisualStudio9Generator.h
+++ b/Source/cmGlobalVisualStudio9Generator.h
@@ -18,12 +18,6 @@ public:
   static cmGlobalGeneratorFactory* NewFactory();
 
   /**
-   * Try to determine system information such as shared library
-   * extension, pthreads, byte order etc.
-   */
-  void WriteSLNHeader(std::ostream& fout) override;
-
-  /**
    * Where does this version of Visual Studio look for macros for the
    * current user? Returns the empty string if this version of Visual
    * Studio does not implement support for VB macros.
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index ff53487..adf0a81 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -62,6 +62,58 @@ const char* cmGlobalVisualStudioGenerator::GetIDEVersion() const
   return "";
 }
 
+void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout)
+{
+  switch (this->Version) {
+    case cmGlobalVisualStudioGenerator::VS9:
+      fout << "Microsoft Visual Studio Solution File, Format Version 10.00\n";
+      fout << "# Visual Studio 2008\n";
+      break;
+    case cmGlobalVisualStudioGenerator::VS10:
+      fout << "Microsoft Visual Studio Solution File, Format Version 11.00\n";
+      if (this->ExpressEdition) {
+        fout << "# Visual C++ Express 2010\n";
+      } else {
+        fout << "# Visual Studio 2010\n";
+      }
+      break;
+    case cmGlobalVisualStudioGenerator::VS11:
+      fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+      if (this->ExpressEdition) {
+        fout << "# Visual Studio Express 2012 for Windows Desktop\n";
+      } else {
+        fout << "# Visual Studio 2012\n";
+      }
+      break;
+    case cmGlobalVisualStudioGenerator::VS12:
+      fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+      if (this->ExpressEdition) {
+        fout << "# Visual Studio Express 2013 for Windows Desktop\n";
+      } else {
+        fout << "# Visual Studio 2013\n";
+      }
+      break;
+    case cmGlobalVisualStudioGenerator::VS14:
+      // Visual Studio 14 writes .sln format 12.00
+      fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+      if (this->ExpressEdition) {
+        fout << "# Visual Studio Express 14 for Windows Desktop\n";
+      } else {
+        fout << "# Visual Studio 14\n";
+      }
+      break;
+    case cmGlobalVisualStudioGenerator::VS15:
+      // Visual Studio 15 writes .sln format 12.00
+      fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
+      if (this->ExpressEdition) {
+        fout << "# Visual Studio Express 15 for Windows Desktop\n";
+      } else {
+        fout << "# Visual Studio 15\n";
+      }
+      break;
+  }
+}
+
 std::string cmGlobalVisualStudioGenerator::GetRegistryBase()
 {
   return cmGlobalVisualStudioGenerator::GetRegistryBase(this->GetIDEVersion());
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 58c0d90..0d4491d 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -142,6 +142,8 @@ protected:
 
   const char* GetIDEVersion() const;
 
+  void WriteSLNHeader(std::ostream& fout);
+
   bool ComputeTargetDepends() override;
   class VSDependSet : public std::set<std::string>
   {

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6d99406e698a3d1b0b69b0fc0f6e09e93fc4ed79
commit 6d99406e698a3d1b0b69b0fc0f6e09e93fc4ed79
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Jan 9 11:50:21 2019 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 10 07:52:49 2019 -0500

    VS: Move ExpressEdition member to top-level generator
    
    We no longer support any VS versions that pre-date introduction of
    express editions.

diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index 0ecf59f..cacfa68 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -44,9 +44,6 @@ public:
     return !this->WindowsCEVersion.empty();
   }
 
-  /** Is the installed VS an Express edition?  */
-  bool IsExpressEdition() const { return this->ExpressEdition; }
-
 protected:
   void AddExtraIDETargets() override;
 
@@ -76,6 +73,5 @@ protected:
 
   std::string Name;
   std::string WindowsCEVersion;
-  bool ExpressEdition;
 };
 #endif
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 6779dc8..58c0d90 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -47,6 +47,9 @@ public:
   VSVersion GetVersion() const;
   void SetVersion(VSVersion v);
 
+  /** Is the installed VS an Express edition?  */
+  bool IsExpressEdition() const { return this->ExpressEdition; }
+
   /**
    * Configure CMake's Visual Studio macros file into the user's Visual
    * Studio macros directory.
@@ -159,6 +162,7 @@ protected:
 
 protected:
   VSVersion Version;
+  bool ExpressEdition;
 
 private:
   virtual std::string GetVSMakeProgram() = 0;

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=03f74a16cde9e2e7e3433054970cc7cadd31388f
commit 03f74a16cde9e2e7e3433054970cc7cadd31388f
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Jan 9 11:28:57 2019 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 10 07:52:48 2019 -0500

    VS: Convert GetIDEVersion to non-virtual table lookup

diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 5c8ab1c..7a071e2 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -140,8 +140,6 @@ protected:
   virtual bool SelectWindowsPhoneToolset(std::string& toolset) const;
   virtual bool SelectWindowsStoreToolset(std::string& toolset) const;
 
-  const char* GetIDEVersion() const override { return "10.0"; }
-
   std::string const& GetMSBuildCommand();
 
   cmIDEFlagTable const* LoadFlagTable(std::string const& flagTableName,
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
index 5b089a4..f7ae0d6 100644
--- a/Source/cmGlobalVisualStudio11Generator.h
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -43,7 +43,6 @@ protected:
   bool IsWindowsPhoneToolsetInstalled() const;
   bool IsWindowsStoreToolsetInstalled() const;
 
-  const char* GetIDEVersion() const override { return "11.0"; }
   bool UseFolderProperty() const override;
   static std::set<std::string> GetInstalledWindowsCESDKs();
 
diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h
index 2e1e00c..d392280 100644
--- a/Source/cmGlobalVisualStudio12Generator.h
+++ b/Source/cmGlobalVisualStudio12Generator.h
@@ -43,7 +43,6 @@ protected:
   // of the toolset is installed
   bool IsWindowsPhoneToolsetInstalled() const;
   bool IsWindowsStoreToolsetInstalled() const;
-  const char* GetIDEVersion() const override { return "12.0"; }
 
 private:
   class Factory;
diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h
index 8edd018..9494681 100644
--- a/Source/cmGlobalVisualStudio14Generator.h
+++ b/Source/cmGlobalVisualStudio14Generator.h
@@ -39,7 +39,6 @@ protected:
   // version of the toolset.
   virtual std::string GetWindows10SDKMaxVersion() const;
 
-  const char* GetIDEVersion() const override { return "14.0"; }
   virtual bool SelectWindows10SDK(cmMakefile* mf, bool required);
 
   // Used to verify that the Desktop toolset for the current generator is
diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h
index 6bf95c3..5a3fa20 100644
--- a/Source/cmGlobalVisualStudio15Generator.h
+++ b/Source/cmGlobalVisualStudio15Generator.h
@@ -37,8 +37,6 @@ protected:
   bool InitializeWindows(cmMakefile* mf) override;
   bool SelectWindowsStoreToolset(std::string& toolset) const override;
 
-  const char* GetIDEVersion() const override { return "15.0"; }
-
   // Used to verify that the Desktop toolset for the current generator is
   // installed on the machine.
   bool IsWindowsDesktopToolsetInstalled() const override;
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index a21c53d..0ecf59f 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -49,7 +49,6 @@ public:
 
 protected:
   void AddExtraIDETargets() override;
-  const char* GetIDEVersion() const override { return "8.0"; }
 
   std::string FindDevEnvCommand() override;
 
diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h
index ee17c37..5b50f77 100644
--- a/Source/cmGlobalVisualStudio9Generator.h
+++ b/Source/cmGlobalVisualStudio9Generator.h
@@ -36,9 +36,6 @@ public:
    */
   std::string GetUserMacrosRegKeyBase() override;
 
-protected:
-  const char* GetIDEVersion() const override { return "9.0"; }
-
 private:
   class Factory;
   friend class Factory;
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index da3daf8..ff53487 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -43,6 +43,25 @@ void cmGlobalVisualStudioGenerator::SetVersion(VSVersion v)
   this->Version = v;
 }
 
+const char* cmGlobalVisualStudioGenerator::GetIDEVersion() const
+{
+  switch (this->Version) {
+    case cmGlobalVisualStudioGenerator::VS9:
+      return "9.0";
+    case cmGlobalVisualStudioGenerator::VS10:
+      return "10.0";
+    case cmGlobalVisualStudioGenerator::VS11:
+      return "11.0";
+    case cmGlobalVisualStudioGenerator::VS12:
+      return "12.0";
+    case cmGlobalVisualStudioGenerator::VS14:
+      return "14.0";
+    case cmGlobalVisualStudioGenerator::VS15:
+      return "15.0";
+  }
+  return "";
+}
+
 std::string cmGlobalVisualStudioGenerator::GetRegistryBase()
 {
   return cmGlobalVisualStudioGenerator::GetRegistryBase(this->GetIDEVersion());
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index c891160..6779dc8 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -137,7 +137,7 @@ protected:
   // below 8.
   virtual bool VSLinksDependencies() const { return true; }
 
-  virtual const char* GetIDEVersion() const = 0;
+  const char* GetIDEVersion() const;
 
   bool ComputeTargetDepends() override;
   class VSDependSet : public std::set<std::string>

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d07f453f39b477d687dd87aad2e1cd766598b434
commit d07f453f39b477d687dd87aad2e1cd766598b434
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Jan 9 11:21:20 2019 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 10 07:51:47 2019 -0500

    VS: Convert GetToolsVersion to non-virtual table lookup

diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index c9c6938..6be1e23 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -1024,6 +1024,27 @@ std::string cmGlobalVisualStudio10Generator::Encoding()
   return "utf-8";
 }
 
+const char* cmGlobalVisualStudio10Generator::GetToolsVersion() const
+{
+  switch (this->Version) {
+    case cmGlobalVisualStudioGenerator::VS9:
+    case cmGlobalVisualStudioGenerator::VS10:
+    case cmGlobalVisualStudioGenerator::VS11:
+      return "4.0";
+
+      // in Visual Studio 2013 they detached the MSBuild tools version
+      // from the .Net Framework version and instead made it have it's own
+      // version number
+    case cmGlobalVisualStudioGenerator::VS12:
+      return "12.0";
+    case cmGlobalVisualStudioGenerator::VS14:
+      return "14.0";
+    case cmGlobalVisualStudioGenerator::VS15:
+      return "15.0";
+  }
+  return "";
+}
+
 bool cmGlobalVisualStudio10Generator::IsNsightTegra() const
 {
   return !this->NsightTegraVersion.empty();
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index dc49ded..5c8ab1c 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -104,7 +104,7 @@ public:
                    std::string const& sfRel);
 
   std::string Encoding() override;
-  virtual const char* GetToolsVersion() { return "4.0"; }
+  const char* GetToolsVersion() const;
 
   virtual bool IsDefaultToolset(const std::string& version) const;
   virtual std::string GetAuxiliaryToolset() const;
diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h
index ae78de7..2e1e00c 100644
--- a/Source/cmGlobalVisualStudio12Generator.h
+++ b/Source/cmGlobalVisualStudio12Generator.h
@@ -26,11 +26,6 @@ public:
 
   void WriteSLNHeader(std::ostream& fout) override;
 
-  // in Visual Studio 2013 they detached the MSBuild tools version
-  // from the .Net Framework version and instead made it have it's own
-  // version number
-  const char* GetToolsVersion() override { return "12.0"; }
-
 protected:
   bool ProcessGeneratorToolsetField(std::string const& key,
                                     std::string const& value) override;
diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h
index 4bc430b..8edd018 100644
--- a/Source/cmGlobalVisualStudio14Generator.h
+++ b/Source/cmGlobalVisualStudio14Generator.h
@@ -26,8 +26,6 @@ public:
 
   void WriteSLNHeader(std::ostream& fout) override;
 
-  const char* GetToolsVersion() override { return "14.0"; }
-
 protected:
   bool InitializeWindows(cmMakefile* mf) override;
   bool InitializeWindowsStore(cmMakefile* mf) override;
diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h
index 68aa14f..6bf95c3 100644
--- a/Source/cmGlobalVisualStudio15Generator.h
+++ b/Source/cmGlobalVisualStudio15Generator.h
@@ -26,8 +26,6 @@ public:
 
   void WriteSLNHeader(std::ostream& fout) override;
 
-  const char* GetToolsVersion() override { return "15.0"; }
-
   bool SetGeneratorInstance(std::string const& i, cmMakefile* mf) override;
 
   bool GetVSInstance(std::string& dir) const;

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=67209a9291c672f7c6d6cc36f28e6adbc9c42b8c
commit 67209a9291c672f7c6d6cc36f28e6adbc9c42b8c
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Nov 1 11:42:23 2018 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 10 07:37:35 2019 -0500

    Tests: Add cases for ctest --show-only=json-v1

diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index 750ae50..cae14b1 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -173,3 +173,32 @@ function(run_TestStdin)
   run_cmake_command(TestStdin ${CMAKE_CTEST_COMMAND} -V)
 endfunction()
 run_TestStdin()
+
+function(ShowAsJson_check_python v)
+  set(json_file "${RunCMake_TEST_BINARY_DIR}/ctest.json")
+  file(WRITE "${json_file}" "${actual_stdout}")
+  set(actual_stdout "" PARENT_SCOPE)
+  execute_process(
+    COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/ShowAsJson${v}-check.py" "${json_file}"
+    RESULT_VARIABLE result
+    OUTPUT_VARIABLE output
+    ERROR_VARIABLE output
+    )
+  if(NOT result EQUAL 0)
+    string(REPLACE "\n" "\n  " output "  ${output}")
+    set(RunCMake_TEST_FAILED "Unexpected output:\n${output}" PARENT_SCOPE)
+  endif()
+endfunction()
+
+function(run_ShowAsJson)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ShowAsJson)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "
+    add_test(ShowAsJson \"${CMAKE_COMMAND}\" -E echo)
+    set_tests_properties(ShowAsJson PROPERTIES WILL_FAIL true _BACKTRACE_TRIPLES \"file1;1;add_test;file0;;\")
+")
+  run_cmake_command(ShowAsJsonVersionOne ${CMAKE_CTEST_COMMAND} --show-only=json-v1)
+endfunction()
+run_ShowAsJson()
diff --git a/Tests/RunCMake/CTestCommandLine/ShowAsJson1-check.py b/Tests/RunCMake/CTestCommandLine/ShowAsJson1-check.py
new file mode 100644
index 0000000..d794e7d
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/ShowAsJson1-check.py
@@ -0,0 +1,106 @@
+from ShowAsJson_check import *
+
+def check_kind(k):
+    assert is_string(k)
+    assert k == "ctestInfo"
+
+def check_version(v):
+    assert is_dict(v)
+    assert sorted(v.keys()) == ["major", "minor"]
+    assert is_int(v["major"])
+    assert is_int(v["minor"])
+    assert v["major"] == 1
+    assert v["minor"] == 0
+
+def check_backtracegraph(b):
+    assert is_dict(b)
+    assert sorted(b.keys()) == ["commands", "files", "nodes"]
+    check_backtracegraph_commands(b["commands"])
+    check_backtracegraph_files(b["files"])
+    check_backtracegraph_nodes(b["nodes"])
+
+def check_backtracegraph_commands(c):
+    assert is_list(c)
+    assert len(c) == 1
+    assert is_string(c[0])
+    assert c[0] == "add_test"
+
+def check_backtracegraph_files(f):
+    assert is_list(f)
+    assert len(f) == 2
+    assert is_string(f[0])
+    assert is_string(f[1])
+    assert f[0] == "file1"
+    assert f[1] == "file0"
+
+def check_backtracegraph_nodes(n):
+    assert is_list(n)
+    assert len(n) == 2
+    node = n[0]
+    assert is_dict(node)
+    assert sorted(node.keys()) == ["file"]
+    assert is_int(node["file"])
+    assert node["file"] == 1
+    node = n[1]
+    assert is_dict(node)
+    assert sorted(node.keys()) == ["command", "file", "line", "parent"]
+    assert is_int(node["command"])
+    assert is_int(node["file"])
+    assert is_int(node["line"])
+    assert is_int(node["parent"])
+    assert node["command"] == 0
+    assert node["file"] == 0
+    assert node["line"] == 1
+    assert node["parent"] == 0
+
+def check_command(c):
+    assert is_list(c)
+    assert len(c) == 3
+    assert is_string(c[0])
+    check_re(c[0], "/cmake(\.exe)?$")
+    assert is_string(c[1])
+    assert c[1] == "-E"
+    assert is_string(c[2])
+    assert c[2] == "echo"
+
+def check_willfail_property(p):
+    assert is_dict(p)
+    assert sorted(p.keys()) == ["name", "value"]
+    assert is_string(p["name"])
+    assert is_bool(p["value"])
+    assert p["name"] == "WILL_FAIL"
+    assert p["value"] == True
+
+def check_workingdir_property(p):
+    assert is_dict(p)
+    assert sorted(p.keys()) == ["name", "value"]
+    assert is_string(p["name"])
+    assert is_string(p["value"])
+    assert p["name"] == "WORKING_DIRECTORY"
+    assert p["value"].endswith("Tests/RunCMake/CTestCommandLine/ShowAsJson")
+
+def check_properties(p):
+    assert is_list(p)
+    assert len(p) == 2
+    check_willfail_property(p[0])
+    check_workingdir_property(p[1])
+
+def check_tests(t):
+    assert is_list(t)
+    assert len(t) == 1
+    test = t[0]
+    assert is_dict(test)
+    assert sorted(test.keys()) == ["backtrace", "command", "name", "properties"]
+    assert is_int(test["backtrace"])
+    assert test["backtrace"] == 1
+    check_command(test["command"])
+    assert is_string(test["name"])
+    assert test["name"] == "ShowAsJson"
+    check_properties(test["properties"])
+
+assert is_dict(ctest_json)
+assert sorted(ctest_json.keys()) == ["backtraceGraph", "kind", "tests", "version"]
+check_backtracegraph(ctest_json["backtraceGraph"])
+check_kind(ctest_json["kind"])
+check_version(ctest_json["version"])
+check_tests(ctest_json["tests"])
diff --git a/Tests/RunCMake/CTestCommandLine/ShowAsJson_check.py b/Tests/RunCMake/CTestCommandLine/ShowAsJson_check.py
new file mode 100644
index 0000000..493c9e5
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/ShowAsJson_check.py
@@ -0,0 +1,24 @@
+import sys
+import json
+import re
+
+def is_bool(x):
+    return isinstance(x, bool)
+
+def is_dict(x):
+    return isinstance(x, dict)
+
+def is_list(x):
+    return isinstance(x, list)
+
+def is_int(x):
+    return isinstance(x, int) or isinstance(x, long)
+
+def is_string(x):
+    return isinstance(x, str) or isinstance(x, unicode)
+
+def check_re(x, regex):
+    assert re.search(regex, x)
+
+with open(sys.argv[1]) as f:
+    ctest_json = json.load(f)

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fc41a95f0803abb2b5daa4f0eb21cf38c625bd26
commit fc41a95f0803abb2b5daa4f0eb21cf38c625bd26
Author:     Justin Goshi <jgoshi at microsoft.com>
AuthorDate: Thu Oct 18 11:34:37 2018 -0700
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Thu Jan 10 07:37:32 2019 -0500

    CTest: Add --show-only[=format] option to print test info
    
    format can be 'human' to print the current text format or 'json-v1' to
    print the test object model in json format and is useful for IDEs who
    want to gather information about the tests. Defaults to 'human' format.

diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
index 1ef20ab..8490e3d 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -109,13 +109,23 @@ Options
 
  This option tells CTest to write all its output to a log file.
 
-``-N,--show-only``
+``-N,--show-only[=<format>]``
  Disable actual execution of tests.
 
  This option tells CTest to list the tests that would be run but not
  actually run them.  Useful in conjunction with the ``-R`` and ``-E``
  options.
 
+ ``<format>`` can be one of the following values.
+
+   ``human``
+     Human-friendly output.  This is not guaranteed to be stable.
+     This is the default.
+
+   ``json-v1``
+     Dump the test information in JSON format.
+     See `Show as JSON Object Model`_.
+
 ``-L <regex>, --label-regex <regex>``
  Run tests with labels matching regular expression.
 
@@ -1163,6 +1173,65 @@ Configuration settings include:
   * :module:`CTest` module variable: ``TRIGGER_SITE`` if set,
     else ``CTEST_TRIGGER_SITE``
 
+.. _`Show as JSON Object Model`:
+
+Show as JSON Object Model
+=========================
+
+When the ``--show-only=json-v1`` command line option is given, the test
+information is output in JSON format.  Version 1.0 of the JSON object
+model is defined as follows:
+
+``kind``
+  The string "ctestInfo".
+
+``version``
+  A JSON object specifying the version components.  Its members are
+
+  ``major``
+    A non-negative integer specifying the major version component.
+  ``minor``
+    A non-negative integer specifying the minor version component.
+
+``backtraceGraph``
+    JSON object representing backtrace information with the
+    following members:
+
+    ``commands``
+      List of command names.
+    ``files``
+      List of file names.
+    ``nodes``
+      List of node JSON objects with members:
+
+      ``command``
+        Index into the ``commands`` member of the ``backtraceGraph``.
+      ``file``
+        Index into the ``files`` member of the ``backtraceGraph``.
+      ``line``
+        Line number in the file where the backtrace was added.
+      ``parent``
+        Index into the ``nodes`` member of the ``backtraceGraph``
+        representing the parent in the graph.
+
+``tests``
+  A JSON array listing information about each test.  Each entry
+  is a JSON object with members:
+
+  ``name``
+    Test name.
+  ``config``
+    Configuration that the test can run on.
+    Empty string means any config.
+  ``command``
+    List where the first element is the test command and the
+    remaining elements are the command arguments.
+  ``backtrace``
+    Index into the ``nodes`` member of the ``backtraceGraph``.
+  ``properties``
+    Test properties.
+    Can contain keys for each of the supported test properties.
+
 See Also
 ========
 
diff --git a/Help/release/dev/ctest-show-only-json-v1.rst b/Help/release/dev/ctest-show-only-json-v1.rst
new file mode 100644
index 0000000..f593e7e
--- /dev/null
+++ b/Help/release/dev/ctest-show-only-json-v1.rst
@@ -0,0 +1,6 @@
+ctest-show-only-json-v1
+-----------------------
+
+* :manual:`ctest(1)` gained a ``--show-only=json-v1`` option to show the
+  list of tests in a machine-readable JSON format.
+  See the :ref:`Show as JSON Object Model` section of the manual.
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index f026001..8867323 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -6,9 +6,13 @@
 #include "cmCTest.h"
 #include "cmCTestRunTest.h"
 #include "cmCTestTestHandler.h"
+#include "cmDuration.h"
+#include "cmListFileCache.h"
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
 
+#include "cm_jsoncpp_value.h"
+#include "cm_jsoncpp_writer.h"
 #include "cm_uv.h"
 
 #include "cmUVSignalHackRAII.h" // IWYU pragma: keep
@@ -20,13 +24,19 @@
 #include <chrono>
 #include <cstring>
 #include <iomanip>
+#include <iostream>
 #include <list>
 #include <math.h>
 #include <sstream>
 #include <stack>
 #include <stdlib.h>
+#include <unordered_map>
 #include <utility>
 
+namespace cmsys {
+class RegularExpression;
+}
+
 class TestComparator
 {
 public:
@@ -725,9 +735,330 @@ void cmCTestMultiProcessHandler::MarkFinished()
   cmSystemTools::RemoveFile(fname);
 }
 
+static Json::Value DumpToJsonArray(const std::set<std::string>& values)
+{
+  Json::Value jsonArray = Json::arrayValue;
+  for (auto& it : values) {
+    jsonArray.append(it);
+  }
+  return jsonArray;
+}
+
+static Json::Value DumpToJsonArray(const std::vector<std::string>& values)
+{
+  Json::Value jsonArray = Json::arrayValue;
+  for (auto& it : values) {
+    jsonArray.append(it);
+  }
+  return jsonArray;
+}
+
+static Json::Value DumpRegExToJsonArray(
+  const std::vector<std::pair<cmsys::RegularExpression, std::string>>& values)
+{
+  Json::Value jsonArray = Json::arrayValue;
+  for (auto& it : values) {
+    jsonArray.append(it.second);
+  }
+  return jsonArray;
+}
+
+static Json::Value DumpMeasurementToJsonArray(
+  const std::map<std::string, std::string>& values)
+{
+  Json::Value jsonArray = Json::arrayValue;
+  for (auto& it : values) {
+    Json::Value measurement = Json::objectValue;
+    measurement["measurement"] = it.first;
+    measurement["value"] = it.second;
+    jsonArray.append(measurement);
+  }
+  return jsonArray;
+}
+
+static Json::Value DumpTimeoutAfterMatch(
+  cmCTestTestHandler::cmCTestTestProperties& testProperties)
+{
+  Json::Value timeoutAfterMatch = Json::objectValue;
+  timeoutAfterMatch["timeout"] = testProperties.AlternateTimeout.count();
+  timeoutAfterMatch["regex"] =
+    DumpRegExToJsonArray(testProperties.TimeoutRegularExpressions);
+  return timeoutAfterMatch;
+}
+
+static Json::Value DumpCTestProperty(std::string const& name,
+                                     Json::Value value)
+{
+  Json::Value property = Json::objectValue;
+  property["name"] = name;
+  property["value"] = std::move(value);
+  return property;
+}
+
+static Json::Value DumpCTestProperties(
+  cmCTestTestHandler::cmCTestTestProperties& testProperties)
+{
+  Json::Value properties = Json::arrayValue;
+  if (!testProperties.AttachOnFail.empty()) {
+    properties.append(DumpCTestProperty(
+      "ATTACHED_FILES_ON_FAIL", DumpToJsonArray(testProperties.AttachOnFail)));
+  }
+  if (!testProperties.AttachedFiles.empty()) {
+    properties.append(DumpCTestProperty(
+      "ATTACHED_FILES", DumpToJsonArray(testProperties.AttachedFiles)));
+  }
+  if (testProperties.Cost != 0.0f) {
+    properties.append(
+      DumpCTestProperty("COST", static_cast<double>(testProperties.Cost)));
+  }
+  if (!testProperties.Depends.empty()) {
+    properties.append(
+      DumpCTestProperty("DEPENDS", DumpToJsonArray(testProperties.Depends)));
+  }
+  if (testProperties.Disabled) {
+    properties.append(DumpCTestProperty("DISABLED", testProperties.Disabled));
+  }
+  if (!testProperties.Environment.empty()) {
+    properties.append(DumpCTestProperty(
+      "ENVIRONMENT", DumpToJsonArray(testProperties.Environment)));
+  }
+  if (!testProperties.ErrorRegularExpressions.empty()) {
+    properties.append(DumpCTestProperty(
+      "FAIL_REGULAR_EXPRESSION",
+      DumpRegExToJsonArray(testProperties.ErrorRegularExpressions)));
+  }
+  if (!testProperties.FixturesCleanup.empty()) {
+    properties.append(DumpCTestProperty(
+      "FIXTURES_CLEANUP", DumpToJsonArray(testProperties.FixturesCleanup)));
+  }
+  if (!testProperties.FixturesRequired.empty()) {
+    properties.append(DumpCTestProperty(
+      "FIXTURES_REQUIRED", DumpToJsonArray(testProperties.FixturesRequired)));
+  }
+  if (!testProperties.FixturesSetup.empty()) {
+    properties.append(DumpCTestProperty(
+      "FIXTURES_SETUP", DumpToJsonArray(testProperties.FixturesSetup)));
+  }
+  if (!testProperties.Labels.empty()) {
+    properties.append(
+      DumpCTestProperty("LABELS", DumpToJsonArray(testProperties.Labels)));
+  }
+  if (!testProperties.Measurements.empty()) {
+    properties.append(DumpCTestProperty(
+      "MEASUREMENT", DumpMeasurementToJsonArray(testProperties.Measurements)));
+  }
+  if (!testProperties.RequiredRegularExpressions.empty()) {
+    properties.append(DumpCTestProperty(
+      "PASS_REGULAR_EXPRESSION",
+      DumpRegExToJsonArray(testProperties.RequiredRegularExpressions)));
+  }
+  if (testProperties.WantAffinity) {
+    properties.append(
+      DumpCTestProperty("PROCESSOR_AFFINITY", testProperties.WantAffinity));
+  }
+  if (testProperties.Processors != 1) {
+    properties.append(
+      DumpCTestProperty("PROCESSORS", testProperties.Processors));
+  }
+  if (!testProperties.RequiredFiles.empty()) {
+    properties["REQUIRED_FILES"] =
+      DumpToJsonArray(testProperties.RequiredFiles);
+  }
+  if (!testProperties.LockedResources.empty()) {
+    properties.append(DumpCTestProperty(
+      "RESOURCE_LOCK", DumpToJsonArray(testProperties.LockedResources)));
+  }
+  if (testProperties.RunSerial) {
+    properties.append(
+      DumpCTestProperty("RUN_SERIAL", testProperties.RunSerial));
+  }
+  if (testProperties.SkipReturnCode != -1) {
+    properties.append(
+      DumpCTestProperty("SKIP_RETURN_CODE", testProperties.SkipReturnCode));
+  }
+  if (testProperties.ExplicitTimeout) {
+    properties.append(
+      DumpCTestProperty("TIMEOUT", testProperties.Timeout.count()));
+  }
+  if (!testProperties.TimeoutRegularExpressions.empty()) {
+    properties.append(DumpCTestProperty(
+      "TIMEOUT_AFTER_MATCH", DumpTimeoutAfterMatch(testProperties)));
+  }
+  if (testProperties.WillFail) {
+    properties.append(DumpCTestProperty("WILL_FAIL", testProperties.WillFail));
+  }
+  if (!testProperties.Directory.empty()) {
+    properties.append(
+      DumpCTestProperty("WORKING_DIRECTORY", testProperties.Directory));
+  }
+  return properties;
+}
+
+class BacktraceData
+{
+  std::unordered_map<std::string, Json::ArrayIndex> CommandMap;
+  std::unordered_map<std::string, Json::ArrayIndex> FileMap;
+  std::unordered_map<cmListFileContext const*, Json::ArrayIndex> NodeMap;
+  Json::Value Commands = Json::arrayValue;
+  Json::Value Files = Json::arrayValue;
+  Json::Value Nodes = Json::arrayValue;
+
+  Json::ArrayIndex AddCommand(std::string const& command)
+  {
+    auto i = this->CommandMap.find(command);
+    if (i == this->CommandMap.end()) {
+      i = this->CommandMap.emplace(command, this->Commands.size()).first;
+      this->Commands.append(command);
+    }
+    return i->second;
+  }
+
+  Json::ArrayIndex AddFile(std::string const& file)
+  {
+    auto i = this->FileMap.find(file);
+    if (i == this->FileMap.end()) {
+      i = this->FileMap.emplace(file, this->Files.size()).first;
+      this->Files.append(file);
+    }
+    return i->second;
+  }
+
+public:
+  bool Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index);
+  Json::Value Dump();
+};
+
+bool BacktraceData::Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index)
+{
+  if (bt.Empty()) {
+    return false;
+  }
+  cmListFileContext const* top = &bt.Top();
+  auto found = this->NodeMap.find(top);
+  if (found != this->NodeMap.end()) {
+    index = found->second;
+    return true;
+  }
+  Json::Value entry = Json::objectValue;
+  entry["file"] = this->AddFile(top->FilePath);
+  if (top->Line) {
+    entry["line"] = static_cast<int>(top->Line);
+  }
+  if (!top->Name.empty()) {
+    entry["command"] = this->AddCommand(top->Name);
+  }
+  Json::ArrayIndex parent;
+  if (this->Add(bt.Pop(), parent)) {
+    entry["parent"] = parent;
+  }
+  index = this->NodeMap[top] = this->Nodes.size();
+  this->Nodes.append(std::move(entry)); // NOLINT(*)
+  return true;
+}
+
+Json::Value BacktraceData::Dump()
+{
+  Json::Value backtraceGraph;
+  this->CommandMap.clear();
+  this->FileMap.clear();
+  this->NodeMap.clear();
+  backtraceGraph["commands"] = std::move(this->Commands);
+  backtraceGraph["files"] = std::move(this->Files);
+  backtraceGraph["nodes"] = std::move(this->Nodes);
+  return backtraceGraph;
+}
+
+static void AddBacktrace(BacktraceData& backtraceGraph, Json::Value& object,
+                         cmListFileBacktrace const& bt)
+{
+  Json::ArrayIndex backtrace;
+  if (backtraceGraph.Add(bt, backtrace)) {
+    object["backtrace"] = backtrace;
+  }
+}
+
+static Json::Value DumpCTestInfo(
+  cmCTestRunTest& testRun,
+  cmCTestTestHandler::cmCTestTestProperties& testProperties,
+  BacktraceData& backtraceGraph)
+{
+  Json::Value testInfo = Json::objectValue;
+  // test name should always be present
+  testInfo["name"] = testProperties.Name;
+  std::string const& config = testRun.GetCTest()->GetConfigType();
+  if (!config.empty()) {
+    testInfo["config"] = config;
+  }
+  std::string const& command = testRun.GetActualCommand();
+  if (!command.empty()) {
+    std::vector<std::string> commandAndArgs;
+    commandAndArgs.push_back(command);
+    const std::vector<std::string>& args = testRun.GetArguments();
+    if (!args.empty()) {
+      commandAndArgs.reserve(args.size() + 1);
+      commandAndArgs.insert(commandAndArgs.end(), args.begin(), args.end());
+    }
+    testInfo["command"] = DumpToJsonArray(commandAndArgs);
+  }
+  Json::Value properties = DumpCTestProperties(testProperties);
+  if (!properties.empty()) {
+    testInfo["properties"] = properties;
+  }
+  if (!testProperties.Backtrace.Empty()) {
+    AddBacktrace(backtraceGraph, testInfo, testProperties.Backtrace);
+  }
+  return testInfo;
+}
+
+static Json::Value DumpVersion(int major, int minor)
+{
+  Json::Value version = Json::objectValue;
+  version["major"] = major;
+  version["minor"] = minor;
+  return version;
+}
+
+void cmCTestMultiProcessHandler::PrintOutputAsJson()
+{
+  this->TestHandler->SetMaxIndex(this->FindMaxIndex());
+
+  Json::Value result = Json::objectValue;
+  result["kind"] = "ctestInfo";
+  result["version"] = DumpVersion(1, 0);
+
+  BacktraceData backtraceGraph;
+  Json::Value tests = Json::arrayValue;
+  for (auto& it : this->Properties) {
+    cmCTestTestHandler::cmCTestTestProperties& p = *it.second;
+
+    // Don't worry if this fails, we are only showing the test list, not
+    // running the tests
+    cmWorkingDirectory workdir(p.Directory);
+    cmCTestRunTest testRun(*this);
+    testRun.SetIndex(p.Index);
+    testRun.SetTestProperties(&p);
+    testRun.ComputeArguments();
+
+    Json::Value testInfo = DumpCTestInfo(testRun, p, backtraceGraph);
+    tests.append(testInfo);
+  }
+  result["backtraceGraph"] = backtraceGraph.Dump();
+  result["tests"] = std::move(tests);
+
+  Json::StreamWriterBuilder builder;
+  builder["indentation"] = "  ";
+  std::unique_ptr<Json::StreamWriter> jout(builder.newStreamWriter());
+  jout->write(result, &std::cout);
+}
+
 // For ShowOnly mode
 void cmCTestMultiProcessHandler::PrintTestList()
 {
+  if (this->CTest->GetOutputAsJson()) {
+    PrintOutputAsJson();
+    return;
+  }
+
   this->TestHandler->SetMaxIndex(this->FindMaxIndex());
   int count = 0;
 
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index 3927a8a..93bb880 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -51,6 +51,7 @@ public:
   void SetParallelLevel(size_t);
   void SetTestLoad(unsigned long load);
   virtual void RunTests();
+  void PrintOutputAsJson();
   void PrintTestList();
   void PrintLabels();
 
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 10dceca..c786413 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -78,6 +78,10 @@ public:
 
   cmCTest* GetCTest() const { return this->CTest; }
 
+  std::string& GetActualCommand() { return this->ActualCommand; }
+
+  const std::vector<std::string>& GetArguments() { return this->Arguments; }
+
   void FinalizeTest();
 
   bool TimedOutForStopTime() const { return this->TimeoutIsForStopTime; }
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 7c19864..225c99f 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -278,6 +278,8 @@ cmCTest::cmCTest()
   this->ExtraVerbose = false;
   this->ProduceXML = false;
   this->ShowOnly = false;
+  this->OutputAsJson = false;
+  this->OutputAsJsonVersion = 1;
   this->RunConfigurationScript = false;
   this->UseHTTP10 = false;
   this->PrintLabels = false;
@@ -1930,6 +1932,20 @@ bool cmCTest::HandleCommandLineArguments(size_t& i,
   if (this->CheckArgument(arg, "-N", "--show-only")) {
     this->ShowOnly = true;
   }
+  if (cmSystemTools::StringStartsWith(arg.c_str(), "--show-only=")) {
+    this->ShowOnly = true;
+
+    // Check if a specific format is requested. Defaults to human readable
+    // text.
+    std::string argWithFormat = "--show-only=";
+    std::string format = arg.substr(argWithFormat.length());
+    if (format == "json-v1") {
+      // Force quiet mode so the only output is the json object model.
+      this->Quiet = true;
+      this->OutputAsJson = true;
+      this->OutputAsJsonVersion = 1;
+    }
+  }
 
   if (this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1) {
     i++;
@@ -2630,6 +2646,16 @@ bool cmCTest::GetShowOnly()
   return this->ShowOnly;
 }
 
+bool cmCTest::GetOutputAsJson()
+{
+  return this->OutputAsJson;
+}
+
+int cmCTest::GetOutputAsJsonVersion()
+{
+  return this->OutputAsJsonVersion;
+}
+
 int cmCTest::GetMaxTestNameWidth() const
 {
   return this->MaxTestNameWidth;
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 480204a..2b40ca3 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -215,6 +215,10 @@ public:
   /** Should we only show what we would do? */
   bool GetShowOnly();
 
+  bool GetOutputAsJson();
+
+  int GetOutputAsJsonVersion();
+
   bool ShouldUseHTTP10() { return this->UseHTTP10; }
 
   bool ShouldPrintLabels() { return this->PrintLabels; }
@@ -507,6 +511,8 @@ private:
   t_TestingHandlers TestingHandlers;
 
   bool ShowOnly;
+  bool OutputAsJson;
+  int OutputAsJsonVersion;
 
   /** Map of configuration properties */
   typedef std::map<std::string, std::string> CTestConfigurationMap;
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index ca412ae..8ba126f 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -46,7 +46,10 @@ static const char* cmDocumentationOptions[][2] = {
     "given number of jobs." },
   { "-Q,--quiet", "Make ctest quiet." },
   { "-O <file>, --output-log <file>", "Output to log file" },
-  { "-N,--show-only", "Disable actual execution of tests." },
+  { "-N,--show-only[=format]",
+    "Disable actual execution of tests. The optional 'format' defines the "
+    "format of the test information and can be 'human' for the current text "
+    "format or 'json-v1' for json format. Defaults to 'human'." },
   { "-L <regex>, --label-regex <regex>",
     "Run tests with labels matching "
     "regular expression." },

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=757737075a3f998c9ecc93f5c467dabe4b005fee
commit 757737075a3f998c9ecc93f5c467dabe4b005fee
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Jan 9 14:21:34 2019 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 9 14:38:12 2019 -0500

    VS: Remove unused MSBuild XML parsing script
    
    It has been superseded by `cmConvertMSBuildXMLToJSON.py`.

diff --git a/Source/cmparseMSBuildXML.py b/Source/cmparseMSBuildXML.py
deleted file mode 100755
index 1b38d15..0000000
--- a/Source/cmparseMSBuildXML.py
+++ /dev/null
@@ -1,341 +0,0 @@
-# This python script parses the spec files from MSBuild to create
-# mappings from compiler options to IDE XML specifications.  For
-# more information see here:
-
-#  http://blogs.msdn.com/vcblog/archive/2008/12/16/msbuild-task.aspx
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/cl.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/lib.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/1033/link.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/cl.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/lib.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V110/1033/link.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/cl.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/lib.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/v120/1033/link.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V140/1033/cl.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V140/1033/lib.xml"
-#  "${PROGRAMFILES}/MSBuild/Microsoft.Cpp/v4.0/V140/1033/link.xml"
-#  "${PROGRAMFILES}/Microsoft Visual Studio/VS15Preview/Common7/IDE/VC/VCTargets/1033/cl.xml"
-#  "${PROGRAMFILES}/Microsoft Visual Studio/VS15Preview/Common7/IDE/VC/VCTargets/1033/lib.xml"
-#  "${PROGRAMFILES}/Microsoft Visual Studio/VS15Preview/Common7/IDE/VC/VCTargets/1033/link.xml"
-#
-#  BoolProperty  <Name>true|false</Name>
-#   simple example:
-#     <BoolProperty ReverseSwitch="Oy-" Name="OmitFramePointers"
-#      Category="Optimization" Switch="Oy">
-#   <BoolProperty.DisplayName>  <BoolProperty.Description>
-# <CLCompile>
-#     <OmitFramePointers>true</OmitFramePointers>
-#  </ClCompile>
-#
-#  argument means it might be this: /MP3
-#   example with argument:
-#   <BoolProperty Name="MultiProcessorCompilation" Category="General" Switch="MP">
-#      <BoolProperty.DisplayName>
-#        <sys:String>Multi-processor Compilation</sys:String>
-#      </BoolProperty.DisplayName>
-#      <BoolProperty.Description>
-#        <sys:String>Multi-processor Compilation</sys:String>
-#      </BoolProperty.Description>
-#      <Argument Property="ProcessorNumber" IsRequired="false" />
-#    </BoolProperty>
-# <CLCompile>
-#   <MultiProcessorCompilation>true</MultiProcessorCompilation>
-#   <ProcessorNumber>4</ProcessorNumber>
-#  </ClCompile>
-#  IntProperty
-#     not used AFIT
-#  <IntProperty Name="ProcessorNumber" Category="General" Visible="false">
-
-
-#  per config options example
-#    <EnableFiberSafeOptimizations Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnableFiberSafeOptimizations>
-#
-#  EnumProperty
-#   <EnumProperty Name="Optimization" Category="Optimization">
-#      <EnumProperty.DisplayName>
-#       <sys:String>Optimization</sys:String>
-#     </EnumProperty.DisplayName>
-#     <EnumProperty.Description>
-#       <sys:String>Select option for code optimization; choose Custom to use specific optimization options.     (/Od, /O1, /O2, /Ox)</sys:String>
-#     </EnumProperty.Description>
-#      <EnumValue Name="MaxSpeed" Switch="O2">
-#       <EnumValue.DisplayName>
-#         <sys:String>Maximize Speed</sys:String>
-#       </EnumValue.DisplayName>
-#       <EnumValue.Description>
-#         <sys:String>Equivalent to /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy</sys:String>
-#       </EnumValue.Description>
-#     </EnumValue>
-#     <EnumValue Name="MinSpace" Switch="O1">
-#       <EnumValue.DisplayName>
-#         <sys:String>Minimize Size</sys:String>
-#       </EnumValue.DisplayName>
-#       <EnumValue.Description>
-#         <sys:String>Equivalent to /Og /Os /Oy /Ob2 /Gs /GF /Gy</sys:String>
-#       </EnumValue.Description>
-#     </EnumValue>
-#     example for O2 would be this:
-#     <Optimization>MaxSpeed</Optimization>
-#     example for O1 would be this:
-#     <Optimization>MinSpace</Optimization>
-#
-#  StringListProperty
-#   <StringListProperty Name="PreprocessorDefinitions" Category="Preprocessor" Switch="D ">
-#     <StringListProperty.DisplayName>
-#       <sys:String>Preprocessor Definitions</sys:String>
-#     </StringListProperty.DisplayName>
-#     <StringListProperty.Description>
-#       <sys:String>Defines a preprocessing symbols for your source file.</sys:String>
-#     </StringListProperty.Description>
-#   </StringListProperty>
-
-#   <StringListProperty Subtype="folder" Name="AdditionalIncludeDirectories" Category="General" Switch="I">
-#     <StringListProperty.DisplayName>
-#       <sys:String>Additional Include Directories</sys:String>
-#     </StringListProperty.DisplayName>
-#     <StringListProperty.Description>
-#       <sys:String>Specifies one or more directories to add to the include path; separate with semi-colons if more than one.     (/I[path])</sys:String>
-#     </StringListProperty.Description>
-#   </StringListProperty>
-#  StringProperty
-
-# Example add bill include:
-
-#   <AdditionalIncludeDirectories>..\..\..\..\..\..\bill;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-
-
-import sys
-from xml.dom.minidom import parse, parseString
-
-def getText(node):
-    nodelist = node.childNodes
-    rc = ""
-    for child in nodelist:
-        if child.nodeType == child.TEXT_NODE:
-            rc = rc + child.data
-    return rc
-
-def print_tree(document, spaces=""):
-  for i in range(len(document.childNodes)):
-    if document.childNodes[i].nodeType == document.childNodes[i].ELEMENT_NODE:
-      print spaces+str(document.childNodes[i].nodeName )
-    print_tree(document.childNodes[i],spaces+"----")
-  pass
-
-###########################################################################################
-#Data structure that stores a property of MSBuild
-class Property:
-  #type = type of MSBuild property (ex. if the property is EnumProperty type should be "Enum")
-  #attributeNames = a list of any attributes that this property could have (ex. if this was a EnumProperty it should be ["Name","Category"])
-  #document = the dom file that's root node is the Property node (ex. if you were parsing a BoolProperty the root node should be something like <BoolProperty Name="RegisterOutput" Category="General" IncludeInCommandLine="false">
-  def __init__(self,type,attributeNames,document=None):
-    self.suffix_type = "Property"
-    self.prefix_type = type
-    self.attributeNames = attributeNames
-    self.attributes = {}
-    self.DisplayName = ""
-    self.Description = ""
-    self.argumentProperty = ""
-    self.argumentIsRequired = ""
-    self.values = []
-    if document is not None:
-      self.populate(document)
-    pass
-
-  #document = the dom file that's root node is the Property node (ex. if you were parsing a BoolProperty the root node should be something like <BoolProperty Name="RegisterOutput" Category="General" IncludeInCommandLine="false">
-  #spaces = do not use
-  def populate(self,document, spaces = ""):
-    if document.nodeName == self.prefix_type+self.suffix_type:
-      for i in self.attributeNames:
-        self.attributes[i] = document.getAttribute(i)
-    for i in range(len(document.childNodes)):
-      child = document.childNodes[i]
-      if child.nodeType == child.ELEMENT_NODE:
-        if child.nodeName == self.prefix_type+self.suffix_type+".DisplayName":
-          self.DisplayName = getText(child.childNodes[1])
-        if child.nodeName == self.prefix_type+self.suffix_type+".Description":
-          self.Description = getText(child.childNodes[1])
-        if child.nodeName == "Argument":
-          self.argumentProperty = child.getAttribute("Property")
-          self.argumentIsRequired = child.getAttribute("IsRequired")
-        if child.nodeName == self.prefix_type+"Value":
-          va = Property(self.prefix_type,["Name","DisplayName","Switch"])
-          va.suffix_type = "Value"
-          va.populate(child)
-          self.values.append(va)
-      self.populate(child,spaces+"----")
-      pass
-
-  #toString function
-  def __str__(self):
-    toReturn = self.prefix_type+self.suffix_type+":"
-    for i in self.attributeNames:
-      toReturn += "\n    "+i+": "+self.attributes[i]
-    if self.argumentProperty != "":
-      toReturn += "\n    Argument:\n        Property: "+self.argumentProperty+"\n        IsRequired: "+self.argumentIsRequired
-    for i in self.values:
-        toReturn+="\n    "+str(i).replace("\n","\n    ")
-    return toReturn
-###########################################################################################
-
-###########################################################################################
-#Class that populates itself from an MSBuild file and outputs it in CMake
-#format
-
-class MSBuildToCMake:
-  #document = the entire MSBuild xml file
-  def __init__(self,document=None):
-    self.enumProperties = []
-    self.stringProperties = []
-    self.stringListProperties = []
-    self.boolProperties = []
-    self.intProperties = []
-    if document!=None :
-      self.populate(document)
-    pass
-
-  #document = the entire MSBuild xml file
-  #spaces = don't use
-  #To add a new property (if they exist) copy and paste this code and fill in appropriate places
-  #
-  #if child.nodeName == "<Name>Property":
-  #        self.<Name>Properties.append(Property("<Name>",[<List of attributes>],child))
-  #
-  #Replace <Name> with the name of the new property (ex. if property is StringProperty replace <Name> with String)
-  #Replace <List of attributes> with a list of attributes in your property's root node
-  #in the __init__ function add the line self.<Name>Properties = []
-  #
-  #That is all that is required to add new properties
-  #
-  def populate(self,document, spaces=""):
-    for i in range(len(document.childNodes)):
-      child = document.childNodes[i]
-      if child.nodeType == child.ELEMENT_NODE:
-        if child.nodeName == "EnumProperty":
-          self.enumProperties.append(Property("Enum",["Name","Category"],child))
-        if child.nodeName == "StringProperty":
-          self.stringProperties.append(Property("String",["Name","Subtype","Separator","Category","Visible","IncludeInCommandLine","Switch","DisplayName","ReadOnly"],child))
-        if child.nodeName == "StringListProperty":
-           self.stringListProperties.append(Property("StringList",["Name","Category","Switch","DisplayName","Subtype"],child))
-        if child.nodeName == "BoolProperty":
-           self.boolProperties.append(Property("Bool",["ReverseSwitch","Name","Category","Switch","DisplayName","SwitchPrefix","IncludeInCommandLine"],child))
-        if child.nodeName == "IntProperty":
-           self.intProperties.append(Property("Int",["Name","Category","Visible"],child))
-      self.populate(child,spaces+"----")
-    pass
-
-  #outputs information that CMake needs to know about MSBuild xml files
-  def toCMake(self):
-    toReturn = "static cmVS7FlagTable cmVS10CxxTable[] =\n{\n"
-    toReturn += "\n  //Enum Properties\n"
-    lastProp = {}
-    for i in self.enumProperties:
-      if i.attributes["Name"] == "CompileAsManaged":
-        #write these out after the rest of the enumProperties
-        lastProp = i
-        continue
-      for j in i.values:
-        #hardcore Brad King's manual fixes for cmVS10CLFlagTable.h
-        if i.attributes["Name"] == "PrecompiledHeader" and j.attributes["Switch"] != "":
-          toReturn+="  {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n   \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\",\n   cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
-        else:
-          #default (normal, non-hardcoded) case
-          toReturn+="  {\""+i.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n   \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n"
-      toReturn += "\n"
-
-    if lastProp != {}:
-      for j in lastProp.values:
-          toReturn+="  {\""+lastProp.attributes["Name"]+"\", \""+j.attributes["Switch"]+"\",\n   \""+j.attributes["DisplayName"]+"\", \""+j.attributes["Name"]+"\", 0},\n"
-      toReturn += "\n"
-
-    toReturn += "\n  //Bool Properties\n"
-    for i in self.boolProperties:
-      if i.argumentProperty == "":
-        if i.attributes["ReverseSwitch"] != "":
-          toReturn += "  {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\", 0},\n"
-        if i.attributes["Switch"] != "":
-          toReturn += "  {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\", 0},\n"
-
-    toReturn += "\n  //Bool Properties With Argument\n"
-    for i in self.boolProperties:
-      if i.argumentProperty != "":
-        if i.attributes["ReverseSwitch"] != "":
-          toReturn += "  {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \"\", \"false\",\n   cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
-          toReturn += "  {\""+i.attributes["Name"]+"\", \""+i.attributes["ReverseSwitch"]+"\", \""+i.attributes["DisplayName"]+"\", \"\",\n   cmVS7FlagTable::UserValueRequired},\n"
-        if i.attributes["Switch"] != "":
-          toReturn += "  {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\", \"\", \"true\",\n   cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue},\n"
-          toReturn += "  {\""+i.argumentProperty+"\", \""+i.attributes["Switch"]+"\", \""+i.attributes["DisplayName"]+"\", \"\",\n   cmVS7FlagTable::UserValueRequired},\n"
-
-    toReturn += "\n  //String List Properties\n"
-    for i in self.stringListProperties:
-      if i.attributes["Switch"] == "":
-        toReturn += "  // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
-      else:
-        toReturn +="  {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+"\",\n   \""+i.attributes["DisplayName"]+"\",\n   \"\", cmVS7FlagTable::UserValue | cmVS7FlagTable::SemicolonAppendable},\n"
-
-    toReturn += "\n  //String Properties\n"
-    for i in self.stringProperties:
-      if i.attributes["Switch"] == "":
-        if i.attributes["Name"] == "PrecompiledHeaderFile":
-          #more hardcoding
-          toReturn += "  {\"PrecompiledHeaderFile\", \"Yc\",\n"
-          toReturn += "   \"Precompiled Header Name\",\n"
-          toReturn += "   \"\", cmVS7FlagTable::UserValueRequired},\n"
-          toReturn += "  {\"PrecompiledHeaderFile\", \"Yu\",\n"
-          toReturn += "   \"Precompiled Header Name\",\n"
-          toReturn += "   \"\", cmVS7FlagTable::UserValueRequired},\n"
-        else:
-          toReturn += "  // Skip [" + i.attributes["Name"] + "] - no command line Switch.\n";
-      else:
-        toReturn +="  {\""+i.attributes["Name"]+"\", \""+i.attributes["Switch"]+i.attributes["Separator"]+"\",\n   \""+i.attributes["DisplayName"]+"\",\n   \"\", cmVS7FlagTable::UserValue},\n"
-
-    toReturn += "  {0,0,0,0,0}\n};"
-    return toReturn
-    pass
-
-  #toString function
-  def __str__(self):
-    toReturn = ""
-    allList = [self.enumProperties,self.stringProperties,self.stringListProperties,self.boolProperties,self.intProperties]
-    for p in allList:
-      for i in p:
-        toReturn += "==================================================\n"+str(i).replace("\n","\n    ")+"\n==================================================\n"
-
-    return toReturn
-###########################################################################################
-
-###########################################################################################
-# main function
-def main(argv):
-  xml_file = None
-  help = """
-  Please specify an input xml file with -x
-
-  Exiting...
-  Have a nice day :)"""
-  for i in range(0,len(argv)):
-    if argv[i] == "-x":
-      xml_file = argv[i+1]
-    if argv[i] == "-h":
-      print help
-      sys.exit(0)
-    pass
-  if xml_file == None:
-    print help
-    sys.exit(1)
-
-  f = open(xml_file,"r")
-  xml_str = f.read()
-  xml_dom = parseString(xml_str)
-
-  convertor = MSBuildToCMake(xml_dom)
-  print convertor.toCMake()
-
-  xml_dom.unlink()
-###########################################################################################
-# main entry point
-if __name__ == "__main__":
-  main(sys.argv)
-
-sys.exit(0)

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5395c526fc0066aad302298ab9ad46cc19b771ab
commit 5395c526fc0066aad302298ab9ad46cc19b771ab
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Jan 9 09:25:20 2019 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 9 11:31:55 2019 -0500

    cmake: Drop unused table entry for selecting default generator
    
    In `cmake::CreateDefaultGlobalGenerator` the table of registry entries
    does not need an entry for VS 2017 because that is found via the VS
    setup helper.

diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 1bc36cc..e1bae34 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -1528,7 +1528,6 @@ void cmake::CreateDefaultGlobalGenerator()
     const char* GeneratorName;
   };
   static VSVersionedGenerator const vsGenerators[] = {
-    { "15.0", "Visual Studio 15 2017" }, //
     { "14.0", "Visual Studio 14 2015" }, //
     { "12.0", "Visual Studio 12 2013" }, //
     { "11.0", "Visual Studio 11 2012" }, //

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7b81d8c21e0a0d8756f0afdc0530c2d06ee3bcd4
commit 7b81d8c21e0a0d8756f0afdc0530c2d06ee3bcd4
Author:     Justin Goshi <jgoshi at microsoft.com>
AuthorDate: Thu Oct 18 11:33:01 2018 -0700
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 8 11:22:11 2019 -0500

    TestGenerator: Record support file and line where test was added
    
    Add internal test properties that ctest can use to report where
    the test was added in CMake code.

diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 2e1bb0a..9fd2299 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -2147,6 +2147,32 @@ bool cmCTestTestHandler::SetTestsProperties(
     for (std::string const& t : tests) {
       for (cmCTestTestProperties& rt : this->TestList) {
         if (t == rt.Name) {
+          if (key == "_BACKTRACE_TRIPLES") {
+            std::vector<std::string> triples;
+            // allow empty args in the triples
+            cmSystemTools::ExpandListArgument(val, triples, true);
+
+            // Ensure we have complete triples otherwise the data is corrupt.
+            if (triples.size() % 3 == 0) {
+              cmState state;
+              rt.Backtrace = cmListFileBacktrace(state.CreateBaseSnapshot());
+
+              // the first entry represents the top of the trace so we need to
+              // reconstruct the backtrace in reverse
+              for (size_t i = triples.size(); i >= 3; i -= 3) {
+                cmListFileContext fc;
+                fc.FilePath = triples[i - 3];
+                long line = 0;
+                if (!cmSystemTools::StringToLong(triples[i - 2].c_str(),
+                                                 &line)) {
+                  line = 0;
+                }
+                fc.Line = line;
+                fc.Name = triples[i - 1];
+                rt.Backtrace = rt.Backtrace.Push(fc);
+              }
+            }
+          }
           if (key == "WILL_FAIL") {
             rt.WillFail = cmSystemTools::IsOn(val);
           }
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index bcacf23..0b557db 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -7,6 +7,7 @@
 
 #include "cmCTestGenericHandler.h"
 #include "cmDuration.h"
+#include "cmListFileCache.h"
 
 #include "cmsys/RegularExpression.hxx"
 #include <chrono>
@@ -141,6 +142,8 @@ public:
     std::set<std::string> FixturesCleanup;
     std::set<std::string> FixturesRequired;
     std::set<std::string> RequireSuccessDepends;
+    // Private test generator properties used to track backtraces
+    cmListFileBacktrace Backtrace;
   };
 
   struct cmCTestTestResult
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 796d2df..e4ced6e 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -7,14 +7,16 @@
 
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
+#include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmOutputConverter.h"
 #include "cmProperty.h"
-#include "cmPropertyMap.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmTest.h"
 
+class cmPropertyMap;
+
 cmTestGenerator::cmTestGenerator(
   cmTest* test, std::vector<std::string> const& configurations)
   : cmScriptGenerator("CTEST_CONFIGURATION_TYPE", configurations)
@@ -121,16 +123,15 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
 
   // Output properties for the test.
   cmPropertyMap& pm = this->Test->GetProperties();
-  if (!pm.empty()) {
-    os << indent << "set_tests_properties(" << this->Test->GetName()
-       << " PROPERTIES ";
-    for (auto const& i : pm) {
-      os << " " << i.first << " "
-         << cmOutputConverter::EscapeForCMake(
-              ge.Parse(i.second.GetValue())->Evaluate(this->LG, config));
-    }
-    os << ")" << std::endl;
+  os << indent << "set_tests_properties(" << this->Test->GetName()
+     << " PROPERTIES ";
+  for (auto const& i : pm) {
+    os << " " << i.first << " "
+       << cmOutputConverter::EscapeForCMake(
+            ge.Parse(i.second.GetValue())->Evaluate(this->LG, config));
   }
+  this->GenerateInternalProperties(os);
+  os << ")" << std::endl;
 }
 
 void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os, Indent indent)
@@ -179,13 +180,37 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent)
 
   // Output properties for the test.
   cmPropertyMap& pm = this->Test->GetProperties();
-  if (!pm.empty()) {
-    fout << indent << "set_tests_properties(" << this->Test->GetName()
-         << " PROPERTIES ";
-    for (auto const& i : pm) {
-      fout << " " << i.first << " "
-           << cmOutputConverter::EscapeForCMake(i.second.GetValue());
+  fout << indent << "set_tests_properties(" << this->Test->GetName()
+       << " PROPERTIES ";
+  for (auto const& i : pm) {
+    fout << " " << i.first << " "
+         << cmOutputConverter::EscapeForCMake(i.second.GetValue());
+  }
+  this->GenerateInternalProperties(fout);
+  fout << ")" << std::endl;
+}
+
+void cmTestGenerator::GenerateInternalProperties(std::ostream& os)
+{
+  cmListFileBacktrace bt = this->Test->GetBacktrace();
+  if (bt.Empty()) {
+    return;
+  }
+
+  os << " "
+     << "_BACKTRACE_TRIPLES"
+     << " \"";
+
+  bool prependTripleSeparator = false;
+  while (!bt.Empty()) {
+    const auto& entry = bt.Top();
+    if (prependTripleSeparator) {
+      os << ";";
     }
-    fout << ")" << std::endl;
+    os << entry.FilePath << ";" << entry.Line << ";" << entry.Name;
+    bt = bt.Pop();
+    prependTripleSeparator = true;
   }
+
+  os << "\"";
 }
diff --git a/Source/cmTestGenerator.h b/Source/cmTestGenerator.h
index 73d05a3..f26d2ff 100644
--- a/Source/cmTestGenerator.h
+++ b/Source/cmTestGenerator.h
@@ -35,6 +35,9 @@ public:
 
   cmTest* GetTest() const;
 
+private:
+  void GenerateInternalProperties(std::ostream& os);
+
 protected:
   void GenerateScriptConfigs(std::ostream& os, Indent indent) override;
   void GenerateScriptActions(std::ostream& os, Indent indent) override;

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=00530d74d5d07a320c998d6caccc00cf4e59b06d
commit 00530d74d5d07a320c998d6caccc00cf4e59b06d
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Nov 2 09:36:31 2018 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Tue Jan 8 11:22:11 2019 -0500

    Tests: Pass python interpreter into RunCMake.CTestCommandLine
    
    This will be useful for adding python-based result checks.

diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 67fd65a..e222376 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -385,8 +385,9 @@ add_RunCMake_test(CPackConfig)
 add_RunCMake_test(CPackInstallProperties)
 add_RunCMake_test(ExternalProject)
 add_RunCMake_test(FetchContent)
+set(CTestCommandLine_ARGS -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
 if(NOT CMake_TEST_EXTERNAL_CMAKE)
-  set(CTestCommandLine_ARGS -DTEST_AFFINITY=$<TARGET_FILE:testAffinity>)
+  list(APPEND CTestCommandLine_ARGS -DTEST_AFFINITY=$<TARGET_FILE:testAffinity>)
 endif()
 add_executable(print_stdin print_stdin.c)
 add_RunCMake_test(CTestCommandLine -DTEST_PRINT_STDIN=$<TARGET_FILE:print_stdin>)

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9045f6a30fc8ce21d2b2298c27ba1da41c23bbf3
commit 9045f6a30fc8ce21d2b2298c27ba1da41c23bbf3
Author:     Tobias Hunger <tobias.hunger at qt.io>
AuthorDate: Wed Nov 28 15:07:31 2018 +0100
Commit:     Tobias Hunger <tobias.hunger at gmail.com>
CommitDate: Mon Jan 7 14:13:10 2019 +0100

    Autogen: Prepare for Qt 6
    
    Handle Qt version > 5 in Qt AutoGen.
    
    This patch does *NOT* include tests and documentation: There is no
    Qt 6 yet. I still need this patch to work on a cmake based build
    system for Qt 6.

diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 5470ec3..0ed8af4 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -77,7 +77,8 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
       if (moc || uic || rcc) {
         // We support Qt4 and Qt5
         auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target);
-        if ((qtVersion.Major == 4) || (qtVersion.Major == 5)) {
+        if ((qtVersion.Major == 4) || (qtVersion.Major == 5) ||
+            (qtVersion.Major == 6)) {
           // Create autogen target initializer
           Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
             this, target, qtVersion, moc, uic, rcc, globalAutoGenTarget,
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 6a2a951..ffa6a35 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -42,6 +42,9 @@
 std::string GetQtExecutableTargetName(
   const cmQtAutoGen::IntegerVersion& qtVersion, std::string const& executable)
 {
+  if (qtVersion.Major == 6) {
+    return ("Qt6::" + executable);
+  }
   if (qtVersion.Major == 5) {
     return ("Qt5::" + executable);
   }
@@ -504,7 +507,7 @@ bool cmQtAutoGenInitializer::InitMoc()
   {
     // We need to disable this until we have all implicit includes available.
     // See issue #18669.
-    // bool const appendImplicit = (this->QtVersion.Major == 5);
+    // bool const appendImplicit = (this->QtVersion.Major >= 5);
 
     auto GetIncludeDirs =
       [this, localGen](std::string const& cfg) -> std::vector<std::string> {
@@ -839,7 +842,7 @@ bool cmQtAutoGenInitializer::InitScanFiles()
 
   // Process qrc files
   if (!this->Rcc.Qrcs.empty()) {
-    const bool QtV5 = (this->QtVersion.Major == 5);
+    const bool modernQt = (this->QtVersion.Major >= 5);
     // Target rcc options
     std::vector<std::string> optionsTarget;
     cmSystemTools::ExpandListArgument(
@@ -911,10 +914,10 @@ bool cmQtAutoGenInitializer::InitScanFiles()
         std::vector<std::string> nameOpts;
         nameOpts.emplace_back("-name");
         nameOpts.emplace_back(std::move(name));
-        RccMergeOptions(opts, nameOpts, QtV5);
+        RccMergeOptions(opts, nameOpts, modernQt);
       }
       // Merge file option
-      RccMergeOptions(opts, qrc.Options, QtV5);
+      RccMergeOptions(opts, qrc.Options, modernQt);
       qrc.Options = std::move(opts);
     }
     // RCC resources
@@ -1374,7 +1377,7 @@ static std::vector<cmQtAutoGenInitializer::IntegerVersion> GetKnownQtVersions(
 
   std::vector<cmQtAutoGenInitializer::IntegerVersion> result;
   for (const std::string& prefix :
-       std::vector<std::string>({ "Qt5Core", "QT" })) {
+       std::vector<std::string>({ "Qt6Core", "Qt5Core", "QT" })) {
     auto tmp = cmQtAutoGenInitializer::IntegerVersion(
       StringToInt(makefile->GetSafeDefinition(prefix + "_VERSION_MAJOR")),
       StringToInt(makefile->GetSafeDefinition(prefix + "_VERSION_MINOR")));
@@ -1427,7 +1430,7 @@ std::pair<bool, std::string> GetQtExecutable(
       GetQtExecutableTargetName(qtVersion, executable);
     if (targetName.empty()) {
       err = "The AUTOMOC, AUTOUIC and AUTORCC feature ";
-      err += "supports only Qt 4 and Qt 5";
+      err += "supports only Qt 4, Qt 5 and Qt 6.";
     } else {
       cmLocalGenerator* localGen = target->GetLocalGenerator();
       cmGeneratorTarget* tgt = localGen->FindGeneratorTargetToUse(targetName);
@@ -1510,7 +1513,7 @@ bool cmQtAutoGenInitializer::GetRccExecutable()
     return false;
   }
 
-  if (this->QtVersion.Major == 5) {
+  if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
     if (stdOut.find("--list") != std::string::npos) {
       this->Rcc.ListOptions.push_back("--list");
     } else {

-----------------------------------------------------------------------

Summary of changes:
 Help/manual/cmake-properties.7.rst                 |   3 +
 Help/manual/ctest.1.rst                            |  71 ++++-
 Help/prop_tgt/AUTOMOC.rst                          |   3 +
 Help/prop_tgt/AUTOMOC_EXECUTABLE.rst               |  15 +
 Help/prop_tgt/AUTORCC.rst                          |   3 +
 Help/prop_tgt/AUTORCC_EXECUTABLE.rst               |  15 +
 Help/prop_tgt/AUTOUIC.rst                          |   3 +
 Help/prop_tgt/AUTOUIC_EXECUTABLE.rst               |  15 +
 Help/release/dev/autogen_executables.rst           |   9 +
 Help/release/dev/ctest-show-only-json-v1.rst       |   6 +
 Source/CTest/cmCTestMultiProcessHandler.cxx        | 331 ++++++++++++++++++++
 Source/CTest/cmCTestMultiProcessHandler.h          |   1 +
 Source/CTest/cmCTestRunTest.h                      |   4 +
 Source/CTest/cmCTestTestHandler.cxx                |  26 ++
 Source/CTest/cmCTestTestHandler.h                  |   3 +
 Source/cmCTest.cxx                                 |  26 ++
 Source/cmCTest.h                                   |   6 +
 Source/cmGlobalVisualStudio10Generator.cxx         |  31 +-
 Source/cmGlobalVisualStudio10Generator.h           |   5 +-
 Source/cmGlobalVisualStudio11Generator.cxx         |  10 -
 Source/cmGlobalVisualStudio11Generator.h           |   3 -
 Source/cmGlobalVisualStudio12Generator.cxx         |  10 -
 Source/cmGlobalVisualStudio12Generator.h           |   8 -
 Source/cmGlobalVisualStudio14Generator.cxx         |  11 -
 Source/cmGlobalVisualStudio14Generator.h           |   5 -
 Source/cmGlobalVisualStudio15Generator.cxx         |  11 -
 Source/cmGlobalVisualStudio15Generator.h           |   6 -
 Source/cmGlobalVisualStudio71Generator.cxx         |   6 -
 Source/cmGlobalVisualStudio71Generator.h           |   1 -
 Source/cmGlobalVisualStudio7Generator.h            |   1 -
 Source/cmGlobalVisualStudio8Generator.h            |   5 -
 Source/cmGlobalVisualStudio9Generator.cxx          |   6 -
 Source/cmGlobalVisualStudio9Generator.h            |   9 -
 Source/cmGlobalVisualStudioGenerator.cxx           |  71 +++++
 Source/cmGlobalVisualStudioGenerator.h             |   8 +-
 Source/cmQtAutoGenGlobalInitializer.cxx            |  21 +-
 Source/cmQtAutoGenInitializer.cxx                  |  78 +++--
 Source/cmTestGenerator.cxx                         |  59 +++-
 Source/cmTestGenerator.h                           |   3 +
 Source/cmake.cxx                                   |   1 -
 Source/cmparseMSBuildXML.py                        | 341 ---------------------
 Source/ctest.cxx                                   |   5 +-
 Tests/RunCMake/CMakeLists.txt                      |   3 +-
 Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake |  29 ++
 .../RunCMake/CTestCommandLine/ShowAsJson1-check.py | 106 +++++++
 .../RunCMake/CTestCommandLine/ShowAsJson_check.py  |  24 ++
 46 files changed, 924 insertions(+), 493 deletions(-)
 create mode 100644 Help/prop_tgt/AUTOMOC_EXECUTABLE.rst
 create mode 100644 Help/prop_tgt/AUTORCC_EXECUTABLE.rst
 create mode 100644 Help/prop_tgt/AUTOUIC_EXECUTABLE.rst
 create mode 100644 Help/release/dev/autogen_executables.rst
 create mode 100644 Help/release/dev/ctest-show-only-json-v1.rst
 delete mode 100755 Source/cmparseMSBuildXML.py
 create mode 100644 Tests/RunCMake/CTestCommandLine/ShowAsJson1-check.py
 create mode 100644 Tests/RunCMake/CTestCommandLine/ShowAsJson_check.py


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list