summaryrefslogtreecommitdiffstats
path: root/Source/cmGeneratorTarget.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmGeneratorTarget.cxx')
-rw-r--r--Source/cmGeneratorTarget.cxx350
1 files changed, 255 insertions, 95 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 45e3b64..c4f1a13 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -57,6 +57,11 @@ using LinkInterfaceFor = cmGeneratorTarget::LinkInterfaceFor;
const cmsys::RegularExpression FrameworkRegularExpression(
"^(.*/)?([^/]*)\\.framework/(.*)$");
+const std::string kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES";
+const std::string kINTERFACE_LINK_LIBRARIES_DIRECT =
+ "INTERFACE_LINK_LIBRARIES_DIRECT";
+const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE =
+ "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE";
}
template <>
@@ -749,6 +754,12 @@ void cmGeneratorTarget::ClearSourcesCache()
this->LinkImplMap.clear();
}
+void cmGeneratorTarget::ClearLinkInterfaceCache()
+{
+ this->LinkInterfaceMap.clear();
+ this->LinkInterfaceUsageRequirementsOnlyMap.clear();
+}
+
void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before)
{
this->SourceEntries.insert(
@@ -3645,7 +3656,7 @@ void processIncludeDirectories(cmGeneratorTarget const* tgt,
cmLinkImplItem const& item = entry.LinkImplItem;
std::string const& targetName = item.AsStr();
bool const fromImported = item.Target && item.Target->IsImported();
- bool const checkCMP0027 = item.FromGenex;
+ bool const checkCMP0027 = item.CheckCMP0027;
std::string usedIncludes;
for (std::string& entryInclude : entry.Values) {
@@ -6638,7 +6649,7 @@ bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n,
cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem(
std::string const& n, cmListFileBacktrace const& bt,
- LookupLinkItemScope* scope) const
+ LookupLinkItemScope* scope, LookupSelf lookupSelf) const
{
cm::optional<cmLinkItem> maybeItem;
if (this->IsLinkLookupScope(n, scope->LG)) {
@@ -6646,20 +6657,22 @@ cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem(
}
std::string name = this->CheckCMP0004(n);
- if (name == this->GetName() || name.empty()) {
+ if (name.empty() ||
+ (lookupSelf == LookupSelf::No && name == this->GetName())) {
return maybeItem;
}
maybeItem = this->ResolveLinkItem(BT<std::string>(name, bt), scope->LG);
return maybeItem;
}
-void cmGeneratorTarget::ExpandLinkItems(std::string const& prop,
- cmBTStringRange entries,
- std::string const& config,
- cmGeneratorTarget const* headTarget,
- LinkInterfaceFor interfaceFor,
- cmLinkInterface& iface) const
+void cmGeneratorTarget::ExpandLinkItems(
+ std::string const& prop, cmBTStringRange entries, std::string const& config,
+ cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor,
+ LinkInterfaceField field, cmLinkInterface& iface) const
{
+ if (entries.empty()) {
+ return;
+ }
// Keep this logic in sync with ComputeLinkImplementationLibraries.
cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
// The $<LINK_ONLY> expression may be in a link interface to specify
@@ -6678,10 +6691,20 @@ void cmGeneratorTarget::ExpandLinkItems(std::string const& prop,
cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker,
this, headTarget->LinkerLanguage));
for (std::string const& lib : libs) {
- if (cm::optional<cmLinkItem> maybeItem =
- this->LookupLinkItem(lib, cge->GetBacktrace(), &scope)) {
+ if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(
+ lib, cge->GetBacktrace(), &scope,
+ field == LinkInterfaceField::Libraries ? LookupSelf::No
+ : LookupSelf::Yes)) {
cmLinkItem item = std::move(*maybeItem);
+ if (field == LinkInterfaceField::HeadInclude) {
+ iface.HeadInclude.emplace_back(std::move(item));
+ continue;
+ }
+ if (field == LinkInterfaceField::HeadExclude) {
+ iface.HeadExclude.emplace_back(std::move(item));
+ continue;
+ }
if (!item.Target) {
// Report explicitly linked object files separately.
std::string const& maybeObj = item.AsStr();
@@ -6736,17 +6759,16 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface(
// Lookup any existing link interface for this configuration.
cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config);
- if (secondPass) {
- hm.erase(head);
- }
-
// If the link interface does not depend on the head target
- // then return the one we computed first.
+ // then re-use the one from the head we computed first.
if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
- return &hm.begin()->second;
+ head = hm.begin()->first;
}
cmOptionalLinkInterface& iface = hm[head];
+ if (secondPass) {
+ iface = cmOptionalLinkInterface();
+ }
if (!iface.LibrariesDone) {
iface.LibrariesDone = true;
this->ComputeLinkInterfaceLibraries(config, iface, head,
@@ -6865,9 +6887,9 @@ const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries(
: this->GetHeadToLinkInterfaceMap(config));
// If the link interface does not depend on the head target
- // then return the one we computed first.
+ // then re-use the one from the head we computed first.
if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
- return &hm.begin()->second;
+ head = hm.begin()->first;
}
cmOptionalLinkInterface& iface = hm[head];
@@ -7146,59 +7168,66 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
// An explicit list of interface libraries may be set for shared
// libraries and executables that export symbols.
- cmValue explicitLibraries = nullptr;
- std::string linkIfaceProp;
+ bool haveExplicitLibraries = false;
+ cmValue explicitLibrariesCMP0022OLD;
+ std::string linkIfacePropCMP0022OLD;
bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD &&
this->GetPolicyStatusCMP0022() != cmPolicies::WARN);
if (cmp0022NEW) {
// CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES.
- linkIfaceProp = "INTERFACE_LINK_LIBRARIES";
- explicitLibraries = this->GetProperty(linkIfaceProp);
- } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
- this->IsExecutableWithExports()) {
+ haveExplicitLibraries = !this->Target->GetLinkInterfaceEntries().empty() ||
+ !this->Target->GetLinkInterfaceDirectEntries().empty() ||
+ !this->Target->GetLinkInterfaceDirectExcludeEntries().empty();
+ } else {
// CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a
// shared lib or executable.
-
- // Lookup the per-configuration property.
- linkIfaceProp = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix);
- explicitLibraries = this->GetProperty(linkIfaceProp);
-
- // If not set, try the generic property.
- if (!explicitLibraries) {
- linkIfaceProp = "LINK_INTERFACE_LIBRARIES";
- explicitLibraries = this->GetProperty(linkIfaceProp);
+ if (this->GetType() == cmStateEnums::SHARED_LIBRARY ||
+ this->IsExecutableWithExports()) {
+ // Lookup the per-configuration property.
+ linkIfacePropCMP0022OLD = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix);
+ explicitLibrariesCMP0022OLD = this->GetProperty(linkIfacePropCMP0022OLD);
+
+ // If not set, try the generic property.
+ if (!explicitLibrariesCMP0022OLD) {
+ linkIfacePropCMP0022OLD = "LINK_INTERFACE_LIBRARIES";
+ explicitLibrariesCMP0022OLD =
+ this->GetProperty(linkIfacePropCMP0022OLD);
+ }
}
- }
- if (explicitLibraries &&
- this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
- !this->PolicyWarnedCMP0022) {
- // Compare the explicitly set old link interface properties to the
- // preferred new link interface property one and warn if different.
- cmValue newExplicitLibraries =
- this->GetProperty("INTERFACE_LINK_LIBRARIES");
- if (newExplicitLibraries &&
- (*newExplicitLibraries != *explicitLibraries)) {
- std::ostringstream w;
- /* clang-format off */
- w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
- "Target \"" << this->GetName() << "\" has an "
- "INTERFACE_LINK_LIBRARIES property which differs from its " <<
- linkIfaceProp << " properties."
- "\n"
- "INTERFACE_LINK_LIBRARIES:\n"
- " " << *newExplicitLibraries << "\n" <<
- linkIfaceProp << ":\n"
- " " << *explicitLibraries << "\n";
- /* clang-format on */
- this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
- this->PolicyWarnedCMP0022 = true;
+ if (explicitLibrariesCMP0022OLD &&
+ this->GetPolicyStatusCMP0022() == cmPolicies::WARN &&
+ !this->PolicyWarnedCMP0022) {
+ // Compare the explicitly set old link interface properties to the
+ // preferred new link interface property one and warn if different.
+ cmValue newExplicitLibraries =
+ this->GetProperty("INTERFACE_LINK_LIBRARIES");
+ if (newExplicitLibraries &&
+ (*newExplicitLibraries != *explicitLibrariesCMP0022OLD)) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n"
+ "Target \"" << this->GetName() << "\" has an "
+ "INTERFACE_LINK_LIBRARIES property which differs from its " <<
+ linkIfacePropCMP0022OLD << " properties."
+ "\n"
+ "INTERFACE_LINK_LIBRARIES:\n"
+ " " << *newExplicitLibraries << "\n" <<
+ linkIfacePropCMP0022OLD << ":\n"
+ " " << *explicitLibrariesCMP0022OLD << "\n";
+ /* clang-format on */
+ this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING,
+ w.str());
+ this->PolicyWarnedCMP0022 = true;
+ }
}
+
+ haveExplicitLibraries = static_cast<bool>(explicitLibrariesCMP0022OLD);
}
// There is no implicit link interface for executables or modules
// so if none was explicitly set then there is no link interface.
- if (!explicitLibraries &&
+ if (!haveExplicitLibraries &&
(this->GetType() == cmStateEnums::EXECUTABLE ||
(this->GetType() == cmStateEnums::MODULE_LIBRARY))) {
return;
@@ -7208,22 +7237,29 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
// If CMP0022 is NEW then the plain tll signature sets the
// INTERFACE_LINK_LIBRARIES property. Even if the project
// clears it, the link interface is still explicit.
- iface.Explicit = cmp0022NEW || explicitLibraries;
-
- if (explicitLibraries) {
- // The interface libraries have been explicitly set.
- if (cmp0022NEW) {
- // The explicitLibraries came from INTERFACE_LINK_LIBRARIES.
- // Use its special representation directly to get backtraces.
- this->ExpandLinkItems(linkIfaceProp,
- this->Target->GetLinkInterfaceEntries(), config,
- headTarget, interfaceFor, iface);
- } else {
- std::vector<BT<std::string>> entries;
- entries.emplace_back(*explicitLibraries);
- this->ExpandLinkItems(linkIfaceProp, cmMakeRange(entries), config,
- headTarget, interfaceFor, iface);
- }
+ iface.Explicit = cmp0022NEW || explicitLibrariesCMP0022OLD;
+
+ if (cmp0022NEW) {
+ // The interface libraries are specified by INTERFACE_LINK_LIBRARIES.
+ // Use its special representation directly to get backtraces.
+ this->ExpandLinkItems(
+ kINTERFACE_LINK_LIBRARIES, this->Target->GetLinkInterfaceEntries(),
+ config, headTarget, interfaceFor, LinkInterfaceField::Libraries, iface);
+ this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT,
+ this->Target->GetLinkInterfaceDirectEntries(),
+ config, headTarget, interfaceFor,
+ LinkInterfaceField::HeadInclude, iface);
+ this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
+ this->Target->GetLinkInterfaceDirectExcludeEntries(),
+ config, headTarget, interfaceFor,
+ LinkInterfaceField::HeadExclude, iface);
+ } else if (explicitLibrariesCMP0022OLD) {
+ // The interface libraries have been explicitly set in pre-CMP0022 style.
+ std::vector<BT<std::string>> entries;
+ entries.emplace_back(*explicitLibrariesCMP0022OLD);
+ this->ExpandLinkItems(linkIfacePropCMP0022OLD, cmMakeRange(entries),
+ config, headTarget, interfaceFor,
+ LinkInterfaceField::Libraries, iface);
}
// If the link interface is explicit, do not fall back to the link impl.
@@ -7241,13 +7277,10 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
// Compare the link implementation fallback link interface to the
// preferred new link interface property and warn if different.
cmLinkInterface ifaceNew;
- static const std::string newProp = "INTERFACE_LINK_LIBRARIES";
- if (cmValue newExplicitLibraries = this->GetProperty(newProp)) {
- std::vector<BT<std::string>> entries;
- entries.emplace_back(*newExplicitLibraries);
- this->ExpandLinkItems(linkIfaceProp, cmMakeRange(entries), config,
- headTarget, interfaceFor, ifaceNew);
- }
+ this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES,
+ this->Target->GetLinkInterfaceEntries(), config,
+ headTarget, interfaceFor,
+ LinkInterfaceField::Libraries, ifaceNew);
if (ifaceNew.Libraries != iface.Libraries) {
std::string oldLibraries = cmJoin(impl->Libraries, ";");
std::string newLibraries = cmJoin(ifaceNew.Libraries, ";");
@@ -7372,29 +7405,37 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface(
? this->GetHeadToLinkInterfaceUsageRequirementsMap(config)
: this->GetHeadToLinkInterfaceMap(config));
- if (secondPass) {
- hm.erase(headTarget);
- }
-
// If the link interface does not depend on the head target
- // then return the one we computed first.
+ // then re-use the one from the head we computed first.
if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
- return &hm.begin()->second;
+ headTarget = hm.begin()->first;
}
cmOptionalLinkInterface& iface = hm[headTarget];
+ if (secondPass) {
+ iface = cmOptionalLinkInterface();
+ }
if (!iface.AllDone) {
iface.AllDone = true;
iface.LibrariesDone = true;
iface.Multiplicity = info->Multiplicity;
cmExpandList(info->Languages, iface.Languages);
+ this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT,
+ cmMakeRange(info->LibrariesHeadInclude), config,
+ headTarget, interfaceFor,
+ LinkInterfaceField::HeadInclude, iface);
+ this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE,
+ cmMakeRange(info->LibrariesHeadExclude), config,
+ headTarget, interfaceFor,
+ LinkInterfaceField::HeadExclude, iface);
this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries),
- config, headTarget, interfaceFor, iface);
+ config, headTarget, interfaceFor,
+ LinkInterfaceField::Libraries, iface);
std::vector<std::string> deps = cmExpandedList(info->SharedDeps);
LookupLinkItemScope scope{ this->LocalGenerator };
for (std::string const& dep : deps) {
- if (cm::optional<cmLinkItem> maybeItem =
- this->LookupLinkItem(dep, cmListFileBacktrace(), &scope)) {
+ if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(
+ dep, cmListFileBacktrace(), &scope, LookupSelf::No)) {
iface.SharedDeps.emplace_back(std::move(*maybeItem));
}
}
@@ -7482,6 +7523,14 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config,
}
}
}
+ for (BT<std::string> const& entry :
+ this->Target->GetLinkInterfaceDirectEntries()) {
+ info.LibrariesHeadInclude.emplace_back(entry);
+ }
+ for (BT<std::string> const& entry :
+ this->Target->GetLinkInterfaceDirectExcludeEntries()) {
+ info.LibrariesHeadExclude.emplace_back(entry);
+ }
if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
if (loc) {
info.LibName = *loc;
@@ -7896,9 +7945,9 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal(
this->LinkImplMap[cmSystemTools::UpperCase(config)];
// If the link implementation does not depend on the head target
- // then return the one we computed first.
+ // then re-use the one from the head we computed first.
if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) {
- return &hm.begin()->second;
+ head = hm.begin()->first;
}
cmOptionalLinkImplementation& impl = hm[head];
@@ -7915,6 +7964,112 @@ bool cmGeneratorTarget::IsNullImpliedByLinkLibraries(
return cm::contains(this->LinkImplicitNullProperties, p);
}
+namespace {
+class TransitiveLinkImpl
+{
+ cmGeneratorTarget const* Self;
+ std::string const& Config;
+ cmLinkImplementation& Impl;
+
+ std::set<cmLinkItem> Emitted;
+ std::set<cmLinkItem> Excluded;
+ std::unordered_set<cmGeneratorTarget const*> Followed;
+
+ void Follow(cmGeneratorTarget const* target);
+
+public:
+ TransitiveLinkImpl(cmGeneratorTarget const* self, std::string const& config,
+ cmLinkImplementation& impl)
+ : Self(self)
+ , Config(config)
+ , Impl(impl)
+ {
+ }
+
+ void Compute();
+};
+
+void TransitiveLinkImpl::Follow(cmGeneratorTarget const* target)
+{
+ if (!target || !this->Followed.insert(target).second ||
+ target->GetPolicyStatusCMP0022() == cmPolicies::OLD ||
+ target->GetPolicyStatusCMP0022() == cmPolicies::WARN) {
+ return;
+ }
+
+ // Get this target's usage requirements.
+ cmLinkInterfaceLibraries const* iface = target->GetLinkInterfaceLibraries(
+ this->Config, this->Self, LinkInterfaceFor::Usage);
+ if (!iface) {
+ return;
+ }
+ if (iface->HadContextSensitiveCondition) {
+ this->Impl.HadContextSensitiveCondition = true;
+ }
+
+ // Process 'INTERFACE_LINK_LIBRARIES_DIRECT' usage requirements.
+ for (cmLinkItem const& item : iface->HeadInclude) {
+ // Inject direct dependencies from the item's usage requirements
+ // before the item itself.
+ this->Follow(item.Target);
+
+ // Add the item itself, but at most once.
+ if (this->Emitted.insert(item).second) {
+ this->Impl.Libraries.emplace_back(item, /* checkCMP0027= */ false);
+ }
+ }
+
+ // Follow transitive dependencies.
+ for (cmLinkItem const& item : iface->Libraries) {
+ this->Follow(item.Target);
+ }
+
+ // Record exclusions from 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE'
+ // usage requirements.
+ for (cmLinkItem const& item : iface->HeadExclude) {
+ this->Excluded.insert(item);
+ }
+}
+
+void TransitiveLinkImpl::Compute()
+{
+ // Save the original items and start with an empty list.
+ std::vector<cmLinkImplItem> original = std::move(this->Impl.Libraries);
+
+ // Avoid injecting any original items as usage requirements.
+ // This gives LINK_LIBRARIES final control over the order
+ // if it explicitly lists everything.
+ this->Emitted.insert(original.cbegin(), original.cend());
+
+ // Process each original item.
+ for (cmLinkImplItem& item : original) {
+ // Inject direct dependencies listed in 'INTERFACE_LINK_LIBRARIES_DIRECT'
+ // usage requirements before the item itself.
+ this->Follow(item.Target);
+
+ // Add the item itself.
+ this->Impl.Libraries.emplace_back(std::move(item));
+ }
+
+ // Remove items listed in 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE'
+ // usage requirements found through any dependency above.
+ this->Impl.Libraries.erase(
+ std::remove_if(this->Impl.Libraries.begin(), this->Impl.Libraries.end(),
+ [this](cmLinkImplItem const& item) {
+ return this->Excluded.find(item) != this->Excluded.end();
+ }),
+ this->Impl.Libraries.end());
+}
+
+void ComputeLinkImplTransitive(cmGeneratorTarget const* self,
+ std::string const& config,
+ cmLinkImplementation& impl)
+{
+ TransitiveLinkImpl transitiveLinkImpl(self, config, impl);
+ transitiveLinkImpl.Compute();
+}
+}
+
void cmGeneratorTarget::ComputeLinkImplementationLibraries(
const std::string& config, cmOptionalLinkImplementation& impl,
cmGeneratorTarget const* head) const
@@ -7935,7 +8090,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
std::string const& evaluated =
cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr,
this->LinkerLanguage);
- bool const fromGenex = evaluated != entry.Value;
+ bool const checkCMP0027 = evaluated != entry.Value;
cmExpandList(evaluated, llibs);
if (cge->GetHadHeadSensitiveCondition()) {
impl.HadHeadSensitiveCondition = true;
@@ -8009,7 +8164,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
}
}
- impl.Libraries.emplace_back(std::move(item), fromGenex);
+ impl.Libraries.emplace_back(std::move(item), checkCMP0027);
}
std::set<std::string> const& seenProps = cge->GetSeenTargetProperties();
@@ -8021,6 +8176,11 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards);
}
+ // Update the list of direct link dependencies from usage requirements.
+ if (head == this) {
+ ComputeLinkImplTransitive(this, config, impl);
+ }
+
// Get the list of configurations considered to be DEBUG.
std::vector<std::string> debugConfigs =
this->Makefile->GetCMakeInstance()->GetDebugConfigs();