mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-01 20:00:51 -05:00
Merge topic 'link-deduplicate-libs'
7b99c42e57Link step: Enable to configure deduplication of libraries07501c1678Link Step: Introduce EntriesProcessing class Acked-by: Kitware Robot <kwrobot@kitware.com> Tested-by: buildbot <buildbot@kitware.com> Acked-by: scivision <michael@scivision.dev> Merge-request: !8946
This commit is contained in:
+209
-43
@@ -16,6 +16,8 @@
|
||||
#include <cm/string_view>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmsys/RegularExpression.hxx"
|
||||
|
||||
#include "cmComputeComponentGraph.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmGeneratorExpressionDAGChecker.h"
|
||||
@@ -26,6 +28,7 @@
|
||||
#include "cmLocalGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmPolicies.h"
|
||||
#include "cmRange.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmStateTypes.h"
|
||||
@@ -232,6 +235,204 @@ 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(const cmGeneratorTarget* target,
|
||||
const std::string& linkLanguage, EntryVector& entries,
|
||||
EntryVector& finalEntries)
|
||||
: Entries(entries)
|
||||
, FinalEntries(finalEntries)
|
||||
{
|
||||
const auto* makefile = target->Makefile;
|
||||
|
||||
switch (target->GetPolicyStatusCMP0156()) {
|
||||
case cmPolicies::WARN:
|
||||
if (!makefile->GetCMakeInstance()->GetIsInTryCompile() &&
|
||||
makefile->PolicyOptionalWarningEnabled(
|
||||
"CMAKE_POLICY_WARNING_CMP0156")) {
|
||||
makefile->GetCMakeInstance()->IssueMessage(
|
||||
MessageType::AUTHOR_WARNING,
|
||||
cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0156),
|
||||
"\nSince the policy is not set, legacy libraries "
|
||||
"de-duplication strategy will be applied."),
|
||||
target->GetBacktrace());
|
||||
}
|
||||
CM_FALLTHROUGH;
|
||||
case cmPolicies::OLD:
|
||||
// rely on default initialization of the class
|
||||
break;
|
||||
case cmPolicies::REQUIRED_IF_USED:
|
||||
case cmPolicies::REQUIRED_ALWAYS:
|
||||
makefile->GetCMakeInstance()->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0156),
|
||||
target->GetBacktrace());
|
||||
CM_FALLTHROUGH;
|
||||
case cmPolicies::NEW: {
|
||||
if (auto libProcessing = makefile->GetDefinition(cmStrCat(
|
||||
"CMAKE_", linkLanguage, "_LINK_LIBRARIES_PROCESSING"))) {
|
||||
cmsys::RegularExpression processingOption{
|
||||
"^(ORDER|UNICITY)=(FORWARD|REVERSE|ALL|NONE|SHARED)$"
|
||||
};
|
||||
std::string errorMessage;
|
||||
for (auto const& option : cmList{ libProcessing }) {
|
||||
if (processingOption.find(option)) {
|
||||
if (processingOption.match(1) == "ORDER") {
|
||||
if (processingOption.match(2) == "FORWARD") {
|
||||
this->Order = Forward;
|
||||
} else if (processingOption.match(2) == "REVERSE") {
|
||||
this->Order = Reverse;
|
||||
} else {
|
||||
errorMessage += cmStrCat(" ", option, '\n');
|
||||
}
|
||||
} else if (processingOption.match(1) == "UNICITY") {
|
||||
if (processingOption.match(2) == "ALL") {
|
||||
this->Unicity = All;
|
||||
} else if (processingOption.match(2) == "NONE") {
|
||||
this->Unicity = None;
|
||||
} else if (processingOption.match(2) == "SHARED") {
|
||||
this->Unicity = Shared;
|
||||
} else {
|
||||
errorMessage += cmStrCat(" ", option, '\n');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errorMessage += cmStrCat(" ", option, '\n');
|
||||
}
|
||||
}
|
||||
if (!errorMessage.empty()) {
|
||||
makefile->GetCMakeInstance()->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("Erroneous option(s) for 'CMAKE_", linkLanguage,
|
||||
"_LINK_LIBRARIES_PROCESSING':\n", errorMessage),
|
||||
target->GetBacktrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 +581,14 @@ 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->Target, this->LinkLanguage,
|
||||
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) {
|
||||
|
||||
+7
-2
@@ -473,7 +473,11 @@ class cmMakefile;
|
||||
SELECT(POLICY, CMP0155, \
|
||||
"C++ sources in targets with at least C++20 are scanned for " \
|
||||
"imports when supported.", \
|
||||
3, 28, 0, cmPolicies::WARN)
|
||||
3, 28, 0, cmPolicies::WARN) \
|
||||
SELECT( \
|
||||
POLICY, CMP0156, \
|
||||
"De-duplicate libraries on link lines based on linker capabilities.", 3, \
|
||||
29, 0, cmPolicies::WARN)
|
||||
|
||||
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
|
||||
#define CM_FOR_EACH_POLICY_ID(POLICY) \
|
||||
@@ -513,7 +517,8 @@ class cmMakefile;
|
||||
F(CMP0131) \
|
||||
F(CMP0142) \
|
||||
F(CMP0154) \
|
||||
F(CMP0155)
|
||||
F(CMP0155) \
|
||||
F(CMP0156)
|
||||
|
||||
#define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) \
|
||||
F(CMP0116) \
|
||||
|
||||
Reference in New Issue
Block a user