Browse Source

cmake: Add `cmake -E capabilities` mode

Add `cmake -E capabilities` to report on generators, cmake version and
possibly other static capabilities of cmake.

Closes: #15462
Tobias Hunger 9 years ago
parent
commit
49ad7f9af8

+ 37 - 0
Help/manual/cmake.1.rst

@@ -180,6 +180,43 @@ CMake provides builtin command-line tools through the signature::
 Run ``cmake -E`` or ``cmake -E help`` for a summary of commands.
 Available commands are:
 
+``capabilities``
+  Report cmake capabilities in JSON format. The output is a JSON object
+  with the following keys:
+
+  ``version``
+    A JSON object with version information. Keys are:
+
+    ``string``
+      The full version string as displayed by cmake ``--version``.
+    ``major``
+      The major version number in integer form.
+    ``minor``
+      The minor version number in integer form.
+    ``patch``
+      The patch level in integer form.
+    ``suffix``
+      The cmake version suffix string.
+    ``isDirty``
+      A bool that is set if the cmake build is from a dirty tree.
+
+  ``generators``
+    A list available generators. Each generator is a JSON object with the
+    following keys:
+
+    ``name``
+      A string containing the name of the generator.
+    ``toolsetSupport``
+      ``true`` if the generator supports toolsets and ``false`` otherwise.
+    ``platformSupport``
+      ``true`` if the generator supports platforms and ``false`` otherwise.
+    ``extraGenerators``
+      A list of strings with all the extra generators compatible with
+      the generator.
+
+  ``serverMode``
+    ``true`` if cmake supports server-mode and ``false`` otherwise.
+
 ``chdir <dir> <cmd> [<arg>...]``
   Change the current working directory and run a command.
 

+ 6 - 0
Help/release/dev/cmake-capabilities.rst

@@ -0,0 +1,6 @@
+cmake-capabilities
+------------------
+
+* :manual:`cmake(1)` gained a ``-E capabilities`` option to provide a
+  machine-readable (JSON) description of the capabilities of the
+  cmake tool (available generators, etc.).

+ 78 - 0
Source/cmake.cxx

@@ -23,11 +23,15 @@
 #include "cmState.h"
 #include "cmTest.h"
 #include "cmUtils.hxx"
+#include "cmVersionMacros.h"
 
 #if defined(CMAKE_BUILD_WITH_CMAKE)
 #include "cmGraphVizWriter.h"
 #include "cmVariableWatch.h"
 #include <cmsys/SystemInformation.hxx>
+
+#include "cm_jsoncpp_value.h"
+#include "cm_jsoncpp_writer.h"
 #endif
 
 #include <cmsys/FStream.hxx>
@@ -110,6 +114,18 @@
 
 #include <list>
 
+namespace {
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+typedef std::unordered_map<std::string, Json::Value> JsonValueMapType;
+#else
+typedef cmsys::hash_map<std::string, Json::Value> JsonValueMapType;
+#endif
+#endif
+
+} // namespace
+
 static bool cmakeCheckStampFile(const char* stampName);
 static bool cmakeCheckStampList(const char* stampName);
 
@@ -201,6 +217,68 @@ cmake::~cmake()
   delete this->FileComparison;
 }
 
