From a232dbe8d23729e4aeeb3e27fe0a807903e82a62 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 10 Jul 2009 16:51:44 -0400 Subject: [PATCH] BUG: Fix Xcode linker language Xcode does not seem to support direct requests for using the linker for a particular language. It always infers the linker using the languages in the source files. When no user source files compile with target's linker language we add one to help Xcode pick the linker. A typical use case is when a C executable links to a C++ archive. The executable has no C++ source files but we need to use the C++ linker. --- Source/cmGlobalGenerator.h | 6 ++-- Source/cmGlobalXCodeGenerator.cxx | 57 +++++++++++++++++++++++++++++++ Source/cmGlobalXCodeGenerator.h | 2 ++ 3 files changed, 62 insertions(+), 3 deletions(-) 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);