Make linking APIs aware of 'head' target

The 'head' is the dependent target to be linked with the current target.
It will be used to evaluate generator expressions with proper handling
of mapped configurations and is used as the source target of properties.

This requires that memoization is done with a key of a pair of target
and config, instead of just config, because now the result also depends
on the target.  Removing the memoization entirely is not an option
because it slows cmake down considerably.
This commit is contained in:
Stephen Kelly 2013-01-04 13:31:01 +01:00 committed by Brad King
parent 894f52f32d
commit 40cf3fb95b
9 changed files with 119 additions and 70 deletions

View File

@ -172,10 +172,11 @@ satisfy dependencies.
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmComputeLinkDepends cmComputeLinkDepends
::cmComputeLinkDepends(cmTarget* target, const char* config) ::cmComputeLinkDepends(cmTarget* target, const char* config, cmTarget* head)
{ {
// Store context information. // Store context information.
this->Target = target; this->Target = target;
this->HeadTarget = head;
this->Makefile = this->Target->GetMakefile(); this->Makefile = this->Target->GetMakefile();
this->LocalGenerator = this->Makefile->GetLocalGenerator(); this->LocalGenerator = this->Makefile->GetLocalGenerator();
this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
@ -352,7 +353,7 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
{ {
// Follow the target dependencies. // Follow the target dependencies.
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
entry.Target->GetLinkInterface(this->Config)) entry.Target->GetLinkInterface(this->Config, this->HeadTarget))
{ {
// This target provides its own link interface information. // This target provides its own link interface information.
this->AddLinkEntries(depender_index, iface->Libraries); this->AddLinkEntries(depender_index, iface->Libraries);
@ -444,7 +445,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
if(entry.Target) if(entry.Target)
{ {
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
entry.Target->GetLinkInterface(this->Config)) entry.Target->GetLinkInterface(this->Config, this->HeadTarget))
{ {
// Follow public and private dependencies transitively. // Follow public and private dependencies transitively.
this->FollowSharedDeps(index, iface, true); this->FollowSharedDeps(index, iface, true);
@ -533,7 +534,7 @@ void cmComputeLinkDepends::AddDirectLinkEntries()
{ {
// Add direct link dependencies in this configuration. // Add direct link dependencies in this configuration.
cmTarget::LinkImplementation const* impl = cmTarget::LinkImplementation const* impl =
this->Target->GetLinkImplementation(this->Config); this->Target->GetLinkImplementation(this->Config, this->HeadTarget);
this->AddLinkEntries(-1, impl->Libraries); this->AddLinkEntries(-1, impl->Libraries);
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
wi = impl->WrongConfigLibraries.begin(); wi = impl->WrongConfigLibraries.begin();
@ -944,7 +945,7 @@ int cmComputeLinkDepends::ComputeComponentCount(NodeList const& nl)
if(cmTarget* target = this->EntryList[*ni].Target) if(cmTarget* target = this->EntryList[*ni].Target)
{ {
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
target->GetLinkInterface(this->Config)) target->GetLinkInterface(this->Config, this->HeadTarget))
{ {
if(iface->Multiplicity > count) if(iface->Multiplicity > count)
{ {

View File

@ -32,7 +32,7 @@ class cmake;
class cmComputeLinkDepends class cmComputeLinkDepends
{ {
public: public:
cmComputeLinkDepends(cmTarget* target, const char* config); cmComputeLinkDepends(cmTarget* target, const char* config, cmTarget *head);
~cmComputeLinkDepends(); ~cmComputeLinkDepends();
// Basic information about each link item. // Basic information about each link item.
@ -59,6 +59,7 @@ private:
// Context information. // Context information.
cmTarget* Target; cmTarget* Target;
cmTarget* HeadTarget;
cmMakefile* Makefile; cmMakefile* Makefile;
cmLocalGenerator* LocalGenerator; cmLocalGenerator* LocalGenerator;
cmGlobalGenerator* GlobalGenerator; cmGlobalGenerator* GlobalGenerator;

View File

@ -239,10 +239,12 @@ because this need be done only for shared libraries without soname-s.
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmComputeLinkInformation cmComputeLinkInformation
::cmComputeLinkInformation(cmTarget* target, const char* config) ::cmComputeLinkInformation(cmTarget* target, const char* config,
cmTarget *headTarget)
{ {
// Store context information. // Store context information.
this->Target = target; this->Target = target;
this->HeadTarget = headTarget;
this->Makefile = this->Target->GetMakefile(); this->Makefile = this->Target->GetMakefile();
this->LocalGenerator = this->Makefile->GetLocalGenerator(); this->LocalGenerator = this->Makefile->GetLocalGenerator();
this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator(); this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
@ -265,7 +267,7 @@ cmComputeLinkInformation
this->OrderDependentRPath = 0; this->OrderDependentRPath = 0;
// Get the language used for linking this target. // Get the language used for linking this target.
this->LinkLanguage = this->Target->GetLinkerLanguage(config); this->LinkLanguage = this->Target->GetLinkerLanguage(config, headTarget);
if(!this->LinkLanguage) if(!this->LinkLanguage)
{ {
// The Compute method will do nothing, so skip the rest of the // The Compute method will do nothing, so skip the rest of the
@ -503,7 +505,7 @@ bool cmComputeLinkInformation::Compute()
} }
// Compute the ordered link line items. // Compute the ordered link line items.
cmComputeLinkDepends cld(this->Target, this->Config); cmComputeLinkDepends cld(this->Target, this->Config, this->HeadTarget);
cld.SetOldLinkDirMode(this->OldLinkDirMode); cld.SetOldLinkDirMode(this->OldLinkDirMode);
cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute(); cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
@ -569,7 +571,8 @@ bool cmComputeLinkInformation::Compute()
void cmComputeLinkInformation::AddImplicitLinkInfo() void cmComputeLinkInformation::AddImplicitLinkInfo()
{ {
// The link closure lists all languages whose implicit info is needed. // The link closure lists all languages whose implicit info is needed.
cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config); cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config,
this->HeadTarget);
for(std::vector<std::string>::const_iterator li = lc->Languages.begin(); for(std::vector<std::string>::const_iterator li = lc->Languages.begin();
li != lc->Languages.end(); ++li) li != lc->Languages.end(); ++li)
{ {

View File

@ -29,7 +29,8 @@ class cmOrderDirectories;
class cmComputeLinkInformation class cmComputeLinkInformation
{ {
public: public:
cmComputeLinkInformation(cmTarget* target, const char* config); cmComputeLinkInformation(cmTarget* target, const char* config,
cmTarget* headTarget);
~cmComputeLinkInformation(); ~cmComputeLinkInformation();
bool Compute(); bool Compute();
@ -74,6 +75,7 @@ private:
// Context information. // Context information.
cmTarget* Target; cmTarget* Target;
cmTarget* HeadTarget;
cmMakefile* Makefile; cmMakefile* Makefile;
cmLocalGenerator* LocalGenerator; cmLocalGenerator* LocalGenerator;
cmGlobalGenerator* GlobalGenerator; cmGlobalGenerator* GlobalGenerator;

View File

@ -244,8 +244,9 @@ void cmComputeTargetDepends::AddInterfaceDepends(int depender_index,
const char *config, const char *config,
std::set<cmStdString> &emitted) std::set<cmStdString> &emitted)
{ {
cmTarget* depender = this->Targets[depender_index];
if(cmTarget::LinkInterface const* iface = if(cmTarget::LinkInterface const* iface =
dependee->GetLinkInterface(config)) dependee->GetLinkInterface(config, depender))
{ {
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
lib = iface->Libraries.begin(); lib = iface->Libraries.begin();

View File

@ -357,7 +357,8 @@ cmExportFileGenerator
} }
// Add the transitive link dependencies for this configuration. // Add the transitive link dependencies for this configuration.
if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config)) if(cmTarget::LinkInterface const* iface = target->GetLinkInterface(config,
target))
{ {
this->SetImportLinkProperty(suffix, target, this->SetImportLinkProperty(suffix, target,
"IMPORTED_LINK_INTERFACE_LANGUAGES", "IMPORTED_LINK_INTERFACE_LANGUAGES",

View File

@ -1206,7 +1206,7 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget)
// If the language is compiled as a source trust Xcode to link with it. // If the language is compiled as a source trust Xcode to link with it.
cmTarget::LinkImplementation const* impl = cmTarget::LinkImplementation const* impl =
cmtarget.GetLinkImplementation("NOCONFIG"); cmtarget.GetLinkImplementation("NOCONFIG", &cmtarget);
for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
li != impl->Languages.end(); ++li) li != impl->Languages.end(); ++li)
{ {

View File

@ -72,6 +72,11 @@ struct cmTarget::ImportInfo
cmTarget::LinkInterface LinkInterface; cmTarget::LinkInterface LinkInterface;
}; };
struct TargetConfigPair : public std::pair<cmTarget*, std::string> {
TargetConfigPair(cmTarget* tgt, const std::string &config)
: std::pair<cmTarget*, std::string>(tgt, config) {}
};
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class cmTargetInternals class cmTargetInternals
{ {
@ -100,20 +105,24 @@ public:
OptionalLinkInterface(): Exists(false) {} OptionalLinkInterface(): Exists(false) {}
bool Exists; bool Exists;
}; };
typedef std::map<cmStdString, OptionalLinkInterface> LinkInterfaceMapType; typedef std::map<TargetConfigPair, OptionalLinkInterface>
LinkInterfaceMapType;
LinkInterfaceMapType LinkInterfaceMap; LinkInterfaceMapType LinkInterfaceMap;
typedef std::map<cmStdString, cmTarget::OutputInfo> OutputInfoMapType; typedef std::map<cmStdString, cmTarget::OutputInfo> OutputInfoMapType;
OutputInfoMapType OutputInfoMap; OutputInfoMapType OutputInfoMap;
typedef std::map<cmStdString, cmTarget::ImportInfo> ImportInfoMapType; typedef std::map<TargetConfigPair, cmTarget::ImportInfo>
ImportInfoMapType;
ImportInfoMapType ImportInfoMap; ImportInfoMapType ImportInfoMap;
// Cache link implementation computation from each configuration. // Cache link implementation computation from each configuration.
typedef std::map<cmStdString, cmTarget::LinkImplementation> LinkImplMapType; typedef std::map<TargetConfigPair,
cmTarget::LinkImplementation> LinkImplMapType;
LinkImplMapType LinkImplMap; LinkImplMapType LinkImplMap;
typedef std::map<cmStdString, cmTarget::LinkClosure> LinkClosureMapType; typedef std::map<TargetConfigPair, cmTarget::LinkClosure>
LinkClosureMapType;
LinkClosureMapType LinkClosureMap; LinkClosureMapType LinkClosureMap;
struct SourceEntry { std::vector<cmSourceFile*> Depends; }; struct SourceEntry { std::vector<cmSourceFile*> Depends; };
@ -3024,8 +3033,11 @@ class cmTargetCollectLinkLanguages
{ {
public: public:
cmTargetCollectLinkLanguages(cmTarget* target, const char* config, cmTargetCollectLinkLanguages(cmTarget* target, const char* config,
std::set<cmStdString>& languages): std::set<cmStdString>& languages,
Config(config), Languages(languages) { this->Visited.insert(target); } cmTarget* head):
Config(config), Languages(languages), HeadTarget(head)
{ this->Visited.insert(target); }
void Visit(cmTarget* target) void Visit(cmTarget* target)
{ {
if(!target || !this->Visited.insert(target).second) if(!target || !this->Visited.insert(target).second)
@ -3034,7 +3046,7 @@ public:
} }
cmTarget::LinkInterface const* iface = cmTarget::LinkInterface const* iface =
target->GetLinkInterface(this->Config); target->GetLinkInterface(this->Config, this->HeadTarget);
if(!iface) { return; } if(!iface) { return; }
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
@ -3053,26 +3065,30 @@ public:
private: private:
const char* Config; const char* Config;
std::set<cmStdString>& Languages; std::set<cmStdString>& Languages;
cmTarget* HeadTarget;
std::set<cmTarget*> Visited; std::set<cmTarget*> Visited;
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
const char* cmTarget::GetLinkerLanguage(const char* config) const char* cmTarget::GetLinkerLanguage(const char* config, cmTarget *head)
{ {
const char* lang = this->GetLinkClosure(config)->LinkerLanguage.c_str(); cmTarget *headTarget = head ? head : this;
const char* lang = this->GetLinkClosure(config, headTarget)
->LinkerLanguage.c_str();
return *lang? lang : 0; return *lang? lang : 0;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config) cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config,
cmTarget *head)
{ {
std::string key = cmSystemTools::UpperCase(config? config : ""); TargetConfigPair key(head, cmSystemTools::UpperCase(config ? config : ""));
cmTargetInternals::LinkClosureMapType::iterator cmTargetInternals::LinkClosureMapType::iterator
i = this->Internal->LinkClosureMap.find(key); i = this->Internal->LinkClosureMap.find(key);
if(i == this->Internal->LinkClosureMap.end()) if(i == this->Internal->LinkClosureMap.end())
{ {
LinkClosure lc; LinkClosure lc;
this->ComputeLinkClosure(config, lc); this->ComputeLinkClosure(config, lc, head);
cmTargetInternals::LinkClosureMapType::value_type entry(key, lc); cmTargetInternals::LinkClosureMapType::value_type entry(key, lc);
i = this->Internal->LinkClosureMap.insert(entry).first; i = this->Internal->LinkClosureMap.insert(entry).first;
} }
@ -3133,11 +3149,12 @@ public:
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc) void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc,
cmTarget *head)
{ {
// Get languages built in this target. // Get languages built in this target.
std::set<cmStdString> languages; std::set<cmStdString> languages;
LinkImplementation const* impl = this->GetLinkImplementation(config); LinkImplementation const* impl = this->GetLinkImplementation(config, head);
for(std::vector<std::string>::const_iterator li = impl->Languages.begin(); for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
li != impl->Languages.end(); ++li) li != impl->Languages.end(); ++li)
{ {
@ -3145,7 +3162,7 @@ void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc)
} }
// Add interface languages from linked targets. // Add interface languages from linked targets.
cmTargetCollectLinkLanguages cll(this, config, languages); cmTargetCollectLinkLanguages cll(this, config, languages, head);
for(std::vector<std::string>::const_iterator li = impl->Libraries.begin(); for(std::vector<std::string>::const_iterator li = impl->Libraries.begin();
li != impl->Libraries.end(); ++li) li != impl->Libraries.end(); ++li)
{ {
@ -3284,7 +3301,8 @@ bool cmTarget::HasSOName(const char* config)
return ((this->GetType() == cmTarget::SHARED_LIBRARY || return ((this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY) && this->GetType() == cmTarget::MODULE_LIBRARY) &&
!this->GetPropertyAsBool("NO_SONAME") && !this->GetPropertyAsBool("NO_SONAME") &&
this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config))); this->Makefile->GetSONameFlag(this->GetLinkerLanguage(config,
this)));
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -3293,7 +3311,7 @@ std::string cmTarget::GetSOName(const char* config)
if(this->IsImported()) if(this->IsImported())
{ {
// Lookup the imported soname. // Lookup the imported soname.
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
{ {
if(info->NoSOName) if(info->NoSOName)
{ {
@ -3330,7 +3348,7 @@ bool cmTarget::IsImportedSharedLibWithoutSOName(const char* config)
{ {
if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY) if(this->IsImported() && this->GetType() == cmTarget::SHARED_LIBRARY)
{ {
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
{ {
return info->NoSOName; return info->NoSOName;
} }
@ -3444,7 +3462,7 @@ std::string cmTarget::NormalGetFullPath(const char* config, bool implib,
std::string cmTarget::ImportedGetFullPath(const char* config, bool implib) std::string cmTarget::ImportedGetFullPath(const char* config, bool implib)
{ {
std::string result; std::string result;
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, this))
{ {
result = implib? info->ImportLibrary : info->Location; result = implib? info->ImportLibrary : info->Location;
} }
@ -3529,7 +3547,7 @@ void cmTarget::GetFullNameInternal(const char* config,
const char* suffixVar = this->GetSuffixVariableInternal(implib); const char* suffixVar = this->GetSuffixVariableInternal(implib);
// Check for language-specific default prefix and suffix. // Check for language-specific default prefix and suffix.
if(const char* ll = this->GetLinkerLanguage(config)) if(const char* ll = this->GetLinkerLanguage(config, this))
{ {
if(!targetSuffix && suffixVar && *suffixVar) if(!targetSuffix && suffixVar && *suffixVar)
{ {
@ -3900,7 +3918,7 @@ bool cmTarget::NeedRelinkBeforeInstall(const char* config)
} }
// Check for rpath support on this platform. // Check for rpath support on this platform.
if(const char* ll = this->GetLinkerLanguage(config)) if(const char* ll = this->GetLinkerLanguage(config, this))
{ {
std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
flagVar += ll; flagVar += ll;
@ -4322,7 +4340,7 @@ bool cmTarget::IsChrpathUsed(const char* config)
// Enable if the rpath flag uses a separator and the target uses ELF // Enable if the rpath flag uses a separator and the target uses ELF
// binaries. // binaries.
if(const char* ll = this->GetLinkerLanguage(config)) if(const char* ll = this->GetLinkerLanguage(config, this))
{ {
std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
sepVar += ll; sepVar += ll;
@ -4346,7 +4364,7 @@ bool cmTarget::IsChrpathUsed(const char* config)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget::ImportInfo const* cmTarget::ImportInfo const*
cmTarget::GetImportInfo(const char* config) cmTarget::GetImportInfo(const char* config, cmTarget *headTarget)
{ {
// There is no imported information for non-imported targets. // There is no imported information for non-imported targets.
if(!this->IsImported()) if(!this->IsImported())
@ -4365,14 +4383,16 @@ cmTarget::GetImportInfo(const char* config)
{ {
config_upper = "NOCONFIG"; config_upper = "NOCONFIG";
} }
TargetConfigPair key(headTarget, config_upper);
typedef cmTargetInternals::ImportInfoMapType ImportInfoMapType; typedef cmTargetInternals::ImportInfoMapType ImportInfoMapType;
ImportInfoMapType::const_iterator i = ImportInfoMapType::const_iterator i =
this->Internal->ImportInfoMap.find(config_upper); this->Internal->ImportInfoMap.find(key);
if(i == this->Internal->ImportInfoMap.end()) if(i == this->Internal->ImportInfoMap.end())
{ {
ImportInfo info; ImportInfo info;
this->ComputeImportInfo(config_upper, info); this->ComputeImportInfo(config_upper, info, headTarget);
ImportInfoMapType::value_type entry(config_upper, info); ImportInfoMapType::value_type entry(key, info);
i = this->Internal->ImportInfoMap.insert(entry).first; i = this->Internal->ImportInfoMap.insert(entry).first;
} }
@ -4511,8 +4531,10 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config,
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::ComputeImportInfo(std::string const& desired_config, void cmTarget::ComputeImportInfo(std::string const& desired_config,
ImportInfo& info) ImportInfo& info,
cmTarget *headTarget)
{ {
(void)headTarget;
// This method finds information about an imported target from its // This method finds information about an imported target from its
// properties. The "IMPORTED_" namespace is reserved for properties // properties. The "IMPORTED_" namespace is reserved for properties
// defined by the project exporting the target. // defined by the project exporting the target.
@ -4669,12 +4691,13 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config,
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config) cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config,
cmTarget *head)
{ {
// Imported targets have their own link interface. // Imported targets have their own link interface.
if(this->IsImported()) if(this->IsImported())
{ {
if(cmTarget::ImportInfo const* info = this->GetImportInfo(config)) if(cmTarget::ImportInfo const* info = this->GetImportInfo(config, head))
{ {
return &info->LinkInterface; return &info->LinkInterface;
} }
@ -4690,14 +4713,15 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config)
} }
// Lookup any existing link interface for this configuration. // Lookup any existing link interface for this configuration.
std::string key = cmSystemTools::UpperCase(config? config : ""); TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : ""));
cmTargetInternals::LinkInterfaceMapType::iterator cmTargetInternals::LinkInterfaceMapType::iterator
i = this->Internal->LinkInterfaceMap.find(key); i = this->Internal->LinkInterfaceMap.find(key);
if(i == this->Internal->LinkInterfaceMap.end()) if(i == this->Internal->LinkInterfaceMap.end())
{ {
// Compute the link interface for this configuration. // Compute the link interface for this configuration.
cmTargetInternals::OptionalLinkInterface iface; cmTargetInternals::OptionalLinkInterface iface;
iface.Exists = this->ComputeLinkInterface(config, iface); iface.Exists = this->ComputeLinkInterface(config, iface, head);
// Store the information for this configuration. // Store the information for this configuration.
cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface); cmTargetInternals::LinkInterfaceMapType::value_type entry(key, iface);
@ -4708,7 +4732,8 @@ cmTarget::LinkInterface const* cmTarget::GetLinkInterface(const char* config)
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface) bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface,
cmTarget *headTarget)
{ {
// Construct the property name suffix for this configuration. // Construct the property name suffix for this configuration.
std::string suffix = "_"; std::string suffix = "_";
@ -4765,7 +4790,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
{ {
emitted.insert(*li); emitted.insert(*li);
} }
LinkImplementation const* impl = this->GetLinkImplementation(config); LinkImplementation const* impl = this->GetLinkImplementation(config,
headTarget);
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li) li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li)
{ {
@ -4793,7 +4819,8 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
else else
{ {
// The link implementation is the default link interface. // The link implementation is the default link interface.
LinkImplementation const* impl = this->GetLinkImplementation(config); LinkImplementation const* impl = this->GetLinkImplementation(config,
headTarget);
iface.Libraries = impl->Libraries; iface.Libraries = impl->Libraries;
iface.WrongConfigLibraries = impl->WrongConfigLibraries; iface.WrongConfigLibraries = impl->WrongConfigLibraries;
if(this->GetType() == cmTarget::STATIC_LIBRARY) if(this->GetType() == cmTarget::STATIC_LIBRARY)
@ -4825,7 +4852,7 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmTarget::LinkImplementation const* cmTarget::LinkImplementation const*
cmTarget::GetLinkImplementation(const char* config) cmTarget::GetLinkImplementation(const char* config, cmTarget *head)
{ {
// There is no link implementation for imported targets. // There is no link implementation for imported targets.
if(this->IsImported()) if(this->IsImported())
@ -4834,14 +4861,15 @@ cmTarget::GetLinkImplementation(const char* config)
} }
// Lookup any existing link implementation for this configuration. // Lookup any existing link implementation for this configuration.
std::string key = cmSystemTools::UpperCase(config? config : ""); TargetConfigPair key(head, cmSystemTools::UpperCase(config? config : ""));
cmTargetInternals::LinkImplMapType::iterator cmTargetInternals::LinkImplMapType::iterator
i = this->Internal->LinkImplMap.find(key); i = this->Internal->LinkImplMap.find(key);
if(i == this->Internal->LinkImplMap.end()) if(i == this->Internal->LinkImplMap.end())
{ {
// Compute the link implementation for this configuration. // Compute the link implementation for this configuration.
LinkImplementation impl; LinkImplementation impl;
this->ComputeLinkImplementation(config, impl); this->ComputeLinkImplementation(config, impl, head);
// Store the information for this configuration. // Store the information for this configuration.
cmTargetInternals::LinkImplMapType::value_type entry(key, impl); cmTargetInternals::LinkImplMapType::value_type entry(key, impl);
@ -4853,8 +4881,10 @@ cmTarget::GetLinkImplementation(const char* config)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmTarget::ComputeLinkImplementation(const char* config, void cmTarget::ComputeLinkImplementation(const char* config,
LinkImplementation& impl) LinkImplementation& impl,
cmTarget *head)
{ {
(void)head;
// Compute which library configuration to link. // Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config); cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
@ -4977,16 +5007,19 @@ std::string cmTarget::CheckCMP0004(std::string const& item)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmComputeLinkInformation* cmComputeLinkInformation*
cmTarget::GetLinkInformation(const char* config) cmTarget::GetLinkInformation(const char* config, cmTarget *head)
{ {
cmTarget *headTarget = head ? head : this;
// Lookup any existing information for this configuration. // Lookup any existing information for this configuration.
std::map<cmStdString, cmComputeLinkInformation*>::iterator TargetConfigPair key(headTarget,
i = this->LinkInformation.find(config?config:""); cmSystemTools::UpperCase(config?config:""));
cmTargetLinkInformationMap::iterator
i = this->LinkInformation.find(key);
if(i == this->LinkInformation.end()) if(i == this->LinkInformation.end())
{ {
// Compute information for this configuration. // Compute information for this configuration.
cmComputeLinkInformation* info = cmComputeLinkInformation* info =
new cmComputeLinkInformation(this, config); new cmComputeLinkInformation(this, config, headTarget);
if(!info || !info->Compute()) if(!info || !info->Compute())
{ {
delete info; delete info;
@ -4994,8 +5027,7 @@ cmTarget::GetLinkInformation(const char* config)
} }
// Store the information for this configuration. // Store the information for this configuration.
std::map<cmStdString, cmComputeLinkInformation*>::value_type cmTargetLinkInformationMap::value_type entry(key, info);
entry(config?config:"", info);
i = this->LinkInformation.insert(entry).first; i = this->LinkInformation.insert(entry).first;
} }
return i->second; return i->second;

View File

@ -25,11 +25,13 @@ class cmSourceFile;
class cmGlobalGenerator; class cmGlobalGenerator;
class cmComputeLinkInformation; class cmComputeLinkInformation;
class cmListFileBacktrace; class cmListFileBacktrace;
class cmTarget;
struct cmTargetLinkInformationMap: struct cmTargetLinkInformationMap:
public std::map<cmStdString, cmComputeLinkInformation*> public std::map<std::pair<cmTarget*, std::string>, cmComputeLinkInformation*>
{ {
typedef std::map<cmStdString, cmComputeLinkInformation*> derived; typedef std::map<std::pair<cmTarget*, std::string>,
cmComputeLinkInformation*> derived;
cmTargetLinkInformationMap() {} cmTargetLinkInformationMap() {}
cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r); cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r);
~cmTargetLinkInformationMap(); ~cmTargetLinkInformationMap();
@ -258,7 +260,8 @@ public:
/** Get the link interface for the given configuration. Returns 0 /** Get the link interface for the given configuration. Returns 0
if the target cannot be linked. */ if the target cannot be linked. */
LinkInterface const* GetLinkInterface(const char* config); LinkInterface const* GetLinkInterface(const char* config,
cmTarget *headTarget);
/** The link implementation specifies the direct library /** The link implementation specifies the direct library
dependencies needed by the object files of the target. */ dependencies needed by the object files of the target. */
@ -274,7 +277,8 @@ public:
// Needed only for OLD behavior of CMP0003. // Needed only for OLD behavior of CMP0003.
std::vector<std::string> WrongConfigLibraries; std::vector<std::string> WrongConfigLibraries;
}; };
LinkImplementation const* GetLinkImplementation(const char* config); LinkImplementation const* GetLinkImplementation(const char* config,
cmTarget *head);
/** Link information from the transitive closure of the link /** Link information from the transitive closure of the link
implementation and the interfaces of its dependencies. */ implementation and the interfaces of its dependencies. */
@ -286,7 +290,7 @@ public:
// Languages whose runtime libraries must be linked. // Languages whose runtime libraries must be linked.
std::vector<std::string> Languages; std::vector<std::string> Languages;
}; };
LinkClosure const* GetLinkClosure(const char* config); LinkClosure const* GetLinkClosure(const char* config, cmTarget *head);
/** Strip off leading and trailing whitespace from an item named in /** Strip off leading and trailing whitespace from an item named in
the link dependencies of this target. */ the link dependencies of this target. */
@ -331,7 +335,7 @@ public:
bool FindSourceFiles(); bool FindSourceFiles();
///! Return the preferred linker language for this target ///! Return the preferred linker language for this target
const char* GetLinkerLanguage(const char* config = 0); const char* GetLinkerLanguage(const char* config = 0, cmTarget *head = 0);
/** Get the full name of the target according to the settings in its /** Get the full name of the target according to the settings in its
makefile. */ makefile. */
@ -399,7 +403,8 @@ public:
std::string GetInstallNameDirForInstallTree(const char* config, std::string GetInstallNameDirForInstallTree(const char* config,
bool for_xcode = false); bool for_xcode = false);
cmComputeLinkInformation* GetLinkInformation(const char* config); cmComputeLinkInformation* GetLinkInformation(const char* config,
cmTarget *head = 0);
// Get the properties // Get the properties
cmPropertyMap &GetProperties() { return this->Properties; }; cmPropertyMap &GetProperties() { return this->Properties; };
@ -597,16 +602,19 @@ private:
// Cache import information from properties for each configuration. // Cache import information from properties for each configuration.
struct ImportInfo; struct ImportInfo;
ImportInfo const* GetImportInfo(const char* config); ImportInfo const* GetImportInfo(const char* config,
void ComputeImportInfo(std::string const& desired_config, ImportInfo& info); cmTarget *workingTarget);
void ComputeImportInfo(std::string const& desired_config, ImportInfo& info,
cmTarget *head);
cmTargetLinkInformationMap LinkInformation; cmTargetLinkInformationMap LinkInformation;
bool ComputeLinkInterface(const char* config, LinkInterface& iface); bool ComputeLinkInterface(const char* config, LinkInterface& iface,
cmTarget *head);
void ComputeLinkImplementation(const char* config, void ComputeLinkImplementation(const char* config,
LinkImplementation& impl); LinkImplementation& impl, cmTarget *head);
void ComputeLinkClosure(const char* config, LinkClosure& lc); void ComputeLinkClosure(const char* config, LinkClosure& lc, cmTarget *head);
void ClearLinkMaps(); void ClearLinkMaps();