Rescan dependencies also if CMakeDirectoryInformation.cmake has changed.
[cmake.git] / Source / cmGlobalXCodeGenerator.cxx
blob4f0c763999b39c5a8416bb2e788baa95551acde2
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalXCodeGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-09-21 17:18:45 $
7 Version: $Revision: 1.229 $
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 "cmLocalXCodeGenerator.h"
19 #include "cmMakefile.h"
20 #include "cmXCodeObject.h"
21 #include "cmXCode21Object.h"
22 #include "cmake.h"
23 #include "cmGeneratedFileStream.h"
24 #include "cmComputeLinkInformation.h"
25 #include "cmSourceFile.h"
27 #include <cmsys/auto_ptr.hxx>
29 //----------------------------------------------------------------------------
30 #if defined(CMAKE_BUILD_WITH_CMAKE)
31 #include "cmXMLParser.h"
33 // parse the xml file storing the installed version of Xcode on
34 // the machine
35 class cmXcodeVersionParser : public cmXMLParser
37 public:
38 void StartElement(const char* , const char** )
40 this->Data = "";
42 void EndElement(const char* name)
44 if(strcmp(name, "key") == 0)
46 this->Key = this->Data;
48 else if(strcmp(name, "string") == 0)
50 if(this->Key == "CFBundleShortVersionString")
52 this->Version = (int)(10.0 * atof(this->Data.c_str()));
56 void CharacterDataHandler(const char* data, int length)
58 this->Data.append(data, length);
60 int Version;
61 std::string Key;
62 std::string Data;
64 #endif
66 // Builds either an object list or a space-separated string from the
67 // given inputs.
68 class cmGlobalXCodeGenerator::BuildObjectListOrString
70 cmGlobalXCodeGenerator *Generator;
71 cmXCodeObject *Group;
72 bool Empty;
73 std::string String;
75 public:
76 BuildObjectListOrString(cmGlobalXCodeGenerator *gen, bool buildObjectList)
77 : Generator(gen), Group(0), Empty(true)
79 if (buildObjectList)
81 this->Group = this->Generator->CreateObject(cmXCodeObject::OBJECT_LIST);
85 bool IsEmpty() const { return this->Empty; }
87 void Add(const char *newString)
89 this->Empty = false;
91 if (this->Group)
93 this->Group->AddObject(this->Generator->CreateString(newString));
95 else
97 this->String += newString;
98 this->String += ' ';
102 const std::string &GetString() const { return this->String; }
104 cmXCodeObject *CreateList()
106 if (this->Group)
108 return this->Group;
110 else
112 return this->Generator->CreateString(this->String.c_str());
117 //----------------------------------------------------------------------------
118 cmGlobalXCodeGenerator::cmGlobalXCodeGenerator()
120 this->FindMakeProgramFile = "CMakeFindXCode.cmake";
121 this->RootObject = 0;
122 this->MainGroupChildren = 0;
123 this->SourcesGroupChildren = 0;
124 this->ResourcesGroupChildren = 0;
125 this->CurrentMakefile = 0;
126 this->CurrentLocalGenerator = 0;
127 this->XcodeVersion = 15;
130 //----------------------------------------------------------------------------
131 cmGlobalGenerator* cmGlobalXCodeGenerator::New()
133 #if defined(CMAKE_BUILD_WITH_CMAKE)
134 cmXcodeVersionParser parser;
135 parser.ParseFile
136 ("/Developer/Applications/Xcode.app/Contents/version.plist");
137 cmsys::auto_ptr<cmGlobalXCodeGenerator> gg(new cmGlobalXCodeGenerator);
138 if (parser.Version == 20)
140 cmSystemTools::Message("Xcode 2.0 not really supported by cmake, "
141 "using Xcode 15 generator\n");
143 gg->SetVersion(parser.Version);
144 return gg.release();
145 #else
146 std::cerr << "CMake should be built with cmake to use XCode, "
147 "default to Xcode 1.5\n";
148 return new cmGlobalXCodeGenerator;
149 #endif
152 //----------------------------------------------------------------------------
153 void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const&
154 lang,
155 cmMakefile * mf, bool optional)
157 mf->AddDefinition("XCODE","1");
158 if(this->XcodeVersion == 15)
161 else
163 mf->AddCacheDefinition(
164 "CMAKE_CONFIGURATION_TYPES",
165 "Debug;Release;MinSizeRel;RelWithDebInfo",
166 "Semicolon separated list of supported configuration types, "
167 "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
168 "anything else will be ignored.",
169 cmCacheManager::STRING);
171 mf->AddDefinition("CMAKE_GENERATOR_CC", "gcc");
172 mf->AddDefinition("CMAKE_GENERATOR_CXX", "g++");
173 mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
174 // initialize Architectures so it can be used by
175 // GetTargetObjectFileDirectories
176 this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
177 const char* osxArch =
178 mf->GetDefinition("CMAKE_OSX_ARCHITECTURES");
179 const char* sysroot =
180 mf->GetDefinition("CMAKE_OSX_SYSROOT");
181 if(osxArch && sysroot)
183 this->Architectures.clear();
184 cmSystemTools::ExpandListArgument(std::string(osxArch),
185 this->Architectures);
189 //----------------------------------------------------------------------------
190 std::string cmGlobalXCodeGenerator
191 ::GenerateBuildCommand(const char* makeProgram,
192 const char *projectName,
193 const char* additionalOptions,
194 const char *targetName,
195 const char* config,
196 bool ignoreErrors,
197 bool)
199 // Config is not used yet
200 (void) ignoreErrors;
202 // now build the test
203 if(makeProgram == 0 || !strlen(makeProgram))
205 cmSystemTools::Error(
206 "Generator cannot find the appropriate make command.");
207 return "";
209 std::string makeCommand =
210 cmSystemTools::ConvertToOutputPath(makeProgram);
211 std::string lowerCaseCommand = makeCommand;
212 cmSystemTools::LowerCase(lowerCaseCommand);
214 makeCommand += " -project ";
215 makeCommand += projectName;
216 makeCommand += ".xcode";
217 if(this->XcodeVersion > 20)
219 makeCommand += "proj";
222 bool clean = false;
223 if ( targetName && strcmp(targetName, "clean") == 0 )
225 clean = true;
226 targetName = "ALL_BUILD";
228 if(clean)
230 makeCommand += " clean";
232 else
234 makeCommand += " build";
236 makeCommand += " -target ";
237 // if it is a null string for config don't use it
238 if(config && *config == 0)
240 config = 0;
242 if (targetName && strlen(targetName))
244 makeCommand += targetName;
246 else
248 makeCommand += "ALL_BUILD";
250 if(this->XcodeVersion == 15)
252 makeCommand += " -buildstyle Development ";
254 else
256 makeCommand += " -configuration ";
257 makeCommand += config?config:"Debug";
259 if ( additionalOptions )
261 makeCommand += " ";
262 makeCommand += additionalOptions;
264 return makeCommand;
267 //----------------------------------------------------------------------------
268 ///! Create a local generator appropriate to this Global Generator
269 cmLocalGenerator *cmGlobalXCodeGenerator::CreateLocalGenerator()
271 cmLocalGenerator *lg = new cmLocalXCodeGenerator;
272 lg->SetGlobalGenerator(this);
273 return lg;
276 //----------------------------------------------------------------------------
277 void cmGlobalXCodeGenerator::Generate()
279 std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
280 // make sure extra targets are added before calling
281 // the parent generate which will call trace depends
282 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
284 cmLocalGenerator* root = it->second[0];
285 this->SetGenerationRoot(root);
286 // add ALL_BUILD, INSTALL, etc
287 this->AddExtraTargets(root, it->second);
289 this->ForceLinkerLanguages();
290 this->cmGlobalGenerator::Generate();
291 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
293 cmLocalGenerator* root = it->second[0];
294 this->SetGenerationRoot(root);
295 // now create the project
296 this->OutputXCodeProject(root, it->second);
300 //----------------------------------------------------------------------------
301 void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
303 this->CurrentProject = root->GetMakefile()->GetProjectName();
304 this->SetCurrentLocalGenerator(root);
305 std::string outDir = this->CurrentMakefile->GetHomeOutputDirectory();
306 outDir =cmSystemTools::CollapseFullPath(outDir.c_str());
307 cmSystemTools::SplitPath(outDir.c_str(),
308 this->ProjectOutputDirectoryComponents);
310 this->CurrentXCodeHackMakefile =
311 root->GetMakefile()->GetCurrentOutputDirectory();
312 this->CurrentXCodeHackMakefile += "/CMakeScripts";
313 cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile.c_str());
314 this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
317 //----------------------------------------------------------------------------
318 void
319 cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
320 std::vector<cmLocalGenerator*>& gens)
322 cmMakefile* mf = root->GetMakefile();
324 // Add ALL_BUILD
325 const char* no_working_directory = 0;
326 std::vector<std::string> no_depends;
327 mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
328 no_working_directory,
329 "echo", "Build all projects");
330 cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
332 // Refer to the main build configuration file for easy editing.
333 std::string listfile = mf->GetStartDirectory();
334 listfile += "/";
335 listfile += "CMakeLists.txt";
336 allbuild->AddSource(listfile.c_str());
338 // Add XCODE depend helper
339 std::string dir = mf->GetCurrentOutputDirectory();
340 cmCustomCommandLine makecommand;
341 makecommand.push_back("make");
342 makecommand.push_back("-C");
343 makecommand.push_back(dir.c_str());
344 makecommand.push_back("-f");
345 makecommand.push_back(this->CurrentXCodeHackMakefile.c_str());
346 if(this->XcodeVersion > 20)
348 makecommand.push_back("all.$(CONFIGURATION)");
350 cmCustomCommandLines commandLines;
351 commandLines.push_back(makecommand);
352 // Add Re-Run CMake rules
353 this->CreateReRunCMakeFile(root);
355 // now make the allbuild depend on all the non-utility targets
356 // in the project
357 for(std::vector<cmLocalGenerator*>::iterator i = gens.begin();
358 i != gens.end(); ++i)
360 cmLocalGenerator* lg = *i;
361 if(this->IsExcluded(root, *i))
363 continue;
365 cmTargets& tgts = lg->GetMakefile()->GetTargets();
366 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
368 cmTarget& target = l->second;
369 // make all exe, shared libs and modules
370 // run the depend check makefile as a post build rule
371 // this will make sure that when the next target is built
372 // things are up-to-date
373 if((target.GetType() == cmTarget::EXECUTABLE ||
374 target.GetType() == cmTarget::STATIC_LIBRARY ||
375 target.GetType() == cmTarget::SHARED_LIBRARY ||
376 target.GetType() == cmTarget::MODULE_LIBRARY))
378 lg->GetMakefile()->AddCustomCommandToTarget(target.GetName(),
379 no_depends,
380 commandLines,
381 cmTarget::POST_BUILD,
382 "Depend check for xcode",
383 dir.c_str());
386 if(!target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
388 allbuild->AddUtility(target.GetName());
391 // Refer to the build configuration file for easy editing.
392 listfile = lg->GetMakefile()->GetStartDirectory();
393 listfile += "/";
394 listfile += "CMakeLists.txt";
395 target.AddSource(listfile.c_str());
400 //----------------------------------------------------------------------------
401 void cmGlobalXCodeGenerator::CreateReRunCMakeFile(cmLocalGenerator* root)
403 cmMakefile* mf = root->GetMakefile();
404 std::vector<std::string> lfiles = mf->GetListFiles();
405 // sort the array
406 std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
407 std::vector<std::string>::iterator new_end =
408 std::unique(lfiles.begin(), lfiles.end());
409 lfiles.erase(new_end, lfiles.end());
410 std::string dir = mf->GetHomeOutputDirectory();
411 this->CurrentReRunCMakeMakefile = dir;
412 this->CurrentReRunCMakeMakefile += "/CMakeScripts";
413 cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
414 this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
415 cmGeneratedFileStream makefileStream
416 (this->CurrentReRunCMakeMakefile.c_str());
417 makefileStream.SetCopyIfDifferent(true);
418 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
419 makefileStream << cmake::GetCMakeFilesDirectoryPostSlash();
420 makefileStream << "cmake.check_cache: ";
421 for(std::vector<std::string>::const_iterator i = lfiles.begin();
422 i != lfiles.end(); ++i)
424 makefileStream << "\\\n" << this->ConvertToRelativeForMake(i->c_str());
426 std::string cmake = mf->GetRequiredDefinition("CMAKE_COMMAND");
427 makefileStream << "\n\t" << this->ConvertToRelativeForMake(cmake.c_str())
428 << " -H" << this->ConvertToRelativeForMake(
429 mf->GetHomeDirectory())
430 << " -B" << this->ConvertToRelativeForMake(
431 mf->GetHomeOutputDirectory()) << "\n";
434 //----------------------------------------------------------------------------
435 void cmGlobalXCodeGenerator::ClearXCodeObjects()
437 this->TargetDoneSet.clear();
438 for(unsigned int i = 0; i < this->XCodeObjects.size(); ++i)
440 delete this->XCodeObjects[i];
442 this->XCodeObjects.clear();
443 this->GroupMap.clear();
444 this->GroupNameMap.clear();
445 this->TargetGroup.clear();
446 this->FileRefs.clear();
449 //----------------------------------------------------------------------------
450 cmXCodeObject*
451 cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype)
453 cmXCodeObject* obj;
454 if(this->XcodeVersion == 15)
456 obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
458 else
460 obj = new cmXCode21Object(ptype, cmXCodeObject::OBJECT);
462 this->XCodeObjects.push_back(obj);
463 return obj;
466 //----------------------------------------------------------------------------
467 cmXCodeObject*
468 cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
470 cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
471 this->XCodeObjects.push_back(obj);
472 return obj;
475 //----------------------------------------------------------------------------
476 cmXCodeObject*
477 cmGlobalXCodeGenerator::CreateString(const char* s)
479 cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
480 obj->SetString(s);
481 return obj;
484 //----------------------------------------------------------------------------
485 cmXCodeObject* cmGlobalXCodeGenerator
486 ::CreateObjectReference(cmXCodeObject* ref)
488 cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
489 obj->SetObject(ref);
490 return obj;
493 //----------------------------------------------------------------------------
494 cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
496 cmStdString key(cmtarget.GetName());
497 key += "-";
498 key += sf->GetFullPath();
499 return key;
502 //----------------------------------------------------------------------------
503 cmXCodeObject*
504 cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
505 cmSourceFile* sf,
506 cmTarget& cmtarget)
508 // Add flags from target and source file properties.
509 std::string flags;
510 if(cmtarget.GetProperty("COMPILE_FLAGS"))
512 lg->AppendFlags(flags, cmtarget.GetProperty("COMPILE_FLAGS"));
514 lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
516 // Add per-source definitions.
517 BuildObjectListOrString flagsBuild(this, false);
518 this->AppendDefines(flagsBuild,
519 sf->GetProperty("COMPILE_DEFINITIONS"), true);
520 if (!flagsBuild.IsEmpty())
522 if (flags.size())
524 flags += ' ';
526 flags += flagsBuild.GetString();
529 // Using a map and the full path guarantees that we will always get the same
530 // fileRef object for any given full path.
532 cmXCodeObject* fileRef = this->CreateXCodeFileReference(sf, cmtarget);
534 cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
535 buildFile->SetComment(fileRef->GetComment());
536 buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
538 cmXCodeObject* settings =
539 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
540 settings->AddAttribute("COMPILER_FLAGS", this->CreateString(flags.c_str()));
542 // Is this a resource file in this target? Add it to the resources group...
544 cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf);
545 bool isResource = (tsFlags.Type == cmTarget::SourceFileTypeResource);
547 // Is this a "private" or "public" framework header file?
548 // Set the ATTRIBUTES attribute appropriately...
550 if(cmtarget.IsFrameworkOnApple())
552 if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader)
554 cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
555 attrs->AddObject(this->CreateString("Private"));
556 settings->AddAttribute("ATTRIBUTES", attrs);
557 isResource = true;
559 else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader)
561 cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
562 attrs->AddObject(this->CreateString("Public"));
563 settings->AddAttribute("ATTRIBUTES", attrs);
564 isResource = true;
568 // Add the fileRef to the top level Resources group/folder if it is not
569 // already there.
571 if(isResource && this->ResourcesGroupChildren &&
572 !this->ResourcesGroupChildren->HasObject(fileRef))
574 this->ResourcesGroupChildren->AddObject(fileRef);
577 buildFile->AddAttribute("settings", settings);
578 return buildFile;
581 //----------------------------------------------------------------------------
582 cmXCodeObject*
583 cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
584 cmTarget& cmtarget)
586 std::string fname = sf->GetFullPath();
587 cmXCodeObject* fileRef = this->FileRefs[fname];
588 if(!fileRef)
590 fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
591 std::string comment = fname;
592 //comment += " in ";
593 //std::string gname = group->GetObject("name")->GetString();
594 //comment += gname.substr(1, gname.size()-2);
595 fileRef->SetComment(fname.c_str());
596 this->FileRefs[fname] = fileRef;
598 cmStdString key = GetGroupMapKey(cmtarget, sf);
599 cmXCodeObject* group = this->GroupMap[key];
600 cmXCodeObject* children = group->GetObject("children");
601 if (!children->HasObject(fileRef))
603 children->AddObject(fileRef);
605 fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
607 const char* lang =
608 this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
609 std::string sourcecode = "sourcecode";
610 std::string ext = sf->GetExtension();
611 ext = cmSystemTools::LowerCase(ext);
613 if(ext == "o")
615 sourcecode = "compiled.mach-o.objfile";
617 else if(ext == "xib")
619 sourcecode = "file.xib";
621 else if(ext == "mm")
623 sourcecode += ".cpp.objcpp";
625 else if(ext == "m")
627 sourcecode += ".c.objc";
629 else if(ext == "xib")
631 sourcecode += ".file.xib";
633 else if(ext == "plist")
635 sourcecode += ".text.plist";
637 else if(ext == "h")
639 sourcecode += ".c.h";
641 else if(ext == "hxx" || ext == "hpp" || ext == "txx"
642 || ext == "pch")
644 sourcecode += ".cpp.h";
646 else if(lang && strcmp(lang, "CXX") == 0)
648 sourcecode += ".cpp.cpp";
650 else if(lang && strcmp(lang, "C") == 0)
652 sourcecode += ".c.c";
654 else if(ext == "png" || ext == "gif" || ext == "jpg")
656 sourcecode = "image";
658 else if(ext == "txt")
660 sourcecode += ".text";
662 //else
663 // {
664 // // Already specialized above or we leave sourcecode == "sourcecode"
665 // // which is probably the most correct choice. Extensionless headers,
666 // // for example... Or file types unknown to Xcode that do not map to a
667 // // valid lastKnownFileType value.
668 // }
670 fileRef->AddAttribute("lastKnownFileType",
671 this->CreateString(sourcecode.c_str()));
673 std::string path =
674 this->ConvertToRelativeForXCode(sf->GetFullPath().c_str());
675 std::string dir;
676 std::string file;
677 cmSystemTools::SplitProgramPath(sf->GetFullPath().c_str(),
678 dir, file);
680 // Try to make the path relative to the project root.
681 bool Absolute = true;
682 if (this->XcodeVersion >= 30)
684 std::string relative =
685 this->CurrentLocalGenerator->Convert(sf->GetFullPath().c_str(),
686 cmLocalGenerator::HOME,
687 cmLocalGenerator::MAKEFILE,
688 false);
689 relative = cmSystemTools::ConvertToOutputPath(relative.c_str());
690 if (!relative.empty() && relative[0] != '/')
692 Absolute = false;
693 path = relative;
697 fileRef->AddAttribute("name", this->CreateString(file.c_str()));
698 fileRef->AddAttribute("path", this->CreateString(path.c_str()));
699 if(this->XcodeVersion == 15)
701 fileRef->AddAttribute("refType", this->CreateString("4"));
703 if(path.size() > 1 && path[0] == '.' && path[1] == '.')
705 fileRef->AddAttribute("sourceTree", this->CreateString("<group>"));
707 else if (Absolute)
709 fileRef->AddAttribute("sourceTree", this->CreateString("<absolute>"));
711 else
713 fileRef->AddAttribute("sourceTree", this->CreateString("SOURCE_ROOT"));
716 return fileRef;
719 //----------------------------------------------------------------------------
720 bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
722 if(tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
723 tname == "install" || tname == "package" || tname == "RUN_TESTS" )
725 if(this->TargetDoneSet.find(tname) != this->TargetDoneSet.end())
727 return true;
729 this->TargetDoneSet.insert(tname);
730 return false;
732 return false;
735 //----------------------------------------------------------------------------
736 void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
738 this->CurrentLocalGenerator = gen;
739 this->CurrentMakefile = gen->GetMakefile();
740 std::string outdir =
741 cmSystemTools::CollapseFullPath(this->CurrentMakefile->
742 GetCurrentOutputDirectory());
743 cmSystemTools::SplitPath(outdir.c_str(),
744 this->CurrentOutputDirectoryComponents);
746 // Select the current set of configuration types.
747 this->CurrentConfigurationTypes.clear();
748 if(this->XcodeVersion > 20)
750 if(const char* types =
751 this->CurrentMakefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
753 cmSystemTools::ExpandListArgument(types,
754 this->CurrentConfigurationTypes);
757 if(this->CurrentConfigurationTypes.empty())
759 if(const char* buildType =
760 this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE"))
762 this->CurrentConfigurationTypes.push_back(buildType);
764 else
766 this->CurrentConfigurationTypes.push_back("");
771 //----------------------------------------------------------------------------
772 void
773 cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
774 std::vector<cmXCodeObject*>&
775 targets)
777 this->SetCurrentLocalGenerator(gen);
778 cmTargets &tgts = this->CurrentMakefile->GetTargets();
779 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
781 cmTarget& cmtarget = l->second;
783 // make sure ALL_BUILD, INSTALL, etc are only done once
784 if(this->SpecialTargetEmitted(l->first.c_str()))
786 continue;
789 if(cmtarget.GetType() == cmTarget::UTILITY ||
790 cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
792 targets.push_back(this->CreateUtilityTarget(cmtarget));
793 continue;
796 // organize the sources
797 std::vector<cmSourceFile*> const &classes = cmtarget.GetSourceFiles();
798 std::vector<cmXCodeObject*> externalObjFiles;
799 std::vector<cmXCodeObject*> headerFiles;
800 std::vector<cmXCodeObject*> resourceFiles;
801 std::vector<cmXCodeObject*> sourceFiles;
802 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
803 i != classes.end(); ++i)
805 cmXCodeObject* xsf =
806 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
807 *i, cmtarget);
808 cmXCodeObject* fr = xsf->GetObject("fileRef");
809 cmXCodeObject* filetype =
810 fr->GetObject()->GetObject("lastKnownFileType");
812 cmTarget::SourceFileFlags tsFlags =
813 cmtarget.GetTargetSourceFileFlags(*i);
815 if(strcmp(filetype->GetString(), "compiled.mach-o.objfile") == 0)
817 externalObjFiles.push_back(xsf);
819 else if(this->IsHeaderFile(*i) ||
820 (tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) ||
821 (tsFlags.Type == cmTarget::SourceFileTypePublicHeader))
823 headerFiles.push_back(xsf);
825 else if(tsFlags.Type == cmTarget::SourceFileTypeResource)
827 resourceFiles.push_back(xsf);
829 else if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY"))
831 // Include this file in the build if it has a known language
832 // and has not been listed as an ignored extension for this
833 // generator.
834 if(this->CurrentLocalGenerator->GetSourceFileLanguage(**i) &&
835 !this->IgnoreFile((*i)->GetExtension().c_str()))
837 sourceFiles.push_back(xsf);
842 // some build phases only apply to bundles and/or frameworks
843 bool isFrameworkTarget = cmtarget.IsFrameworkOnApple();
844 bool isBundleTarget = cmtarget.GetPropertyAsBool("MACOSX_BUNDLE");
846 cmXCodeObject* buildFiles = 0;
848 // create source build phase
849 cmXCodeObject* sourceBuildPhase = 0;
850 if (!sourceFiles.empty())
852 sourceBuildPhase =
853 this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
854 sourceBuildPhase->SetComment("Sources");
855 sourceBuildPhase->AddAttribute("buildActionMask",
856 this->CreateString("2147483647"));
857 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
858 for(std::vector<cmXCodeObject*>::iterator i = sourceFiles.begin();
859 i != sourceFiles.end(); ++i)
861 buildFiles->AddObject(*i);
863 sourceBuildPhase->AddAttribute("files", buildFiles);
864 sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
865 this->CreateString("0"));
868 // create header build phase - only for framework targets
869 cmXCodeObject* headerBuildPhase = 0;
870 if (!headerFiles.empty() && isFrameworkTarget)
872 headerBuildPhase =
873 this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
874 headerBuildPhase->SetComment("Headers");
875 headerBuildPhase->AddAttribute("buildActionMask",
876 this->CreateString("2147483647"));
877 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
878 for(std::vector<cmXCodeObject*>::iterator i = headerFiles.begin();
879 i != headerFiles.end(); ++i)
881 buildFiles->AddObject(*i);
883 headerBuildPhase->AddAttribute("files", buildFiles);
884 headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
885 this->CreateString("0"));
888 // create resource build phase - only for framework or bundle targets
889 cmXCodeObject* resourceBuildPhase = 0;
890 if (!resourceFiles.empty() && (isFrameworkTarget || isBundleTarget))
892 resourceBuildPhase =
893 this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
894 resourceBuildPhase->SetComment("Resources");
895 resourceBuildPhase->AddAttribute("buildActionMask",
896 this->CreateString("2147483647"));
897 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
898 for(std::vector<cmXCodeObject*>::iterator i = resourceFiles.begin();
899 i != resourceFiles.end(); ++i)
901 buildFiles->AddObject(*i);
903 resourceBuildPhase->AddAttribute("files", buildFiles);
904 resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
905 this->CreateString("0"));
908 // create vector of "non-resource content file" build phases - only for
909 // framework or bundle targets
910 std::vector<cmXCodeObject*> contentBuildPhases;
911 if (isFrameworkTarget || isBundleTarget)
913 typedef std::map<cmStdString, std::vector<cmSourceFile*> >
914 mapOfVectorOfSourceFiles;
915 mapOfVectorOfSourceFiles bundleFiles;
916 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
917 i != classes.end(); ++i)
919 cmTarget::SourceFileFlags tsFlags =
920 cmtarget.GetTargetSourceFileFlags(*i);
921 if(tsFlags.Type == cmTarget::SourceFileTypeMacContent)
923 bundleFiles[tsFlags.MacFolder].push_back(*i);
926 mapOfVectorOfSourceFiles::iterator mit;
927 for ( mit = bundleFiles.begin(); mit != bundleFiles.end(); ++ mit )
929 cmXCodeObject* copyFilesBuildPhase =
930 this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
931 copyFilesBuildPhase->SetComment("Copy files");
932 copyFilesBuildPhase->AddAttribute("buildActionMask",
933 this->CreateString("2147483647"));
934 copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
935 this->CreateString("6"));
936 cmOStringStream ostr;
937 if (cmtarget.IsFrameworkOnApple())
939 // dstPath in frameworks is relative to Versions/<version>
940 ostr << mit->first;
942 else if ( mit->first != "MacOS" )
944 // dstPath in bundles is relative to Contents/MacOS
945 ostr << "../" << mit->first.c_str();
947 copyFilesBuildPhase->AddAttribute("dstPath",
948 this->CreateString(ostr.str().c_str()));
949 copyFilesBuildPhase->AddAttribute(
950 "runOnlyForDeploymentPostprocessing", this->CreateString("0"));
951 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
952 copyFilesBuildPhase->AddAttribute("files", buildFiles);
953 std::vector<cmSourceFile*>::iterator sfIt;
954 for ( sfIt = mit->second.begin(); sfIt != mit->second.end(); ++ sfIt )
956 cmXCodeObject* xsf =
957 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
958 *sfIt, cmtarget);
959 buildFiles->AddObject(xsf);
961 contentBuildPhases.push_back(copyFilesBuildPhase);
965 // create framework build phase
966 cmXCodeObject* frameworkBuildPhase = 0;
967 if (!externalObjFiles.empty())
969 frameworkBuildPhase =
970 this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
971 frameworkBuildPhase->SetComment("Frameworks");
972 frameworkBuildPhase->AddAttribute("buildActionMask",
973 this->CreateString("2147483647"));
974 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
975 frameworkBuildPhase->AddAttribute("files", buildFiles);
976 for(std::vector<cmXCodeObject*>::iterator i = externalObjFiles.begin();
977 i != externalObjFiles.end(); ++i)
979 buildFiles->AddObject(*i);
981 frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
982 this->CreateString("0"));
985 // create list of build phases and create the XCode target
986 cmXCodeObject* buildPhases =
987 this->CreateObject(cmXCodeObject::OBJECT_LIST);
989 this->CreateCustomCommands(buildPhases, sourceBuildPhase,
990 headerBuildPhase, resourceBuildPhase,
991 contentBuildPhases,
992 frameworkBuildPhase, cmtarget);
994 targets.push_back(this->CreateXCodeTarget(cmtarget, buildPhases));
998 //----------------------------------------------------------------------------
999 void cmGlobalXCodeGenerator::ForceLinkerLanguages()
1001 // This makes sure all targets link using the proper language.
1002 for(std::map<cmStdString, cmTarget*>::const_iterator
1003 ti = this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti)
1005 this->ForceLinkerLanguage(*ti->second);
1009 //----------------------------------------------------------------------------
1010 void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget)
1012 // This matters only for targets that link.
1013 if(cmtarget.GetType() != cmTarget::EXECUTABLE &&
1014 cmtarget.GetType() != cmTarget::SHARED_LIBRARY &&
1015 cmtarget.GetType() != cmTarget::MODULE_LIBRARY)
1017 return;
1020 const char* llang = cmtarget.GetLinkerLanguage("NOCONFIG");
1021 if(!llang) { return; }
1023 // If the language is compiled as a source trust Xcode to link with it.
1024 cmTarget::LinkImplementation const* impl =
1025 cmtarget.GetLinkImplementation("NOCONFIG");
1026 for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
1027 li != impl->Languages.end(); ++li)
1029 if(*li == llang) { return; }
1032 // Add an empty source file to the target that compiles with the
1033 // linker language. This should convince Xcode to choose the proper
1034 // language.
1035 cmMakefile* mf = cmtarget.GetMakefile();
1036 std::string fname = mf->GetCurrentOutputDirectory();
1037 fname += cmake::GetCMakeFilesDirectory();
1038 fname += "/";
1039 fname += cmtarget.GetName();
1040 fname += "-CMakeForceLinker";
1041 fname += ".";
1042 fname += cmSystemTools::LowerCase(llang);
1044 cmGeneratedFileStream fout(fname.c_str());
1045 fout << "\n";
1047 if(cmSourceFile* sf = mf->GetOrCreateSource(fname.c_str()))
1049 sf->SetProperty("LANGUAGE", llang);
1050 cmtarget.AddSourceFile(sf);
1054 //----------------------------------------------------------------------------
1055 bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf)
1057 const std::vector<std::string>& hdrExts =
1058 this->CurrentMakefile->GetHeaderExtensions();
1059 return (std::find(hdrExts.begin(), hdrExts.end(), sf->GetExtension()) !=
1060 hdrExts.end());
1063 //----------------------------------------------------------------------------
1064 cmXCodeObject*
1065 cmGlobalXCodeGenerator::CreateBuildPhase(const char* name,
1066 const char* name2,
1067 cmTarget& cmtarget,
1068 const std::vector<cmCustomCommand>&
1069 commands)
1071 if(commands.size() == 0 && strcmp(name, "CMake ReRun") != 0)
1073 return 0;
1075 cmXCodeObject* buildPhase =
1076 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
1077 buildPhase->AddAttribute("buildActionMask",
1078 this->CreateString("2147483647"));
1079 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1080 buildPhase->AddAttribute("files", buildFiles);
1081 buildPhase->AddAttribute("name",
1082 this->CreateString(name));
1083 buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1084 this->CreateString("0"));
1085 buildPhase->AddAttribute("shellPath",
1086 this->CreateString("/bin/sh"));
1087 this->AddCommandsToBuildPhase(buildPhase, cmtarget, commands,
1088 name2);
1089 return buildPhase;
1092 //----------------------------------------------------------------------------
1093 void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases,
1094 cmXCodeObject*
1095 sourceBuildPhase,
1096 cmXCodeObject*
1097 headerBuildPhase,
1098 cmXCodeObject*
1099 resourceBuildPhase,
1100 std::vector<cmXCodeObject*>
1101 contentBuildPhases,
1102 cmXCodeObject*
1103 frameworkBuildPhase,
1104 cmTarget& cmtarget)
1106 std::vector<cmCustomCommand> const & prebuild
1107 = cmtarget.GetPreBuildCommands();
1108 std::vector<cmCustomCommand> const & prelink
1109 = cmtarget.GetPreLinkCommands();
1110 std::vector<cmCustomCommand> const & postbuild
1111 = cmtarget.GetPostBuildCommands();
1112 std::vector<cmSourceFile*>const &classes = cmtarget.GetSourceFiles();
1113 // add all the sources
1114 std::vector<cmCustomCommand> commands;
1115 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
1116 i != classes.end(); ++i)
1118 if((*i)->GetCustomCommand())
1120 commands.push_back(*(*i)->GetCustomCommand());
1123 std::vector<cmCustomCommand> reruncom;
1124 cmXCodeObject* cmakeReRunPhase =
1125 this->CreateBuildPhase("CMake ReRun", "cmakeReRunPhase",
1126 cmtarget, reruncom);
1127 buildPhases->AddObject(cmakeReRunPhase);
1128 // create prebuild phase
1129 cmXCodeObject* cmakeRulesBuildPhase =
1130 this->CreateBuildPhase("CMake Rules",
1131 "cmakeRulesBuildPhase",
1132 cmtarget, commands);
1133 // create prebuild phase
1134 cmXCodeObject* preBuildPhase =
1135 this->CreateBuildPhase("CMake PreBuild Rules", "preBuildCommands",
1136 cmtarget, prebuild);
1137 // create prelink phase
1138 cmXCodeObject* preLinkPhase =
1139 this->CreateBuildPhase("CMake PreLink Rules", "preLinkCommands",
1140 cmtarget, prelink);
1141 // create postbuild phase
1142 cmXCodeObject* postBuildPhase =
1143 this->CreateBuildPhase("CMake PostBuild Rules", "postBuildPhase",
1144 cmtarget, postbuild);
1146 // The order here is the order they will be built in.
1147 // The order "headers, resources, sources" mimics a native project generated
1148 // from an xcode template...
1150 if(preBuildPhase)
1152 buildPhases->AddObject(preBuildPhase);
1154 if(cmakeRulesBuildPhase)
1156 buildPhases->AddObject(cmakeRulesBuildPhase);
1158 if(headerBuildPhase)
1160 buildPhases->AddObject(headerBuildPhase);
1162 if(resourceBuildPhase)
1164 buildPhases->AddObject(resourceBuildPhase);
1166 std::vector<cmXCodeObject*>::iterator cit;
1167 for (cit = contentBuildPhases.begin(); cit != contentBuildPhases.end();
1168 ++cit)
1170 buildPhases->AddObject(*cit);
1172 if(sourceBuildPhase)
1174 buildPhases->AddObject(sourceBuildPhase);
1176 if(preLinkPhase)
1178 buildPhases->AddObject(preLinkPhase);
1180 if(frameworkBuildPhase)
1182 buildPhases->AddObject(frameworkBuildPhase);
1184 if(postBuildPhase)
1186 buildPhases->AddObject(postBuildPhase);
1190 //----------------------------------------------------------------------------
1191 std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
1192 std::string& flags)
1194 std::string retFlag;
1195 std::string::size_type pos = flags.find(flag);
1196 if(pos != flags.npos && (pos ==0 || flags[pos-1]==' '))
1198 while(pos < flags.size() && flags[pos] != ' ')
1200 retFlag += flags[pos];
1201 flags[pos] = ' ';
1202 pos++;
1205 return retFlag;
1208 //----------------------------------------------------------------------------
1209 void
1210 cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
1211 cmTarget& target,
1212 std::vector<cmCustomCommand>
1213 const & commands,
1214 const char* name)
1216 if(strcmp(name, "cmakeReRunPhase") == 0)
1218 std::string cdir = this->CurrentMakefile->GetHomeOutputDirectory();
1219 cdir = this->ConvertToRelativeForMake(cdir.c_str());
1220 std::string makecmd = "make -C ";
1221 makecmd += cdir;
1222 makecmd += " -f ";
1223 makecmd +=
1224 this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str());
1225 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1226 buildphase->AddAttribute("shellScript",
1227 this->CreateString(makecmd.c_str()));
1228 return;
1231 // collect multiple outputs of custom commands into a set
1232 // which will be used for every configuration
1233 std::map<cmStdString, cmStdString> multipleOutputPairs;
1234 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1235 i != commands.end(); ++i)
1237 cmCustomCommand const& cc = *i;
1238 if(!cc.GetCommandLines().empty())
1240 const std::vector<std::string>& outputs = cc.GetOutputs();
1241 if(!outputs.empty())
1243 // If there are more than one outputs treat the
1244 // first as the primary output and make the rest depend on it.
1245 std::vector<std::string>::const_iterator o = outputs.begin();
1246 std::string primaryOutput = this->ConvertToRelativeForMake(o->c_str());
1247 for(++o; o != outputs.end(); ++o)
1249 std::string currentOutput=this->ConvertToRelativeForMake(o->c_str());
1250 multipleOutputPairs[currentOutput] = primaryOutput;
1256 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
1257 dir += "/CMakeScripts";
1258 cmSystemTools::MakeDirectory(dir.c_str());
1259 std::string makefile = dir;
1260 makefile += "/";
1261 makefile += target.GetName();
1262 makefile += "_";
1263 makefile += name;
1264 makefile += ".make";
1266 for (std::vector<std::string>::const_iterator currentConfig=
1267 this->CurrentConfigurationTypes.begin();
1268 currentConfig!=this->CurrentConfigurationTypes.end();
1269 currentConfig++ )
1271 this->CreateCustomRulesMakefile(makefile.c_str(),
1272 target,
1273 commands,
1274 currentConfig->c_str(),
1275 multipleOutputPairs);
1278 std::string cdir = this->CurrentMakefile->GetCurrentOutputDirectory();
1279 cdir = this->ConvertToRelativeForXCode(cdir.c_str());
1280 std::string makecmd = "make -C ";
1281 makecmd += cdir;
1282 makecmd += " -f ";
1283 makecmd += this->ConvertToRelativeForMake(
1284 (makefile+"$CONFIGURATION").c_str());
1285 if(!multipleOutputPairs.empty())
1287 makecmd += " cmake_check_multiple_outputs";
1289 makecmd += " all";
1290 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1291 buildphase->AddAttribute("shellScript",
1292 this->CreateString(makecmd.c_str()));
1295 //----------------------------------------------------------------------------
1296 void cmGlobalXCodeGenerator
1297 ::CreateCustomRulesMakefile(const char* makefileBasename,
1298 cmTarget& target,
1299 std::vector<cmCustomCommand>
1300 const & commands,
1301 const char* configName,
1302 const std::map<cmStdString,
1303 cmStdString>& multipleOutputPairs
1306 std::string makefileName=makefileBasename;
1307 makefileName+=configName;
1308 cmGeneratedFileStream makefileStream(makefileName.c_str());
1309 if(!makefileStream)
1311 return;
1313 makefileStream.SetCopyIfDifferent(true);
1314 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
1315 makefileStream << "# Custom rules for " << target.GetName() << "\n";
1317 // have all depend on all outputs
1318 makefileStream << "all: ";
1319 std::map<const cmCustomCommand*, cmStdString> tname;
1320 int count = 0;
1321 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1322 i != commands.end(); ++i)
1324 cmCustomCommand const& cc = *i;
1325 if(!cc.GetCommandLines().empty())
1327 const std::vector<std::string>& outputs = cc.GetOutputs();
1328 if(!outputs.empty())
1330 for(std::vector<std::string>::const_iterator o = outputs.begin();
1331 o != outputs.end(); ++o)
1333 makefileStream
1334 << "\\\n\t" << this->ConvertToRelativeForMake(o->c_str());
1337 else
1339 cmOStringStream str;
1340 str << "_buildpart_" << count++ ;
1341 tname[&cc] = std::string(target.GetName()) + str.str();
1342 makefileStream << "\\\n\t" << tname[&cc];
1346 makefileStream << "\n\n";
1347 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1348 i != commands.end(); ++i)
1350 cmCustomCommand const& cc = *i;
1351 if(!cc.GetCommandLines().empty())
1353 bool escapeOldStyle = cc.GetEscapeOldStyle();
1354 bool escapeAllowMakeVars = cc.GetEscapeAllowMakeVars();
1355 makefileStream << "\n";
1356 const std::vector<std::string>& outputs = cc.GetOutputs();
1357 if(!outputs.empty())
1359 // There is at least one output, start the rule for it
1360 std::string primary_output =
1361 this->ConvertToRelativeForMake(outputs.begin()->c_str());
1362 makefileStream << primary_output << ": ";
1364 else
1366 // There are no outputs. Use the generated force rule name.
1367 makefileStream << tname[&cc] << ": ";
1369 for(std::vector<std::string>::const_iterator d =
1370 cc.GetDepends().begin();
1371 d != cc.GetDepends().end(); ++d)
1373 std::string dep =
1374 this->CurrentLocalGenerator->GetRealDependency(d->c_str(),
1375 configName);
1376 makefileStream << "\\\n" << this
1377 ->ConvertToRelativeForMake(dep.c_str());
1379 makefileStream << "\n";
1381 if(const char* comment = cc.GetComment())
1383 std::string echo_cmd = "echo ";
1384 echo_cmd += (this->CurrentLocalGenerator->
1385 EscapeForShell(comment, escapeAllowMakeVars));
1386 makefileStream << "\t" << echo_cmd.c_str() << "\n";
1389 // Add each command line to the set of commands.
1390 for(cmCustomCommandLines::const_iterator cl =
1391 cc.GetCommandLines().begin();
1392 cl != cc.GetCommandLines().end(); ++cl)
1394 // Build the command line in a single string.
1395 const cmCustomCommandLine& commandLine = *cl;
1396 std::string cmd2 = this->CurrentLocalGenerator
1397 ->GetRealLocation(commandLine[0].c_str(), configName);
1399 cmSystemTools::ReplaceString(cmd2, "/./", "/");
1400 cmd2 = this->ConvertToRelativeForMake(cmd2.c_str());
1401 std::string cmd;
1402 if(cc.GetWorkingDirectory())
1404 cmd += "cd ";
1405 cmd += this->ConvertToRelativeForMake(cc.GetWorkingDirectory());
1406 cmd += " && ";
1408 cmd += cmd2;
1409 for(unsigned int j=1; j < commandLine.size(); ++j)
1411 cmd += " ";
1412 if(escapeOldStyle)
1414 cmd += (this->CurrentLocalGenerator
1415 ->EscapeForShellOldStyle(commandLine[j].c_str()));
1417 else
1419 cmd += (this->CurrentLocalGenerator->
1420 EscapeForShell(commandLine[j].c_str(),
1421 escapeAllowMakeVars));
1424 makefileStream << "\t" << cmd.c_str() << "\n";
1429 // Add rules to deal with multiple outputs of custom commands.
1430 if(!multipleOutputPairs.empty())
1432 makefileStream <<
1433 "\n# Dependencies of multiple outputs to their primary outputs \n";
1435 for(std::map<cmStdString, cmStdString>::const_iterator o =
1436 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1438 makefileStream << o->first << ": " << o->second << "\n";
1441 makefileStream <<
1442 "\n"
1443 "cmake_check_multiple_outputs:\n";
1444 for(std::map<cmStdString, cmStdString>::const_iterator o =
1445 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1447 makefileStream << "\t@if [ ! -f "
1448 << o->first << " ]; then rm -f "
1449 << o->second << "; fi\n";
1454 //----------------------------------------------------------------------------
1455 void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
1456 cmXCodeObject* buildSettings,
1457 const char* configName)
1459 std::string flags;
1460 std::string defFlags;
1461 bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
1462 (target.GetType() == cmTarget::MODULE_LIBRARY));
1464 const char* lang = target.GetLinkerLanguage(configName);
1465 std::string cflags;
1466 if(lang)
1468 // for c++ projects get the c flags as well
1469 if(strcmp(lang, "CXX") == 0)
1471 this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName);
1472 this->CurrentLocalGenerator->AddSharedFlags(cflags, lang, shared);
1475 // Add language-specific flags.
1476 this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName);
1478 // Add shared-library flags if needed.
1479 this->CurrentLocalGenerator->AddSharedFlags(flags, lang, shared);
1482 // Add define flags
1483 this->CurrentLocalGenerator->
1484 AppendFlags(defFlags,
1485 this->CurrentMakefile->GetDefineFlags());
1487 // Add preprocessor definitions for this target and configuration.
1488 BuildObjectListOrString ppDefs(this, this->XcodeVersion >= 30);
1489 if(this->XcodeVersion > 15)
1491 this->AppendDefines(ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)\"");
1493 if(const char* exportMacro = target.GetExportMacro())
1495 // Add the export symbol definition for shared library objects.
1496 this->AppendDefines(ppDefs, exportMacro);
1498 this->AppendDefines
1499 (ppDefs, this->CurrentMakefile->GetProperty("COMPILE_DEFINITIONS"));
1500 this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS"));
1501 if(configName)
1503 std::string defVarName = "COMPILE_DEFINITIONS_";
1504 defVarName += cmSystemTools::UpperCase(configName);
1505 this->AppendDefines
1506 (ppDefs, this->CurrentMakefile->GetProperty(defVarName.c_str()));
1507 this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str()));
1509 buildSettings->AddAttribute
1510 ("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList());
1512 std::string extraLinkOptions;
1513 if(target.GetType() == cmTarget::EXECUTABLE)
1515 extraLinkOptions =
1516 this->CurrentMakefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
1517 std::string var = "CMAKE_EXE_LINKER_FLAGS_";
1518 var += cmSystemTools::UpperCase(configName);
1519 std::string val =
1520 this->CurrentMakefile->GetSafeDefinition(var.c_str());
1521 if(val.size())
1523 extraLinkOptions += " ";
1524 extraLinkOptions += val;
1527 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1529 extraLinkOptions = this->CurrentMakefile->
1530 GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
1532 if(target.GetType() == cmTarget::MODULE_LIBRARY)
1534 extraLinkOptions = this->CurrentMakefile->
1535 GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
1538 const char* targetLinkFlags = target.GetProperty("LINK_FLAGS");
1539 if(targetLinkFlags)
1541 extraLinkOptions += " ";
1542 extraLinkOptions += targetLinkFlags;
1545 // Get the product name components.
1546 std::string pnprefix;
1547 std::string pnbase;
1548 std::string pnsuffix;
1549 target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
1551 // Store the product name for all target types.
1552 buildSettings->AddAttribute("PRODUCT_NAME",
1553 this->CreateString(pnbase.c_str()));
1555 // Set attributes to specify the proper name for the target.
1556 if(target.GetType() == cmTarget::STATIC_LIBRARY ||
1557 target.GetType() == cmTarget::SHARED_LIBRARY ||
1558 target.GetType() == cmTarget::MODULE_LIBRARY ||
1559 target.GetType() == cmTarget::EXECUTABLE)
1561 std::string pndir = target.GetDirectory();
1562 buildSettings->AddAttribute("SYMROOT",
1563 this->CreateString(pndir.c_str()));
1564 buildSettings->AddAttribute("EXECUTABLE_PREFIX",
1565 this->CreateString(pnprefix.c_str()));
1566 buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
1567 this->CreateString(pnsuffix.c_str()));
1570 // Handle settings for each target type.
1571 switch(target.GetType())
1573 case cmTarget::STATIC_LIBRARY:
1575 buildSettings->AddAttribute("LIBRARY_STYLE",
1576 this->CreateString("STATIC"));
1577 break;
1580 case cmTarget::MODULE_LIBRARY:
1582 buildSettings->AddAttribute("LIBRARY_STYLE",
1583 this->CreateString("BUNDLE"));
1584 if(this->XcodeVersion >= 22)
1586 buildSettings->AddAttribute("MACH_O_TYPE",
1587 this->CreateString("mh_bundle"));
1588 buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
1589 this->CreateString("NO"));
1590 // Add the flags to create an executable.
1591 std::string createFlags =
1592 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1593 if(!createFlags.empty())
1595 extraLinkOptions += " ";
1596 extraLinkOptions += createFlags;
1599 else
1601 // Add the flags to create a module.
1602 std::string createFlags =
1603 this->LookupFlags("CMAKE_SHARED_MODULE_CREATE_", lang, "_FLAGS",
1604 "-bundle");
1605 if(!createFlags.empty())
1607 extraLinkOptions += " ";
1608 extraLinkOptions += createFlags;
1611 break;
1613 case cmTarget::SHARED_LIBRARY:
1615 if(target.GetPropertyAsBool("FRAMEWORK"))
1617 std::string version = target.GetFrameworkVersion();
1618 buildSettings->AddAttribute("FRAMEWORK_VERSION",
1619 this->CreateString(version.c_str()));
1621 std::string plist = this->ComputeInfoPListLocation(target);
1622 // Xcode will create the final version of Info.plist at build time,
1623 // so let it replace the framework name. This avoids creating
1624 // a per-configuration Info.plist file.
1625 this->CurrentLocalGenerator
1626 ->GenerateFrameworkInfoPList(&target, "$(EXECUTABLE_NAME)",
1627 plist.c_str());
1628 std::string path =
1629 this->ConvertToRelativeForXCode(plist.c_str());
1630 buildSettings->AddAttribute("INFOPLIST_FILE",
1631 this->CreateString(path.c_str()));
1633 else
1635 // Add the flags to create a shared library.
1636 std::string createFlags =
1637 this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", lang, "_FLAGS",
1638 "-dynamiclib");
1639 if(!createFlags.empty())
1641 extraLinkOptions += " ";
1642 extraLinkOptions += createFlags;
1646 buildSettings->AddAttribute("LIBRARY_STYLE",
1647 this->CreateString("DYNAMIC"));
1648 break;
1650 case cmTarget::EXECUTABLE:
1652 // Add the flags to create an executable.
1653 std::string createFlags =
1654 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1655 if(!createFlags.empty())
1657 extraLinkOptions += " ";
1658 extraLinkOptions += createFlags;
1661 // Handle bundles and normal executables separately.
1662 if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
1664 std::string plist = this->ComputeInfoPListLocation(target);
1665 // Xcode will create the final version of Info.plist at build time,
1666 // so let it replace the executable name. This avoids creating
1667 // a per-configuration Info.plist file.
1668 this->CurrentLocalGenerator
1669 ->GenerateAppleInfoPList(&target, "$(EXECUTABLE_NAME)",
1670 plist.c_str());
1671 std::string path =
1672 this->ConvertToRelativeForXCode(plist.c_str());
1673 buildSettings->AddAttribute("INFOPLIST_FILE",
1674 this->CreateString(path.c_str()));
1678 break;
1679 default:
1680 break;
1682 if(this->XcodeVersion >= 22)
1684 buildSettings->AddAttribute("PREBINDING",
1685 this->CreateString("NO"));
1688 BuildObjectListOrString dirs(this, this->XcodeVersion >= 30);
1689 BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30);
1690 std::vector<std::string> includes;
1691 this->CurrentLocalGenerator->GetIncludeDirectories(includes);
1692 std::set<cmStdString> emitted;
1693 emitted.insert("/System/Library/Frameworks");
1694 for(std::vector<std::string>::iterator i = includes.begin();
1695 i != includes.end(); ++i)
1697 if(this->NameResolvesToFramework(i->c_str()))
1699 std::string frameworkDir = *i;
1700 frameworkDir += "/../";
1701 frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str());
1702 if(emitted.insert(frameworkDir).second)
1704 fdirs.Add(this->XCodeEscapePath(frameworkDir.c_str()).c_str());
1707 else
1709 std::string incpath =
1710 this->XCodeEscapePath(i->c_str());
1711 dirs.Add(incpath.c_str());
1714 std::vector<std::string>& frameworks = target.GetFrameworks();
1715 if(frameworks.size())
1717 for(std::vector<std::string>::iterator fmIt = frameworks.begin();
1718 fmIt != frameworks.end(); ++fmIt)
1720 if(emitted.insert(*fmIt).second)
1722 fdirs.Add(this->XCodeEscapePath(fmIt->c_str()).c_str());
1726 if(!fdirs.IsEmpty())
1728 buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS",
1729 fdirs.CreateList());
1731 if(!dirs.IsEmpty())
1733 buildSettings->AddAttribute("HEADER_SEARCH_PATHS",
1734 dirs.CreateList());
1736 std::string oflagc = this->ExtractFlag("-O", cflags);
1737 char optLevel[2];
1738 optLevel[0] = '0';
1739 optLevel[1] = 0;
1740 if(oflagc.size() == 3)
1742 optLevel[0] = oflagc[2];
1744 if(oflagc.size() == 2)
1746 optLevel[0] = '1';
1748 std::string oflag = this->ExtractFlag("-O", flags);
1749 if(oflag.size() == 3)
1751 optLevel[0] = oflag[2];
1753 if(oflag.size() == 2)
1755 optLevel[0] = '1';
1757 std::string gflagc = this->ExtractFlag("-g", cflags);
1758 // put back gdwarf-2 if used since there is no way
1759 // to represent it in the gui, but we still want debug yes
1760 if(gflagc == "-gdwarf-2")
1762 cflags += " ";
1763 cflags += gflagc;
1765 std::string gflag = this->ExtractFlag("-g", flags);
1766 if(gflag == "-gdwarf-2")
1768 flags += " ";
1769 flags += gflag;
1771 const char* debugStr = "YES";
1772 if(gflagc.size() ==0 && gflag.size() == 0)
1774 debugStr = "NO";
1777 buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
1778 this->CreateString(debugStr));
1779 buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
1780 this->CreateString(optLevel));
1781 buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
1782 this->CreateString("NO"));
1783 buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
1784 this->CreateString("NO"));
1785 if(lang && strcmp(lang, "CXX") == 0)
1787 flags += " ";
1788 flags += defFlags;
1789 buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
1790 this->CreateString(flags.c_str()));
1791 cflags += " ";
1792 cflags += defFlags;
1793 buildSettings->AddAttribute("OTHER_CFLAGS",
1794 this->CreateString(cflags.c_str()));
1797 else
1799 flags += " ";
1800 flags += defFlags;
1801 buildSettings->AddAttribute("OTHER_CFLAGS",
1802 this->CreateString(flags.c_str()));
1805 // Create the INSTALL_PATH attribute.
1806 std::string install_name_dir;
1807 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1809 // Get the install_name directory for the build tree.
1810 install_name_dir = target.GetInstallNameDirForBuildTree(configName, true);
1811 if(install_name_dir.empty())
1813 // Xcode will not pass the -install_name option at all if INSTALL_PATH
1814 // is not given or is empty. We must explicitly put the flag in the
1815 // link flags to create an install_name with just the library soname.
1816 extraLinkOptions += " -install_name ";
1817 extraLinkOptions += target.GetFullName(configName);
1819 else
1821 // Convert to a path for the native build tool.
1822 cmSystemTools::ConvertToUnixSlashes(install_name_dir);
1823 // do not escape spaces on this since it is only a single path
1826 buildSettings->AddAttribute("INSTALL_PATH",
1827 this->CreateString(install_name_dir.c_str()));
1829 buildSettings->AddAttribute("OTHER_LDFLAGS",
1830 this->CreateString(extraLinkOptions.c_str()));
1831 buildSettings->AddAttribute("OTHER_REZFLAGS",
1832 this->CreateString(""));
1833 buildSettings->AddAttribute("SECTORDER_FLAGS",
1834 this->CreateString(""));
1835 buildSettings->AddAttribute("USE_HEADERMAP",
1836 this->CreateString("NO"));
1837 if (this->XcodeVersion >= 30)
1839 cmXCodeObject *group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1840 group->AddObject(this->CreateString("-Wmost"));
1841 group->AddObject(this->CreateString("-Wno-four-char-constants"));
1842 group->AddObject(this->CreateString("-Wno-unknown-pragmas"));
1843 buildSettings->AddAttribute("WARNING_CFLAGS", group);
1845 else
1847 buildSettings->AddAttribute("WARNING_CFLAGS",
1848 this->CreateString(
1849 "-Wmost -Wno-four-char-constants"
1850 " -Wno-unknown-pragmas"));
1853 // Runtime version information.
1854 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1856 int major;
1857 int minor;
1858 int patch;
1860 // VERSION -> current_version
1861 target.GetTargetVersion(false, major, minor, patch);
1862 if(major == 0 && minor == 0 && patch == 0)
1864 // Xcode always wants at least 1.0.0
1865 major = 1;
1867 cmOStringStream v;
1868 v << major << "." << minor << "." << patch;
1869 buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
1870 this->CreateString(v.str().c_str()));
1872 // SOVERSION -> compatibility_version
1873 target.GetTargetVersion(true, major, minor, patch);
1874 if(major == 0 && minor == 0 && patch == 0)
1876 // Xcode always wants at least 1.0.0
1877 major = 1;
1879 cmOStringStream vso;
1880 vso << major << "." << minor << "." << patch;
1881 buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
1882 this->CreateString(vso.str().c_str()));
1884 // put this last so it can override existing settings
1885 // Convert "XCODE_ATTRIBUTE_*" properties directly.
1887 cmPropertyMap const& props = target.GetProperties();
1888 for(cmPropertyMap::const_iterator i = props.begin();
1889 i != props.end(); ++i)
1891 if(i->first.find("XCODE_ATTRIBUTE_") == 0)
1893 buildSettings->AddAttribute(i->first.substr(16).c_str(),
1894 this->CreateString(i->second.GetValue()));
1900 //----------------------------------------------------------------------------
1901 cmXCodeObject*
1902 cmGlobalXCodeGenerator::CreateUtilityTarget(cmTarget& cmtarget)
1904 cmXCodeObject* shellBuildPhase =
1905 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
1906 shellBuildPhase->AddAttribute("buildActionMask",
1907 this->CreateString("2147483647"));
1908 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1909 shellBuildPhase->AddAttribute("files", buildFiles);
1910 cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1911 shellBuildPhase->AddAttribute("inputPaths", inputPaths);
1912 cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1913 shellBuildPhase->AddAttribute("outputPaths", outputPaths);
1914 shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1915 this->CreateString("0"));
1916 shellBuildPhase->AddAttribute("shellPath",
1917 this->CreateString("/bin/sh"));
1918 shellBuildPhase->AddAttribute("shellScript",
1919 this->CreateString(
1920 "# shell script goes here\nexit 0"));
1921 cmXCodeObject* target =
1922 this->CreateObject(cmXCodeObject::PBXAggregateTarget);
1923 target->SetComment(cmtarget.GetName());
1924 cmXCodeObject* buildPhases =
1925 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1926 std::vector<cmXCodeObject*> emptyContentVector;
1927 this->CreateCustomCommands(buildPhases, 0, 0, 0, emptyContentVector, 0,
1928 cmtarget);
1929 target->AddAttribute("buildPhases", buildPhases);
1930 if(this->XcodeVersion > 20)
1932 this->AddConfigurations(target, cmtarget);
1934 else
1936 const char* theConfig =
1937 this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
1938 cmXCodeObject* buildSettings =
1939 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1940 this->CreateBuildSettings(cmtarget, buildSettings, theConfig);
1941 target->AddAttribute("buildSettings", buildSettings);
1943 cmXCodeObject* dependencies =
1944 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1945 target->AddAttribute("dependencies", dependencies);
1946 target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
1947 target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
1948 target->SetTarget(&cmtarget);
1950 // Add source files without build rules for editing convenience.
1951 if(cmtarget.GetType() == cmTarget::UTILITY)
1953 std::vector<cmSourceFile*> const& sources = cmtarget.GetSourceFiles();
1954 for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
1955 i != sources.end(); ++i)
1957 if(!(*i)->GetPropertyAsBool("GENERATED"))
1959 this->CreateXCodeFileReference(*i, cmtarget);
1964 return target;
1967 //----------------------------------------------------------------------------
1968 std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
1969 cmTarget& cmtarget)
1971 std::string configTypes =
1972 this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
1973 std::vector<std::string> configVectorIn;
1974 std::vector<std::string> configVector;
1975 configVectorIn.push_back(configTypes);
1976 cmSystemTools::ExpandList(configVectorIn, configVector);
1977 cmXCodeObject* configlist =
1978 this->CreateObject(cmXCodeObject::XCConfigurationList);
1979 cmXCodeObject* buildConfigurations =
1980 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1981 configlist->AddAttribute("buildConfigurations", buildConfigurations);
1982 std::string comment = "Build configuration list for ";
1983 comment += cmXCodeObject::PBXTypeNames[target->GetIsA()];
1984 comment += " \"";
1985 comment += cmtarget.GetName();
1986 comment += "\"";
1987 configlist->SetComment(comment.c_str());
1988 target->AddAttribute("buildConfigurationList",
1989 this->CreateObjectReference(configlist));
1990 for(unsigned int i = 0; i < configVector.size(); ++i)
1992 cmXCodeObject* config =
1993 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
1994 buildConfigurations->AddObject(config);
1995 cmXCodeObject* buildSettings =
1996 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1997 this->CreateBuildSettings(cmtarget, buildSettings,
1998 configVector[i].c_str());
1999 config->AddAttribute("name", this->CreateString(configVector[i].c_str()));
2000 config->SetComment(configVector[i].c_str());
2001 config->AddAttribute("buildSettings", buildSettings);
2003 if(configVector.size())
2005 configlist->AddAttribute("defaultConfigurationName",
2006 this->CreateString(configVector[0].c_str()));
2007 configlist->AddAttribute("defaultConfigurationIsVisible",
2008 this->CreateString("0"));
2009 return configVector[0];
2011 return "";
2014 //----------------------------------------------------------------------------
2015 const char* cmGlobalXCodeGenerator::GetTargetFileType(cmTarget& cmtarget)
2017 switch(cmtarget.GetType())
2019 case cmTarget::STATIC_LIBRARY:
2020 return "archive.ar";
2021 case cmTarget::MODULE_LIBRARY:
2022 return ((this->XcodeVersion >= 22)?
2023 "compiled.mach-o.executable" : "compiled.mach-o.dylib");
2024 case cmTarget::SHARED_LIBRARY:
2025 return (cmtarget.GetPropertyAsBool("FRAMEWORK")?
2026 "wrapper.framework" : "compiled.mach-o.dylib");
2027 case cmTarget::EXECUTABLE:
2028 return "compiled.mach-o.executable";
2029 default: break;
2031 return 0;
2034 //----------------------------------------------------------------------------
2035 const char* cmGlobalXCodeGenerator::GetTargetProductType(cmTarget& cmtarget)
2037 switch(cmtarget.GetType())
2039 case cmTarget::STATIC_LIBRARY:
2040 return "com.apple.product-type.library.static";
2041 case cmTarget::MODULE_LIBRARY:
2042 return ((this->XcodeVersion >= 22)? "com.apple.product-type.tool" :
2043 "com.apple.product-type.library.dynamic");
2044 case cmTarget::SHARED_LIBRARY:
2045 return (cmtarget.GetPropertyAsBool("FRAMEWORK")?
2046 "com.apple.product-type.framework" :
2047 "com.apple.product-type.library.dynamic");
2048 case cmTarget::EXECUTABLE:
2049 return (cmtarget.GetPropertyAsBool("MACOSX_BUNDLE")?
2050 "com.apple.product-type.application" :
2051 "com.apple.product-type.tool");
2052 default: break;
2054 return 0;
2057 //----------------------------------------------------------------------------
2058 cmXCodeObject*
2059 cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
2060 cmXCodeObject* buildPhases)
2062 cmXCodeObject* target =
2063 this->CreateObject(cmXCodeObject::PBXNativeTarget);
2064 target->AddAttribute("buildPhases", buildPhases);
2065 cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2066 target->AddAttribute("buildRules", buildRules);
2067 std::string defConfig;
2068 if(this->XcodeVersion > 20)
2070 defConfig = this->AddConfigurations(target, cmtarget);
2072 else
2074 cmXCodeObject* buildSettings =
2075 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2076 defConfig = this->CurrentMakefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
2077 this->CreateBuildSettings(cmtarget, buildSettings, defConfig.c_str());
2078 target->AddAttribute("buildSettings", buildSettings);
2080 cmXCodeObject* dependencies =
2081 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2082 target->AddAttribute("dependencies", dependencies);
2083 target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
2084 target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
2086 cmXCodeObject* fileRef =
2087 this->CreateObject(cmXCodeObject::PBXFileReference);
2088 if(const char* fileType = this->GetTargetFileType(cmtarget))
2090 fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
2092 std::string fullName = cmtarget.GetFullName(defConfig.c_str());
2093 fileRef->AddAttribute("path", this->CreateString(fullName.c_str()));
2094 fileRef->AddAttribute("refType", this->CreateString("0"));
2095 fileRef->AddAttribute("sourceTree",
2096 this->CreateString("BUILT_PRODUCTS_DIR"));
2097 fileRef->SetComment(cmtarget.GetName());
2098 target->AddAttribute("productReference",
2099 this->CreateObjectReference(fileRef));
2100 if(const char* productType = this->GetTargetProductType(cmtarget))
2102 target->AddAttribute("productType", this->CreateString(productType));
2104 target->SetTarget(&cmtarget);
2105 return target;
2108 //----------------------------------------------------------------------------
2109 cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
2111 if(!t)
2113 return 0;
2115 for(std::vector<cmXCodeObject*>::iterator i = this->XCodeObjects.begin();
2116 i != this->XCodeObjects.end(); ++i)
2118 cmXCodeObject* o = *i;
2119 if(o->GetTarget() == t)
2121 return o;
2124 return 0;
2127 //----------------------------------------------------------------------------
2128 void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
2129 cmXCodeObject* dependTarget)
2131 // make sure a target does not depend on itself
2132 if(target == dependTarget)
2134 return;
2136 // now avoid circular references if dependTarget already
2137 // depends on target then skip it. Circular references crashes
2138 // xcode
2139 cmXCodeObject* dependTargetDepends =
2140 dependTarget->GetObject("dependencies");
2141 if(dependTargetDepends)
2143 if(dependTargetDepends->HasObject(target->GetPBXTargetDependency()))
2145 return;
2149 cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency();
2150 if(!targetdep)
2152 cmXCodeObject* container =
2153 this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
2154 container->SetComment("PBXContainerItemProxy");
2155 container->AddAttribute("containerPortal",
2156 this->CreateObjectReference(this->RootObject));
2157 container->AddAttribute("proxyType", this->CreateString("1"));
2158 container->AddAttribute("remoteGlobalIDString",
2159 this->CreateObjectReference(dependTarget));
2160 container->AddAttribute("remoteInfo",
2161 this->CreateString(
2162 dependTarget->GetTarget()->GetName()));
2163 targetdep =
2164 this->CreateObject(cmXCodeObject::PBXTargetDependency);
2165 targetdep->SetComment("PBXTargetDependency");
2166 targetdep->AddAttribute("target",
2167 this->CreateObjectReference(dependTarget));
2168 targetdep->AddAttribute("targetProxy",
2169 this->CreateObjectReference(container));
2170 dependTarget->SetPBXTargetDependency(targetdep);
2173 cmXCodeObject* depends = target->GetObject("dependencies");
2174 if(!depends)
2176 cmSystemTools::
2177 Error("target does not have dependencies attribute error..");
2180 else
2182 depends->AddUniqueObject(targetdep);
2186 //----------------------------------------------------------------------------
2187 void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
2188 const char* attribute,
2189 const char* value)
2191 if(settings)
2193 cmXCodeObject* attr = settings->GetObject(attribute);
2194 if(!attr)
2196 settings->AddAttribute(attribute, this->CreateString(value));
2198 else
2200 std::string oldValue = attr->GetString();
2201 oldValue += " ";
2202 oldValue += value;
2203 attr->SetString(oldValue.c_str());
2208 //----------------------------------------------------------------------------
2209 void cmGlobalXCodeGenerator
2210 ::AppendBuildSettingAttribute(cmXCodeObject* target,
2211 const char* attribute,
2212 const char* value,
2213 const char* configName)
2215 if(this->XcodeVersion < 21)
2217 // There is only one configuration. Add the setting to the buildSettings
2218 // of the target.
2219 this->AppendOrAddBuildSetting(target->GetObject("buildSettings"),
2220 attribute, value);
2222 else
2224 // There are multiple configurations. Add the setting to the
2225 // buildSettings of the configuration name given.
2226 cmXCodeObject* configurationList =
2227 target->GetObject("buildConfigurationList")->GetObject();
2228 cmXCodeObject* buildConfigs =
2229 configurationList->GetObject("buildConfigurations");
2230 std::vector<cmXCodeObject*> list = buildConfigs->GetObjectList();
2231 // each configuration and the target itself has a buildSettings in it
2232 //list.push_back(target);
2233 for(std::vector<cmXCodeObject*>::iterator i = list.begin();
2234 i != list.end(); ++i)
2236 if(configName)
2238 if(strcmp((*i)->GetObject("name")->GetString(), configName) == 0)
2240 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2241 this->AppendOrAddBuildSetting(settings, attribute, value);
2244 else
2246 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2247 this->AppendOrAddBuildSetting(settings, attribute, value);
2253 //----------------------------------------------------------------------------
2254 void cmGlobalXCodeGenerator
2255 ::AddDependAndLinkInformation(cmXCodeObject* target)
2257 cmTarget* cmtarget = target->GetTarget();
2258 if(!cmtarget)
2260 cmSystemTools::Error("Error no target on xobject\n");
2261 return;
2264 // Add dependencies on other CMake targets.
2265 TargetDependSet const& deps = this->GetTargetDirectDepends(*cmtarget);
2266 for(TargetDependSet::const_iterator i = deps.begin(); i != deps.end(); ++i)
2268 if(cmXCodeObject* dptarget = this->FindXCodeTarget(*i))
2270 this->AddDependTarget(target, dptarget);
2274 // Skip link information for static libraries.
2275 if(cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
2277 return;
2280 // Loop over configuration types and set per-configuration info.
2281 for(std::vector<std::string>::iterator i =
2282 this->CurrentConfigurationTypes.begin();
2283 i != this->CurrentConfigurationTypes.end(); ++i)
2285 // Get the current configuration name.
2286 const char* configName = i->c_str();
2287 if(!*configName)
2289 configName = 0;
2292 // Compute the link library and directory information.
2293 cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName);
2294 if(!pcli)
2296 continue;
2298 cmComputeLinkInformation& cli = *pcli;
2300 // Add dependencies directly on library files.
2302 std::vector<std::string> const& libDeps = cli.GetDepends();
2303 for(std::vector<std::string>::const_iterator j = libDeps.begin();
2304 j != libDeps.end(); ++j)
2306 target->AddDependLibrary(configName, j->c_str());
2310 // add the library search paths
2312 std::vector<std::string> const& libDirs = cli.GetDirectories();
2313 std::string linkDirs;
2314 for(std::vector<std::string>::const_iterator libDir = libDirs.begin();
2315 libDir != libDirs.end(); ++libDir)
2317 if(libDir->size() && *libDir != "/usr/lib")
2319 if(this->XcodeVersion > 15)
2321 // now add the same one but append $(CONFIGURATION) to it:
2322 linkDirs += " ";
2323 linkDirs += this->XCodeEscapePath(
2324 (*libDir + "/$(CONFIGURATION)").c_str());
2326 linkDirs += " ";
2327 linkDirs += this->XCodeEscapePath(libDir->c_str());
2330 this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
2331 linkDirs.c_str(), configName);
2334 // add the framework search paths
2336 const char* sep = "";
2337 std::string fdirs;
2338 std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
2339 for(std::vector<std::string>::const_iterator fdi = fwDirs.begin();
2340 fdi != fwDirs.end(); ++fdi)
2342 fdirs += sep;
2343 sep = " ";
2344 fdirs += this->XCodeEscapePath(fdi->c_str());
2346 if(!fdirs.empty())
2348 this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
2349 fdirs.c_str(), configName);
2353 // now add the link libraries
2355 std::string linkLibs;
2356 const char* sep = "";
2357 typedef cmComputeLinkInformation::ItemVector ItemVector;
2358 ItemVector const& libNames = cli.GetItems();
2359 for(ItemVector::const_iterator li = libNames.begin();
2360 li != libNames.end(); ++li)
2362 linkLibs += sep;
2363 sep = " ";
2364 if(li->IsPath)
2366 linkLibs += this->XCodeEscapePath(li->Value.c_str());
2368 else
2370 linkLibs += li->Value;
2373 this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
2374 linkLibs.c_str(), configName);
2379 //----------------------------------------------------------------------------
2380 void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
2381 std::vector<cmLocalGenerator*>&
2382 generators)
2384 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2385 i != generators.end(); ++i)
2387 if(this->IsExcluded(root, *i))
2389 continue;
2391 cmMakefile* mf = (*i)->GetMakefile();
2392 std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
2393 cmTargets &tgts = mf->GetTargets();
2394 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
2396 cmTarget& cmtarget = l->second;
2398 // Same skipping logic here as in CreateXCodeTargets so that we do not
2399 // end up with (empty anyhow) ALL_BUILD and XCODE_DEPEND_HELPER source
2400 // groups:
2402 if(cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
2404 continue;
2407 // add the soon to be generated Info.plist file as a source for a
2408 // MACOSX_BUNDLE file
2409 if(cmtarget.GetPropertyAsBool("MACOSX_BUNDLE"))
2411 std::string plist = this->ComputeInfoPListLocation(cmtarget);
2412 cmSourceFile* sf = mf->GetOrCreateSource(plist.c_str(), true);
2413 cmtarget.AddSourceFile(sf);
2416 std::vector<cmSourceFile*> classes = cmtarget.GetSourceFiles();
2418 for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
2419 s != classes.end(); s++)
2421 cmSourceFile* sf = *s;
2422 // Add the file to the list of sources.
2423 std::string const& source = sf->GetFullPath();
2424 cmSourceGroup& sourceGroup =
2425 mf->FindSourceGroup(source.c_str(), sourceGroups);
2426 cmXCodeObject* pbxgroup =
2427 this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
2428 cmStdString key = GetGroupMapKey(cmtarget, sf);
2429 this->GroupMap[key] = pbxgroup;
2435 //----------------------------------------------------------------------------
2436 cmXCodeObject* cmGlobalXCodeGenerator
2437 ::CreateOrGetPBXGroup(cmTarget& cmtarget, cmSourceGroup* sg)
2439 cmStdString s = cmtarget.GetName();
2440 s += "/";
2441 s += sg->GetName();
2442 std::map<cmStdString, cmXCodeObject* >::iterator i =
2443 this->GroupNameMap.find(s);
2444 if(i != this->GroupNameMap.end())
2446 return i->second;
2448 i = this->TargetGroup.find(cmtarget.GetName());
2449 cmXCodeObject* tgroup = 0;
2450 if(i != this->TargetGroup.end())
2452 tgroup = i->second;
2454 else
2456 tgroup = this->CreateObject(cmXCodeObject::PBXGroup);
2457 this->TargetGroup[cmtarget.GetName()] = tgroup;
2458 cmXCodeObject* tgroupChildren =
2459 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2460 tgroup->AddAttribute("name", this->CreateString(cmtarget.GetName()));
2461 tgroup->AddAttribute("children", tgroupChildren);
2462 if(this->XcodeVersion == 15)
2464 tgroup->AddAttribute("refType", this->CreateString("4"));
2466 tgroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2467 this->SourcesGroupChildren->AddObject(tgroup);
2470 // If it's the default source group (empty name) then put the source file
2471 // directly in the tgroup...
2473 if (cmStdString(sg->GetName()) == "")
2475 this->GroupNameMap[s] = tgroup;
2476 return tgroup;
2479 cmXCodeObject* tgroupChildren = tgroup->GetObject("children");
2480 cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
2481 cmXCodeObject* groupChildren =
2482 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2483 group->AddAttribute("name", this->CreateString(sg->GetName()));
2484 group->AddAttribute("children", groupChildren);
2485 if(this->XcodeVersion == 15)
2487 group->AddAttribute("refType", this->CreateString("4"));
2489 group->AddAttribute("sourceTree", this->CreateString("<group>"));
2490 tgroupChildren->AddObject(group);
2491 this->GroupNameMap[s] = group;
2492 return group;
2495 //----------------------------------------------------------------------------
2496 void cmGlobalXCodeGenerator
2497 ::CreateXCodeObjects(cmLocalGenerator* root,
2498 std::vector<cmLocalGenerator*>&
2499 generators)
2501 this->ClearXCodeObjects();
2502 this->RootObject = 0;
2503 this->SourcesGroupChildren = 0;
2504 this->ResourcesGroupChildren = 0;
2505 this->MainGroupChildren = 0;
2506 cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2507 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2508 cmXCodeObject* developBuildStyle =
2509 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2510 cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2511 if(this->XcodeVersion == 15)
2513 developBuildStyle->AddAttribute("name",
2514 this->CreateString("Development"));
2515 developBuildStyle->AddAttribute("buildSettings", group);
2516 listObjs->AddObject(developBuildStyle);
2517 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2518 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
2519 cmXCodeObject* deployBuildStyle =
2520 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2521 deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
2522 deployBuildStyle->AddAttribute("buildSettings", group);
2523 listObjs->AddObject(deployBuildStyle);
2525 else
2527 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2529 cmXCodeObject* buildStyle =
2530 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2531 const char* name = this->CurrentConfigurationTypes[i].c_str();
2532 buildStyle->AddAttribute("name", this->CreateString(name));
2533 buildStyle->SetComment(name);
2534 cmXCodeObject* sgroup =
2535 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2536 sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2537 buildStyle->AddAttribute("buildSettings", sgroup);
2538 listObjs->AddObject(buildStyle);
2542 cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2543 this->MainGroupChildren =
2544 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2545 mainGroup->AddAttribute("children", this->MainGroupChildren);
2546 if(this->XcodeVersion == 15)
2548 mainGroup->AddAttribute("refType", this->CreateString("4"));
2550 mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2552 cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2553 this->SourcesGroupChildren =
2554 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2555 sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
2556 sourcesGroup->AddAttribute("children", this->SourcesGroupChildren);
2557 if(this->XcodeVersion == 15)
2559 sourcesGroup->AddAttribute("refType", this->CreateString("4"));
2561 sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2562 this->MainGroupChildren->AddObject(sourcesGroup);
2564 cmXCodeObject* resourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2565 this->ResourcesGroupChildren =
2566 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2567 resourcesGroup->AddAttribute("name", this->CreateString("Resources"));
2568 resourcesGroup->AddAttribute("children", this->ResourcesGroupChildren);
2569 if(this->XcodeVersion == 15)
2571 resourcesGroup->AddAttribute("refType", this->CreateString("4"));
2573 resourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2574 this->MainGroupChildren->AddObject(resourcesGroup);
2576 // now create the cmake groups
2577 this->CreateGroups(root, generators);
2579 cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2580 productGroup->AddAttribute("name", this->CreateString("Products"));
2581 if(this->XcodeVersion == 15)
2583 productGroup->AddAttribute("refType", this->CreateString("4"));
2585 productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2586 cmXCodeObject* productGroupChildren =
2587 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2588 productGroup->AddAttribute("children", productGroupChildren);
2589 this->MainGroupChildren->AddObject(productGroup);
2592 this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
2593 this->RootObject->SetComment("Project object");
2594 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2595 this->RootObject->AddAttribute("mainGroup",
2596 this->CreateObjectReference(mainGroup));
2597 this->RootObject->AddAttribute("buildSettings", group);
2598 this->RootObject->AddAttribute("buildStyles", listObjs);
2599 this->RootObject->AddAttribute("hasScannedForEncodings",
2600 this->CreateString("0"));
2601 if (this->XcodeVersion >= 30)
2603 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2604 group->AddAttribute("BuildIndependentTargetsInParallel",
2605 this->CreateString("YES"));
2606 this->RootObject->AddAttribute("attributes", group);
2607 if (this->XcodeVersion >= 31)
2608 this->RootObject->AddAttribute("compatibilityVersion",
2609 this->CreateString("Xcode 3.1"));
2610 else
2611 this->RootObject->AddAttribute("compatibilityVersion",
2612 this->CreateString("Xcode 3.0"));
2613 this->RootObject->AddAttribute("projectDirPath", this->CreateString(""));
2615 // Point Xcode at the top of the source tree.
2617 std::string proot = root->GetMakefile()->GetCurrentDirectory();
2618 proot = this->ConvertToRelativeForXCode(proot.c_str());
2619 if (this->XcodeVersion >= 30)
2621 this->RootObject->AddAttribute("projectRoot",
2622 this->CreateString(""));
2623 this->RootObject->AddAttribute("projectDirPath",
2624 this->CreateString(proot.c_str()));
2626 else
2628 this->RootObject->AddAttribute("projectRoot",
2629 this->CreateString(proot.c_str()));
2632 cmXCodeObject* configlist =
2633 this->CreateObject(cmXCodeObject::XCConfigurationList);
2634 cmXCodeObject* buildConfigurations =
2635 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2636 std::vector<cmXCodeObject*> configs;
2637 if(this->XcodeVersion == 15)
2639 cmXCodeObject* configDebug =
2640 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2641 configDebug->AddAttribute("name", this->CreateString("Debug"));
2642 configs.push_back(configDebug);
2643 cmXCodeObject* configRelease =
2644 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2645 configRelease->AddAttribute("name", this->CreateString("Release"));
2646 configs.push_back(configRelease);
2648 else
2650 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2652 const char* name = this->CurrentConfigurationTypes[i].c_str();
2653 cmXCodeObject* config =
2654 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2655 config->AddAttribute("name", this->CreateString(name));
2656 configs.push_back(config);
2659 for(std::vector<cmXCodeObject*>::iterator c = configs.begin();
2660 c != configs.end(); ++c)
2662 buildConfigurations->AddObject(*c);
2664 configlist->AddAttribute("buildConfigurations", buildConfigurations);
2666 std::string comment = "Build configuration list for PBXProject ";
2667 comment += " \"";
2668 comment += this->CurrentProject;
2669 comment += "\"";
2670 configlist->SetComment(comment.c_str());
2671 configlist->AddAttribute("defaultConfigurationIsVisible",
2672 this->CreateString("0"));
2673 configlist->AddAttribute("defaultConfigurationName",
2674 this->CreateString("Debug"));
2675 cmXCodeObject* buildSettings =
2676 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2677 const char* osxArch =
2678 this->CurrentMakefile->GetDefinition("CMAKE_OSX_ARCHITECTURES");
2679 if(strlen(osxArch) == 0)
2681 if(this->XcodeVersion >= 32)
2683 osxArch = "$(ARCHS_STANDARD_32_64_BIT)";
2685 else if(this->XcodeVersion <= 25)
2687 #ifdef __i386
2688 osxArch = "i386";
2689 #endif
2690 #ifdef __ppc__
2691 osxArch = "ppc";
2692 #endif
2694 else
2696 osxArch = "$(ARCHS_STANDARD_32_BIT)";
2698 buildSettings->AddAttribute("ONLY_ACTIVE_ARCH",
2699 this->CreateString("YES"));
2702 const char* sysroot =
2703 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
2704 const char* sysrootDefault =
2705 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT_DEFAULT");
2706 const char* deploymentTarget =
2707 this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
2708 if(osxArch && sysroot)
2710 bool flagsUsed = false;
2711 // recompute this as it may have been changed since enable language
2712 this->Architectures.clear();
2713 cmSystemTools::ExpandListArgument(std::string(osxArch),
2714 this->Architectures);
2715 flagsUsed = true;
2716 buildSettings->AddAttribute("SDKROOT",
2717 this->CreateString(sysroot));
2718 std::string archString;
2719 for( std::vector<std::string>::iterator i =
2720 this->Architectures.begin();
2721 i != this->Architectures.end(); ++i)
2723 archString += *i;
2724 archString += " ";
2726 buildSettings->AddAttribute("ARCHS",
2727 this->CreateString(archString.c_str()));
2728 if(!flagsUsed && sysrootDefault &&
2729 strcmp(sysroot, sysrootDefault) != 0)
2731 buildSettings->AddAttribute("SDKROOT",
2732 this->CreateString(sysroot));
2735 if(deploymentTarget && *deploymentTarget)
2737 buildSettings->AddAttribute("MACOSX_DEPLOYMENT_TARGET",
2738 this->CreateString(deploymentTarget));
2741 std::string symroot = root->GetMakefile()->GetCurrentOutputDirectory();
2742 symroot += "/build";
2743 buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot.c_str()));
2745 for( std::vector<cmXCodeObject*>::iterator i = configs.begin();
2746 i != configs.end(); ++i)
2748 (*i)->AddAttribute("buildSettings", buildSettings);
2751 this->RootObject->AddAttribute("buildConfigurationList",
2752 this->CreateObjectReference(configlist));
2754 std::vector<cmXCodeObject*> targets;
2755 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2756 i != generators.end(); ++i)
2758 if(!this->IsExcluded(root, *i))
2760 this->CreateXCodeTargets(*i, targets);
2763 // loop over all targets and add link and depend info
2764 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2765 i != targets.end(); ++i)
2767 cmXCodeObject* t = *i;
2768 this->AddDependAndLinkInformation(t);
2770 // now create xcode depend hack makefile
2771 this->CreateXCodeDependHackTarget(targets);
2772 // now add all targets to the root object
2773 cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2774 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2775 i != targets.end(); ++i)
2777 cmXCodeObject* t = *i;
2778 allTargets->AddObject(t);
2779 cmXCodeObject* productRef = t->GetObject("productReference");
2780 if(productRef)
2782 productGroupChildren->AddObject(productRef->GetObject());
2785 this->RootObject->AddAttribute("targets", allTargets);
2788 //----------------------------------------------------------------------------
2789 void
2790 cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
2791 std::vector<cmXCodeObject*>& targets)
2793 cmGeneratedFileStream
2794 makefileStream(this->CurrentXCodeHackMakefile.c_str());
2795 if(!makefileStream)
2797 cmSystemTools::Error("Could not create",
2798 this->CurrentXCodeHackMakefile.c_str());
2799 return;
2801 makefileStream.SetCopyIfDifferent(true);
2802 // one more pass for external depend information not handled
2803 // correctly by xcode
2804 makefileStream << "# DO NOT EDIT\n";
2805 makefileStream << "# This makefile makes sure all linkable targets are\n";
2806 makefileStream << "# up-to-date with anything they link to, avoiding a "
2807 "bug in XCode 1.5\n";
2808 for(std::vector<std::string>::const_iterator
2809 ct = this->CurrentConfigurationTypes.begin();
2810 ct != this->CurrentConfigurationTypes.end(); ++ct)
2812 if(this->XcodeVersion < 21 || ct->empty())
2814 makefileStream << "all: ";
2816 else
2818 makefileStream << "all." << *ct << ": ";
2820 const char* configName = 0;
2821 if(!ct->empty())
2823 configName = ct->c_str();
2825 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2826 i != targets.end(); ++i)
2828 cmXCodeObject* target = *i;
2829 cmTarget* t =target->GetTarget();
2830 if(t->GetType() == cmTarget::EXECUTABLE ||
2831 t->GetType() == cmTarget::SHARED_LIBRARY ||
2832 t->GetType() == cmTarget::MODULE_LIBRARY)
2834 std::string tfull = t->GetFullPath(configName);
2835 makefileStream << "\\\n\t" <<
2836 this->ConvertToRelativeForMake(tfull.c_str());
2839 makefileStream << "\n\n";
2841 makefileStream
2842 << "# For each target create a dummy rule "
2843 "so the target does not have to exist\n";
2844 std::set<cmStdString> emitted;
2845 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2846 i != targets.end(); ++i)
2848 cmXCodeObject* target = *i;
2849 std::map<cmStdString, cmXCodeObject::StringVec> const& deplibs =
2850 target->GetDependLibraries();
2851 for(std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator ci
2852 = deplibs.begin(); ci != deplibs.end(); ++ci)
2854 for(cmXCodeObject::StringVec::const_iterator d = ci->second.begin();
2855 d != ci->second.end(); ++d)
2857 if(emitted.insert(*d).second)
2859 makefileStream <<
2860 this->ConvertToRelativeForMake(d->c_str()) << ":\n";
2865 makefileStream << "\n\n";
2867 // Write rules to help Xcode relink things at the right time.
2868 makefileStream <<
2869 "# Rules to remove targets that are older than anything to which they\n"
2870 "# link. This forces Xcode to relink the targets from scratch. It\n"
2871 "# does not seem to check these dependencies itself.\n";
2872 for(std::vector<std::string>::const_iterator
2873 ct = this->CurrentConfigurationTypes.begin();
2874 ct != this->CurrentConfigurationTypes.end(); ++ct)
2876 const char* configName = 0;
2877 if(!ct->empty())
2879 configName = ct->c_str();
2881 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2882 i != targets.end(); ++i)
2884 cmXCodeObject* target = *i;
2885 cmTarget* t =target->GetTarget();
2886 if(t->GetType() == cmTarget::EXECUTABLE ||
2887 t->GetType() == cmTarget::SHARED_LIBRARY ||
2888 t->GetType() == cmTarget::MODULE_LIBRARY)
2890 // Create a rule for this target.
2891 std::string tfull = t->GetFullPath(configName);
2892 makefileStream << this->ConvertToRelativeForMake(tfull.c_str())
2893 << ":";
2895 // List dependencies if any exist.
2896 std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator
2897 x = target->GetDependLibraries().find(*ct);
2898 if(x != target->GetDependLibraries().end())
2900 std::vector<cmStdString> const& deplibs = x->second;
2901 for(std::vector<cmStdString>::const_iterator d = deplibs.begin();
2902 d != deplibs.end(); ++d)
2904 makefileStream << "\\\n\t" <<
2905 this->ConvertToRelativeForMake(d->c_str());
2908 // Write the action to remove the target if it is out of date.
2909 makefileStream << "\n";
2910 makefileStream << "\t/bin/rm -f "
2911 << this->ConvertToRelativeForMake(tfull.c_str())
2912 << "\n";
2913 // if building for more than one architecture
2914 // then remove those exectuables as well
2915 if(this->Architectures.size() > 1)
2917 std::string universal = t->GetDirectory();
2918 universal += "/";
2919 universal += this->CurrentProject;
2920 universal += ".build/";
2921 universal += configName;
2922 universal += "/";
2923 universal += t->GetName();
2924 universal += ".build/Objects-normal/";
2925 for( std::vector<std::string>::iterator arch =
2926 this->Architectures.begin();
2927 arch != this->Architectures.end(); ++arch)
2929 std::string universalFile = universal;
2930 universalFile += *arch;
2931 universalFile += "/";
2932 universalFile += t->GetFullName(configName);
2933 makefileStream << "\t/bin/rm -f "
2935 this->ConvertToRelativeForMake(universalFile.c_str())
2936 << "\n";
2939 makefileStream << "\n\n";
2945 //----------------------------------------------------------------------------
2946 void
2947 cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
2948 std::vector<cmLocalGenerator*>&
2949 generators)
2951 if(generators.size() == 0)
2953 return;
2955 // Skip local generators that are excluded from this project.
2956 for(std::vector<cmLocalGenerator*>::iterator g = generators.begin();
2957 g != generators.end(); ++g)
2959 if(this->IsExcluded(root, *g))
2961 continue;
2965 this->CreateXCodeObjects(root,
2966 generators);
2967 std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
2968 xcodeDir += "/";
2969 xcodeDir += root->GetMakefile()->GetProjectName();
2970 xcodeDir += ".xcode";
2971 if(this->XcodeVersion > 20)
2973 xcodeDir += "proj";
2975 cmSystemTools::MakeDirectory(xcodeDir.c_str());
2976 std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
2977 cmGeneratedFileStream fout(xcodeProjFile.c_str());
2978 fout.SetCopyIfDifferent(true);
2979 if(!fout)
2981 return;
2983 this->WriteXCodePBXProj(fout, root, generators);
2984 this->ClearXCodeObjects();
2987 //----------------------------------------------------------------------------
2988 void
2989 cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
2990 cmLocalGenerator* ,
2991 std::vector<cmLocalGenerator*>& )
2993 fout << "// !$*UTF8*$!\n";
2994 fout << "{\n";
2995 cmXCodeObject::Indent(1, fout);
2996 fout << "archiveVersion = 1;\n";
2997 cmXCodeObject::Indent(1, fout);
2998 fout << "classes = {\n";
2999 cmXCodeObject::Indent(1, fout);
3000 fout << "};\n";
3001 cmXCodeObject::Indent(1, fout);
3002 if(this->XcodeVersion >= 21)
3004 if (this->XcodeVersion >= 31)
3005 fout << "objectVersion = 45;\n";
3006 else if (this->XcodeVersion >= 30)
3007 fout << "objectVersion = 44;\n";
3008 else
3009 fout << "objectVersion = 42;\n";
3010 cmXCode21Object::PrintList(this->XCodeObjects, fout);
3012 else
3014 fout << "objectVersion = 39;\n";
3015 cmXCodeObject::PrintList(this->XCodeObjects, fout);
3017 cmXCodeObject::Indent(1, fout);
3018 fout << "rootObject = " << this->RootObject->GetId() << ";\n";
3019 fout << "}\n";
3022 //----------------------------------------------------------------------------
3023 const char* cmGlobalXCodeGenerator::GetCMakeCFGInitDirectory()
3025 return this->XcodeVersion >= 21? "$(CONFIGURATION)" : ".";
3028 //----------------------------------------------------------------------------
3029 void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
3030 const
3032 entry.Name = this->GetName();
3033 entry.Brief = "Generate XCode project files.";
3034 entry.Full = "";
3037 //----------------------------------------------------------------------------
3038 std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(const char* p)
3040 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
3042 return cmSystemTools::ConvertToOutputPath(p);
3044 else
3046 std::string ret =
3047 this->CurrentLocalGenerator->
3048 ConvertToRelativePath(this->CurrentOutputDirectoryComponents, p);
3049 return cmSystemTools::ConvertToOutputPath(ret.c_str());
3053 //----------------------------------------------------------------------------
3054 std::string cmGlobalXCodeGenerator::ConvertToRelativeForXCode(const char* p)
3056 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
3058 return cmSystemTools::ConvertToOutputPath(p);
3060 else
3062 std::string ret =
3063 this->CurrentLocalGenerator->
3064 ConvertToRelativePath(this->ProjectOutputDirectoryComponents, p);
3065 return cmSystemTools::ConvertToOutputPath(ret.c_str());
3069 //----------------------------------------------------------------------------
3070 std::string cmGlobalXCodeGenerator::XCodeEscapePath(const char* p)
3072 std::string ret = p;
3073 if(ret.find(' ') != ret.npos)
3075 std::string t = ret;
3076 ret = "\"";
3077 ret += t;
3078 ret += "\"";
3080 return ret;
3083 //----------------------------------------------------------------------------
3084 void cmGlobalXCodeGenerator::
3085 GetTargetObjectFileDirectories(cmTarget* target,
3086 std::vector<std::string>&
3087 dirs)
3089 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
3090 dir += "/";
3091 dir += this->CurrentMakefile->GetProjectName();
3092 dir += ".build/";
3093 dir += this->GetCMakeCFGInitDirectory();
3094 dir += "/";
3095 dir += target->GetName();
3096 dir += ".build/Objects-normal/";
3097 std::string dirsave = dir;
3098 if(this->Architectures.size())
3100 for(std::vector<std::string>::iterator i = this->Architectures.begin();
3101 i != this->Architectures.end(); ++i)
3103 dir += *i;
3104 dirs.push_back(dir);
3105 dir = dirsave;
3108 else
3110 dirs.push_back(dir);
3114 //----------------------------------------------------------------------------
3115 void
3116 cmGlobalXCodeGenerator
3117 ::AppendDirectoryForConfig(const char* prefix,
3118 const char* config,
3119 const char* suffix,
3120 std::string& dir)
3122 if(this->XcodeVersion > 20)
3124 if(config)
3126 dir += prefix;
3127 dir += config;
3128 dir += suffix;
3133 //----------------------------------------------------------------------------
3134 std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix,
3135 const char* varNameLang,
3136 const char* varNameSuffix,
3137 const char* default_flags)
3139 if(varNameLang)
3141 std::string varName = varNamePrefix;
3142 varName += varNameLang;
3143 varName += varNameSuffix;
3144 if(const char* varValue =
3145 this->CurrentMakefile->GetDefinition(varName.c_str()))
3147 if(*varValue)
3149 return varValue;
3153 return default_flags;
3156 //----------------------------------------------------------------------------
3157 void cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
3158 const char* defines_list,
3159 bool dflag)
3161 // Skip this if there are no definitions.
3162 if(!defines_list)
3164 return;
3167 // Expand the list of definitions.
3168 std::vector<std::string> defines;
3169 cmSystemTools::ExpandListArgument(defines_list, defines);
3171 // Store the definitions in the string.
3172 this->AppendDefines(defs, defines, dflag);
3175 //----------------------------------------------------------------------------
3176 void
3177 cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
3178 std::vector<std::string> const& defines,
3179 bool dflag)
3181 // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
3182 std::string def;
3183 for(std::vector<std::string>::const_iterator di = defines.begin();
3184 di != defines.end(); ++di)
3186 // Start with -D if requested.
3187 def = dflag? "-D": "";
3188 def += *di;
3190 // Append the flag with needed escapes.
3191 std::string tmp;
3192 this->AppendFlag(tmp, def);
3193 defs.Add(tmp.c_str());
3197 //----------------------------------------------------------------------------
3198 void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
3199 std::string const& flag)
3201 // Short-circuit for an empty flag.
3202 if(flag.empty())
3204 return;
3207 // Separate from previous flags.
3208 if(!flags.empty())
3210 flags += " ";
3213 // Check if the flag needs quoting.
3214 bool quoteFlag =
3215 flag.find_first_of("`~!@#$%^&*()+={}[]|:;\"'<>,.? ") != flag.npos;
3217 // We escape a flag as follows:
3218 // - Place each flag in single quotes ''
3219 // - Escape a single quote as \\'
3220 // - Escape a backslash as \\\\ since it itself is an escape
3221 // Note that in the code below we need one more level of escapes for
3222 // C string syntax in this source file.
3224 // The final level of escaping is done when the string is stored
3225 // into the project file by cmXCodeObject::PrintString.
3227 if(quoteFlag)
3229 // Open single quote.
3230 flags += "'";
3233 // Flag value with escaped quotes and backslashes.
3234 for(const char* c = flag.c_str(); *c; ++c)
3236 if(*c == '\'')
3238 flags += "\\\\'";
3240 else if(*c == '\\')
3242 flags += "\\\\\\\\";
3244 else
3246 flags += *c;
3250 if(quoteFlag)
3252 // Close single quote.
3253 flags += "'";
3257 //----------------------------------------------------------------------------
3258 std::string
3259 cmGlobalXCodeGenerator::ComputeInfoPListLocation(cmTarget& target)
3261 std::string plist = target.GetMakefile()->GetCurrentOutputDirectory();
3262 plist += cmake::GetCMakeFilesDirectory();
3263 plist += "/";
3264 plist += target.GetName();
3265 plist += ".dir/Info.plist";
3266 return plist;