ENH: Introduce cmTarget::LinkImplementation API

The new method centralizes loops that process raw OriginalLinkLibraries
to extract the link implementation (libraries linked into the target)
for each configuration.  Results are computed on demand and then cached.
This simplifies link interface computation because the default case
trivially copies the link implementation.
This commit is contained in:
Brad King 2009-07-08 12:04:48 -04:00
parent d1aa17a7b0
commit 7c67524dfa
3 changed files with 124 additions and 86 deletions

View File

@ -520,22 +520,15 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
void cmComputeLinkDepends::AddDirectLinkEntries()
{
// Add direct link dependencies in this configuration.
int depender_index = -1;
LinkLibraryVectorType const& libs=this->Target->GetOriginalLinkLibraries();
std::vector<std::string> actual_libs;
for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
li != libs.end(); ++li)
cmTarget::LinkImplementation const* impl =
this->Target->GetLinkImplementation(this->Config);
this->AddLinkEntries(-1, impl->Libraries);
for(std::vector<std::string>::const_iterator
wi = impl->WrongConfigLibraries.begin();
wi != impl->WrongConfigLibraries.end(); ++wi)
{
if(li->second == cmTarget::GENERAL || li->second == this->LinkType)
{
actual_libs.push_back(li->first);
this->CheckWrongConfigItem(-1, *wi);
}
else if(this->OldLinkDirMode)
{
this->CheckWrongConfigItem(depender_index, li->first);
}
}
this->AddLinkEntries(depender_index, actual_libs);
}
//----------------------------------------------------------------------------

View File

@ -81,6 +81,10 @@ public:
typedef std::map<cmStdString, cmTarget::ImportInfo> ImportInfoMapType;
ImportInfoMapType ImportInfoMap;
// Cache link implementation computation from each configuration.
typedef std::map<cmStdString, cmTarget::LinkImplementation> LinkImplMapType;
LinkImplMapType LinkImplMap;
};
//----------------------------------------------------------------------------
@ -3777,76 +3781,33 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
return false;
}
// Is the link interface just the link implementation?
bool doLibraries = !explicitLibraries;
// Do we need to construct a list of shared library dependencies not
// included in the interface?
bool doSharedDeps = (explicitLibraries &&
this->GetType() == cmTarget::SHARED_LIBRARY);
// Keep track of what libraries have been emitted.
std::set<cmStdString> emitted;
std::set<cmStdString> emittedWrongConfig;
if(explicitLibraries)
{
// The interface libraries have been explicitly set.
cmSystemTools::ExpandListArgument(explicitLibraries, iface.Libraries);
if(this->GetType() == cmTarget::SHARED_LIBRARY)
{
// Shared libraries may have runtime implementation dependencies
// on other shared libraries that are not in the interface.
std::set<cmStdString> emitted;
for(std::vector<std::string>::const_iterator
li = iface.Libraries.begin(); li != iface.Libraries.end(); ++li)
{
emitted.insert(*li);
}
}
if(doLibraries || doSharedDeps)
LinkImplementation const* impl = this->GetLinkImplementation(config);
for(std::vector<std::string>::const_iterator
li = impl->Libraries.begin(); li != impl->Libraries.end(); ++li)
{
// Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
// Construct the list of libs linked for this configuration.
cmTarget::LinkLibraryVectorType const& llibs =
this->GetOriginalLinkLibraries();
for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin();
li != llibs.end(); ++li)
if(emitted.insert(*li).second)
{
// Skip entries that resolve to the target itself or are empty.
std::string item = this->CheckCMP0004(li->first);
if(item == this->GetName() || item.empty())
{
continue;
}
// Skip entries not meant for this configuration.
if(li->second != cmTarget::GENERAL && li->second != linkType)
{
// Support OLD behavior for CMP0003.
if(doLibraries && emittedWrongConfig.insert(item).second)
{
iface.WrongConfigLibraries.push_back(item);
}
continue;
}
// Skip entries that have already been emitted.
if(!emitted.insert(item).second)
{
continue;
}
// Emit this item.
if(doLibraries)
{
// This implementation dependency goes in the implicit interface.
iface.Libraries.push_back(item);
}
else if(cmTarget* tgt = this->Makefile->FindTargetToUse(item.c_str()))
if(cmTarget* tgt = this->Makefile->FindTargetToUse(li->c_str()))
{
// This is a runtime dependency on another shared library.
if(tgt->GetType() == cmTarget::SHARED_LIBRARY)
{
iface.SharedDeps.push_back(item);
iface.SharedDeps.push_back(*li);
}
}
else
@ -3858,10 +3819,78 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
}
}
}
}
}
else
{
// The link implementation is the default link interface.
LinkImplementation const* impl = this->GetLinkImplementation(config);
iface.Libraries = impl->Libraries;
iface.WrongConfigLibraries = impl->WrongConfigLibraries;
}
return true;
}
//----------------------------------------------------------------------------
cmTarget::LinkImplementation const*
cmTarget::GetLinkImplementation(const char* config)
{
// There is no link implementation for imported targets.
if(this->IsImported())
{
return 0;
}
// Lookup any existing link implementation for this configuration.
std::string key = cmSystemTools::UpperCase(config? config : "");
cmTargetInternals::LinkImplMapType::iterator
i = this->Internal->LinkImplMap.find(key);
if(i == this->Internal->LinkImplMap.end())
{
// Compute the link implementation for this configuration.
LinkImplementation impl;
this->ComputeLinkImplementation(config, impl);
// Store the information for this configuration.
cmTargetInternals::LinkImplMapType::value_type entry(key, impl);
i = this->Internal->LinkImplMap.insert(entry).first;
}
return &i->second;
}
//----------------------------------------------------------------------------
void cmTarget::ComputeLinkImplementation(const char* config,
LinkImplementation& impl)
{
// Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
LinkLibraryVectorType const& llibs = this->GetOriginalLinkLibraries();
for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin();
li != llibs.end(); ++li)
{
// Skip entries that resolve to the target itself or are empty.
std::string item = this->CheckCMP0004(li->first);
if(item == this->GetName() || item.empty())
{
continue;
}
if(li->second == cmTarget::GENERAL || li->second == linkType)
{
// The entry is meant for this configuration.
impl.Libraries.push_back(item);
}
else
{
// Support OLD behavior for CMP0003.
impl.WrongConfigLibraries.push_back(item);
}
}
}
//----------------------------------------------------------------------------
std::string cmTarget::CheckCMP0004(std::string const& item)
{

View File

@ -255,6 +255,19 @@ public:
if the target cannot be linked. */
LinkInterface const* GetLinkInterface(const char* config);
/** The link implementation specifies the direct library
dependencies needed by the object files of the target. */
struct LinkImplementation
{
// Libraries linked directly in this configuration.
std::vector<std::string> Libraries;
// Libraries linked directly in other configurations.
// Needed only for OLD behavior of CMP0003.
std::vector<std::string> WrongConfigLibraries;
};
LinkImplementation const* GetLinkImplementation(const char* config);
/** Strip off leading and trailing whitespace from an item named in
the link dependencies of this target. */
std::string CheckCMP0004(std::string const& item);
@ -520,6 +533,9 @@ private:
bool ComputeLinkInterface(const char* config, LinkInterface& iface);
void ComputeLinkImplementation(const char* config,
LinkImplementation& impl);
// The cmMakefile instance that owns this target. This should
// always be set.
cmMakefile* Makefile;