ENH: Centralize default link interface computation

When LINK_INTERFACE_LIBRARIES is not set we use the link implementation
to implicitly define the link interface.  These changes centralize the
decision so that all linkable targets internally have a link interface.
This commit is contained in:
Brad King 2009-07-06 16:25:20 -04:00
parent 26df00f83a
commit 06b0a692f4
6 changed files with 85 additions and 101 deletions

View File

@ -223,7 +223,7 @@ std::vector<cmComputeLinkDepends::LinkEntry> const&
cmComputeLinkDepends::Compute() cmComputeLinkDepends::Compute()
{ {
// Follow the link dependencies of the target to be linked. // Follow the link dependencies of the target to be linked.
this->AddTargetLinkEntries(-1, this->Target->GetOriginalLinkLibraries()); this->AddDirectLinkEntries();
// Complete the breadth-first search of dependencies. // Complete the breadth-first search of dependencies.
while(!this->BFSQueue.empty()) while(!this->BFSQueue.empty())
@ -364,13 +364,14 @@ void cmComputeLinkDepends::FollowLinkEntry(BFSEntry const& qe)
// Handle dependent shared libraries. // Handle dependent shared libraries.
this->QueueSharedDependencies(depender_index, iface->SharedDeps); this->QueueSharedDependencies(depender_index, iface->SharedDeps);
}
else if(!entry.Target->IsImported() && // Support for CMP0003.
entry.Target->GetType() != cmTarget::EXECUTABLE) for(std::vector<std::string>::const_iterator
{ oi = iface->WrongConfigLibraries.begin();
// Use the target's link implementation as the interface. oi != iface->WrongConfigLibraries.end(); ++oi)
this->AddTargetLinkEntries(depender_index, {
entry.Target->GetOriginalLinkLibraries()); this->CheckWrongConfigItem(depender_index, *oi);
}
} }
} }
else else
@ -516,11 +517,11 @@ void cmComputeLinkDepends::AddVarLinkEntries(int depender_index,
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void void cmComputeLinkDepends::AddDirectLinkEntries()
cmComputeLinkDepends::AddTargetLinkEntries(int depender_index,
LinkLibraryVectorType const& libs)
{ {
// Look for entries meant for this configuration. // Add direct link dependencies in this configuration.
int depender_index = -1;
LinkLibraryVectorType const& libs=this->Target->GetOriginalLinkLibraries();
std::vector<std::string> actual_libs; std::vector<std::string> actual_libs;
for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin(); for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
li != libs.end(); ++li) li != libs.end(); ++li)
@ -534,8 +535,6 @@ cmComputeLinkDepends::AddTargetLinkEntries(int depender_index,
this->CheckWrongConfigItem(depender_index, li->first); this->CheckWrongConfigItem(depender_index, li->first);
} }
} }
// Add these entries.
this->AddLinkEntries(depender_index, actual_libs); this->AddLinkEntries(depender_index, actual_libs);
} }

View File

@ -83,8 +83,7 @@ private:
AllocateLinkEntry(std::string const& item); AllocateLinkEntry(std::string const& item);
int AddLinkEntry(int depender_index, std::string const& item); int AddLinkEntry(int depender_index, std::string const& item);
void AddVarLinkEntries(int depender_index, const char* value); void AddVarLinkEntries(int depender_index, const char* value);
void AddTargetLinkEntries(int depender_index, void AddDirectLinkEntries();
LinkLibraryVectorType const& libs);
void AddLinkEntries(int depender_index, void AddLinkEntries(int depender_index,
std::vector<std::string> const& libs); std::vector<std::string> const& libs);
cmTarget* FindTargetToLink(int depender_index, const char* name); cmTarget* FindTargetToLink(int depender_index, const char* name);

View File

