[Cmake-commits] CMake branch, next, updated. v3.6.2-2595-g51b8062

Brad King brad.king at kitware.com
Wed Sep 28 15:11:52 EDT 2016


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, next has been updated
       via  51b80629c0e9fbd7cda9a1ee940a628063dac0e5 (commit)
       via  71a505870c1f5a4fc89a8ad4e4dc3bb008a35118 (commit)
       via  7b1e60f26e284e223be8638744ba3a3b0efdee63 (commit)
       via  84553a6e709ea810f3e7fc5ece5daa1c53be5cda (commit)
       via  ead71873b2025a28df1208bbd3f2f8e1918a120c (commit)
      from  fc5eef544936995b4768f400d6473ce9e082bc78 (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=51b80629c0e9fbd7cda9a1ee940a628063dac0e5
commit 51b80629c0e9fbd7cda9a1ee940a628063dac0e5
Merge: fc5eef5 71a5058
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Sep 28 15:11:50 2016 -0400
Commit:     CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Wed Sep 28 15:11:50 2016 -0400

    Merge topic 'cmake-server-commands' into next
    
    71a50587 server-mode: Add project data for unit tests
    7b1e60f2 server-mode: Report CMakeCache entries
    84553a6e server-mode: Add command to retrieve build system files
    ead71873 server-mode: Report information relevant for a codemodel


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=71a505870c1f5a4fc89a8ad4e4dc3bb008a35118
commit 71a505870c1f5a4fc89a8ad4e4dc3bb008a35118
Author:     Tobias Hunger <tobias.hunger at qt.io>
AuthorDate: Tue Sep 27 21:29:20 2016 +0200
Commit:     Tobias Hunger <tobias.hunger at qt.io>
CommitDate: Wed Sep 28 20:10:59 2016 +0200

    server-mode: Add project data for unit tests
    
    Do some basic unit tests for "codemodel", "cmakeInputs" and "cache"
    commands of the cmake server.
    
    This just calls the commands right now and makes sure the server
    thinks it can reply to the request. The data itself is currently not
    validated.

diff --git a/Tests/Server/CMakeLists.txt b/Tests/Server/CMakeLists.txt
index 03f5042..8913406 100644
--- a/Tests/Server/CMakeLists.txt
+++ b/Tests/Server/CMakeLists.txt
@@ -10,6 +10,7 @@ macro(do_test bsname file)
     "${CMAKE_SOURCE_DIR}/${file}"
     "${CMAKE_SOURCE_DIR}"
     "${CMAKE_BINARY_DIR}"
+    "${CMAKE_GENERATOR}"
     RESULT_VARIABLE test_result
     )
 
@@ -20,5 +21,6 @@ endmacro()
 
 do_test("test_handshake" "tc_handshake.json")
 do_test("test_globalSettings" "tc_globalSettings.json")
+do_test("test_buildsystem1" "tc_buildsystem1.json")
 
 add_executable(Server empty.cpp)
diff --git a/Tests/Server/buildsystem1/CMakeLists.txt b/Tests/Server/buildsystem1/CMakeLists.txt
new file mode 100644
index 0000000..d690472
--- /dev/null
+++ b/Tests/Server/buildsystem1/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.4)
+
+project(buildsystem2)
+
+set(var1 123)
+
+set(var2 345)
+
+add_executable(main main.cpp)
+
+add_executable(m_other main.cpp)
+
+add_library(foo foo.cpp)
+
+function(f1)
+endfunction()
+
+set(var3 345)
+
+add_library(someImportedLib UNKNOWN IMPORTED)
+
+add_subdirectory(subdir)
diff --git a/Tests/Server/buildsystem1/foo.cpp b/Tests/Server/buildsystem1/foo.cpp
new file mode 100644
index 0000000..7f39d71
--- /dev/null
+++ b/Tests/Server/buildsystem1/foo.cpp
@@ -0,0 +1,5 @@
+
+int foo()
+{
+  return 0;
+}
diff --git a/Tests/Server/buildsystem1/main.cpp b/Tests/Server/buildsystem1/main.cpp
new file mode 100644
index 0000000..766b775
--- /dev/null
+++ b/Tests/Server/buildsystem1/main.cpp
@@ -0,0 +1,5 @@
+
+int main()
+{
+  return 0;
+}
diff --git a/Tests/Server/buildsystem1/subdir/CMakeLists.txt b/Tests/Server/buildsystem1/subdir/CMakeLists.txt
new file mode 100644
index 0000000..9157312
--- /dev/null
+++ b/Tests/Server/buildsystem1/subdir/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(bar4 something)
+
+set(bar5 more)
+
+add_executable(ooo empty.cpp)
diff --git a/Tests/Server/buildsystem1/subdir/empty.cpp b/Tests/Server/buildsystem1/subdir/empty.cpp
new file mode 100644
index 0000000..7f39d71
--- /dev/null
+++ b/Tests/Server/buildsystem1/subdir/empty.cpp
@@ -0,0 +1,5 @@
+
+int foo()
+{
+  return 0;
+}
diff --git a/Tests/Server/cmakelib.py b/Tests/Server/cmakelib.py
index 8beaeef..94384eb 100644
--- a/Tests/Server/cmakelib.py
+++ b/Tests/Server/cmakelib.py
@@ -102,10 +102,20 @@ def waitForMessage(cmakeCommand, expected):
     sys.exit(-1)
   return packet
 
-def waitForReply(cmakeCommand, originalType, cookie):
-  packet = waitForRawMessage(cmakeCommand)
-  if packet['cookie'] != cookie or packet['type'] != 'reply' or packet['inReplyTo'] != originalType:
+def waitForReply(cmakeCommand, originalType, cookie, skipProgress):
+  gotResult = False
+  while True:
+    packet = waitForRawMessage(cmakeCommand)
+    t = packet['type']
+    if packet['cookie'] != cookie or packet['inReplyTo'] != originalType:
+      sys.exit(1)
+    if t == 'message' or t == 'progress':
+      if skipProgress:
+        continue
+    if t == 'reply':
+        break
     sys.exit(1)
+
   return packet
 
 def waitForError(cmakeCommand, originalType, cookie, message):
