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.
This commit is contained in:
Brad King 2009-07-10 16:51:44 -04:00
parent bb2228ea1a
commit a232dbe8d2
3 changed files with 62 additions and 3 deletions

View File

@ -317,6 +317,9 @@ protected:
// This is computed just before local generators generate.
cmTargetManifest TargetManifest;
// All targets in the entire project.
std::map<cmStdString,cmTarget *> TotalTargets;
private:
float FirstTimeProgress;
// If you add a new map here, make sure it is copied
@ -328,9 +331,6 @@ private:
std::map<cmStdString, cmStdString> ExtensionToLanguage;
std::map<cmStdString, int> LanguageToLinkerPreference;
// this is used to improve performance
std::map<cmStdString,cmTarget *> TotalTargets;
// Record hashes for rules and outputs.
struct RuleHash { char Data[32]; };
std::map<cmStdString, RuleHash> RuleHashes;

View File

@ -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<cmStdString, cmTarget*>::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<std::string>::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)
{

View File

@ -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);