From 3ce26c57ba06b5a02e153b8bb16eb8c60938e4ce Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 20 Sep 2024 13:42:57 -0400 Subject: cmMakefileTargetGenerator: Avoid crash on GetLinkInformation failure --- Source/cmMakefileTargetGenerator.cxx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 9ff0a4a..9d0d466 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -2206,13 +2206,14 @@ void cmMakefileTargetGenerator::CreateLinkLibs( bool useResponseFile, std::vector& makefile_depends, std::string const& linkLanguage, ResponseFlagFor responseMode) { - std::string frameworkPath; - std::string linkPath; - cmComputeLinkInformation* pcli = - this->GeneratorTarget->GetLinkInformation(this->GetConfigName()); - this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, - frameworkPath, linkPath); - linkLibs = frameworkPath + linkPath + linkLibs; + if (cmComputeLinkInformation* pcli = + this->GeneratorTarget->GetLinkInformation(this->GetConfigName())) { + std::string frameworkPath; + std::string linkPath; + this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, + frameworkPath, linkPath); + linkLibs = frameworkPath + linkPath + linkLibs; + } if (useResponseFile && linkLibs.find_first_not_of(' ') != std::string::npos) { -- cgit v0.12 From 445a82e5da1ad5d17db7e7c3ed3b1a8b1d629e21 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 17 Sep 2024 13:54:12 -0400 Subject: cmComputeLinkDepends: Shorten local variable name --- Source/cmComputeLinkDepends.cxx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index f12bcdb..1c7b478 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -431,8 +431,8 @@ public: 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) { + for (const auto& g : groups) { + for (auto index : g.second) { this->Emitted.insert(index); } } @@ -477,8 +477,8 @@ public: // expand groups if (this->Groups) { - for (const auto& group : *this->Groups) { - const LinkEntry& groupEntry = this->Entries[group.first]; + for (const auto& g : *this->Groups) { + const LinkEntry& groupEntry = this->Entries[g.first]; auto it = this->FinalEntries.begin(); while (true) { it = std::find_if(it, this->FinalEntries.end(), @@ -489,8 +489,8 @@ public: break; } it->Item.Value = ""; - for (auto index = group.second.rbegin(); - index != group.second.rend(); ++index) { + for (auto index = g.second.rbegin(); index != g.second.rend(); + ++index) { it = this->FinalEntries.insert(it, this->Entries[*index]); } it = this->FinalEntries.insert(it, groupEntry); @@ -1252,10 +1252,10 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, std::vector indexes; bool entryHandled = false; // search any occurrence of the library in already defined groups - for (const auto& group : this->GroupItems) { - for (auto index : group.second) { + for (const auto& g : this->GroupItems) { + for (auto index : g.second) { if (entry.Item.Value == this->EntryList[index].Item.Value) { - indexes.push_back(group.first); + indexes.push_back(g.first); entryHandled = true; break; } -- cgit v0.12 From 80327430adfc9dccf8b0ac4029694135f7cb7be7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 17 Sep 2024 13:54:55 -0400 Subject: cmComputeLinkDepends: Avoid unsigned integer rollover --- Source/cmComputeLinkDepends.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 1c7b478..abdd576 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -1494,9 +1494,8 @@ void cmComputeLinkDepends::OrderLinkEntries() this->ComponentOrderId = n; // Run in reverse order so the topological order will preserve the // original order where there are no constraints. - for (size_t c = n - 1; c != cmComputeComponentGraph::INVALID_COMPONENT; - --c) { - this->VisitComponent(c); + for (size_t c = n; c > 0; --c) { + this->VisitComponent(c - 1); } // Display the component graph. -- cgit v0.12 From 6c9d8dc243be7b55c7bffd1a7a400b3e042ead90 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 17 Sep 2024 13:57:59 -0400 Subject: cmComputeLinkDepends: Replace group index sentinel value with cm::optional --- Source/cmComputeLinkDepends.cxx | 50 ++++++++++++++++++----------------------- Source/cmComputeLinkDepends.h | 11 ++++----- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index abdd576..014d600 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -766,7 +766,7 @@ cmComputeLinkDepends::AllocateLinkEntry(cmLinkItem const& item) } std::pair cmComputeLinkDepends::AddLinkEntry( - cmLinkItem const& item, size_t groupIndex) + cmLinkItem const& item, cm::optional const& groupIndex) { // Allocate a spot for the item entry. auto lei = this->AllocateLinkEntry(item); @@ -842,10 +842,7 @@ void cmComputeLinkDepends::AddLinkObject(cmLinkItem const& item) void cmComputeLinkDepends::FollowLinkEntry(BFSEntry qe) { // Get this entry representation. - size_t depender_index = - qe.GroupIndex == cmComputeComponentGraph::INVALID_COMPONENT - ? qe.Index - : qe.GroupIndex; + size_t depender_index = qe.GroupIndex ? *qe.GroupIndex : qe.Index; LinkEntry const& entry = this->EntryList[qe.Index]; // Follow the item's dependencies. @@ -1029,10 +1026,7 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, // Track inferred dependency sets implied by this list. std::map dependSets; - bool inGroup = false; - std::pair groupIndex{ - cmComputeComponentGraph::INVALID_COMPONENT, false - }; + cm::optional> group; std::vector groupItems; // Loop over the libraries linked directly by the depender. @@ -1069,18 +1063,17 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, if (cmHasPrefix(item.AsStr(), LG_BEGIN) && cmHasSuffix(item.AsStr(), '>')) { - groupIndex = this->AddLinkEntry(item); - if (groupIndex.second) { - LinkEntry& entry = this->EntryList[groupIndex.first]; + group = this->AddLinkEntry(item, cm::nullopt); + if (group->second) { + LinkEntry& entry = this->EntryList[group->first]; entry.Feature = ExtractGroupFeature(item.AsStr()); } - inGroup = true; if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT) { this->EntryConstraintGraph[depender_index].emplace_back( - groupIndex.first, false, false, cmListFileBacktrace()); + group->first, false, false, cmListFileBacktrace()); } else { // This is a direct dependency of the target being linked. - this->OriginalEntries.push_back(groupIndex.first); + this->OriginalEntries.push_back(group->first); } continue; } @@ -1088,20 +1081,20 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, size_t dependee_index; if (cmHasPrefix(item.AsStr(), LG_END) && cmHasSuffix(item.AsStr(), '>')) { - dependee_index = groupIndex.first; - if (groupIndex.second) { - this->GroupItems.emplace(groupIndex.first, groupItems); + assert(group); + dependee_index = group->first; + if (group->second) { + this->GroupItems.emplace(group->first, std::move(groupItems)); } - inGroup = false; - groupIndex = std::make_pair(-1, false); + group = cm::nullopt; groupItems.clear(); continue; } if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT && - inGroup) { + group) { const auto& depender = this->EntryList[depender_index]; - const auto& groupFeature = this->EntryList[groupIndex.first].Feature; + const auto& groupFeature = this->EntryList[group->first].Feature; if (depender.Target && depender.Target->IsImported() && !IsGroupFeatureSupported(this->Makefile, this->LinkLanguage, groupFeature)) { @@ -1121,18 +1114,19 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, } // Add a link entry for this item. - auto ale = this->AddLinkEntry(item, groupIndex.first); + auto ale = this->AddLinkEntry( + item, group ? cm::optional(group->first) : cm::nullopt); dependee_index = ale.first; LinkEntry& entry = this->EntryList[dependee_index]; bool supportedItem = true; auto const& itemFeature = this->GetCurrentFeature(entry.Item.Value, item.Feature); - if (inGroup && ale.second && entry.Target && + if (group && ale.second && entry.Target && (entry.Target->GetType() == cmStateEnums::TargetType::OBJECT_LIBRARY || entry.Target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY)) { supportedItem = false; - const auto& groupFeature = this->EntryList[groupIndex.first].Feature; + const auto& groupFeature = this->EntryList[group->first].Feature; this->CMakeInstance->IssueMessage( MessageType::AUTHOR_WARNING, cmStrCat( @@ -1173,8 +1167,8 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, } if (supportedItem) { - if (inGroup) { - const auto& currentFeature = this->EntryList[groupIndex.first].Feature; + if (group) { + const auto& currentFeature = this->EntryList[group->first].Feature; for (const auto& g : this->GroupItems) { const auto& groupFeature = this->EntryList[g.first].Feature; if (groupFeature == currentFeature) { @@ -1245,7 +1239,7 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, } } - if (inGroup) { + if (group) { // store item index for dependencies handling groupItems.push_back(dependee_index); } else { diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 66daa07..e3d179b 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -13,12 +13,14 @@ #include #include -#include "cmComputeComponentGraph.h" +#include + #include "cmGraphAdjacencyList.h" #include "cmLinkItem.h" #include "cmListFileCache.h" #include "cmTargetLinkLibraryType.h" +class cmComputeComponentGraph; class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; @@ -98,9 +100,8 @@ private: std::pair::iterator, bool> AllocateLinkEntry( cmLinkItem const& item); - std::pair AddLinkEntry( - cmLinkItem const& item, - size_t groupIndex = cmComputeComponentGraph::INVALID_COMPONENT); + std::pair AddLinkEntry(cmLinkItem const& item, + cm::optional const& groupIndex); void AddLinkObject(cmLinkItem const& item); void AddVarLinkEntries(size_t depender_index, const char* value); void AddDirectLinkEntries(); @@ -120,7 +121,7 @@ private: struct BFSEntry { size_t Index; - size_t GroupIndex; + cm::optional GroupIndex; const char* LibDepends; }; std::queue BFSQueue; -- cgit v0.12 From dccdd030cd6b3e57f5f5e1e810c38cc7bc46c4eb Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 17 Sep 2024 14:05:43 -0400 Subject: cmComputeLinkDepends: Replace depender index sentinel value with cm::optional --- Source/cmComputeLinkDepends.cxx | 40 ++++++++++++++++++---------------------- Source/cmComputeLinkDepends.h | 9 ++++++--- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 014d600..8a1e38b 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -941,8 +941,8 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) } } -void cmComputeLinkDepends::AddVarLinkEntries(size_t depender_index, - const char* value) +void cmComputeLinkDepends::AddVarLinkEntries( + cm::optional const& depender_index, const char* value) { // This is called to add the dependencies named by // _LIB_DEPENDS. The variable contains a semicolon-separated @@ -1003,15 +1003,13 @@ void cmComputeLinkDepends::AddDirectLinkEntries() // Add direct link dependencies in this configuration. cmLinkImplementation const* impl = this->Target->GetLinkImplementation( this->Config, cmGeneratorTarget::UseTo::Link); - this->AddLinkEntries(cmComputeComponentGraph::INVALID_COMPONENT, - impl->Libraries); + this->AddLinkEntries(cm::nullopt, impl->Libraries); this->AddLinkObjects(impl->Objects); for (auto const& language : impl->Languages) { auto runtimeEntries = impl->LanguageRuntimeLibraries.find(language); if (runtimeEntries != impl->LanguageRuntimeLibraries.end()) { - this->AddLinkEntries(cmComputeComponentGraph::INVALID_COMPONENT, - runtimeEntries->second); + this->AddLinkEntries(cm::nullopt, runtimeEntries->second); } } for (cmLinkItem const& wi : impl->WrongConfigLibraries) { @@ -1020,8 +1018,8 @@ void cmComputeLinkDepends::AddDirectLinkEntries() } template -void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, - std::vector const& libs) +void cmComputeLinkDepends::AddLinkEntries( + cm::optional const& depender_index, std::vector const& libs) { // Track inferred dependency sets implied by this list. std::map dependSets; @@ -1040,9 +1038,8 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, // emit a warning if an undefined feature is used as part of // an imported target - if (item.Feature != LinkEntry::DEFAULT && - depender_index != cmComputeComponentGraph::INVALID_COMPONENT) { - const auto& depender = this->EntryList[depender_index]; + if (item.Feature != LinkEntry::DEFAULT && depender_index) { + const auto& depender = this->EntryList[*depender_index]; if (depender.Target && depender.Target->IsImported() && !IsFeatureSupported(this->Makefile, this->LinkLanguage, item.Feature)) { @@ -1068,8 +1065,8 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, LinkEntry& entry = this->EntryList[group->first]; entry.Feature = ExtractGroupFeature(item.AsStr()); } - if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT) { - this->EntryConstraintGraph[depender_index].emplace_back( + if (depender_index) { + this->EntryConstraintGraph[*depender_index].emplace_back( group->first, false, false, cmListFileBacktrace()); } else { // This is a direct dependency of the target being linked. @@ -1091,9 +1088,8 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, continue; } - if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT && - group) { - const auto& depender = this->EntryList[depender_index]; + if (depender_index && group) { + const auto& depender = this->EntryList[*depender_index]; const auto& groupFeature = this->EntryList[group->first].Feature; if (depender.Target && depender.Target->IsImported() && !IsGroupFeatureSupported(this->Makefile, this->LinkLanguage, @@ -1261,8 +1257,8 @@ void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, for (auto index : indexes) { // The dependee must come after the depender. - if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT) { - this->EntryConstraintGraph[depender_index].emplace_back( + if (depender_index) { + this->EntryConstraintGraph[*depender_index].emplace_back( index, false, false, cmListFileBacktrace()); } else { // This is a direct dependency of the target being linked. @@ -1305,14 +1301,14 @@ void cmComputeLinkDepends::AddLinkObjects(std::vector const& objs) } } -cmLinkItem cmComputeLinkDepends::ResolveLinkItem(size_t depender_index, - const std::string& name) +cmLinkItem cmComputeLinkDepends::ResolveLinkItem( + cm::optional const& depender_index, const std::string& name) { // Look for a target in the scope of the depender. cmGeneratorTarget const* from = this->Target; - if (depender_index != cmComputeComponentGraph::INVALID_COMPONENT) { + if (depender_index) { if (cmGeneratorTarget const* depender = - this->EntryList[depender_index].Target) { + this->EntryList[*depender_index].Target) { from = depender; } } diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index e3d179b..de6e6fa 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -103,12 +103,15 @@ private: std::pair AddLinkEntry(cmLinkItem const& item, cm::optional const& groupIndex); void AddLinkObject(cmLinkItem const& item); - void AddVarLinkEntries(size_t depender_index, const char* value); + void AddVarLinkEntries(cm::optional const& depender_index, + const char* value); void AddDirectLinkEntries(); template - void AddLinkEntries(size_t depender_index, std::vector const& libs); + void AddLinkEntries(cm::optional const& depender_index, + std::vector const& libs); void AddLinkObjects(std::vector const& objs); - cmLinkItem ResolveLinkItem(size_t depender_index, const std::string& name); + cmLinkItem ResolveLinkItem(cm::optional const& depender_index, + const std::string& name); // One entry for each unique item. std::vector EntryList; -- cgit v0.12 From 8db69c767bb2cf85abc20333be04ae758f11c89d Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 18 Sep 2024 14:03:12 -0400 Subject: cmComputeLinkDepends: Remove redundant member --- Source/cmComputeLinkDepends.cxx | 5 ++--- Source/cmComputeLinkDepends.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 8a1e38b..9ff6d70 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -642,8 +642,7 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, } // The configuration being linked. - this->HasConfig = !config.empty(); - this->Config = (this->HasConfig) ? config : std::string(); + this->Config = config; std::vector debugConfigs = this->Makefile->GetCMakeInstance()->GetDebugConfigs(); this->LinkType = CMP0003_ComputeLinkType(this->Config, debugConfigs); @@ -706,7 +705,7 @@ cmComputeLinkDepends::Compute() "---------------------------------------\n"); fprintf(stderr, "Link dependency analysis for target %s, config %s\n", this->Target->GetName().c_str(), - this->HasConfig ? this->Config.c_str() : "noconfig"); + this->Config.empty() ? "noconfig" : this->Config.c_str()); this->DisplayConstraintGraph(); } diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index de6e6fa..d51d548 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -208,7 +208,6 @@ private: size_t ComponentOrderId; cmTargetLinkLibraryType LinkType; - bool HasConfig; bool DebugMode; bool OldLinkDirMode; }; -- cgit v0.12 From 3bd73fcc76576b0e0656ca8ba73402d102a1ee30 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 18 Sep 2024 13:58:54 -0400 Subject: cmComputeLinkDepends: Modernize member initialization --- Source/cmComputeLinkDepends.cxx | 33 ++++++++++----------------------- Source/cmComputeLinkDepends.h | 15 ++++++++------- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 9ff6d70..1e3b7e9 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -580,15 +580,17 @@ std::string const& cmComputeLinkDepends::LinkEntry::DEFAULT = cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, const std::string& config, const std::string& linkLanguage) -{ - // Store context information. - this->Target = target; - this->Makefile = this->Target->Target->GetMakefile(); - this->GlobalGenerator = - this->Target->GetLocalGenerator()->GetGlobalGenerator(); - this->CMakeInstance = this->GlobalGenerator->GetCMakeInstance(); - this->LinkLanguage = linkLanguage; + : Target(target) + , Makefile(this->Target->Target->GetMakefile()) + , GlobalGenerator(this->Target->GetLocalGenerator()->GetGlobalGenerator()) + , CMakeInstance(this->GlobalGenerator->GetCMakeInstance()) + , Config(config) + , DebugMode(this->Makefile->IsOn("CMAKE_LINK_DEPENDS_DEBUG_MODE")) + , LinkLanguage(linkLanguage) + , LinkType(CMP0003_ComputeLinkType( + this->Config, this->Makefile->GetCMakeInstance()->GetDebugConfigs())) +{ // target oriented feature override property takes precedence over // global override property cm::string_view lloPrefix = "LINK_LIBRARY_OVERRIDE_"_s; @@ -640,21 +642,6 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, }); } } - - // The configuration being linked. - this->Config = config; - std::vector debugConfigs = - this->Makefile->GetCMakeInstance()->GetDebugConfigs(); - this->LinkType = CMP0003_ComputeLinkType(this->Config, debugConfigs); - - // Enable debug mode if requested. - this->DebugMode = this->Makefile->IsOn("CMAKE_LINK_DEPENDS_DEBUG_MODE"); - - // Assume no compatibility until set. - this->OldLinkDirMode = false; - - // No computation has been done. - this->CCG = nullptr; } cmComputeLinkDepends::~cmComputeLinkDepends() = default; diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index d51d548..5926c12 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -86,12 +86,15 @@ public: private: // Context information. - cmGeneratorTarget const* Target; - cmMakefile* Makefile; - cmGlobalGenerator const* GlobalGenerator; + cmGeneratorTarget const* Target = nullptr; + cmMakefile* Makefile = nullptr; + cmGlobalGenerator const* GlobalGenerator = nullptr; cmake* CMakeInstance; - std::string LinkLanguage; std::string Config; + bool DebugMode = false; + std::string LinkLanguage; + cmTargetLinkLibraryType LinkType; + EntryVector FinalLinkEntries; std::map LinkLibraryOverride; @@ -207,7 +210,5 @@ private: std::vector ObjectEntries; size_t ComponentOrderId; - cmTargetLinkLibraryType LinkType; - bool DebugMode; - bool OldLinkDirMode; + bool OldLinkDirMode = false; }; -- cgit v0.12 From 80b469a51de05984c47149ab093d7f2fcf9b9816 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 18 Sep 2024 18:49:22 -0400 Subject: cmComputeLinkDepends: Factor out string literals as named constants --- Source/cmComputeLinkDepends.cxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 1e3b7e9..21bc8ae 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -315,8 +315,10 @@ const LinkLibraryFeatureAttributeSet& GetLinkLibraryFeatureAttributes( } // LINK_GROUP helpers -const auto LG_BEGIN = "FinalEntries.end()) { break; } - it->Item.Value = ""; + it->Item.Value = std::string(LG_ITEM_END); for (auto index = g.second.rbegin(); index != g.second.rend(); ++index) { it = this->FinalEntries.insert(it, this->Entries[*index]); } it = this->FinalEntries.insert(it, groupEntry); - it->Item.Value = ""; + it->Item.Value = std::string(LG_ITEM_BEGIN); } } } -- cgit v0.12 From f792db4ca2b41e1263cfc6825bb53bc3f6bb9606 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 18 Sep 2024 18:28:13 -0400 Subject: cmComputeLinkDepends: Add undocumented per-target debug property This will be useful for testing. --- Source/cmComputeLinkDepends.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 21bc8ae..976a158 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -587,7 +587,8 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, , GlobalGenerator(this->Target->GetLocalGenerator()->GetGlobalGenerator()) , CMakeInstance(this->GlobalGenerator->GetCMakeInstance()) , Config(config) - , DebugMode(this->Makefile->IsOn("CMAKE_LINK_DEPENDS_DEBUG_MODE")) + , DebugMode(this->Makefile->IsOn("CMAKE_LINK_DEPENDS_DEBUG_MODE") || + this->Target->GetProperty("LINK_DEPENDS_DEBUG_MODE").IsOn()) , LinkLanguage(linkLanguage) , LinkType(CMP0003_ComputeLinkType( this->Config, this->Makefile->GetCMakeInstance()->GetDebugConfigs())) -- cgit v0.12 From 9285a9dc9a71bcf511b22a14aaa4a13ebf269480 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 18 Sep 2024 18:29:51 -0400 Subject: cmComputeLinkDepends: Add final dependency ordering to debug output Print results of the main ordering algorithm before platform-specific filtering by `CMAKE__LINK_LIBRARIES_PROCESSING`. --- Source/cmComputeLinkDepends.cxx | 62 ++++++++++++++++++++++++++++++----------- Source/cmComputeLinkDepends.h | 1 + 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 976a158..ae33c12 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -715,6 +715,11 @@ cmComputeLinkDepends::Compute() // Compute the final ordering. this->OrderLinkEntries(); + // Display the final ordering. + if (this->DebugMode) { + this->DisplayOrderedEntries(); + } + // Compute the final set of link entries. EntriesProcessing entriesProcessing{ this->Target, this->LinkLanguage, this->EntryList, @@ -1649,26 +1654,49 @@ size_t cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl) return count; } -void cmComputeLinkDepends::DisplayFinalEntries() +namespace { +void DisplayLinkEntry(int& count, cmComputeLinkDepends::LinkEntry const& entry) { - fprintf(stderr, "target [%s] links to:\n", this->Target->GetName().c_str()); - char space[] = " "; - int count = 2; - for (LinkEntry const& lei : this->FinalLinkEntries) { - if (lei.Kind == LinkEntry::Group) { - fprintf(stderr, " %s group", - lei.Item.Value == "" ? "start" : "end"); - count = lei.Item.Value == "" ? 4 : 2; - } else if (lei.Target) { - fprintf(stderr, "%*starget [%s]", count, space, - lei.Target->GetName().c_str()); + if (entry.Kind == cmComputeLinkDepends::LinkEntry::Group) { + if (entry.Item.Value == LG_ITEM_BEGIN) { + fprintf(stderr, " start group"); + count = 4; + } else if (entry.Item.Value == LG_ITEM_END) { + fprintf(stderr, " end group"); + count = 2; } else { - fprintf(stderr, "%*sitem [%s]", count, space, lei.Item.Value.c_str()); + fprintf(stderr, " group"); } - if (lei.Feature != LinkEntry::DEFAULT) { - fprintf(stderr, ", feature [%s]", lei.Feature.c_str()); - } - fprintf(stderr, "\n"); + } else if (entry.Target) { + fprintf(stderr, "%*starget [%s]", count, "", + entry.Target->GetName().c_str()); + } else { + fprintf(stderr, "%*sitem [%s]", count, "", entry.Item.Value.c_str()); + } + if (entry.Feature != cmComputeLinkDepends::LinkEntry::DEFAULT) { + fprintf(stderr, ", feature [%s]", entry.Feature.c_str()); + } + fprintf(stderr, "\n"); +} +} + +void cmComputeLinkDepends::DisplayOrderedEntries() +{ + fprintf(stderr, "target [%s] link dependency ordering:\n", + this->Target->GetName().c_str()); + int count = 2; + for (auto index : this->FinalLinkOrder) { + DisplayLinkEntry(count, this->EntryList[index]); + } + fprintf(stderr, "\n"); +} + +void cmComputeLinkDepends::DisplayFinalEntries() +{ + fprintf(stderr, "target [%s] link line:\n", this->Target->GetName().c_str()); + int count = 2; + for (LinkEntry const& entry : this->FinalLinkEntries) { + DisplayLinkEntry(count, entry); } fprintf(stderr, "\n"); } diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 5926c12..55f0032 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -199,6 +199,7 @@ private: void VisitEntry(size_t index); PendingComponent& MakePendingComponent(size_t component); size_t ComputeComponentCount(NodeList const& nl); + void DisplayOrderedEntries(); void DisplayFinalEntries(); // Record of the original link line. -- cgit v0.12 From 7abd3137b74543cf698ac6c7290696d82042e7de Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 19 Sep 2024 13:10:04 -0400 Subject: Linking: Optionally reorder direct dependencies from LINK_LIBRARIES Traditionally CMake generates link lines by starting with the direct link dependencies specified by `LINK_LIBRARIES` in their original order and then appending indirect dependencies that the direct dependencies do not express. This gives projects control over ordering among independent entries, which can be important when intermixing flags and libraries, or when multiple libraries provide the same symbol. However, it may also result in inefficient link lines. Add support for an alternative strategy that can reorder direct link dependencies to produce more efficient link lines. This is useful for projects that cannot easily specify their targets' direct dependencies in an order that satisfies indirect dependencies. Add a `CMAKE_LINK_LIBRARIES_STRATEGY` variable and corresponding `LINK_LIBRARIES_STRATEGY` target property to select a strategy. Fixes: #26271 --- Help/command/target_link_libraries.rst | 5 ++ Help/manual/cmake-properties.7.rst | 1 + Help/manual/cmake-variables.7.rst | 1 + Help/prop_tgt/LINK_LIBRARIES.rst | 5 ++ Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst | 11 ++++ Help/release/dev/link-strategy.rst | 7 +++ Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst | 68 ++++++++++++++++++++++ Source/cmComputeLinkDepends.cxx | 22 ++++++- Source/cmComputeLinkDepends.h | 10 +++- Source/cmComputeLinkInformation.cxx | 20 ++++++- Source/cmTarget.cxx | 1 + Tests/RunCMake/CMakeLists.txt | 1 + .../Basic-PRESERVE_ORDER-run-stdout-reverse.txt | 1 + .../Basic-PRESERVE_ORDER-run-stdout.txt | 1 + .../Basic-PRESERVE_ORDER-stderr.txt | 7 +++ .../Basic-PRESERVE_ORDER.cmake | 2 + .../Basic-REORDER-run-stdout.txt | 1 + .../LinkLibrariesStrategy/Basic-REORDER-stderr.txt | 6 ++ .../LinkLibrariesStrategy/Basic-REORDER.cmake | 2 + .../LinkLibrariesStrategy/Basic-common.cmake | 15 +++++ Tests/RunCMake/LinkLibrariesStrategy/Basic.c | 11 ++++ Tests/RunCMake/LinkLibrariesStrategy/BasicA.c | 4 ++ Tests/RunCMake/LinkLibrariesStrategy/BasicB.c | 5 ++ Tests/RunCMake/LinkLibrariesStrategy/BasicC.c | 5 ++ Tests/RunCMake/LinkLibrariesStrategy/BasicX.c | 7 +++ .../RunCMake/LinkLibrariesStrategy/CMakeLists.txt | 3 + .../Duplicate-PRESERVE_ORDER-stderr.txt | 15 +++++ .../Duplicate-PRESERVE_ORDER.cmake | 2 + .../Duplicate-REORDER-stderr.txt | 9 +++ .../LinkLibrariesStrategy/Duplicate-REORDER.cmake | 2 + .../LinkLibrariesStrategy/Duplicate-common.cmake | 12 ++++ Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c | 4 ++ Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake | 12 ++++ .../LinkLibrariesStrategy/RunCMakeTest.cmake | 36 ++++++++++++ .../LinkLibrariesStrategy/Unknown-result.txt | 1 + .../LinkLibrariesStrategy/Unknown-stderr.txt | 4 ++ Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake | 5 ++ Tests/RunCMake/LinkLibrariesStrategy/main.c | 4 ++ 38 files changed, 323 insertions(+), 5 deletions(-) create mode 100644 Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst create mode 100644 Help/release/dev/link-strategy.rst create mode 100644 Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Basic.c create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/BasicA.c create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/BasicB.c create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/BasicC.c create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/BasicX.c create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER-stderr.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake create mode 100644 Tests/RunCMake/LinkLibrariesStrategy/main.c diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst index a82adda..94a2429 100644 --- a/Help/command/target_link_libraries.rst +++ b/Help/command/target_link_libraries.rst @@ -140,6 +140,11 @@ Items containing ``::``, such as ``Foo::Bar``, are assumed to be target names and will cause an error if no such target exists. See policy :policy:`CMP0028`. +See the :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable and +corresponding :prop_tgt:`LINK_LIBRARIES_STRATEGY` target property +for details on how CMake orders direct link dependencies on linker +command lines. + See the :manual:`cmake-buildsystem(7)` manual for more on defining buildsystem properties. diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 9ad856d..10dbe10 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -336,6 +336,7 @@ Properties on Targets /prop_tgt/LINK_INTERFACE_MULTIPLICITY_CONFIG /prop_tgt/LINK_LIBRARIES /prop_tgt/LINK_LIBRARIES_ONLY_TARGETS + /prop_tgt/LINK_LIBRARIES_STRATEGY /prop_tgt/LINK_LIBRARY_OVERRIDE /prop_tgt/LINK_LIBRARY_OVERRIDE_LIBRARY /prop_tgt/LINK_OPTIONS diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index a79747f..cc10950 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -491,6 +491,7 @@ Variables that Control the Build /variable/CMAKE_LINK_GROUP_USING_FEATURE /variable/CMAKE_LINK_GROUP_USING_FEATURE_SUPPORTED /variable/CMAKE_LINK_INTERFACE_LIBRARIES + /variable/CMAKE_LINK_LIBRARIES_STRATEGY /variable/CMAKE_LINK_LIBRARY_FEATURE_ATTRIBUTES /variable/CMAKE_LINK_LIBRARY_FILE_FLAG /variable/CMAKE_LINK_LIBRARY_FLAG diff --git a/Help/prop_tgt/LINK_LIBRARIES.rst b/Help/prop_tgt/LINK_LIBRARIES.rst index b5c1d89..b449aa1 100644 --- a/Help/prop_tgt/LINK_LIBRARIES.rst +++ b/Help/prop_tgt/LINK_LIBRARIES.rst @@ -28,3 +28,8 @@ In advanced use cases, the list of direct link dependencies specified by this property may be updated by usage requirements from dependencies. See the :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` and :prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE` target properties. + +See the :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable and +corresponding :prop_tgt:`LINK_LIBRARIES_STRATEGY` target property +for details on how CMake orders direct link dependencies on linker +command lines. diff --git a/Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst b/Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst new file mode 100644 index 0000000..bba707c --- /dev/null +++ b/Help/prop_tgt/LINK_LIBRARIES_STRATEGY.rst @@ -0,0 +1,11 @@ +LINK_LIBRARIES_STRATEGY +----------------------- + +.. versionadded:: 3.31 + +Specify a strategy for ordering a target's direct link dependencies +on linker command lines. + +See the :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable for details +and supported values. This property is initialized by the value of that +variable when a target is created. diff --git a/Help/release/dev/link-strategy.rst b/Help/release/dev/link-strategy.rst new file mode 100644 index 0000000..ab626d1 --- /dev/null +++ b/Help/release/dev/link-strategy.rst @@ -0,0 +1,7 @@ +link-strategy +------------- + +* The :variable:`CMAKE_LINK_LIBRARIES_STRATEGY` variable and + corresponding :prop_tgt:`LINK_LIBRARIES_STRATEGY` target + property were added to optionally specify the strategy + CMake uses to generate link lines. diff --git a/Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst b/Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst new file mode 100644 index 0000000..1ba6b27 --- /dev/null +++ b/Help/variable/CMAKE_LINK_LIBRARIES_STRATEGY.rst @@ -0,0 +1,68 @@ +CMAKE_LINK_LIBRARIES_STRATEGY +----------------------------- + +.. versionadded:: 3.31 + +Specify a strategy for ordering targets' direct link dependencies +on linker command lines. + +The value of this variable initializes the :prop_tgt:`LINK_LIBRARIES_STRATEGY` +target property of targets as they are created. Set that property directly +to specify a strategy for a single target. + +CMake generates a target's link line using its :ref:`Target Link Properties`. +In particular, the :prop_tgt:`LINK_LIBRARIES` target property records the +target's direct link dependencies, typically populated by calls to +:command:`target_link_libraries`. Indirect link dependencies are +propagated from those entries of :prop_tgt:`LINK_LIBRARIES` that name +library targets by following the transitive closure of their +:prop_tgt:`INTERFACE_LINK_LIBRARIES` properties. CMake supports multiple +strategies for passing direct and indirect link dependencies to the linker. + +Consider this example for the strategies below: + +.. code-block:: cmake + + add_library(A STATIC ...) + add_library(B STATIC ...) + add_library(C STATIC ...) + add_executable(main ...) + target_link_libraries(B PRIVATE A) + target_link_libraries(C PRIVATE A) + target_link_libraries(main PRIVATE A B C) + +The supported strategies are: + +``PRESERVE_ORDER`` + Entries of :prop_tgt:`LINK_LIBRARIES` always appear first and in their + original order. Indirect link dependencies not satisfied by the + original entries may be reordered and de-duplicated with respect to + one another, but are always appended after the original entries. + This may result in less efficient link lines, but gives projects + control of ordering among independent entries. Such control may be + important when intermixing link flags with libraries, or when multiple + libraries provide a given symbol. + + This is the default. + + In the above example, this strategy computes a link line for ``main`` + by starting with its original entries ``A B C``, and then appends + another ``A`` to satisfy the dependencies of ``B`` and ``C`` on ``A``. + The final order is ``A B C A``. + +``REORDER`` + Entries of :prop_tgt:`LINK_LIBRARIES` may be reordered, de-duplicated, + and intermixed with indirect link dependencies. This may result in + more efficient link lines, but does not give projects any control of + ordering among independent entries. + + In the above example, this strategy computes a link line for ``main`` + by re-ordering its original entries ``A B C`` to satisfy the + dependencies of ``B`` and ``C`` on ``A``. + The final order is ``B C A``. + +.. note:: + + Regardless of the strategy used, the actual linker invocation for + some platforms may de-duplicate entries based on linker capabilities. + See policy :policy:`CMP0156`. diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index ae33c12..70e992e 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -581,7 +581,8 @@ std::string const& cmComputeLinkDepends::LinkEntry::DEFAULT = cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, const std::string& config, - const std::string& linkLanguage) + const std::string& linkLanguage, + LinkLibrariesStrategy strategy) : Target(target) , Makefile(this->Target->Target->GetMakefile()) , GlobalGenerator(this->Target->GetLocalGenerator()->GetGlobalGenerator()) @@ -592,6 +593,7 @@ cmComputeLinkDepends::cmComputeLinkDepends(const cmGeneratorTarget* target, , LinkLanguage(linkLanguage) , LinkType(CMP0003_ComputeLinkType( this->Config, this->Makefile->GetCMakeInstance()->GetDebugConfigs())) + , Strategy(strategy) { // target oriented feature override property takes precedence over @@ -1488,8 +1490,22 @@ void cmComputeLinkDepends::OrderLinkEntries() } // Start with the original link line. - for (size_t originalEntry : this->OriginalEntries) { - this->VisitEntry(originalEntry); + switch (this->Strategy) { + case LinkLibrariesStrategy::PRESERVE_ORDER: { + // Emit the direct dependencies in their original order. + // This gives projects control over ordering. + for (size_t originalEntry : this->OriginalEntries) { + this->VisitEntry(originalEntry); + } + } break; + case LinkLibrariesStrategy::REORDER: { + // Schedule the direct dependencies for emission in topo order. + // This may produce more efficient link lines. + for (size_t originalEntry : this->OriginalEntries) { + this->MakePendingComponent( + this->CCG->GetComponentMap()[originalEntry]); + } + } break; } // Now explore anything left pending. Since the component graph is diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 55f0032..8b8aba4 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -27,6 +27,12 @@ class cmMakefile; class cmSourceFile; class cmake; +enum class LinkLibrariesStrategy +{ + PRESERVE_ORDER, + REORDER, +}; + /** \class cmComputeLinkDepends * \brief Compute link dependencies for targets. */ @@ -35,7 +41,8 @@ class cmComputeLinkDepends public: cmComputeLinkDepends(cmGeneratorTarget const* target, const std::string& config, - const std::string& linkLanguage); + const std::string& linkLanguage, + LinkLibrariesStrategy strategy); ~cmComputeLinkDepends(); cmComputeLinkDepends(const cmComputeLinkDepends&) = delete; @@ -94,6 +101,7 @@ private: bool DebugMode = false; std::string LinkLanguage; cmTargetLinkLibraryType LinkType; + LinkLibrariesStrategy Strategy; EntryVector FinalLinkEntries; std::map LinkLibraryOverride; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index dd194ed..26ff326 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -567,8 +568,25 @@ bool cmComputeLinkInformation::Compute() return false; } + LinkLibrariesStrategy strategy = LinkLibrariesStrategy::PRESERVE_ORDER; + if (cmValue s = this->Target->GetProperty("LINK_LIBRARIES_STRATEGY")) { + if (*s == "PRESERVE_ORDER"_s) { + strategy = LinkLibrariesStrategy::PRESERVE_ORDER; + } else if (*s == "REORDER"_s) { + strategy = LinkLibrariesStrategy::REORDER; + } else { + this->CMakeInstance->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("LINK_LIBRARIES_STRATEGY value '", *s, + "' is not recognized."), + this->Target->GetBacktrace()); + return false; + } + } + // Compute the ordered link line items. - cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage); + cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage, + strategy); cld.SetOldLinkDirMode(this->OldLinkDirMode); cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute(); FeatureDescriptor const* currentFeature = nullptr; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index da0091b..f220837 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -466,6 +466,7 @@ TargetProperty const StaticTargetProperties[] = { { "LINKER_TYPE"_s, IC::CanCompileSources }, { "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports }, { "LINK_LIBRARIES_ONLY_TARGETS"_s, IC::NormalNonImportedTarget }, + { "LINK_LIBRARIES_STRATEGY"_s, IC::NormalNonImportedTarget }, { "LINK_SEARCH_START_STATIC"_s, IC::CanCompileSources }, { "LINK_SEARCH_END_STATIC"_s, IC::CanCompileSources }, // Initialize per-configuration name postfix property from the variable only diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 40db51b..ba8776f 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -836,6 +836,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin|Windows)" endif() add_RunCMake_test(LinkLibrariesProcessing) +add_RunCMake_test(LinkLibrariesStrategy) add_RunCMake_test(File_Archive) add_RunCMake_test(File_Configure) add_RunCMake_test(File_Generate) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt new file mode 100644 index 0000000..7e46d1ba --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout-reverse.txt @@ -0,0 +1 @@ +^Library 'B' was linked first\.$ diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt new file mode 100644 index 0000000..6ef12eb --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-run-stdout.txt @@ -0,0 +1 @@ +^Library 'A' was linked first\.$ diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt new file mode 100644 index 0000000..1d8f4ba --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER-stderr.txt @@ -0,0 +1,7 @@ +target \[main\] link dependency ordering: + target \[A\] + target \[B\] + target \[C\] + target \[A\] + +target \[main\] link line: diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake new file mode 100644 index 0000000..f3dc096 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-PRESERVE_ORDER.cmake @@ -0,0 +1,2 @@ +set(CMAKE_LINK_LIBRARIES_STRATEGY PRESERVE_ORDER) +include(Basic-common.cmake) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt new file mode 100644 index 0000000..7e46d1ba --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-run-stdout.txt @@ -0,0 +1 @@ +^Library 'B' was linked first\.$ diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt new file mode 100644 index 0000000..54b02bd --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER-stderr.txt @@ -0,0 +1,6 @@ +target \[main\] link dependency ordering: + target \[B\] + target \[C\] + target \[A\] + +target \[main\] link line: diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake new file mode 100644 index 0000000..8e62377 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-REORDER.cmake @@ -0,0 +1,2 @@ +set(CMAKE_LINK_LIBRARIES_STRATEGY REORDER) +include(Basic-common.cmake) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake new file mode 100644 index 0000000..8dbbd39 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic-common.cmake @@ -0,0 +1,15 @@ +enable_language(C) + +add_library(A STATIC BasicA.c BasicX.c) +add_library(B STATIC BasicB.c BasicX.c) +add_library(C STATIC BasicC.c BasicX.c) +target_link_libraries(B PRIVATE A) +target_link_libraries(C PRIVATE A) +target_compile_definitions(A PRIVATE BASIC_ID="A") +target_compile_definitions(B PRIVATE BASIC_ID="B") +target_compile_definitions(C PRIVATE BASIC_ID="C") + +add_executable(main Basic.c) +target_link_libraries(main PRIVATE A B C) +set_property(TARGET main PROPERTY LINK_DEPENDS_DEBUG_MODE 1) # undocumented +set_property(TARGET main PROPERTY RUNTIME_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}>") diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Basic.c b/Tests/RunCMake/LinkLibrariesStrategy/Basic.c new file mode 100644 index 0000000..124d489 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Basic.c @@ -0,0 +1,11 @@ +extern int BasicB(void); +extern int BasicC(void); + +/* Use a symbol provided by a dedicated object file in A, B, and C. + The first library linked will determine the return value. */ +extern int BasicX(void); + +int main(void) +{ + return BasicB() + BasicC() + BasicX(); +} diff --git a/Tests/RunCMake/LinkLibrariesStrategy/BasicA.c b/Tests/RunCMake/LinkLibrariesStrategy/BasicA.c new file mode 100644 index 0000000..d3fe95d --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/BasicA.c @@ -0,0 +1,4 @@ +int BasicA(void) +{ + return 0; +} diff --git a/Tests/RunCMake/LinkLibrariesStrategy/BasicB.c b/Tests/RunCMake/LinkLibrariesStrategy/BasicB.c new file mode 100644 index 0000000..fd7a120 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/BasicB.c @@ -0,0 +1,5 @@ +extern int BasicA(void); +int BasicB(void) +{ + return BasicA(); +} diff --git a/Tests/RunCMake/LinkLibrariesStrategy/BasicC.c b/Tests/RunCMake/LinkLibrariesStrategy/BasicC.c new file mode 100644 index 0000000..7171dd1 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/BasicC.c @@ -0,0 +1,5 @@ +extern int BasicA(void); +int BasicC(void) +{ + return BasicA(); +} diff --git a/Tests/RunCMake/LinkLibrariesStrategy/BasicX.c b/Tests/RunCMake/LinkLibrariesStrategy/BasicX.c new file mode 100644 index 0000000..39f7863 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/BasicX.c @@ -0,0 +1,7 @@ +#include + +int BasicX(void) +{ + printf("Library '%s' was linked first.\n", BASIC_ID); + return 0; +} diff --git a/Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt b/Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt new file mode 100644 index 0000000..dda37d8 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.30) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt new file mode 100644 index 0000000..2637f93 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER-stderr.txt @@ -0,0 +1,15 @@ +target \[main\] link dependency ordering: + item \[-Flag1\] + target \[A\] + item \[-Flag1\] + target \[B\] + item \[-Flag2\] + target \[C\] + item \[-Flag2\] + target \[A\] + item \[-Flag2\] + target \[B\] + item \[-Flag3\] + target \[C\] + +target \[main\] link line: diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake new file mode 100644 index 0000000..9f694db --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-PRESERVE_ORDER.cmake @@ -0,0 +1,2 @@ +set(CMAKE_LINK_LIBRARIES_STRATEGY PRESERVE_ORDER) +include(Duplicate-common.cmake) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER-stderr.txt new file mode 100644 index 0000000..2353288 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER-stderr.txt @@ -0,0 +1,9 @@ +target \[main\] link dependency ordering: + item \[-Flag1\] + target \[A\] + target \[B\] + item \[-Flag2\] + target \[C\] + item \[-Flag3\] + +target \[main\] link line: diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake new file mode 100644 index 0000000..cc51e0a --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-REORDER.cmake @@ -0,0 +1,2 @@ +set(CMAKE_LINK_LIBRARIES_STRATEGY REORDER) +include(Duplicate-common.cmake) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake new file mode 100644 index 0000000..5050a0a --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate-common.cmake @@ -0,0 +1,12 @@ +enable_language(C) + +add_library(A INTERFACE IMPORTED) +add_library(B INTERFACE IMPORTED) +add_library(C INTERFACE IMPORTED) +set_property(TARGET A PROPERTY IMPORTED_LIBNAME A) +set_property(TARGET B PROPERTY IMPORTED_LIBNAME B) +set_property(TARGET C PROPERTY IMPORTED_LIBNAME C) + +add_executable(main Duplicate.c) +target_link_libraries(main PRIVATE -Flag1 A -Flag1 B -Flag2 C -Flag2 A -Flag2 B -Flag3 C) +set_property(TARGET main PROPERTY LINK_DEPENDS_DEBUG_MODE 1) # undocumented diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Duplicate.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake new file mode 100644 index 0000000..fd5da91 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Inspect.cmake @@ -0,0 +1,12 @@ +enable_language(C) + +set(info "") +foreach(var + CMAKE_C_LINK_LIBRARIES_PROCESSING + ) + if(DEFINED ${var}) + string(APPEND info "set(${var} \"${${var}}\")\n") + endif() +endforeach() + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}") diff --git a/Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake b/Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake new file mode 100644 index 0000000..1b02355 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/RunCMakeTest.cmake @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.30) + +include(RunCMake) + +if(RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug) +else() + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug) +endif() + +# Detect information from the toolchain: +# - CMAKE_C_LINK_LIBRARIES_PROCESSING +run_cmake(Inspect) +include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake") + +run_cmake(Unknown) + +function(run_strategy case exe) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build) + run_cmake(${case}) + set(RunCMake_TEST_NO_CLEAN 1) + run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug) + if(exe) + if("ORDER=REVERSE" IN_LIST CMAKE_C_LINK_LIBRARIES_PROCESSING) + set(RunCMake-stdout-file ${case}-run-stdout-reverse.txt) + endif() + run_cmake_command(${case}-run ${RunCMake_TEST_BINARY_DIR}/${exe}) + unset(RunCMake-stdout-file) + endif() +endfunction() + +run_strategy(Basic-PRESERVE_ORDER "main") +run_strategy(Basic-REORDER "main") + +run_cmake(Duplicate-PRESERVE_ORDER) +run_cmake(Duplicate-REORDER) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt b/Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Unknown-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt b/Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt new file mode 100644 index 0000000..3081f32 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Unknown-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at Unknown.cmake:5 \(add_executable\): + LINK_LIBRARIES_STRATEGY value 'unknown' is not recognized\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9] \(include\) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake b/Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake new file mode 100644 index 0000000..d3ad586 --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/Unknown.cmake @@ -0,0 +1,5 @@ +enable_language(C) + +set(CMAKE_LINK_LIBRARIES_STRATEGY unknown) + +add_executable(main main.c) diff --git a/Tests/RunCMake/LinkLibrariesStrategy/main.c b/Tests/RunCMake/LinkLibrariesStrategy/main.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/LinkLibrariesStrategy/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} -- cgit v0.12