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)