cmLocalGenerator: Improve performance of source group lookups

Introduce an index from source file to source group in
`cmLocalGenerator` to make lookups significantly more efficient
during the source group generation, which could be particularly
slow when dealing with thousands of source files.
Falls back to the recursive lookup when the source file is not present
on the index, which is more likely to happen when dealing with
regex-based sources.

Fixes: #27359
This commit is contained in:
Cristiano Carvalheiro committed 2025-11-26 20:32:19 +00:00
1 parent caf6e782e1
commit a46491d0d3
13 files changed
+141 -93

No files matched your search

+6 -8
View File
@@ -461,21 +461,21 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile()
}
void cmExtraEclipseCDT4Generator::WriteGroups(
std::vector<cmSourceGroup> const& sourceGroups, std::string& linkName,
SourceGroupVector const& sourceGroups, std::string& linkName,
cmXMLWriter& xml)
{
for (cmSourceGroup const& sg : sourceGroups) {
std::string linkName3 = cmStrCat(linkName, '/', sg.GetFullName());
for (auto const& sg : sourceGroups) {
std::string linkName3 = cmStrCat(linkName, '/', sg->GetFullName());
std::replace(linkName3.begin(), linkName3.end(), '\\', '/');
cmExtraEclipseCDT4Generator::AppendLinkedResource(
xml, linkName3, "virtual:/virtual", VirtualFolder);
std::vector<cmSourceGroup> const& children = sg.GetGroupChildren();
SourceGroupVector const& children = sg->GetGroupChildren();
if (!children.empty()) {
this->WriteGroups(children, linkName, xml);
}
std::vector<cmSourceFile const*> sFiles = sg.GetSourceFiles();
std::vector<cmSourceFile const*> sFiles = sg->GetSourceFiles();
for (cmSourceFile const* file : sFiles) {
std::string const& fullPath = file->GetFullPath();
@@ -529,9 +529,7 @@ void cmExtraEclipseCDT4Generator::CreateLinksForTargets(cmXMLWriter& xml)
sourceGroup->AssignSource(sf);
}
std::vector<cmSourceGroup> sourceGroups =
makefile->GetSourceGroups();
this->WriteGroups(sourceGroups, linkName2, xml);
this->WriteGroups(makefile->GetSourceGroups(), linkName2, xml);
} break;
// ignore all others:
default:
+2 -2
View File
@@ -10,10 +10,10 @@
#include <vector>
#include "cmExternalMakefileProjectGenerator.h"
#include "cmSourceGroup.h"
class cmLocalGenerator;
class cmMakefile;
class cmSourceGroup;
class cmXMLWriter;
/** \class cmExtraEclipseCDT4Generator
@@ -87,7 +87,7 @@ private:
static void AddEnvVar(std::ostream& out, char const* envVar,
cmLocalGenerator& lg);
void WriteGroups(std::vector<cmSourceGroup> const& sourceGroups,
void WriteGroups(SourceGroupVector const& sourceGroups,
std::string& linkName, cmXMLWriter& xml);
void CreateLinksToSubprojects(cmXMLWriter& xml, std::string const& baseDir);
void CreateLinksForTargets(cmXMLWriter& xml);
+1 -1
View File
@@ -122,7 +122,7 @@ void addFileSetEntry(cmGeneratorTarget const* headTarget,
}
bool found = false;
for (auto const& sg : headTarget->Makefile->GetSourceGroups()) {
if (sg.MatchChildrenFiles(path)) {
if (sg->MatchChildrenFiles(path)) {
found = true;
break;
}
+1
View File
@@ -1615,6 +1615,7 @@ bool cmGlobalGenerator::Compute()
for (auto const& localGen : this->LocalGenerators) {
localGen->ComputeHomeRelativeOutputPath();
localGen->ComputeSourceGroupSearchIndex();
}
return true;
+46 -4
View File
@@ -10,6 +10,7 @@
#include <cstdlib>
#include <initializer_list>
#include <iterator>
#include <queue>
#include <sstream>
#include <unordered_set>
#include <utility>
@@ -4104,11 +4105,52 @@ std::string cmLocalGenerator::CreateSafeObjectFileName(
return ssin;
}
cmSourceGroup* cmLocalGenerator::FindSourceGroup(
std::string const& source) const
void cmLocalGenerator::ComputeSourceGroupSearchIndex()
{
return cmSourceGroup::FindSourceGroup(source,
this->Makefile->GetSourceGroups());
#if !defined(CMAKE_BOOTSTRAP)
SourceGroupVector const& sourceGroups = this->Makefile->GetSourceGroups();
// Build lookup index from sources to source groups
std::queue<cmSourceGroup*> sgToVisit;
for (auto const& group : sourceGroups) {
cmSourceGroup* cmSourceGroup = group.get();
sgToVisit.emplace(cmSourceGroup);
}
while (!sgToVisit.empty()) {
cmSourceGroup* sourceGroup = sgToVisit.front();
sgToVisit.pop();
for (auto const& sgChild : sourceGroup->GetGroupChildren()) {
sgToVisit.emplace(sgChild.get());
}
for (std::string const& source : sourceGroup->GetGroupFiles()) {
this->SourceGroupSearchIndex.emplace(source, sourceGroup);
}
}
#endif
}
cmSourceGroup* cmLocalGenerator::FindSourceGroup(std::string const& source)
{
#if !defined(CMAKE_BOOTSTRAP)
auto const indexIt = SourceGroupSearchIndex.find(source);
if (indexIt != SourceGroupSearchIndex.cend()) {
if (cmSourceGroup* result = indexIt->second) {
return result;
}
}
cmSourceGroup* sourceGroup =
cmSourceGroup::FindSourceGroup(source, this->Makefile->GetSourceGroups());
if (sourceGroup) {
// Update index if we have a miss
SourceGroupSearchIndex.emplace(source, sourceGroup);
}
return sourceGroup;
#else
static_cast<void>(source);
return nullptr;
#endif
}
std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(
+12 -1
View File
@@ -574,10 +574,15 @@ public:
std::string CreateSafeObjectFileName(std::string const& sin) const;
/**
* Build the search index from source files to source groups
*/
void ComputeSourceGroupSearchIndex();
/**
* find what source group this source is in
*/
cmSourceGroup* FindSourceGroup(std::string const& source) const;
cmSourceGroup* FindSourceGroup(std::string const& source);
protected:
// The default implementation converts to a Windows shortpath to
@@ -637,6 +642,12 @@ protected:
bool EmitUniversalBinaryFlags;
#if !defined(CMAKE_BOOTSTRAP)
// Map from source file path to source group for lookup acceleration
using SourceGroupMap = std::unordered_map<std::string, cmSourceGroup*>;
SourceGroupMap SourceGroupSearchIndex;
#endif
private:
/**
* See LinearGetSourceFileWithOutput for background information
+5 -4
View File
@@ -1459,9 +1459,9 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
fout << "\t<Files>\n";
// Loop through every source group.
std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
SourceGroupVector const& sourceGroups = this->Makefile->GetSourceGroups();
for (auto const& sg : sourceGroups) {
this->WriteGroup(&sg, target, fout, libName, configs, sources);
this->WriteGroup(sg.get(), target, fout, libName, configs, sources);
}
fout << "\t</Files>\n";
@@ -1676,13 +1676,14 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
cmGlobalVisualStudio7Generator* gg =
static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
std::vector<cmSourceFile const*> const& sourceFiles = sg->GetSourceFiles();
std::vector<cmSourceGroup> const& children = sg->GetGroupChildren();
SourceGroupVector const& children = sg->GetGroupChildren();
// Write the children to temporary output.
bool hasChildrenWithSources = false;
std::ostringstream tmpOut;
for (auto const& child : children) {
if (this->WriteGroup(&child, target, tmpOut, libName, configs, sources)) {
if (this->WriteGroup(child.get(), target, tmpOut, libName, configs,
sources)) {
hasChildrenWithSources = true;
}
}
+12 -9
View File
@@ -195,7 +195,8 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size();
this->SourceGroups.emplace_back("Object Libraries", "^MATCH_NO_SOURCES$");
this->SourceGroups.emplace_back(
cm::make_unique<cmSourceGroup>("Object Libraries", "^MATCH_NO_SOURCES$"));
#endif
}
@@ -2085,8 +2086,8 @@ namespace {
void cmMakefile::ResolveSourceGroupGenex(cmLocalGenerator* lg)
{
for (cmSourceGroup& sourceGroup : this->SourceGroups) {
sourceGroup.ResolveGenex(lg, {});
for (auto const& sourceGroup : this->SourceGroups) {
sourceGroup->ResolveGenex(lg, {});
}
}
@@ -2096,10 +2097,10 @@ cmSourceGroup* cmMakefile::GetSourceGroup(
cmSourceGroup* sg = nullptr;
// first look for source group starting with the same as the one we want
for (cmSourceGroup const& srcGroup : this->SourceGroups) {
std::string const& sgName = srcGroup.GetName();
for (auto const& srcGroup : this->SourceGroups) {
std::string const& sgName = srcGroup->GetName();
if (sgName == name[0]) {
sg = const_cast<cmSourceGroup*>(&srcGroup);
sg = srcGroup.get();
break;
}
}
@@ -2151,7 +2152,8 @@ void cmMakefile::AddSourceGroup(std::vector<std::string> const& name,
if (i == -1) {
// group does not exist nor belong to any existing group
// add its first component
this->SourceGroups.emplace_back(name[0], regex);
this->SourceGroups.emplace_back(
cm::make_unique<cmSourceGroup>(name[0], regex));
sg = this->GetSourceGroup(currentName);
i = 0; // last component found
}
@@ -2161,7 +2163,8 @@ void cmMakefile::AddSourceGroup(std::vector<std::string> const& name,
}
// build the whole source group path
for (++i; i <= lastElement; ++i) {
sg->AddChild(cmSourceGroup(name[i], nullptr, sg->GetFullName().c_str()));
sg->AddChild(cm::make_unique<cmSourceGroup>(name[i], nullptr,
sg->GetFullName().c_str()));
sg = sg->LookupChild(name[i]);
}
@@ -3134,7 +3137,7 @@ void cmMakefile::AddTargetObject(std::string const& tgtName,
// file that compiles to it. Needs a policy as it likely affects link
// language selection if done unconditionally.
#if !defined(CMAKE_BOOTSTRAP)
this->SourceGroups[this->ObjectLibrariesSourceGroupIndex].AddGroupFile(
this->SourceGroups[this->ObjectLibrariesSourceGroupIndex]->AddGroupFile(
sf->ResolveFullPath());
#endif
}
+6 -6
View File
@@ -40,6 +40,10 @@
// will not compile without the complete type.
#include "cmTarget.h" // IWYU pragma: keep
#if !defined(CMAKE_BOOTSTRAP)
# include "cmSourceGroup.h"
#endif
enum class cmCustomCommandType;
enum class cmObjectLibraryCommands;
@@ -60,10 +64,6 @@ class cmTestGenerator;
class cmVariableWatch;
class cmake;
#if !defined(CMAKE_BOOTSTRAP)
class cmSourceGroup;
#endif
/** A type-safe wrapper for a string representing a directory id. */
class cmDirectoryId
{
@@ -621,7 +621,7 @@ public:
/**
* Get the vector source groups.
*/
std::vector<cmSourceGroup> const& GetSourceGroups() const
SourceGroupVector const& GetSourceGroups() const
{
return this->SourceGroups;
}
@@ -1131,7 +1131,7 @@ protected:
std::string DefineFlags;
#if !defined(CMAKE_BOOTSTRAP)
std::vector<cmSourceGroup> SourceGroups;
SourceGroupVector SourceGroups;
size_t ObjectLibrariesSourceGroupIndex;
#endif
+27 -44
View File
@@ -13,7 +13,7 @@
class cmSourceGroupInternals
{
public:
std::vector<cmSourceGroup> GroupChildren;
SourceGroupVector GroupChildren;
};
cmSourceGroup::cmSourceGroup(std::string name, char const* regex,
@@ -30,28 +30,6 @@ cmSourceGroup::cmSourceGroup(std::string name, char const* regex,
cmSourceGroup::~cmSourceGroup() = default;
cmSourceGroup::cmSourceGroup(cmSourceGroup const& r)
{
this->Name = r.Name;
this->FullName = r.FullName;
this->GroupRegex = r.GroupRegex;
this->GroupFiles = r.GroupFiles;
this->SourceFiles = r.SourceFiles;
this->Internal = cm::make_unique<cmSourceGroupInternals>(*r.Internal);
}
cmSourceGroup& cmSourceGroup::operator=(cmSourceGroup const& r)
{
if (this != &r) {
this->Name = r.Name;
this->GroupRegex = r.GroupRegex;
this->GroupFiles = r.GroupFiles;
this->SourceFiles = r.SourceFiles;
*(this->Internal) = *(r.Internal);
}
return *this;
}
void cmSourceGroup::SetGroupRegex(char const* regex)
{
if (regex) {
@@ -76,8 +54,8 @@ void cmSourceGroup::ResolveGenex(cmLocalGenerator* lg,
return;
}
for (cmSourceGroup& group : this->Internal->GroupChildren) {
group.ResolveGenex(lg, config);
for (auto const& group : this->Internal->GroupChildren) {
group->ResolveGenex(lg, config);
}
}
@@ -112,22 +90,27 @@ void cmSourceGroup::AssignSource(cmSourceFile const* sf)
this->SourceFiles.push_back(sf);
}
std::set<std::string> const& cmSourceGroup::GetGroupFiles() const
{
return this->GroupFiles;
}
std::vector<cmSourceFile const*> const& cmSourceGroup::GetSourceFiles() const
{
return this->SourceFiles;
}
void cmSourceGroup::AddChild(cmSourceGroup const& child)
void cmSourceGroup::AddChild(std::unique_ptr<cmSourceGroup> child)
{
this->Internal->GroupChildren.push_back(child);
this->Internal->GroupChildren.push_back(std::move(child));
}
cmSourceGroup* cmSourceGroup::LookupChild(std::string const& name) const
{
for (cmSourceGroup& group : this->Internal->GroupChildren) {
for (auto& group : this->Internal->GroupChildren) {
// look if descendant is the one we're looking for
if (group.GetName() == name) {
return (&group); // if so return it
if (group->GetName() == name) {
return group.get(); // if so return it
}
}
@@ -140,8 +123,8 @@ cmSourceGroup* cmSourceGroup::MatchChildrenFiles(std::string const& name)
if (this->MatchesFiles(name)) {
return this;
}
for (cmSourceGroup& group : this->Internal->GroupChildren) {
cmSourceGroup* result = group.MatchChildrenFiles(name);
for (auto& group : this->Internal->GroupChildren) {
cmSourceGroup* result = group->MatchChildrenFiles(name);
if (result) {
return result;
}
@@ -155,8 +138,8 @@ cmSourceGroup const* cmSourceGroup::MatchChildrenFiles(
if (this->MatchesFiles(name)) {
return this;
}
for (cmSourceGroup const& group : this->Internal->GroupChildren) {
cmSourceGroup const* result = group.MatchChildrenFiles(name);
for (auto const& group : this->Internal->GroupChildren) {
cmSourceGroup const* result = group->MatchChildrenFiles(name);
if (result) {
return result;
}
@@ -166,8 +149,8 @@ cmSourceGroup const* cmSourceGroup::MatchChildrenFiles(
cmSourceGroup* cmSourceGroup::MatchChildrenRegex(std::string const& name) const
{
for (cmSourceGroup& group : this->Internal->GroupChildren) {
cmSourceGroup* result = group.MatchChildrenRegex(name);
for (auto& group : this->Internal->GroupChildren) {
cmSourceGroup* result = group->MatchChildrenRegex(name);
if (result) {
return result;
}
@@ -179,7 +162,7 @@ cmSourceGroup* cmSourceGroup::MatchChildrenRegex(std::string const& name) const
return nullptr;
}
std::vector<cmSourceGroup> const& cmSourceGroup::GetGroupChildren() const
SourceGroupVector const& cmSourceGroup::GetGroupChildren() const
{
return this->Internal->GroupChildren;
}
@@ -191,25 +174,25 @@ std::vector<cmSourceGroup> const& cmSourceGroup::GetGroupChildren() const
* non-inherited SOURCE_GROUP commands will have precedence over
* inherited ones.
*/
cmSourceGroup* cmSourceGroup::FindSourceGroup(
std::string const& source, std::vector<cmSourceGroup> const& groups)
cmSourceGroup* cmSourceGroup::FindSourceGroup(std::string const& source,
SourceGroupVector const& groups)
{
// First search for a group that lists the file explicitly.
for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
cmSourceGroup const* result = sg->MatchChildrenFiles(source);
cmSourceGroup* result = (*sg)->MatchChildrenFiles(source);
if (result) {
return const_cast<cmSourceGroup*>(result);
return result;
}
}
// Now search for a group whose regex matches the file.
for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
cmSourceGroup const* result = sg->MatchChildrenRegex(source);
cmSourceGroup* result = (*sg)->MatchChildrenRegex(source);
if (result) {
return const_cast<cmSourceGroup*>(result);
return result;
}
}
// Shouldn't get here, but just in case, return the default group.
return const_cast<cmSourceGroup*>(groups.data());
return groups.data()->get();
}
+14 -6
View File
@@ -13,8 +13,11 @@
class cmLocalGenerator;
class cmSourceFile;
class cmSourceGroup;
class cmSourceGroupInternals;
using SourceGroupVector = std::vector<std::unique_ptr<cmSourceGroup>>;
/** \class cmSourceGroup
* \brief Hold a group of sources as specified by a SOURCE_GROUP command.
*
@@ -30,9 +33,9 @@ class cmSourceGroup
public:
cmSourceGroup(std::string name, char const* regex,
char const* parentName = nullptr);
cmSourceGroup(cmSourceGroup const& r);
cmSourceGroup(cmSourceGroup const& r) = delete;
~cmSourceGroup();
cmSourceGroup& operator=(cmSourceGroup const&);
cmSourceGroup& operator=(cmSourceGroup const&) = delete;
/**
* Set the regular expression for this group.
@@ -52,7 +55,7 @@ public:
/**
* Add child to this sourcegroup
*/
void AddChild(cmSourceGroup const& child);
void AddChild(std::unique_ptr<cmSourceGroup> child);
/**
* Looks up child and returns it
@@ -102,19 +105,24 @@ public:
*/
void AssignSource(cmSourceFile const* sf);
/**
* Get the set of file names explicitly added to this source group.
*/
std::set<std::string> const& GetGroupFiles() const;
/**
* Get the list of the source files that have been assigned to this
* source group.
*/
std::vector<cmSourceFile const*> const& GetSourceFiles() const;
std::vector<cmSourceGroup> const& GetGroupChildren() const;
SourceGroupVector const& GetGroupChildren() const;
/**
* Given a source group collection, find the source group for a given source.
*/
static cmSourceGroup* FindSourceGroup(
std::string const& source, std::vector<cmSourceGroup> const& groups);
static cmSourceGroup* FindSourceGroup(std::string const& source,
SourceGroupVector const& groups);
private:
/**
+7 -7
View File
@@ -2125,17 +2125,17 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
// Add to groupsUsed empty source groups that have non-empty children.
void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
std::set<cmSourceGroup const*>& groupsUsed,
std::vector<cmSourceGroup> const& allGroups)
SourceGroupVector const& allGroups)
{
for (cmSourceGroup const& current : allGroups) {
std::vector<cmSourceGroup> const& children = current.GetGroupChildren();
for (auto const& current : allGroups) {
SourceGroupVector const& children = current->GetGroupChildren();
if (children.empty()) {
continue; // the group is really empty
}
this->AddMissingSourceGroups(groupsUsed, children);
if (groupsUsed.count(&current) > 0) {
if (groupsUsed.count(current.get()) > 0) {
continue; // group has already been added to set
}
@@ -2143,17 +2143,17 @@ void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
// (at least one child must already have been added)
auto child_it = children.begin();
while (child_it != children.end()) {
if (groupsUsed.count(&(*child_it)) > 0) {
if (groupsUsed.count(child_it->get()) > 0) {
break; // found a child that was already added => add current group too
}
child_it++;
++child_it;
}
if (child_it == children.end()) {
continue; // no descendants have source files => ignore this group
}
groupsUsed.insert(&current);
groupsUsed.insert(current.get());
}
}
+2 -1
View File
@@ -14,6 +14,7 @@
#include <vector>
#include "cmGeneratorTarget.h"
#include "cmSourceGroup.h"
#include "cmVsProjectType.h"
class cmComputeLinkInformation;
@@ -204,7 +205,7 @@ private:
void WriteGroupSources(Elem& e0, std::string const& name,
ToolSources const& sources);
void AddMissingSourceGroups(std::set<cmSourceGroup const*>& groupsUsed,
std::vector<cmSourceGroup> const& allGroups);
SourceGroupVector const& allGroups);
bool IsResxHeader(std::string const& headerFile);
bool IsXamlHeader(std::string const& headerFile);
bool IsXamlSource(std::string const& headerFile);