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