소스 검색

Merge topic 'fileapi-provide-glob-dependent'

6116bcb066 fileapi: Add CONFIGURE_DEPENDS glob info to cmakeFiles object
f578515d02 cmGlobCacheEntry: Add helper to carry CONFIGURE_DEPENDS glob cache arguments

Acked-by: Kitware Robot <[email protected]>
Tested-by: buildbot <[email protected]>
Merge-request: !9348
Brad King 1 년 전
부모
커밋
388f7bc11b

+ 49 - 1
Help/manual/cmake-file-api.7.rst

@@ -1489,7 +1489,7 @@ There is only one ``cmakeFiles`` object major version, version 1.
 
   {
     "kind": "cmakeFiles",
-    "version": { "major": 1, "minor": 0 },
+    "version": { "major": 1, "minor": 1 },
     "paths": {
       "build": "/path/to/top-level-build-dir",
       "source": "/path/to/top-level-source-dir"
@@ -1511,6 +1511,16 @@ There is only one ``cmakeFiles`` object major version, version 1.
         "isExternal": true,
         "path": "/path/to/cmake/Modules/CMakeGenericSystem.cmake"
       }
+    ],
+    "globsDependent": [
+      {
+        "expression": "src/*.cxx",
+        "recurse": true,
+        "files": [
+          "src/foo.cxx",
+          "src/bar.cxx"
+        ]
+      }
     ]
   }
 
@@ -1553,6 +1563,44 @@ The members specific to ``cmakeFiles`` objects are:
     Optional member that is present with boolean value ``true``
     if the path specifies a file in the CMake installation.
 
+``globsDependent``
+  Optional member that is present when the project calls :command:`file(GLOB)`
+  or :command:`file(GLOB_RECURSE)` with the ``CONFIGURE_DEPENDS`` option.
+  The value is a JSON array of JSON objects, each specifying a globbing
+  expression and the list of paths it matched.  If the globbing expression
+  no longer matches the same list of paths, CMake considers the build system
+  to be out of date.
+
+  This field was added in ``cmakeFiles`` version 1.1.
+
+  The members of each entry are:
+
+  ``expression``
+    A string specifying the globbing expression.
+
+  ``recurse``
+    Optional member that is present with boolean value ``true``
+    if the entry corresponds to a :command:`file(GLOB_RECURSE)` call.
+    Otherwise the entry corresponds to a :command:`file(GLOB)` call.
+
+  ``listDirectories``
+    Optional member that is present with boolean value ``true`` if
+    :command:`file(GLOB)` was called without ``LIST_DIRECTORIES false`` or
+    :command:`file(GLOB_RECURSE)` was called with ``LIST_DIRECTORIES true``.
+
+  ``followSymlinks``
+    Optional member that is present with boolean value ``true`` if
+    :command:`file(GLOB)` was called with the ``FOLLOW_SYMLINKS`` option.
+
+  ``relative``
+    Optional member that is present if :command:`file(GLOB)` was called
+    with the ``RELATIVE <path>`` option.  The value is a string containing
+    the ``<path>`` given.
+
+  ``paths``
+    A JSON array of strings specifying the paths matched by the call
+    to :command:`file(GLOB)` or :command:`file(GLOB_RECURSE)`.
+
 Object Kind "toolchains"
 ------------------------
 

+ 9 - 0
Help/release/dev/fileapi-provide-glob-dependent.rst

@@ -0,0 +1,9 @@
+fileapi-provide-glob-dependent
+------------------------------
+
+* The :manual:`cmake-file-api(7)` "cmakeFiles" version 1 object's ``version``
+  field has been updated to 1.1.
+
+* The :manual:`cmake-file-api(7)` "cmakeFiles" version 1 object gained a
+  ``globsDependent`` field to report :command:`file(GLOB)` calls using
+  ``CONFIGURE_DEPENDS``.

+ 1 - 1
Source/cmFileAPI.cxx

@@ -830,7 +830,7 @@ Json::Value cmFileAPI::BuildCache(Object const& object)
 
 // The "cmakeFiles" object kind.
 
-static unsigned int const CMakeFilesV1Minor = 0;
+static unsigned int const CMakeFilesV1Minor = 1;
 
 void cmFileAPI::BuildClientRequestCMakeFiles(
   ClientRequest& r, std::vector<RequestVersion> const& versions)

