cmGeneratorTarget: Move GetLinkClosure from cmTarget.

This commit is contained in:
Stephen Kelly 2015-08-04 19:19:49 +02:00
parent 7c809fa2a6
commit f8076644ce
6 changed files with 255 additions and 238 deletions

View File

@ -19,6 +19,7 @@
#include "cmOutputConverter.h"
#include "cmMakefile.h"
#include "cmTarget.h"
#include "cmGeneratorTarget.h"
#include "cmake.h"
#include "cmAlgorithms.h"
@ -579,8 +580,12 @@ bool cmComputeLinkInformation::Compute()
//----------------------------------------------------------------------------
void cmComputeLinkInformation::AddImplicitLinkInfo()
{
cmGeneratorTarget *gtgt = this->Target->GetMakefile()
->GetGlobalGenerator()
->GetGeneratorTarget(this->Target);
// The link closure lists all languages whose implicit info is needed.
cmTarget::LinkClosure const* lc=this->Target->GetLinkClosure(this->Config);
cmGeneratorTarget::LinkClosure const* lc=gtgt->GetLinkClosure(this->Config);
for(std::vector<std::string>::const_iterator li = lc->Languages.begin();
li != lc->Languages.end(); ++li)
{
@ -2006,8 +2011,12 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
// Add runtime paths required by the languages to always be
// present. This is done even when skipping rpath support.
{
cmTarget::LinkClosure const* lc =
this->Target->GetLinkClosure(this->Config);
cmGeneratorTarget *gtgt = this->Makefile
->GetGlobalGenerator()
->GetGeneratorTarget(this->Target);
cmGeneratorTarget::LinkClosure const* lc =
gtgt->GetLinkClosure(this->Config);
for(std::vector<std::string>::const_iterator li = lc->Languages.begin();
li != lc->Languages.end(); ++li)
{

View File

@ -20,6 +20,7 @@ class cmake;
class cmGlobalGenerator;
class cmMakefile;
class cmTarget;
class cmGeneratorTarget;
class cmOrderDirectories;
/** \class cmComputeLinkInformation

View File

@ -27,6 +27,13 @@
#include <errno.h>
#include "assert.h"
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include <cmsys/hash_set.hxx>
#define UNORDERED_SET cmsys::hash_set
#else
#define UNORDERED_SET std::set
#endif
//----------------------------------------------------------------------------
void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib,
cmTarget *target, cmake *cm)
@ -1025,6 +1032,223 @@ std::string cmGeneratorTarget::GetInstallNameDirForInstallTree() const
}
}
//----------------------------------------------------------------------------
class cmTargetCollectLinkLanguages
{
public:
cmTargetCollectLinkLanguages(cmGeneratorTarget const* target,
const std::string& config,
UNORDERED_SET<std::string>& languages,
cmTarget const* head):
Config(config), Languages(languages), HeadTarget(head),
Makefile(target->Target->GetMakefile()), Target(target)
{ this->Visited.insert(target->Target); }
void Visit(cmLinkItem const& item)
{
if(!item.Target)
{
if(item.find("::") != std::string::npos)
{
bool noMessage = false;
cmake::MessageType messageType = cmake::FATAL_ERROR;
std::stringstream e;
switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0028))
{
case cmPolicies::WARN:
{
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n";
messageType = cmake::AUTHOR_WARNING;
}
break;
case cmPolicies::OLD:
noMessage = true;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
// Issue the fatal message.
break;
}
if(!noMessage)
{
e << "Target \"" << this->Target->GetName()
<< "\" links to target \"" << item
<< "\" but the target was not found. Perhaps a find_package() "
"call is missing for an IMPORTED target, or an ALIAS target is "
"missing?";
this->Makefile->GetCMakeInstance()->IssueMessage(
messageType, e.str(), this->Target->Target->GetBacktrace());
}
}
return;
}
if(!this->Visited.insert(item.Target).second)
{
return;
}
cmTarget::LinkInterface const* iface =
item.Target->GetLinkInterface(this->Config, this->HeadTarget);
if(!iface) { return; }
for(std::vector<std::string>::const_iterator
li = iface->Languages.begin(); li != iface->Languages.end(); ++li)
{
this->Languages.insert(*li);
}
for(std::vector<cmLinkItem>::const_iterator
li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li)
{
this->Visit(*li);
}
}
private:
std::string Config;
UNORDERED_SET<std::string>& Languages;
cmTarget const* HeadTarget;
cmMakefile* Makefile;
const cmGeneratorTarget* Target;
std::set<cmTarget const*> Visited;
};
//----------------------------------------------------------------------------
cmGeneratorTarget::LinkClosure const*
cmGeneratorTarget::GetLinkClosure(const std::string& config) const
{
std::string key(cmSystemTools::UpperCase(config));
LinkClosureMapType::iterator
i = this->LinkClosureMap.find(key);
if(i == this->LinkClosureMap.end())
{
LinkClosure lc;
this->ComputeLinkClosure(config, lc);
LinkClosureMapType::value_type entry(key, lc);
i = this->LinkClosureMap.insert(entry).first;
}
return &i->second;
}
//----------------------------------------------------------------------------
class cmTargetSelectLinker
{
int Preference;
cmGeneratorTarget const* Target;
cmMakefile* Makefile;
cmGlobalGenerator* GG;
std::set<std::string> Preferred;
public:
cmTargetSelectLinker(cmGeneratorTarget const* target)
: Preference(0), Target(target)
{
this->Makefile = this->Target->Makefile;
this->GG = this->Makefile->GetGlobalGenerator();
}
void Consider(const char* lang)
{
int preference = this->GG->GetLinkerPreference(lang);
if(preference > this->Preference)
{
this->Preference = preference;
this->Preferred.clear();
}
if(preference == this->Preference)
{
this->Preferred.insert(lang);
}
}
std::string Choose()
{
if(this->Preferred.empty())
{
return "";
}
else if(this->Preferred.size() > 1)
{
std::stringstream e;
e << "Target " << this->Target->GetName()
<< " contains multiple languages with the highest linker preference"
<< " (" << this->Preference << "):\n";
for(std::set<std::string>::const_iterator
li = this->Preferred.begin(); li != this->Preferred.end(); ++li)
{
e << " " << *li << "\n";
}
e << "Set the LINKER_LANGUAGE property for this target.";
cmake* cm = this->Makefile->GetCMakeInstance();
cm->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->Target->GetBacktrace());
}
return *this->Preferred.begin();
}
};
//----------------------------------------------------------------------------
void cmGeneratorTarget::ComputeLinkClosure(const std::string& config,
LinkClosure& lc) const
{
// Get languages built in this target.
UNORDERED_SET<std::string> languages;
cmTarget::LinkImplementation const* impl =
this->Target->GetLinkImplementation(config);
for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
li != impl->Languages.end(); ++li)
{
languages.insert(*li);
}
// Add interface languages from linked targets.
cmTargetCollectLinkLanguages cll(this, config, languages, this->Target);
for(std::vector<cmLinkImplItem>::const_iterator li = impl->Libraries.begin();
li != impl->Libraries.end(); ++li)
{
cll.Visit(*li);
}
// Store the transitive closure of languages.
for(UNORDERED_SET<std::string>::const_iterator li = languages.begin();
li != languages.end(); ++li)
{
lc.Languages.push_back(*li);
}
// Choose the language whose linker should be used.
if(this->GetProperty("HAS_CXX"))
{
lc.LinkerLanguage = "CXX";
}
else if(const char* linkerLang = this->GetProperty("LINKER_LANGUAGE"))
{
lc.LinkerLanguage = linkerLang;
}
else
{
// Find the language with the highest preference value.
cmTargetSelectLinker tsl(this);
// First select from the languages compiled directly in this target.
for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
li != impl->Languages.end(); ++li)
{
tsl.Consider(li->c_str());
}
// Now consider languages that propagate from linked targets.
for(UNORDERED_SET<std::string>::const_iterator sit = languages.begin();
sit != languages.end(); ++sit)
{
std::string propagates = "CMAKE_"+*sit+"_LINKER_PREFERENCE_PROPAGATES";
if(this->Makefile->IsOn(propagates))
{
tsl.Consider(sit->c_str());
}
}
lc.LinkerLanguage = tsl.Choose();
}
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetFullNameComponents(std::string& prefix,
std::string& base,
@ -2058,7 +2282,7 @@ void cmGeneratorTarget::GetFullNameInternal(const std::string& config,
std::string
cmGeneratorTarget::GetLinkerLanguage(const std::string& config) const
{
return this->Target->GetLinkClosure(config)->LinkerLanguage;
return this->GetLinkClosure(config)->LinkerLanguage;
}
//----------------------------------------------------------------------------

View File

@ -165,6 +165,20 @@ public:
std::string GetModuleDefinitionFile(const std::string& config) const;
/** Link information from the transitive closure of the link
implementation and the interfaces of its dependencies. */
struct LinkClosure
{
// The preferred linker language.
std::string LinkerLanguage;
// Languages whose runtime libraries must be linked.
std::vector<std::string> Languages;
};
LinkClosure const* GetLinkClosure(const std::string& config) const;
void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const;
/** Full path with trailing slash to the top-level directory
holding object files for this target. Includes the build
time config name placeholder if needed for the generator. */
@ -301,6 +315,9 @@ private:
std::string& outPrefix, std::string& outBase,
std::string& outSuffix) const;
typedef std::map<std::string, LinkClosure> LinkClosureMapType;
mutable LinkClosureMapType LinkClosureMap;
struct CompatibleInterfacesBase
{
std::set<std::string> PropsBool;

View File

@ -160,9 +160,6 @@ public:
HeadToLinkImplementationMap> LinkImplMapType;
LinkImplMapType LinkImplMap;
typedef std::map<std::string, cmTarget::LinkClosure> LinkClosureMapType;
LinkClosureMapType LinkClosureMap;
typedef std::map<std::string, std::vector<cmSourceFile*> >
SourceFilesMapType;
SourceFilesMapType SourceFilesMap;
@ -511,7 +508,6 @@ void cmTarget::ClearLinkMaps()
this->Internal->LinkImplMap.clear();
this->Internal->LinkInterfaceMap.clear();
this->Internal->LinkInterfaceUsageRequirementsOnlyMap.clear();
this->Internal->LinkClosureMap.clear();
this->Internal->SourceFilesMap.clear();
}
@ -3135,223 +3131,6 @@ bool cmTarget::GetPropertyAsBool(const std::string& prop) const
return cmSystemTools::IsOn(this->GetProperty(prop));
}
//----------------------------------------------------------------------------
class cmTargetCollectLinkLanguages
{
public:
cmTargetCollectLinkLanguages(cmTarget const* target,
const std::string& config,
UNORDERED_SET<std::string>& languages,
cmTarget const* head):
Config(config), Languages(languages), HeadTarget(head),
Makefile(target->GetMakefile()), Target(target)
{ this->Visited.insert(target); }
void Visit(cmLinkItem const& item)
{
if(!item.Target)
{
if(item.find("::") != std::string::npos)
{
bool noMessage = false;
cmake::MessageType messageType = cmake::FATAL_ERROR;
std::ostringstream e;
switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0028))
{
case cmPolicies::WARN:
{
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n";
messageType = cmake::AUTHOR_WARNING;
}
break;
case cmPolicies::OLD:
noMessage = true;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
// Issue the fatal message.
break;
}
if(!noMessage)
{
e << "Target \"" << this->Target->GetName()
<< "\" links to target \"" << item
<< "\" but the target was not found. Perhaps a find_package() "
"call is missing for an IMPORTED target, or an ALIAS target is "
"missing?";
this->Makefile->GetCMakeInstance()->IssueMessage(messageType,
e.str(),
this->Target->GetBacktrace());
}
}
return;
}
if(!this->Visited.insert(item.Target).second)
{
return;
}
cmTarget::LinkInterface const* iface =
item.Target->GetLinkInterface(this->Config, this->HeadTarget);
if(!iface) { return; }
for(std::vector<std::string>::const_iterator
li = iface->Languages.begin(); li != iface->Languages.end(); ++li)
{
this->Languages.insert(*li);
}
for(std::vector<cmLinkItem>::const_iterator
li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li)
{
this->Visit(*li);
}
}
private:
std::string Config;
UNORDERED_SET<std::string>& Languages;
cmTarget const* HeadTarget;
cmMakefile* Makefile;
const cmTarget* Target;
std::set<cmTarget const*> Visited;
};
//----------------------------------------------------------------------------
cmTarget::LinkClosure const*
cmTarget::GetLinkClosure(const std::string& config) const
{
std::string key(cmSystemTools::UpperCase(config));
cmTargetInternals::LinkClosureMapType::iterator
i = this->Internal->LinkClosureMap.find(key);
if(i == this->Internal->LinkClosureMap.end())
{
LinkClosure lc;
this->ComputeLinkClosure(config, lc);
cmTargetInternals::LinkClosureMapType::value_type entry(key, lc);
i = this->Internal->LinkClosureMap.insert(entry).first;
}
return &i->second;
}
//----------------------------------------------------------------------------
class cmTargetSelectLinker
{
int Preference;
cmTarget const* Target;
cmMakefile* Makefile;
cmGlobalGenerator* GG;
UNORDERED_SET<std::string> Preferred;
public:
cmTargetSelectLinker(cmTarget const* target): Preference(0), Target(target)
{
this->Makefile = this->Target->GetMakefile();
this->GG = this->Makefile->GetGlobalGenerator();
}
void Consider(const std::string& lang)
{
int preference = this->GG->GetLinkerPreference(lang);
if(preference > this->Preference)
{
this->Preference = preference;
this->Preferred.clear();
}
if(preference == this->Preference)
{
this->Preferred.insert(lang);
}
}
std::string Choose()
{
if(this->Preferred.empty())
{
return "";
}
else if(this->Preferred.size() > 1)
{
std::ostringstream e;
e << "Target " << this->Target->GetName()
<< " contains multiple languages with the highest linker preference"
<< " (" << this->Preference << "):\n";
for(UNORDERED_SET<std::string>::const_iterator
li = this->Preferred.begin(); li != this->Preferred.end(); ++li)
{
e << " " << *li << "\n";
}
e << "Set the LINKER_LANGUAGE property for this target.";
cmake* cm = this->Makefile->GetCMakeInstance();
cm->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->GetBacktrace());
}
return *this->Preferred.begin();
}
};
//----------------------------------------------------------------------------
void cmTarget::ComputeLinkClosure(const std::string& config,
LinkClosure& lc) const
{
// Get languages built in this target.
UNORDERED_SET<std::string> languages;
LinkImplementation const* impl = this->GetLinkImplementation(config);
for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
li != impl->Languages.end(); ++li)
{
languages.insert(*li);
}
// Add interface languages from linked targets.
cmTargetCollectLinkLanguages cll(this, config, languages, this);
for(std::vector<cmLinkImplItem>::const_iterator
li = impl->Libraries.begin();
li != impl->Libraries.end(); ++li)
{
cll.Visit(*li);
}
// Store the transitive closure of languages.
for(UNORDERED_SET<std::string>::const_iterator li = languages.begin();
li != languages.end(); ++li)
{
lc.Languages.push_back(*li);
}
// Choose the language whose linker should be used.
if(this->GetProperty("HAS_CXX"))
{
lc.LinkerLanguage = "CXX";
}
else if(const char* linkerLang = this->GetProperty("LINKER_LANGUAGE"))
{
lc.LinkerLanguage = linkerLang;
}
else
{
// Find the language with the highest preference value.
cmTargetSelectLinker tsl(this);
// First select from the languages compiled directly in this target.
for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
li != impl->Languages.end(); ++li)
{
tsl.Consider(*li);
}
// Now consider languages that propagate from linked targets.
for(UNORDERED_SET<std::string>::const_iterator sit = languages.begin();
sit != languages.end(); ++sit)
{
std::string propagates = "CMAKE_"+*sit+"_LINKER_PREFERENCE_PROPAGATES";
if(this->Makefile->IsOn(propagates))
{
tsl.Consider(*sit);
}
}
lc.LinkerLanguage = tsl.Choose();
}
}
//----------------------------------------------------------------------------
void cmTarget::ExpandLinkItems(std::string const& prop,
std::string const& value,

View File

@ -315,18 +315,6 @@ public:
LinkImplementationLibraries const*
GetLinkImplementationLibraries(const std::string& config) const;
/** Link information from the transitive closure of the link
implementation and the interfaces of its dependencies. */
struct LinkClosure
{
// The preferred linker language.
std::string LinkerLanguage;
// Languages whose runtime libraries must be linked.
std::vector<std::string> Languages;
};
LinkClosure const* GetLinkClosure(const std::string& config) const;
cmTarget const* FindTargetToLink(std::string const& name) const;
/** Strip off leading and trailing whitespace from an item named in
@ -662,7 +650,6 @@ private:
LinkImplementationLibraries const*
GetLinkImplementationLibrariesInternal(const std::string& config,
cmTarget const* head) const;
void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const;
void ExpandLinkItems(std::string const& prop, std::string const& value,
std::string const& config, cmTarget const* headTarget,