/*========================================================================= 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 "cmLocalXCodeGenerator.h" #include "cmMakefile.h" #include "cmXCodeObject.h" #include "cmake.h" #include "cmGeneratedFileStream.h" #include "cmSourceFile.h" //TODO // custom commands // custom targets // ALL_BUILD // RUN_TESTS // add a group for Sources Headers, and other cmake group stuff // for each target create a custom build phase that is run first // it can have inputs and outputs should just be a makefile // per file flags howto // 115281011528101152810000 = { // fileEncoding = 4; // isa = PBXFileReference; // lastKnownFileType = sourcecode.cpp.cpp; // path = /Users/kitware/Bill/CMake/Source/cmakemain.cxx; // refType = 0; // sourceTree = ""; // }; // 115285011528501152850000 = { // fileRef = 115281011528101152810000; // isa = PBXBuildFile; // settings = { // COMPILER_FLAGS = "-Dcmakemakeindefflag"; // }; // }; // custom commands and clean up custom targets // do I need an ALL_BUILD yes // exe/lib output paths //---------------------------------------------------------------------------- cmGlobalXCodeGenerator::cmGlobalXCodeGenerator() { m_FindMakeProgramFile = "CMakeFindXCode.cmake"; m_RootObject = 0; m_MainGroupChildren = 0; m_SourcesGroupChildren = 0; m_ExternalGroupChildren = 0; } //---------------------------------------------------------------------------- void cmGlobalXCodeGenerator::EnableLanguage(std::vectorconst& lang, cmMakefile * mf) { 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); } //---------------------------------------------------------------------------- int cmGlobalXCodeGenerator::TryCompile(const char *, const char * bindir, const char * projectName, const char * targetName, std::string * output, cmMakefile*) { // now build the test std::string makeCommand = m_CMakeInstance->GetCacheManager()->GetCacheValue("CMAKE_MAKE_PROGRAM"); if(makeCommand.size() == 0) { cmSystemTools::Error( "Generator cannot find the appropriate make command."); return 1; } makeCommand = cmSystemTools::ConvertToOutputPath(makeCommand.c_str()); std::string lowerCaseCommand = makeCommand; cmSystemTools::LowerCase(lowerCaseCommand); /** * Run an executable command and put the stdout in output. */ std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); cmSystemTools::ChangeDirectory(bindir); // Usage: xcodebuild [-project ] [-activetarget] // [-alltargets] [-target ]... [-activebuildstyle] // [-buildstyle ] [-optionalbuildstyle ] // [=]... []... // xcodebuild [-list] makeCommand += " -project "; makeCommand += projectName; makeCommand += ".xcode"; makeCommand += " build "; if (targetName) { makeCommand += "-target "; makeCommand += targetName; } makeCommand += " -buildstyle Development "; makeCommand += " SYMROOT="; makeCommand += cmSystemTools::ConvertToOutputPath(bindir); int retVal; int timeout = cmGlobalGenerator::s_TryCompileTimeout; if (!cmSystemTools::RunSingleCommand(makeCommand.c_str(), output, &retVal, 0, false, timeout)) { cmSystemTools::Error("Generator: execution of xcodebuild failed."); // return to the original directory cmSystemTools::ChangeDirectory(cwd.c_str()); return 1; } cmSystemTools::ChangeDirectory(cwd.c_str()); return retVal; } 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 >::iterator it; for(it = m_ProjectMap.begin(); it!= m_ProjectMap.end(); ++it) { this->OutputXCodeProject(it->second[0], it->second); } } //---------------------------------------------------------------------------- void cmGlobalXCodeGenerator::ClearXCodeObjects() { for(unsigned int i = 0; i < m_XCodeObjects.size(); ++i) { delete m_XCodeObjects[i]; } m_XCodeObjects.clear(); } //---------------------------------------------------------------------------- cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype) { cmXCodeObject* obj = new cmXCodeObject(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. m_CurrentLocalGenerator ->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS")); cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); m_SourcesGroupChildren->AddObject(fileRef); cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); 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"; if(!lang) { std::string ext = "."; ext = sf->GetSourceExtension(); sourcecode += ext; sourcecode += ext; } else if(strcmp(lang, "C") == 0) { sourcecode += ".c.c"; } // default to c++ else { sourcecode += ".cpp.cpp"; } fileRef->AddAttribute("lastKnownFileType", this->CreateString(sourcecode.c_str())); fileRef->AddAttribute("path", this->CreateString( lg->ConvertToRelativeOutputPath(sf->GetFullPath().c_str()).c_str())); fileRef->AddAttribute("refType", this->CreateString("4")); fileRef->AddAttribute("sourceTree", this->CreateString("")); return buildFile; } //---------------------------------------------------------------------------- void cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen, std::vector& targets) { m_CurrentLocalGenerator = gen; m_CurrentMakefile = gen->GetMakefile(); cmTargets &tgts = gen->GetMakefile()->GetTargets(); for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { cmTarget& cmtarget = l->second; 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")); cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); sourceBuildPhase->AddAttribute("files", buildFiles); sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", this->CreateString("0")); std::vector &classes = l->second.GetSourceFiles(); // add all the sources for(std::vector::iterator i = classes.begin(); i != classes.end(); ++i) { buildFiles->AddObject(this->CreateXCodeSourceFile(gen, *i)); } // create header build phase cmXCodeObject* headerBuildPhase = this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase); headerBuildPhase->AddAttribute("buildActionMask", this->CreateString("2147483647")); buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); headerBuildPhase->AddAttribute("files", buildFiles); headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", this->CreateString("0")); // create framework build phase cmXCodeObject* frameworkBuildPhase = this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase); frameworkBuildPhase->AddAttribute("buildActionMask", this->CreateString("2147483647")); buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); frameworkBuildPhase->AddAttribute("files", buildFiles); 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)); } } void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases, cmXCodeObject* sourceBuildPhase, cmXCodeObject* headerBuildPhase, cmXCodeObject* frameworkBuildPhase, cmTarget& cmtarget) { std::vector const & prebuild = cmtarget.GetPreBuildCommands(); std::vector const & prelink = cmtarget.GetPreLinkCommands(); std::vector const & postbuild = cmtarget.GetPostBuildCommands(); cmtarget.TraceVSDependencies(cmtarget.GetName(), m_CurrentMakefile); std::vector &classes = cmtarget.GetSourceFiles(); // add all the sources std::vector commands; for(std::vector::iterator i = classes.begin(); i != classes.end(); ++i) { if((*i)->GetCustomCommand()) { commands.push_back(*(*i)->GetCustomCommand()); } } // create prebuild phase cmXCodeObject* cmakeRulesBuildPhase = 0; if(commands.size()) { cmakeRulesBuildPhase = this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase); cmakeRulesBuildPhase->AddAttribute("buildActionMask", this->CreateString("2147483647")); cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); cmakeRulesBuildPhase->AddAttribute("files", buildFiles); cmakeRulesBuildPhase->AddAttribute("name", this->CreateString("CMake Rules")); cmakeRulesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", this->CreateString("0")); cmakeRulesBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh")); this->AddCommandsToBuildPhase(cmakeRulesBuildPhase, cmtarget, commands, "cmakeRulesCommands"); } // create prebuild phase cmXCodeObject* preBuildPhase = 0; if(prebuild.size()) { preBuildPhase = this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase); preBuildPhase->AddAttribute("buildActionMask", this->CreateString("2147483647")); cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); preBuildPhase->AddAttribute("files", buildFiles); preBuildPhase->AddAttribute("name", this->CreateString("CMake PreBuild Rules")); preBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", this->CreateString("0")); preBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh")); this->AddCommandsToBuildPhase(preBuildPhase, cmtarget, prebuild, "preBuildCommands"); } // create prebuild phase cmXCodeObject* preLinkPhase = 0; if(prelink.size()) { preLinkPhase = this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase); preLinkPhase->AddAttribute("buildActionMask", this->CreateString("2147483647")); cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); preLinkPhase->AddAttribute("files", buildFiles); preLinkPhase->AddAttribute("name", this->CreateString("CMake PreLink Rules")); preLinkPhase->AddAttribute("runOnlyForDeploymentPostprocessing", this->CreateString("0")); preLinkPhase->AddAttribute("shellPath", this->CreateString("/bin/sh")); this->AddCommandsToBuildPhase(preLinkPhase, cmtarget, prelink, "preLinkCommands"); } // create prebuild phase cmXCodeObject* postBuildPhase = 0; if(postbuild.size()) { postBuildPhase = this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase); postBuildPhase->AddAttribute("buildActionMask", this->CreateString("2147483647")); cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); postBuildPhase->AddAttribute("files", buildFiles); postBuildPhase->AddAttribute("name", this->CreateString("CMake PostBuild Rules")); postBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", this->CreateString("0")); postBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh")); this->AddCommandsToBuildPhase(postBuildPhase, cmtarget, postbuild, "postBuildCommands"); } // 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); } } void cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase, cmTarget& target, std::vector const & commands, const char* name) { std::string makefile = m_CurrentMakefile->GetCurrentOutputDirectory(); cmSystemTools::MakeDirectory(makefile.c_str()); makefile += "/"; makefile += target.GetName(); makefile += "_"; makefile += name; makefile += ".make"; cmGeneratedFileStream makefileStream(makefile.c_str()); if(!makefileStream) { return; } makefileStream << "# Generated by CMake, DO NOT EDIT\n"; makefileStream << "# Custom rules for " << target.GetName() << "\n"; // have all depend on all outputs makefileStream << "all: "; for(std::vector::const_iterator i = commands.begin(); i != commands.end(); ++i) { cmCustomCommand const& cc = *i; if(cc.GetCommand().size()) { if(cc.GetOutput().size()) { makefileStream << "\\\n\t" << m_CurrentLocalGenerator ->ConvertToRelativeOutputPath(cc.GetOutput().c_str()); } else { makefileStream << "\\\n\t" << target.GetName(); } } } makefileStream << "\n\n"; for(std::vector::const_iterator i = commands.begin(); i != commands.end(); ++i) { cmCustomCommand const& cc = *i; if(cc.GetCommand().size()) { makefileStream << "\n#" << "Custom command rule: " << cc.GetComment() << "\n"; if(cc.GetOutput().size()) { makefileStream << m_CurrentLocalGenerator ->ConvertToRelativeOutputPath(cc.GetOutput().c_str()) << ": "; } else { // if no outputs then use the target name as this must // be a utility target makefileStream << target.GetName() << ": "; } for(std::vector::const_iterator d = cc.GetDepends().begin(); d != cc.GetDepends().end(); ++d) { if(!this->FindTarget(d->c_str())) { makefileStream << "\\\n" << *d; } 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"; makefileStream << "\t" << cc.GetCommand() << " " << cc.GetArguments() << "\n"; } } std::string dir = cmSystemTools::ConvertToOutputPath( m_CurrentMakefile->GetCurrentOutputDirectory()); std::string makecmd = "make -C "; makecmd += dir; makecmd += " -f "; makecmd += makefile; buildphase->AddAttribute("shellScript", this->CreateString(makecmd.c_str())); } void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, cmXCodeObject* buildSettings, std::string& fileType, std::string& productType, std::string& productName) { this->ConfigureOutputPaths(); std::string flags; bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) || (target.GetType() == cmTarget::MODULE_LIBRARY)); if(shared) { flags += "-D"; if(const char* custom_export_name = target.GetProperty("DEFINE_SYMBOL")) { flags += custom_export_name; } else { std::string in = target.GetName(); in += "_EXPORTS"; flags += cmSystemTools::MakeCindentifier(in.c_str()); } } const char* lang = target.GetLinkerLanguage(this); if(lang) { // Add language-specific flags. m_CurrentLocalGenerator->AddLanguageFlags(flags, lang); // Add shared-library flags if needed. m_CurrentLocalGenerator->AddSharedFlags(flags, lang, shared); } // Add define flags m_CurrentLocalGenerator->AppendFlags(flags, m_CurrentMakefile->GetDefineFlags()); cmSystemTools::ReplaceString(flags, "\"", "\\\""); productName = target.GetName(); bool needLinkDirs = true; switch(target.GetType()) { case cmTarget::STATIC_LIBRARY: { needLinkDirs = false; if(m_LibraryOutputPath.size()) { buildSettings->AddAttribute("SYMROOT", this->CreateString (m_LibraryOutputPath.c_str())); } productName += ".a"; std::string t = "lib"; t += productName; productName = t; productType = "com.apple.product-type.library.static"; fileType = "archive.ar"; buildSettings->AddAttribute("LIBRARY_STYLE", this->CreateString("STATIC")); break; } case cmTarget::MODULE_LIBRARY: { if(m_LibraryOutputPath.size()) { buildSettings->AddAttribute("SYMROOT", this->CreateString (m_LibraryOutputPath.c_str())); } buildSettings->AddAttribute("LIBRARY_STYLE", this->CreateString("DYNAMIC")); productName += ".so"; std::string t = "lib"; t += productName; productName = t; buildSettings->AddAttribute("OTHER_LDFLAGS", this->CreateString("-bundle")); productType = "com.apple.product-type.library.dynamic"; fileType = "compiled.mach-o.dylib"; break; } case cmTarget::SHARED_LIBRARY: { if(m_LibraryOutputPath.size()) { buildSettings->AddAttribute("SYMROOT", this->CreateString (m_LibraryOutputPath.c_str())); } buildSettings->AddAttribute("LIBRARY_STYLE", this->CreateString("DYNAMIC")); productName += ".dylib"; std::string t = "lib"; t += productName; productName = t; buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION", this->CreateString("1")); buildSettings->AddAttribute("DYLIB_CURRENT_VERSION", this->CreateString("1")); buildSettings->AddAttribute("OTHER_LDFLAGS", this->CreateString("-dynamiclib")); productType = "com.apple.product-type.library.dynamic"; fileType = "compiled.mach-o.dylib"; break; } case cmTarget::EXECUTABLE: if(m_ExecutableOutputPath.size()) { buildSettings->AddAttribute("SYMROOT", this->CreateString (m_ExecutableOutputPath.c_str())); } fileType = "compiled.mach-o.executable"; productType = "com.apple.product-type.tool"; break; case cmTarget::UTILITY: break; case cmTarget::INSTALL_FILES: break; case cmTarget::INSTALL_PROGRAMS: break; } std::string dirs; if(needLinkDirs) { // Try to emit each search path once std::set emitted; // Some search paths should never be emitted emitted.insert(""); emitted.insert("/usr/lib"); std::vector const& linkdirs = target.GetLinkDirectories(); for(std::vector::const_iterator l = linkdirs.begin(); l != linkdirs.end(); ++l) { std::string libpath = m_CurrentLocalGenerator->ConvertToOutputForExisting(l->c_str()); if(emitted.insert(libpath).second) { dirs += libpath + " "; } } if(dirs.size()) { buildSettings->AddAttribute("LIBRARY_SEARCH_PATHS", this->CreateString(dirs.c_str())); } } dirs = ""; std::vector& includes = m_CurrentMakefile->GetIncludeDirectories(); std::vector::iterator i = includes.begin(); for(;i != includes.end(); ++i) { std::string incpath = m_CurrentLocalGenerator->ConvertToOutputForExisting(i->c_str()); dirs += incpath + " "; } if(dirs.size()) { buildSettings->AddAttribute("HEADER_SEARCH_PATHS", this->CreateString(dirs.c_str())); } buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL", this->CreateString("0")); buildSettings->AddAttribute("INSTALL_PATH", this->CreateString("/usr/local/bin")); buildSettings->AddAttribute("OPTIMIZATION_CFLAGS", this->CreateString("")); buildSettings->AddAttribute("OTHER_CFLAGS", this->CreateString(flags.c_str())); buildSettings->AddAttribute("OTHER_LDFLAGS", this->CreateString("")); buildSettings->AddAttribute("OTHER_REZFLAGS", this->CreateString("")); buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString("")); buildSettings->AddAttribute("WARNING_CFLAGS", this->CreateString( "-Wmost -Wno-four-char-constants" " -Wno-unknown-pragmas")); buildSettings->AddAttribute("PRODUCT_NAME", this->CreateString(target.GetName())); } 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); 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); target->AddAttribute("buildSettings", buildSettings); cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST); target->AddAttribute("dependencies", dependencies); target->AddAttribute("name", this->CreateString(cmtarget.GetName())); target->AddAttribute("productName",this->CreateString(cmtarget.GetName())); target->SetcmTarget(&cmtarget); return target; } 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; this->CreateBuildSettings(cmtarget, buildSettings, fileTypeString, productTypeString, productName); target->AddAttribute("buildSettings", buildSettings); cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST); target->AddAttribute("dependencies", dependencies); target->AddAttribute("name", this->CreateString(cmtarget.GetName())); target->AddAttribute("productName",this->CreateString(cmtarget.GetName())); 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")); 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::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) { cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency(); if(!targetdep) { cmXCodeObject* container = this->CreateObject(cmXCodeObject::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->AddAttribute("target", this->CreateObjectReference(dependTarget)); targetdep->AddAttribute("targetProxy", this->CreateObjectReference(container)); dependTarget->SetPBXTargetDependency(targetdep); } cmXCodeObject* depends = target->GetObject("dependencies"); if(!depends) { std::cerr << "target does not have dependencies attribute error...\n"; } else { depends->AddObject(targetdep); } } void cmGlobalXCodeGenerator::AddLinkTarget(cmXCodeObject* target , cmXCodeObject* dependTarget ) { cmXCodeObject* ref = dependTarget->GetObject("productReference"); cmXCodeObject* buildfile = this->CreateObject(cmXCodeObject::PBXBuildFile); buildfile->AddAttribute("fileRef", ref); cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); buildfile->AddAttribute("settings", settings); cmXCodeObject* buildPhases = target->GetObject("buildPhases"); cmXCodeObject* frameworkBuildPhase = buildPhases->GetObject(cmXCodeObject::PBXFrameworksBuildPhase); cmXCodeObject* files = frameworkBuildPhase->GetObject("files"); files->AddObject(buildfile); } void cmGlobalXCodeGenerator::AddLinkLibrary(cmXCodeObject* target, const char* library) { // if the library is a full path then create a file reference // and build file and add them to the PBXFrameworksBuildPhase // for the target if(cmSystemTools::FileIsFullPath(library)) { std::string libPath = library; cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); if(libPath[libPath.size()-1] == 'a') { fileRef->AddAttribute("lastKnownFileType", this->CreateString("archive.ar")); } else { fileRef->AddAttribute("lastKnownFileType", this->CreateString("compiled.mach-o.dylib")); } fileRef->AddAttribute("name", this->CreateString( cmSystemTools::GetFilenameName(libPath).c_str())); fileRef->AddAttribute("path", this->CreateString(libPath.c_str())); fileRef->AddAttribute("refType", this->CreateString("0")); fileRef->AddAttribute("sourceTree", this->CreateString("")); cmXCodeObject* buildfile = this->CreateObject(cmXCodeObject::PBXBuildFile); buildfile->AddAttribute("fileRef", this->CreateObjectReference(fileRef)); cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); buildfile->AddAttribute("settings", settings); // get the framework build phase from the target cmXCodeObject* buildPhases = target->GetObject("buildPhases"); cmXCodeObject* frameworkBuildPhase = buildPhases->GetObject(cmXCodeObject::PBXFrameworksBuildPhase); cmXCodeObject* files = frameworkBuildPhase->GetObject("files"); files->AddObject(buildfile); m_ExternalGroupChildren->AddObject(fileRef); } else { // if the library is not a full path then add it with a -l flag // to the settings of the target cmXCodeObject* settings = target->GetObject("buildSettings"); cmXCodeObject* ldflags = settings->GetObject("OTHER_LDFLAGS"); std::string link = ldflags->GetString(); cmSystemTools::ReplaceString(link, "\"", ""); cmsys::RegularExpression reg("^([ \t]*\\-[lWRB])|([ \t]*\\-framework)|(\\${)|([ \t]*\\-pthread)|([ \t]*`)"); // if the library is not already in the form required by the compiler // add a -l infront of the name if(!reg.find(library)) { link += " -l"; } link += library; ldflags->SetString(link.c_str()); } } void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) { cmTarget* cmtarget = target->GetcmTarget(); if(!cmtarget) { std::cerr << "Error no target on xobject\n"; return; } cmTarget::LinkLibraries::const_iterator j, jend; j = cmtarget->GetLinkLibraries().begin(); jend = cmtarget->GetLinkLibraries().end(); for(;j!= jend; ++j) { cmTarget* t = this->FindTarget(j->first.c_str()); cmXCodeObject* dptarget = this->FindXCodeTarget(t); if(dptarget) { this->AddDependTarget(target, dptarget); if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY) { this->AddLinkTarget(target, dptarget); } } else { if(cmtarget->GetType() != cmTarget::STATIC_LIBRARY) { this->AddLinkLibrary(target, j->first.c_str()); } } } std::set::const_iterator i, end; // write utility dependencies. i = cmtarget->GetUtilities().begin(); end = cmtarget->GetUtilities().end(); for(;i!= end; ++i) { cmTarget* t = this->FindTarget(i->c_str()); cmXCodeObject* dptarget = this->FindXCodeTarget(t); if(dptarget) { this->AddDependTarget(target, dptarget); } else { std::cerr << "Error External Util???: " << i->c_str() << "\n"; } } } // to force the location of a target // add this to build settings of target SYMROOT = /tmp/; //---------------------------------------------------------------------------- void cmGlobalXCodeGenerator::CreateXCodeObjects(cmLocalGenerator* , std::vector& generators ) { this->ClearXCodeObjects(); m_RootObject = 0; m_ExternalGroupChildren = 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); developBuildStyle->AddAttribute("name", this->CreateString("Development")); developBuildStyle->AddAttribute("buildSettings", group); 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); 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); mainGroup->AddAttribute("refType", this->CreateString("4")); mainGroup->AddAttribute("sourceTree", this->CreateString("")); cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup); m_SourcesGroupChildren = this->CreateObject(cmXCodeObject::OBJECT_LIST); sourcesGroup->AddAttribute("name", this->CreateString("Sources")); sourcesGroup->AddAttribute("children", m_SourcesGroupChildren); sourcesGroup->AddAttribute("refType", this->CreateString("4")); sourcesGroup->AddAttribute("sourceTree", this->CreateString("")); m_MainGroupChildren->AddObject(sourcesGroup); cmXCodeObject* externalGroup = this->CreateObject(cmXCodeObject::PBXGroup); m_ExternalGroupChildren = this->CreateObject(cmXCodeObject::OBJECT_LIST); externalGroup->AddAttribute("name", this->CreateString("External Libraries and Frameworks")); externalGroup->AddAttribute("children", m_ExternalGroupChildren); externalGroup->AddAttribute("refType", this->CreateString("4")); externalGroup->AddAttribute("sourceTree", this->CreateString("")); m_MainGroupChildren->AddObject(externalGroup); cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup); productGroup->AddAttribute("name", this->CreateString("Products")); productGroup->AddAttribute("refType", this->CreateString("4")); productGroup->AddAttribute("sourceTree", this->CreateString("")); cmXCodeObject* productGroupChildren = this->CreateObject(cmXCodeObject::OBJECT_LIST); productGroup->AddAttribute("children", productGroupChildren); m_MainGroupChildren->AddObject(productGroup); m_RootObject = this->CreateObject(cmXCodeObject::PBXProject); group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); m_RootObject->AddAttribute("mainGroup", this->CreateObjectReference(mainGroup)); m_RootObject->AddAttribute("buildSettings", group); m_RootObject->AddAttribute("buildSyles", listObjs); m_RootObject->AddAttribute("hasScannedForEncodings", this->CreateString("0")); std::vector targets; for(std::vector::iterator i = generators.begin(); i != generators.end(); ++i) { this->CreateXCodeTargets(*i, targets); } cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST); for(std::vector::iterator i = targets.begin(); i != targets.end(); ++i) { cmXCodeObject* t = *i; this->AddDependAndLinkInformation(t); allTargets->AddObject(t); cmXCodeObject* productRef = t->GetObject("productReference"); if(productRef) { productGroupChildren->AddObject(productRef->GetObject()); } } m_RootObject->AddAttribute("targets", allTargets); } //---------------------------------------------------------------------------- void cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root, std::vector& generators) { if(generators.size() == 0) { return; } this->CreateXCodeObjects(root, generators); std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory(); xcodeDir += "/"; xcodeDir += root->GetMakefile()->GetProjectName(); xcodeDir += ".xcode"; cmSystemTools::MakeDirectory(xcodeDir.c_str()); xcodeDir += "/project.pbxproj"; cmGeneratedFileStream fout(xcodeDir.c_str()); fout.SetCopyIfDifferent(true); if(!fout) { return; } this->WriteXCodePBXProj(fout, root, generators); this->ClearXCodeObjects(); } //---------------------------------------------------------------------------- void cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout, cmLocalGenerator* , std::vector& ) { 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 = ""; }