+ 42 - 0
Source/cmFileAPICMakeFiles.cxx

@@ -4,11 +4,13 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include <cm3p/json/value.h>
 
 #include "cmFileAPI.h"
+#include "cmGlobCacheEntry.h"
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -29,6 +31,8 @@ class CMakeFiles
   Json::Value DumpPaths();
   Json::Value DumpInputs();
   Json::Value DumpInput(std::string const& file);
+  Json::Value DumpGlobsDependent();
+  Json::Value DumpGlobDependent(cmGlobCacheEntry const& entry);
 
 public:
   CMakeFiles(cmFileAPI& fileAPI, unsigned long version);
@@ -51,6 +55,10 @@ Json::Value CMakeFiles::Dump()
   Json::Value cmakeFiles = Json::objectValue;
   cmakeFiles["paths"] = this->DumpPaths();
   cmakeFiles["inputs"] = this->DumpInputs();
+  Json::Value globsDependent = this->DumpGlobsDependent();
+  if (!globsDependent.empty()) {
+    cmakeFiles["globsDependent"] = std::move(globsDependent);
+  }
   return cmakeFiles;
 }
 
@@ -106,6 +114,40 @@ Json::Value CMakeFiles::DumpInput(std::string const& file)
 
   return input;
 }
+
+Json::Value CMakeFiles::DumpGlobsDependent()
+{
+  Json::Value globsDependent = Json::arrayValue;
+  for (cmGlobCacheEntry const& entry :
+       this->FileAPI.GetCMakeInstance()->GetGlobCacheEntries()) {
+    globsDependent.append(this->DumpGlobDependent(entry));
+  }
+  return globsDependent;
+}
+
+Json::Value CMakeFiles::DumpGlobDependent(cmGlobCacheEntry const& entry)
+{
+  Json::Value globDependent = Json::objectValue;
+  globDependent["expression"] = entry.Expression;
+  if (entry.Recurse) {
+    globDependent["recurse"] = true;
+  }
+  if (entry.ListDirectories) {
+    globDependent["listDirectories"] = true;
+  }
+  if (entry.FollowSymlinks) {
+    globDependent["followSymlinks"] = true;
+  }
+  if (!entry.Relative.empty()) {
+    globDependent["relative"] = entry.Relative;
+  }
+  Json::Value paths = Json::arrayValue;
+  for (std::string const& file : entry.Files) {
+    paths.append(file);
+  }
+  globDependent["paths"] = std::move(paths);
+  return globDependent;
+}
 }
 
 Json::Value cmFileAPICMakeFilesDump(cmFileAPI& fileAPI, unsigned long version)

+ 10 - 4
Source/cmFileCommand.cxx

@@ -41,6 +41,7 @@
 #include "cmFileTimes.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
+#include "cmGlobCacheEntry.h"
 #include "cmGlobalGenerator.h"
 #include "cmHexFileConverter.h"
 #include "cmList.h"
@@ -810,11 +811,16 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
         std::sort(foundFiles.begin(), foundFiles.end());
         foundFiles.erase(std::unique(foundFiles.begin(), foundFiles.end()),
                          foundFiles.end());
-        cm->AddGlobCacheEntry(
-          recurse, (recurse ? g.GetRecurseListDirs() : g.GetListDirs()),
+        auto entry = cmGlobCacheEntry{
+          recurse,
+          (recurse ? g.GetRecurseListDirs() : g.GetListDirs()),
           (recurse ? g.GetRecurseThroughSymlinks() : false),
-          (g.GetRelative() ? g.GetRelative() : ""), expr, foundFiles, variable,
-          status.GetMakefile().GetBacktrace());
+          (g.GetRelative() ? g.GetRelative() : ""),
+          expr,
+          foundFiles
+        };
+        cm->AddGlobCacheEntry(entry, variable,
+                              status.GetMakefile().GetBacktrace());
       } else {
         warnConfigureLate = true;
       }

+ 30 - 0
Source/cmGlobCacheEntry.h

