diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 0eb27e4af..4df2d3964 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -317,6 +317,9 @@ protected: // This is computed just before local generators generate. cmTargetManifest TargetManifest; + // All targets in the entire project. + std::map TotalTargets; + private: float FirstTimeProgress; // If you add a new map here, make sure it is copied @@ -328,9 +331,6 @@ private: std::map ExtensionToLanguage; std::map LanguageToLinkerPreference; - // this is used to improve performance - std::map TotalTargets; - // Record hashes for rules and outputs. struct RuleHash { char Data[32]; }; std::map RuleHashes; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 5f22946c3..353fa6e30 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -239,6 +239,7 @@ void cmGlobalXCodeGenerator::Generate() // add ALL_BUILD, INSTALL, etc this->AddExtraTargets(root, it->second); } + this->ForceLinkerLanguages(); this->cmGlobalGenerator::Generate(); for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it) { @@ -968,6 +969,62 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, } } +//---------------------------------------------------------------------------- +void cmGlobalXCodeGenerator::ForceLinkerLanguages() +{ + // This makes sure all targets link using the proper language. + for(std::map::const_iterator + ti = this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti) + { + this->ForceLinkerLanguage(*ti->second); + } +} + +//---------------------------------------------------------------------------- +void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget) +{ + // This matters only for targets that link. + if(cmtarget.GetType() != cmTarget::EXECUTABLE && + cmtarget.GetType() != cmTarget::SHARED_LIBRARY && + cmtarget.GetType() != cmTarget::MODULE_LIBRARY) + { + return; + } + + const char* llang = cmtarget.GetLinkerLanguage("NOCONFIG"); + if(!llang) { return; } + + // If the language is compiled as a source trust Xcode to link with it. + cmTarget::LinkImplementation const* impl = + cmtarget.GetLinkImplementation("NOCONFIG"); + for(std::vector::const_iterator li = impl->Languages.begin(); + li != impl->Languages.end(); ++li) + { + if(*li == llang) { return; } + } + + // Add an empty source file to the target that compiles with the + // linker language. This should convince Xcode to choose the proper + // language. + cmMakefile* mf = cmtarget.GetMakefile(); + std::string fname = mf->GetCurrentOutputDirectory(); + fname += cmake::GetCMakeFilesDirectory(); + fname += "/"; + fname += cmtarget.GetName(); + fname += "-CMakeForceLinker"; + fname += "."; + fname += cmSystemTools::LowerCase(llang); + { + cmGeneratedFileStream fout(fname.c_str()); + fout << "\n"; + } + if(cmSourceFile* sf = mf->GetOrCreateSource(fname.c_str())) + { + sf->SetProperty("LANGUAGE", llang); + cmtarget.AddSourceFile(sf); + } +} + //---------------------------------------------------------------------------- bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf) { diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index ba1529de7..e7bb20c6a 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -128,6 +128,8 @@ private: cmXCodeObject* CreateObjectReference(cmXCodeObject*); cmXCodeObject* CreateXCodeTarget(cmTarget& target, cmXCodeObject* buildPhases); + void ForceLinkerLanguages(); + void ForceLinkerLanguage(cmTarget& cmtarget); const char* GetTargetFileType(cmTarget& cmtarget); const char* GetTargetProductType(cmTarget& cmtarget); std::string AddConfigurations(cmXCodeObject* target, cmTarget& cmtarget);