diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 8f7c33685..2ccc6be10 100644
--- a/Help/manual/cmake.1.rst
+++ b/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
[...]``
Change the current working directory and run a command.
diff --git a/Help/release/dev/cmake-capabilities.rst b/Help/release/dev/cmake-capabilities.rst
new file mode 100644
index 000000000..7abb9736c
--- /dev/null
+++ b/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.).
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index b11f4f696..4313d83ac 100644
--- a/Source/cmake.cxx
+++ b/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
+
+#include "cm_jsoncpp_value.h"
+#include "cm_jsoncpp_writer.h"
#endif
#include
@@ -110,6 +114,18 @@
#include
+namespace {
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#ifdef CMake_HAVE_CXX_UNORDERED_MAP
+typedef std::unordered_map JsonValueMapType;
+#else
+typedef cmsys::hash_map 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 generatorInfoList;
+ this->GetRegisteredGenerators(generatorInfoList);
+
+ JsonValueMapType generatorMap;
+ for (std::vector::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();
@@ -811,7 +889,8 @@ void cmake::AddDefaultExtraGenerators()
#endif
}
-void cmake::GetRegisteredGenerators(std::vector& generators)
+void cmake::GetRegisteredGenerators(
+ std::vector& generators) const
{
for (RegisteredGeneratorsVector::const_iterator i = this->Generators.begin(),
e = this->Generators.end();
diff --git a/Source/cmake.h b/Source/cmake.h
index 304a15d67..343d37120 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -117,6 +117,8 @@ public:
/// Destructor
~cmake();
+ std::string ReportCapabilities() const;
+
static const char* GetCMakeFilesDirectory() { return "/CMakeFiles"; }
static const char* GetCMakeFilesDirectoryPostSlash()
{
@@ -187,7 +189,7 @@ public:
void SetGlobalGenerator(cmGlobalGenerator*);
///! Get the names of the current registered generators
- void GetRegisteredGenerators(std::vector& generators);
+ void GetRegisteredGenerators(std::vector& generators) const;
///! Set the name of the selected generator-specific platform.
void SetGeneratorPlatform(std::string const& ts)
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 9d0337a66..be023b135 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -60,6 +60,8 @@ void CMakeCommandUsage(const char* program)
errorStream
<< "Usage: " << program << " -E [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 ... destination - copy files to destination "
@@ -510,6 +512,16 @@ int cmcmd::ExecuteCMakeCommand(std::vector& 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) {
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-arg-result.txt b/Tests/RunCMake/CommandLine/E_capabilities-arg-result.txt
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_capabilities-arg-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt b/Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt
new file mode 100644
index 000000000..f74cebe69
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_capabilities-arg-stderr.txt
@@ -0,0 +1 @@
+^-E capabilities accepts no additional arguments$
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
new file mode 100644
index 000000000..6c5ea44b3
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
@@ -0,0 +1 @@
+^{.*}$
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 077a19d41..6ae47a8f1 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/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)