@@ -126,10 +136,10 @@ def handshake(cmakeCommand, major, minor, source, build, generator, extraGenerat
   writePayload(cmakeCommand, { 'type': 'handshake', 'protocolVersion': version,
     'cookie': 'TEST_HANDSHAKE', 'sourceDirectory': source, 'buildDirectory': build,
     'generator': generator, 'extraGenerator': extraGenerator })
-  waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE')
+  waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE', False)
 
 def validateGlobalSettings(cmakeCommand, cmakeCommandPath, data):
-  packet = waitForReply(cmakeCommand, 'globalSettings', '')
+  packet = waitForReply(cmakeCommand, 'globalSettings', '', False)
 
   capabilities = packet['capabilities']
 
diff --git a/Tests/Server/server-test.py b/Tests/Server/server-test.py
index d2bf92e..72f82ba 100644
--- a/Tests/Server/server-test.py
+++ b/Tests/Server/server-test.py
@@ -1,24 +1,25 @@
-import sys, cmakelib, json
+import sys, cmakelib, json, os, shutil
 
 debug = True
 
 cmakeCommand = sys.argv[1]
 testFile = sys.argv[2]
 sourceDir = sys.argv[3]
-buildDir = sys.argv[4]
+buildDir = sys.argv[4] + "/" + os.path.splitext(os.path.basename(testFile))[0]
+cmakeGenerator = sys.argv[5]
 
-print("SourceDir: ", sourceDir, " -- BuildDir: ", buildDir)
+print("Test:", testFile,
+      "\n-- SourceDir:", sourceDir,
+      "\n-- BuildDir:", buildDir,
+      "\n-- Generator:", cmakeGenerator)
+
+if os.path.exists(buildDir):
+    shutil.rmtree(buildDir)
 
 proc = cmakelib.initProc(cmakeCommand)
 
 with open(testFile) as f:
-    testText = f.read()
-    testText = testText.replace('%BUILDDIR%', buildDir)
-    testText = testText.replace('%SOURCEDIR%', sourceDir)
-    testData = json.loads(testText)
-
-buildDir = sys.argv[3]
-sourceDir = sys.argv[4]
+    testData = json.loads(f.read())
 
 for obj in testData:
     if 'sendRaw' in obj:
@@ -38,9 +39,11 @@ for obj in testData:
         if debug: print("Waiting for reply:", json.dumps(data))
         originalType = ""
         cookie = ""
+        skipProgress = False;
         if 'cookie' in data: cookie = data['cookie']
         if 'type' in data: originalType = data['type']
-        cmakelib.waitForReply(proc, originalType, cookie)
+        if 'skipProgress' in data: skipProgress = data['skipProgress']
+        cmakelib.waitForReply(proc, originalType, cookie, skipProgress)
     elif 'error' in obj:
         data = obj['error']
         if debug: print("Waiting for error:", json.dumps(data))
@@ -68,8 +71,8 @@ for obj in testData:
         if debug: print("Doing handshake:", json.dumps(data))
         major = -1
         minor = -1
-        generator = 'Ninja'
-        extraGenerator = 'CodeBlocks'
+        generator = cmakeGenerator
+        extraGenerator = ''
         sourceDirectory = sourceDir
         buildDirectory = buildDir
         if 'major' in data: major = data['major']
@@ -78,14 +81,18 @@ for obj in testData:
         if 'sourceDirectory' in data: sourceDirectory = data['sourceDirectory']
         if 'generator' in data: generator = data['generator']
         if 'extraGenerator' in data: extraGenerator = data['extraGenerator']
+        if not os.path.isabs(buildDirectory):
+            buildDirectory = buildDir + "/" + buildDirectory
+        if not os.path.isabs(sourceDirectory):
+            sourceDirectory = sourceDir + "/" + sourceDirectory
         cmakelib.handshake(proc, major, minor, sourceDirectory, buildDirectory,
           generator, extraGenerator)
     elif 'validateGlobalSettings' in obj:
         data = obj['validateGlobalSettings']
         if not 'buildDirectory' in data: data['buildDirectory'] = buildDir
         if not 'sourceDirectory' in data: data['sourceDirectory'] = sourceDir
-        if not 'generator' in data: data['generator'] = 'Ninja'
-        if not 'extraGenerator' in data: data['extraGenerator'] = 'CodeBlocks'
+        if not 'generator' in data: data['generator'] = cmakeGenerator
+        if not 'extraGenerator' in data: data['extraGenerator'] = ''
         cmakelib.validateGlobalSettings(proc, cmakeCommand, data)
     elif 'message' in obj:
         print("MESSAGE:", obj["message"])
diff --git a/Tests/Server/tc_buildsystem1.json b/Tests/Server/tc_buildsystem1.json
new file mode 100644
index 0000000..08831b7
--- /dev/null
+++ b/Tests/Server/tc_buildsystem1.json
@@ -0,0 +1,27 @@
+[
+{ "message": "Testing globalSettings" },
+
+{ "handshake": {"major": 1, "sourceDirectory":"buildsystem1","buildDirectory":"buildsystem1"} },
+
+{ "message": "Configure:" },
+{ "send": { "type": "configure", "cookie":"CONFIG" } },
+{ "reply": { "type": "configure", "cookie":"CONFIG", "skipProgress":true } },
+
+{ "message": "Compute:" },
+{ "send": { "type": "compute", "cookie":"COMPUTE" } },
+{ "reply": { "type": "compute", "cookie":"COMPUTE", "skipProgress":true } },
+
+{ "message": "Codemodel:" },
+{ "send": { "type": "codemodel", "cookie":"CODEMODEL" } },
+{ "reply": { "type": "codemodel", "cookie":"CODEMODEL" } },
+
+{ "message": "CMake Inputs:"},
+{ "send": { "type": "cmakeInputs", "cookie":"INPUTS" } },
+{ "reply": { "type": "cmakeInputs", "cookie":"INPUTS" } },
+
+{ "message": "Cache:"},
+{ "send": { "type": "cache", "cookie":"CACHE" } },
+{ "reply": { "type": "cache", "cookie":"CACHE" } },
+
+{ "message": "Everything ok." }
+]

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7b1e60f26e284e223be8638744ba3a3b0efdee63
commit 7b1e60f26e284e223be8638744ba3a3b0efdee63
Author:     Tobias Hunger <tobias.hunger at qt.io>
AuthorDate: Fri Sep 9 10:01:46 2016 +0200
Commit:     Tobias Hunger <tobias.hunger at qt.io>
CommitDate: Wed Sep 28 18:32:55 2016 +0200

    server-mode: Report CMakeCache entries
    
    With this it would be possible to implement something like
    cmake-gui using server-mode.

diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst
index 76ee3fb..f662125 100644
--- a/Help/manual/cmake-server.7.rst
+++ b/Help/manual/cmake-server.7.rst
@@ -599,3 +599,39 @@ The list of files which "isCMake" set to true are part of the cmake installation
 
 The list of files witch "isTemporary" set to true are part of the build directory
 and will not survive the build directory getting cleaned out.
+
+
+Type "cache"
+^^^^^^^^^^^^
+
+The "cache" request can be used once a project is configured and will
+list the cached configuration values.
+
+Example::
+
+  [== CMake Server ==[
+  {"type":"cache"}
+  ]== CMake Server ==]
+
+CMake will respond with the following output::
+
+  [== CMake Server ==[
+  {
+    "cookie":"","inReplyTo":"cache","type":"reply",
+    "cache":
+    [
+      {
+        "key":"SOMEVALUE",
+        "properties":
+        {
+          "ADVANCED":"1",
+          "HELPSTRING":"This is not helpful"
+        }
+        "type":"STRING",
+        "value":"TEST"}
+    ]
+  }
+  ]== CMake Server ==]
+
+The output can be limited to a list of keys by passing an array of key names
+to the "keys" optional field of the "cache" request.
diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h
index bccce55..c811b83 100644
--- a/Source/cmServerDictionary.h
+++ b/Source/cmServerDictionary.h
@@ -6,6 +6,7 @@
 
 // Vocabulary:
 
+static const std::string kCACHE_TYPE = "cache";
 static const std::string kCMAKE_INPUTS_TYPE = "cmakeInputs";
 static const std::string kCODE_MODEL_TYPE = "codemodel";
 static const std::string kCOMPUTE_TYPE = "compute";
@@ -23,6 +24,7 @@ static const std::string kARTIFACTS_KEY = "artifacts";
 static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
 static const std::string kBUILD_FILES_KEY = "buildFiles";
 static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments";
+static const std::string kCACHE_KEY = "cache";
 static const std::string kCAPABILITIES_KEY = "capabilities";
 static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars";
 static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory";
@@ -43,6 +45,8 @@ static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental";
 static const std::string kIS_GENERATED_KEY = "isGenerated";
 static const std::string kIS_SYSTEM_KEY = "isSystem";
 static const std::string kIS_TEMPORARY_KEY = "isTemporary";
+static const std::string kKEY_KEY = "key";
+static const std::string kKEYS_KEY = "keys";
 static const std::string kLANGUAGE_KEY = "language";
 static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage";
 static const std::string kLINK_FLAGS_KEY = "linkFlags";
@@ -59,6 +63,7 @@ static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum";
 static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage";
 static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum";
 static const std::string kPROJECTS_KEY = "projects";
+static const std::string kPROPERTIES_KEY = "properties";
 static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion";
 static const std::string kREPLY_TO_KEY = "inReplyTo";
 static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
@@ -71,6 +76,7 @@ static const std::string kTITLE_KEY = "title";
 static const std::string kTRACE_EXPAND_KEY = "traceExpand";
 static const std::string kTRACE_KEY = "trace";
 static const std::string kTYPE_KEY = "type";
+static const std::string kVALUE_KEY = "value";
 static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized";
 static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli";
 static const std::string kWARN_UNUSED_KEY = "warnUnused";
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 00a8135..f083e49 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmServerProtocol.h"
 
+#include "cmCacheManager.h"
 #include "cmExternalMakefileProjectGenerator.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -62,6 +63,15 @@ static Json::Value fromStringList(const T& in)
   return result;
 }
 
+static std::vector<std::string> toStringList(const Json::Value& in)
+{
+  std::vector<std::string> result;
+  for (const auto& it : in) {
+    result.push_back(it.asString());
+  }
+  return result;
+}
+
 static void getCMakeInputs(const cmGlobalGenerator* gg,
                            const std::string& sourceDir,
                            const std::string& buildDir,
@@ -360,6 +370,9 @@ const cmServerResponse cmServerProtocol1_0::Process(
 {
   assert(this->m_State >= STATE_ACTIVE);
 
+  if (request.Type == kCACHE_TYPE) {
+    return this->ProcessCache(request);
+  }
   if (request.Type == kCMAKE_INPUTS_TYPE) {
     return this->ProcessCMakeInputs(request);
   }
@@ -387,6 +400,57 @@ bool cmServerProtocol1_0::IsExperimental() const
   return true;
 }
 
+cmServerResponse cmServerProtocol1_0::ProcessCache(
+  const cmServerRequest& request)
+{
+  if (this->m_State < STATE_CONFIGURED) {
+    return request.ReportError("This project was not configured yet.");
+  }
+
+  cmState* state = this->CMakeInstance()->GetState();
+
+  Json::Value result = Json::objectValue;
+
+  std::vector<std::string> allKeys = state->GetCacheEntryKeys();
+
+  Json::Value list = Json::arrayValue;
+  std::vector<std::string> keys = toStringList(request.Data[kKEYS_KEY]);
+  if (keys.empty()) {
+    keys = allKeys;
+  } else {
+    for (auto i : keys) {
+      if (std::find_if(allKeys.begin(), allKeys.end(),
+                       [i](const std::string& j) { return i == j; }) ==
+          allKeys.end()) {
+        return request.ReportError("Key \"" + i + "\" not found in cache.");
+      }
+    }
+  }
+  std::sort(keys.begin(), keys.end());
+  for (auto key : keys) {
+    Json::Value entry = Json::objectValue;
+    entry[kKEY_KEY] = key;
+    entry[kTYPE_KEY] =
+      cmState::CacheEntryTypeToString(state->GetCacheEntryType(key));
+    entry[kVALUE_KEY] = state->GetCacheEntryValue(key);
+
+    Json::Value props = Json::objectValue;
+    bool haveProperties = false;
+    for (auto prop : state->GetCacheEntryPropertyList(key)) {
+      haveProperties = true;
+      props[prop] = state->GetCacheEntryProperty(key, prop);
+    }
+    if (haveProperties) {
+      entry[kPROPERTIES_KEY] = props;
+    }
+
+    list.append(entry);
+  }
+
+  result[kCACHE_KEY] = list;
+  return request.Reply(result);
+}
+
 cmServerResponse cmServerProtocol1_0::ProcessCMakeInputs(
   const cmServerRequest& request)
 {
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
index 2a6b193..d672a60 100644
--- a/Source/cmServerProtocol.h
+++ b/Source/cmServerProtocol.h
@@ -108,6 +108,7 @@ private:
                   std::string* errorMessage) override;
 
   // Handle requests:
+  cmServerResponse ProcessCache(const cmServerRequest& request);
   cmServerResponse ProcessCMakeInputs(const cmServerRequest& request);
   cmServerResponse ProcessCodeModel(const cmServerRequest& request);
   cmServerResponse ProcessCompute(const cmServerRequest& request);

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=84553a6e709ea810f3e7fc5ece5daa1c53be5cda
commit 84553a6e709ea810f3e7fc5ece5daa1c53be5cda
Author:     Tobias Hunger <tobias.hunger at qt.io>
AuthorDate: Fri Sep 9 10:01:46 2016 +0200
Commit:     Tobias Hunger <tobias.hunger at qt.io>
CommitDate: Wed Sep 28 18:32:54 2016 +0200

    server-mode: Add command to retrieve build system files
    
    Add a command to retrieve files that are input to cmake itself.

diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst
index 79b67b0..76ee3fb 100644
--- a/Help/manual/cmake-server.7.rst
+++ b/Help/manual/cmake-server.7.rst
@@ -558,3 +558,44 @@ listed by default.
 Finally you can limit the target types that are going to be listed. This is
 done by providing a list of target types as an array of strings to the
 "targetTypes" key.
+
+
+Type "cmakeInputs"
+^^^^^^^^^^^^^^^^^^
+
+The "cmakeInputs" requests will report files used by CMake as part
+of the build system itself.
+
+This request is only available after a project was successfully
+"configure"d.
+
+Example::
+
+  [== CMake Server ==[
+  {"type":"cmakeInputs"}
+  ]== CMake Server ==]
+
+CMake will reply with the following information::
+
+  [== CMake Server ==[
+  {"buildFiles":
+    [
+      {"isCMake":true,"isTemporary":false,"sources":["/usr/lib/cmake/...", ... ]},
+      {"isCMake":false,"isTemporary":false,"sources":["CMakeLists.txt", ...]},
+      {"isCMake":false,"isTemporary":true,"sources":["/tmp/build/CMakeFiles/...", ...]}
+    ],
+    "cmakeRootDirectory":"/usr/lib/cmake",
+    "sourceDirectory":"/home/code/src/cmake",
+    "cookie":"",
+    "inReplyTo":"cmakeInputs",
+    "type":"reply"
+  }
+  ]== CMake Server ==]
+
+All file names are either relative to the top level source directory or
+absolute.
+
+The list of files which "isCMake" set to true are part of the cmake installation.
+
+The list of files witch "isTemporary" set to true are part of the build directory
+and will not survive the build directory getting cleaned out.
diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h
index 9e83864..bccce55 100644
--- a/Source/cmServerDictionary.h
+++ b/Source/cmServerDictionary.h
@@ -6,6 +6,7 @@
 
 // Vocabulary:
 
+static const std::string kCMAKE_INPUTS_TYPE = "cmakeInputs";
 static const std::string kCODE_MODEL_TYPE = "codemodel";
 static const std::string kCOMPUTE_TYPE = "compute";
 static const std::string kCONFIGURE_TYPE = "configure";
@@ -20,9 +21,11 @@ static const std::string kSIGNAL_TYPE = "signal";
 
 static const std::string kARTIFACTS_KEY = "artifacts";
 static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
+static const std::string kBUILD_FILES_KEY = "buildFiles";
 static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments";
 static const std::string kCAPABILITIES_KEY = "capabilities";
 static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars";
+static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory";
 static const std::string kCOMPILE_FLAGS_KEY = "compileFlags";
 static const std::string kCONFIGURATIONS_KEY = "configurations";
 static const std::string kCOOKIE_KEY = "cookie";
@@ -35,9 +38,11 @@ static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath";
 static const std::string kFULL_NAME_KEY = "fullName";
 static const std::string kGENERATOR_KEY = "generator";
 static const std::string kINCLUDE_PATH_KEY = "includePath";
+static const std::string kIS_CMAKE_KEY = "isCMake";
 static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental";
 static const std::string kIS_GENERATED_KEY = "isGenerated";
 static const std::string kIS_SYSTEM_KEY = "isSystem";
+static const std::string kIS_TEMPORARY_KEY = "isTemporary";
 static const std::string kLANGUAGE_KEY = "language";
 static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage";
 static const std::string kLINK_FLAGS_KEY = "linkFlags";
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index c2eeee0..00a8135 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -5,6 +5,7 @@
 #include "cmExternalMakefileProjectGenerator.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmServer.h"
@@ -61,6 +62,48 @@ static Json::Value fromStringList(const T& in)
   return result;
 }
 
+static void getCMakeInputs(const cmGlobalGenerator* gg,
+                           const std::string& sourceDir,
+                           const std::string& buildDir,
+                           std::vector<std::string>* internalFiles,
+                           std::vector<std::string>* explicitFiles,
+                           std::vector<std::string>* tmpFiles)
+{
+  const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/';
+  const std::vector<cmMakefile*> makefiles = gg->GetMakefiles();
+  for (auto it = makefiles.begin(); it != makefiles.end(); ++it) {
+    const std::vector<std::string> listFiles = (*it)->GetListFiles();
+
+    for (auto jt = listFiles.begin(); jt != listFiles.end(); ++jt) {
+
+      const std::string startOfFile = jt->substr(0, cmakeRootDir.size());
+      const bool isInternal = (startOfFile == cmakeRootDir);
+      const bool isTemporary = !isInternal && (jt->find(buildDir + '/') == 0);
+
+      std::string toAdd = *jt;
+      if (!sourceDir.empty()) {
+        const std::string& relative =
+          cmSystemTools::RelativePath(sourceDir.c_str(), jt->c_str());
+        if (toAdd.size() > relative.size())
+          toAdd = relative;
+      }
+
+      if (isInternal) {
+        if (internalFiles)
+          internalFiles->push_back(toAdd);
+      } else {
+        if (isTemporary) {
+          if (tmpFiles)
+            tmpFiles->push_back(toAdd);
+        } else {
+          if (explicitFiles)
+            explicitFiles->push_back(toAdd);
+        }
+      }
+    }
+  }
+}
+
 } // namespace
 
 cmServerRequest::cmServerRequest(cmServer* server, const std::string& t,
@@ -317,6 +360,9 @@ const cmServerResponse cmServerProtocol1_0::Process(
 {
   assert(this->m_State >= STATE_ACTIVE);
 
+  if (request.Type == kCMAKE_INPUTS_TYPE) {
+    return this->ProcessCMakeInputs(request);
+  }
   if (request.Type == kCODE_MODEL_TYPE) {
     return this->ProcessCodeModel(request);
   }
@@ -341,6 +387,54 @@ bool cmServerProtocol1_0::IsExperimental() const
   return true;
 }
 
+cmServerResponse cmServerProtocol1_0::ProcessCMakeInputs(
+  const cmServerRequest& request)
+{
+  if (this->m_State < STATE_CONFIGURED) {
+    return request.ReportError("This instance was not yet configured.");
+  }
+
+  const cmake* cm = this->CMakeInstance();
+  const cmGlobalGenerator* gg = cm->GetGlobalGenerator();
+  const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot();
+  const std::string buildDir = cm->GetHomeOutputDirectory();
+  const std::string sourceDir = cm->GetHomeDirectory();
+
+  Json::Value result = Json::objectValue;
+  result[kSOURCE_DIRECTORY_KEY] = sourceDir;
+  result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir;
+
+  std::vector<std::string> internalFiles;
+  std::vector<std::string> explicitFiles;
+  std::vector<std::string> tmpFiles;
+  getCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles,
+                 &tmpFiles);
+
+  Json::Value array = Json::arrayValue;
+
+  Json::Value tmp = Json::objectValue;
+  tmp[kIS_CMAKE_KEY] = true;
+  tmp[kIS_TEMPORARY_KEY] = false;
+  tmp[kSOURCES_KEY] = fromStringList(internalFiles);
+  array.append(tmp);
+
+  tmp = Json::objectValue;
+  tmp[kIS_CMAKE_KEY] = false;
+  tmp[kIS_TEMPORARY_KEY] = false;
+  tmp[kSOURCES_KEY] = fromStringList(explicitFiles);
+  array.append(tmp);
+
+  tmp = Json::objectValue;
+  tmp[kIS_CMAKE_KEY] = false;
+  tmp[kIS_TEMPORARY_KEY] = true;
+  tmp[kSOURCES_KEY] = fromStringList(tmpFiles);
+  array.append(tmp);
+
+  result[kBUILD_FILES_KEY] = array;
+
+  return request.Reply(result);
+}
+
 class LanguageData
 {
 public:
@@ -732,6 +826,8 @@ cmServerResponse cmServerProtocol1_0::ProcessConfigure(
   std::string sourceDir = cm->GetHomeDirectory();
   const std::string buildDir = cm->GetHomeOutputDirectory();
 
+  cmGlobalGenerator* gg = cm->GetGlobalGenerator();
+
   if (buildDir.empty()) {
     return request.ReportError(
       "No build directory set via setGlobalSettings.");
@@ -752,8 +848,7 @@ cmServerResponse cmServerProtocol1_0::ProcessConfigure(
     const char* cachedGenerator =
       cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR");
     if (cachedGenerator) {
-      cmGlobalGenerator* gen = cm->GetGlobalGenerator();
-      if (gen && gen->GetName() != cachedGenerator) {
+      if (gg && gg->GetName() != cachedGenerator) {
         return request.ReportError("Configured generator does not match with "
                                    "CMAKE_GENERATOR found in cache.");
       }
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
index 193e0a3..2a6b193 100644
--- a/Source/cmServerProtocol.h
+++ b/Source/cmServerProtocol.h
@@ -108,6 +108,7 @@ private:
                   std::string* errorMessage) override;
 
   // Handle requests:
+  cmServerResponse ProcessCMakeInputs(const cmServerRequest& request);
   cmServerResponse ProcessCodeModel(const cmServerRequest& request);
   cmServerResponse ProcessCompute(const cmServerRequest& request);
   cmServerResponse ProcessConfigure(const cmServerRequest& request);

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ead71873b2025a28df1208bbd3f2f8e1918a120c
commit ead71873b2025a28df1208bbd3f2f8e1918a120c
Author:     Tobias Hunger <tobias.hunger at qt.io>
AuthorDate: Fri Sep 9 10:01:46 2016 +0200
Commit:     Tobias Hunger <tobias.hunger at qt.io>
CommitDate: Wed Sep 28 18:32:54 2016 +0200

    server-mode: Report information relevant for a codemodel
    
    Add "codemodel" command to report information relevant to feed a code
    model.

diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst
index b8a425c..79b67b0 100644
--- a/Help/manual/cmake-server.7.rst
+++ b/Help/manual/cmake-server.7.rst
@@ -374,3 +374,187 @@ CMake will reply (after reporting progress information)::
   [== CMake Server ==[
   {"cookie":"","inReplyTo":"compute","type":"reply"}
   ]== CMake Server ==]
+
+
+Type "codemodel"
+^^^^^^^^^^^^^^^^
+
+The "codemodel" request can be used after a project was "compute"d successfully.
+
+It will list the complete project structure as it is known to cmake.
+
+The reply will contain a key "projects", which will contain a list of
+project objects, one for each (sub-)project defined in the cmake build system.
+
+Each project object can have the following keys:
+
+"name"
+  contains the (sub-)projects name.
+"sourceDirectory"
+  contains the current source directory
+"buildDirectory"
+  contains the current build directory.
+"configurations"
+  contains a list of configuration objects.
+
+Configuration objects are used to destinquish between different
+configurations the build directory might have enabled. While most generators
+only support one configuration, others support several.
+
+Each configuration object can have the following keys:
+
+"name"
+  contains the name of the configuration. The name may be empty.
+"targets"
+  contains a list of target objects, one for each build target.
+
+Target objects define individual build targets for a certain configuration.
+
+Each target object can have the following keys:
+
+"name"
+  contains the name of the target.
+"type"
+  defines the type of build of the target. Possible values are
+  "STATIC_LIBRARY", "MODULE_LIBRARY", "SHARED_LIBRARY", "OBJECT_LIBRARY",
+  "EXECUTABLE", "UTILITY" and "INTERFACE_LIBRARY".
+"fullName"
+  contains the full name of the build result (incl. extensions, etc.).
+"sourceDirectory"
+  contains the current source directory.
+"buildDirectory"
+  contains the current build directory.
+"artifacts"
+  with a list of build artifacts. The list is sorted with the most
+  important artifacts first (e.g. a .DLL file is listed before a
+  .PDB file on windows).
+"linkerLanguage"
+  contains the language of the linker used to produce the artifact.
+"linkLibraries"
+  with a list of libraries to link to. This value is encoded in the
+  system's native shell format.
+"linkFlags"
+  with a list of flags to pass to the linker. This value is encoded in
+  the system's native shell format.
+"linkLanguageFlags"
+  with the flags for a compiler using the linkerLanguage. This value is
+  encoded in the system's native shell format.
+"frameworkPath"
+  with the framework path (on Apple computers). This value is encoded
+  in the system's native shell format.
+"linkPath"
+  with the link path. This value is encoded in the system's native shell
+  format.
+"sysroot"
+  with the sysroot path.
+"fileGroups"
+  contains the source files making up the target.
+
+FileGroups are used to group sources using similar settings together.
+
+Each fileGroup object may contain the following keys:
+
+"language"
+  contains the programming language used by all files in the group.
+"compileFlags"
+  with a string containing all the flags passed to the compiler
+  when building any of the files in this group. This value is encoded in
+  the system's native shell format.
+"includePath"
+  with a list of include paths. Each include path is an object
+  containing a "path" with the actual include path and "isSystem" with a bool
+  value informing whether this is a normal include or a system include. This
+  value is encoded in the system's native shell format.
+"defines"
+  with a list of defines in the form "SOMEVALUE" or "SOMEVALUE=42". This
+  value is encoded in the system's native shell format.
+"sources"
+  with a list of source files.
+
+All file paths in the fileGroup are either absolute or relative to the
+sourceDirectory of the target.
+
+Example::
+
+  [== CMake Server ==[
+  {"type":"project"}
+  ]== CMake Server ==]
+
+CMake will reply::
+
+  [== CMake Server ==[
+  {
+    "cookie":"",
+    "type":"reply",
+    "inReplyTo":"project",
+
+    "projects":
+    [
+      {
+        "name":"CMAKE_FORM",
+        "sourceDirectory":"/home/code/src/cmake/Source/CursesDialog/form"
+        "buildDirectory":"/tmp/cmake-build-test/Source/CursesDialog/form",
+        "configurations":
+        [
+          {
+            "name":"",
+            "targets":
+            [
+              {
+                "artifactDirectory":"/tmp/cmake/Source/CursesDialog/form",
+                "fileGroups":
+                [
+                  {
+                    "compileFlags":"  -std=gnu11",
+                    "defines":
+                    [
+                      "SOMETHING=1",
+                      "LIBARCHIVE_STATIC"
+                    ],
+                    "includePath":
+                    [
+                      { "path":"/tmp/cmake-build-test/Utilities" },
+                      { "isSystem": true, "path":"/usr/include/something" },
+                      ...
+                    ]
+                    "language":"C",
+                    "sources":
+                    [
+                      "fld_arg.c",
+                      ...
+                      "fty_regex.c"
+                    ]
+                  }
+                ],
+                "fullName":"libcmForm.a",
+                "linkerLanguage":"C",
+                "name":"cmForm",
+                "type":"STATIC_LIBRARY"
+              }
+            ]
+          }
+        ],
+      },
+      ...
+    ]
+  }
+  ]== CMake Server ==]
+
+The output can be tailored to the specific needs via parameter passed when
+requesting "project" information.
+
+You can have a "depth" key, which accepts "project", "configuration" and
+"target" as string values. These cause the output to be trimmed at the
+appropriate depth of the output tree.
+
+You can also set "configurations" to an array of strings with configuration
+names to list. This will cause any configuration that is not listed to be
+trimmed from the output.
+
+Generated files can be included in the listing by setting "includeGeneratedFiles"
+to "true". This setting defaults to "false", so generated files are not
+listed by default.
+
+Finally you can limit the target types that are going to be listed. This is
+done by providing a list of target types as an array of strings to the
+"targetTypes" key.
diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h
index e429571..9e83864 100644
--- a/Source/cmServerDictionary.h
+++ b/Source/cmServerDictionary.h
@@ -6,6 +6,7 @@
 
 // Vocabulary:
 
+static const std::string kCODE_MODEL_TYPE = "codemodel";
 static const std::string kCOMPUTE_TYPE = "compute";
 static const std::string kCONFIGURE_TYPE = "configure";
 static const std::string kERROR_TYPE = "error";
@@ -17,29 +18,50 @@ static const std::string kREPLY_TYPE = "reply";
 static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings";
 static const std::string kSIGNAL_TYPE = "signal";
 
+static const std::string kARTIFACTS_KEY = "artifacts";
 static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
 static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments";
 static const std::string kCAPABILITIES_KEY = "capabilities";
 static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars";
+static const std::string kCOMPILE_FLAGS_KEY = "compileFlags";
+static const std::string kCONFIGURATIONS_KEY = "configurations";
 static const std::string kCOOKIE_KEY = "cookie";
 static const std::string kDEBUG_OUTPUT_KEY = "debugOutput";
+static const std::string kDEFINES_KEY = "defines";
 static const std::string kERROR_MESSAGE_KEY = "errorMessage";
 static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
+static const std::string kFILE_GROUPS_KEY = "fileGroups";
+static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath";
+static const std::string kFULL_NAME_KEY = "fullName";
 static const std::string kGENERATOR_KEY = "generator";
+static const std::string kINCLUDE_PATH_KEY = "includePath";
 static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental";
+static const std::string kIS_GENERATED_KEY = "isGenerated";
+static const std::string kIS_SYSTEM_KEY = "isSystem";
+static const std::string kLANGUAGE_KEY = "language";
+static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage";
+static const std::string kLINK_FLAGS_KEY = "linkFlags";
+static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags";
+static const std::string kLINK_LIBRARIES_KEY = "linkLibraries";
+static const std::string kLINK_PATH_KEY = "linkPath";
 static const std::string kMAJOR_KEY = "major";
 static const std::string kMESSAGE_KEY = "message";
 static const std::string kMINOR_KEY = "minor";
 static const std::string kNAME_KEY = "name";
+static const std::string kPATH_KEY = "path";
 static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent";
 static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum";
 static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage";
 static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum";
+static const std::string kPROJECTS_KEY = "projects";
 static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion";
 static const std::string kREPLY_TO_KEY = "inReplyTo";
 static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
+static const std::string kSOURCES_KEY = "sources";
 static const std::string kSUPPORTED_PROTOCOL_VERSIONS =
   "supportedProtocolVersions";
+static const std::string kSYSROOT_KEY = "sysroot";
+static const std::string kTARGETS_KEY = "targets";
 static const std::string kTITLE_KEY = "title";
 static const std::string kTRACE_EXPAND_KEY = "traceExpand";
 static const std::string kTRACE_KEY = "trace";
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index c505568..c2eeee0 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -3,9 +3,13 @@
 #include "cmServerProtocol.h"
 
 #include "cmExternalMakefileProjectGenerator.h"
+#include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
 #include "cmServer.h"
 #include "cmServerDictionary.h"
+#include "cmSourceFile.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -16,6 +20,49 @@
 #include "cm_jsoncpp_value.h"
 #endif
 
+#include <algorithm>
+#include <string>
+#include <vector>
+
+// Get rid of some windows macros:
+#undef max
+
+namespace {
+
+static std::vector<std::string> getConfigurations(const cmake* cm)
+{
+  std::vector<std::string> configurations;
+  auto makefiles = cm->GetGlobalGenerator()->GetMakefiles();
+  if (makefiles.empty()) {
+    return configurations;
+  }
+
+  makefiles[0]->GetConfigurations(configurations);
+  if (configurations.empty())
+    configurations.push_back("");
+  return configurations;
+}
+
+static bool hasString(const Json::Value& v, const std::string& s)
+{
+  return !v.isNull() &&
+    std::find_if(v.begin(), v.end(), [s](const Json::Value& i) {
+      return i.asString() == s;
+    }) != v.end();
+}
+
+template <class T>
+static Json::Value fromStringList(const T& in)
+{
+  Json::Value result = Json::arrayValue;
+  for (const std::string& i : in) {
+    result.append(i);
+  }
+  return result;
+}
+
+} // namespace
+
 cmServerRequest::cmServerRequest(cmServer* server, const std::string& t,
                                  const std::string& c, const Json::Value& d)
   : Type(t)
@@ -270,6 +317,9 @@ const cmServerResponse cmServerProtocol1_0::Process(
 {
   assert(this->m_State >= STATE_ACTIVE);
 
+  if (request.Type == kCODE_MODEL_TYPE) {
+    return this->ProcessCodeModel(request);
+  }
   if (request.Type == kCOMPUTE_TYPE) {
     return this->ProcessCompute(request);
   }
@@ -291,6 +341,342 @@ bool cmServerProtocol1_0::IsExperimental() const
   return true;
 }
 
+class LanguageData
+{
+public:
+  bool operator==(const LanguageData& other) const;
+
+  void SetDefines(const std::set<std::string>& defines);
+
+  bool IsGenerated = false;
+  std::string Language;
+  std::string Flags;
+  std::vector<std::string> Defines;
+  std::vector<std::pair<std::string, bool> > IncludePathList;
+};
+
+bool LanguageData::operator==(const LanguageData& other) const
+{
+  return Language == other.Language && Defines == other.Defines &&
+    Flags == other.Flags && IncludePathList == other.IncludePathList &&
+    IsGenerated == other.IsGenerated;
+}
+
+void LanguageData::SetDefines(const std::set<std::string>& defines)
+{
+  std::vector<std::string> result;
+  for (auto i : defines) {
+    result.push_back(i);
+  }
+  std::sort(result.begin(), result.end());
+  Defines = result;
+}
+
+namespace std {
+
+template <>
+struct hash<LanguageData>
+{
+  std::size_t operator()(const LanguageData& in) const
+  {
+    using std::hash;
+    size_t result =
+      hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags);
+    for (auto i : in.IncludePathList) {
+      result = result ^ (hash<std::string>()(i.first) ^
+                         (i.second ? std::numeric_limits<size_t>::max() : 0));
+    }
+    for (auto i : in.Defines) {
+      result = result ^ hash<std::string>()(i);
+    }
+    result =
+      result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0);
+    return result;
+  }
+};
+
+} // namespace std
+
+static Json::Value DumpSourceFileGroup(const LanguageData& data,
+                                       const std::vector<std::string>& files,
+                                       const std::string& baseDir)
+{
+  Json::Value result = Json::objectValue;
+
+  if (!data.Language.empty()) {
+    result[kLANGUAGE_KEY] = data.Language;
+    if (!data.Flags.empty()) {
+      result[kCOMPILE_FLAGS_KEY] = data.Flags;
+    }
+    if (!data.IncludePathList.empty()) {
+      Json::Value includes = Json::arrayValue;
+      for (auto i : data.IncludePathList) {
+        Json::Value tmp = Json::objectValue;
+        tmp[kPATH_KEY] = i.first;
+        if (i.second) {
+          tmp[kIS_SYSTEM_KEY] = i.second;
+        }
+        includes.append(tmp);
+      }
+      result[kINCLUDE_PATH_KEY] = includes;
+    }
+    if (!data.Defines.empty()) {
+      result[kDEFINES_KEY] = fromStringList(data.Defines);
+    }
+  }
+
+  result[kIS_GENERATED_KEY] = data.IsGenerated;
+
+  Json::Value sourcesValue = Json::arrayValue;
+  for (auto i : files) {
+    const std::string relPath =
+      cmSystemTools::RelativePath(baseDir.c_str(), i.c_str());
+    sourcesValue.append(relPath.size() < i.size() ? relPath : i);
+  }
+
+  result[kSOURCES_KEY] = sourcesValue;
+  return result;
+}
+
+static Json::Value DumpSourceFilesList(
+  cmGeneratorTarget* target, const std::string& config,
+  const std::map<std::string, LanguageData>& languageDataMap)
+{
+  // Collect sourcefile groups:
+
+  std::vector<cmSourceFile*> files;
+  target->GetSourceFiles(files, config);
+
+  std::unordered_map<LanguageData, std::vector<std::string> > fileGroups;
+  for (cmSourceFile* file : files) {
+    LanguageData fileData;
+    fileData.Language = file->GetLanguage();
+    if (!fileData.Language.empty()) {
+      const LanguageData& ld = languageDataMap.at(fileData.Language);
+      cmLocalGenerator* lg = target->GetLocalGenerator();
+
+      std::string compileFlags = ld.Flags;
+      lg->AppendFlags(compileFlags, file->GetProperty("COMPILE_FLAGS"));
+      fileData.Flags = compileFlags;
+
+      fileData.IncludePathList = ld.IncludePathList;
+
+      std::set<std::string> defines;
+      lg->AppendDefines(defines, file->GetProperty("COMPILE_DEFINITIONS"));
+      const std::string defPropName =
+        "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
+      lg->AppendDefines(defines, file->GetProperty(defPropName));
+      defines.insert(ld.Defines.begin(), ld.Defines.end());
+
+      fileData.SetDefines(defines);
+    }
+
+    fileData.IsGenerated = file->GetPropertyAsBool("GENERATED");
+    std::vector<std::string>& groupFileList = fileGroups[fileData];
+    groupFileList.push_back(file->GetFullPath());
+  }
+
+  const std::string baseDir = target->Makefile->GetCurrentSourceDirectory();
+  Json::Value result = Json::arrayValue;
+  for (auto it = fileGroups.begin(); it != fileGroups.end(); ++it) {
+    Json::Value group = DumpSourceFileGroup(it->first, it->second, baseDir);
+    if (!group.isNull())
+      result.append(group);
+  }
+
+  return result;
+}
+
+static Json::Value DumpTarget(cmGeneratorTarget* target,
+                              const std::string& config)
+{
+  cmLocalGenerator* lg = target->GetLocalGenerator();
+  const cmState* state = lg->GetState();
+
+  const cmState::TargetType type = target->GetType();
+  const std::string typeName = state->GetTargetTypeName(type);
+
+  Json::Value ttl = Json::arrayValue;
+  ttl.append("EXECUTABLE");
+  ttl.append("STATIC_LIBRARY");
+  ttl.append("SHARED_LIBRARY");
+  ttl.append("MODULE_LIBRARY");
+  ttl.append("OBJECT_LIBRARY");
+  ttl.append("UTILITY");
+  ttl.append("INTERFACE_LIBRARY");
+
+  if (!hasString(ttl, typeName) || target->IsImported()) {
+    return Json::Value();
+  }
+
+  Json::Value result = Json::objectValue;
+  result[kNAME_KEY] = target->GetName();
+
+  result[kTYPE_KEY] = typeName;
+  result[kFULL_NAME_KEY] = target->GetFullName(config);
+  result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory();
+  result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory();
+
+  if (target->HaveWellDefinedOutputFiles()) {
+    Json::Value artifacts = Json::arrayValue;
+    artifacts.append(target->GetFullPath(config, false));
+    if (target->IsDLLPlatform()) {
+      artifacts.append(target->GetFullPath(config, true));
+      const cmGeneratorTarget::OutputInfo* output =
+        target->GetOutputInfo(config);
+      if (output && !output->PdbDir.empty()) {
+        artifacts.append(output->PdbDir + '/' + target->GetPDBName(config));
+      }
+    }
+    result[kARTIFACTS_KEY] = artifacts;
+
+    result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config);
+
+    std::string linkLibs;
+    std::string linkFlags;
+    std::string linkLanguageFlags;
+    std::string frameworkPath;
+    std::string linkPath;
+    lg->GetTargetFlags(config, linkLibs, linkLanguageFlags, linkFlags,
+                       frameworkPath, linkPath, target, false);
+
+    linkLibs = cmSystemTools::TrimWhitespace(linkLibs);
+    linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
+    linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags);
+    frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath);
+    linkPath = cmSystemTools::TrimWhitespace(linkPath);
+
+    if (!cmSystemTools::TrimWhitespace(linkLibs).empty()) {
+      result[kLINK_LIBRARIES_KEY] = linkLibs;
+    }
+    if (!cmSystemTools::TrimWhitespace(linkFlags).empty()) {
+      result[kLINK_FLAGS_KEY] = linkFlags;
+    }
+    if (!cmSystemTools::TrimWhitespace(linkLanguageFlags).empty()) {
+      result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags;
+    }
+    if (!frameworkPath.empty()) {
+      result[kFRAMEWORK_PATH_KEY] = frameworkPath;
+    }
+    if (!linkPath.empty()) {
+      result[kLINK_PATH_KEY] = linkPath;
+    }
+    const std::string sysroot =
+      lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT");
+    if (!sysroot.empty()) {
+      result[kSYSROOT_KEY] = sysroot;
+    }
+  }
+
+  std::set<std::string> languages;
+  target->GetLanguages(languages, config);
+  std::map<std::string, LanguageData> languageDataMap;
+  for (auto lang : languages) {
+    LanguageData& ld = languageDataMap[lang];
+    ld.Language = lang;
+    lg->GetTargetCompileFlags(target, config, lang, ld.Flags);
+    std::set<std::string> defines;
+    lg->GetTargetDefines(target, config, lang, defines);
+    ld.SetDefines(defines);
+    std::vector<std::string> includePathList;
+    lg->GetIncludeDirectories(includePathList, target, lang, config, true);
+    for (auto i : includePathList) {
+      ld.IncludePathList.push_back(
+        std::make_pair(i, target->IsSystemIncludeDirectory(i, config)));
+    }
+  }
+
+  Json::Value sourceGroupsValue =
+    DumpSourceFilesList(target, config, languageDataMap);
+  if (!sourceGroupsValue.empty()) {
+    result[kFILE_GROUPS_KEY] = sourceGroupsValue;
+  }
+
+  return result;
+}
+
+static Json::Value DumpTargetsList(
+  const std::vector<cmLocalGenerator*>& generators, const std::string& config)
+{
+  Json::Value result = Json::arrayValue;
+
+  std::vector<cmGeneratorTarget*> targetList;
+  for (const auto& lgIt : generators) {
+    auto list = lgIt->GetGeneratorTargets();
+    targetList.insert(targetList.end(), list.begin(), list.end());
+  }
+  std::sort(targetList.begin(), targetList.end());
+
+  for (cmGeneratorTarget* target : targetList) {
+    Json::Value tmp = DumpTarget(target, config);
+    if (!tmp.isNull()) {
+      result.append(tmp);
+    }
+  }
+
+  return result;
+}
+
+static Json::Value DumpProjectList(const cmake* cm, const std::string config)
+{
+  Json::Value result = Json::arrayValue;
+
+  auto globalGen = cm->GetGlobalGenerator();
+
+  for (const auto& projectIt : globalGen->GetProjectMap()) {
+    Json::Value pObj = Json::objectValue;
+    pObj[kNAME_KEY] = projectIt.first;
+
+    assert(projectIt.second.size() >
+           0); // All Projects must have at least one local generator
+    const cmLocalGenerator* lg = projectIt.second.at(0);
+
+    // Project structure information:
+    const cmMakefile* mf = lg->GetMakefile();
+    pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory();
+    pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory();
+    pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config);
+
+    result.append(pObj);
+  }
+
+  return result;
+}
+
+static Json::Value DumpConfiguration(const cmake* cm,
+                                     const std::string& config)
+{
+  Json::Value result = Json::objectValue;
+  result[kNAME_KEY] = config;
+
+  result[kPROJECTS_KEY] = DumpProjectList(cm, config);
+
+  return result;
+}
+
+static Json::Value DumpConfigurationsList(const cmake* cm)
+{
+  Json::Value result = Json::arrayValue;
+
+  for (const std::string& c : getConfigurations(cm)) {
+    result.append(DumpConfiguration(cm, c));
+  }
+
+  return result;
+}
+
+cmServerResponse cmServerProtocol1_0::ProcessCodeModel(
+  const cmServerRequest& request)
+{
+  if (this->m_State != STATE_COMPUTED) {
+    return request.ReportError("No build system was generated yet.");
+  }
+
+  Json::Value result = Json::objectValue;
+  result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(this->CMakeInstance());
+  return request.Reply(result);
+}
+
 cmServerResponse cmServerProtocol1_0::ProcessCompute(
   const cmServerRequest& request)
 {
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
index 63ef0be..193e0a3 100644
--- a/Source/cmServerProtocol.h
+++ b/Source/cmServerProtocol.h
@@ -108,6 +108,7 @@ private:
                   std::string* errorMessage) override;
 
   // Handle requests:
+  cmServerResponse ProcessCodeModel(const cmServerRequest& request);
   cmServerResponse ProcessCompute(const cmServerRequest& request);
   cmServerResponse ProcessConfigure(const cmServerRequest& request);
   cmServerResponse ProcessGlobalSettings(const cmServerRequest& request);

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

Summary of changes:
 Help/manual/cmake-server.7.rst                     |  261 ++++++++++
 Source/cmServerDictionary.h                        |   33 ++
 Source/cmServerProtocol.cxx                        |  549 +++++++++++++++++++-
 Source/cmServerProtocol.h                          |    3 +
 Tests/Server/CMakeLists.txt                        |    2 +
 Tests/Server/buildsystem1/CMakeLists.txt           |   22 +
 .../buildsystem1}/foo.cpp                          |    1 +
 .../buildsystem1}/main.cpp                         |    0
 Tests/Server/buildsystem1/subdir/CMakeLists.txt    |    5 +
 .../buildsystem1/subdir/empty.cpp}                 |    1 +
 Tests/Server/cmakelib.py                           |   20 +-
 Tests/Server/server-test.py                        |   37 +-
 Tests/Server/tc_buildsystem1.json                  |   27 +
 13 files changed, 939 insertions(+), 22 deletions(-)
 create mode 100644 Tests/Server/buildsystem1/CMakeLists.txt
 copy Tests/{CompatibleInterface => Server/buildsystem1}/foo.cpp (96%)
 copy Tests/{RunCMake/COMPILE_LANGUAGE-genex => Server/buildsystem1}/main.cpp (100%)
 create mode 100644 Tests/Server/buildsystem1/subdir/CMakeLists.txt
 copy Tests/{CompatibleInterface/foo.cpp => Server/buildsystem1/subdir/empty.cpp} (96%)
 create mode 100644 Tests/Server/tc_buildsystem1.json


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list