@ -150,10 +150,8 @@ cmExportFileGenerator
} }
// Add the transitive link dependencies for this configuration. // Add the transitive link dependencies for this configuration.
if(cmTargetLinkInterface const* iface = if(cmTargetLinkInterface const* iface = target->GetLinkInterface(config))
target->GetLinkInterface(config))
{ {
// This target provides a link interface, so use it.
this->SetImportLinkProperty(suffix, target, this->SetImportLinkProperty(suffix, target,
"IMPORTED_LINK_INTERFACE_LIBRARIES", "IMPORTED_LINK_INTERFACE_LIBRARIES",
iface->Libraries, properties); iface->Libraries, properties);
@ -161,47 +159,6 @@ cmExportFileGenerator
"IMPORTED_LINK_DEPENDENT_LIBRARIES", "IMPORTED_LINK_DEPENDENT_LIBRARIES",
iface->SharedDeps, properties); iface->SharedDeps, properties);
} }
else if(target->GetType() == cmTarget::STATIC_LIBRARY ||
target->GetType() == cmTarget::SHARED_LIBRARY)
{
// The default link interface for static and shared libraries is
// their link implementation library list.
this->SetImportLinkProperties(config, suffix, target, properties);
}
}
//----------------------------------------------------------------------------
void
cmExportFileGenerator
::SetImportLinkProperties(const char* config, std::string const& suffix,
cmTarget* target, ImportPropertyMap& properties)
{
// Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = target->ComputeLinkType(config);
// Construct the list of libs linked for this configuration.
std::vector<std::string> actual_libs;
cmTarget::LinkLibraryVectorType const& libs =
target->GetOriginalLinkLibraries();
for(cmTarget::LinkLibraryVectorType::const_iterator li = libs.begin();
li != libs.end(); ++li)
{
// Skip entries that will resolve to the target itself, are empty,
// or are not meant for this configuration.
if(li->first == target->GetName() || li->first.empty() ||
!(li->second == cmTarget::GENERAL || li->second == linkType))
{
continue;
}
// Store this entry.
actual_libs.push_back(li->first);
}
// Store the entries in the property.
this->SetImportLinkProperty(suffix, target,
"IMPORTED_LINK_INTERFACE_LIBRARIES",
actual_libs, properties);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -67,9 +67,6 @@ protected:
void SetImportDetailProperties(const char* config, void SetImportDetailProperties(const char* config,
std::string const& suffix, cmTarget* target, std::string const& suffix, cmTarget* target,
ImportPropertyMap& properties); ImportPropertyMap& properties);
void SetImportLinkProperties(const char* config,
std::string const& suffix, cmTarget* target,
ImportPropertyMap& properties);
void SetImportLinkProperty(std::string const& suffix, void SetImportLinkProperty(std::string const& suffix,
cmTarget* target, const char* propName, cmTarget* target, const char* propName,
std::vector<std::string> const& libs, std::vector<std::string> const& libs,

View File

@ -3682,10 +3682,10 @@ cmTargetLinkInterface const* cmTarget::GetLinkInterface(const char* config)
return 0; return 0;
} }
// Link interfaces are supported only for shared libraries and // Link interfaces are not supported for executables that do not
// executables that export symbols. // export symbols.
if((this->GetType() != cmTarget::SHARED_LIBRARY && if(this->GetType() == cmTarget::EXECUTABLE &&
!this->IsExecutableWithExports())) !this->IsExecutableWithExports())
{ {
return 0; return 0;
} }
@ -3724,23 +3724,27 @@ cmTarget::ComputeLinkInterface(const char* config)
suffix += "NOCONFIG"; suffix += "NOCONFIG";
} }
// Lookup the link interface libraries. // An explicit list of interface libraries may be set for shared
const char* libs = 0; // libraries and executables that export symbols.
{ const char* explicitLibraries = 0;
// Lookup the per-configuration property. if(this->GetType() == cmTarget::SHARED_LIBRARY ||
std::string propName = "LINK_INTERFACE_LIBRARIES"; this->IsExecutableWithExports())
propName += suffix;
libs = this->GetProperty(propName.c_str());
// If not set, try the generic property.
if(!libs)
{ {
libs = this->GetProperty("LINK_INTERFACE_LIBRARIES"); // Lookup the per-configuration property.
} std::string propName = "LINK_INTERFACE_LIBRARIES";
} propName += suffix;
explicitLibraries = this->GetProperty(propName.c_str());
// If still not set, there is no link interface. // If not set, try the generic property.
if(!libs) if(!explicitLibraries)
{
explicitLibraries = this->GetProperty("LINK_INTERFACE_LIBRARIES");
}
}
// There is no implicit link interface for executables, so if none
// was explicitly set, there is no link interface.
if(!explicitLibraries && this->GetType() == cmTarget::EXECUTABLE)
{ {
return cmsys::auto_ptr<cmTargetLinkInterface>(); return cmsys::auto_ptr<cmTargetLinkInterface>();
} }
@ -3752,23 +3756,31 @@ cmTarget::ComputeLinkInterface(const char* config)
return cmsys::auto_ptr<cmTargetLinkInterface>(); return cmsys::auto_ptr<cmTargetLinkInterface>();
} }
// Expand the list of libraries in the interface. // Is the link interface just the link implementation?
cmSystemTools::ExpandListArgument(libs, iface->Libraries); bool doLibraries = !explicitLibraries;
// Now we need to construct a list of shared library dependencies // Do we need to construct a list of shared library dependencies not
// not included in the interface. // included in the interface?
if(this->GetType() == cmTarget::SHARED_LIBRARY) 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)
{ {
// Use a set to keep track of what libraries have been emitted to // The interface libraries have been explicitly set.
// either list. cmSystemTools::ExpandListArgument(explicitLibraries, iface->Libraries);
std::set<cmStdString> emitted;
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
li = iface->Libraries.begin(); li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li)
li != iface->Libraries.end(); ++li)
{ {
emitted.insert(*li); emitted.insert(*li);
} }
}
if(doLibraries || doSharedDeps)
{
// Compute which library configuration to link. // Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config); cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
@ -3778,26 +3790,42 @@ cmTarget::ComputeLinkInterface(const char* config)
for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin(); for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin();
li != llibs.end(); ++li) li != llibs.end(); ++li)
{ {
// Skip entries that will resolve to the target itself, are empty, // Skip entries that resolve to the target itself or are empty.
// or are not meant for this configuration. std::string item = this->CheckCMP0004(li->first);
if(li->first == this->GetName() || li->first.empty() || if(item == this->GetName() || item.empty())
!(li->second == cmTarget::GENERAL || li->second == linkType))
{ {
continue; continue;
} }
// Skip entries that have already been emitted into either list. // Skip entries not meant for this configuration.
if(!emitted.insert(li->first).second) 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; continue;
} }
// Add this entry if it is a shared library. // Emit this item.
if(cmTarget* tgt = this->Makefile->FindTargetToUse(li->first.c_str())) 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()))
{
// This is a runtime dependency on another shared library.
if(tgt->GetType() == cmTarget::SHARED_LIBRARY) if(tgt->GetType() == cmTarget::SHARED_LIBRARY)
{ {
iface->SharedDeps.push_back(li->first); iface->SharedDeps.push_back(item);
} }
} }
else else

View File

@ -46,6 +46,10 @@ struct cmTargetLinkInterface
// Shared library dependencies needed for linking on some platforms. // Shared library dependencies needed for linking on some platforms.
std::vector<std::string> SharedDeps; std::vector<std::string> SharedDeps;
// Libraries listed for other configurations.
// Needed only for OLD behavior of CMP0003.
std::vector<std::string> WrongConfigLibraries;
}; };
struct cmTargetLinkInterfaceMap: struct cmTargetLinkInterfaceMap: