1
0
Эх сурвалжийг харах

fileapi: add cmakeFiles v1

Issue: #18398
Brad King 7 жил өмнө
parent
commit
6615408193

+ 82 - 0
Help/manual/cmake-file-api.7.rst

@@ -943,3 +943,85 @@ The members specific to ``cache`` objects are:
 
     ``value``
       A string specifying the value of the cache entry property.
+
+Object Kind "cmakeFiles"
+------------------------
+
+The ``cmakeFiles`` object kind lists files used by CMake while
+configuring and generating the build system.  These include the
+``CMakeLists.txt`` files as well as included ``.cmake`` files.
+
+There is only one ``cmakeFiles`` object major version, version 1.
+
+"cmakeFiles" version 1
+^^^^^^^^^^^^^^^^^^^^^^
+
+``cmakeFiles`` object version 1 is a JSON object:
+
+.. code-block:: json
+
+  {
+    "kind": "cmakeFiles",
+    "version": { "major": 1, "minor": 0 },
+    "paths": {
+      "build": "/path/to/top-level-build-dir",
+      "source": "/path/to/top-level-source-dir"
+    },
+    "inputs": [
+      {
+        "path": "CMakeLists.txt"
+      },
+      {
+        "isGenerated": true,
+        "path": "/path/to/top-level-build-dir/.../CMakeSystem.cmake"
+      },
+      {
+        "isExternal": true,
+        "path": "/path/to/external/third-party/module.cmake"
+      },
+      {
+        "isCMake": true,
+        "isExternal": true,
+        "path": "/path/to/cmake/Modules/CMakeGenericSystem.cmake"
+      }
+    ]
+  }
+
+The members specific to ``cmakeFiles`` objects are:
+
+``paths``
+  A JSON object containing members:
+
+  ``source``
+    A string specifying the absolute path to the top-level source directory,
+    represented with forward slashes.
+
+  ``build``
+    A string specifying the absolute path to the top-level build directory,
+    represented with forward slashes.
+
+``inputs``
+  A JSON array whose entries are each a JSON object specifying an input
+  file used by CMake when configuring and generating the build system.
+  The members of each entry are:
+
+  ``path``
+    A string specifying the path to an input file to CMake, represented
+    with forward slashes.  If the file is inside the top-level source
+    directory then the path is specified relative to that directory.
+    Otherwise the path is absolute.
+
+  ``isGenerated``
+    Optional member that is present with boolean value ``true``
+    if the path specifies a file that is under the top-level
+    build directory and the build is out-of-source.
+    This member is not available on in-source builds.
+
+  ``isExternal``
+    Optional member that is present with boolean value ``true``
+    if the path specifies a file that is not under the top-level
+    source or build directories.
+
+  ``isCMake``
+    Optional member that is present with boolean value ``true``
+    if the path specifies a file in the CMake installation.

+ 2 - 0
Source/CMakeLists.txt

@@ -213,6 +213,8 @@ set(SRCS
   cmFileAPICache.h
   cmFileAPICodemodel.cxx
   cmFileAPICodemodel.h
+  cmFileAPICMakeFiles.cxx
+  cmFileAPICMakeFiles.h
   cmFileLock.cxx
   cmFileLock.h
   cmFileLockPool.cxx

+ 60 - 3
Source/cmFileAPI.cxx

@@ -4,6 +4,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmCryptoHash.h"
+#include "cmFileAPICMakeFiles.h"
 #include "cmFileAPICache.h"
 #include "cmFileAPICodemodel.h"
 #include "cmGlobalGenerator.h"
@@ -248,6 +249,17 @@ bool cmFileAPI::ReadQuery(std::string const& query,
     objects.push_back(o);
     return true;
   }
+  if (kindName == ObjectKindName(ObjectKind::CMakeFiles)) {
+    Object o;
+    o.Kind = ObjectKind::CMakeFiles;
+    if (verStr == "v1") {
+      o.Version = 1;
+    } else {
+      return false;
+    }
+    objects.push_back(o);
+    return true;
+  }
   if (kindName == ObjectKindName(ObjectKind::InternalTest)) {
     Object o;
     o.Kind = ObjectKind::InternalTest;
@@ -385,9 +397,10 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind)
 {
   // Keep in sync with ObjectKind enum.
   static const char* objectKindNames[] = {
-    "codemodel", //
-    "cache",     //
-    "__test"     //
+    "codemodel",  //
+    "cache",      //
+    "cmakeFiles", //
+    "__test"      //
   };
   return objectKindNames[size_t(kind)];
 }
@@ -411,6 +424,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object)
     case ObjectKind::Cache:
       value = this->BuildCache(object);
       break;
+    case ObjectKind::CMakeFiles:
+      value = this->BuildCMakeFiles(object);
+      break;
     case ObjectKind::InternalTest:
       value = this->BuildInternalTest(object);
       break;
