Merge branch 'xcode-object-library' into object-library

* xcode-object-library:
  Xcode: Honor $<TARGET_OBJECTS:...> source expressions
  Build object library targets in Xcode
  Pre-compute object file names before Xcode generation
  Allow txt files as ExtraSources in object library targets
  Add a default source group for object files.
  Xcode: Re-factor some existing methods into "FromPath" variants
  Xcode: Re-factor code into GetObjectsNormalDirectory method
This commit is contained in:
Brad King 2012-03-19 13:11:22 -04:00
commit 821037cf2e
4 changed files with 286 additions and 68 deletions

View File

@ -75,7 +75,10 @@ void cmGeneratorTarget::ClassifySources()
else
{
this->ExtraSources.push_back(sf);
if(isObjLib) { badObjLib.push_back(sf); }
if(isObjLib && cmSystemTools::LowerCase(sf->GetExtension()) != "txt")
{
badObjLib.push_back(sf);
}
}
}

View File

@ -19,6 +19,7 @@
#include "cmComputeLinkInformation.h"
#include "cmSourceFile.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratorTarget.h"
#include <cmsys/auto_ptr.hxx>
@ -294,6 +295,10 @@ void cmGlobalXCodeGenerator::Generate()
}
this->ForceLinkerLanguages();
this->cmGlobalGenerator::Generate();
if(cmSystemTools::GetErrorOccuredFlag())
{
return;
}
for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
{
cmLocalGenerator* root = it->second[0];
@ -408,6 +413,8 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
// this will make sure that when the next target is built
// things are up-to-date
if((target.GetType() == cmTarget::EXECUTABLE ||
// Nope - no post-build for OBJECT_LIRBRARY
// target.GetType() == cmTarget::OBJECT_LIBRARY ||
target.GetType() == cmTarget::STATIC_LIBRARY ||
target.GetType() == cmTarget::SHARED_LIBRARY ||
target.GetType() == cmTarget::MODULE_LIBRARY))
@ -561,14 +568,42 @@ cmXCodeObject* cmGlobalXCodeGenerator
}
//----------------------------------------------------------------------------
cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
cmStdString
GetGroupMapKeyFromPath(cmTarget& cmtarget, const std::string& fullpath)
{
cmStdString key(cmtarget.GetName());
key += "-";
key += sf->GetFullPath();
key += fullpath;
return key;
}
//----------------------------------------------------------------------------
cmStdString
GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
{
return GetGroupMapKeyFromPath(cmtarget, sf->GetFullPath());
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
const std::string &fullpath,
cmTarget& cmtarget,
const std::string &lang)
{
// Using a map and the full path guarantees that we will always get the same
// fileRef object for any given full path.
//
cmXCodeObject* fileRef =
this->CreateXCodeFileReferenceFromPath(fullpath, cmtarget, lang);
cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
buildFile->SetComment(fileRef->GetComment());
buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
return buildFile;
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
@ -603,14 +638,16 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
flags += flagsBuild.GetString();
}
// Using a map and the full path guarantees that we will always get the same
// fileRef object for any given full path.
//
cmXCodeObject* fileRef = this->CreateXCodeFileReference(sf, cmtarget);
const char* lang =
this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
if (!lang)
{
lang = "";
}
cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
buildFile->SetComment(fileRef->GetComment());
buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
cmXCodeObject* buildFile =
this->CreateXCodeSourceFileFromPath(sf->GetFullPath(), cmtarget, lang);
cmXCodeObject* fileRef = buildFile->GetObject("fileRef")->GetObject();
cmXCodeObject* settings =
this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
@ -662,36 +699,12 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
cmTarget& cmtarget)
std::string
GetSourcecodeValueFromFileExtension(const std::string& _ext,
const std::string& lang)
{
std::string fname = sf->GetFullPath();
cmXCodeObject* fileRef = this->FileRefs[fname];
if(!fileRef)
{
fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
std::string comment = fname;
//comment += " in ";
//std::string gname = group->GetObject("name")->GetString();
//comment += gname.substr(1, gname.size()-2);
fileRef->SetComment(fname.c_str());
this->FileRefs[fname] = fileRef;
}
cmStdString key = GetGroupMapKey(cmtarget, sf);
cmXCodeObject* group = this->GroupMap[key];
cmXCodeObject* children = group->GetObject("children");
if (!children->HasObject(fileRef))
{
children->AddObject(fileRef);
}
fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
const char* lang =
this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
std::string ext = cmSystemTools::LowerCase(_ext);
std::string sourcecode = "sourcecode";
std::string ext = sf->GetExtension();
ext = cmSystemTools::LowerCase(ext);
if(ext == "o")
{
@ -726,18 +739,6 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
{
sourcecode += ".cpp.h";
}
else if(lang && strcmp(lang, "CXX") == 0)
{
sourcecode += ".cpp.cpp";
}
else if(lang && strcmp(lang, "C") == 0)
{
sourcecode += ".c.c";
}
else if(lang && strcmp(lang, "Fortran") == 0)
{
sourcecode += ".fortran.f90";
}
else if(ext == "png" || ext == "gif" || ext == "jpg")
{
sourcecode = "image";
@ -746,6 +747,18 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
{
sourcecode += ".text";
}
else if(lang == "CXX")
{
sourcecode += ".cpp.cpp";
}
else if(lang == "C")
{
sourcecode += ".c.c";
}
else if(lang == "Fortran")
{
sourcecode += ".fortran.f90";
}
//else
// {
// // Already specialized above or we leave sourcecode == "sourcecode"
@ -754,11 +767,51 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
// // valid lastKnownFileType value.
// }
return sourcecode;
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
const std::string &fullpath,
cmTarget& cmtarget,
const std::string &lang)
{
std::string fname = fullpath;
cmXCodeObject* fileRef = this->FileRefs[fname];
if(!fileRef)
{
fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
std::string comment = fname;
fileRef->SetComment(fname.c_str());
this->FileRefs[fname] = fileRef;
}
cmStdString key = GetGroupMapKeyFromPath(cmtarget, fullpath);
cmXCodeObject* group = this->GroupMap[key];
cmXCodeObject* children = group->GetObject("children");
if (!children->HasObject(fileRef))
{
children->AddObject(fileRef);
}
fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
// Compute the extension.
std::string ext;
std::string realExt =
cmSystemTools::GetFilenameLastExtension(fullpath);
if(!realExt.empty())
{
// Extension without the leading '.'.
ext = realExt.substr(1);
}
std::string sourcecode = GetSourcecodeValueFromFileExtension(ext, lang);
fileRef->AddAttribute("lastKnownFileType",
this->CreateString(sourcecode.c_str()));
// Store the file path relative to the top of the source tree.
std::string path = this->RelativeToSource(sf->GetFullPath().c_str());
std::string path = this->RelativeToSource(fullpath.c_str());
std::string name = cmSystemTools::GetFilenameName(path.c_str());
const char* sourceTree = (cmSystemTools::FileIsFullPath(path.c_str())?
"<absolute>" : "SOURCE_ROOT");
@ -772,6 +825,22 @@ cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
return fileRef;
}
//----------------------------------------------------------------------------
cmXCodeObject*
cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
cmTarget& cmtarget)
{
const char* lang =
this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
if (!lang)
{
lang = "";
}
return this->CreateXCodeFileReferenceFromPath(
sf->GetFullPath(), cmtarget, lang);
}
//----------------------------------------------------------------------------
bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
{
@ -880,6 +949,20 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
}
}
// Add object library contents as external objects. (Equivalent to
// the externalObjFiles above, except each one is not a cmSourceFile
// within the target.)
std::vector<std::string> objs;
this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs);
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
std::string obj = *oi;
cmXCodeObject* xsf =
this->CreateXCodeSourceFileFromPath(obj, cmtarget, "");
externalObjFiles.push_back(xsf);
}
// some build phases only apply to bundles and/or frameworks
bool isFrameworkTarget = cmtarget.IsFrameworkOnApple();
bool isBundleTarget = cmtarget.GetPropertyAsBool("MACOSX_BUNDLE");
@ -1485,7 +1568,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
std::string defFlags;
bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
(target.GetType() == cmTarget::MODULE_LIBRARY));
bool binary = ((target.GetType() == cmTarget::STATIC_LIBRARY) ||
bool binary = ((target.GetType() == cmTarget::OBJECT_LIBRARY) ||
(target.GetType() == cmTarget::STATIC_LIBRARY) ||
(target.GetType() == cmTarget::EXECUTABLE) ||
shared);
@ -1572,7 +1656,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
}
const char* linkFlagsProp = "LINK_FLAGS";
if(target.GetType() == cmTarget::STATIC_LIBRARY)
if(target.GetType() == cmTarget::OBJECT_LIBRARY ||
target.GetType() == cmTarget::STATIC_LIBRARY)
{
linkFlagsProp = "STATIC_LIBRARY_FLAGS";
}
@ -1626,11 +1711,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
std::string pnprefix;
std::string pnbase;
std::string pnsuffix;
target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
// Store the product name for all target types.
buildSettings->AddAttribute("PRODUCT_NAME",
this->CreateString(pnbase.c_str()));
target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
// Set attributes to specify the proper name for the target.
std::string pndir = this->CurrentMakefile->GetCurrentOutputDirectory();
@ -1654,17 +1736,44 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
this->CreateString(pndir.c_str()));
pndir = target.GetDirectory(configName);
}
buildSettings->AddAttribute("EXECUTABLE_PREFIX",
this->CreateString(pnprefix.c_str()));
buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
this->CreateString(pnsuffix.c_str()));
}
else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
{
pnprefix = "lib";
pnbase = target.GetName();
pnsuffix = ".a";
if(this->XcodeVersion >= 21)
{
std::string pncdir = this->GetObjectsNormalDirectory(
this->CurrentProject, configName, &target);
buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
this->CreateString(pncdir.c_str()));
}
else
{
buildSettings->AddAttribute("OBJROOT",
this->CreateString(pndir.c_str()));
pndir = this->GetObjectsNormalDirectory(
this->CurrentProject, configName, &target);
}
}
// Store the product name for all target types.
buildSettings->AddAttribute("PRODUCT_NAME",
this->CreateString(pnbase.c_str()));
buildSettings->AddAttribute("SYMROOT",
this->CreateString(pndir.c_str()));
// Handle settings for each target type.
switch(target.GetType())
{
case cmTarget::OBJECT_LIBRARY:
case cmTarget::STATIC_LIBRARY:
{
buildSettings->AddAttribute("LIBRARY_STYLE",
@ -2168,6 +2277,7 @@ const char* cmGlobalXCodeGenerator::GetTargetFileType(cmTarget& cmtarget)
{
switch(cmtarget.GetType())
{
case cmTarget::OBJECT_LIBRARY:
case cmTarget::STATIC_LIBRARY:
return "archive.ar";
case cmTarget::MODULE_LIBRARY:
@ -2191,6 +2301,7 @@ const char* cmGlobalXCodeGenerator::GetTargetProductType(cmTarget& cmtarget)
{
switch(cmtarget.GetType())
{
case cmTarget::OBJECT_LIBRARY:
case cmTarget::STATIC_LIBRARY:
return "com.apple.product-type.library.static";
case cmTarget::MODULE_LIBRARY:
@ -2248,7 +2359,17 @@ cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
{
fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
}
std::string fullName = cmtarget.GetFullName(defConfig.c_str());
std::string fullName;
if(cmtarget.GetType() == cmTarget::OBJECT_LIBRARY)
{
fullName = "lib";
fullName += cmtarget.GetName();
fullName += ".a";
}
else
{
fullName = cmtarget.GetFullName(defConfig.c_str());
}
fileRef->AddAttribute("path", this->CreateString(fullName.c_str()));
fileRef->AddAttribute("refType", this->CreateString("0"));
fileRef->AddAttribute("sourceTree",
@ -2453,7 +2574,8 @@ void cmGlobalXCodeGenerator
}
// Skip link information for static libraries.
if(cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
if(cmtarget->GetType() == cmTarget::OBJECT_LIBRARY ||
cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
{
return;
}
@ -2601,6 +2723,7 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
std::vector<cmSourceFile*> classes = cmtarget.GetSourceFiles();
// Put cmSourceFile instances in proper groups:
for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
s != classes.end(); s++)
{
@ -2614,6 +2737,21 @@ void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
cmStdString key = GetGroupMapKey(cmtarget, sf);
this->GroupMap[key] = pbxgroup;
}
// Put OBJECT_LIBRARY objects in proper groups:
std::vector<std::string> objs;
this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs);
for(std::vector<std::string>::const_iterator
oi = objs.begin(); oi != objs.end(); ++oi)
{
std::string const& source = *oi;
cmSourceGroup& sourceGroup =
mf->FindSourceGroup(source.c_str(), sourceGroups);
cmXCodeObject* pbxgroup =
this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
cmStdString key = GetGroupMapKeyFromPath(cmtarget, source);
this->GroupMap[key] = pbxgroup;
}
}
}
}
@ -3045,6 +3183,26 @@ void cmGlobalXCodeGenerator
this->RootObject->AddAttribute("targets", allTargets);
}
//----------------------------------------------------------------------------
std::string
cmGlobalXCodeGenerator::GetObjectsNormalDirectory(
const std::string &projName,
const std::string &configName,
const cmTarget *t) const
{
std::string dir =
t->GetMakefile()->GetCurrentOutputDirectory();
dir += "/";
dir += projName;
dir += ".build/";
dir += configName;
dir += "/";
dir += t->GetName();
dir += ".build/Objects-normal/";
return dir;
}
//----------------------------------------------------------------------------
void
cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
@ -3114,6 +3272,8 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
cmTarget* t =target->GetTarget();
if(t->GetType() == cmTarget::EXECUTABLE ||
// Nope - no post-build for OBJECT_LIRBRARY
// t->GetType() == cmTarget::OBJECT_LIBRARY ||
t->GetType() == cmTarget::STATIC_LIBRARY ||
t->GetType() == cmTarget::SHARED_LIBRARY ||
t->GetType() == cmTarget::MODULE_LIBRARY)
@ -3169,15 +3329,8 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
// then remove those exectuables as well
if(this->Architectures.size() > 1)
{
std::string universal =
t->GetMakefile()->GetCurrentOutputDirectory();
universal += "/";
universal += this->CurrentProject;
universal += ".build/";
universal += configName;
universal += "/";
universal += t->GetName();
universal += ".build/Objects-normal/";
std::string universal = this->GetObjectsNormalDirectory(
this->CurrentProject, configName, t);
for( std::vector<std::string>::iterator arch =
this->Architectures.begin();
arch != this->Architectures.end(); ++arch)
@ -3536,3 +3689,51 @@ bool cmGlobalXCodeGenerator::IsMultiConfig()
// Newer Xcode versions are multi config:
return true;
}
//----------------------------------------------------------------------------
void
cmGlobalXCodeGenerator
::ComputeTargetObjects(cmGeneratorTarget* gt) const
{
// Count the number of object files with each name. Warn about duplicate
// names since Xcode names them uniquely automatically with a numeric suffix
// to avoid exact duplicate file names. Note that Mac file names are not
// typically case sensitive, hence the LowerCase.
std::map<cmStdString, int> counts;
for(std::vector<cmSourceFile*>::const_iterator
si = gt->ObjectSources.begin();
si != gt->ObjectSources.end(); ++si)
{
cmSourceFile* sf = *si;
std::string objectName =
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
objectName += ".o";
std::string objectNameLower = cmSystemTools::LowerCase(objectName);
counts[objectNameLower] += 1;
if (2 == counts[objectNameLower])
{
// TODO: emit warning about duplicate name?
}
gt->Objects[sf] = objectName;
}
const char* configName = this->GetCMakeCFGIntDir();
std::string dir = this->GetObjectsNormalDirectory(
this->CurrentProject, configName, gt->Target);
if(this->XcodeVersion >= 21)
{
dir += "$(CURRENT_ARCH)/";
}
else
{
#ifdef __ppc__
dir += "ppc/";
#endif
#ifdef __i386
dir += "i386/";
#endif
}
gt->ObjectDirectory = dir;
}

View File

@ -153,6 +153,12 @@ private:
std::vector<cmLocalGenerator*>& generators);
void WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
cmXCodeObject* CreateXCodeFileReferenceFromPath(const std::string &fullpath,
cmTarget& cmtarget,
const std::string &lang);
cmXCodeObject* CreateXCodeSourceFileFromPath(const std::string &fullpath,
cmTarget& cmtarget,
const std::string &lang);
cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf,
cmTarget& cmtarget);
cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen,
@ -200,6 +206,13 @@ protected:
std::vector<cmXCodeObject*> XCodeObjects;
cmXCodeObject* RootObject;
private:
void ComputeTargetObjects(cmGeneratorTarget* gt) const;
std::string GetObjectsNormalDirectory(
const std::string &projName,
const std::string &configName,
const cmTarget *t) const;
void addObject(cmXCodeObject *obj);
std::string PostBuildMakeTarget(std::string const& tName,
std::string const& configName);

View File

@ -782,6 +782,7 @@ void cmMakefile::SetLocalGenerator(cmLocalGenerator* lg)
"\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$");
this->AddSourceGroup("CMake Rules", "\\.rule$");
this->AddSourceGroup("Resources", "\\.plist$");
this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
#endif
this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused();