summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/cmTarget.cxx135
-rw-r--r--Source/cmTarget.h19
2 files changed, 135 insertions, 19 deletions
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 5f2217d..2a20030 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -85,6 +85,9 @@ public:
// Cache link implementation computation from each configuration.
typedef std::map<cmStdString, cmTarget::LinkImplementation> LinkImplMapType;
LinkImplMapType LinkImplMap;
+
+ typedef std::map<cmStdString, cmTarget::LinkClosure> LinkClosureMapType;
+ LinkClosureMapType LinkClosureMap;
};
//----------------------------------------------------------------------------
@@ -2321,22 +2324,106 @@ bool cmTarget::GetPropertyAsBool(const char* prop)
}
//----------------------------------------------------------------------------
-const char* cmTarget::GetLinkerLanguage(const char*)
+class cmTargetCollectLinkLanguages
{
- cmGlobalGenerator* gg =
- this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
- if(this->GetProperty("HAS_CXX"))
+public:
+ cmTargetCollectLinkLanguages(cmTarget* target, const char* config,
+ std::set<cmStdString>& languages):
+ Config(config), Languages(languages) { this->Visited.insert(target); }
+ void Visit(cmTarget* target)
{
- const_cast<cmTarget*>(this)->SetProperty("LINKER_LANGUAGE", "CXX");
+ if(!target || !this->Visited.insert(target).second)
+ {
+ return;
+ }
+
+ cmTarget::LinkInterface const* iface =
+ target->GetLinkInterface(this->Config);
+ if(!iface) { return; }
+
+ for(std::vector<std::string>::const_iterator
+ li = iface->Languages.begin(); li != iface->Languages.end(); ++li)
+ {
+ this->Languages.insert(*li);
+ }
+
+ cmMakefile* mf = target->GetMakefile();
+ for(std::vector<std::string>::const_iterator
+ li = iface->Libraries.begin(); li != iface->Libraries.end(); ++li)
+ {
+ this->Visit(mf->FindTargetToUse(li->c_str()));
+ }
}
- const char* linkerLang = this->GetProperty("LINKER_LANGUAGE");
- if (linkerLang==0)
+private:
+ const char* Config;
+ std::set<cmStdString>& Languages;
+ std::set<cmTarget*> Visited;
+};
+
+//----------------------------------------------------------------------------
+const char* cmTarget::GetLinkerLanguage(const char* config)
+{
+ const char* lang = this->GetLinkClosure(config)->LinkerLanguage.c_str();
+ return *lang? lang : 0;
+}
+
+//----------------------------------------------------------------------------
+cmTarget::LinkClosure const* cmTarget::GetLinkClosure(const char* config)
+{
+ std::string key = cmSystemTools::UpperCase(config? config : "");
+ cmTargetInternals::LinkClosureMapType::iterator
+ i = this->Internal->LinkClosureMap.find(key);
+ if(i == this->Internal->LinkClosureMap.end())
{
- // if the property has not yet been set, collect all languages in the
- // target and then find the language with the highest preference value
- std::set<cmStdString> languages;
- this->GetLanguages(languages);
+ LinkClosure lc;
+ this->ComputeLinkClosure(config, lc);
+ cmTargetInternals::LinkClosureMapType::value_type entry(key, lc);
+ i = this->Internal->LinkClosureMap.insert(entry).first;
+ }
+ return &i->second;
+}
+//----------------------------------------------------------------------------
+void cmTarget::ComputeLinkClosure(const char* config, LinkClosure& lc)
+{
+ // Get languages built in this target.
+ std::set<cmStdString> 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);
+ for(std::vector<std::string>::const_iterator li = impl->Libraries.begin();
+ li != impl->Libraries.end(); ++li)
+ {
+ cll.Visit(this->Makefile->FindTargetToUse(li->c_str()));
+ }
+
+ // Store the transitive closure of languages.
+ for(std::set<cmStdString>::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.
+ cmGlobalGenerator* gg =
+ this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
std::string linkerLangList; // only used for the error message
int maxLinkerPref = 0;
bool multiplePreferedLanguages = false;
@@ -2344,10 +2431,10 @@ const char* cmTarget::GetLinkerLanguage(const char*)
sit != languages.end(); ++sit)
{
int linkerPref = gg->GetLinkerPreference(sit->c_str());
- if ((linkerPref > maxLinkerPref) || (linkerLang==0))
+ if (lc.LinkerLanguage.empty() || (linkerPref > maxLinkerPref))
{
maxLinkerPref = linkerPref;
- linkerLang = sit->c_str();
+ lc.LinkerLanguage = *sit;
linkerLangList = *sit;
multiplePreferedLanguages = false;
}
@@ -2359,21 +2446,16 @@ const char* cmTarget::GetLinkerLanguage(const char*)
}
}
- if (linkerLang!=0)
- {
- const_cast<cmTarget*>(this)->SetProperty("LINKER_LANGUAGE", linkerLang);
- }
if (multiplePreferedLanguages)
{
cmOStringStream err;
err << "Error: Target " << this->Name << " contains multiple languages "
- << "with the highest linker preference (" << maxLinkerPref << "): "
+ << "with the highest linker preference (" << maxLinkerPref << "): "
<< linkerLangList << "\n"
<< "You must set the LINKER_LANGUAGE property for this target.";
cmSystemTools::Error(err.str().c_str());
}
}
- return this->GetProperty("LINKER_LANGUAGE");
}
//----------------------------------------------------------------------------
@@ -3829,6 +3911,11 @@ bool cmTarget::ComputeLinkInterface(const char* config, LinkInterface& iface)
LinkImplementation const* impl = this->GetLinkImplementation(config);
iface.Libraries = impl->Libraries;
iface.WrongConfigLibraries = impl->WrongConfigLibraries;
+ if(this->GetType() == cmTarget::STATIC_LIBRARY)
+ {
+ // Targets using this archive need its language runtime libraries.
+ iface.Languages = impl->Languages;
+ }
}
return true;
@@ -3869,6 +3956,7 @@ void cmTarget::ComputeLinkImplementation(const char* config,
// Compute which library configuration to link.
cmTarget::LinkLibraryType linkType = this->ComputeLinkType(config);
+ // Collect libraries directly linked in this configuration.
LinkLibraryVectorType const& llibs = this->GetOriginalLinkLibraries();
for(cmTarget::LinkLibraryVectorType::const_iterator li = llibs.begin();
li != llibs.end(); ++li)
@@ -3891,6 +3979,15 @@ void cmTarget::ComputeLinkImplementation(const char* config,
impl.WrongConfigLibraries.push_back(item);
}
}
+
+ // This target needs runtime libraries for its source languages.
+ std::set<cmStdString> languages;
+ this->GetLanguages(languages);
+ for(std::set<cmStdString>::iterator li = languages.begin();
+ li != languages.end(); ++li)
+ {
+ impl.Languages.push_back(*li);
+ }
}
//----------------------------------------------------------------------------
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 63e8516..015a3a6 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -240,6 +240,9 @@ public:
other information needed by targets that link to this target. */
struct LinkInterface
{
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+
// Libraries listed in the interface.
std::vector<std::string> Libraries;
@@ -259,6 +262,9 @@ public:
dependencies needed by the object files of the target. */
struct LinkImplementation
{
+ // Languages whose runtime libraries must be linked.
+ std::vector<std::string> Languages;
+
// Libraries linked directly in this configuration.
std::vector<std::string> Libraries;
@@ -268,6 +274,18 @@ public:
};
LinkImplementation const* GetLinkImplementation(const char* config);
+ /** 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 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);
@@ -535,6 +553,7 @@ private:
void ComputeLinkImplementation(const char* config,
LinkImplementation& impl);
+ void ComputeLinkClosure(const char* config, LinkClosure& lc);
// The cmMakefile instance that owns this target. This should
// always be set.