@@ -465,6 +481,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
     r.Kind = ObjectKind::CodeModel;
   } else if (kindName == this->ObjectKindName(ObjectKind::Cache)) {
     r.Kind = ObjectKind::Cache;
+  } else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) {
+    r.Kind = ObjectKind::CMakeFiles;
   } else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
     r.Kind = ObjectKind::InternalTest;
   } else {
@@ -489,6 +507,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
     case ObjectKind::Cache:
       this->BuildClientRequestCache(r, versions);
       break;
+    case ObjectKind::CMakeFiles:
+      this->BuildClientRequestCMakeFiles(r, versions);
+      break;
     case ObjectKind::InternalTest:
       this->BuildClientRequestInternalTest(r, versions);
       break;
@@ -706,6 +727,42 @@ Json::Value cmFileAPI::BuildCache(Object const& object)
   return cache;
 }
 
+// The "cmakeFiles" object kind.
+
+static unsigned int const CMakeFilesV1Minor = 0;
+
+void cmFileAPI::BuildClientRequestCMakeFiles(
+  ClientRequest& r, std::vector<RequestVersion> const& versions)
+{
+  // Select a known version from those requested.
+  for (RequestVersion const& v : versions) {
+    if ((v.Major == 1 && v.Minor <= CMakeFilesV1Minor)) {
+      r.Version = v.Major;
+      break;
+    }
+  }
+  if (!r.Version) {
+    r.Error = NoSupportedVersion(versions);
+  }
+}
+
+Json::Value cmFileAPI::BuildCMakeFiles(Object const& object)
+{
+  using namespace std::placeholders;
+  Json::Value cmakeFiles = cmFileAPICMakeFilesDump(*this, object.Version);
+  cmakeFiles["kind"] = this->ObjectKindName(object.Kind);
+
+  Json::Value& version = cmakeFiles["version"] = Json::objectValue;
+  if (object.Version == 1) {
+    version["major"] = 1;
+    version["minor"] = CMakeFilesV1Minor;
+  } else {
+    return cmakeFiles; // should be unreachable
+  }
+
+  return cmakeFiles;
+}
+
 // The "__test" object kind is for internal testing of CMake.
 
 static unsigned int const InternalTestV1Minor = 3;

+ 5 - 0
Source/cmFileAPI.h

@@ -53,6 +53,7 @@ private:
   {
     CodeModel,
     Cache,
+    CMakeFiles,
     InternalTest
   };
 
@@ -191,6 +192,10 @@ private:
                                std::vector<RequestVersion> const& versions);
   Json::Value BuildCache(Object const& object);
 
+  void BuildClientRequestCMakeFiles(
+    ClientRequest& r, std::vector<RequestVersion> const& versions);
+  Json::Value BuildCMakeFiles(Object const& object);
+
   void BuildClientRequestInternalTest(
     ClientRequest& r, std::vector<RequestVersion> const& versions);
   Json::Value BuildInternalTest(Object const& object);

+ 113 - 0
Source/cmFileAPICMakeFiles.cxx

@@ -0,0 +1,113 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmFileAPICMakeFiles.h"
+
+#include "cmFileAPI.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include "cm_jsoncpp_value.h"
+
+#include <string>
+
+namespace {
+
+class CMakeFiles
+{
+  cmFileAPI& FileAPI;
+  unsigned long Version;
+  std::string CMakeModules;
+  std::string const& TopSource;
+  std::string const& TopBuild;
+  bool OutOfSource;
+
+  Json::Value DumpPaths();
+  Json::Value DumpInputs();
+  Json::Value DumpInput(std::string const& file);
+
+public:
+  CMakeFiles(cmFileAPI& fileAPI, unsigned long version);
+  Json::Value Dump();
+};
+
+CMakeFiles::CMakeFiles(cmFileAPI& fileAPI, unsigned long version)
+  : FileAPI(fileAPI)
+  , Version(version)
+  , CMakeModules(cmSystemTools::GetCMakeRoot() + "/Modules")
+  , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
+  , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
+  , OutOfSource(TopBuild != TopSource)
+{
+  static_cast<void>(this->Version);
+}
+
+Json::Value CMakeFiles::Dump()
+{
+  Json::Value cmakeFiles = Json::objectValue;
+  cmakeFiles["paths"] = this->DumpPaths();
+  cmakeFiles["inputs"] = DumpInputs();
+  return cmakeFiles;
+}
+
+Json::Value CMakeFiles::DumpPaths()
+{
+  Json::Value paths = Json::objectValue;
+  paths["source"] = this->TopSource;
+  paths["build"] = this->TopBuild;
+  return paths;
+}
+
+Json::Value CMakeFiles::DumpInputs()
+{
+  Json::Value inputs = Json::arrayValue;
+
+  cmGlobalGenerator* gg =
+    this->FileAPI.GetCMakeInstance()->GetGlobalGenerator();
+  for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) {
+    cmMakefile const* mf = lg->GetMakefile();
+    for (std::string const& file : mf->GetListFiles()) {
+      inputs.append(this->DumpInput(file));
+    }
+  }
+
+  return inputs;
+}
+
+Json::Value CMakeFiles::DumpInput(std::string const& file)
+{
+  Json::Value input = Json::objectValue;
+
+  bool const isCMake = cmSystemTools::IsSubDirectory(file, this->CMakeModules);
+  if (isCMake) {
+    input["isCMake"] = true;
+  }
+
+  if (!cmSystemTools::IsSubDirectory(file, this->TopSource) &&
+      !cmSystemTools::IsSubDirectory(file, this->TopBuild)) {
+    input["isExternal"] = true;
+  }
+
+  if (this->OutOfSource &&
+      cmSystemTools::IsSubDirectory(file, this->TopBuild)) {
+    input["isGenerated"] = true;
+  }
+
+  std::string path = file;
+  if (!isCMake && cmSystemTools::IsSubDirectory(path, this->TopSource)) {
+    // Use a relative path within the source directory.
+    path = cmSystemTools::RelativePath(this->TopSource, path);
+  }
+  input["path"] = path;
+
+  return input;
+}
+}
+
+Json::Value cmFileAPICMakeFilesDump(cmFileAPI& fileAPI, unsigned long version)
+{
+  CMakeFiles cmakeFiles(fileAPI, version);
+  return cmakeFiles.Dump();
+}