@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+struct cmGlobCacheEntry
+{
+  const bool Recurse;
+  const bool ListDirectories;
+  const bool FollowSymlinks;
+  const std::string Relative;
+  const std::string Expression;
+  std::vector<std::string> Files;
+
+  cmGlobCacheEntry(bool recurse, bool listDirectories, bool followSymlinks,
+                   std::string relative, std::string expression,
+                   std::vector<std::string> files)
+    : Recurse(recurse)
+    , ListDirectories(listDirectories)
+    , FollowSymlinks(followSymlinks)
+    , Relative(std::move(relative))
+    , Expression(std::move(expression))
+    , Files(std::move(files))
+  {
+  }
+};

+ 22 - 7
Source/cmGlobVerificationManager.cxx

@@ -7,6 +7,7 @@
 #include "cmsys/FStream.hxx"
 
 #include "cmGeneratedFileStream.h"
+#include "cmGlobCacheEntry.h"
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
 #include "cmMessenger.h"
@@ -145,19 +146,18 @@ void cmGlobVerificationManager::CacheEntryKey::PrintGlobCommand(
 }
 
 void cmGlobVerificationManager::AddCacheEntry(
-  const bool recurse, const bool listDirectories, const bool followSymlinks,
-  const std::string& relative, const std::string& expression,
-  const std::vector<std::string>& files, const std::string& variable,
+  const cmGlobCacheEntry& entry, const std::string& variable,
   const cmListFileBacktrace& backtrace, cmMessenger* messenger)
 {
-  CacheEntryKey key = CacheEntryKey(recurse, listDirectories, followSymlinks,
-                                    relative, expression);
+  CacheEntryKey key =
+    CacheEntryKey(entry.Recurse, entry.ListDirectories, entry.FollowSymlinks,
+                  entry.Relative, entry.Expression);
   CacheEntryValue& value = this->Cache[key];
   if (!value.Initialized) {
-    value.Files = files;
+    value.Files = entry.Files;
     value.Initialized = true;
     value.Backtraces.emplace_back(variable, backtrace);
-  } else if (value.Initialized && value.Files != files) {
+  } else if (value.Initialized && value.Files != entry.Files) {
     std::ostringstream message;
     message << std::boolalpha;
     message << "The glob expression\n ";
@@ -176,6 +176,21 @@ void cmGlobVerificationManager::AddCacheEntry(
   }
 }
 
+std::vector<cmGlobCacheEntry> cmGlobVerificationManager::GetCacheEntries()
+  const
+{
+  std::vector<cmGlobCacheEntry> entries;
+  for (auto const& i : this->Cache) {
+    CacheEntryKey k = std::get<0>(i);
+    CacheEntryValue v = std::get<1>(i);
+    if (v.Initialized) {
+      entries.emplace_back(k.Recurse, k.ListDirectories, k.FollowSymlinks,
+                           k.Relative, k.Expression, v.Files);
+    }
+  }
+  return entries;
+}
+
 void cmGlobVerificationManager::Reset()
 {
   this->Cache.clear();

+ 5 - 4
Source/cmGlobVerificationManager.h

@@ -13,6 +13,7 @@
 #include "cmListFileCache.h"
 
 class cmMessenger;
+struct cmGlobCacheEntry;
 
 /** \class cmGlobVerificationManager
  * \brief Class for expressing build-time dependencies on glob expressions.
@@ -28,13 +29,13 @@ protected:
   bool SaveVerificationScript(const std::string& path, cmMessenger* messenger);
 
   //! Add an entry into the glob cache
-  void AddCacheEntry(bool recurse, bool listDirectories, bool followSymlinks,
-                     const std::string& relative,
-                     const std::string& expression,
-                     const std::vector<std::string>& files,
+  void AddCacheEntry(const cmGlobCacheEntry& entry,
                      const std::string& variable,
                      const cmListFileBacktrace& bt, cmMessenger* messenger);
 
+  //! Get all cache entries
+  std::vector<cmGlobCacheEntry> GetCacheEntries() const;
+
   //! Clear the glob cache for state reset.
   void Reset();
 

+ 12 - 8
Source/cmState.cxx

@@ -16,6 +16,7 @@
 #include "cmCommand.h"
 #include "cmDefinitions.h"
 #include "cmExecutionStatus.h"
+#include "cmGlobCacheEntry.h"
 #include "cmGlobVerificationManager.h"
 #include "cmList.h"
 #include "cmListFileCache.h"
@@ -238,15 +239,18 @@ bool cmState::SaveVerificationScript(const std::string& path,
                                                                messenger);
 }
 
-void cmState::AddGlobCacheEntry(
-  bool recurse, bool listDirectories, bool followSymlinks,
-  const std::string& relative, const std::string& expression,
-  const std::vector<std::string>& files, const std::string& variable,
-  cmListFileBacktrace const& backtrace, cmMessenger* messenger)
+void cmState::AddGlobCacheEntry(const cmGlobCacheEntry& entry,
+                                const std::string& variable,
+                                cmListFileBacktrace const& backtrace,
+                                cmMessenger* messenger)
 {
-  this->GlobVerificationManager->AddCacheEntry(
-    recurse, listDirectories, followSymlinks, relative, expression, files,
-    variable, backtrace, messenger);
+  this->GlobVerificationManager->AddCacheEntry(entry, variable, backtrace,
+                                               messenger);
+}
+
+std::vector<cmGlobCacheEntry> cmState::GetGlobCacheEntries() const
+{
+  return this->GlobVerificationManager->GetCacheEntries();
 }
 
 void cmState::RemoveCacheEntry(std::string const& key)

+ 3 - 4
Source/cmState.h

@@ -34,6 +34,7 @@ class cmStateSnapshot;
 class cmMessenger;
 class cmExecutionStatus;
 class cmListFileBacktrace;
+struct cmGlobCacheEntry;
 struct cmListFileArgument;
 
 template <typename T>
@@ -263,13 +264,11 @@ private:
   std::string const& GetGlobVerifyScript() const;
   std::string const& GetGlobVerifyStamp() const;
   bool SaveVerificationScript(const std::string& path, cmMessenger* messenger);
-  void AddGlobCacheEntry(bool recurse, bool listDirectories,
-                         bool followSymlinks, const std::string& relative,
-                         const std::string& expression,
-                         const std::vector<std::string>& files,
+  void AddGlobCacheEntry(const cmGlobCacheEntry& entry,
                          const std::string& variable,
                          cmListFileBacktrace const& bt,
                          cmMessenger* messenger);
+  std::vector<cmGlobCacheEntry> GetGlobCacheEntries() const;
 
   cmPropertyDefinitionMap PropertyDefinitions;
   std::vector<std::string> EnabledLanguages;

+ 9 - 7
Source/cmake.cxx

@@ -48,6 +48,7 @@
 #include "cmExternalMakefileProjectGenerator.h"
 #include "cmFileTimeCache.h"
 #include "cmGeneratorTarget.h"
+#include "cmGlobCacheEntry.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmLinkLineComputer.h"
@@ -2949,16 +2950,17 @@ std::string const& cmake::GetGlobVerifyStamp() const
   return this->State->GetGlobVerifyStamp();
 }
 
-void cmake::AddGlobCacheEntry(bool recurse, bool listDirectories,
-                              bool followSymlinks, const std::string& relative,
-                              const std::string& expression,
-                              const std::vector<std::string>& files,
+void cmake::AddGlobCacheEntry(const cmGlobCacheEntry& entry,
                               const std::string& variable,
                               cmListFileBacktrace const& backtrace)
 {
-  this->State->AddGlobCacheEntry(recurse, listDirectories, followSymlinks,
-                                 relative, expression, files, variable,
-                                 backtrace, this->Messenger.get());
+  this->State->AddGlobCacheEntry(entry, variable, backtrace,
+                                 this->Messenger.get());
+}
+
+std::vector<cmGlobCacheEntry> cmake::GetGlobCacheEntries() const
+{
+  return this->State->GetGlobCacheEntries();
 }
 
 std::vector<std::string> cmake::GetAllExtensions() const

+ 3 - 4
Source/cmake.h

@@ -53,6 +53,7 @@ class cmMakefile;
 class cmMessenger;
 class cmVariableWatch;
 struct cmBuildOptions;
+struct cmGlobCacheEntry;
 
 /** \brief Represents a cmake invocation.
  *
@@ -351,12 +352,10 @@ public:
   bool DoWriteGlobVerifyTarget() const;
   std::string const& GetGlobVerifyScript() const;
   std::string const& GetGlobVerifyStamp() const;
-  void AddGlobCacheEntry(bool recurse, bool listDirectories,
-                         bool followSymlinks, const std::string& relative,
-                         const std::string& expression,
-                         const std::vector<std::string>& files,
+  void AddGlobCacheEntry(const cmGlobCacheEntry& entry,
                          const std::string& variable,
                          cmListFileBacktrace const& bt);
+  std::vector<cmGlobCacheEntry> GetGlobCacheEntries() const;
 
   /**
    * Get the system information and write it to the file specified

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

@@ -1 +1 @@
-^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":7}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
+^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":7}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":1}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$

+ 42 - 2
Tests/RunCMake/FileAPI/cmakeFiles-v1-check.py

@@ -3,7 +3,7 @@ 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)
+    check_index_object(o[0], "cmakeFiles", 1, 1, check_object_cmakeFiles)
 
 def check_input(actual, expected):
     assert is_dict(actual)
@@ -23,8 +23,27 @@ def check_input(actual, expected):
 
     assert sorted(actual.keys()) == sorted(expected_keys)
 
+def check_glob_dependent(actual, expected):
+    assert is_dict(actual)
+
+    if "followSymlinks" in expected:
+        assert is_bool(actual["followSymlinks"], expected["followSymlinks"])
+
+    if "listDirectories" in expected:
+        assert is_bool(actual["listDirectories"], expected["listDirectories"])
+
+    if "recurse" in expected:
+        assert is_bool(actual["recurse"], expected["recurse"])
+
+    if "relative" in expected:
+        assert matches(actual["relative"], expected["relative"])
+
+    check_list_match(lambda a, e: matches(a, e), actual["paths"], expected["paths"], allow_extra=True)
+
+    assert sorted(actual.keys()) == sorted(expected.keys())
+
 def check_object_cmakeFiles(o):
-    assert sorted(o.keys()) == ["inputs", "kind", "paths", "version"]
+    assert sorted(o.keys()) == ["globsDependent", "inputs", "kind", "paths", "version"]
     # The "kind" and "version" members are handled by check_index_object.
     assert is_dict(o["paths"])
     assert sorted(o["paths"].keys()) == ["build", "source"]
@@ -82,12 +101,33 @@ def check_object_cmakeFiles(o):
         },
     ]
 
+    expected_globs = [
+        {
+            "expression": "^.*/Tests/RunCMake/FileAPI/dir/\\*$",
+            "paths": [
+                "^.*/Tests/RunCMake/FileAPI/dir/dir$",
+                "^.*/Tests/RunCMake/FileAPI/dir/dirtest\\.cmake$"
+            ],
+            "listDirectories": True,
+        },
+        {
+            "expression": "^.*/Tests/RunCMake/FileAPI/dir/\\*\\.cmake$",
+            "paths": [
+                "^dir/dirtest\\.cmake$"
+            ],
+            "followSymlinks": True,
+            "recurse": True,
+            "relative": "^.*/Tests/RunCMake/FileAPI$"
+        }
+    ]
+
     inSource = os.path.dirname(o["paths"]["build"]) == o["paths"]["source"]
     if inSource:
         for e in expected:
             e["path"] = e["path"].replace("^.*/Tests/RunCMake/FileAPI/", "^", 1)
 
     check_list_match(lambda a, e: matches(a["path"], e["path"]), o["inputs"], expected, check=check_input, allow_extra=True)
+    check_list_match(lambda a, e: matches(a["expression"], e["expression"]), o["globsDependent"], expected_globs, check=check_glob_dependent, allow_extra=True)
 
 assert is_dict(index)
 assert sorted(index.keys()) == ["cmake", "objects", "reply"]

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

@@ -5,4 +5,14 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/generated.cmake" "")
 include("${CMAKE_CURRENT_BINARY_DIR}/generated.cmake")
 include("${CMAKE_CURRENT_LIST_DIR}/../FileAPIDummyFile.cmake")
 
+file(GLOB var
+  CONFIGURE_DEPENDS
+  "${CMAKE_CURRENT_SOURCE_DIR}/dir/*")
+
+file(GLOB_RECURSE var
+  FOLLOW_SYMLINKS
+  RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
+  CONFIGURE_DEPENDS
+  "${CMAKE_CURRENT_SOURCE_DIR}/dir/*.cmake")
+
 add_subdirectory(dir)