diff options
Diffstat (limited to 'Source/cmTarget.cxx')
-rw-r--r-- | Source/cmTarget.cxx | 135 |
1 files changed, 116 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); + } } //---------------------------------------------------------------------------- |