fileapi: Add CONFIGURE_DEPENDS glob info to cmakeFiles object

Fixes: #25668
Co-authored-by: Brad King <brad.king@kitware.com>
This commit is contained in:
Arctic Lampyrid 2024-03-19 11:45:58 +08:00 committed by Brad King
parent f578515d02
commit 6116bcb066
13 changed files with 182 additions and 5 deletions

View File

@ -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"
------------------------

View File

@ -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``.

View File

@ -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)

View File

@ -31,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);
@ -53,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;
}
@ -108,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)

View File

@ -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();

View File

@ -33,6 +33,9 @@ protected:
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();

View File

@ -248,6 +248,11 @@ void cmState::AddGlobCacheEntry(const cmGlobCacheEntry& entry,
messenger);
}
std::vector<cmGlobCacheEntry> cmState::GetGlobCacheEntries() const
{
return this->GlobVerificationManager->GetCacheEntries();
}
void cmState::RemoveCacheEntry(std::string const& key)
{
this->CacheManager->RemoveCacheEntry(key);

View File

@ -268,6 +268,7 @@ private:
const std::string& variable,
cmListFileBacktrace const& bt,
cmMessenger* messenger);
std::vector<cmGlobCacheEntry> GetGlobCacheEntries() const;
cmPropertyDefinitionMap PropertyDefinitions;
std::vector<std::string> EnabledLanguages;

View File

@ -2958,6 +2958,11 @@ void cmake::AddGlobCacheEntry(const cmGlobCacheEntry& entry,
this->Messenger.get());
}
std::vector<cmGlobCacheEntry> cmake::GetGlobCacheEntries() const
{
return this->State->GetGlobCacheEntries();
}
std::vector<std::string> cmake::GetAllExtensions() const
{
std::vector<std::string> allExt = this->CLikeSourceFileExtensions.ordered;

View File

@ -355,6 +355,7 @@ public:
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

View File

@ -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":{.*}}$

View File

@ -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"]

View File

@ -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)