fix many bugs related to target names being computed inconsistently. - Centralized computation of a target's file name to a method in cmTarget. Now that global knowledge is always available the *_CMAKE_PATH cache variables are no longer needed. - Centralized computation of link library command lines and link directory search order. - Moved computation of link directories needed to link CMake targets to be after evaluation of linking dependencies. This also removed alot of duplicate code in which each version had its own bugs. This commit is surrounded by the tags CMake-TargetNameCentralization1-pre and CMake-TargetNameCentralization1-post so make the large set of changes easy to identify.
2283 lines
78 KiB
C++
2283 lines
78 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** )
|
|
{
|
|
m_Data = "";
|
|
}
|
|
void EndElement(const char* name)
|
|
{
|
|
if(strcmp(name, "key") == 0)
|
|
{
|
|
m_Key = m_Data;
|
|
}
|
|
else if(strcmp(name, "string") == 0)
|
|
{
|
|
if(m_Key == "CFBundleShortVersionString")
|
|
{
|
|
m_Version = (int)(10.0 * atof(m_Data.c_str()));
|
|
}
|
|
}
|
|
}
|
|
void CharacterDataHandler(const char* data, int length)
|
|
{
|
|
m_Data.append(data, length);
|
|
}
|
|
int m_Version;
|
|
std::string m_Key;
|
|
std::string m_Data;
|
|
};
|
|
#endif
|
|
|
|
|
|
//TODO
|
|
// add OSX application stuff
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmGlobalXCodeGenerator::cmGlobalXCodeGenerator()
|
|
{
|
|
m_FindMakeProgramFile = "CMakeFindXCode.cmake";
|
|
m_RootObject = 0;
|
|
m_MainGroupChildren = 0;
|
|
m_SourcesGroupChildren = 0;
|
|
m_CurrentMakefile = 0;
|
|
m_CurrentLocalGenerator = 0;
|
|
m_XcodeVersion = 15;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmGlobalGenerator* cmGlobalXCodeGenerator::New()
|
|
{
|
|
#if defined(CMAKE_BUILD_WITH_CMAKE)
|
|
cmXcodeVersionParser parser;
|
|
parser.ParseFile("/Developer/Applications/Xcode.app/Contents/version.plist");
|
|
if(parser.m_Version == 15)
|
|
{
|
|
return new cmGlobalXCodeGenerator;
|
|
}
|
|
else if (parser.m_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.m_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(m_XcodeVersion == 15)
|
|
{
|
|
mf->AddDefinition("CMAKE_CFG_INTDIR",".");
|
|
}
|
|
else
|
|
{
|
|
mf->AddDefinition("CMAKE_CFG_INTDIR","$(CONFIGURATION)");
|
|
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");
|
|
this->cmGlobalGenerator::EnableLanguage(lang, mf);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmGlobalXCodeGenerator::GenerateBuildCommand(const char* makeProgram,
|
|
const char *projectName, const char* additionalOptions, const char *targetName,
|
|
const char* config, bool ignoreErrors)
|
|
{
|
|
// 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(m_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(m_XcodeVersion == 15)
|
|
{
|
|
makeCommand += " -buildstyle Development ";
|
|
}
|
|
else
|
|
{
|
|
makeCommand += " -configuration ";
|
|
makeCommand += config?config:"Debug";
|
|
}
|
|
if ( additionalOptions )
|
|
{
|
|
makeCommand += " ";
|
|
makeCommand += additionalOptions;
|
|
}
|
|
makeCommand += " OBJROOT=.";
|
|
return makeCommand;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::ConfigureOutputPaths()
|
|
{
|
|
// Format the library and executable output paths.
|
|
m_LibraryOutputPath =
|
|
m_CurrentMakefile->GetSafeDefinition("LIBRARY_OUTPUT_PATH");
|
|
if(m_LibraryOutputPath.size() == 0)
|
|
{
|
|
m_LibraryOutputPath = m_CurrentMakefile->GetCurrentOutputDirectory();
|
|
}
|
|
// make sure there is a trailing slash
|
|
if(m_LibraryOutputPath.size() &&
|
|
m_LibraryOutputPath[m_LibraryOutputPath.size()-1] != '/')
|
|
{
|
|
m_LibraryOutputPath += "/";
|
|
if(!cmSystemTools::MakeDirectory(m_LibraryOutputPath.c_str()))
|
|
{
|
|
cmSystemTools::Error("Error creating directory ",
|
|
m_LibraryOutputPath.c_str());
|
|
}
|
|
}
|
|
m_CurrentMakefile->AddLinkDirectory(m_LibraryOutputPath.c_str());
|
|
m_ExecutableOutputPath =
|
|
m_CurrentMakefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
|
|
if(m_ExecutableOutputPath.size() == 0)
|
|
{
|
|
m_ExecutableOutputPath = m_CurrentMakefile->GetCurrentOutputDirectory();
|
|
}
|
|
// make sure there is a trailing slash
|
|
if(m_ExecutableOutputPath.size() &&
|
|
m_ExecutableOutputPath[m_ExecutableOutputPath.size()-1] != '/')
|
|
{
|
|
m_ExecutableOutputPath += "/";
|
|
if(!cmSystemTools::MakeDirectory(m_ExecutableOutputPath.c_str()))
|
|
{
|
|
cmSystemTools::Error("Error creating directory ",
|
|
m_ExecutableOutputPath.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
///! Create a local generator appropriate to this Global Generator
|
|
cmLocalGenerator *cmGlobalXCodeGenerator::CreateLocalGenerator()
|
|
{
|
|
cmLocalGenerator *lg = new cmLocalXCodeGenerator;
|
|
lg->SetGlobalGenerator(this);
|
|
return lg;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::Generate()
|
|
{
|
|
this->cmGlobalGenerator::Generate();
|
|
std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
|
|
for(it = m_ProjectMap.begin(); it!= m_ProjectMap.end(); ++it)
|
|
{
|
|
cmLocalGenerator* root = it->second[0];
|
|
m_CurrentProject = root->GetMakefile()->GetProjectName();
|
|
this->SetCurrentLocalGenerator(root);
|
|
m_OutputDir = m_CurrentMakefile->GetHomeOutputDirectory();
|
|
m_OutputDir = cmSystemTools::CollapseFullPath(m_OutputDir.c_str());
|
|
cmSystemTools::SplitPath(m_OutputDir.c_str(),
|
|
m_ProjectOutputDirectoryComponents);
|
|
m_CurrentLocalGenerator = root;
|
|
// add ALL_BUILD, INSTALL, etc
|
|
this->AddExtraTargets(root, it->second);
|
|
// now create the project
|
|
this->OutputXCodeProject(root, it->second);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
|
|
std::vector<cmLocalGenerator*>& gens)
|
|
{
|
|
cmMakefile* mf = root->GetMakefile();
|
|
// Add ALL_BUILD
|
|
const char* no_output = 0;
|
|
std::vector<std::string> no_depends;
|
|
mf->AddUtilityCommand("ALL_BUILD", false, no_output, no_depends,
|
|
"echo", "Build all projects");
|
|
cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
|
|
// ADD install
|
|
std::string cmake_command = mf->GetRequiredDefinition("CMAKE_COMMAND");
|
|
if(m_XcodeVersion == 15)
|
|
{
|
|
mf->AddUtilityCommand("install", false, no_output, no_depends,
|
|
cmake_command.c_str(),
|
|
"-P", "cmake_install.cmake");
|
|
}
|
|
else
|
|
{
|
|
mf->AddUtilityCommand("install", false, no_output, no_depends,
|
|
cmake_command.c_str(),
|
|
"-DBUILD_TYPE=$(CONFIGURATION)",
|
|
"-P", "cmake_install.cmake");
|
|
}
|
|
|
|
const char* noall =
|
|
mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
|
|
if(!noall || cmSystemTools::IsOff(noall))
|
|
{
|
|
cmTarget* install = mf->FindTarget("install");
|
|
install->AddUtility("ALL_BUILD");
|
|
}
|
|
|
|
// Add RUN_TESTS target if testing has been enabled
|
|
std::string fname;
|
|
fname = mf->GetStartOutputDirectory();
|
|
fname += "/";
|
|
fname += "DartTestfile.txt";
|
|
if (cmSystemTools::FileExists(fname.c_str()))
|
|
{
|
|
std::string ctest_command =
|
|
mf->GetRequiredDefinition("CMAKE_CTEST_COMMAND");
|
|
mf->AddUtilityCommand("RUN_TESTS", false, no_output, no_depends,
|
|
ctest_command.c_str());
|
|
}
|
|
// Add XCODE depend helper
|
|
std::string dir = mf->GetCurrentOutputDirectory();
|
|
m_CurrentXCodeHackMakefile = dir;
|
|
m_CurrentXCodeHackMakefile += "/CMakeScripts";
|
|
cmSystemTools::MakeDirectory(m_CurrentXCodeHackMakefile.c_str());
|
|
m_CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
|
|
cmCustomCommandLine makecommand;
|
|
makecommand.push_back("make");
|
|
makecommand.push_back("-C");
|
|
makecommand.push_back(dir.c_str());
|
|
makecommand.push_back("-f");
|
|
makecommand.push_back(m_CurrentXCodeHackMakefile.c_str());
|
|
if(m_XcodeVersion > 20)
|
|
{
|
|
makecommand.push_back("all.$(CONFIGURATION)");
|
|
}
|
|
cmCustomCommandLines commandLines;
|
|
commandLines.push_back(makecommand);
|
|
mf->AddUtilityCommand("XCODE_DEPEND_HELPER", false, no_output, 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.IsInAll())
|
|
{
|
|
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();
|
|
m_CurrentReRunCMakeMakefile = dir;
|
|
m_CurrentReRunCMakeMakefile += "/CMakeScripts";
|
|
cmSystemTools::MakeDirectory(m_CurrentReRunCMakeMakefile.c_str());
|
|
m_CurrentReRunCMakeMakefile += "/ReRunCMake.make";
|
|
cmGeneratedFileStream makefileStream(m_CurrentReRunCMakeMakefile.c_str());
|
|
makefileStream.SetCopyIfDifferent(true);
|
|
makefileStream << "# Generated by CMake, DO NOT EDIT\n";
|
|
makefileStream << "CMakeFiles/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()
|
|
{
|
|
m_TargetDoneSet.clear();
|
|
for(unsigned int i = 0; i < m_XCodeObjects.size(); ++i)
|
|
{
|
|
delete m_XCodeObjects[i];
|
|
}
|
|
m_XCodeObjects.clear();
|
|
m_GroupMap.clear();
|
|
m_GroupNameMap.clear();
|
|
m_TargetGroup.clear();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype)
|
|
{
|
|
cmXCodeObject* obj;
|
|
if(m_XcodeVersion == 15)
|
|
{
|
|
obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
|
|
}
|
|
else
|
|
{
|
|
obj = new cmXCode21Object(ptype, cmXCodeObject::OBJECT);
|
|
}
|
|
m_XCodeObjects.push_back(obj);
|
|
return obj;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject*
|
|
cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
|
|
{
|
|
cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
|
|
m_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)
|
|
{
|
|
std::string flags;
|
|
// Add flags from source file properties.
|
|
lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
|
|
|
|
cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
|
|
|
|
cmXCodeObject* group = m_GroupMap[sf];
|
|
cmXCodeObject* children = group->GetObject("children");
|
|
children->AddObject(fileRef);
|
|
cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
|
|
std::string fname = sf->GetSourceName();
|
|
fname += ".";
|
|
fname += sf->GetSourceExtension();
|
|
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->GetLanguageFromExtension(sf->GetSourceExtension().c_str());
|
|
std::string sourcecode = "sourcecode";
|
|
std::string ext = sf->GetSourceExtension();
|
|
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
|
|
{
|
|
sourcecode += ".cpp.cpp";
|
|
}
|
|
|
|
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(m_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(m_TargetDoneSet.find(tname) != m_TargetDoneSet.end())
|
|
{
|
|
return true;
|
|
}
|
|
m_TargetDoneSet.insert(tname);
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
|
|
{
|
|
m_CurrentLocalGenerator = gen;
|
|
m_CurrentMakefile = gen->GetMakefile();
|
|
std::string outdir =
|
|
cmSystemTools::CollapseFullPath(m_CurrentMakefile->
|
|
GetCurrentOutputDirectory());
|
|
cmSystemTools::SplitPath(outdir.c_str(), m_CurrentOutputDirectoryComponents);
|
|
|
|
// Select the current set of configuration types.
|
|
m_CurrentConfigurationTypes.clear();
|
|
if(m_XcodeVersion > 20)
|
|
{
|
|
if(const char* types =
|
|
m_CurrentMakefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
|
|
{
|
|
cmSystemTools::ExpandListArgument(types, m_CurrentConfigurationTypes);
|
|
}
|
|
}
|
|
if(m_CurrentConfigurationTypes.empty())
|
|
{
|
|
if(const char* buildType =
|
|
m_CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE"))
|
|
{
|
|
m_CurrentConfigurationTypes.push_back(buildType);
|
|
}
|
|
else
|
|
{
|
|
m_CurrentConfigurationTypes.push_back("");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
|
|
std::vector<cmXCodeObject*>&
|
|
targets)
|
|
{
|
|
this->SetCurrentLocalGenerator(gen);
|
|
cmTargets &tgts = m_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::INSTALL_FILES ||
|
|
cmtarget.GetType() == cmTarget::INSTALL_PROGRAMS)
|
|
{
|
|
if(cmtarget.GetType() == cmTarget::UTILITY)
|
|
{
|
|
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*> &classes = l->second.GetSourceFiles();
|
|
// add all the sources
|
|
std::vector<cmXCodeObject*> externalObjFiles;
|
|
std::vector<cmXCodeObject*> headerFiles;
|
|
for(std::vector<cmSourceFile*>::iterator i = classes.begin();
|
|
i != classes.end(); ++i)
|
|
{
|
|
cmXCodeObject* xsf =
|
|
this->CreateXCodeSourceFile(m_CurrentLocalGenerator, *i);
|
|
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));
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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*> &classes = cmtarget.GetSourceFiles();
|
|
// add all the sources
|
|
std::vector<cmCustomCommand> commands;
|
|
for(std::vector<cmSourceFile*>::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)
|
|
{
|
|
retFlag = flag;
|
|
// remove the flag
|
|
flags[pos]=' ';
|
|
flags[pos+1]=' ';
|
|
char pos2 = flags[pos+2];
|
|
// if the pos after the option
|
|
if(pos2 != ' ' && pos2 != 0 )
|
|
{
|
|
retFlag += pos2;
|
|
// remove the next part of the flag
|
|
flags[pos+2] = ' ';
|
|
}
|
|
}
|
|
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 = m_CurrentMakefile->GetHomeOutputDirectory();
|
|
cdir = this->ConvertToRelativeForMake(cdir.c_str());
|
|
std::string makecmd = "make -C ";
|
|
makecmd += cdir;
|
|
makecmd += " -f ";
|
|
makecmd +=
|
|
this->ConvertToRelativeForMake(m_CurrentReRunCMakeMakefile.c_str());
|
|
cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
|
|
buildphase->AddAttribute("shellScript",
|
|
this->CreateString(makecmd.c_str()));
|
|
return;
|
|
}
|
|
|
|
std::string dir = m_CurrentMakefile->GetCurrentOutputDirectory();
|
|
dir += "/CMakeScripts";
|
|
cmSystemTools::MakeDirectory(dir.c_str());
|
|
std::string makefile = dir;
|
|
makefile += "/";
|
|
makefile += target.GetName();
|
|
makefile += "_";
|
|
makefile += name;
|
|
makefile += ".make";
|
|
cmGeneratedFileStream makefileStream(makefile.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())
|
|
{
|
|
if(cc.GetOutput()[0])
|
|
{
|
|
makefileStream << "\\\n\t" << this->
|
|
ConvertToRelativeForMake(cc.GetOutput());
|
|
}
|
|
else
|
|
{
|
|
char c = '1' + count++;
|
|
tname[&cc] = std::string(target.GetName()) + c;
|
|
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())
|
|
{
|
|
|
|
makefileStream << "\n#" << "Custom command rule: " <<
|
|
cc.GetComment() << "\n";
|
|
if(cc.GetOutput()[0])
|
|
{
|
|
makefileStream << this
|
|
->ConvertToRelativeForMake(cc.GetOutput()) << ": ";
|
|
}
|
|
else
|
|
{
|
|
makefileStream << tname[&cc] << ": ";
|
|
}
|
|
for(std::vector<std::string>::const_iterator d = cc.GetDepends().begin();
|
|
d != cc.GetDepends().end(); ++d)
|
|
{
|
|
if(!this->FindTarget(m_CurrentProject.c_str(),
|
|
d->c_str()))
|
|
{
|
|
// if the depend is not a target but
|
|
// is a full path then use it, if not then
|
|
// just skip it
|
|
if(cmSystemTools::FileIsFullPath(d->c_str()))
|
|
{
|
|
makefileStream << "\\\n" << this
|
|
->ConvertToRelativeForMake(d->c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if the depend is a target then make
|
|
// the target with the source that is a custom command
|
|
// depend on the that target via a AddUtility call
|
|
target.AddUtility(d->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 cmd = commandLine[0];
|
|
cmSystemTools::ReplaceString(cmd, "/./", "/");
|
|
cmd = this->ConvertToRelativeForMake(cmd.c_str());
|
|
for(unsigned int j=1; j < commandLine.size(); ++j)
|
|
{
|
|
cmd += " ";
|
|
cmd += cmSystemTools::EscapeSpaces(commandLine[j].c_str());
|
|
}
|
|
makefileStream << "\t" << cmd.c_str() << "\n";
|
|
}
|
|
}
|
|
}
|
|
std::string cdir = m_CurrentMakefile->GetCurrentOutputDirectory();
|
|
cdir = this->ConvertToRelativeForXCode(cdir.c_str());
|
|
std::string makecmd = "make -C ";
|
|
makecmd += cdir;
|
|
makecmd += " -f ";
|
|
makecmd += this->ConvertToRelativeForMake(makefile.c_str());
|
|
cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
|
|
buildphase->AddAttribute("shellScript", this->CreateString(makecmd.c_str()));
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
|
|
cmXCodeObject* buildSettings,
|
|
std::string& fileType,
|
|
std::string& productType,
|
|
std::string& productName,
|
|
const char* configName)
|
|
{
|
|
this->ConfigureOutputPaths();
|
|
std::string flags;
|
|
std::string defFlags;
|
|
bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
|
|
(target.GetType() == cmTarget::MODULE_LIBRARY));
|
|
if(shared)
|
|
{
|
|
defFlags += "-D";
|
|
if(const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL"))
|
|
{
|
|
defFlags += custom_export_name;
|
|
}
|
|
else
|
|
{
|
|
std::string in = target.GetName();
|
|
in += "_EXPORTS";
|
|
defFlags += cmSystemTools::MakeCindentifier(in.c_str());
|
|
}
|
|
}
|
|
const char* lang = target.GetLinkerLanguage(this);
|
|
std::string cflags;
|
|
if(lang)
|
|
{
|
|
// Temporarily set the CMAKE_BUILD_TYPE so the local generator can use
|
|
// it. TODO: The local generator methods should take the configuration
|
|
// name as input.
|
|
if(configName)
|
|
{
|
|
m_CurrentMakefile->AddDefinition("CMAKE_BUILD_TYPE", configName);
|
|
}
|
|
// for c++ projects get the c flags as well
|
|
if(strcmp(lang, "CXX") == 0)
|
|
{
|
|
m_CurrentLocalGenerator->AddLanguageFlags(cflags, "C");
|
|
m_CurrentLocalGenerator->AddSharedFlags(cflags, lang, shared);
|
|
}
|
|
// Add language-specific flags.
|
|
m_CurrentLocalGenerator->AddLanguageFlags(flags, lang);
|
|
|
|
// Add shared-library flags if needed.
|
|
m_CurrentLocalGenerator->AddSharedFlags(flags, lang, shared);
|
|
|
|
// Remove the temporary CMAKE_BUILD_TYPE definition.
|
|
m_CurrentMakefile->AddDefinition("CMAKE_BUILD_TYPE", "");
|
|
}
|
|
|
|
// Add define flags
|
|
m_CurrentLocalGenerator->AppendFlags(defFlags,
|
|
m_CurrentMakefile->GetDefineFlags());
|
|
cmSystemTools::ReplaceString(defFlags, "\"", "\\\"");
|
|
cmSystemTools::ReplaceString(flags, "\"", "\\\"");
|
|
cmSystemTools::ReplaceString(cflags, "\"", "\\\"");
|
|
if(m_XcodeVersion > 15)
|
|
{
|
|
buildSettings->
|
|
AddAttribute("GCC_PREPROCESSOR_DEFINITIONS",
|
|
this->CreateString("CMAKE_INTDIR=\\\\\\\"$(CONFIGURATION)\\\\\\\""));
|
|
|
|
}
|
|
std::string extraLinkOptions;
|
|
if(target.GetType() == cmTarget::EXECUTABLE)
|
|
{
|
|
extraLinkOptions =
|
|
m_CurrentMakefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
|
|
}
|
|
if(target.GetType() == cmTarget::SHARED_LIBRARY)
|
|
{
|
|
extraLinkOptions =
|
|
m_CurrentMakefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
|
|
}
|
|
if(target.GetType() == cmTarget::MODULE_LIBRARY)
|
|
{
|
|
extraLinkOptions =
|
|
m_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();
|
|
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(m_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"));
|
|
buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
|
|
this->CreateString("NO"));
|
|
buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
|
|
this->CreateString("NO"));
|
|
std::string outflag = "-o \\\"$(CONFIGURATION_BUILD_DIR)/";
|
|
outflag += productName;
|
|
outflag += "\\\"";
|
|
extraLinkOptions += " ";
|
|
extraLinkOptions += outflag;
|
|
}
|
|
else
|
|
{
|
|
fileType = "compiled.mach-o.dylib";
|
|
productType = "com.apple.product-type.library.dynamic";
|
|
|
|
extraLinkOptions += " -bundle";
|
|
}
|
|
break;
|
|
}
|
|
case cmTarget::SHARED_LIBRARY:
|
|
{
|
|
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"));
|
|
extraLinkOptions += " -dynamiclib";
|
|
break;
|
|
}
|
|
case cmTarget::EXECUTABLE:
|
|
{
|
|
fileType = "compiled.mach-o.executable";
|
|
|
|
// Handle bundles and normal executables separately.
|
|
if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
|
|
{
|
|
productType = "com.apple.product-type.application";
|
|
std::string f1 =
|
|
m_CurrentMakefile->GetModulesFile("MacOSXBundleInfo.plist.in");
|
|
if ( f1.size() == 0 )
|
|
{
|
|
cmSystemTools::Error("could not find Mac OSX bundle template file.");
|
|
}
|
|
std::string f2 = m_CurrentMakefile->GetCurrentOutputDirectory();
|
|
f2 += "/Info.plist";
|
|
m_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;
|
|
}
|
|
|
|
std::string dirs;
|
|
std::vector<std::string>& includes =
|
|
m_CurrentMakefile->GetIncludeDirectories();
|
|
std::vector<std::string>::iterator i = includes.begin();
|
|
std::string fdirs;
|
|
std::set<cmStdString> emitted;
|
|
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);
|
|
std::string gflag = this->ExtractFlag("-g", flags);
|
|
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("INSTALL_PATH",
|
|
this->CreateString(""));
|
|
buildSettings->AddAttribute("OPTIMIZATION_CFLAGS",
|
|
this->CreateString(oflagc.c_str()));
|
|
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()));
|
|
}
|
|
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;
|
|
this->CreateBuildSettings(cmtarget,
|
|
buildSettings, fileTypeString,
|
|
productTypeString, productName, 0);
|
|
if(m_XcodeVersion > 20)
|
|
{
|
|
this->AddConfigurations(target, cmtarget);
|
|
}
|
|
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->SetcmTarget(&cmtarget);
|
|
return target;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
|
|
cmTarget& cmtarget)
|
|
{
|
|
std::string configTypes = m_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;
|
|
if(m_XcodeVersion > 20)
|
|
{
|
|
this->AddConfigurations(target, cmtarget);
|
|
}
|
|
this->CreateBuildSettings(cmtarget,
|
|
buildSettings, fileTypeString,
|
|
productTypeString, productName, 0);
|
|
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->SetcmTarget(&cmtarget);
|
|
return target;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
|
|
{
|
|
if(!t)
|
|
{
|
|
return 0;
|
|
}
|
|
for(std::vector<cmXCodeObject*>::iterator i = m_XCodeObjects.begin();
|
|
i != m_XCodeObjects.end(); ++i)
|
|
{
|
|
cmXCodeObject* o = *i;
|
|
if(o->GetcmTarget() == 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(m_RootObject));
|
|
container->AddAttribute("proxyType", this->CreateString("1"));
|
|
container->AddAttribute("remoteGlobalIDString",
|
|
this->CreateObjectReference(dependTarget));
|
|
container->AddAttribute("remoteInfo",
|
|
this->CreateString(
|
|
dependTarget->GetcmTarget()->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(m_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->GetcmTarget();
|
|
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::LinkLibraries& tlibs = cmtarget->GetLinkLibraries();
|
|
for(cmTarget::LinkLibraries::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(m_CurrentProject.c_str(),
|
|
lib->first.c_str());
|
|
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(m_CurrentProject.c_str(),
|
|
i->c_str());
|
|
// 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 += m_CurrentProject.c_str();
|
|
cmSystemTools::Error(m.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop over configuration types and set per-configuration info.
|
|
for(std::vector<std::string>::iterator i =
|
|
m_CurrentConfigurationTypes.begin();
|
|
i != m_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;
|
|
m_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(m_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)
|
|
{
|
|
for(std::vector<cmStdString>::iterator lib = libNames.begin();
|
|
lib != libNames.end(); ++lib)
|
|
{
|
|
this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
|
|
lib->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"))
|
|
{
|
|
cmSourceFile file;
|
|
file.SetName("Info",
|
|
m_CurrentMakefile->GetCurrentOutputDirectory(),
|
|
"plist", false);
|
|
cmtarget.GetSourceFiles().push_back(m_CurrentMakefile->AddSource(file));
|
|
}
|
|
|
|
std::vector<cmSourceFile*> & classes = cmtarget.GetSourceFiles();
|
|
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);
|
|
m_GroupMap[sf] = pbxgroup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
cmXCodeObject* cmGlobalXCodeGenerator::CreateOrGetPBXGroup(cmTarget& cmtarget,
|
|
cmSourceGroup* sg)
|
|
{
|
|
cmStdString s = cmtarget.GetName();
|
|
s += "/";
|
|
s += sg->GetName();
|
|
std::map<cmStdString, cmXCodeObject* >::iterator i = m_GroupNameMap.find(s);
|
|
if(i != m_GroupNameMap.end())
|
|
{
|
|
return i->second;
|
|
}
|
|
i = m_TargetGroup.find(cmtarget.GetName());
|
|
cmXCodeObject* tgroup = 0;
|
|
if(i != m_TargetGroup.end())
|
|
{
|
|
tgroup = i->second;
|
|
}
|
|
else
|
|
{
|
|
tgroup = this->CreateObject(cmXCodeObject::PBXGroup);
|
|
m_TargetGroup[cmtarget.GetName()] = tgroup;
|
|
cmXCodeObject* tgroupChildren =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
tgroup->AddAttribute("name", this->CreateString(cmtarget.GetName()));
|
|
tgroup->AddAttribute("children", tgroupChildren);
|
|
if(m_XcodeVersion == 15)
|
|
{
|
|
tgroup->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
tgroup->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
m_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(m_XcodeVersion == 15)
|
|
{
|
|
group->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
group->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
tgroupChildren->AddObject(group);
|
|
m_GroupNameMap[s] = group;
|
|
return group;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void cmGlobalXCodeGenerator::CreateXCodeObjects(cmLocalGenerator* root,
|
|
std::vector<cmLocalGenerator*>&
|
|
generators
|
|
)
|
|
{
|
|
this->ClearXCodeObjects();
|
|
m_RootObject = 0;
|
|
m_SourcesGroupChildren = 0;
|
|
m_MainGroupChildren = 0;
|
|
cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
|
|
cmXCodeObject* developBuildStyle =
|
|
this->CreateObject(cmXCodeObject::PBXBuildStyle);
|
|
if(m_XcodeVersion == 15)
|
|
{
|
|
developBuildStyle->AddAttribute("name", this->CreateString("Development"));
|
|
}
|
|
else
|
|
{
|
|
developBuildStyle->AddAttribute("name", this->CreateString("Debug"));
|
|
developBuildStyle->SetComment("Debug");
|
|
}
|
|
developBuildStyle->AddAttribute("buildSettings", group);
|
|
|
|
group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
|
|
cmXCodeObject* deployBuildStyle =
|
|
this->CreateObject(cmXCodeObject::PBXBuildStyle);
|
|
if(m_XcodeVersion == 15)
|
|
{
|
|
deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
|
|
}
|
|
else
|
|
{
|
|
deployBuildStyle->AddAttribute("name", this->CreateString("Release"));
|
|
deployBuildStyle->SetComment("Release");
|
|
}
|
|
|
|
deployBuildStyle->AddAttribute("buildSettings", group);
|
|
|
|
cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
listObjs->AddObject(developBuildStyle);
|
|
listObjs->AddObject(deployBuildStyle);
|
|
cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
|
|
m_MainGroupChildren =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
mainGroup->AddAttribute("children", m_MainGroupChildren);
|
|
if(m_XcodeVersion == 15)
|
|
{
|
|
mainGroup->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
|
|
cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
|
|
m_SourcesGroupChildren =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
|
|
sourcesGroup->AddAttribute("children", m_SourcesGroupChildren);
|
|
if(m_XcodeVersion == 15)
|
|
{
|
|
sourcesGroup->AddAttribute("refType", this->CreateString("4"));
|
|
}
|
|
sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
|
|
m_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(m_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);
|
|
m_MainGroupChildren->AddObject(productGroup);
|
|
|
|
|
|
m_RootObject = this->CreateObject(cmXCodeObject::PBXProject);
|
|
m_RootObject->SetComment("Project object");
|
|
group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
|
|
m_RootObject->AddAttribute("mainGroup",
|
|
this->CreateObjectReference(mainGroup));
|
|
m_RootObject->AddAttribute("buildSettings", group);
|
|
m_RootObject->AddAttribute("buildStyles", listObjs);
|
|
m_RootObject->AddAttribute("hasScannedForEncodings",
|
|
this->CreateString("0"));
|
|
cmXCodeObject* configlist = this->CreateObject(cmXCodeObject::XCConfigurationList);
|
|
cmXCodeObject* configDebug = this->CreateObject(cmXCodeObject::XCBuildConfiguration);
|
|
cmXCodeObject* configRelease = this->CreateObject(cmXCodeObject::XCBuildConfiguration);
|
|
cmXCodeObject* buildConfigurations =
|
|
this->CreateObject(cmXCodeObject::OBJECT_LIST);
|
|
buildConfigurations->AddObject(configDebug);
|
|
buildConfigurations->AddObject(configRelease);
|
|
configlist->AddAttribute("buildConfigurations", buildConfigurations);
|
|
std::string comment = "Build configuration list for PBXProject ";
|
|
comment += " \"";
|
|
comment += m_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);
|
|
configDebug->AddAttribute("name", this->CreateString("Debug"));
|
|
configDebug->AddAttribute("buildSettings", buildSettings);
|
|
configRelease->AddAttribute("name", this->CreateString("Release"));
|
|
configRelease->AddAttribute("buildSettings", buildSettings);
|
|
|
|
m_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());
|
|
}
|
|
}
|
|
m_RootObject->AddAttribute("targets", allTargets);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
|
|
std::vector<cmXCodeObject*>& targets)
|
|
{
|
|
cmGeneratedFileStream makefileStream(m_CurrentXCodeHackMakefile.c_str());
|
|
if(!makefileStream)
|
|
{
|
|
cmSystemTools::Error("Could not create",
|
|
m_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 = m_CurrentConfigurationTypes.begin();
|
|
ct != m_CurrentConfigurationTypes.end(); ++ct)
|
|
{
|
|
if(m_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->GetcmTarget();
|
|
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 = m_CurrentConfigurationTypes.begin();
|
|
ct != m_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->GetcmTarget();
|
|
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";
|
|
makefileStream << "\n\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
|
|
std::vector<cmLocalGenerator*>&
|
|
generators)
|
|
{
|
|
if(generators.size() == 0)
|
|
{
|
|
return;
|
|
}
|
|
#if 1
|
|
// TODO: This block should be moved to a central location for all
|
|
// generators. It is duplicated in every generator.
|
|
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();
|
|
// Call TraceVSDependencies on all targets
|
|
for(cmTargets::iterator l = tgts.begin();
|
|
l != tgts.end(); l++)
|
|
{
|
|
// INCLUDE_EXTERNAL_MSPROJECT command only affects the workspace
|
|
// so don't build a projectfile for it
|
|
if ((l->second.GetType() != cmTarget::INSTALL_FILES)
|
|
&& (l->second.GetType() != cmTarget::INSTALL_PROGRAMS)
|
|
&& (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) != 0))
|
|
{
|
|
cmTarget& target = l->second;
|
|
target.TraceVSDependencies(target.GetName(), mf);
|
|
}
|
|
}
|
|
// now for all custom commands that are not used directly in a
|
|
// target, add them to all targets in the current directory or
|
|
// makefile
|
|
std::set<cmStdString> banned;
|
|
banned.insert("ALL_BUILD");
|
|
banned.insert("XCODE_DEPEND_HELPER");
|
|
banned.insert("install");
|
|
std::vector<cmSourceFile*> & classesmf = mf->GetSourceFiles();
|
|
for(std::vector<cmSourceFile*>::const_iterator i = classesmf.begin();
|
|
i != classesmf.end(); i++)
|
|
{
|
|
if(cmCustomCommand* cc = (*i)->GetCustomCommand())
|
|
{
|
|
if(!cc->IsUsed())
|
|
{
|
|
for(cmTargets::iterator l = tgts.begin();
|
|
l != tgts.end(); l++)
|
|
{
|
|
if ((l->second.GetType() != cmTarget::INSTALL_FILES)
|
|
&& (l->second.GetType() != cmTarget::INSTALL_PROGRAMS)
|
|
&& (strncmp(l->first.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) != 0)
|
|
&& banned.find(l->second.GetName()) == banned.end())
|
|
{
|
|
cmTarget& target = l->second;
|
|
bool sameAsTarget = false;
|
|
// make sure we don't add a custom command that depends on
|
|
// this target
|
|
for(unsigned int k =0; k < cc->GetDepends().size(); k++)
|
|
{
|
|
if(cmSystemTools::GetFilenameName(cc->GetDepends()[k]) == target.GetFullName())
|
|
{
|
|
sameAsTarget = true;
|
|
}
|
|
}
|
|
if(!sameAsTarget)
|
|
{
|
|
target.GetSourceFiles().push_back(*i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
this->CreateXCodeObjects(root,
|
|
generators);
|
|
std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
|
|
xcodeDir += "/";
|
|
xcodeDir += root->GetMakefile()->GetProjectName();
|
|
xcodeDir += ".xcode";
|
|
if(m_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(m_XCodeObjects, fout);
|
|
cmXCodeObject::Indent(1, fout);
|
|
fout << "rootObject = " << m_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 ( !m_CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
|
|
{
|
|
return cmSystemTools::ConvertToOutputPath(p);
|
|
}
|
|
else
|
|
{
|
|
std::string ret =
|
|
this->ConvertToRelativePath(m_CurrentOutputDirectoryComponents, p);
|
|
return cmSystemTools::ConvertToOutputPath(ret.c_str());
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::string cmGlobalXCodeGenerator::ConvertToRelativeForXCode(const char* p)
|
|
{
|
|
if ( !m_CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
|
|
{
|
|
return cmSystemTools::ConvertToOutputPath(p);
|
|
}
|
|
else
|
|
{
|
|
std::string ret =
|
|
this->ConvertToRelativePath(m_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;
|
|
}
|