+std::string cmake::ReportCapabilities() const
+{
+  std::string result;
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+  Json::Value obj = Json::objectValue;
+  // Version information:
+  Json::Value version = Json::objectValue;
+  version["string"] = CMake_VERSION;
+  version["major"] = CMake_VERSION_MAJOR;
+  version["minor"] = CMake_VERSION_MINOR;
+  version["suffix"] = CMake_VERSION_SUFFIX;
+  version["isDirty"] = (CMake_VERSION_IS_DIRTY == 1);
+  version["patch"] = CMake_VERSION_PATCH;
+
+  obj["version"] = version;
+
+  // Generators:
+  std::vector<cmake::GeneratorInfo> generatorInfoList;
+  this->GetRegisteredGenerators(generatorInfoList);
+
+  JsonValueMapType generatorMap;
+  for (std::vector<cmake::GeneratorInfo>::const_iterator i =
+         generatorInfoList.begin();
+       i != generatorInfoList.end(); ++i) {
+    if (i->isAlias) { // skip aliases, they are there for compatibility reasons
+                      // only
+      continue;
+    }
+
+    if (i->extraName.empty()) {
+      Json::Value gen = Json::objectValue;
+      gen["name"] = i->name;
+      gen["toolsetSupport"] = i->supportsToolset;
+      gen["platformSupport"] = i->supportsPlatform;
+      gen["extraGenerators"] = Json::arrayValue;
+      generatorMap[i->name] = gen;
+    } else {
+      Json::Value& gen = generatorMap[i->baseName];
+      gen["extraGenerators"].append(i->extraName);
+    }
+  }
+
+  Json::Value generators = Json::arrayValue;
+  for (JsonValueMapType::const_iterator i = generatorMap.begin();
+       i != generatorMap.end(); ++i) {
+    generators.append(i->second);
+  }
+  obj["generators"] = generators;
+
+#if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE
+  obj["serverMode"] = true;
+#else
+  obj["serverMode"] = false;
+#endif
+  Json::FastWriter writer;
+  result = writer.write(obj);
+#else
+  result = "Not supported";
+#endif
+  return result;
+}
+
 void cmake::CleanupCommandsAndMacros()
 {
   this->CurrentSnapshot = this->State->Reset();

+ 2 - 0
Source/cmake.h

@@ -117,6 +117,8 @@ public:
   /// Destructor
   ~cmake();
 
+  std::string ReportCapabilities() const;
+
   static const char* GetCMakeFilesDirectory() { return "/CMakeFiles"; }
   static const char* GetCMakeFilesDirectoryPostSlash()
   {

+ 12 - 0
Source/cmcmd.cxx

@@ -60,6 +60,8 @@ void CMakeCommandUsage(const char* program)
   errorStream
     << "Usage: " << program << " -E <command> [arguments...]\n"
     << "Available commands: \n"
+    << "  capabilities              - Report capabilities built into cmake "
+       "in JSON format\n"
     << "  chdir dir cmd [args...]   - run command in a given directory\n"
     << "  compare_files file1 file2 - check if file1 is same as file2\n"
     << "  copy <file>... destination  - copy files to destination "
@@ -510,6 +512,16 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
       }
       return 0;
     }
+    // capabilities
+    else if (args[1] == "capabilities") {
+      if (args.size() > 2) {
+        std::cerr << "-E capabilities accepts no additional arguments\n";
+        return 1;
+      }
+      cmake cm;
+      std::cout << cm.ReportCapabilities();
+      return 0;
+    }
 
     // Sleep command
     else if (args[1] == "sleep" && args.size() > 2) {

+ 1 - 0
Tests/RunCMake/CommandLine/E_capabilities-arg-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt

@@ -0,0 +1 @@
+^-E capabilities accepts no additional arguments$

+ 1 - 0
Tests/RunCMake/CommandLine/E_capabilities-stdout.txt

@@ -0,0 +1 @@
+^{.*}$

+ 2 - 0
Tests/RunCMake/CommandLine/RunCMakeTest.cmake

@@ -8,6 +8,8 @@ run_cmake_command(lists-no-file ${CMAKE_COMMAND} nosuchsubdir/CMakeLists.txt)
 run_cmake_command(D-no-arg ${CMAKE_COMMAND} -D)
 run_cmake_command(U-no-arg ${CMAKE_COMMAND} -U)
 run_cmake_command(E-no-arg ${CMAKE_COMMAND} -E)
+run_cmake_command(E_capabilities ${CMAKE_COMMAND} -E capabilities)
+run_cmake_command(E_capabilities-arg ${CMAKE_COMMAND} -E capabilities --extra-arg)
 run_cmake_command(E_echo_append ${CMAKE_COMMAND} -E echo_append)
 run_cmake_command(E_rename-no-arg ${CMAKE_COMMAND} -E rename)
 run_cmake_command(E_touch_nocreate-no-arg ${CMAKE_COMMAND} -E touch_nocreate)