Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmGlobalXCodeGenerator.cxx
blob8f3c668786c74208dffc5034d345a4ca0e819b6e
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalXCodeGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-03-16 18:30:24 $
7 Version: $Revision: 1.210 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmGlobalXCodeGenerator.h"
18 #include "cmGlobalXCode21Generator.h"
19 #include "cmLocalXCodeGenerator.h"
20 #include "cmMakefile.h"
21 #include "cmXCodeObject.h"
22 #include "cmXCode21Object.h"
23 #include "cmake.h"
24 #include "cmGeneratedFileStream.h"
25 #include "cmComputeLinkInformation.h"
26 #include "cmSourceFile.h"
28 //----------------------------------------------------------------------------
29 #if defined(CMAKE_BUILD_WITH_CMAKE)
30 #include "cmXMLParser.h"
32 // parse the xml file storing the installed version of Xcode on
33 // the machine
34 class cmXcodeVersionParser : public cmXMLParser
36 public:
37 void StartElement(const char* , const char** )
39 this->Data = "";
41 void EndElement(const char* name)
43 if(strcmp(name, "key") == 0)
45 this->Key = this->Data;
47 else if(strcmp(name, "string") == 0)
49 if(this->Key == "CFBundleShortVersionString")
51 this->Version = (int)(10.0 * atof(this->Data.c_str()));
55 void CharacterDataHandler(const char* data, int length)
57 this->Data.append(data, length);
59 int Version;
60 std::string Key;
61 std::string Data;
63 #endif
65 //----------------------------------------------------------------------------
66 cmGlobalXCodeGenerator::cmGlobalXCodeGenerator()
68 this->FindMakeProgramFile = "CMakeFindXCode.cmake";
69 this->RootObject = 0;
70 this->MainGroupChildren = 0;
71 this->SourcesGroupChildren = 0;
72 this->ResourcesGroupChildren = 0;
73 this->CurrentMakefile = 0;
74 this->CurrentLocalGenerator = 0;
75 this->XcodeVersion = 15;
78 //----------------------------------------------------------------------------
79 cmGlobalGenerator* cmGlobalXCodeGenerator::New()
81 #if defined(CMAKE_BUILD_WITH_CMAKE)
82 cmXcodeVersionParser parser;
83 parser.ParseFile
84 ("/Developer/Applications/Xcode.app/Contents/version.plist");
85 if(parser.Version == 15)
87 return new cmGlobalXCodeGenerator;
89 else if (parser.Version == 20)
91 cmSystemTools::Message("Xcode 2.0 not really supported by cmake, "
92 "using Xcode 15 generator\n");
93 return new cmGlobalXCodeGenerator;
95 cmGlobalXCodeGenerator* ret = new cmGlobalXCode21Generator;
96 ret->SetVersion(parser.Version);
97 return ret;
98 #else
99 std::cerr << "CMake should be built with cmake to use XCode, "
100 "default to Xcode 1.5\n";
101 return new cmGlobalXCodeGenerator;
102 #endif
105 //----------------------------------------------------------------------------
106 void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const&
107 lang,
108 cmMakefile * mf, bool optional)
110 mf->AddDefinition("XCODE","1");
111 if(this->XcodeVersion == 15)
114 else
116 mf->AddCacheDefinition(
117 "CMAKE_CONFIGURATION_TYPES",
118 "Debug;Release;MinSizeRel;RelWithDebInfo",
119 "Semicolon separated list of supported configuration types, "
120 "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
121 "anything else will be ignored.",
122 cmCacheManager::STRING);
124 mf->AddDefinition("CMAKE_GENERATOR_CC", "gcc");
125 mf->AddDefinition("CMAKE_GENERATOR_CXX", "g++");
126 mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
127 // initialize Architectures so it can be used by
128 // GetTargetObjectFileDirectories
129 this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
130 const char* osxArch =
131 mf->GetDefinition("CMAKE_OSX_ARCHITECTURES");
132 const char* sysroot =
133 mf->GetDefinition("CMAKE_OSX_SYSROOT");
134 if(osxArch && sysroot)
136 this->Architectures.clear();
137 cmSystemTools::ExpandListArgument(std::string(osxArch),
138 this->Architectures);
142 //----------------------------------------------------------------------------
143 std::string cmGlobalXCodeGenerator
144 ::GenerateBuildCommand(const char* makeProgram,
145 const char *projectName,
146 const char* additionalOptions,
147 const char *targetName,
148 const char* config,
149 bool ignoreErrors,
150 bool)
152 // Config is not used yet
153 (void) ignoreErrors;
155 // now build the test
156 if(makeProgram == 0 || !strlen(makeProgram))
158 cmSystemTools::Error(
159 "Generator cannot find the appropriate make command.");
160 return "";
162 std::string makeCommand =
163 cmSystemTools::ConvertToOutputPath(makeProgram);
164 std::string lowerCaseCommand = makeCommand;
165 cmSystemTools::LowerCase(lowerCaseCommand);
167 makeCommand += " -project ";
168 makeCommand += projectName;
169 makeCommand += ".xcode";
170 if(this->XcodeVersion > 20)
172 makeCommand += "proj";
175 bool clean = false;
176 if ( targetName && strcmp(targetName, "clean") == 0 )
178 clean = true;
179 targetName = "ALL_BUILD";
181 if(clean)
183 makeCommand += " clean";
185 else
187 makeCommand += " build";
189 makeCommand += " -target ";
190 // if it is a null string for config don't use it
191 if(config && *config == 0)
193 config = 0;
195 if (targetName && strlen(targetName))
197 makeCommand += targetName;
199 else
201 makeCommand += "ALL_BUILD";
203 if(this->XcodeVersion == 15)
205 makeCommand += " -buildstyle Development ";
207 else
209 makeCommand += " -configuration ";
210 makeCommand += config?config:"Debug";
212 if ( additionalOptions )
214 makeCommand += " ";
215 makeCommand += additionalOptions;
217 return makeCommand;
220 //----------------------------------------------------------------------------
221 ///! Create a local generator appropriate to this Global Generator
222 cmLocalGenerator *cmGlobalXCodeGenerator::CreateLocalGenerator()
224 cmLocalGenerator *lg = new cmLocalXCodeGenerator;
225 lg->SetGlobalGenerator(this);
226 return lg;
229 //----------------------------------------------------------------------------
230 void cmGlobalXCodeGenerator::Generate()
232 std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
233 // make sure extra targets are added before calling
234 // the parent generate which will call trace depends
235 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
237 cmLocalGenerator* root = it->second[0];
238 this->SetGenerationRoot(root);
239 // add ALL_BUILD, INSTALL, etc
240 this->AddExtraTargets(root, it->second);
242 this->cmGlobalGenerator::Generate();
243 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
245 cmLocalGenerator* root = it->second[0];
246 this->SetGenerationRoot(root);
247 // now create the project
248 this->OutputXCodeProject(root, it->second);
252 //----------------------------------------------------------------------------
253 void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
255 this->CurrentProject = root->GetMakefile()->GetProjectName();
256 this->SetCurrentLocalGenerator(root);
257 std::string outDir = this->CurrentMakefile->GetHomeOutputDirectory();
258 outDir =cmSystemTools::CollapseFullPath(outDir.c_str());
259 cmSystemTools::SplitPath(outDir.c_str(),
260 this->ProjectOutputDirectoryComponents);
262 this->CurrentXCodeHackMakefile =
263 root->GetMakefile()->GetCurrentOutputDirectory();
264 this->CurrentXCodeHackMakefile += "/CMakeScripts";
265 cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile.c_str());
266 this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
269 //----------------------------------------------------------------------------
270 void
271 cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
272 std::vector<cmLocalGenerator*>& gens)
274 cmMakefile* mf = root->GetMakefile();
276 // Add ALL_BUILD
277 const char* no_working_directory = 0;
278 std::vector<std::string> no_depends;
279 mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
280 no_working_directory,
281 "echo", "Build all projects");
282 cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
284 // Refer to the main build configuration file for easy editing.
285 std::string listfile = mf->GetStartDirectory();
286 listfile += "/";
287 listfile += "CMakeLists.txt";
288 allbuild->AddSource(listfile.c_str());
290 // Add XCODE depend helper
291 std::string dir = mf->GetCurrentOutputDirectory();
292 cmCustomCommandLine makecommand;
293 makecommand.push_back("make");
294 makecommand.push_back("-C");
295 makecommand.push_back(dir.c_str());
296 makecommand.push_back("-f");
297 makecommand.push_back(this->CurrentXCodeHackMakefile.c_str());
298 if(this->XcodeVersion > 20)
300 makecommand.push_back("all.$(CONFIGURATION)");
302 cmCustomCommandLines commandLines;
303 commandLines.push_back(makecommand);
304 // Add Re-Run CMake rules
305 this->CreateReRunCMakeFile(root);
307 // now make the allbuild depend on all the non-utility targets
308 // in the project
309 for(std::vector<cmLocalGenerator*>::iterator i = gens.begin();
310 i != gens.end(); ++i)
312 cmLocalGenerator* lg = *i;
313 if(this->IsExcluded(root, *i))
315 continue;
317 cmTargets& tgts = lg->GetMakefile()->GetTargets();
318 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
320 cmTarget& target = l->second;
321 // make all exe, shared libs and modules
322 // run the depend check makefile as a post build rule
323 // this will make sure that when the next target is built
324 // things are up-to-date
325 if((target.GetType() == cmTarget::EXECUTABLE ||
326 target.GetType() == cmTarget::STATIC_LIBRARY ||
327 target.GetType() == cmTarget::SHARED_LIBRARY ||
328 target.GetType() == cmTarget::MODULE_LIBRARY))
330 lg->GetMakefile()->AddCustomCommandToTarget(target.GetName(),
331 no_depends,
332 commandLines,
333 cmTarget::POST_BUILD,
334 "Depend check for xcode",
335 dir.c_str());
338 if(!target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
340 allbuild->AddUtility(target.GetName());
343 // Refer to the build configuration file for easy editing.
344 listfile = lg->GetMakefile()->GetStartDirectory();
345 listfile += "/";
346 listfile += "CMakeLists.txt";
347 target.AddSource(listfile.c_str());
352 //----------------------------------------------------------------------------
353 void cmGlobalXCodeGenerator::CreateReRunCMakeFile(cmLocalGenerator* root)
355 cmMakefile* mf = root->GetMakefile();
356 std::vector<std::string> lfiles = mf->GetListFiles();
357 // sort the array
358 std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
359 std::vector<std::string>::iterator new_end =
360 std::unique(lfiles.begin(), lfiles.end());
361 lfiles.erase(new_end, lfiles.end());
362 std::string dir = mf->GetHomeOutputDirectory();
363 this->CurrentReRunCMakeMakefile = dir;
364 this->CurrentReRunCMakeMakefile += "/CMakeScripts";
365 cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
366 this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
367 cmGeneratedFileStream makefileStream
368 (this->CurrentReRunCMakeMakefile.c_str());
369 makefileStream.SetCopyIfDifferent(true);
370 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
371 makefileStream << cmake::GetCMakeFilesDirectoryPostSlash();
372 makefileStream << "cmake.check_cache: ";
373 for(std::vector<std::string>::const_iterator i = lfiles.begin();
374 i != lfiles.end(); ++i)
376 makefileStream << "\\\n" << this->ConvertToRelativeForMake(i->c_str());
378 std::string cmake = mf->GetRequiredDefinition("CMAKE_COMMAND");
379 makefileStream << "\n\t" << this->ConvertToRelativeForMake(cmake.c_str())
380 << " -H" << this->ConvertToRelativeForMake(
381 mf->GetHomeDirectory())
382 << " -B" << this->ConvertToRelativeForMake(
383 mf->GetHomeOutputDirectory()) << "\n";
386 //----------------------------------------------------------------------------
387 void cmGlobalXCodeGenerator::ClearXCodeObjects()
389 this->TargetDoneSet.clear();
390 for(unsigned int i = 0; i < this->XCodeObjects.size(); ++i)
392 delete this->XCodeObjects[i];
394 this->XCodeObjects.clear();
395 this->GroupMap.clear();
396 this->GroupNameMap.clear();
397 this->TargetGroup.clear();
398 this->FileRefs.clear();
401 //----------------------------------------------------------------------------
402 cmXCodeObject*
403 cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype)
405 cmXCodeObject* obj;
406 if(this->XcodeVersion == 15)
408 obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
410 else
412 obj = new cmXCode21Object(ptype, cmXCodeObject::OBJECT);
414 this->XCodeObjects.push_back(obj);
415 return obj;
418 //----------------------------------------------------------------------------
419 cmXCodeObject*
420 cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
422 cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
423 this->XCodeObjects.push_back(obj);
424 return obj;
427 //----------------------------------------------------------------------------
428 cmXCodeObject*
429 cmGlobalXCodeGenerator::CreateString(const char* s)
431 cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
432 obj->SetString(s);
433 return obj;
436 //----------------------------------------------------------------------------
437 cmXCodeObject* cmGlobalXCodeGenerator
438 ::CreateObjectReference(cmXCodeObject* ref)
440 cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
441 obj->SetObject(ref);
442 return obj;
445 //----------------------------------------------------------------------------
446 cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
448 cmStdString key(cmtarget.GetName());
449 key += "-";
450 key += sf->GetFullPath();
451 return key;
454 //----------------------------------------------------------------------------
455 cmXCodeObject*
456 cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
457 cmSourceFile* sf,
458 cmTarget& cmtarget)
460 // Add flags from target and source file properties.
461 std::string flags;
462 if(cmtarget.GetProperty("COMPILE_FLAGS"))
464 lg->AppendFlags(flags, cmtarget.GetProperty("COMPILE_FLAGS"));
466 lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
468 // Add per-source definitions.
469 this->AppendDefines(flags, sf->GetProperty("COMPILE_DEFINITIONS"), true);
471 // Using a map and the full path guarantees that we will always get the same
472 // fileRef object for any given full path.
474 cmXCodeObject* fileRef = this->CreateXCodeFileReference(sf, cmtarget);
476 cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
477 buildFile->SetComment(fileRef->GetComment());
478 buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
480 cmXCodeObject* settings =
481 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
482 settings->AddAttribute("COMPILER_FLAGS", this->CreateString(flags.c_str()));
484 // Is this a resource file in this target? Add it to the resources group...
486 cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf);
487 bool isResource = (tsFlags.Type == cmTarget::SourceFileTypeResource);
489 // Is this a "private" or "public" framework header file?
490 // Set the ATTRIBUTES attribute appropriately...
492 if(cmtarget.IsFrameworkOnApple())
494 if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader)
496 cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
497 attrs->AddObject(this->CreateString("Private"));
498 settings->AddAttribute("ATTRIBUTES", attrs);
499 isResource = true;
501 else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader)
503 cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
504 attrs->AddObject(this->CreateString("Public"));
505 settings->AddAttribute("ATTRIBUTES", attrs);
506 isResource = true;
510 // Add the fileRef to the top level Resources group/folder if it is not
511 // already there.
513 if(isResource && this->ResourcesGroupChildren &&
514 !this->ResourcesGroupChildren->HasObject(fileRef))
516 this->ResourcesGroupChildren->AddObject(fileRef);
519 buildFile->AddAttribute("settings", settings);
520 return buildFile;
523 //----------------------------------------------------------------------------
524 cmXCodeObject*
525 cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
526 cmTarget& cmtarget)
528 std::string fname = sf->GetFullPath();
529 cmXCodeObject* fileRef = this->FileRefs[fname];
530 if(!fileRef)
532 fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
533 std::string comment = fname;
534 //comment += " in ";
535 //std::string gname = group->GetObject("name")->GetString();
536 //comment += gname.substr(1, gname.size()-2);
537 fileRef->SetComment(fname.c_str());
538 this->FileRefs[fname] = fileRef;
540 cmStdString key = GetGroupMapKey(cmtarget, sf);
541 cmXCodeObject* group = this->GroupMap[key];
542 cmXCodeObject* children = group->GetObject("children");
543 if (!children->HasObject(fileRef))
545 children->AddObject(fileRef);
547 fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
549 const char* lang =
550 this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
551 std::string sourcecode = "sourcecode";
552 std::string ext = sf->GetExtension();
553 ext = cmSystemTools::LowerCase(ext);
555 if(ext == "o")
557 sourcecode = "compiled.mach-o.objfile";
559 else if(ext == "xib")
561 sourcecode = "file.xib";
563 else if(ext == "mm")
565 sourcecode += ".cpp.objcpp";
567 else if(ext == "m")
569 sourcecode += ".c.objc";
571 else if(ext == "plist")
573 sourcecode += ".text.plist";
575 else if(ext == "h" || ext == "hxx" || ext == "hpp")
577 const char* linkLanguage = cmtarget.GetLinkerLanguage(this);
578 if(linkLanguage && (std::string(linkLanguage) == "CXX"))
580 sourcecode += ".cpp.h";
582 else
584 sourcecode += ".c.h";
587 else if(lang && strcmp(lang, "CXX") == 0)
589 sourcecode += ".cpp.cpp";
591 else if(lang && strcmp(lang, "C") == 0)
593 sourcecode += ".c.c";
595 else if(ext == "txt")
597 sourcecode += ".text";
599 //else
600 // {
601 // // Already specialized above or we leave sourcecode == "sourcecode"
602 // // which is probably the most correct choice. Extensionless headers,
603 // // for example... Or file types unknown to Xcode that do not map to a
604 // // valid lastKnownFileType value.
605 // }
607 fileRef->AddAttribute("lastKnownFileType",
608 this->CreateString(sourcecode.c_str()));
610 std::string path =
611 this->ConvertToRelativeForXCode(sf->GetFullPath().c_str());
612 std::string dir;
613 std::string file;
614 cmSystemTools::SplitProgramPath(sf->GetFullPath().c_str(),
615 dir, file);
617 fileRef->AddAttribute("name", this->CreateString(file.c_str()));
618 fileRef->AddAttribute("path", this->CreateString(path.c_str()));
619 if(this->XcodeVersion == 15)
621 fileRef->AddAttribute("refType", this->CreateString("4"));
623 if(path.size() > 1 && path[0] == '.' && path[1] == '.')
625 fileRef->AddAttribute("sourceTree", this->CreateString("<group>"));
627 else
629 fileRef->AddAttribute("sourceTree", this->CreateString("<absolute>"));
632 return fileRef;
635 //----------------------------------------------------------------------------
636 bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
638 if(tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
639 tname == "install" || tname == "package" || tname == "RUN_TESTS" )
641 if(this->TargetDoneSet.find(tname) != this->TargetDoneSet.end())
643 return true;
645 this->TargetDoneSet.insert(tname);
646 return false;
648 return false;
651 //----------------------------------------------------------------------------
652 void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
654 this->CurrentLocalGenerator = gen;
655 this->CurrentMakefile = gen->GetMakefile();
656 std::string outdir =
657 cmSystemTools::CollapseFullPath(this->CurrentMakefile->
658 GetCurrentOutputDirectory());
659 cmSystemTools::SplitPath(outdir.c_str(),
660 this->CurrentOutputDirectoryComponents);
662 // Select the current set of configuration types.
663 this->CurrentConfigurationTypes.clear();
664 if(this->XcodeVersion > 20)
666 if(const char* types =
667 this->CurrentMakefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
669 cmSystemTools::ExpandListArgument(types,
670 this->CurrentConfigurationTypes);
673 if(this->CurrentConfigurationTypes.empty())
675 if(const char* buildType =
676 this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE"))
678 this->CurrentConfigurationTypes.push_back(buildType);
680 else
682 this->CurrentConfigurationTypes.push_back("");
687 //----------------------------------------------------------------------------
688 void
689 cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
690 std::vector<cmXCodeObject*>&
691 targets)
693 this->SetCurrentLocalGenerator(gen);
694 cmTargets &tgts = this->CurrentMakefile->GetTargets();
695 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
697 cmTarget& cmtarget = l->second;
699 // make sure ALL_BUILD, INSTALL, etc are only done once
700 if(this->SpecialTargetEmitted(l->first.c_str()))
702 continue;
705 if(cmtarget.GetType() == cmTarget::UTILITY ||
706 cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
708 targets.push_back(this->CreateUtilityTarget(cmtarget));
709 continue;
712 // organize the sources
713 std::vector<cmSourceFile*> const &classes = cmtarget.GetSourceFiles();
714 std::vector<cmXCodeObject*> externalObjFiles;
715 std::vector<cmXCodeObject*> headerFiles;
716 std::vector<cmXCodeObject*> resourceFiles;
717 std::vector<cmXCodeObject*> sourceFiles;
718 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
719 i != classes.end(); ++i)
721 cmXCodeObject* xsf =
722 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
723 *i, cmtarget);
724 cmXCodeObject* fr = xsf->GetObject("fileRef");
725 cmXCodeObject* filetype =
726 fr->GetObject()->GetObject("lastKnownFileType");
728 cmTarget::SourceFileFlags tsFlags =
729 cmtarget.GetTargetSourceFileFlags(*i);
731 if(strcmp(filetype->GetString(), "compiled.mach-o.objfile") == 0)
733 externalObjFiles.push_back(xsf);
735 else if(this->IsHeaderFile(*i) ||
736 (tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) ||
737 (tsFlags.Type == cmTarget::SourceFileTypePublicHeader))
739 headerFiles.push_back(xsf);
741 else if(tsFlags.Type == cmTarget::SourceFileTypeResource)
743 resourceFiles.push_back(xsf);
745 else if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY"))
747 // Include this file in the build if it has a known language
748 // and has not been listed as an ignored extension for this
749 // generator.
750 if(this->CurrentLocalGenerator->GetSourceFileLanguage(**i) &&
751 !this->IgnoreFile((*i)->GetExtension().c_str()))
753 sourceFiles.push_back(xsf);
758 // some build phases only apply to bundles and/or frameworks
759 bool isFrameworkTarget = cmtarget.IsFrameworkOnApple();
760 bool isBundleTarget = cmtarget.GetPropertyAsBool("MACOSX_BUNDLE");
762 cmXCodeObject* buildFiles = 0;
764 // create source build phase
765 cmXCodeObject* sourceBuildPhase = 0;
766 if (!sourceFiles.empty())
768 sourceBuildPhase =
769 this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
770 sourceBuildPhase->SetComment("Sources");
771 sourceBuildPhase->AddAttribute("buildActionMask",
772 this->CreateString("2147483647"));
773 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
774 for(std::vector<cmXCodeObject*>::iterator i = sourceFiles.begin();
775 i != sourceFiles.end(); ++i)
777 buildFiles->AddObject(*i);
779 sourceBuildPhase->AddAttribute("files", buildFiles);
780 sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
781 this->CreateString("0"));
784 // create header build phase - only for framework targets
785 cmXCodeObject* headerBuildPhase = 0;
786 if (!headerFiles.empty() && isFrameworkTarget)
788 headerBuildPhase =
789 this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
790 headerBuildPhase->SetComment("Headers");
791 headerBuildPhase->AddAttribute("buildActionMask",
792 this->CreateString("2147483647"));
793 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
794 for(std::vector<cmXCodeObject*>::iterator i = headerFiles.begin();
795 i != headerFiles.end(); ++i)
797 buildFiles->AddObject(*i);
799 headerBuildPhase->AddAttribute("files", buildFiles);
800 headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
801 this->CreateString("0"));
804 // create resource build phase - only for framework or bundle targets
805 cmXCodeObject* resourceBuildPhase = 0;
806 if (!resourceFiles.empty() && (isFrameworkTarget || isBundleTarget))
808 resourceBuildPhase =
809 this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
810 resourceBuildPhase->SetComment("Resources");
811 resourceBuildPhase->AddAttribute("buildActionMask",
812 this->CreateString("2147483647"));
813 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
814 for(std::vector<cmXCodeObject*>::iterator i = resourceFiles.begin();
815 i != resourceFiles.end(); ++i)
817 buildFiles->AddObject(*i);
819 resourceBuildPhase->AddAttribute("files", buildFiles);
820 resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
821 this->CreateString("0"));
824 // create vector of "non-resource content file" build phases - only for
825 // framework or bundle targets
826 std::vector<cmXCodeObject*> contentBuildPhases;
827 if (isFrameworkTarget || isBundleTarget)
829 typedef std::map<cmStdString, std::vector<cmSourceFile*> >
830 mapOfVectorOfSourceFiles;
831 mapOfVectorOfSourceFiles bundleFiles;
832 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
833 i != classes.end(); ++i)
835 cmTarget::SourceFileFlags tsFlags =
836 cmtarget.GetTargetSourceFileFlags(*i);
837 if(tsFlags.Type == cmTarget::SourceFileTypeMacContent)
839 bundleFiles[tsFlags.MacFolder].push_back(*i);
842 mapOfVectorOfSourceFiles::iterator mit;
843 for ( mit = bundleFiles.begin(); mit != bundleFiles.end(); ++ mit )
845 cmXCodeObject* copyFilesBuildPhase =
846 this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
847 copyFilesBuildPhase->SetComment("Copy files");
848 copyFilesBuildPhase->AddAttribute("buildActionMask",
849 this->CreateString("2147483647"));
850 copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
851 this->CreateString("6"));
852 cmOStringStream ostr;
853 if (cmtarget.IsFrameworkOnApple())
855 // dstPath in frameworks is relative to Versions/<version>
856 ostr << mit->first;
858 else if ( mit->first != "MacOS" )
860 // dstPath in bundles is relative to Contents/MacOS
861 ostr << "../" << mit->first.c_str();
863 copyFilesBuildPhase->AddAttribute("dstPath",
864 this->CreateString(ostr.str().c_str()));
865 copyFilesBuildPhase->AddAttribute(
866 "runOnlyForDeploymentPostprocessing", this->CreateString("0"));
867 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
868 copyFilesBuildPhase->AddAttribute("files", buildFiles);
869 std::vector<cmSourceFile*>::iterator sfIt;
870 for ( sfIt = mit->second.begin(); sfIt != mit->second.end(); ++ sfIt )
872 cmXCodeObject* xsf =
873 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
874 *sfIt, cmtarget);
875 buildFiles->AddObject(xsf);
877 contentBuildPhases.push_back(copyFilesBuildPhase);
881 // create framework build phase
882 cmXCodeObject* frameworkBuildPhase = 0;
883 if (!externalObjFiles.empty())
885 frameworkBuildPhase =
886 this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
887 frameworkBuildPhase->SetComment("Frameworks");
888 frameworkBuildPhase->AddAttribute("buildActionMask",
889 this->CreateString("2147483647"));
890 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
891 frameworkBuildPhase->AddAttribute("files", buildFiles);
892 for(std::vector<cmXCodeObject*>::iterator i = externalObjFiles.begin();
893 i != externalObjFiles.end(); ++i)
895 buildFiles->AddObject(*i);
897 frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
898 this->CreateString("0"));
901 // create list of build phases and create the XCode target
902 cmXCodeObject* buildPhases =
903 this->CreateObject(cmXCodeObject::OBJECT_LIST);
905 this->CreateCustomCommands(buildPhases, sourceBuildPhase,
906 headerBuildPhase, resourceBuildPhase,
907 contentBuildPhases,
908 frameworkBuildPhase, cmtarget);
910 targets.push_back(this->CreateXCodeTarget(cmtarget, buildPhases));
914 //----------------------------------------------------------------------------
915 bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf)
917 const std::vector<std::string>& hdrExts =
918 this->CurrentMakefile->GetHeaderExtensions();
919 return (std::find(hdrExts.begin(), hdrExts.end(), sf->GetExtension()) !=
920 hdrExts.end());
923 //----------------------------------------------------------------------------
924 cmXCodeObject*
925 cmGlobalXCodeGenerator::CreateBuildPhase(const char* name,
926 const char* name2,
927 cmTarget& cmtarget,
928 const std::vector<cmCustomCommand>&
929 commands)
931 if(commands.size() == 0 && strcmp(name, "CMake ReRun") != 0)
933 return 0;
935 cmXCodeObject* buildPhase =
936 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
937 buildPhase->AddAttribute("buildActionMask",
938 this->CreateString("2147483647"));
939 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
940 buildPhase->AddAttribute("files", buildFiles);
941 buildPhase->AddAttribute("name",
942 this->CreateString(name));
943 buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
944 this->CreateString("0"));
945 buildPhase->AddAttribute("shellPath",
946 this->CreateString("/bin/sh"));
947 this->AddCommandsToBuildPhase(buildPhase, cmtarget, commands,
948 name2);
949 return buildPhase;
952 //----------------------------------------------------------------------------
953 void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases,
954 cmXCodeObject*
955 sourceBuildPhase,
956 cmXCodeObject*
957 headerBuildPhase,
958 cmXCodeObject*
959 resourceBuildPhase,
960 std::vector<cmXCodeObject*>
961 contentBuildPhases,
962 cmXCodeObject*
963 frameworkBuildPhase,
964 cmTarget& cmtarget)
966 std::vector<cmCustomCommand> const & prebuild
967 = cmtarget.GetPreBuildCommands();
968 std::vector<cmCustomCommand> const & prelink
969 = cmtarget.GetPreLinkCommands();
970 std::vector<cmCustomCommand> const & postbuild
971 = cmtarget.GetPostBuildCommands();
972 std::vector<cmSourceFile*>const &classes = cmtarget.GetSourceFiles();
973 // add all the sources
974 std::vector<cmCustomCommand> commands;
975 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
976 i != classes.end(); ++i)
978 if((*i)->GetCustomCommand())
980 commands.push_back(*(*i)->GetCustomCommand());
983 std::vector<cmCustomCommand> reruncom;
984 cmXCodeObject* cmakeReRunPhase =
985 this->CreateBuildPhase("CMake ReRun", "cmakeReRunPhase",
986 cmtarget, reruncom);
987 buildPhases->AddObject(cmakeReRunPhase);
988 // create prebuild phase
989 cmXCodeObject* cmakeRulesBuildPhase =
990 this->CreateBuildPhase("CMake Rules",
991 "cmakeRulesBuildPhase",
992 cmtarget, commands);
993 // create prebuild phase
994 cmXCodeObject* preBuildPhase =
995 this->CreateBuildPhase("CMake PreBuild Rules", "preBuildCommands",
996 cmtarget, prebuild);
997 // create prelink phase
998 cmXCodeObject* preLinkPhase =
999 this->CreateBuildPhase("CMake PreLink Rules", "preLinkCommands",
1000 cmtarget, prelink);
1001 // create postbuild phase
1002 cmXCodeObject* postBuildPhase =
1003 this->CreateBuildPhase("CMake PostBuild Rules", "postBuildPhase",
1004 cmtarget, postbuild);
1006 // The order here is the order they will be built in.
1007 // The order "headers, resources, sources" mimics a native project generated
1008 // from an xcode template...
1010 if(preBuildPhase)
1012 buildPhases->AddObject(preBuildPhase);
1014 if(cmakeRulesBuildPhase)
1016 buildPhases->AddObject(cmakeRulesBuildPhase);
1018 if(headerBuildPhase)
1020 buildPhases->AddObject(headerBuildPhase);
1022 if(resourceBuildPhase)
1024 buildPhases->AddObject(resourceBuildPhase);
1026 std::vector<cmXCodeObject*>::iterator cit;
1027 for (cit = contentBuildPhases.begin(); cit != contentBuildPhases.end();
1028 ++cit)
1030 buildPhases->AddObject(*cit);
1032 if(sourceBuildPhase)
1034 buildPhases->AddObject(sourceBuildPhase);
1036 if(preLinkPhase)
1038 buildPhases->AddObject(preLinkPhase);
1040 if(frameworkBuildPhase)
1042 buildPhases->AddObject(frameworkBuildPhase);
1044 if(postBuildPhase)
1046 buildPhases->AddObject(postBuildPhase);
1050 //----------------------------------------------------------------------------
1051 std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
1052 std::string& flags)
1054 std::string retFlag;
1055 std::string::size_type pos = flags.find(flag);
1056 if(pos != flags.npos && (pos ==0 || flags[pos-1]==' '))
1058 while(pos < flags.size() && flags[pos] != ' ')
1060 retFlag += flags[pos];
1061 flags[pos] = ' ';
1062 pos++;
1065 return retFlag;
1068 //----------------------------------------------------------------------------
1069 void
1070 cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
1071 cmTarget& target,
1072 std::vector<cmCustomCommand>
1073 const & commands,
1074 const char* name)
1076 if(strcmp(name, "cmakeReRunPhase") == 0)
1078 std::string cdir = this->CurrentMakefile->GetHomeOutputDirectory();
1079 cdir = this->ConvertToRelativeForMake(cdir.c_str());
1080 std::string makecmd = "make -C ";
1081 makecmd += cdir;
1082 makecmd += " -f ";
1083 makecmd +=
1084 this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str());
1085 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1086 buildphase->AddAttribute("shellScript",
1087 this->CreateString(makecmd.c_str()));
1088 return;
1091 // collect multiple outputs of custom commands into a set
1092 // which will be used for every configuration
1093 std::map<cmStdString, cmStdString> multipleOutputPairs;
1094 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1095 i != commands.end(); ++i)
1097 cmCustomCommand const& cc = *i;
1098 if(!cc.GetCommandLines().empty())
1100 const std::vector<std::string>& outputs = cc.GetOutputs();
1101 if(!outputs.empty())
1103 // If there are more than one outputs treat the
1104 // first as the primary output and make the rest depend on it.
1105 std::vector<std::string>::const_iterator o = outputs.begin();
1106 std::string primaryOutput = this->ConvertToRelativeForMake(o->c_str());
1107 for(++o; o != outputs.end(); ++o)
1109 std::string currentOutput=this->ConvertToRelativeForMake(o->c_str());
1110 multipleOutputPairs[currentOutput] = primaryOutput;
1116 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
1117 dir += "/CMakeScripts";
1118 cmSystemTools::MakeDirectory(dir.c_str());
1119 std::string makefile = dir;
1120 makefile += "/";
1121 makefile += target.GetName();
1122 makefile += "_";
1123 makefile += name;
1124 makefile += ".make";
1126 for (std::vector<std::string>::const_iterator currentConfig=
1127 this->CurrentConfigurationTypes.begin();
1128 currentConfig!=this->CurrentConfigurationTypes.end();
1129 currentConfig++ )
1131 this->CreateCustomRulesMakefile(makefile.c_str(),
1132 target,
1133 commands,
1134 currentConfig->c_str(),
1135 multipleOutputPairs);
1138 std::string cdir = this->CurrentMakefile->GetCurrentOutputDirectory();
1139 cdir = this->ConvertToRelativeForXCode(cdir.c_str());
1140 std::string makecmd = "make -C ";
1141 makecmd += cdir;
1142 makecmd += " -f ";
1143 makecmd += this->ConvertToRelativeForMake(
1144 (makefile+"$CONFIGURATION").c_str());
1145 if(!multipleOutputPairs.empty())
1147 makecmd += " cmake_check_multiple_outputs";
1149 makecmd += " all";
1150 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1151 buildphase->AddAttribute("shellScript",
1152 this->CreateString(makecmd.c_str()));
1155 //----------------------------------------------------------------------------
1156 void cmGlobalXCodeGenerator
1157 ::CreateCustomRulesMakefile(const char* makefileBasename,
1158 cmTarget& target,
1159 std::vector<cmCustomCommand>
1160 const & commands,
1161 const char* configName,
1162 const std::map<cmStdString,
1163 cmStdString>& multipleOutputPairs
1166 std::string makefileName=makefileBasename;
1167 makefileName+=configName;
1168 cmGeneratedFileStream makefileStream(makefileName.c_str());
1169 if(!makefileStream)
1171 return;
1173 makefileStream.SetCopyIfDifferent(true);
1174 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
1175 makefileStream << "# Custom rules for " << target.GetName() << "\n";
1177 // have all depend on all outputs
1178 makefileStream << "all: ";
1179 std::map<const cmCustomCommand*, cmStdString> tname;
1180 int count = 0;
1181 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1182 i != commands.end(); ++i)
1184 cmCustomCommand const& cc = *i;
1185 if(!cc.GetCommandLines().empty())
1187 const std::vector<std::string>& outputs = cc.GetOutputs();
1188 if(!outputs.empty())
1190 for(std::vector<std::string>::const_iterator o = outputs.begin();
1191 o != outputs.end(); ++o)
1193 makefileStream
1194 << "\\\n\t" << this->ConvertToRelativeForMake(o->c_str());
1197 else
1199 cmOStringStream str;
1200 str << "_buildpart_" << count++ ;
1201 tname[&cc] = std::string(target.GetName()) + str.str();
1202 makefileStream << "\\\n\t" << tname[&cc];
1206 makefileStream << "\n\n";
1207 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1208 i != commands.end(); ++i)
1210 cmCustomCommand const& cc = *i;
1211 if(!cc.GetCommandLines().empty())
1213 bool escapeOldStyle = cc.GetEscapeOldStyle();
1214 bool escapeAllowMakeVars = cc.GetEscapeAllowMakeVars();
1215 makefileStream << "\n";
1216 const std::vector<std::string>& outputs = cc.GetOutputs();
1217 if(!outputs.empty())
1219 // There is at least one output, start the rule for it
1220 std::string primary_output =
1221 this->ConvertToRelativeForMake(outputs.begin()->c_str());
1222 makefileStream << primary_output << ": ";
1224 else
1226 // There are no outputs. Use the generated force rule name.
1227 makefileStream << tname[&cc] << ": ";
1229 for(std::vector<std::string>::const_iterator d =
1230 cc.GetDepends().begin();
1231 d != cc.GetDepends().end(); ++d)
1233 std::string dep =
1234 this->CurrentLocalGenerator->GetRealDependency(d->c_str(),
1235 configName);
1236 makefileStream << "\\\n" << this
1237 ->ConvertToRelativeForMake(dep.c_str());
1239 makefileStream << "\n";
1241 if(const char* comment = cc.GetComment())
1243 std::string echo_cmd = "echo ";
1244 echo_cmd += (this->CurrentLocalGenerator->
1245 EscapeForShell(comment, escapeAllowMakeVars));
1246 makefileStream << "\t" << echo_cmd.c_str() << "\n";
1249 // Add each command line to the set of commands.
1250 for(cmCustomCommandLines::const_iterator cl =
1251 cc.GetCommandLines().begin();
1252 cl != cc.GetCommandLines().end(); ++cl)
1254 // Build the command line in a single string.
1255 const cmCustomCommandLine& commandLine = *cl;
1256 std::string cmd2 = this->CurrentLocalGenerator
1257 ->GetRealLocation(commandLine[0].c_str(), configName);
1259 cmSystemTools::ReplaceString(cmd2, "/./", "/");
1260 cmd2 = this->ConvertToRelativeForMake(cmd2.c_str());
1261 std::string cmd;
1262 if(cc.GetWorkingDirectory())
1264 cmd += "cd ";
1265 cmd += this->ConvertToRelativeForMake(cc.GetWorkingDirectory());
1266 cmd += " && ";
1268 cmd += cmd2;
1269 for(unsigned int j=1; j < commandLine.size(); ++j)
1271 cmd += " ";
1272 if(escapeOldStyle)
1274 cmd += (this->CurrentLocalGenerator
1275 ->EscapeForShellOldStyle(commandLine[j].c_str()));
1277 else
1279 cmd += (this->CurrentLocalGenerator->
1280 EscapeForShell(commandLine[j].c_str(),
1281 escapeAllowMakeVars));
1284 makefileStream << "\t" << cmd.c_str() << "\n";
1289 // Add rules to deal with multiple outputs of custom commands.
1290 if(!multipleOutputPairs.empty())
1292 makefileStream <<
1293 "\n# Dependencies of multiple outputs to their primary outputs \n";
1295 for(std::map<cmStdString, cmStdString>::const_iterator o =
1296 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1298 makefileStream << o->first << ": " << o->second << "\n";
1301 makefileStream <<
1302 "\n"
1303 "cmake_check_multiple_outputs:\n";
1304 for(std::map<cmStdString, cmStdString>::const_iterator o =
1305 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1307 makefileStream << "\t@if [ ! -f "
1308 << o->first << " ]; then rm -f "
1309 << o->second << "; fi\n";
1314 //----------------------------------------------------------------------------
1315 void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
1316 cmXCodeObject* buildSettings,
1317 std::string& fileType,
1318 std::string& productType,
1319 std::string& productName,
1320 const char* configName)
1322 std::string flags;
1323 std::string defFlags;
1324 bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
1325 (target.GetType() == cmTarget::MODULE_LIBRARY));
1327 const char* lang = target.GetLinkerLanguage(this);
1328 std::string cflags;
1329 if(lang)
1331 // for c++ projects get the c flags as well
1332 if(strcmp(lang, "CXX") == 0)
1334 this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName);
1335 this->CurrentLocalGenerator->AddSharedFlags(cflags, lang, shared);
1338 // Add language-specific flags.
1339 this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName);
1341 // Add shared-library flags if needed.
1342 this->CurrentLocalGenerator->AddSharedFlags(flags, lang, shared);
1345 // Add define flags
1346 this->CurrentLocalGenerator->
1347 AppendFlags(defFlags,
1348 this->CurrentMakefile->GetDefineFlags());
1350 // Add preprocessor definitions for this target and configuration.
1351 std::string ppDefs;
1352 if(this->XcodeVersion > 15)
1354 this->AppendDefines(ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)\"");
1356 if(const char* exportMacro = target.GetExportMacro())
1358 // Add the export symbol definition for shared library objects.
1359 this->AppendDefines(ppDefs, exportMacro);
1361 this->AppendDefines
1362 (ppDefs, this->CurrentMakefile->GetProperty("COMPILE_DEFINITIONS"));
1363 this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS"));
1364 if(configName)
1366 std::string defVarName = "COMPILE_DEFINITIONS_";
1367 defVarName += cmSystemTools::UpperCase(configName);
1368 this->AppendDefines
1369 (ppDefs, this->CurrentMakefile->GetProperty(defVarName.c_str()));
1370 this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str()));
1372 buildSettings->AddAttribute
1373 ("GCC_PREPROCESSOR_DEFINITIONS", this->CreateString(ppDefs.c_str()));
1375 std::string extraLinkOptions;
1376 if(target.GetType() == cmTarget::EXECUTABLE)
1378 extraLinkOptions =
1379 this->CurrentMakefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
1381 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1383 extraLinkOptions = this->CurrentMakefile->
1384 GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
1386 if(target.GetType() == cmTarget::MODULE_LIBRARY)
1388 extraLinkOptions = this->CurrentMakefile->
1389 GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
1392 const char* targetLinkFlags = target.GetProperty("LINK_FLAGS");
1393 if(targetLinkFlags)
1395 extraLinkOptions += " ";
1396 extraLinkOptions += targetLinkFlags;
1399 // The product name is the full name of the target for this configuration.
1400 productName = target.GetFullName(configName);
1402 // Get the product name components.
1403 std::string pnprefix;
1404 std::string pnbase;
1405 std::string pnsuffix;
1406 target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
1408 // Store the product name for all target types.
1409 buildSettings->AddAttribute("PRODUCT_NAME",
1410 this->CreateString(pnbase.c_str()));
1412 // Set attributes to specify the proper name for the target.
1413 if(target.GetType() == cmTarget::STATIC_LIBRARY ||
1414 target.GetType() == cmTarget::SHARED_LIBRARY ||
1415 target.GetType() == cmTarget::MODULE_LIBRARY ||
1416 target.GetType() == cmTarget::EXECUTABLE)
1418 std::string pndir = target.GetDirectory();
1419 buildSettings->AddAttribute("SYMROOT",
1420 this->CreateString(pndir.c_str()));
1421 buildSettings->AddAttribute("EXECUTABLE_PREFIX",
1422 this->CreateString(pnprefix.c_str()));
1423 buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
1424 this->CreateString(pnsuffix.c_str()));
1427 // Handle settings for each target type.
1428 switch(target.GetType())
1430 case cmTarget::STATIC_LIBRARY:
1432 fileType = "archive.ar";
1433 productType = "com.apple.product-type.library.static";
1435 buildSettings->AddAttribute("LIBRARY_STYLE",
1436 this->CreateString("STATIC"));
1437 break;
1440 case cmTarget::MODULE_LIBRARY:
1442 buildSettings->AddAttribute("LIBRARY_STYLE",
1443 this->CreateString("BUNDLE"));
1444 if(this->XcodeVersion >= 22)
1446 fileType = "compiled.mach-o.executable";
1447 productType = "com.apple.product-type.tool";
1449 buildSettings->AddAttribute("MACH_O_TYPE",
1450 this->CreateString("mh_bundle"));
1451 buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
1452 this->CreateString("NO"));
1453 // Add the flags to create an executable.
1454 std::string createFlags =
1455 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1456 if(!createFlags.empty())
1458 extraLinkOptions += " ";
1459 extraLinkOptions += createFlags;
1462 else
1464 fileType = "compiled.mach-o.dylib";
1465 productType = "com.apple.product-type.library.dynamic";
1467 // Add the flags to create a module.
1468 std::string createFlags =
1469 this->LookupFlags("CMAKE_SHARED_MODULE_CREATE_", lang, "_FLAGS",
1470 "-bundle");
1471 if(!createFlags.empty())
1473 extraLinkOptions += " ";
1474 extraLinkOptions += createFlags;
1477 break;
1479 case cmTarget::SHARED_LIBRARY:
1481 if(target.GetPropertyAsBool("FRAMEWORK"))
1483 fileType = "wrapper.framework";
1484 productType = "com.apple.product-type.framework";
1486 std::string version = target.GetFrameworkVersion();
1487 buildSettings->AddAttribute("FRAMEWORK_VERSION",
1488 this->CreateString(version.c_str()));
1490 std::string plist = this->ComputeInfoPListLocation(target);
1491 // Xcode will create the final version of Info.plist at build time,
1492 // so let it replace the framework name. This avoids creating
1493 // a per-configuration Info.plist file.
1494 this->CurrentLocalGenerator
1495 ->GenerateFrameworkInfoPList(&target, "$(EXECUTABLE_NAME)",
1496 plist.c_str());
1497 std::string path =
1498 this->ConvertToRelativeForXCode(plist.c_str());
1499 buildSettings->AddAttribute("INFOPLIST_FILE",
1500 this->CreateString(path.c_str()));
1502 else
1504 fileType = "compiled.mach-o.dylib";
1505 productType = "com.apple.product-type.library.dynamic";
1507 // Add the flags to create a shared library.
1508 std::string createFlags =
1509 this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", lang, "_FLAGS",
1510 "-dynamiclib");
1511 if(!createFlags.empty())
1513 extraLinkOptions += " ";
1514 extraLinkOptions += createFlags;
1518 buildSettings->AddAttribute("LIBRARY_STYLE",
1519 this->CreateString("DYNAMIC"));
1520 break;
1522 case cmTarget::EXECUTABLE:
1524 fileType = "compiled.mach-o.executable";
1526 // Add the flags to create an executable.
1527 std::string createFlags =
1528 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1529 if(!createFlags.empty())
1531 extraLinkOptions += " ";
1532 extraLinkOptions += createFlags;
1535 // Handle bundles and normal executables separately.
1536 if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
1538 productType = "com.apple.product-type.application";
1539 std::string plist = this->ComputeInfoPListLocation(target);
1540 // Xcode will create the final version of Info.plist at build time,
1541 // so let it replace the executable name. This avoids creating
1542 // a per-configuration Info.plist file.
1543 this->CurrentLocalGenerator
1544 ->GenerateAppleInfoPList(&target, "$(EXECUTABLE_NAME)",
1545 plist.c_str());
1546 std::string path =
1547 this->ConvertToRelativeForXCode(plist.c_str());
1548 buildSettings->AddAttribute("INFOPLIST_FILE",
1549 this->CreateString(path.c_str()));
1552 else
1554 productType = "com.apple.product-type.tool";
1557 break;
1558 default:
1559 break;
1561 if(this->XcodeVersion >= 22)
1563 buildSettings->AddAttribute("PREBINDING",
1564 this->CreateString("NO"));
1566 std::string dirs;
1567 std::vector<std::string> includes;
1568 this->CurrentLocalGenerator->GetIncludeDirectories(includes);
1569 std::string fdirs;
1570 std::set<cmStdString> emitted;
1571 emitted.insert("/System/Library/Frameworks");
1572 for(std::vector<std::string>::iterator i = includes.begin();
1573 i != includes.end(); ++i)
1575 if(this->NameResolvesToFramework(i->c_str()))
1577 std::string frameworkDir = *i;
1578 frameworkDir += "/../";
1579 frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str());
1580 if(emitted.insert(frameworkDir).second)
1582 fdirs += this->XCodeEscapePath(frameworkDir.c_str());
1583 fdirs += " ";
1586 else
1588 std::string incpath =
1589 this->XCodeEscapePath(i->c_str());
1590 dirs += incpath + " ";
1593 std::vector<std::string>& frameworks = target.GetFrameworks();
1594 if(frameworks.size())
1596 for(std::vector<std::string>::iterator fmIt = frameworks.begin();
1597 fmIt != frameworks.end(); ++fmIt)
1599 if(emitted.insert(*fmIt).second)
1601 fdirs += this->XCodeEscapePath(fmIt->c_str());
1602 fdirs += " ";
1606 if(fdirs.size())
1608 buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS",
1609 this->CreateString(fdirs.c_str()));
1611 if(dirs.size())
1613 buildSettings->AddAttribute("HEADER_SEARCH_PATHS",
1614 this->CreateString(dirs.c_str()));
1616 std::string oflagc = this->ExtractFlag("-O", cflags);
1617 char optLevel[2];
1618 optLevel[0] = '0';
1619 optLevel[1] = 0;
1620 if(oflagc.size() == 3)
1622 optLevel[0] = oflagc[2];
1624 if(oflagc.size() == 2)
1626 optLevel[0] = '1';
1628 std::string oflag = this->ExtractFlag("-O", flags);
1629 if(oflag.size() == 3)
1631 optLevel[0] = oflag[2];
1633 if(oflag.size() == 2)
1635 optLevel[0] = '1';
1637 std::string gflagc = this->ExtractFlag("-g", cflags);
1638 // put back gdwarf-2 if used since there is no way
1639 // to represent it in the gui, but we still want debug yes
1640 if(gflagc == "-gdwarf-2")
1642 cflags += " ";
1643 cflags += gflagc;
1645 std::string gflag = this->ExtractFlag("-g", flags);
1646 if(gflag == "-gdwarf-2")
1648 flags += " ";
1649 flags += gflag;
1651 const char* debugStr = "YES";
1652 if(gflagc.size() ==0 && gflag.size() == 0)
1654 debugStr = "NO";
1657 buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
1658 this->CreateString(debugStr));
1659 buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
1660 this->CreateString(optLevel));
1661 buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
1662 this->CreateString("NO"));
1663 buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
1664 this->CreateString("NO"));
1665 if(lang && strcmp(lang, "CXX") == 0)
1667 flags += " ";
1668 flags += defFlags;
1669 buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
1670 this->CreateString(flags.c_str()));
1671 cflags += " ";
1672 cflags += defFlags;
1673 buildSettings->AddAttribute("OTHER_CFLAGS",
1674 this->CreateString(cflags.c_str()));
1677 else
1679 flags += " ";
1680 flags += defFlags;
1681 buildSettings->AddAttribute("OTHER_CFLAGS",
1682 this->CreateString(flags.c_str()));
1685 // Create the INSTALL_PATH attribute.
1686 std::string install_name_dir;
1687 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1689 // Get the install_name directory for the build tree.
1690 install_name_dir = target.GetInstallNameDirForBuildTree(configName, true);
1691 if(install_name_dir.empty())
1693 // Xcode will not pass the -install_name option at all if INSTALL_PATH
1694 // is not given or is empty. We must explicitly put the flag in the
1695 // link flags to create an install_name with just the library soname.
1696 extraLinkOptions += " -install_name ";
1697 extraLinkOptions += productName;
1699 else
1701 // Convert to a path for the native build tool.
1702 cmSystemTools::ConvertToUnixSlashes(install_name_dir);
1703 // do not escape spaces on this since it is only a single path
1706 buildSettings->AddAttribute("INSTALL_PATH",
1707 this->CreateString(install_name_dir.c_str()));
1709 buildSettings->AddAttribute("OTHER_LDFLAGS",
1710 this->CreateString(extraLinkOptions.c_str()));
1711 buildSettings->AddAttribute("OTHER_REZFLAGS",
1712 this->CreateString(""));
1713 buildSettings->AddAttribute("SECTORDER_FLAGS",
1714 this->CreateString(""));
1715 buildSettings->AddAttribute("USE_HEADERMAP",
1716 this->CreateString("NO"));
1717 buildSettings->AddAttribute("WARNING_CFLAGS",
1718 this->CreateString(
1719 "-Wmost -Wno-four-char-constants"
1720 " -Wno-unknown-pragmas"));
1722 // Runtime version information.
1723 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1725 int major;
1726 int minor;
1727 int patch;
1729 // VERSION -> current_version
1730 target.GetTargetVersion(false, major, minor, patch);
1731 if(major == 0 && minor == 0 && patch == 0)
1733 // Xcode always wants at least 1.0.0
1734 major = 1;
1736 cmOStringStream v;
1737 v << major << "." << minor << "." << patch;
1738 buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
1739 this->CreateString(v.str().c_str()));
1741 // SOVERSION -> compatibility_version
1742 target.GetTargetVersion(true, major, minor, patch);
1743 if(major == 0 && minor == 0 && patch == 0)
1745 // Xcode always wants at least 1.0.0
1746 major = 1;
1748 cmOStringStream vso;
1749 vso << major << "." << minor << "." << patch;
1750 buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
1751 this->CreateString(vso.str().c_str()));
1753 // put this last so it can override existing settings
1754 // Convert "XCODE_ATTRIBUTE_*" properties directly.
1756 cmPropertyMap const& props = target.GetProperties();
1757 for(cmPropertyMap::const_iterator i = props.begin();
1758 i != props.end(); ++i)
1760 if(i->first.find("XCODE_ATTRIBUTE_") == 0)
1762 buildSettings->AddAttribute(i->first.substr(16).c_str(),
1763 this->CreateString(i->second.GetValue()));
1769 //----------------------------------------------------------------------------
1770 cmXCodeObject*
1771 cmGlobalXCodeGenerator::CreateUtilityTarget(cmTarget& cmtarget)
1773 cmXCodeObject* shellBuildPhase =
1774 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
1775 shellBuildPhase->AddAttribute("buildActionMask",
1776 this->CreateString("2147483647"));
1777 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1778 shellBuildPhase->AddAttribute("files", buildFiles);
1779 cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1780 shellBuildPhase->AddAttribute("inputPaths", inputPaths);
1781 cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1782 shellBuildPhase->AddAttribute("outputPaths", outputPaths);
1783 shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1784 this->CreateString("0"));
1785 shellBuildPhase->AddAttribute("shellPath",
1786 this->CreateString("/bin/sh"));
1787 shellBuildPhase->AddAttribute("shellScript",
1788 this->CreateString(
1789 "# shell script goes here\nexit 0"));
1790 cmXCodeObject* target =
1791 this->CreateObject(cmXCodeObject::PBXAggregateTarget);
1792 target->SetComment(cmtarget.GetName());
1793 cmXCodeObject* buildPhases =
1794 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1795 std::vector<cmXCodeObject*> emptyContentVector;
1796 this->CreateCustomCommands(buildPhases, 0, 0, 0, emptyContentVector, 0,
1797 cmtarget);
1798 target->AddAttribute("buildPhases", buildPhases);
1799 cmXCodeObject* buildSettings =
1800 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1801 std::string fileTypeString;
1802 std::string productTypeString;
1803 std::string productName;
1804 const char* globalConfig = 0;
1805 if(this->XcodeVersion > 20)
1807 this->AddConfigurations(target, cmtarget);
1809 else
1811 globalConfig = this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
1813 this->CreateBuildSettings(cmtarget,
1814 buildSettings, fileTypeString,
1815 productTypeString, productName, globalConfig);
1816 target->AddAttribute("buildSettings", buildSettings);
1817 cmXCodeObject* dependencies =
1818 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1819 target->AddAttribute("dependencies", dependencies);
1820 target->AddAttribute("name", this->CreateString(productName.c_str()));
1821 target->AddAttribute("productName",this->CreateString(productName.c_str()));
1822 target->SetTarget(&cmtarget);
1824 // Add source files without build rules for editing convenience.
1825 if(cmtarget.GetType() == cmTarget::UTILITY)
1827 std::vector<cmSourceFile*> const& sources = cmtarget.GetSourceFiles();
1828 for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
1829 i != sources.end(); ++i)
1831 if(!(*i)->GetPropertyAsBool("GENERATED"))
1833 this->CreateXCodeFileReference(*i, cmtarget);
1838 return target;
1841 //----------------------------------------------------------------------------
1842 void cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
1843 cmTarget& cmtarget)
1845 std::string configTypes =
1846 this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
1847 std::vector<std::string> configVectorIn;
1848 std::vector<std::string> configVector;
1849 configVectorIn.push_back(configTypes);
1850 cmSystemTools::ExpandList(configVectorIn, configVector);
1851 cmXCodeObject* configlist =
1852 this->CreateObject(cmXCodeObject::XCConfigurationList);
1853 cmXCodeObject* buildConfigurations =
1854 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1855 configlist->AddAttribute("buildConfigurations", buildConfigurations);
1856 std::string comment = "Build configuration list for ";
1857 comment += cmXCodeObject::PBXTypeNames[target->GetIsA()];
1858 comment += " \"";
1859 comment += cmtarget.GetName();
1860 comment += "\"";
1861 configlist->SetComment(comment.c_str());
1862 target->AddAttribute("buildConfigurationList",
1863 this->CreateObjectReference(configlist));
1864 for(unsigned int i = 0; i < configVector.size(); ++i)
1866 cmXCodeObject* config =
1867 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
1868 buildConfigurations->AddObject(config);
1869 cmXCodeObject* buildSettings =
1870 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1871 std::string fileTypeString;
1872 std::string productTypeString;
1873 std::string productName;
1874 this->CreateBuildSettings(cmtarget,
1875 buildSettings, fileTypeString,
1876 productTypeString, productName,
1877 configVector[i].c_str());
1878 config->AddAttribute("name", this->CreateString(configVector[i].c_str()));
1879 config->SetComment(configVector[i].c_str());
1880 config->AddAttribute("buildSettings", buildSettings);
1882 if(configVector.size())
1884 configlist->AddAttribute("defaultConfigurationName",
1885 this->CreateString(configVector[0].c_str()));
1886 configlist->AddAttribute("defaultConfigurationIsVisible",
1887 this->CreateString("0"));
1891 //----------------------------------------------------------------------------
1892 cmXCodeObject*
1893 cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
1894 cmXCodeObject* buildPhases)
1896 cmXCodeObject* target =
1897 this->CreateObject(cmXCodeObject::PBXNativeTarget);
1898 target->AddAttribute("buildPhases", buildPhases);
1899 cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1900 target->AddAttribute("buildRules", buildRules);
1901 cmXCodeObject* buildSettings =
1902 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1903 std::string fileTypeString;
1904 std::string productTypeString;
1905 std::string productName;
1906 const char* globalConfig = 0;
1907 if(this->XcodeVersion > 20)
1909 this->AddConfigurations(target, cmtarget);
1911 else
1913 globalConfig = this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
1915 this->CreateBuildSettings(cmtarget,
1916 buildSettings, fileTypeString,
1917 productTypeString, productName, globalConfig);
1918 target->AddAttribute("buildSettings", buildSettings);
1919 cmXCodeObject* dependencies =
1920 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1921 target->AddAttribute("dependencies", dependencies);
1922 target->AddAttribute("name", this->CreateString(productName.c_str()));
1923 target->AddAttribute("productName",this->CreateString(productName.c_str()));
1925 cmXCodeObject* fileRef =
1926 this->CreateObject(cmXCodeObject::PBXFileReference);
1927 fileRef->AddAttribute("explicitFileType",
1928 this->CreateString(fileTypeString.c_str()));
1929 fileRef->AddAttribute("path", this->CreateString(productName.c_str()));
1930 fileRef->AddAttribute("refType", this->CreateString("0"));
1931 fileRef->AddAttribute("sourceTree",
1932 this->CreateString("BUILT_PRODUCTS_DIR"));
1933 fileRef->SetComment(cmtarget.GetName());
1934 target->AddAttribute("productReference",
1935 this->CreateObjectReference(fileRef));
1936 target->AddAttribute("productType",
1937 this->CreateString(productTypeString.c_str()));
1938 target->SetTarget(&cmtarget);
1939 return target;
1942 //----------------------------------------------------------------------------
1943 cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
1945 if(!t)
1947 return 0;
1949 for(std::vector<cmXCodeObject*>::iterator i = this->XCodeObjects.begin();
1950 i != this->XCodeObjects.end(); ++i)
1952 cmXCodeObject* o = *i;
1953 if(o->GetTarget() == t)
1955 return o;
1958 return 0;
1961 //----------------------------------------------------------------------------
1962 void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
1963 cmXCodeObject* dependTarget)
1965 // make sure a target does not depend on itself
1966 if(target == dependTarget)
1968 return;
1970 // now avoid circular references if dependTarget already
1971 // depends on target then skip it. Circular references crashes
1972 // xcode
1973 cmXCodeObject* dependTargetDepends =
1974 dependTarget->GetObject("dependencies");
1975 if(dependTargetDepends)
1977 if(dependTargetDepends->HasObject(target->GetPBXTargetDependency()))
1979 return;
1983 cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency();
1984 if(!targetdep)
1986 cmXCodeObject* container =
1987 this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
1988 container->SetComment("PBXContainerItemProxy");
1989 container->AddAttribute("containerPortal",
1990 this->CreateObjectReference(this->RootObject));
1991 container->AddAttribute("proxyType", this->CreateString("1"));
1992 container->AddAttribute("remoteGlobalIDString",
1993 this->CreateObjectReference(dependTarget));
1994 container->AddAttribute("remoteInfo",
1995 this->CreateString(
1996 dependTarget->GetTarget()->GetName()));
1997 targetdep =
1998 this->CreateObject(cmXCodeObject::PBXTargetDependency);
1999 targetdep->SetComment("PBXTargetDependency");
2000 targetdep->AddAttribute("target",
2001 this->CreateObjectReference(dependTarget));
2002 targetdep->AddAttribute("targetProxy",
2003 this->CreateObjectReference(container));
2004 dependTarget->SetPBXTargetDependency(targetdep);
2007 cmXCodeObject* depends = target->GetObject("dependencies");
2008 if(!depends)
2010 cmSystemTools::
2011 Error("target does not have dependencies attribute error..");
2014 else
2016 depends->AddUniqueObject(targetdep);
2020 //----------------------------------------------------------------------------
2021 void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
2022 const char* attribute,
2023 const char* value)
2025 if(settings)
2027 cmXCodeObject* attr = settings->GetObject(attribute);
2028 if(!attr)
2030 settings->AddAttribute(attribute, this->CreateString(value));
2032 else
2034 std::string oldValue = attr->GetString();
2035 oldValue += " ";
2036 oldValue += value;
2037 attr->SetString(oldValue.c_str());
2042 //----------------------------------------------------------------------------
2043 void cmGlobalXCodeGenerator
2044 ::AppendBuildSettingAttribute(cmXCodeObject* target,
2045 const char* attribute,
2046 const char* value,
2047 const char* configName)
2049 if(this->XcodeVersion < 21)
2051 // There is only one configuration. Add the setting to the buildSettings
2052 // of the target.
2053 this->AppendOrAddBuildSetting(target->GetObject("buildSettings"),
2054 attribute, value);
2056 else
2058 // There are multiple configurations. Add the setting to the
2059 // buildSettings of the configuration name given.
2060 cmXCodeObject* configurationList =
2061 target->GetObject("buildConfigurationList")->GetObject();
2062 cmXCodeObject* buildConfigs =
2063 configurationList->GetObject("buildConfigurations");
2064 std::vector<cmXCodeObject*> list = buildConfigs->GetObjectList();
2065 // each configuration and the target itself has a buildSettings in it
2066 //list.push_back(target);
2067 for(std::vector<cmXCodeObject*>::iterator i = list.begin();
2068 i != list.end(); ++i)
2070 if(configName)
2072 if(strcmp((*i)->GetObject("name")->GetString(), configName) == 0)
2074 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2075 this->AppendOrAddBuildSetting(settings, attribute, value);
2078 else
2080 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2081 this->AppendOrAddBuildSetting(settings, attribute, value);
2087 //----------------------------------------------------------------------------
2088 void cmGlobalXCodeGenerator
2089 ::AddDependAndLinkInformation(cmXCodeObject* target)
2091 cmTarget* cmtarget = target->GetTarget();
2092 if(!cmtarget)
2094 cmSystemTools::Error("Error no target on xobject\n");
2095 return;
2098 // Add dependencies on other CMake targets.
2099 TargetDependSet const& deps = this->GetTargetDirectDepends(*cmtarget);
2100 for(TargetDependSet::const_iterator i = deps.begin(); i != deps.end(); ++i)
2102 if(cmXCodeObject* dptarget = this->FindXCodeTarget(*i))
2104 this->AddDependTarget(target, dptarget);
2108 // Skip link information for static libraries.
2109 if(cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
2111 return;
2114 // Loop over configuration types and set per-configuration info.
2115 for(std::vector<std::string>::iterator i =
2116 this->CurrentConfigurationTypes.begin();
2117 i != this->CurrentConfigurationTypes.end(); ++i)
2119 // Get the current configuration name.
2120 const char* configName = i->c_str();
2121 if(!*configName)
2123 configName = 0;
2126 // Compute the link library and directory information.
2127 cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName);
2128 if(!pcli)
2130 continue;
2132 cmComputeLinkInformation& cli = *pcli;
2134 // Add dependencies directly on library files.
2136 std::vector<std::string> const& libDeps = cli.GetDepends();
2137 for(std::vector<std::string>::const_iterator j = libDeps.begin();
2138 j != libDeps.end(); ++j)
2140 target->AddDependLibrary(configName, j->c_str());
2144 // add the library search paths
2146 std::vector<std::string> const& libDirs = cli.GetDirectories();
2147 std::string linkDirs;
2148 for(std::vector<std::string>::const_iterator libDir = libDirs.begin();
2149 libDir != libDirs.end(); ++libDir)
2151 if(libDir->size() && *libDir != "/usr/lib")
2153 if(this->XcodeVersion > 15)
2155 // now add the same one but append $(CONFIGURATION) to it:
2156 linkDirs += " ";
2157 linkDirs += this->XCodeEscapePath(
2158 (*libDir + "/$(CONFIGURATION)").c_str());
2160 linkDirs += " ";
2161 linkDirs += this->XCodeEscapePath(libDir->c_str());
2164 this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
2165 linkDirs.c_str(), configName);
2168 // add the framework search paths
2170 const char* sep = "";
2171 std::string fdirs;
2172 std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
2173 for(std::vector<std::string>::const_iterator fdi = fwDirs.begin();
2174 fdi != fwDirs.end(); ++fdi)
2176 fdirs += sep;
2177 sep = " ";
2178 fdirs += this->XCodeEscapePath(fdi->c_str());
2180 if(!fdirs.empty())
2182 this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
2183 fdirs.c_str(), configName);
2187 // now add the link libraries
2189 std::string linkLibs;
2190 const char* sep = "";
2191 typedef cmComputeLinkInformation::ItemVector ItemVector;
2192 ItemVector const& libNames = cli.GetItems();
2193 for(ItemVector::const_iterator li = libNames.begin();
2194 li != libNames.end(); ++li)
2196 linkLibs += sep;
2197 sep = " ";
2198 if(li->IsPath)
2200 linkLibs += this->XCodeEscapePath(li->Value.c_str());
2202 else
2204 linkLibs += li->Value;
2207 this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
2208 linkLibs.c_str(), configName);
2213 //----------------------------------------------------------------------------
2214 void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
2215 std::vector<cmLocalGenerator*>&
2216 generators)
2218 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2219 i != generators.end(); ++i)
2221 if(this->IsExcluded(root, *i))
2223 continue;
2225 cmMakefile* mf = (*i)->GetMakefile();
2226 std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
2227 cmTargets &tgts = mf->GetTargets();
2228 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
2230 cmTarget& cmtarget = l->second;
2232 // Same skipping logic here as in CreateXCodeTargets so that we do not
2233 // end up with (empty anyhow) ALL_BUILD and XCODE_DEPEND_HELPER source
2234 // groups:
2236 if(cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
2238 continue;
2241 // add the soon to be generated Info.plist file as a source for a
2242 // MACOSX_BUNDLE file
2243 if(cmtarget.GetPropertyAsBool("MACOSX_BUNDLE"))
2245 std::string plist = this->ComputeInfoPListLocation(cmtarget);
2246 cmSourceFile* sf = mf->GetOrCreateSource(plist.c_str(), true);
2247 cmtarget.AddSourceFile(sf);
2250 std::vector<cmSourceFile*> classes = cmtarget.GetSourceFiles();
2252 for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
2253 s != classes.end(); s++)
2255 cmSourceFile* sf = *s;
2256 // Add the file to the list of sources.
2257 std::string const& source = sf->GetFullPath();
2258 cmSourceGroup& sourceGroup =
2259 mf->FindSourceGroup(source.c_str(), sourceGroups);
2260 cmXCodeObject* pbxgroup =
2261 this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
2262 cmStdString key = GetGroupMapKey(cmtarget, sf);
2263 this->GroupMap[key] = pbxgroup;
2269 //----------------------------------------------------------------------------
2270 cmXCodeObject* cmGlobalXCodeGenerator
2271 ::CreateOrGetPBXGroup(cmTarget& cmtarget, cmSourceGroup* sg)
2273 cmStdString s = cmtarget.GetName();
2274 s += "/";
2275 s += sg->GetName();
2276 std::map<cmStdString, cmXCodeObject* >::iterator i =
2277 this->GroupNameMap.find(s);
2278 if(i != this->GroupNameMap.end())
2280 return i->second;
2282 i = this->TargetGroup.find(cmtarget.GetName());
2283 cmXCodeObject* tgroup = 0;
2284 if(i != this->TargetGroup.end())
2286 tgroup = i->second;
2288 else
2290 tgroup = this->CreateObject(cmXCodeObject::PBXGroup);
2291 this->TargetGroup[cmtarget.GetName()] = tgroup;
2292 cmXCodeObject* tgroupChildren =
2293 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2294 tgroup->AddAttribute("name", this->CreateString(cmtarget.GetName()));
2295 tgroup->AddAttribute("children", tgroupChildren);
2296 if(this->XcodeVersion == 15)
2298 tgroup->AddAttribute("refType", this->CreateString("4"));
2300 tgroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2301 this->SourcesGroupChildren->AddObject(tgroup);
2304 // If it's the default source group (empty name) then put the source file
2305 // directly in the tgroup...
2307 if (cmStdString(sg->GetName()) == "")
2309 this->GroupNameMap[s] = tgroup;
2310 return tgroup;
2313 cmXCodeObject* tgroupChildren = tgroup->GetObject("children");
2314 cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
2315 cmXCodeObject* groupChildren =
2316 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2317 group->AddAttribute("name", this->CreateString(sg->GetName()));
2318 group->AddAttribute("children", groupChildren);
2319 if(this->XcodeVersion == 15)
2321 group->AddAttribute("refType", this->CreateString("4"));
2323 group->AddAttribute("sourceTree", this->CreateString("<group>"));
2324 tgroupChildren->AddObject(group);
2325 this->GroupNameMap[s] = group;
2326 return group;
2329 //----------------------------------------------------------------------------
2330 void cmGlobalXCodeGenerator
2331 ::CreateXCodeObjects(cmLocalGenerator* root,
2332 std::vector<cmLocalGenerator*>&
2333 generators)
2335 this->ClearXCodeObjects();
2336 this->RootObject = 0;
2337 this->SourcesGroupChildren = 0;
2338 this->ResourcesGroupChildren = 0;
2339 this->MainGroupChildren = 0;
2340 cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2341 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2342 cmXCodeObject* developBuildStyle =
2343 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2344 cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2345 if(this->XcodeVersion == 15)
2347 developBuildStyle->AddAttribute("name",
2348 this->CreateString("Development"));
2349 developBuildStyle->AddAttribute("buildSettings", group);
2350 listObjs->AddObject(developBuildStyle);
2351 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2352 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
2353 cmXCodeObject* deployBuildStyle =
2354 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2355 deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
2356 deployBuildStyle->AddAttribute("buildSettings", group);
2357 listObjs->AddObject(deployBuildStyle);
2359 else
2361 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2363 cmXCodeObject* buildStyle =
2364 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2365 const char* name = this->CurrentConfigurationTypes[i].c_str();
2366 buildStyle->AddAttribute("name", this->CreateString(name));
2367 buildStyle->SetComment(name);
2368 cmXCodeObject* sgroup =
2369 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2370 sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2371 buildStyle->AddAttribute("buildSettings", sgroup);
2372 listObjs->AddObject(buildStyle);
2376 cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2377 this->MainGroupChildren =
2378 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2379 mainGroup->AddAttribute("children", this->MainGroupChildren);
2380 if(this->XcodeVersion == 15)
2382 mainGroup->AddAttribute("refType", this->CreateString("4"));
2384 mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2386 cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2387 this->SourcesGroupChildren =
2388 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2389 sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
2390 sourcesGroup->AddAttribute("children", this->SourcesGroupChildren);
2391 if(this->XcodeVersion == 15)
2393 sourcesGroup->AddAttribute("refType", this->CreateString("4"));
2395 sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2396 this->MainGroupChildren->AddObject(sourcesGroup);
2398 cmXCodeObject* resourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2399 this->ResourcesGroupChildren =
2400 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2401 resourcesGroup->AddAttribute("name", this->CreateString("Resources"));
2402 resourcesGroup->AddAttribute("children", this->ResourcesGroupChildren);
2403 if(this->XcodeVersion == 15)
2405 resourcesGroup->AddAttribute("refType", this->CreateString("4"));
2407 resourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2408 this->MainGroupChildren->AddObject(resourcesGroup);
2410 // now create the cmake groups
2411 this->CreateGroups(root, generators);
2413 cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2414 productGroup->AddAttribute("name", this->CreateString("Products"));
2415 if(this->XcodeVersion == 15)
2417 productGroup->AddAttribute("refType", this->CreateString("4"));
2419 productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2420 cmXCodeObject* productGroupChildren =
2421 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2422 productGroup->AddAttribute("children", productGroupChildren);
2423 this->MainGroupChildren->AddObject(productGroup);
2426 this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
2427 this->RootObject->SetComment("Project object");
2428 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2429 this->RootObject->AddAttribute("mainGroup",
2430 this->CreateObjectReference(mainGroup));
2431 this->RootObject->AddAttribute("buildSettings", group);
2432 this->RootObject->AddAttribute("buildStyles", listObjs);
2433 this->RootObject->AddAttribute("hasScannedForEncodings",
2434 this->CreateString("0"));
2435 // Point Xcode at the top of the source tree.
2437 std::string proot = root->GetMakefile()->GetCurrentDirectory();
2438 proot = this->ConvertToRelativeForXCode(proot.c_str());
2439 this->RootObject->AddAttribute("projectRoot",
2440 this->CreateString(proot.c_str()));
2442 cmXCodeObject* configlist =
2443 this->CreateObject(cmXCodeObject::XCConfigurationList);
2444 cmXCodeObject* buildConfigurations =
2445 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2446 std::vector<cmXCodeObject*> configs;
2447 if(this->XcodeVersion == 15)
2449 cmXCodeObject* configDebug =
2450 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2451 configDebug->AddAttribute("name", this->CreateString("Debug"));
2452 configs.push_back(configDebug);
2453 cmXCodeObject* configRelease =
2454 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2455 configRelease->AddAttribute("name", this->CreateString("Release"));
2456 configs.push_back(configRelease);
2458 else
2460 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2462 const char* name = this->CurrentConfigurationTypes[i].c_str();
2463 cmXCodeObject* config =
2464 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2465 config->AddAttribute("name", this->CreateString(name));
2466 configs.push_back(config);
2469 for(std::vector<cmXCodeObject*>::iterator c = configs.begin();
2470 c != configs.end(); ++c)
2472 buildConfigurations->AddObject(*c);
2474 configlist->AddAttribute("buildConfigurations", buildConfigurations);
2476 std::string comment = "Build configuration list for PBXProject ";
2477 comment += " \"";
2478 comment += this->CurrentProject;
2479 comment += "\"";
2480 configlist->SetComment(comment.c_str());
2481 configlist->AddAttribute("defaultConfigurationIsVisible",
2482 this->CreateString("0"));
2483 configlist->AddAttribute("defaultConfigurationName",
2484 this->CreateString("Debug"));
2485 cmXCodeObject* buildSettings =
2486 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2487 const char* osxArch =
2488 this->CurrentMakefile->GetDefinition("CMAKE_OSX_ARCHITECTURES");
2489 const char* sysroot =
2490 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
2491 const char* sysrootDefault =
2492 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT_DEFAULT");
2493 const char* deploymentTarget =
2494 this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
2495 if(osxArch && sysroot)
2497 bool flagsUsed = false;
2498 // recompute this as it may have been changed since enable language
2499 this->Architectures.clear();
2500 cmSystemTools::ExpandListArgument(std::string(osxArch),
2501 this->Architectures);
2502 bool addArchFlag = true;
2503 if(this->Architectures.size() == 1)
2505 const char* archOrig =
2506 this->
2507 CurrentMakefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES_DEFAULT");
2508 if(this->Architectures[0] == archOrig)
2510 addArchFlag = false;
2513 if(addArchFlag)
2515 flagsUsed = true;
2516 buildSettings->AddAttribute("SDKROOT",
2517 this->CreateString(sysroot));
2518 std::string archString;
2519 for( std::vector<std::string>::iterator i =
2520 this->Architectures.begin();
2521 i != this->Architectures.end(); ++i)
2523 archString += *i;
2524 archString += " ";
2526 buildSettings->AddAttribute("ARCHS",
2527 this->CreateString(archString.c_str()));
2529 if(!flagsUsed && sysrootDefault &&
2530 strcmp(sysroot, sysrootDefault) != 0)
2532 buildSettings->AddAttribute("SDKROOT",
2533 this->CreateString(sysroot));
2536 if(deploymentTarget && *deploymentTarget)
2538 buildSettings->AddAttribute("MACOSX_DEPLOYMENT_TARGET",
2539 this->CreateString(deploymentTarget));
2541 for( std::vector<cmXCodeObject*>::iterator i = configs.begin();
2542 i != configs.end(); ++i)
2544 (*i)->AddAttribute("buildSettings", buildSettings);
2546 this->RootObject->AddAttribute("buildConfigurationList",
2547 this->CreateObjectReference(configlist));
2549 std::vector<cmXCodeObject*> targets;
2550 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2551 i != generators.end(); ++i)
2553 if(!this->IsExcluded(root, *i))
2555 this->CreateXCodeTargets(*i, targets);
2558 // loop over all targets and add link and depend info
2559 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2560 i != targets.end(); ++i)
2562 cmXCodeObject* t = *i;
2563 this->AddDependAndLinkInformation(t);
2565 // now create xcode depend hack makefile
2566 this->CreateXCodeDependHackTarget(targets);
2567 // now add all targets to the root object
2568 cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2569 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2570 i != targets.end(); ++i)
2572 cmXCodeObject* t = *i;
2573 allTargets->AddObject(t);
2574 cmXCodeObject* productRef = t->GetObject("productReference");
2575 if(productRef)
2577 productGroupChildren->AddObject(productRef->GetObject());
2580 this->RootObject->AddAttribute("targets", allTargets);
2583 //----------------------------------------------------------------------------
2584 void
2585 cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
2586 std::vector<cmXCodeObject*>& targets)
2588 cmGeneratedFileStream
2589 makefileStream(this->CurrentXCodeHackMakefile.c_str());
2590 if(!makefileStream)
2592 cmSystemTools::Error("Could not create",
2593 this->CurrentXCodeHackMakefile.c_str());
2594 return;
2596 makefileStream.SetCopyIfDifferent(true);
2597 // one more pass for external depend information not handled
2598 // correctly by xcode
2599 makefileStream << "# DO NOT EDIT\n";
2600 makefileStream << "# This makefile makes sure all linkable targets are\n";
2601 makefileStream << "# up-to-date with anything they link to, avoiding a "
2602 "bug in XCode 1.5\n";
2603 for(std::vector<std::string>::const_iterator
2604 ct = this->CurrentConfigurationTypes.begin();
2605 ct != this->CurrentConfigurationTypes.end(); ++ct)
2607 if(this->XcodeVersion < 21 || ct->empty())
2609 makefileStream << "all: ";
2611 else
2613 makefileStream << "all." << *ct << ": ";
2615 const char* configName = 0;
2616 if(!ct->empty())
2618 configName = ct->c_str();
2620 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2621 i != targets.end(); ++i)
2623 cmXCodeObject* target = *i;
2624 cmTarget* t =target->GetTarget();
2625 if(t->GetType() == cmTarget::EXECUTABLE ||
2626 t->GetType() == cmTarget::SHARED_LIBRARY ||
2627 t->GetType() == cmTarget::MODULE_LIBRARY)
2629 std::string tfull = t->GetFullPath(configName);
2630 makefileStream << "\\\n\t" <<
2631 this->ConvertToRelativeForMake(tfull.c_str());
2634 makefileStream << "\n\n";
2636 makefileStream
2637 << "# For each target create a dummy rule "
2638 "so the target does not have to exist\n";
2639 std::set<cmStdString> emitted;
2640 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2641 i != targets.end(); ++i)
2643 cmXCodeObject* target = *i;
2644 std::map<cmStdString, cmXCodeObject::StringVec> const& deplibs =
2645 target->GetDependLibraries();
2646 for(std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator ci
2647 = deplibs.begin(); ci != deplibs.end(); ++ci)
2649 for(cmXCodeObject::StringVec::const_iterator d = ci->second.begin();
2650 d != ci->second.end(); ++d)
2652 if(emitted.insert(*d).second)
2654 makefileStream <<
2655 this->ConvertToRelativeForMake(d->c_str()) << ":\n";
2660 makefileStream << "\n\n";
2662 // Write rules to help Xcode relink things at the right time.
2663 makefileStream <<
2664 "# Rules to remove targets that are older than anything to which they\n"
2665 "# link. This forces Xcode to relink the targets from scratch. It\n"
2666 "# does not seem to check these dependencies itself.\n";
2667 for(std::vector<std::string>::const_iterator
2668 ct = this->CurrentConfigurationTypes.begin();
2669 ct != this->CurrentConfigurationTypes.end(); ++ct)
2671 const char* configName = 0;
2672 if(!ct->empty())
2674 configName = ct->c_str();
2676 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2677 i != targets.end(); ++i)
2679 cmXCodeObject* target = *i;
2680 cmTarget* t =target->GetTarget();
2681 if(t->GetType() == cmTarget::EXECUTABLE ||
2682 t->GetType() == cmTarget::SHARED_LIBRARY ||
2683 t->GetType() == cmTarget::MODULE_LIBRARY)
2685 // Create a rule for this target.
2686 std::string tfull = t->GetFullPath(configName);
2687 makefileStream << this->ConvertToRelativeForMake(tfull.c_str())
2688 << ":";
2690 // List dependencies if any exist.
2691 std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator
2692 x = target->GetDependLibraries().find(*ct);
2693 if(x != target->GetDependLibraries().end())
2695 std::vector<cmStdString> const& deplibs = x->second;
2696 for(std::vector<cmStdString>::const_iterator d = deplibs.begin();
2697 d != deplibs.end(); ++d)
2699 makefileStream << "\\\n\t" <<
2700 this->ConvertToRelativeForMake(d->c_str());
2703 // Write the action to remove the target if it is out of date.
2704 makefileStream << "\n";
2705 makefileStream << "\t/bin/rm -f "
2706 << this->ConvertToRelativeForMake(tfull.c_str())
2707 << "\n";
2708 // if building for more than one architecture
2709 // then remove those exectuables as well
2710 if(this->Architectures.size() > 1)
2712 std::string universal = t->GetDirectory();
2713 universal += "/";
2714 universal += this->CurrentProject;
2715 universal += ".build/";
2716 universal += configName;
2717 universal += "/";
2718 universal += t->GetFullName(configName);
2719 universal += ".build/Objects-normal/";
2720 for( std::vector<std::string>::iterator arch =
2721 this->Architectures.begin();
2722 arch != this->Architectures.end(); ++arch)
2724 std::string universalFile = universal;
2725 universalFile += *arch;
2726 universalFile += "/";
2727 universalFile += t->GetFullName(configName);
2728 makefileStream << "\t/bin/rm -f "
2730 this->ConvertToRelativeForMake(universalFile.c_str())
2731 << "\n";
2734 makefileStream << "\n\n";
2740 //----------------------------------------------------------------------------
2741 void
2742 cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
2743 std::vector<cmLocalGenerator*>&
2744 generators)
2746 if(generators.size() == 0)
2748 return;
2750 // Skip local generators that are excluded from this project.
2751 for(std::vector<cmLocalGenerator*>::iterator g = generators.begin();
2752 g != generators.end(); ++g)
2754 if(this->IsExcluded(root, *g))
2756 continue;
2760 this->CreateXCodeObjects(root,
2761 generators);
2762 std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
2763 xcodeDir += "/";
2764 xcodeDir += root->GetMakefile()->GetProjectName();
2765 xcodeDir += ".xcode";
2766 if(this->XcodeVersion > 20)
2768 xcodeDir += "proj";
2770 cmSystemTools::MakeDirectory(xcodeDir.c_str());
2771 std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
2772 cmGeneratedFileStream fout(xcodeProjFile.c_str());
2773 fout.SetCopyIfDifferent(true);
2774 if(!fout)
2776 return;
2778 this->WriteXCodePBXProj(fout, root, generators);
2779 this->ClearXCodeObjects();
2782 //----------------------------------------------------------------------------
2783 void
2784 cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
2785 cmLocalGenerator* ,
2786 std::vector<cmLocalGenerator*>& )
2788 fout << "// !$*UTF8*$!\n";
2789 fout << "{\n";
2790 cmXCodeObject::Indent(1, fout);
2791 fout << "archiveVersion = 1;\n";
2792 cmXCodeObject::Indent(1, fout);
2793 fout << "classes = {\n";
2794 cmXCodeObject::Indent(1, fout);
2795 fout << "};\n";
2796 cmXCodeObject::Indent(1, fout);
2797 fout << "objectVersion = 39;\n";
2798 cmXCodeObject::PrintList(this->XCodeObjects, fout);
2799 cmXCodeObject::Indent(1, fout);
2800 fout << "rootObject = " << this->RootObject->GetId() << ";\n";
2801 fout << "}\n";
2804 //----------------------------------------------------------------------------
2805 void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
2806 const
2808 entry.Name = this->GetName();
2809 entry.Brief = "Generate XCode project files.";
2810 entry.Full = "";
2813 //----------------------------------------------------------------------------
2814 std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(const char* p)
2816 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
2818 return cmSystemTools::ConvertToOutputPath(p);
2820 else
2822 std::string ret =
2823 this->CurrentLocalGenerator->
2824 ConvertToRelativePath(this->CurrentOutputDirectoryComponents, p);
2825 return cmSystemTools::ConvertToOutputPath(ret.c_str());
2829 //----------------------------------------------------------------------------
2830 std::string cmGlobalXCodeGenerator::ConvertToRelativeForXCode(const char* p)
2832 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
2834 return cmSystemTools::ConvertToOutputPath(p);
2836 else
2838 std::string ret =
2839 this->CurrentLocalGenerator->
2840 ConvertToRelativePath(this->ProjectOutputDirectoryComponents, p);
2841 return cmSystemTools::ConvertToOutputPath(ret.c_str());
2845 //----------------------------------------------------------------------------
2846 std::string cmGlobalXCodeGenerator::XCodeEscapePath(const char* p)
2848 std::string ret = p;
2849 if(ret.find(' ') != ret.npos)
2851 std::string t = ret;
2852 ret = "\"";
2853 ret += t;
2854 ret += "\"";
2856 return ret;
2859 //----------------------------------------------------------------------------
2860 void cmGlobalXCodeGenerator::
2861 GetTargetObjectFileDirectories(cmTarget* target,
2862 std::vector<std::string>&
2863 dirs)
2865 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
2866 dir += "/";
2867 dir += this->CurrentMakefile->GetProjectName();
2868 dir += ".build/";
2869 dir += this->GetCMakeCFGInitDirectory();
2870 dir += "/";
2871 if(target->GetType() != cmTarget::EXECUTABLE)
2873 dir += "lib";
2875 dir += target->GetName();
2876 if(target->GetType() == cmTarget::STATIC_LIBRARY)
2878 dir += ".a";
2880 if(target->GetType() == cmTarget::SHARED_LIBRARY)
2882 dir += ".dylib";
2884 if(target->GetType() == cmTarget::MODULE_LIBRARY)
2886 dir += ".so";
2888 dir += ".build/Objects-normal/";
2889 std::string dirsave = dir;
2890 if(this->Architectures.size())
2892 for(std::vector<std::string>::iterator i = this->Architectures.begin();
2893 i != this->Architectures.end(); ++i)
2895 dir += *i;
2896 dirs.push_back(dir);
2897 dir = dirsave;
2900 else
2902 dirs.push_back(dir);
2906 //----------------------------------------------------------------------------
2907 void
2908 cmGlobalXCodeGenerator
2909 ::AppendDirectoryForConfig(const char* prefix,
2910 const char* config,
2911 const char* suffix,
2912 std::string& dir)
2914 if(this->XcodeVersion > 20)
2916 if(config)
2918 dir += prefix;
2919 dir += config;
2920 dir += suffix;
2925 //----------------------------------------------------------------------------
2926 std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix,
2927 const char* varNameLang,
2928 const char* varNameSuffix,
2929 const char* default_flags)
2931 if(varNameLang)
2933 std::string varName = varNamePrefix;
2934 varName += varNameLang;
2935 varName += varNameSuffix;
2936 if(const char* varValue =
2937 this->CurrentMakefile->GetDefinition(varName.c_str()))
2939 if(*varValue)
2941 return varValue;
2945 return default_flags;
2948 //----------------------------------------------------------------------------
2949 void cmGlobalXCodeGenerator::AppendDefines(std::string& defs,
2950 const char* defines_list,
2951 bool dflag)
2953 // Skip this if there are no definitions.
2954 if(!defines_list)
2956 return;
2959 // Expand the list of definitions.
2960 std::vector<std::string> defines;
2961 cmSystemTools::ExpandListArgument(defines_list, defines);
2963 // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
2964 // We escape everything as follows:
2965 // - Place each definition in single quotes ''
2966 // - Escape a single quote as \\'
2967 // - Escape a backslash as \\\\ since it itself is an escape
2968 // Note that in the code below we need one more level of escapes for
2969 // C string syntax in this source file.
2970 const char* sep = defs.empty()? "" : " ";
2971 for(std::vector<std::string>::const_iterator di = defines.begin();
2972 di != defines.end(); ++di)
2974 // Separate from previous definition.
2975 defs += sep;
2976 sep = " ";
2978 // Open single quote.
2979 defs += "'";
2981 // Add -D flag if requested.
2982 if(dflag)
2984 defs += "-D";
2987 // Escaped definition string.
2988 for(const char* c = di->c_str(); *c; ++c)
2990 if(*c == '\'')
2992 defs += "\\\\'";
2994 else if(*c == '\\')
2996 defs += "\\\\\\\\";
2998 else
3000 defs += *c;
3004 // Close single quote.
3005 defs += "'";
3009 //----------------------------------------------------------------------------
3010 std::string
3011 cmGlobalXCodeGenerator::ComputeInfoPListLocation(cmTarget& target)
3013 std::string plist = target.GetMakefile()->GetCurrentOutputDirectory();
3014 plist += cmake::GetCMakeFilesDirectory();
3015 plist += "/";
3016 plist += target.GetName();
3017 plist += ".dir/Info.plist";
3018 return plist;