get_filename_component: Cache the actual case of path components

get_filename_component(ABSOLUTE|REALPATH) queried the disk for the
actual case of every path component on every call.  Remember the actual
case of components found to exist until files may have been removed or
renamed, as for source file lookups.
This commit is contained in:
Cristian Adam committed 2026-10-14 07:33:47 +02:00
1 parent 6591abb0b2
commit ae0dc8ab9f
5 files changed
+50 -11

No files matched your search

+3 -1
View File
@@ -8,6 +8,7 @@
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"
#include "cmake.h"
// cmGetFilenameComponentCommand
bool cmGetFilenameComponentCommand(std::vector<std::string> const& args,
@@ -113,7 +114,8 @@ bool cmGetFilenameComponentCommand(std::vector<std::string> const& args,
// Resolve symlinks if possible
result = cmSystemTools::GetRealPath(result);
}
result = cmSystemTools::GetActualCaseForPath(result);
result = cmSystemTools::GetActualCaseForPath(
result, status.GetMakefile().GetCMakeInstance()->GetActualCaseCache());
} else {
std::string err = "unknown component " + args[2];
status.SetError(err);
+28 -9
View File
@@ -2047,7 +2047,8 @@ std::string cmSystemTools::RelativeIfUnder(std::string const& top,
return out;
}
std::string cmSystemTools::GetActualCaseForPath(std::string const& p)
std::string cmSystemTools::GetActualCaseForPath(
std::string const& p, std::unordered_map<std::string, std::string>* cache)
{
#ifdef _WIN32
std::string casePath;
@@ -2101,15 +2102,32 @@ std::string cmSystemTools::GetActualCaseForPath(std::string const& p)
std::string test_str = casePath;
test_str += path_components[idx];
WIN32_FIND_DATAW findData;
HANDLE hFind = ::FindFirstFileW(
cmsys::Encoding::ToWide(test_str).c_str(), &findData);
if (INVALID_HANDLE_VALUE != hFind) {
auto case_file_name = cmsys::Encoding::ToNarrow(findData.cFileName);
path_components[idx] = std::move(case_file_name);
::FindClose(hFind);
// Only components found to exist are cached, so that a path
// created later is still converted.
std::string const* cached = nullptr;
if (cache) {
auto it = cache->find(test_str);
if (it != cache->end()) {
cached = &it->second;
}
}
if (cached) {
path_components[idx] = *cached;
} else {
converting = false;
WIN32_FIND_DATAW findData;
HANDLE hFind = ::FindFirstFileW(
cmsys::Encoding::ToWide(test_str).c_str(), &findData);
if (INVALID_HANDLE_VALUE != hFind) {
auto case_file_name =
cmsys::Encoding::ToNarrow(findData.cFileName);
::FindClose(hFind);
if (cache) {
cache->emplace(std::move(test_str), case_file_name);
}
path_components[idx] = std::move(case_file_name);
} else {
converting = false;
}
}
}
}
@@ -2118,6 +2136,7 @@ std::string cmSystemTools::GetActualCaseForPath(std::string const& p)
}
return casePath;
#else
static_cast<void>(cache);
return p;
#endif
}
+10 -1
View File
@@ -11,6 +11,7 @@
#include <cstddef>
#include <functional>
#include <string>
#include <unordered_map>
#include <vector>
#include <cm/optional>
@@ -433,7 +434,15 @@ public:
static std::string RelativeIfUnder(std::string const& top,
std::string const& in);
static std::string GetActualCaseForPath(std::string const& p);
/**
* Get the path with the actual case of all existing components on disk.
* If a cache is given, it is used to remember the actual case of
* components found to exist, to avoid querying the disk again for
* paths sharing the same directories.
*/
static std::string GetActualCaseForPath(
std::string const& p,
std::unordered_map<std::string, std::string>* cache = nullptr);
static cm::optional<std::string> GetEnvVar(std::string const& var);
static std::vector<std::string> GetEnvPathNormalized(std::string const& var);
+1
View File
@@ -2577,6 +2577,7 @@ int cmake::Configure()
void cmake::InvalidateFileSystemCaches()
{
this->ActualCaseCache.clear();
if (this->GlobalGenerator) {
this->GlobalGenerator->ClearSourceFileExistsCache();
}
+8
View File
@@ -11,6 +11,7 @@
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
@@ -476,6 +477,12 @@ public:
return *this->GeneratorExpressionParseCache;
}
//! Cache for cmSystemTools::GetActualCaseForPath.
std::unordered_map<std::string, std::string>* GetActualCaseCache()
{
return &this->ActualCaseCache;
}
//! Forget what is known about the file system, e.g. after files may
//! have been removed or renamed.
void InvalidateFileSystemCaches();
@@ -830,6 +837,7 @@ private:
std::unique_ptr<cmFileTimeCache> FileTimeCache;
std::unique_ptr<cmGeneratorExpressionParseCache>
GeneratorExpressionParseCache;
std::unordered_map<std::string, std::string> ActualCaseCache;
std::string GraphVizFile;
InstalledFilesMap InstalledFiles;
#ifndef CMAKE_BOOTSTRAP