cmGeneratorTarget: Move GetLinkClosure from cmTarget.
This commit is contained in:
parent
7c809fa2a6
commit
f8076644ce
@ -19,6 +19,7 @@
|
|||||||
#include "cmOutputConverter.h"
|
#include "cmOutputConverter.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmTarget.h"
|
#include "cmTarget.h"
|
||||||
|
#include "cmGeneratorTarget.h"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
#include "cmAlgorithms.h"
|
#include "cmAlgorithms.h"
|
||||||
|
|
||||||
@ -579,8 +580,12 @@ bool cmComputeLinkInformation::Compute()
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeLinkInformation::AddImplicitLinkInfo()
|
void cmComputeLinkInformation::AddImplicitLinkInfo()
|
||||||
{
|
{
|
||||||
|
cmGeneratorTarget *gtgt = this->Target->GetMakefile()
|
||||||
|
->GetGlobalGenerator()
|
||||||
|
->GetGeneratorTarget(this->Target);
|
||||||
|
|
||||||
// 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);
|
cmGeneratorTarget::LinkClosure const* lc=gtgt->GetLinkClosure(this->Config);
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -2006,8 +2011,12 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
|
|||||||
// Add runtime paths required by the languages to always be
|
// Add runtime paths required by the languages to always be
|
||||||
// present. This is done even when skipping rpath support.
|
// present. This is done even when skipping rpath support.
|
||||||
{
|
{
|
||||||
cmTarget::LinkClosure const* lc =
|
cmGeneratorTarget *gtgt = this->Makefile
|
||||||
this->Target->GetLinkClosure(this->Config);
|
->GetGlobalGenerator()
|
||||||
|
->GetGeneratorTarget(this->Target);
|
||||||
|
|
||||||
|
cmGeneratorTarget::LinkClosure const* lc =
|
||||||
|
gtgt->GetLinkClosure(this->Config);
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -20,6 +20,7 @@ class cmake;
|
|||||||
class cmGlobalGenerator;
|
class cmGlobalGenerator;
|
||||||
class cmMakefile;
|
class cmMakefile;
|
||||||
class cmTarget;
|
class cmTarget;
|
||||||
|
class cmGeneratorTarget;
|
||||||
class cmOrderDirectories;
|
class cmOrderDirectories;
|
||||||
|
|
||||||
/** \class cmComputeLinkInformation
|
/** \class cmComputeLinkInformation
|
||||||
|
@ -27,6 +27,13 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "assert.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,
|
void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib,
|
||||||
cmTarget *target, cmake *cm)
|
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,
|
void cmGeneratorTarget::GetFullNameComponents(std::string& prefix,
|
||||||
std::string& base,
|
std::string& base,
|
||||||
@ -2058,7 +2282,7 @@ void cmGeneratorTarget::GetFullNameInternal(const std::string& config,
|
|||||||
std::string
|
std::string
|
||||||
cmGeneratorTarget::GetLinkerLanguage(const std::string& config) const
|
cmGeneratorTarget::GetLinkerLanguage(const std::string& config) const
|
||||||
{
|
{
|
||||||
return this->Target->GetLinkClosure(config)->LinkerLanguage;
|
return this->GetLinkClosure(config)->LinkerLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -165,6 +165,20 @@ public:
|
|||||||
|
|
||||||
std::string GetModuleDefinitionFile(const std::string& config) const;
|
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
|
/** Full path with trailing slash to the top-level directory
|
||||||
holding object files for this target. Includes the build
|
holding object files for this target. Includes the build
|
||||||
time config name placeholder if needed for the generator. */
|
time config name placeholder if needed for the generator. */
|
||||||
@ -301,6 +315,9 @@ private:
|
|||||||
std::string& outPrefix, std::string& outBase,
|
std::string& outPrefix, std::string& outBase,
|
||||||
std::string& outSuffix) const;
|
std::string& outSuffix) const;
|
||||||
|
|
||||||
|
typedef std::map<std::string, LinkClosure> LinkClosureMapType;
|
||||||
|
mutable LinkClosureMapType LinkClosureMap;
|
||||||
|
|
||||||
struct CompatibleInterfacesBase
|
struct CompatibleInterfacesBase
|
||||||
{
|
{
|
||||||
std::set<std::string> PropsBool;
|
std::set<std::string> PropsBool;
|
||||||
|
@ -160,9 +160,6 @@ public:
|
|||||||
HeadToLinkImplementationMap> LinkImplMapType;
|
HeadToLinkImplementationMap> LinkImplMapType;
|
||||||
LinkImplMapType LinkImplMap;
|
LinkImplMapType LinkImplMap;
|
||||||
|
|
||||||
typedef std::map<std::string, cmTarget::LinkClosure> LinkClosureMapType;
|
|
||||||
LinkClosureMapType LinkClosureMap;
|
|
||||||
|
|
||||||
typedef std::map<std::string, std::vector<cmSourceFile*> >
|
typedef std::map<std::string, std::vector<cmSourceFile*> >
|
||||||
SourceFilesMapType;
|
SourceFilesMapType;
|
||||||
SourceFilesMapType SourceFilesMap;
|
SourceFilesMapType SourceFilesMap;
|
||||||
@ -511,7 +508,6 @@ void cmTarget::ClearLinkMaps()
|
|||||||
this->Internal->LinkImplMap.clear();
|
this->Internal->LinkImplMap.clear();
|
||||||
this->Internal->LinkInterfaceMap.clear();
|
this->Internal->LinkInterfaceMap.clear();
|
||||||
this->Internal->LinkInterfaceUsageRequirementsOnlyMap.clear();
|
this->Internal->LinkInterfaceUsageRequirementsOnlyMap.clear();
|
||||||
this->Internal->LinkClosureMap.clear();
|
|
||||||
this->Internal->SourceFilesMap.clear();
|
this->Internal->SourceFilesMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3135,223 +3131,6 @@ bool cmTarget::GetPropertyAsBool(const std::string& prop) const
|
|||||||
return cmSystemTools::IsOn(this->GetProperty(prop));
|
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,
|
void cmTarget::ExpandLinkItems(std::string const& prop,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
|
@ -315,18 +315,6 @@ public:
|
|||||||
LinkImplementationLibraries const*
|
LinkImplementationLibraries const*
|
||||||
GetLinkImplementationLibraries(const std::string& config) 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;
|
cmTarget const* FindTargetToLink(std::string const& name) const;
|
||||||
|
|
||||||
/** Strip off leading and trailing whitespace from an item named in
|
/** Strip off leading and trailing whitespace from an item named in
|
||||||
@ -662,7 +650,6 @@ private:
|
|||||||
LinkImplementationLibraries const*
|
LinkImplementationLibraries const*
|
||||||
GetLinkImplementationLibrariesInternal(const std::string& config,
|
GetLinkImplementationLibrariesInternal(const std::string& config,
|
||||||
cmTarget const* head) const;
|
cmTarget const* head) const;
|
||||||
void ComputeLinkClosure(const std::string& config, LinkClosure& lc) const;
|
|
||||||
|
|
||||||
void ExpandLinkItems(std::string const& prop, std::string const& value,
|
void ExpandLinkItems(std::string const& prop, std::string const& value,
|
||||||
std::string const& config, cmTarget const* headTarget,
|
std::string const& config, cmTarget const* headTarget,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user