35936433e1
CMake-SourceFile2-bp and CMake-SourceFile2-b-mp1 to trunk. This commit is surrounded by tags CMake-SourceFile2-b-mp1-pre and CMake-SourceFile2-b-mp1-post on the trunk. The changes re-implement cmSourceFile and the use of it to allow instances to be created much earlier. The use of cmSourceFileLocation allows locating a source file referenced by a user to be much simpler and more robust. The two SetName methods are no longer needed so some duplicate code has been removed. The strange "SourceName" stuff is gone. Code that created cmSourceFile instances on the stack and then sent them to cmMakefile::AddSource has been simplified and converted to getting cmSourceFile instances from cmMakefile. The CPluginAPI has preserved the old API through a compatibility interface. Source lists are gone. Targets now get real instances of cmSourceFile right away instead of storing a list of strings until the final pass. TraceVSDependencies has been re-written to avoid the use of SourceName. It is now called TraceDependencies since it is not just for VS. It is now implemented with a helper object which makes the code simpler.
2722 lines
92 KiB
C++
2722 lines
92 KiB
C++
/*=========================================================================
|
|
|
|
Program: CMake - Cross-Platform Makefile Generator
|
|
Module: $RCSfile$
|
|
Language: C++
|
|
Date: $Date$
|
|
Version: $Revision$
|
|
|
|
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
|
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notices for more information.
|
|
|
|
=========================================================================*/
|
|
#include "cmGlobalXCodeGenerator.h"
|
|
#include "cmGlobalXCode21Generator.h"
|
|
#include "cmLocalXCodeGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmXCodeObject.h"
|
|
#include "cmXCode21Object.h"
|
|
#include "cmake.h"
|
|
#include "cmGeneratedFileStream.h"
|
|
#include "cmSourceFile.h"
|
|
#include "cmOrderLinkDirectories.h"
|
|
|
|
#if defined(CMAKE_BUILD_WITH_CMAKE)
|
|
#include "cmXMLParser.h"
|
|
|
|
// parse the xml file storing the installed version of Xcode on
|
|
// the machine
|
|
class cmXcodeVersionParser : public cmXMLParser
|
|
{
|
|
public:
|
|
void StartElement(const char* , const char** )
|
|
{
|
|
this->Data = "";
|
|
}
|
|
void EndElement(const char* name)
|
|
{
|
|
if(strcmp(name, "key") == 0)
|
|
{
|
|
this->Key = this->Data;
|
|
}
|
|
else if(strcmp(name, "string") == 0)
|
|
{
|
|
if(this->Key == "CFBundleShortVersionString")
|
|
{
|
|
this->Version = (int)(10.0 * atof(this->Data.c_str()));
|
|
}
|
|
}
|
|
}
|
|
void CharacterDataHandler(const char* data, int length)
|
|
{
|
|
this->Data.append(data, length);
|
|
}
|
|
int Version;
|
|
std::string Key;
|
|
std::string Data;
|
|
};
|
|
#endif
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmGlobalXCodeGenerator::cmGlobalXCodeGenerator()
|
|
{
|
|
this->FindMakeProgramFile = "CMakeFindXCode.cmake";
|
|
this->RootObject = 0;
|
|
this->MainGroupChildren = 0;
|
|
this->SourcesGroupChildren = 0;
|
|
this->CurrentMakefile = 0;
|
|
this->CurrentLocalGenerator = 0;
|
|
this->XcodeVersion = 15;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmGlobalGenerator* cmGlobalXCodeGenerator::New()
|
|
{
|
|
#if defined(CMAKE_BUILD_WITH_CMAKE)
|
|
cmXcodeVersionParser parser;
|
|
parser.ParseFile
|
|
("/Developer/Applications/Xcode.app/Contents/version.plist");
|
|
if(parser.Version == 15)
|
|
{
|
|
return new cmGlobalXCodeGenerator;
|
|
}
|
|
else if (parser.Version == 20)
|
|
{
|
|
cmSystemTools::Message("Xcode 2.0 not really supported by cmake, "
|
|
"using Xcode 15 generator\n");
|
|
return new cmGlobalXCodeGenerator;
|
|
}
|
|
cmGlobalXCodeGenerator* ret = new cmGlobalXCode21Generator;
|
|
ret->SetVersion(parser.Version);
|
|
return ret;
|
|
#else
|
|
std::cerr << "CMake should be built with cmake to use XCode, "
|
|
"default to Xcode 1.5\n";
|
|
return new cmGlobalXCodeGenerator;
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const&
|
|
lang,
|
|
cmMakefile * mf)
|
|
{
|
|
mf->AddDefinition("XCODE","1");
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
mf->AddCacheDefinition(
|
|
"CMAKE_CONFIGURATION_TYPES",
|
|
"Debug;Release;MinSizeRel;RelWithDebInfo",
|
|
"Semicolon separated list of supported configuration types, "
|
|
"only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
|
|
"anything else will be ignored.",
|
|
cmCacheManager::STRING);
|
|
}
|
|
mf->AddDefinition("CMAKE_GENERATOR_CC", "gcc");
|
|
mf->AddDefinition("CMAKE_GENERATOR_CXX", "g++");
|
|
mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
|
|
// initialize Architectures so it can be used by
|
|
// GetTargetObjectFileDirectories
|
|
this->cmGlobalGenerator::EnableLanguage(lang, mf);
|
|
const char* osxArch =
|
|
mf->GetDefinition("CMAKE_OSX_ARCHITECTURES");
|
|
const char* sysroot =
|
|
mf->GetDefinition("CMAKE_OSX_SYSROOT");
|
|
if(osxArch && sysroot)
|
|
{
|
|
this->Architectures.clear();
|
|
cmSystemTools::ExpandListArgument(std::string(osxArch),
|
|
this->Architectures);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmGlobalXCodeGenerator
|
|
::GenerateBuildCommand(const char* makeProgram,
|
|
const char *projectName,
|
|
const char* additionalOptions,
|
|
const char *targetName,
|
|
const char* config,
|
|
bool ignoreErrors,
|
|
bool)
|
|
{
|
|
// Config is not used yet
|
|
(void) ignoreErrors;
|
|
|
|
// now build the test
|
|
if(makeProgram == 0 || !strlen(makeProgram))
|
|
{
|
|
cmSystemTools::Error(
|
|
"Generator cannot find the appropriate make command.");
|
|
return "";
|
|
}
|
|
std::string makeCommand =
|
|
cmSystemTools::ConvertToOutputPath(makeProgram);
|
|
std::string lowerCaseCommand = makeCommand;
|
|
cmSystemTools::LowerCase(lowerCaseCommand);
|
|
|
|
makeCommand += " -project ";
|
|
makeCommand += projectName;
|
|
makeCommand += ".xcode";
|
|
if(this->XcodeVersion > 20)
|
|
{
|
|
makeCommand += "proj";
|
|
}
|
|
|
|
bool clean = false;
|
|
if ( targetName && strcmp(targetName, "clean") == 0 )
|
|
{
|
|
clean = true;
|
|
targetName = "ALL_BUILD";
|
|
}
|
|
if(clean)
|
|
{
|
|
makeCommand += " clean";
|
|
}
|
|
else
|
|
{
|
|
makeCommand += " build";
|
|
}
|
|
makeCommand += " -target ";
|
|
if (targetName && strlen(targetName))
|
|
{
|
|
makeCommand += targetName;
|
|
}
|
|
else
|
|
{
|
|
makeCommand += "ALL_BUILD";
|
|
}
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
makeCommand += " -buildstyle Development ";
|
|
}
|
|
else
|
|
{
|
|
makeCommand += " -configuration ";
|
|
makeCommand += config?config:"Debug";
|
|
}
|
|
if ( additionalOptions )
|
|
{
|
|
makeCommand += " ";
|
|
makeCommand += additionalOptions;
|
|
}
|
|
return makeCommand;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
///! Create a local generator appropriate to this Global Generator
|
|
cmLocalGenerator *cmGlobalXCodeGenerator::CreateLocalGenerator()
|
|
{
|
|
cmLocalGenerator *lg = new cmLocalXCodeGenerator;
|
|
lg->SetGlobalGenerator(this);
|
|
return lg;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::Generate()
|
|
{
|
|
std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
|
|
// make sure extra targets are added before calling
|
|
// the parent generate which will call trace depends
|
|
for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
|
|
{
|
|
cmLocalGenerator* root = it->second[0];
|
|
this->SetGenerationRoot(root);
|
|
// add ALL_BUILD, INSTALL, etc
|
|
this->AddExtraTargets(root, it->second);
|
|
}
|
|
this->cmGlobalGenerator::Generate();
|
|
for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
|
|
{
|
|
cmLocalGenerator* root = it->second[0];
|
|
this->SetGenerationRoot(root);
|
|
// now create the project
|
|
this->OutputXCodeProject(root, it->second);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
|
|
{
|
|
this->CurrentProject = root->GetMakefile()->GetProjectName();
|
|
this->SetCurrentLocalGenerator(root);
|
|
std::string outDir = this->CurrentMakefile->GetHomeOutputDirectory();
|
|
outDir =cmSystemTools::CollapseFullPath(outDir.c_str());
|
|
cmSystemTools::SplitPath(outDir.c_str(),
|
|
this->ProjectOutputDirectoryComponents);
|
|
|
|
this->CurrentXCodeHackMakefile =
|
|
root->GetMakefile()->GetCurrentOutputDirectory();
|
|
this->CurrentXCodeHackMakefile += "/CMakeScripts";
|
|
cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile.c_str());
|
|
this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
|
|
std::vector<cmLocalGenerator*>& gens)
|
|
{
|
|
cmMakefile* mf = root->GetMakefile();
|
|
// Add ALL_BUILD
|
|
const char* no_working_directory = 0;
|
|
std::vector<std::string> no_depends;
|
|
mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
|
|
no_working_directory,
|
|
"echo", "Build all projects");
|
|
cmTarget* allbuild = mf->FindTarget("ALL_BUILD", false);
|
|
|
|
// Add XCODE depend helper
|
|
std::string dir = mf->GetCurrentOutputDirectory();
|
|
cmCustomCommandLine makecommand;
|
|
makecommand.push_back("make");
|
|
makecommand.push_back("-C");
|
|
makecommand.push_back(dir.c_str());
|
|
makecommand.push_back("-f");
|
|
makecommand.push_back(this->CurrentXCodeHackMakefile.c_str());
|
|
if(this->XcodeVersion > 20)
|
|
{
|
|
makecommand.push_back("all.$(CONFIGURATION)");
|
|
}
|
|
cmCustomCommandLines commandLines;
|
|
commandLines.push_back(makecommand);
|
|
mf->AddUtilityCommand("XCODE_DEPEND_HELPER", true,
|
|
no_working_directory,
|
|
no_depends,
|
|
commandLines);
|
|
|
|
// Add Re-Run CMake rules
|
|
this->CreateReRunCMakeFile(root);
|
|
|
|
// now make the allbuild depend on all the non-utility targets
|
|
// in the project
|
|
for(std::vector<cmLocalGenerator*>::iterator i = gens.begin();
|
|
i != gens.end(); ++i)
|
|
{
|
|
cmLocalGenerator* lg = *i;
|
|
if(this->IsExcluded(root, *i))
|
|
{
|
|
continue;
|
|
}
|
|
cmTargets& tgts = lg->GetMakefile()->GetTargets();
|
|
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
|
|
{
|
|
cmTarget& target = l->second;
|
|
// make all exe, shared libs and modules depend
|
|
// on the XCODE_DEPEND_HELPER target
|
|
if((target.GetType() == cmTarget::EXECUTABLE ||
|
|
target.GetType() == cmTarget::SHARED_LIBRARY ||
|
|
target.GetType() == cmTarget::MODULE_LIBRARY))
|
|
{
|
|
target.AddUtility("XCODE_DEPEND_HELPER");
|
|
}
|
|
if(!target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
|
|
{
|
|
allbuild->AddUtility(target.GetName());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::CreateReRunCMakeFile(cmLocalGenerator* root)
|
|
{
|
|
cmMakefile* mf = root->GetMakefile();
|
|
std::vector<std::string> lfiles = mf->GetListFiles();
|
|
// sort the array
|
|
std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
|
|
std::vector<std::string>::iterator new_end =
|
|
std::unique(lfiles.begin(), lfiles.end());
|
|
lfiles.erase(new_end, lfiles.end());
|
|
std::string dir = mf->GetHomeOutputDirectory();
|
|
this->CurrentReRunCMakeMakefile = dir;
|
|
this->CurrentReRunCMakeMakefile += "/CMakeScripts";
|
|
cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
|
|
this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
|
|
cmGeneratedFileStream makefileStream
|
|
(this->CurrentReRunCMakeMakefile.c_str());
|
|
makefileStream.SetCopyIfDifferent(true);
|
|
makefileStream << "# Generated by CMake, DO NOT EDIT\n";
|
|
makefileStream << cmake::GetCMakeFilesDirectoryPostSlash();
|
|
makefileStream << "cmake.check_cache: ";
|
|
for(std::vector<std::string>::const_iterator i = lfiles.begin();
|
|
i != lfiles.end(); ++i)
|
|
{
|
|
makefileStream << "\\\n" << this->ConvertToRelativeForMake(i->c_str());
|
|
}
|
|
std::string cmake = mf->GetRequiredDefinition("CMAKE_COMMAND");
|
|
makefileStream << "\n\t" << this->ConvertToRelativeForMake(cmake.c_str())
|
|
<< " -H" << this->ConvertToRelativeForMake(
|
|
mf->GetHomeDirectory())
|
|
<< " -B" << this->ConvertToRelativeForMake(
|
|
mf->GetHomeOutputDirectory()) << "\n";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::ClearXCodeObjects()
|
|
{
|
|
this->TargetDoneSet.clear();
|
|
for(unsigned int i = 0; i < this->XCodeObjects.size(); ++i)
|
|
{
|
|
delete this->XCodeObjects[i];
|
|
}
|
|
this->XCodeObjects.clear();
|
|
this->GroupMap.clear();
|
|
this->GroupNameMap.clear();
|
|
this->TargetGroup.clear();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype)
|
|
{
|
|
cmXCodeObject* obj;
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
|
|
}
|
|
else
|
|
{
|
|
obj = new cmXCode21Object(ptype, cmXCodeObject::OBJECT);
|
|
}
|
|
this->XCodeObjects.push_back(obj);
|
|
return obj;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
|
|
{
|
|
cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
|
|
this->XCodeObjects.push_back(obj);
|
|
return obj;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateString(const char* s)
|
|
{
|
|
cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
|
|
obj->SetString(s);
|
|
return obj;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject* cmGlobalXCodeGenerator
|
|
::CreateObjectReference(cmXCodeObject* ref)
|
|
{
|
|
cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
|
|
obj->SetObject(ref);
|
|
return obj;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
|
|
cmSourceFile* sf,
|
|
cmTarget& cmtarget)
|
|
{
|
|
std::string flags;
|
|
// Add flags from source file properties.
|
|
if(cmtarget.GetProperty("COMPILE_FLAGS"))
|
|
{
|
|
lg->AppendFlags(flags, cmtarget.GetProperty("COMPILE_FLAGS"));
|
|
}
|
|
lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
|
|
cmSystemTools::ReplaceString(flags, "\"", "\\\"");
|
|
cmXCodeObject* fileRef =
|
|
this->CreateObject(cmXCodeObject::PBXFileReference);
|
|
|
|
cmXCodeObject* group = this->GroupMap[sf];
|
|
cmXCodeObject* children = group->GetObject("children");
|
|
children->AddObject(fileRef);
|
|
cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
|
|
std::string fname = sf->GetFullPath();
|
|
std::string comment = fname;
|
|
comment += " in ";
|
|
std::string gname = group->GetObject("name")->GetString();
|
|
comment += gname.substr(1, gname.size()-2);
|
|
buildFile->SetComment(comment.c_str());
|
|
fileRef->SetComment(fname.c_str());
|
|
buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
|
|
cmXCodeObject* settings =
|
|
this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
settings->AddAttribute("COMPILER_FLAGS", this->CreateString(flags.c_str()));
|
|
buildFile->AddAttribute("settings", settings);
|
|
fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
|
|
const char* lang =
|
|
this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
|
|
std::string sourcecode = "sourcecode";
|
|
std::string ext = sf->GetExtension();
|
|
ext = cmSystemTools::LowerCase(ext);
|
|
if(ext == "o")
|
|
{
|
|
sourcecode = "compiled.mach-o.objfile";
|
|
}
|
|
else if(ext == "mm")
|
|
{
|
|
sourcecode += ".cpp.objcpp";
|
|
}
|
|
else if(ext == "m")
|
|
{
|
|
sourcecode += ".cpp.objc";
|
|
}
|
|
else if(ext == "plist")
|
|
{
|
|
sourcecode += ".text.plist";
|
|
}
|
|
else if(!lang)
|
|
{
|
|
sourcecode += ext;
|
|
sourcecode += ".";
|
|
sourcecode += ext;
|
|
}
|
|
else if(strcmp(lang, "C") == 0)
|
|
{
|
|
sourcecode += ".c.c";
|
|
}
|
|
else if(strcmp(lang, "CXX") == 0)
|
|
{
|
|
sourcecode += ".cpp.cpp";
|
|
}
|
|
else
|
|
{
|
|
sourcecode += ext;
|
|
sourcecode += ".";
|
|
sourcecode += ext;
|
|
}
|
|
fileRef->AddAttribute("lastKnownFileType",
|
|
this->CreateString(sourcecode.c_str()));
|
|
std::string path =
|
|
this->ConvertToRelativeForXCode(sf->GetFullPath().c_str());
|
|
std::string dir;
|
|
std::string file;
|
|
cmSystemTools::SplitProgramPath(sf->GetFullPath().c_str(),
|
|
dir, file);
|
|
|
|
fileRef->AddAttribute("name", this->CreateString(file.c_str()));
|
|
fileRef->AddAttribute("path", this->CreateString(path.c_str()));
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
fileRef->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
if(path.size() > 1 && path[0] == '.' && path[1] == '.')
|
|
{
|
|
fileRef->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
}
|
|
else
|
|
{
|
|
fileRef->AddAttribute("sourceTree", this->CreateString("<absolute>"));
|
|
}
|
|
return buildFile;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
|
|
{
|
|
if(tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
|
|
tname == "install" || tname == "RUN_TESTS" )
|
|
{
|
|
if(this->TargetDoneSet.find(tname) != this->TargetDoneSet.end())
|
|
{
|
|
return true;
|
|
}
|
|
this->TargetDoneSet.insert(tname);
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
|
|
{
|
|
this->CurrentLocalGenerator = gen;
|
|
this->CurrentMakefile = gen->GetMakefile();
|
|
std::string outdir =
|
|
cmSystemTools::CollapseFullPath(this->CurrentMakefile->
|
|
GetCurrentOutputDirectory());
|
|
cmSystemTools::SplitPath(outdir.c_str(),
|
|
this->CurrentOutputDirectoryComponents);
|
|
|
|
// Select the current set of configuration types.
|
|
this->CurrentConfigurationTypes.clear();
|
|
if(this->XcodeVersion > 20)
|
|
{
|
|
if(const char* types =
|
|
this->CurrentMakefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
|
|
{
|
|
cmSystemTools::ExpandListArgument(types,
|
|
this->CurrentConfigurationTypes);
|
|
}
|
|
}
|
|
if(this->CurrentConfigurationTypes.empty())
|
|
{
|
|
if(const char* buildType =
|
|
this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE"))
|
|
{
|
|
this->CurrentConfigurationTypes.push_back(buildType);
|
|
}
|
|
else
|
|
{
|
|
this->CurrentConfigurationTypes.push_back("");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
|
|
std::vector<cmXCodeObject*>&
|
|
targets)
|
|
{
|
|
this->SetCurrentLocalGenerator(gen);
|
|
cmTargets &tgts = this->CurrentMakefile->GetTargets();
|
|
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
|
|
{
|
|
cmTarget& cmtarget = l->second;
|
|
// make sure ALL_BUILD, INSTALL, etc are only done once
|
|
if(this->SpecialTargetEmitted(l->first.c_str()))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(cmtarget.GetType() == cmTarget::UTILITY ||
|
|
cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
|
|
{
|
|
targets.push_back(this->CreateUtilityTarget(cmtarget));
|
|
continue;
|
|
}
|
|
|
|
// create source build phase
|
|
cmXCodeObject* sourceBuildPhase =
|
|
this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
|
|
sourceBuildPhase->AddAttribute("buildActionMask",
|
|
this->CreateString("2147483647"));
|
|
sourceBuildPhase->SetComment("Sources");
|
|
cmXCodeObject* buildFiles =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
sourceBuildPhase->AddAttribute("files", buildFiles);
|
|
sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
|
|
this->CreateString("0"));
|
|
std::vector<cmSourceFile*> const &classes = l->second.GetSourceFiles();
|
|
// add all the sources
|
|
std::vector<cmXCodeObject*> externalObjFiles;
|
|
std::vector<cmXCodeObject*> headerFiles;
|
|
std::vector<cmXCodeObject*> specialBundleFiles;
|
|
for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
|
|
i != classes.end(); ++i)
|
|
{
|
|
cmXCodeObject* xsf =
|
|
this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
|
|
*i, cmtarget);
|
|
cmXCodeObject* fr = xsf->GetObject("fileRef");
|
|
cmXCodeObject* filetype =
|
|
fr->GetObject()->GetObject("lastKnownFileType");
|
|
if(strcmp(filetype->GetString(), "\"compiled.mach-o.objfile\"") == 0)
|
|
{
|
|
externalObjFiles.push_back(xsf);
|
|
}
|
|
else if((*i)->GetPropertyAsBool("HEADER_FILE_ONLY"))
|
|
{
|
|
headerFiles.push_back(xsf);
|
|
}
|
|
else
|
|
{
|
|
buildFiles->AddObject(xsf);
|
|
}
|
|
}
|
|
// create header build phase
|
|
cmXCodeObject* headerBuildPhase =
|
|
this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
|
|
headerBuildPhase->SetComment("Headers");
|
|
headerBuildPhase->AddAttribute("buildActionMask",
|
|
this->CreateString("2147483647"));
|
|
buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
for(std::vector<cmXCodeObject*>::iterator i = headerFiles.begin();
|
|
i != headerFiles.end(); ++i)
|
|
{
|
|
buildFiles->AddObject(*i);
|
|
}
|
|
headerBuildPhase->AddAttribute("files", buildFiles);
|
|
headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
|
|
this->CreateString("0"));
|
|
|
|
// create framework build phase
|
|
cmXCodeObject* frameworkBuildPhase =
|
|
this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
|
|
frameworkBuildPhase->SetComment("Frameworks");
|
|
frameworkBuildPhase->AddAttribute("buildActionMask",
|
|
this->CreateString("2147483647"));
|
|
buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
frameworkBuildPhase->AddAttribute("files", buildFiles);
|
|
for(std::vector<cmXCodeObject*>::iterator i = externalObjFiles.begin();
|
|
i != externalObjFiles.end(); ++i)
|
|
{
|
|
buildFiles->AddObject(*i);
|
|
}
|
|
frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
|
|
this->CreateString("0"));
|
|
cmXCodeObject* buildPhases =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
this->CreateCustomCommands(buildPhases, sourceBuildPhase,
|
|
headerBuildPhase, frameworkBuildPhase,
|
|
cmtarget);
|
|
targets.push_back(this->CreateXCodeTarget(l->second, buildPhases));
|
|
|
|
// copy files build phase
|
|
typedef std::map<cmStdString, std::vector<cmSourceFile*> >
|
|
mapOfVectorOfSourceFiles;
|
|
mapOfVectorOfSourceFiles bundleFiles;
|
|
for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
|
|
i != classes.end(); ++i)
|
|
{
|
|
const char* resLoc = (*i)->GetProperty("MACOSX_PACKAGE_LOCATION");
|
|
if ( !resLoc )
|
|
{
|
|
continue;
|
|
}
|
|
bundleFiles[resLoc].push_back(*i);
|
|
}
|
|
mapOfVectorOfSourceFiles::iterator mit;
|
|
for ( mit = bundleFiles.begin(); mit != bundleFiles.end(); ++ mit )
|
|
{
|
|
cmXCodeObject* copyFilesBuildPhase;
|
|
if ( mit->first == "Resources" )
|
|
{
|
|
copyFilesBuildPhase
|
|
= this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
|
|
}
|
|
else
|
|
{
|
|
copyFilesBuildPhase
|
|
= this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
|
|
copyFilesBuildPhase->SetComment("Copy files");
|
|
copyFilesBuildPhase->AddAttribute("buildActionMask",
|
|
this->CreateString("2147483647"));
|
|
copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
|
|
this->CreateString("6"));
|
|
cmOStringStream ostr;
|
|
if ( mit->first != "MacOS" )
|
|
{
|
|
ostr << "../" << mit->first.c_str();
|
|
}
|
|
copyFilesBuildPhase->AddAttribute("dstPath",
|
|
this->CreateString(ostr.str().c_str()));
|
|
}
|
|
copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
|
|
this->CreateString("0"));
|
|
buildPhases->AddObject(copyFilesBuildPhase);
|
|
buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
copyFilesBuildPhase->AddAttribute("files", buildFiles);
|
|
std::vector<cmSourceFile*>::iterator sfIt;
|
|
for ( sfIt = mit->second.begin(); sfIt != mit->second.end(); ++ sfIt )
|
|
{
|
|
cmXCodeObject* xsf =
|
|
this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
|
|
*sfIt, cmtarget);
|
|
buildFiles->AddObject(xsf);
|
|
}
|
|
}
|
|
if(cmtarget.GetPropertyAsBool("FRAMEWORK"))
|
|
{
|
|
this->AddFrameworkPhases(&cmtarget, buildPhases);
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::AddFrameworkPhases(cmTarget* target,
|
|
cmXCodeObject* buildPhases)
|
|
{
|
|
const char* headers = target->GetProperty("FRAMEWORK_PUBLIC_HEADERS");
|
|
if(!headers)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cmXCodeObject* copyHeaders =
|
|
this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
|
|
copyHeaders->SetComment("Copy files");
|
|
copyHeaders->AddAttribute("buildActionMask",
|
|
this->CreateString("2147483647"));
|
|
copyHeaders->AddAttribute("dstSubfolderSpec",
|
|
this->CreateString("6"));
|
|
copyHeaders->AddAttribute("dstPath",
|
|
this->CreateString("Headers"));
|
|
buildPhases->AddObject(copyHeaders);
|
|
cmXCodeObject* headersToCopy =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
copyHeaders->AddAttribute("files", headersToCopy);
|
|
std::vector<std::string> headersVec;
|
|
cmSystemTools::ExpandListArgument(headers,
|
|
headersVec);
|
|
cmCustomCommandLines commandLines;
|
|
std::vector<std::string> depends;
|
|
for(std::vector<std::string>::iterator i = headersVec.begin();
|
|
i != headersVec.end(); ++i)
|
|
{
|
|
cmCustomCommandLine line;
|
|
cmSourceFile* sf = this->CurrentMakefile->GetOrCreateSource(i->c_str());
|
|
cmXCodeObject* xsf =
|
|
this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
|
|
sf, *target);
|
|
//std::cerr << "copy header " << sf->GetFullPath() << "\n";
|
|
headersToCopy->AddObject(xsf);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateBuildPhase(const char* name,
|
|
const char* name2,
|
|
cmTarget& cmtarget,
|
|
const std::vector<cmCustomCommand>&
|
|
commands)
|
|
{
|
|
if(commands.size() == 0 && strcmp(name, "CMake ReRun") != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
cmXCodeObject* buildPhase =
|
|
this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
|
|
buildPhase->AddAttribute("buildActionMask",
|
|
this->CreateString("2147483647"));
|
|
cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
buildPhase->AddAttribute("files", buildFiles);
|
|
buildPhase->AddAttribute("name",
|
|
this->CreateString(name));
|
|
buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
|
|
this->CreateString("0"));
|
|
buildPhase->AddAttribute("shellPath",
|
|
this->CreateString("/bin/sh"));
|
|
this->AddCommandsToBuildPhase(buildPhase, cmtarget, commands,
|
|
name2);
|
|
return buildPhase;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases,
|
|
cmXCodeObject*
|
|
sourceBuildPhase,
|
|
cmXCodeObject*
|
|
headerBuildPhase,
|
|
cmXCodeObject*
|
|
frameworkBuildPhase,
|
|
cmTarget& cmtarget)
|
|
{
|
|
std::vector<cmCustomCommand> const & prebuild
|
|
= cmtarget.GetPreBuildCommands();
|
|
std::vector<cmCustomCommand> const & prelink
|
|
= cmtarget.GetPreLinkCommands();
|
|
std::vector<cmCustomCommand> const & postbuild
|
|
= cmtarget.GetPostBuildCommands();
|
|
std::vector<cmSourceFile*>const &classes = cmtarget.GetSourceFiles();
|
|
// add all the sources
|
|
std::vector<cmCustomCommand> commands;
|
|
for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
|
|
i != classes.end(); ++i)
|
|
{
|
|
if((*i)->GetCustomCommand())
|
|
{
|
|
commands.push_back(*(*i)->GetCustomCommand());
|
|
}
|
|
}
|
|
std::vector<cmCustomCommand> reruncom;
|
|
cmXCodeObject* cmakeReRunPhase =
|
|
this->CreateBuildPhase("CMake ReRun", "cmakeReRunPhase",
|
|
cmtarget, reruncom);
|
|
buildPhases->AddObject(cmakeReRunPhase);
|
|
// create prebuild phase
|
|
cmXCodeObject* cmakeRulesBuildPhase =
|
|
this->CreateBuildPhase("CMake Rules",
|
|
"cmakeRulesBuildPhase",
|
|
cmtarget, commands);
|
|
// create prebuild phase
|
|
cmXCodeObject* preBuildPhase =
|
|
this->CreateBuildPhase("CMake PreBuild Rules", "preBuildCommands",
|
|
cmtarget, prebuild);
|
|
// create prebuild phase
|
|
cmXCodeObject* preLinkPhase =
|
|
this->CreateBuildPhase("CMake PreLink Rules", "preLinkCommands",
|
|
cmtarget, prelink);
|
|
// create prebuild phase
|
|
cmXCodeObject* postBuildPhase =
|
|
this->CreateBuildPhase("CMake PostBuild Rules", "postBuildPhase",
|
|
cmtarget, postbuild);
|
|
// the order here is the order they will be built in
|
|
if(preBuildPhase)
|
|
{
|
|
buildPhases->AddObject(preBuildPhase);
|
|
}
|
|
if(cmakeRulesBuildPhase)
|
|
{
|
|
buildPhases->AddObject(cmakeRulesBuildPhase);
|
|
}
|
|
if(sourceBuildPhase)
|
|
{
|
|
buildPhases->AddObject(sourceBuildPhase);
|
|
}
|
|
if(headerBuildPhase)
|
|
{
|
|
buildPhases->AddObject(headerBuildPhase);
|
|
}
|
|
if(preLinkPhase)
|
|
{
|
|
buildPhases->AddObject(preLinkPhase);
|
|
}
|
|
if(frameworkBuildPhase)
|
|
{
|
|
buildPhases->AddObject(frameworkBuildPhase);
|
|
}
|
|
if(postBuildPhase)
|
|
{
|
|
buildPhases->AddObject(postBuildPhase);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
|
|
std::string& flags)
|
|
{
|
|
std::string retFlag;
|
|
std::string::size_type pos = flags.find(flag);
|
|
if(pos != flags.npos)
|
|
{
|
|
while(pos < flags.size() && flags[pos] != ' ')
|
|
{
|
|
retFlag += flags[pos];
|
|
flags[pos] = ' ';
|
|
pos++;
|
|
}
|
|
}
|
|
return retFlag;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
|
|
cmTarget& target,
|
|
std::vector<cmCustomCommand>
|
|
const & commands,
|
|
const char* name)
|
|
{
|
|
if(strcmp(name, "cmakeReRunPhase") == 0)
|
|
{
|
|
std::string cdir = this->CurrentMakefile->GetHomeOutputDirectory();
|
|
cdir = this->ConvertToRelativeForMake(cdir.c_str());
|
|
std::string makecmd = "make -C ";
|
|
makecmd += cdir;
|
|
makecmd += " -f ";
|
|
makecmd +=
|
|
this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str());
|
|
cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
|
|
buildphase->AddAttribute("shellScript",
|
|
this->CreateString(makecmd.c_str()));
|
|
return;
|
|
}
|
|
|
|
// collect multiple outputs of custom commands into a set
|
|
// which will be used for every configuration
|
|
std::map<cmStdString, cmStdString> multipleOutputPairs;
|
|
for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
|
|
i != commands.end(); ++i)
|
|
{
|
|
cmCustomCommand const& cc = *i;
|
|
if(!cc.GetCommandLines().empty())
|
|
{
|
|
const std::vector<std::string>& outputs = cc.GetOutputs();
|
|
if(!outputs.empty())
|
|
{
|
|
// If there are more than one outputs treat the
|
|
// first as the primary output and make the rest depend on it.
|
|
std::vector<std::string>::const_iterator o = outputs.begin();
|
|
std::string primaryOutput = this->ConvertToRelativeForMake(o->c_str());
|
|
for(++o; o != outputs.end(); ++o)
|
|
{
|
|
std::string currentOutput=this->ConvertToRelativeForMake(o->c_str());
|
|
multipleOutputPairs[currentOutput] = primaryOutput;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
|
|
dir += "/CMakeScripts";
|
|
cmSystemTools::MakeDirectory(dir.c_str());
|
|
std::string makefile = dir;
|
|
makefile += "/";
|
|
makefile += target.GetName();
|
|
makefile += "_";
|
|
makefile += name;
|
|
makefile += ".make";
|
|
|
|
for (std::vector<std::string>::const_iterator currentConfig=
|
|
this->CurrentConfigurationTypes.begin();
|
|
currentConfig!=this->CurrentConfigurationTypes.end();
|
|
currentConfig++ )
|
|
{
|
|
this->CreateCustomRulesMakefile(makefile.c_str(),
|
|
target,
|
|
commands,
|
|
currentConfig->c_str(),
|
|
multipleOutputPairs);
|
|
}
|
|
|
|
std::string cdir = this->CurrentMakefile->GetCurrentOutputDirectory();
|
|
cdir = this->ConvertToRelativeForXCode(cdir.c_str());
|
|
std::string makecmd = "make -C ";
|
|
makecmd += cdir;
|
|
makecmd += " -f ";
|
|
makecmd += this->ConvertToRelativeForMake(
|
|
(makefile+"$CONFIGURATION").c_str());
|
|
if(!multipleOutputPairs.empty())
|
|
{
|
|
makecmd += " cmake_check_multiple_outputs";
|
|
}
|
|
makecmd += " all";
|
|
cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
|
|
buildphase->AddAttribute("shellScript",
|
|
this->CreateString(makecmd.c_str()));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator
|
|
::CreateCustomRulesMakefile(const char* makefileBasename,
|
|
cmTarget& target,
|
|
std::vector<cmCustomCommand>
|
|
const & commands,
|
|
const char* configName,
|
|
const std::map<cmStdString,
|
|
cmStdString>& multipleOutputPairs
|
|
)
|
|
{
|
|
std::string makefileName=makefileBasename;
|
|
makefileName+=configName;
|
|
cmGeneratedFileStream makefileStream(makefileName.c_str());
|
|
if(!makefileStream)
|
|
{
|
|
return;
|
|
}
|
|
makefileStream.SetCopyIfDifferent(true);
|
|
makefileStream << "# Generated by CMake, DO NOT EDIT\n";
|
|
makefileStream << "# Custom rules for " << target.GetName() << "\n";
|
|
|
|
// have all depend on all outputs
|
|
makefileStream << "all: ";
|
|
std::map<const cmCustomCommand*, cmStdString> tname;
|
|
int count = 0;
|
|
for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
|
|
i != commands.end(); ++i)
|
|
{
|
|
cmCustomCommand const& cc = *i;
|
|
if(!cc.GetCommandLines().empty())
|
|
{
|
|
const std::vector<std::string>& outputs = cc.GetOutputs();
|
|
if(!outputs.empty())
|
|
{
|
|
for(std::vector<std::string>::const_iterator o = outputs.begin();
|
|
o != outputs.end(); ++o)
|
|
{
|
|
makefileStream
|
|
<< "\\\n\t" << this->ConvertToRelativeForMake(o->c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cmOStringStream str;
|
|
str << "_buildpart_" << count++ ;
|
|
tname[&cc] = std::string(target.GetName()) + str.str();
|
|
makefileStream << "\\\n\t" << tname[&cc];
|
|
}
|
|
}
|
|
}
|
|
makefileStream << "\n\n";
|
|
for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
|
|
i != commands.end(); ++i)
|
|
{
|
|
cmCustomCommand const& cc = *i;
|
|
if(!cc.GetCommandLines().empty())
|
|
{
|
|
bool escapeOldStyle = cc.GetEscapeOldStyle();
|
|
bool escapeAllowMakeVars = cc.GetEscapeAllowMakeVars();
|
|
makefileStream << "\n#" << "Custom command rule: ";
|
|
if(cc.GetComment())
|
|
{
|
|
makefileStream << cc.GetComment();
|
|
}
|
|
makefileStream << "\n";
|
|
const std::vector<std::string>& outputs = cc.GetOutputs();
|
|
if(!outputs.empty())
|
|
{
|
|
// There is at least one output, start the rule for it
|
|
std::string primary_output =
|
|
this->ConvertToRelativeForMake(outputs.begin()->c_str());
|
|
makefileStream << primary_output << ": ";
|
|
}
|
|
else
|
|
{
|
|
// There are no outputs. Use the generated force rule name.
|
|
makefileStream << tname[&cc] << ": ";
|
|
}
|
|
for(std::vector<std::string>::const_iterator d =
|
|
cc.GetDepends().begin();
|
|
d != cc.GetDepends().end(); ++d)
|
|
{
|
|
std::string dep =
|
|
this->CurrentLocalGenerator->GetRealDependency(d->c_str(),
|
|
configName);
|
|
makefileStream << "\\\n" << this
|
|
->ConvertToRelativeForMake(dep.c_str());
|
|
}
|
|
makefileStream << "\n";
|
|
|
|
// Add each command line to the set of commands.
|
|
for(cmCustomCommandLines::const_iterator cl =
|
|
cc.GetCommandLines().begin();
|
|
cl != cc.GetCommandLines().end(); ++cl)
|
|
{
|
|
// Build the command line in a single string.
|
|
const cmCustomCommandLine& commandLine = *cl;
|
|
std::string cmd2 = this->CurrentLocalGenerator
|
|
->GetRealLocation(commandLine[0].c_str(), configName);
|
|
|
|
cmSystemTools::ReplaceString(cmd2, "/./", "/");
|
|
cmd2 = this->ConvertToRelativeForMake(cmd2.c_str());
|
|
std::string cmd;
|
|
if(cc.GetWorkingDirectory())
|
|
{
|
|
cmd += "cd ";
|
|
cmd += this->ConvertToRelativeForMake(cc.GetWorkingDirectory());
|
|
cmd += " && ";
|
|
}
|
|
cmd += cmd2;
|
|
for(unsigned int j=1; j < commandLine.size(); ++j)
|
|
{
|
|
cmd += " ";
|
|
if(escapeOldStyle)
|
|
{
|
|
cmd += (this->CurrentLocalGenerator
|
|
->EscapeForShellOldStyle(commandLine[j].c_str()));
|
|
}
|
|
else
|
|
{
|
|
cmd += (this->CurrentLocalGenerator->
|
|
EscapeForShell(commandLine[j].c_str(),
|
|
escapeAllowMakeVars));
|
|
}
|
|
}
|
|
makefileStream << "\t" << cmd.c_str() << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add rules to deal with multiple outputs of custom commands.
|
|
if(!multipleOutputPairs.empty())
|
|
{
|
|
makefileStream <<
|
|
"\n# Dependencies of multiple outputs to their primary outputs \n";
|
|
|
|
for(std::map<cmStdString, cmStdString>::const_iterator o =
|
|
multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
|
|
{
|
|
makefileStream << o->first << ": " << o->second << "\n";
|
|
}
|
|
|
|
makefileStream <<
|
|
"\n"
|
|
"cmake_check_multiple_outputs:\n";
|
|
for(std::map<cmStdString, cmStdString>::const_iterator o =
|
|
multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
|
|
{
|
|
makefileStream << "\t@if [ ! -f "
|
|
<< o->first << " ]; then rm -f "
|
|
<< o->second << "; fi\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
|
|
cmXCodeObject* buildSettings,
|
|
std::string& fileType,
|
|
std::string& productType,
|
|
std::string& productName,
|
|
const char* configName)
|
|
{
|
|
std::string flags;
|
|
std::string defFlags;
|
|
bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
|
|
(target.GetType() == cmTarget::MODULE_LIBRARY));
|
|
|
|
// Add the export symbol definition for shared library objects.
|
|
if(const char* exportMacro = target.GetExportMacro())
|
|
{
|
|
defFlags += "-D";
|
|
defFlags += exportMacro;
|
|
}
|
|
const char* lang = target.GetLinkerLanguage(this);
|
|
std::string cflags;
|
|
if(lang)
|
|
{
|
|
// for c++ projects get the c flags as well
|
|
if(strcmp(lang, "CXX") == 0)
|
|
{
|
|
this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName);
|
|
this->CurrentLocalGenerator->AddSharedFlags(cflags, lang, shared);
|
|
}
|
|
|
|
// Add language-specific flags.
|
|
this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName);
|
|
|
|
// Add shared-library flags if needed.
|
|
this->CurrentLocalGenerator->AddSharedFlags(flags, lang, shared);
|
|
}
|
|
|
|
// Add define flags
|
|
this->CurrentLocalGenerator->
|
|
AppendFlags(defFlags,
|
|
this->CurrentMakefile->GetDefineFlags());
|
|
cmSystemTools::ReplaceString(defFlags, "\"", "\\\"");
|
|
cmSystemTools::ReplaceString(flags, "\"", "\\\"");
|
|
cmSystemTools::ReplaceString(cflags, "\"", "\\\"");
|
|
if(this->XcodeVersion > 15)
|
|
{
|
|
buildSettings->AddAttribute
|
|
("GCC_PREPROCESSOR_DEFINITIONS",
|
|
this->CreateString("CMAKE_INTDIR=\\\\\"$(CONFIGURATION)\\\\\""));
|
|
}
|
|
std::string extraLinkOptions;
|
|
if(target.GetType() == cmTarget::EXECUTABLE)
|
|
{
|
|
extraLinkOptions =
|
|
this->CurrentMakefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
|
|
}
|
|
if(target.GetType() == cmTarget::SHARED_LIBRARY)
|
|
{
|
|
extraLinkOptions = this->CurrentMakefile->
|
|
GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
|
|
}
|
|
if(target.GetType() == cmTarget::MODULE_LIBRARY)
|
|
{
|
|
extraLinkOptions = this->CurrentMakefile->
|
|
GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
|
|
}
|
|
|
|
const char* targetLinkFlags = target.GetProperty("LINK_FLAGS");
|
|
if(targetLinkFlags)
|
|
{
|
|
extraLinkOptions += " ";
|
|
extraLinkOptions += targetLinkFlags;
|
|
}
|
|
|
|
// The product name is the full name of the target for this configuration.
|
|
productName = target.GetFullName(configName);
|
|
|
|
// Get the product name components.
|
|
std::string pnprefix;
|
|
std::string pnbase;
|
|
std::string pnsuffix;
|
|
target.GetFullName(pnprefix, pnbase, pnsuffix, configName);
|
|
|
|
// Store the product name for all target types.
|
|
buildSettings->AddAttribute("PRODUCT_NAME",
|
|
this->CreateString(pnbase.c_str()));
|
|
|
|
// Set attributes to specify the proper name for the target.
|
|
if(target.GetType() == cmTarget::STATIC_LIBRARY ||
|
|
target.GetType() == cmTarget::SHARED_LIBRARY ||
|
|
target.GetType() == cmTarget::MODULE_LIBRARY ||
|
|
target.GetType() == cmTarget::EXECUTABLE)
|
|
{
|
|
std::string pndir = target.GetDirectory();
|
|
if(target.GetPropertyAsBool("FRAMEWORK"))
|
|
{
|
|
pndir += "/..";
|
|
pndir = cmSystemTools::CollapseFullPath(pndir.c_str());
|
|
}
|
|
buildSettings->AddAttribute("SYMROOT",
|
|
this->CreateString(pndir.c_str()));
|
|
buildSettings->AddAttribute("EXECUTABLE_PREFIX",
|
|
this->CreateString(pnprefix.c_str()));
|
|
buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
|
|
this->CreateString(pnsuffix.c_str()));
|
|
}
|
|
|
|
// Handle settings for each target type.
|
|
switch(target.GetType())
|
|
{
|
|
case cmTarget::STATIC_LIBRARY:
|
|
{
|
|
fileType = "archive.ar";
|
|
productType = "com.apple.product-type.library.static";
|
|
|
|
buildSettings->AddAttribute("LIBRARY_STYLE",
|
|
this->CreateString("STATIC"));
|
|
break;
|
|
}
|
|
|
|
case cmTarget::MODULE_LIBRARY:
|
|
{
|
|
buildSettings->AddAttribute("LIBRARY_STYLE",
|
|
this->CreateString("BUNDLE"));
|
|
if(this->XcodeVersion >= 22)
|
|
{
|
|
fileType = "compiled.mach-o.executable";
|
|
productType = "com.apple.product-type.tool";
|
|
|
|
buildSettings->AddAttribute("MACH_O_TYPE",
|
|
this->CreateString("mh_bundle"));
|
|
buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
|
|
this->CreateString("NO"));
|
|
// Add the flags to create an executable.
|
|
std::string createFlags =
|
|
this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
|
|
if(!createFlags.empty())
|
|
{
|
|
extraLinkOptions += " ";
|
|
extraLinkOptions += createFlags;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fileType = "compiled.mach-o.dylib";
|
|
productType = "com.apple.product-type.library.dynamic";
|
|
|
|
// Add the flags to create a module.
|
|
std::string createFlags =
|
|
this->LookupFlags("CMAKE_SHARED_MODULE_CREATE_", lang, "_FLAGS",
|
|
"-bundle");
|
|
if(!createFlags.empty())
|
|
{
|
|
extraLinkOptions += " ";
|
|
extraLinkOptions += createFlags;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case cmTarget::SHARED_LIBRARY:
|
|
{
|
|
if(target.GetPropertyAsBool("FRAMEWORK"))
|
|
{
|
|
fileType = "wrapper.framework";
|
|
productType = "com.apple.product-type.framework";
|
|
break;
|
|
}
|
|
fileType = "compiled.mach-o.dylib";
|
|
productType = "com.apple.product-type.library.dynamic";
|
|
|
|
buildSettings->AddAttribute("LIBRARY_STYLE",
|
|
this->CreateString("DYNAMIC"));
|
|
buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
|
|
this->CreateString("1"));
|
|
buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
|
|
this->CreateString("1"));
|
|
|
|
// Add the flags to create a shared library.
|
|
std::string createFlags =
|
|
this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", lang, "_FLAGS",
|
|
"-dynamiclib");
|
|
if(!createFlags.empty())
|
|
{
|
|
extraLinkOptions += " ";
|
|
extraLinkOptions += createFlags;
|
|
}
|
|
break;
|
|
}
|
|
case cmTarget::EXECUTABLE:
|
|
{
|
|
fileType = "compiled.mach-o.executable";
|
|
|
|
// Add the flags to create an executable.
|
|
std::string createFlags =
|
|
this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
|
|
if(!createFlags.empty())
|
|
{
|
|
extraLinkOptions += " ";
|
|
extraLinkOptions += createFlags;
|
|
}
|
|
|
|
// Handle bundles and normal executables separately.
|
|
if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
|
|
{
|
|
productType = "com.apple.product-type.application";
|
|
std::string f1 =
|
|
this->CurrentMakefile->GetModulesFile("MacOSXBundleInfo.plist.in");
|
|
if ( f1.size() == 0 )
|
|
{
|
|
cmSystemTools::Error("could not find Mac OSX bundle template file.");
|
|
}
|
|
std::string f2 = this->CurrentMakefile->GetCurrentOutputDirectory();
|
|
f2 += "/Info.plist";
|
|
this->CurrentMakefile->ConfigureFile(f1.c_str(), f2.c_str(),
|
|
false, false, false);
|
|
std::string path =
|
|
this->ConvertToRelativeForXCode(f2.c_str());
|
|
buildSettings->AddAttribute("INFOPLIST_FILE",
|
|
this->CreateString(path.c_str()));
|
|
|
|
}
|
|
else
|
|
{
|
|
productType = "com.apple.product-type.tool";
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if(this->XcodeVersion >= 22)
|
|
{
|
|
buildSettings->AddAttribute("PREBINDING",
|
|
this->CreateString("NO"));
|
|
}
|
|
std::string dirs;
|
|
std::vector<std::string> includes;
|
|
this->CurrentLocalGenerator->GetIncludeDirectories(includes);
|
|
std::vector<std::string>::iterator i = includes.begin();
|
|
std::string fdirs;
|
|
std::set<cmStdString> emitted;
|
|
emitted.insert("/System/Library/Frameworks");
|
|
for(;i != includes.end(); ++i)
|
|
{
|
|
if(cmSystemTools::IsPathToFramework(i->c_str()))
|
|
{
|
|
std::string frameworkDir = *i;
|
|
frameworkDir += "/../";
|
|
frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str());
|
|
if(emitted.insert(frameworkDir).second)
|
|
{
|
|
fdirs += this->XCodeEscapePath(frameworkDir.c_str());
|
|
fdirs += " ";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string incpath =
|
|
this->XCodeEscapePath(i->c_str());
|
|
dirs += incpath + " ";
|
|
}
|
|
}
|
|
std::vector<std::string>& frameworks = target.GetFrameworks();
|
|
if(frameworks.size())
|
|
{
|
|
for(std::vector<std::string>::iterator fmIt = frameworks.begin();
|
|
fmIt != frameworks.end(); ++fmIt)
|
|
{
|
|
if(emitted.insert(*fmIt).second)
|
|
{
|
|
fdirs += this->XCodeEscapePath(fmIt->c_str());
|
|
fdirs += " ";
|
|
}
|
|
}
|
|
}
|
|
if(fdirs.size())
|
|
{
|
|
buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS",
|
|
this->CreateString(fdirs.c_str()));
|
|
}
|
|
if(dirs.size())
|
|
{
|
|
buildSettings->AddAttribute("HEADER_SEARCH_PATHS",
|
|
this->CreateString(dirs.c_str()));
|
|
}
|
|
std::string oflagc = this->ExtractFlag("-O", cflags);
|
|
char optLevel[2];
|
|
optLevel[0] = '0';
|
|
optLevel[1] = 0;
|
|
if(oflagc.size() == 3)
|
|
{
|
|
optLevel[0] = oflagc[2];
|
|
}
|
|
if(oflagc.size() == 2)
|
|
{
|
|
optLevel[0] = '1';
|
|
}
|
|
std::string oflag = this->ExtractFlag("-O", flags);
|
|
if(oflag.size() == 3)
|
|
{
|
|
optLevel[0] = oflag[2];
|
|
}
|
|
if(oflag.size() == 2)
|
|
{
|
|
optLevel[0] = '1';
|
|
}
|
|
std::string gflagc = this->ExtractFlag("-g", cflags);
|
|
// put back gdwarf-2 if used since there is no way
|
|
// to represent it in the gui, but we still want debug yes
|
|
if(gflagc == "-gdwarf-2")
|
|
{
|
|
cflags += " ";
|
|
cflags += gflagc;
|
|
}
|
|
std::string gflag = this->ExtractFlag("-g", flags);
|
|
if(gflag == "-gdwarf-2")
|
|
{
|
|
flags += " ";
|
|
flags += gflag;
|
|
}
|
|
const char* debugStr = "YES";
|
|
if(gflagc.size() ==0 && gflag.size() == 0)
|
|
{
|
|
debugStr = "NO";
|
|
}
|
|
buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
|
|
this->CreateString(debugStr));
|
|
buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
|
|
this->CreateString(optLevel));
|
|
buildSettings->AddAttribute("OPTIMIZATION_CFLAGS",
|
|
this->CreateString(oflagc.c_str()));
|
|
buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
|
|
this->CreateString("NO"));
|
|
buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
|
|
this->CreateString("NO"));
|
|
if(lang && strcmp(lang, "CXX") == 0)
|
|
{
|
|
flags += " ";
|
|
flags += defFlags;
|
|
buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
|
|
this->CreateString(flags.c_str()));
|
|
cflags += " ";
|
|
cflags += defFlags;
|
|
buildSettings->AddAttribute("OTHER_CFLAGS",
|
|
this->CreateString(cflags.c_str()));
|
|
|
|
}
|
|
else
|
|
{
|
|
flags += " ";
|
|
flags += defFlags;
|
|
buildSettings->AddAttribute("OTHER_CFLAGS",
|
|
this->CreateString(flags.c_str()));
|
|
}
|
|
|
|
// Create the INSTALL_PATH attribute.
|
|
std::string install_name_dir;
|
|
if(target.GetType() == cmTarget::SHARED_LIBRARY)
|
|
{
|
|
// Get the install_name directory for the build tree.
|
|
install_name_dir = target.GetInstallNameDirForBuildTree(configName);
|
|
if(target.GetPropertyAsBool("FRAMEWORK"))
|
|
{
|
|
if(install_name_dir.find(".framework") != install_name_dir.npos)
|
|
{
|
|
install_name_dir = install_name_dir + "/..";
|
|
install_name_dir =
|
|
cmSystemTools::CollapseFullPath(install_name_dir.c_str());
|
|
//std::cerr << "new install name " << install_name_dir << "\n";
|
|
}
|
|
}
|
|
|
|
if(install_name_dir.empty())
|
|
{
|
|
// Xcode will not pass the -install_name option at all if INSTALL_PATH
|
|
// is not given or is empty. We must explicitly put the flag in the
|
|
// link flags to create an install_name with just the library soname.
|
|
extraLinkOptions += " -install_name ";
|
|
extraLinkOptions += productName;
|
|
}
|
|
else
|
|
{
|
|
// Convert to a path for the native build tool.
|
|
cmSystemTools::ConvertToUnixSlashes(install_name_dir);
|
|
// do not escape spaces on this since it is only a single path
|
|
}
|
|
}
|
|
buildSettings->AddAttribute("INSTALL_PATH",
|
|
this->CreateString(install_name_dir.c_str()));
|
|
|
|
buildSettings->AddAttribute("OTHER_LDFLAGS",
|
|
this->CreateString(extraLinkOptions.c_str()));
|
|
buildSettings->AddAttribute("OTHER_REZFLAGS",
|
|
this->CreateString(""));
|
|
buildSettings->AddAttribute("SECTORDER_FLAGS",
|
|
this->CreateString(""));
|
|
buildSettings->AddAttribute("USE_HEADERMAP",
|
|
this->CreateString("NO"));
|
|
buildSettings->AddAttribute("WARNING_CFLAGS",
|
|
this->CreateString(
|
|
"-Wmost -Wno-four-char-constants"
|
|
" -Wno-unknown-pragmas"));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateUtilityTarget(cmTarget& cmtarget)
|
|
{
|
|
cmXCodeObject* shellBuildPhase =
|
|
this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
|
|
shellBuildPhase->AddAttribute("buildActionMask",
|
|
this->CreateString("2147483647"));
|
|
cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
shellBuildPhase->AddAttribute("files", buildFiles);
|
|
cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
shellBuildPhase->AddAttribute("inputPaths", inputPaths);
|
|
cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
shellBuildPhase->AddAttribute("outputPaths", outputPaths);
|
|
shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
|
|
this->CreateString("0"));
|
|
shellBuildPhase->AddAttribute("shellPath",
|
|
this->CreateString("/bin/sh"));
|
|
shellBuildPhase->AddAttribute("shellScript",
|
|
this->CreateString(
|
|
"# shell script goes here\nexit 0"));
|
|
cmXCodeObject* target =
|
|
this->CreateObject(cmXCodeObject::PBXAggregateTarget);
|
|
target->SetComment(cmtarget.GetName());
|
|
cmXCodeObject* buildPhases =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
this->CreateCustomCommands(buildPhases, 0, 0, 0, cmtarget);
|
|
target->AddAttribute("buildPhases", buildPhases);
|
|
cmXCodeObject* buildSettings =
|
|
this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
std::string fileTypeString;
|
|
std::string productTypeString;
|
|
std::string productName;
|
|
const char* globalConfig = 0;
|
|
if(this->XcodeVersion > 20)
|
|
{
|
|
this->AddConfigurations(target, cmtarget);
|
|
}
|
|
else
|
|
{
|
|
globalConfig = this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
|
|
}
|
|
this->CreateBuildSettings(cmtarget,
|
|
buildSettings, fileTypeString,
|
|
productTypeString, productName, globalConfig);
|
|
target->AddAttribute("buildSettings", buildSettings);
|
|
cmXCodeObject* dependencies =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
target->AddAttribute("dependencies", dependencies);
|
|
target->AddAttribute("name", this->CreateString(productName.c_str()));
|
|
target->AddAttribute("productName",this->CreateString(productName.c_str()));
|
|
target->SetTarget(&cmtarget);
|
|
return target;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
|
|
cmTarget& cmtarget)
|
|
{
|
|
std::string configTypes =
|
|
this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
|
|
std::vector<std::string> configVectorIn;
|
|
std::vector<std::string> configVector;
|
|
configVectorIn.push_back(configTypes);
|
|
cmSystemTools::ExpandList(configVectorIn, configVector);
|
|
cmXCodeObject* configlist =
|
|
this->CreateObject(cmXCodeObject::XCConfigurationList);
|
|
cmXCodeObject* buildConfigurations =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
configlist->AddAttribute("buildConfigurations", buildConfigurations);
|
|
std::string comment = "Build configuration list for ";
|
|
comment += cmXCodeObject::PBXTypeNames[target->GetIsA()];
|
|
comment += " \"";
|
|
comment += cmtarget.GetName();
|
|
comment += "\"";
|
|
configlist->SetComment(comment.c_str());
|
|
target->AddAttribute("buildConfigurationList",
|
|
this->CreateObjectReference(configlist));
|
|
for(unsigned int i = 0; i < configVector.size(); ++i)
|
|
{
|
|
cmXCodeObject* config =
|
|
this->CreateObject(cmXCodeObject::XCBuildConfiguration);
|
|
buildConfigurations->AddObject(config);
|
|
cmXCodeObject* buildSettings =
|
|
this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
std::string fileTypeString;
|
|
std::string productTypeString;
|
|
std::string productName;
|
|
this->CreateBuildSettings(cmtarget,
|
|
buildSettings, fileTypeString,
|
|
productTypeString, productName,
|
|
configVector[i].c_str());
|
|
config->AddAttribute("name", this->CreateString(configVector[i].c_str()));
|
|
config->SetComment(configVector[i].c_str());
|
|
config->AddAttribute("buildSettings", buildSettings);
|
|
}
|
|
if(configVector.size())
|
|
{
|
|
configlist->AddAttribute("defaultConfigurationName",
|
|
this->CreateString(configVector[0].c_str()));
|
|
configlist->AddAttribute("defaultConfigurationIsVisible",
|
|
this->CreateString("0"));
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
|
|
cmXCodeObject* buildPhases)
|
|
{
|
|
cmXCodeObject* target =
|
|
this->CreateObject(cmXCodeObject::PBXNativeTarget);
|
|
target->AddAttribute("buildPhases", buildPhases);
|
|
cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
target->AddAttribute("buildRules", buildRules);
|
|
cmXCodeObject* buildSettings =
|
|
this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
std::string fileTypeString;
|
|
std::string productTypeString;
|
|
std::string productName;
|
|
const char* globalConfig = 0;
|
|
if(this->XcodeVersion > 20)
|
|
{
|
|
this->AddConfigurations(target, cmtarget);
|
|
}
|
|
else
|
|
{
|
|
globalConfig = this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
|
|
}
|
|
this->CreateBuildSettings(cmtarget,
|
|
buildSettings, fileTypeString,
|
|
productTypeString, productName, globalConfig);
|
|
target->AddAttribute("buildSettings", buildSettings);
|
|
cmXCodeObject* dependencies =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
target->AddAttribute("dependencies", dependencies);
|
|
target->AddAttribute("name", this->CreateString(productName.c_str()));
|
|
target->AddAttribute("productName",this->CreateString(productName.c_str()));
|
|
|
|
cmXCodeObject* fileRef =
|
|
this->CreateObject(cmXCodeObject::PBXFileReference);
|
|
fileRef->AddAttribute("explicitFileType",
|
|
this->CreateString(fileTypeString.c_str()));
|
|
fileRef->AddAttribute("path", this->CreateString(productName.c_str()));
|
|
fileRef->AddAttribute("refType", this->CreateString("0"));
|
|
fileRef->AddAttribute("sourceTree",
|
|
this->CreateString("BUILT_PRODUCTS_DIR"));
|
|
fileRef->SetComment(cmtarget.GetName());
|
|
target->AddAttribute("productReference",
|
|
this->CreateObjectReference(fileRef));
|
|
target->AddAttribute("productType",
|
|
this->CreateString(productTypeString.c_str()));
|
|
target->SetTarget(&cmtarget);
|
|
return target;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
|
|
{
|
|
if(!t)
|
|
{
|
|
return 0;
|
|
}
|
|
for(std::vector<cmXCodeObject*>::iterator i = this->XCodeObjects.begin();
|
|
i != this->XCodeObjects.end(); ++i)
|
|
{
|
|
cmXCodeObject* o = *i;
|
|
if(o->GetTarget() == t)
|
|
{
|
|
return o;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
|
|
cmXCodeObject* dependTarget)
|
|
{
|
|
// make sure a target does not depend on itself
|
|
if(target == dependTarget)
|
|
{
|
|
return;
|
|
}
|
|
// now avoid circular references if dependTarget already
|
|
// depends on target then skip it. Circular references crashes
|
|
// xcode
|
|
cmXCodeObject* dependTargetDepends =
|
|
dependTarget->GetObject("dependencies");
|
|
if(dependTargetDepends)
|
|
{
|
|
if(dependTargetDepends->HasObject(target->GetPBXTargetDependency()))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency();
|
|
if(!targetdep)
|
|
{
|
|
cmXCodeObject* container =
|
|
this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
|
|
container->SetComment("PBXContainerItemProxy");
|
|
container->AddAttribute("containerPortal",
|
|
this->CreateObjectReference(this->RootObject));
|
|
container->AddAttribute("proxyType", this->CreateString("1"));
|
|
container->AddAttribute("remoteGlobalIDString",
|
|
this->CreateObjectReference(dependTarget));
|
|
container->AddAttribute("remoteInfo",
|
|
this->CreateString(
|
|
dependTarget->GetTarget()->GetName()));
|
|
targetdep =
|
|
this->CreateObject(cmXCodeObject::PBXTargetDependency);
|
|
targetdep->SetComment("PBXTargetDependency");
|
|
targetdep->AddAttribute("target",
|
|
this->CreateObjectReference(dependTarget));
|
|
targetdep->AddAttribute("targetProxy",
|
|
this->CreateObjectReference(container));
|
|
dependTarget->SetPBXTargetDependency(targetdep);
|
|
}
|
|
|
|
cmXCodeObject* depends = target->GetObject("dependencies");
|
|
if(!depends)
|
|
{
|
|
cmSystemTools::
|
|
Error("target does not have dependencies attribute error..");
|
|
|
|
}
|
|
else
|
|
{
|
|
depends->AddUniqueObject(targetdep);
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
|
|
const char* attribute,
|
|
const char* value)
|
|
{
|
|
if(settings)
|
|
{
|
|
cmXCodeObject* attr = settings->GetObject(attribute);
|
|
if(!attr)
|
|
{
|
|
settings->AddAttribute(attribute, this->CreateString(value));
|
|
}
|
|
else
|
|
{
|
|
std::string oldValue = attr->GetString();
|
|
cmSystemTools::ReplaceString(oldValue, "\"", "");
|
|
oldValue += " ";
|
|
oldValue += value;
|
|
attr->SetString(oldValue.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator
|
|
::AppendBuildSettingAttribute(cmXCodeObject* target,
|
|
const char* attribute,
|
|
const char* value,
|
|
const char* configName)
|
|
{
|
|
if(this->XcodeVersion < 21)
|
|
{
|
|
// There is only one configuration. Add the setting to the buildSettings
|
|
// of the target.
|
|
this->AppendOrAddBuildSetting(target->GetObject("buildSettings"),
|
|
attribute, value);
|
|
}
|
|
else
|
|
{
|
|
// There are multiple configurations. Add the setting to the
|
|
// buildSettings of the configuration name given.
|
|
cmXCodeObject* configurationList =
|
|
target->GetObject("buildConfigurationList")->GetObject();
|
|
cmXCodeObject* buildConfigs =
|
|
configurationList->GetObject("buildConfigurations");
|
|
std::vector<cmXCodeObject*> list = buildConfigs->GetObjectList();
|
|
// each configuration and the target itself has a buildSettings in it
|
|
//list.push_back(target);
|
|
for(std::vector<cmXCodeObject*>::iterator i = list.begin();
|
|
i != list.end(); ++i)
|
|
{
|
|
if(configName)
|
|
{
|
|
if(strcmp((*i)->GetObject("name")->GetString(), configName) == 0)
|
|
{
|
|
cmXCodeObject* settings = (*i)->GetObject("buildSettings");
|
|
this->AppendOrAddBuildSetting(settings, attribute, value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cmXCodeObject* settings = (*i)->GetObject("buildSettings");
|
|
this->AppendOrAddBuildSetting(settings, attribute, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator
|
|
::AddDependAndLinkInformation(cmXCodeObject* target)
|
|
{
|
|
cmTarget* cmtarget = target->GetTarget();
|
|
if(!cmtarget)
|
|
{
|
|
cmSystemTools::Error("Error no target on xobject\n");
|
|
return;
|
|
}
|
|
|
|
// Add dependencies on other CMake targets.
|
|
if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY)
|
|
{
|
|
// Keep track of dependencies already listed.
|
|
std::set<cmStdString> emitted;
|
|
|
|
// A target should not depend on itself.
|
|
emitted.insert(cmtarget->GetName());
|
|
|
|
// Loop over all library dependencies.
|
|
const cmTarget::LinkLibraryVectorType& tlibs =
|
|
cmtarget->GetLinkLibraries();
|
|
for(cmTarget::LinkLibraryVectorType::const_iterator lib = tlibs.begin();
|
|
lib != tlibs.end(); ++lib)
|
|
{
|
|
// Don't emit the same library twice for this target.
|
|
if(emitted.insert(lib->first).second)
|
|
{
|
|
// Add this dependency.
|
|
cmTarget* t = this->FindTarget(this->CurrentProject.c_str(),
|
|
lib->first.c_str(), false);
|
|
cmXCodeObject* dptarget = this->FindXCodeTarget(t);
|
|
if(dptarget)
|
|
{
|
|
this->AddDependTarget(target, dptarget);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// write utility dependencies.
|
|
for(std::set<cmStdString>::const_iterator i
|
|
= cmtarget->GetUtilities().begin();
|
|
i != cmtarget->GetUtilities().end(); ++i)
|
|
{
|
|
cmTarget* t = this->FindTarget(this->CurrentProject.c_str(),
|
|
i->c_str(), false);
|
|
// if the target is in this project then make target depend
|
|
// on it. It may not be in this project if this is a sub
|
|
// project from the top.
|
|
if(t)
|
|
{
|
|
cmXCodeObject* dptarget = this->FindXCodeTarget(t);
|
|
if(dptarget)
|
|
{
|
|
this->AddDependTarget(target, dptarget);
|
|
}
|
|
else
|
|
{
|
|
std::string m = "Error Utility: ";
|
|
m += i->c_str();
|
|
m += "\n";
|
|
m += "cmtarget ";
|
|
if(t)
|
|
{
|
|
m += t->GetName();
|
|
}
|
|
m += "\n";
|
|
m += "Is on the target ";
|
|
m += cmtarget->GetName();
|
|
m += "\n";
|
|
m += "But it has no xcode target created yet??\n";
|
|
m += "Current project is ";
|
|
m += this->CurrentProject.c_str();
|
|
cmSystemTools::Error(m.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop over configuration types and set per-configuration info.
|
|
for(std::vector<std::string>::iterator i =
|
|
this->CurrentConfigurationTypes.begin();
|
|
i != this->CurrentConfigurationTypes.end(); ++i)
|
|
{
|
|
// Get the current configuration name.
|
|
const char* configName = i->c_str();
|
|
if(!*configName)
|
|
{
|
|
configName = 0;
|
|
}
|
|
|
|
// Compute the link library and directory information.
|
|
std::vector<cmStdString> libNames;
|
|
std::vector<cmStdString> libDirs;
|
|
std::vector<cmStdString> fullPathLibs;
|
|
this->CurrentLocalGenerator->ComputeLinkInformation(*cmtarget, configName,
|
|
libNames, libDirs,
|
|
&fullPathLibs);
|
|
|
|
// Add dependencies directly on library files.
|
|
for(std::vector<cmStdString>::iterator j = fullPathLibs.begin();
|
|
j != fullPathLibs.end(); ++j)
|
|
{
|
|
target->AddDependLibrary(configName, j->c_str());
|
|
}
|
|
|
|
std::string linkDirs;
|
|
// add the library search paths
|
|
for(std::vector<cmStdString>::const_iterator libDir = libDirs.begin();
|
|
libDir != libDirs.end(); ++libDir)
|
|
{
|
|
if(libDir->size() && *libDir != "/usr/lib")
|
|
{
|
|
if(this->XcodeVersion > 15)
|
|
{
|
|
// now add the same one but append $(CONFIGURATION) to it:
|
|
linkDirs += " ";
|
|
linkDirs += this->XCodeEscapePath(libDir->c_str());
|
|
linkDirs += "/$(CONFIGURATION)";
|
|
}
|
|
linkDirs += " ";
|
|
linkDirs += this->XCodeEscapePath(libDir->c_str());
|
|
}
|
|
}
|
|
this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
|
|
linkDirs.c_str(), configName);
|
|
// now add the link libraries
|
|
if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY)
|
|
{
|
|
std::string fdirs;
|
|
std::set<cmStdString> emitted;
|
|
emitted.insert("/System/Library/Frameworks");
|
|
for(std::vector<cmStdString>::iterator lib = libNames.begin();
|
|
lib != libNames.end(); ++lib)
|
|
{
|
|
std::string& libString = *lib;
|
|
// check to see if this is a -F framework path and extract it if it is
|
|
// -F framework stuff should be in the FRAMEWORK_SEARCH_PATHS and not
|
|
// OTHER_LDFLAGS
|
|
if(libString.size() > 2 && libString[0] == '-'
|
|
&& libString[1] == 'F')
|
|
{
|
|
std::string path = libString.substr(2);
|
|
// remove escaped spaces from the path
|
|
cmSystemTools::ReplaceString(path, "\\ ", " ");
|
|
if(emitted.insert(path).second)
|
|
{
|
|
if(fdirs.size())
|
|
{
|
|
fdirs += " ";
|
|
}
|
|
fdirs += this->XCodeEscapePath(path.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
|
|
lib->c_str(), configName);
|
|
}
|
|
}
|
|
if(fdirs.size())
|
|
{
|
|
this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
|
|
fdirs.c_str(), configName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
|
|
std::vector<cmLocalGenerator*>&
|
|
generators)
|
|
{
|
|
for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
|
|
i != generators.end(); ++i)
|
|
{
|
|
if(this->IsExcluded(root, *i))
|
|
{
|
|
continue;
|
|
}
|
|
cmMakefile* mf = (*i)->GetMakefile();
|
|
std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
|
|
cmTargets &tgts = mf->GetTargets();
|
|
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
|
|
{
|
|
cmTarget& cmtarget = l->second;
|
|
// add the soon to be generated Info.plist file as a source for a
|
|
// MACOSX_BUNDLE file
|
|
if(cmtarget.GetPropertyAsBool("MACOSX_BUNDLE"))
|
|
{
|
|
std::string plistFile =
|
|
this->CurrentMakefile->GetCurrentOutputDirectory();
|
|
plistFile += "/Info.plist";
|
|
cmSourceFile* sf =
|
|
this->CurrentMakefile->GetOrCreateSource(plistFile.c_str(), true);
|
|
cmtarget.AddSourceFile(sf);
|
|
}
|
|
std::vector<cmSourceFile*> classes = cmtarget.GetSourceFiles();
|
|
// add framework copy headers
|
|
if(cmtarget.GetPropertyAsBool("FRAMEWORK"))
|
|
{
|
|
const char* headers = cmtarget.GetProperty("FRAMEWORK_PUBLIC_HEADERS");
|
|
if(!headers)
|
|
{
|
|
return;
|
|
}
|
|
std::vector<std::string> headersVec;
|
|
cmSystemTools::ExpandListArgument(headers,
|
|
headersVec);
|
|
cmCustomCommandLines commandLines;
|
|
std::vector<std::string> depends;
|
|
for(std::vector<std::string>::iterator h = headersVec.begin();
|
|
h != headersVec.end(); ++h)
|
|
{
|
|
cmSourceFile* sf
|
|
= this->CurrentMakefile->GetOrCreateSource(h->c_str());
|
|
classes.push_back(sf);
|
|
}
|
|
}
|
|
for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
|
|
s != classes.end(); s++)
|
|
{
|
|
cmSourceFile* sf = *s;
|
|
// Add the file to the list of sources.
|
|
std::string const& source = sf->GetFullPath();
|
|
cmSourceGroup& sourceGroup =
|
|
mf->FindSourceGroup(source.c_str(), sourceGroups);
|
|
cmXCodeObject* pbxgroup =
|
|
this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
|
|
this->GroupMap[sf] = pbxgroup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject* cmGlobalXCodeGenerator
|
|
::CreateOrGetPBXGroup(cmTarget& cmtarget, cmSourceGroup* sg)
|
|
{
|
|
cmStdString s = cmtarget.GetName();
|
|
s += "/";
|
|
s += sg->GetName();
|
|
std::map<cmStdString, cmXCodeObject* >::iterator i =
|
|
this->GroupNameMap.find(s);
|
|
if(i != this->GroupNameMap.end())
|
|
{
|
|
return i->second;
|
|
}
|
|
i = this->TargetGroup.find(cmtarget.GetName());
|
|
cmXCodeObject* tgroup = 0;
|
|
if(i != this->TargetGroup.end())
|
|
{
|
|
tgroup = i->second;
|
|
}
|
|
else
|
|
{
|
|
tgroup = this->CreateObject(cmXCodeObject::PBXGroup);
|
|
this->TargetGroup[cmtarget.GetName()] = tgroup;
|
|
cmXCodeObject* tgroupChildren =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
tgroup->AddAttribute("name", this->CreateString(cmtarget.GetName()));
|
|
tgroup->AddAttribute("children", tgroupChildren);
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
tgroup->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
tgroup->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
this->SourcesGroupChildren->AddObject(tgroup);
|
|
}
|
|
|
|
cmXCodeObject* tgroupChildren = tgroup->GetObject("children");
|
|
cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
|
|
cmXCodeObject* groupChildren =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
group->AddAttribute("name", this->CreateString(sg->GetName()));
|
|
group->AddAttribute("children", groupChildren);
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
group->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
group->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
tgroupChildren->AddObject(group);
|
|
this->GroupNameMap[s] = group;
|
|
return group;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator
|
|
::CreateXCodeObjects(cmLocalGenerator* root,
|
|
std::vector<cmLocalGenerator*>&
|
|
generators)
|
|
{
|
|
this->ClearXCodeObjects();
|
|
this->RootObject = 0;
|
|
this->SourcesGroupChildren = 0;
|
|
this->MainGroupChildren = 0;
|
|
cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
|
|
cmXCodeObject* developBuildStyle =
|
|
this->CreateObject(cmXCodeObject::PBXBuildStyle);
|
|
cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
developBuildStyle->AddAttribute("name",
|
|
this->CreateString("Development"));
|
|
developBuildStyle->AddAttribute("buildSettings", group);
|
|
listObjs->AddObject(developBuildStyle);
|
|
group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
|
|
cmXCodeObject* deployBuildStyle =
|
|
this->CreateObject(cmXCodeObject::PBXBuildStyle);
|
|
deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
|
|
deployBuildStyle->AddAttribute("buildSettings", group);
|
|
listObjs->AddObject(deployBuildStyle);
|
|
}
|
|
else
|
|
{
|
|
for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
|
|
{
|
|
cmXCodeObject* buildStyle =
|
|
this->CreateObject(cmXCodeObject::PBXBuildStyle);
|
|
const char* name = this->CurrentConfigurationTypes[i].c_str();
|
|
buildStyle->AddAttribute("name", this->CreateString(name));
|
|
buildStyle->SetComment(name);
|
|
cmXCodeObject* sgroup =
|
|
this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
|
|
buildStyle->AddAttribute("buildSettings", sgroup);
|
|
listObjs->AddObject(buildStyle);
|
|
}
|
|
}
|
|
|
|
cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
|
|
this->MainGroupChildren =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
mainGroup->AddAttribute("children", this->MainGroupChildren);
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
mainGroup->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
|
|
cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
|
|
this->SourcesGroupChildren =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
|
|
sourcesGroup->AddAttribute("children", this->SourcesGroupChildren);
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
sourcesGroup->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
this->MainGroupChildren->AddObject(sourcesGroup);
|
|
// now create the cmake groups
|
|
this->CreateGroups(root, generators);
|
|
|
|
cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
|
|
productGroup->AddAttribute("name", this->CreateString("Products"));
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
productGroup->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
cmXCodeObject* productGroupChildren =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
productGroup->AddAttribute("children", productGroupChildren);
|
|
this->MainGroupChildren->AddObject(productGroup);
|
|
|
|
|
|
this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
|
|
this->RootObject->SetComment("Project object");
|
|
group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
this->RootObject->AddAttribute("mainGroup",
|
|
this->CreateObjectReference(mainGroup));
|
|
this->RootObject->AddAttribute("buildSettings", group);
|
|
this->RootObject->AddAttribute("buildStyles", listObjs);
|
|
this->RootObject->AddAttribute("hasScannedForEncodings",
|
|
this->CreateString("0"));
|
|
cmXCodeObject* configlist =
|
|
this->CreateObject(cmXCodeObject::XCConfigurationList);
|
|
cmXCodeObject* buildConfigurations =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
std::vector<cmXCodeObject*> configs;
|
|
if(this->XcodeVersion == 15)
|
|
{
|
|
cmXCodeObject* configDebug =
|
|
this->CreateObject(cmXCodeObject::XCBuildConfiguration);
|
|
configDebug->AddAttribute("name", this->CreateString("Debug"));
|
|
configs.push_back(configDebug);
|
|
cmXCodeObject* configRelease =
|
|
this->CreateObject(cmXCodeObject::XCBuildConfiguration);
|
|
configRelease->AddAttribute("name", this->CreateString("Release"));
|
|
configs.push_back(configRelease);
|
|
}
|
|
else
|
|
{
|
|
for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
|
|
{
|
|
const char* name = this->CurrentConfigurationTypes[i].c_str();
|
|
cmXCodeObject* config =
|
|
this->CreateObject(cmXCodeObject::XCBuildConfiguration);
|
|
config->AddAttribute("name", this->CreateString(name));
|
|
configs.push_back(config);
|
|
}
|
|
}
|
|
for(std::vector<cmXCodeObject*>::iterator c = configs.begin();
|
|
c != configs.end(); ++c)
|
|
{
|
|
buildConfigurations->AddObject(*c);
|
|
}
|
|
configlist->AddAttribute("buildConfigurations", buildConfigurations);
|
|
|
|
std::string comment = "Build configuration list for PBXProject ";
|
|
comment += " \"";
|
|
comment += this->CurrentProject;
|
|
comment += "\"";
|
|
configlist->SetComment(comment.c_str());
|
|
configlist->AddAttribute("defaultConfigurationIsVisible",
|
|
this->CreateString("0"));
|
|
configlist->AddAttribute("defaultConfigurationName",
|
|
this->CreateString("Debug"));
|
|
cmXCodeObject* buildSettings =
|
|
this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
const char* osxArch =
|
|
this->CurrentMakefile->GetDefinition("CMAKE_OSX_ARCHITECTURES");
|
|
const char* sysroot =
|
|
this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
|
|
if(osxArch && sysroot)
|
|
{
|
|
// recompute this as it may have been changed since enable language
|
|
this->Architectures.clear();
|
|
cmSystemTools::ExpandListArgument(std::string(osxArch),
|
|
this->Architectures);
|
|
if(this->Architectures.size() > 1)
|
|
{
|
|
buildSettings->AddAttribute("SDKROOT",
|
|
this->CreateString(sysroot));
|
|
std::string archString;
|
|
for( std::vector<std::string>::iterator i =
|
|
this->Architectures.begin();
|
|
i != this->Architectures.end(); ++i)
|
|
{
|
|
archString += *i;
|
|
archString += " ";
|
|
}
|
|
buildSettings->AddAttribute("ARCHS",
|
|
this->CreateString(archString.c_str()));
|
|
}
|
|
}
|
|
for( std::vector<cmXCodeObject*>::iterator i = configs.begin();
|
|
i != configs.end(); ++i)
|
|
{
|
|
(*i)->AddAttribute("buildSettings", buildSettings);
|
|
}
|
|
this->RootObject->AddAttribute("buildConfigurationList",
|
|
this->CreateObjectReference(configlist));
|
|
|
|
std::vector<cmXCodeObject*> targets;
|
|
for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
|
|
i != generators.end(); ++i)
|
|
{
|
|
if(!this->IsExcluded(root, *i))
|
|
{
|
|
this->CreateXCodeTargets(*i, targets);
|
|
}
|
|
}
|
|
// loop over all targets and add link and depend info
|
|
for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
|
|
i != targets.end(); ++i)
|
|
{
|
|
cmXCodeObject* t = *i;
|
|
this->AddDependAndLinkInformation(t);
|
|
}
|
|
// now create xcode depend hack makefile
|
|
this->CreateXCodeDependHackTarget(targets);
|
|
// now add all targets to the root object
|
|
cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
|
|
i != targets.end(); ++i)
|
|
{
|
|
cmXCodeObject* t = *i;
|
|
allTargets->AddObject(t);
|
|
cmXCodeObject* productRef = t->GetObject("productReference");
|
|
if(productRef)
|
|
{
|
|
productGroupChildren->AddObject(productRef->GetObject());
|
|
}
|
|
}
|
|
this->RootObject->AddAttribute("targets", allTargets);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
|
|
std::vector<cmXCodeObject*>& targets)
|
|
{
|
|
cmGeneratedFileStream
|
|
makefileStream(this->CurrentXCodeHackMakefile.c_str());
|
|
if(!makefileStream)
|
|
{
|
|
cmSystemTools::Error("Could not create",
|
|
this->CurrentXCodeHackMakefile.c_str());
|
|
return;
|
|
}
|
|
makefileStream.SetCopyIfDifferent(true);
|
|
// one more pass for external depend information not handled
|
|
// correctly by xcode
|
|
makefileStream << "# DO NOT EDIT\n";
|
|
makefileStream << "# This makefile makes sure all linkable targets are \n";
|
|
makefileStream << "# up-to-date with anything they link to,avoiding a "
|
|
"bug in XCode 1.5\n";
|
|
for(std::vector<std::string>::const_iterator
|
|
ct = this->CurrentConfigurationTypes.begin();
|
|
ct != this->CurrentConfigurationTypes.end(); ++ct)
|
|
{
|
|
if(this->XcodeVersion < 21 || ct->empty())
|
|
{
|
|
makefileStream << "all: ";
|
|
}
|
|
else
|
|
{
|
|
makefileStream << "all." << *ct << ": ";
|
|
}
|
|
const char* configName = 0;
|
|
if(!ct->empty())
|
|
{
|
|
configName = ct->c_str();
|
|
}
|
|
for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
|
|
i != targets.end(); ++i)
|
|
{
|
|
cmXCodeObject* target = *i;
|
|
cmTarget* t =target->GetTarget();
|
|
if(t->GetType() == cmTarget::EXECUTABLE ||
|
|
t->GetType() == cmTarget::SHARED_LIBRARY ||
|
|
t->GetType() == cmTarget::MODULE_LIBRARY)
|
|
{
|
|
makefileStream << "\\\n\t" <<
|
|
this->ConvertToRelativeForMake(
|
|
t->GetFullPath(configName).c_str());
|
|
}
|
|
}
|
|
makefileStream << "\n\n";
|
|
}
|
|
makefileStream
|
|
<< "# For each target create a dummy rule "
|
|
"so the target does not have to exist\n";
|
|
std::set<cmStdString> emitted;
|
|
for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
|
|
i != targets.end(); ++i)
|
|
{
|
|
cmXCodeObject* target = *i;
|
|
std::map<cmStdString, cmXCodeObject::StringVec> const& deplibs =
|
|
target->GetDependLibraries();
|
|
for(std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator ci
|
|
= deplibs.begin(); ci != deplibs.end(); ++ci)
|
|
{
|
|
for(cmXCodeObject::StringVec::const_iterator d = ci->second.begin();
|
|
d != ci->second.end(); ++d)
|
|
{
|
|
if(emitted.insert(*d).second)
|
|
{
|
|
makefileStream <<
|
|
this->ConvertToRelativeForMake(d->c_str()) << ":\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
makefileStream << "\n\n";
|
|
|
|
// Write rules to help Xcode relink things at the right time.
|
|
makefileStream <<
|
|
"# Rules to remove targets that are older than anything to which they\n"
|
|
"# link. This forces Xcode to relink the targets from scratch. It\n"
|
|
"# does not seem to check these dependencies itself.\n";
|
|
for(std::vector<std::string>::const_iterator
|
|
ct = this->CurrentConfigurationTypes.begin();
|
|
ct != this->CurrentConfigurationTypes.end(); ++ct)
|
|
{
|
|
const char* configName = 0;
|
|
if(!ct->empty())
|
|
{
|
|
configName = ct->c_str();
|
|
}
|
|
for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
|
|
i != targets.end(); ++i)
|
|
{
|
|
cmXCodeObject* target = *i;
|
|
cmTarget* t =target->GetTarget();
|
|
if(t->GetType() == cmTarget::EXECUTABLE ||
|
|
t->GetType() == cmTarget::SHARED_LIBRARY ||
|
|
t->GetType() == cmTarget::MODULE_LIBRARY)
|
|
{
|
|
// Create a rule for this target.
|
|
std::string tfull = t->GetFullPath(configName);
|
|
makefileStream << this->ConvertToRelativeForMake(tfull.c_str())
|
|
<< ":";
|
|
|
|
// List dependencies if any exist.
|
|
std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator
|
|
x = target->GetDependLibraries().find(*ct);
|
|
if(x != target->GetDependLibraries().end())
|
|
{
|
|
std::vector<cmStdString> const& deplibs = x->second;
|
|
for(std::vector<cmStdString>::const_iterator d = deplibs.begin();
|
|
d != deplibs.end(); ++d)
|
|
{
|
|
makefileStream << "\\\n\t" <<
|
|
this->ConvertToRelativeForMake(d->c_str());
|
|
}
|
|
}
|
|
// Write the action to remove the target if it is out of date.
|
|
makefileStream << "\n";
|
|
makefileStream << "\t/bin/rm -f "
|
|
<< this->ConvertToRelativeForMake(tfull.c_str())
|
|
<< "\n";
|
|
// if building for more than one architecture
|
|
// then remove those exectuables as well
|
|
if(this->Architectures.size() > 1)
|
|
{
|
|
std::string universal = t->GetDirectory();
|
|
universal += "/";
|
|
universal += this->CurrentMakefile->GetProjectName();
|
|
universal += ".build/";
|
|
universal += configName;
|
|
universal += "/";
|
|
universal += t->GetName();
|
|
universal += ".build/Objects-normal/";
|
|
for( std::vector<std::string>::iterator arch =
|
|
this->Architectures.begin();
|
|
arch != this->Architectures.end(); ++arch)
|
|
{
|
|
std::string universalFile = universal;
|
|
universalFile += *arch;
|
|
universalFile += "/";
|
|
universalFile += t->GetName();
|
|
makefileStream << "\t/bin/rm -f "
|
|
<<
|
|
this->ConvertToRelativeForMake(universalFile.c_str())
|
|
<< "\n";
|
|
}
|
|
}
|
|
makefileStream << "\n\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
|
|
std::vector<cmLocalGenerator*>&
|
|
generators)
|
|
{
|
|
if(generators.size() == 0)
|
|
{
|
|
return;
|
|
}
|
|
// Skip local generators that are excluded from this project.
|
|
for(std::vector<cmLocalGenerator*>::iterator g = generators.begin();
|
|
g != generators.end(); ++g)
|
|
{
|
|
if(this->IsExcluded(root, *g))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
this->CreateXCodeObjects(root,
|
|
generators);
|
|
std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
|
|
xcodeDir += "/";
|
|
xcodeDir += root->GetMakefile()->GetProjectName();
|
|
xcodeDir += ".xcode";
|
|
if(this->XcodeVersion > 20)
|
|
{
|
|
xcodeDir += "proj";
|
|
}
|
|
cmSystemTools::MakeDirectory(xcodeDir.c_str());
|
|
std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
|
|
cmGeneratedFileStream fout(xcodeProjFile.c_str());
|
|
fout.SetCopyIfDifferent(true);
|
|
if(!fout)
|
|
{
|
|
return;
|
|
}
|
|
this->WriteXCodePBXProj(fout, root, generators);
|
|
this->ClearXCodeObjects();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
|
|
cmLocalGenerator* ,
|
|
std::vector<cmLocalGenerator*>& )
|
|
{
|
|
fout << "// !$*UTF8*$!\n";
|
|
fout << "{\n";
|
|
cmXCodeObject::Indent(1, fout);
|
|
fout << "archiveVersion = 1;\n";
|
|
cmXCodeObject::Indent(1, fout);
|
|
fout << "classes = {\n";
|
|
cmXCodeObject::Indent(1, fout);
|
|
fout << "};\n";
|
|
cmXCodeObject::Indent(1, fout);
|
|
fout << "objectVersion = 39;\n";
|
|
cmXCodeObject::PrintList(this->XCodeObjects, fout);
|
|
cmXCodeObject::Indent(1, fout);
|
|
fout << "rootObject = " << this->RootObject->GetId() << ";\n";
|
|
fout << "}\n";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
|
|
const
|
|
{
|
|
entry.name = this->GetName();
|
|
entry.brief = "Generate XCode project files.";
|
|
entry.full = "";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(const char* p)
|
|
{
|
|
if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
|
|
{
|
|
return cmSystemTools::ConvertToOutputPath(p);
|
|
}
|
|
else
|
|
{
|
|
std::string ret =
|
|
this->CurrentLocalGenerator->
|
|
ConvertToRelativePath(this->CurrentOutputDirectoryComponents, p);
|
|
return cmSystemTools::ConvertToOutputPath(ret.c_str());
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmGlobalXCodeGenerator::ConvertToRelativeForXCode(const char* p)
|
|
{
|
|
if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
|
|
{
|
|
return cmSystemTools::ConvertToOutputPath(p);
|
|
}
|
|
else
|
|
{
|
|
std::string ret =
|
|
this->CurrentLocalGenerator->
|
|
ConvertToRelativePath(this->ProjectOutputDirectoryComponents, p);
|
|
return cmSystemTools::ConvertToOutputPath(ret.c_str());
|
|
}
|
|
}
|
|
|
|
std::string cmGlobalXCodeGenerator::XCodeEscapePath(const char* p)
|
|
{
|
|
std::string ret = p;
|
|
if(ret.find(' ') != ret.npos)
|
|
{
|
|
std::string t = ret;
|
|
ret = "\"";
|
|
ret += t;
|
|
ret += "\"";
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void cmGlobalXCodeGenerator::
|
|
GetTargetObjectFileDirectories(cmTarget* target,
|
|
std::vector<std::string>&
|
|
dirs)
|
|
{
|
|
std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
|
|
dir += "/";
|
|
dir += this->CurrentMakefile->GetProjectName();
|
|
dir += ".build/";
|
|
dir += this->GetCMakeCFGInitDirectory();
|
|
dir += "/";
|
|
if(target->GetType() != cmTarget::EXECUTABLE)
|
|
{
|
|
dir += "lib";
|
|
}
|
|
dir += target->GetName();
|
|
if(target->GetType() == cmTarget::STATIC_LIBRARY)
|
|
{
|
|
dir += ".a";
|
|
}
|
|
if(target->GetType() == cmTarget::SHARED_LIBRARY)
|
|
{
|
|
dir += ".dylib";
|
|
}
|
|
if(target->GetType() == cmTarget::MODULE_LIBRARY)
|
|
{
|
|
dir += ".so";
|
|
}
|
|
dir += ".build/Objects-normal/";
|
|
std::string dirsave = dir;
|
|
if(this->Architectures.size())
|
|
{
|
|
for(std::vector<std::string>::iterator i = this->Architectures.begin();
|
|
i != this->Architectures.end(); ++i)
|
|
{
|
|
dir += *i;
|
|
dirs.push_back(dir);
|
|
dir = dirsave;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dirs.push_back(dir);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator
|
|
::AppendDirectoryForConfig(const char* prefix,
|
|
const char* config,
|
|
const char* suffix,
|
|
std::string& dir)
|
|
{
|
|
if(this->XcodeVersion > 20)
|
|
{
|
|
if(config)
|
|
{
|
|
if(dir.find(".framework") != dir.npos)
|
|
{
|
|
std::string::size_type pos = dir.rfind("/");
|
|
std::string framework = dir.substr(pos);
|
|
std::string newDir;
|
|
newDir = dir.substr(0, pos);
|
|
newDir += "/";
|
|
newDir += config;
|
|
dir = newDir;
|
|
}
|
|
else
|
|
{
|
|
dir += prefix;
|
|
dir += config;
|
|
dir += suffix;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix,
|
|
const char* varNameLang,
|
|
const char* varNameSuffix,
|
|
const char* default_flags)
|
|
{
|
|
if(varNameLang)
|
|
{
|
|
std::string varName = varNamePrefix;
|
|
varName += varNameLang;
|
|
varName += varNameSuffix;
|
|
if(const char* varValue =
|
|
this->CurrentMakefile->GetDefinition(varName.c_str()))
|
|
{
|
|
if(*varValue)
|
|
{
|
|
return varValue;
|
|
}
|
|
}
|
|
}
|
|
return default_flags;
|
|
}
|