+ 15 - 0
Source/cmFileAPICMakeFiles.h

@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmFileAPICMakeFiles_h
+#define cmFileAPICMakeFiles_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cm_jsoncpp_value.h"
+
+class cmFileAPI;
+
+extern Json::Value cmFileAPICMakeFilesDump(cmFileAPI& fileAPI,
+                                           unsigned long version);
+
+#endif

+ 1 - 0
Tests/RunCMake/FileAPI/RunCMakeTest.cmake

@@ -55,3 +55,4 @@ endfunction()
 
 run_object(codemodel-v2)
 run_object(cache-v2)
+run_object(cmakeFiles-v1)

+ 11 - 0
Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateful-check.cmake

@@ -0,0 +1,11 @@
+set(expect
+  query
+  query/client-foo
+  query/client-foo/query.json
+  reply
+  reply/cmakeFiles-v1-[0-9a-f]+.json
+  reply/index-[0-9.T-]+.json
+  )
+check_api("^${expect}$")
+
+check_python(cmakeFiles-v1)

+ 4 - 0
Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateful-prep.cmake

@@ -0,0 +1,4 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/query.json" [[
+{ "requests": [ { "kind": "cmakeFiles", "version" : 1 } ] }
+]])

+ 11 - 0
Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateless-check.cmake

@@ -0,0 +1,11 @@
+set(expect
+  query
+  query/client-foo
+  query/client-foo/cmakeFiles-v1
+  reply
+  reply/cmakeFiles-v1-[0-9a-f]+.json
+  reply/index-[0-9.T-]+.json
+  )
+check_api("^${expect}$")
+
+check_python(cmakeFiles-v1)

+ 2 - 0
Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateless-prep.cmake

@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/cmakeFiles-v1" "")

+ 10 - 0
Tests/RunCMake/FileAPI/cmakeFiles-v1-SharedStateless-check.cmake

@@ -0,0 +1,10 @@
+set(expect
+  query
+  query/cmakeFiles-v1
+  reply
+  reply/cmakeFiles-v1-[0-9a-f]+.json
+  reply/index-[0-9.T-]+.json
+  )
+check_api("^${expect}$")
+
+check_python(cmakeFiles-v1)

+ 2 - 0
Tests/RunCMake/FileAPI/cmakeFiles-v1-SharedStateless-prep.cmake

@@ -0,0 +1,2 @@
+file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/cmakeFiles-v1" "")

+ 15 - 0
Tests/RunCMake/FileAPI/cmakeFiles-v1-check.py

@@ -0,0 +1,15 @@
+from check_index import *
+
+def check_objects(o):
+    assert is_list(o)
+    assert len(o) == 1
+    check_index_object(o[0], "cmakeFiles", 1, 0, check_object_cmakeFiles)
+
+def check_object_cmakeFiles(o):
+    assert sorted(o.keys()) == ["inputs", "kind", "paths", "version"]
+    # The "kind" and "version" members are handled by check_index_object.
+    # FIXME: Check "paths" and "inputs" members.
+
+assert is_dict(index)
+assert sorted(index.keys()) == ["cmake", "objects", "reply"]
+check_objects(index["objects"])

+ 0 - 0
Tests/RunCMake/FileAPI/cmakeFiles-v1.cmake