Link Step: Introduce EntriesProcessing class

This refactoring is done in preparation of the possibility to configure
the deduplication of the libraries as well as the order on the link command.
This commit is contained in:
Marc Chevrier
2023-11-07 08:38:31 +01:00
parent d6b796854b
commit 07501c1678

View File

@@ -232,6 +232,135 @@ bool IsGroupFeatureSupported(cmMakefile* makefile,
cmStrCat("CMAKE_LINK_GROUP_USING_", feature, "_SUPPORTED");
return makefile->GetDefinition(featureSupported).IsOn();
}
class EntriesProcessing
{
public:
using LinkEntry = cmComputeLinkDepends::LinkEntry;
using EntryVector = cmComputeLinkDepends::EntryVector;
EntriesProcessing(EntryVector& entries, EntryVector& finalEntries)
: Entries(entries)
, FinalEntries(finalEntries)
{
}
void AddGroups(const std::map<size_t, std::vector<size_t>>& groups)
{
if (!groups.empty()) {
this->Groups = &groups;
// record all libraries as part of groups to ensure correct
// deduplication: libraries as part of groups are always kept.
for (const auto& group : groups) {
for (auto index : group.second) {
this->Emitted.insert(index);
}
}
}
}
void AddLibraries(const std::vector<size_t>& libEntries)
{
if (this->Order == Reverse) {
// Iterate in reverse order so we can keep only the last occurrence
// of a library.
this->AddLibraries(cmReverseRange(libEntries));
} else {
this->AddLibraries(cmMakeRange(libEntries));
}
}
void AddObjects(const std::vector<size_t>& objectEntries)
{
// Place explicitly linked object files in the front. The linker will
// always use them anyway, and they may depend on symbols from libraries.
if (this->Order == Reverse) {
// Append in reverse order at the end since we reverse the final order.
for (auto index : cmReverseRange(objectEntries)) {
this->FinalEntries.emplace_back(this->Entries[index]);
}
} else {
// Append in reverse order to ensure correct final order
for (auto index : cmReverseRange(objectEntries)) {
this->FinalEntries.emplace(this->FinalEntries.begin(),
this->Entries[index]);
}
}
}
void Finalize()
{
if (this->Order == Reverse) {
// Reverse the resulting order since we iterated in reverse.
std::reverse(this->FinalEntries.begin(), this->FinalEntries.end());
}
// expand groups
if (this->Groups != nullptr) {
for (const auto& group : *this->Groups) {
const LinkEntry& groupEntry = this->Entries[group.first];
auto it = this->FinalEntries.begin();
while (true) {
it = std::find_if(it, this->FinalEntries.end(),
[&groupEntry](const LinkEntry& entry) -> bool {
return groupEntry.Item == entry.Item;
});
if (it == this->FinalEntries.end()) {
break;
}
it->Item.Value = "</LINK_GROUP>";
for (auto index = group.second.rbegin();
index != group.second.rend(); ++index) {
it = this->FinalEntries.insert(it, this->Entries[*index]);
}
it = this->FinalEntries.insert(it, groupEntry);
it->Item.Value = "<LINK_GROUP>";
}
}
}
}
private:
enum OrderKind
{
Forward,
Reverse
};
enum UnicityKind
{
None,
Shared,
All
};
bool IncludeEntry(LinkEntry const& entry) const
{
return this->Unicity == None ||
(this->Unicity == Shared &&
(entry.Target == nullptr ||
entry.Target->GetType() != cmStateEnums::SHARED_LIBRARY)) ||
(this->Unicity == All && entry.Kind != LinkEntry::Library);
}
template <typename Range>
void AddLibraries(const Range& libEntries)
{
for (auto index : libEntries) {
LinkEntry const& entry = this->Entries[index];
if (this->IncludeEntry(entry) || this->Emitted.insert(index).second) {
this->FinalEntries.emplace_back(entry);
}
}
}
OrderKind Order = Reverse;
UnicityKind Unicity = Shared;
EntryVector& Entries;
EntryVector& FinalEntries;
std::set<size_t> Emitted;
const std::map<size_t, std::vector<size_t>>* Groups = nullptr;
};
}
const std::string cmComputeLinkDepends::LinkEntry::DEFAULT = "DEFAULT";
@@ -380,49 +509,13 @@ cmComputeLinkDepends::Compute()
this->OrderLinkEntries();
// Compute the final set of link entries.
// Iterate in reverse order so we can keep only the last occurrence
// of a shared library.
std::set<size_t> emitted;
for (size_t i : cmReverseRange(this->FinalLinkOrder)) {
LinkEntry const& e = this->EntryList[i];
cmGeneratorTarget const* t = e.Target;
// Entries that we know the linker will re-use do not need to be repeated.
bool uniquify = t && t->GetType() == cmStateEnums::SHARED_LIBRARY;
if (!uniquify || emitted.insert(i).second) {
this->FinalLinkEntries.push_back(e);
}
}
// Place explicitly linked object files in the front. The linker will
// always use them anyway, and they may depend on symbols from libraries.
// Append in reverse order since we reverse the final order below.
for (size_t i : cmReverseRange(this->ObjectEntries)) {
this->FinalLinkEntries.emplace_back(this->EntryList[i]);
}
// Reverse the resulting order since we iterated in reverse.
std::reverse(this->FinalLinkEntries.begin(), this->FinalLinkEntries.end());
// Expand group items
if (!this->GroupItems.empty()) {
for (const auto& group : this->GroupItems) {
const LinkEntry& groupEntry = this->EntryList[group.first];
auto it = this->FinalLinkEntries.begin();
while (true) {
it = std::find_if(it, this->FinalLinkEntries.end(),
[&groupEntry](const LinkEntry& entry) -> bool {
return groupEntry.Item == entry.Item;
});
if (it == this->FinalLinkEntries.end()) {
break;
}
it->Item.Value = "</LINK_GROUP>";
for (auto i = group.second.rbegin(); i != group.second.rend(); ++i) {
it = this->FinalLinkEntries.insert(it, this->EntryList[*i]);
}
it = this->FinalLinkEntries.insert(it, groupEntry);
it->Item.Value = "<LINK_GROUP>";
}
}
}
EntriesProcessing entriesProcessing{ this->EntryList,
this->FinalLinkEntries };
// Add groups first, to ensure that libraries of the groups are always kept.
entriesProcessing.AddGroups(this->GroupItems);
entriesProcessing.AddLibraries(this->FinalLinkOrder);
entriesProcessing.AddObjects(this->ObjectEntries);
entriesProcessing.Finalize();
// Display the final set.
if (this->DebugMode) {