Fix Xcode project references to the source tree
[cmake.git] / Source / cmGlobalXCodeGenerator.cxx
blob015cd6c0c3e6c990680b524a92dc55d9ad17ee0c
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalXCodeGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-09-22 20:18:30 $
7 Version: $Revision: 1.230 $
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 cmSystemTools::SplitPath(this->CurrentMakefile->GetCurrentDirectory(),
306 this->ProjectSourceDirectoryComponents);
307 cmSystemTools::SplitPath(this->CurrentMakefile->GetCurrentOutputDirectory(),
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 // Store the file path relative to the top of the source tree.
674 std::string path = this->RelativeToSource(sf->GetFullPath().c_str());
675 std::string name = cmSystemTools::GetFilenameName(path.c_str());
676 const char* sourceTree = (cmSystemTools::FileIsFullPath(path.c_str())?
677 "<absolute>" : "SOURCE_ROOT");
678 fileRef->AddAttribute("name", this->CreateString(name.c_str()));
679 fileRef->AddAttribute("path", this->CreateString(path.c_str()));
680 fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
681 if(this->XcodeVersion == 15)
683 fileRef->AddAttribute("refType", this->CreateString("4"));
685 return fileRef;
688 //----------------------------------------------------------------------------
689 bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
691 if(tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
692 tname == "install" || tname == "package" || tname == "RUN_TESTS" )
694 if(this->TargetDoneSet.find(tname) != this->TargetDoneSet.end())
696 return true;
698 this->TargetDoneSet.insert(tname);
699 return false;
701 return false;
704 //----------------------------------------------------------------------------
705 void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
707 this->CurrentLocalGenerator = gen;
708 this->CurrentMakefile = gen->GetMakefile();
709 std::string outdir =
710 cmSystemTools::CollapseFullPath(this->CurrentMakefile->
711 GetCurrentOutputDirectory());
712 cmSystemTools::SplitPath(outdir.c_str(),
713 this->CurrentOutputDirectoryComponents);
715 // Select the current set of configuration types.
716 this->CurrentConfigurationTypes.clear();
717 if(this->XcodeVersion > 20)
719 if(const char* types =
720 this->CurrentMakefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
722 cmSystemTools::ExpandListArgument(types,
723 this->CurrentConfigurationTypes);
726 if(this->CurrentConfigurationTypes.empty())
728 if(const char* buildType =
729 this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE"))
731 this->CurrentConfigurationTypes.push_back(buildType);
733 else
735 this->CurrentConfigurationTypes.push_back("");
740 //----------------------------------------------------------------------------
741 void
742 cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
743 std::vector<cmXCodeObject*>&
744 targets)
746 this->SetCurrentLocalGenerator(gen);
747 cmTargets &tgts = this->CurrentMakefile->GetTargets();
748 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
750 cmTarget& cmtarget = l->second;
752 // make sure ALL_BUILD, INSTALL, etc are only done once
753 if(this->SpecialTargetEmitted(l->first.c_str()))
755 continue;
758 if(cmtarget.GetType() == cmTarget::UTILITY ||
759 cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
761 targets.push_back(this->CreateUtilityTarget(cmtarget));
762 continue;
765 // organize the sources
766 std::vector<cmSourceFile*> const &classes = cmtarget.GetSourceFiles();
767 std::vector<cmXCodeObject*> externalObjFiles;
768 std::vector<cmXCodeObject*> headerFiles;
769 std::vector<cmXCodeObject*> resourceFiles;
770 std::vector<cmXCodeObject*> sourceFiles;
771 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
772 i != classes.end(); ++i)
774 cmXCodeObject* xsf =
775 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
776 *i, cmtarget);
777 cmXCodeObject* fr = xsf->GetObject("fileRef");
778 cmXCodeObject* filetype =
779 fr->GetObject()->GetObject("lastKnownFileType");
781 cmTarget::SourceFileFlags tsFlags =
782 cmtarget.GetTargetSourceFileFlags(*i);
784 if(strcmp(filetype->GetString(), "compiled.mach-o.objfile") == 0)
786 externalObjFiles.push_back(xsf);
788 else if(this->IsHeaderFile(*i) ||
789 (tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) ||
790 (tsFlags.Type == cmTarget::SourceFileTypePublicHeader))
792 headerFiles.push_back(xsf);
794 else if(tsFlags.Type == cmTarget::SourceFileTypeResource)
796 resourceFiles.push_back(xsf);
798 else if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY"))
800 // Include this file in the build if it has a known language
801 // and has not been listed as an ignored extension for this
802 // generator.
803 if(this->CurrentLocalGenerator->GetSourceFileLanguage(**i) &&
804 !this->IgnoreFile((*i)->GetExtension().c_str()))
806 sourceFiles.push_back(xsf);
811 // some build phases only apply to bundles and/or frameworks
812 bool isFrameworkTarget = cmtarget.IsFrameworkOnApple();
813 bool isBundleTarget = cmtarget.GetPropertyAsBool("MACOSX_BUNDLE");
815 cmXCodeObject* buildFiles = 0;
817 // create source build phase
818 cmXCodeObject* sourceBuildPhase = 0;
819 if (!sourceFiles.empty())
821 sourceBuildPhase =
822 this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
823 sourceBuildPhase->SetComment("Sources");
824 sourceBuildPhase->AddAttribute("buildActionMask",
825 this->CreateString("2147483647"));
826 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
827 for(std::vector<cmXCodeObject*>::iterator i = sourceFiles.begin();
828 i != sourceFiles.end(); ++i)
830 buildFiles->AddObject(*i);
832 sourceBuildPhase->AddAttribute("files", buildFiles);
833 sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
834 this->CreateString("0"));
837 // create header build phase - only for framework targets
838 cmXCodeObject* headerBuildPhase = 0;
839 if (!headerFiles.empty() && isFrameworkTarget)
841 headerBuildPhase =
842 this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
843 headerBuildPhase->SetComment("Headers");
844 headerBuildPhase->AddAttribute("buildActionMask",
845 this->CreateString("2147483647"));
846 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
847 for(std::vector<cmXCodeObject*>::iterator i = headerFiles.begin();
848 i != headerFiles.end(); ++i)
850 buildFiles->AddObject(*i);
852 headerBuildPhase->AddAttribute("files", buildFiles);
853 headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
854 this->CreateString("0"));
857 // create resource build phase - only for framework or bundle targets
858 cmXCodeObject* resourceBuildPhase = 0;
859 if (!resourceFiles.empty() && (isFrameworkTarget || isBundleTarget))
861 resourceBuildPhase =
862 this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
863 resourceBuildPhase->SetComment("Resources");
864 resourceBuildPhase->AddAttribute("buildActionMask",
865 this->CreateString("2147483647"));
866 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
867 for(std::vector<cmXCodeObject*>::iterator i = resourceFiles.begin();
868 i != resourceFiles.end(); ++i)
870 buildFiles->AddObject(*i);
872 resourceBuildPhase->AddAttribute("files", buildFiles);
873 resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
874 this->CreateString("0"));
877 // create vector of "non-resource content file" build phases - only for
878 // framework or bundle targets
879 std::vector<cmXCodeObject*> contentBuildPhases;
880 if (isFrameworkTarget || isBundleTarget)
882 typedef std::map<cmStdString, std::vector<cmSourceFile*> >
883 mapOfVectorOfSourceFiles;
884 mapOfVectorOfSourceFiles bundleFiles;
885 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
886 i != classes.end(); ++i)
888 cmTarget::SourceFileFlags tsFlags =
889 cmtarget.GetTargetSourceFileFlags(*i);
890 if(tsFlags.Type == cmTarget::SourceFileTypeMacContent)
892 bundleFiles[tsFlags.MacFolder].push_back(*i);
895 mapOfVectorOfSourceFiles::iterator mit;
896 for ( mit = bundleFiles.begin(); mit != bundleFiles.end(); ++ mit )
898 cmXCodeObject* copyFilesBuildPhase =
899 this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
900 copyFilesBuildPhase->SetComment("Copy files");
901 copyFilesBuildPhase->AddAttribute("buildActionMask",
902 this->CreateString("2147483647"));
903 copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
904 this->CreateString("6"));
905 cmOStringStream ostr;
906 if (cmtarget.IsFrameworkOnApple())
908 // dstPath in frameworks is relative to Versions/<version>
909 ostr << mit->first;
911 else if ( mit->first != "MacOS" )
913 // dstPath in bundles is relative to Contents/MacOS
914 ostr << "../" << mit->first.c_str();
916 copyFilesBuildPhase->AddAttribute("dstPath",
917 this->CreateString(ostr.str().c_str()));
918 copyFilesBuildPhase->AddAttribute(
919 "runOnlyForDeploymentPostprocessing", this->CreateString("0"));
920 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
921 copyFilesBuildPhase->AddAttribute("files", buildFiles);
922 std::vector<cmSourceFile*>::iterator sfIt;
923 for ( sfIt = mit->second.begin(); sfIt != mit->second.end(); ++ sfIt )
925 cmXCodeObject* xsf =
926 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
927 *sfIt, cmtarget);
928 buildFiles->AddObject(xsf);
930 contentBuildPhases.push_back(copyFilesBuildPhase);
934 // create framework build phase
935 cmXCodeObject* frameworkBuildPhase = 0;
936 if (!externalObjFiles.empty())
938 frameworkBuildPhase =
939 this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
940 frameworkBuildPhase->SetComment("Frameworks");
941 frameworkBuildPhase->AddAttribute("buildActionMask",
942 this->CreateString("2147483647"));
943 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
944 frameworkBuildPhase->AddAttribute("files", buildFiles);
945 for(std::vector<cmXCodeObject*>::iterator i = externalObjFiles.begin();
946 i != externalObjFiles.end(); ++i)
948 buildFiles->AddObject(*i);
950 frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
951 this->CreateString("0"));
954 // create list of build phases and create the XCode target
955 cmXCodeObject* buildPhases =
956 this->CreateObject(cmXCodeObject::OBJECT_LIST);
958 this->CreateCustomCommands(buildPhases, sourceBuildPhase,
959 headerBuildPhase, resourceBuildPhase,
960 contentBuildPhases,
961 frameworkBuildPhase, cmtarget);
963 targets.push_back(this->CreateXCodeTarget(cmtarget, buildPhases));
967 //----------------------------------------------------------------------------
968 void cmGlobalXCodeGenerator::ForceLinkerLanguages()
970 // This makes sure all targets link using the proper language.
971 for(std::map<cmStdString, cmTarget*>::const_iterator
972 ti = this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti)
974 this->ForceLinkerLanguage(*ti->second);
978 //----------------------------------------------------------------------------
979 void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget)
981 // This matters only for targets that link.
982 if(cmtarget.GetType() != cmTarget::EXECUTABLE &&
983 cmtarget.GetType() != cmTarget::SHARED_LIBRARY &&
984 cmtarget.GetType() != cmTarget::MODULE_LIBRARY)
986 return;
989 const char* llang = cmtarget.GetLinkerLanguage("NOCONFIG");
990 if(!llang) { return; }
992 // If the language is compiled as a source trust Xcode to link with it.
993 cmTarget::LinkImplementation const* impl =
994 cmtarget.GetLinkImplementation("NOCONFIG");
995 for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
996 li != impl->Languages.end(); ++li)
998 if(*li == llang) { return; }
1001 // Add an empty source file to the target that compiles with the
1002 // linker language. This should convince Xcode to choose the proper
1003 // language.
1004 cmMakefile* mf = cmtarget.GetMakefile();
1005 std::string fname = mf->GetCurrentOutputDirectory();
1006 fname += cmake::GetCMakeFilesDirectory();
1007 fname += "/";
1008 fname += cmtarget.GetName();
1009 fname += "-CMakeForceLinker";
1010 fname += ".";
1011 fname += cmSystemTools::LowerCase(llang);
1013 cmGeneratedFileStream fout(fname.c_str());
1014 fout << "\n";
1016 if(cmSourceFile* sf = mf->GetOrCreateSource(fname.c_str()))
1018 sf->SetProperty("LANGUAGE", llang);
1019 cmtarget.AddSourceFile(sf);
1023 //----------------------------------------------------------------------------
1024 bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf)
1026 const std::vector<std::string>& hdrExts =
1027 this->CurrentMakefile->GetHeaderExtensions();
1028 return (std::find(hdrExts.begin(), hdrExts.end(), sf->GetExtension()) !=
1029 hdrExts.end());
1032 //----------------------------------------------------------------------------
1033 cmXCodeObject*
1034 cmGlobalXCodeGenerator::CreateBuildPhase(const char* name,
1035 const char* name2,
1036 cmTarget& cmtarget,
1037 const std::vector<cmCustomCommand>&
1038 commands)
1040 if(commands.size() == 0 && strcmp(name, "CMake ReRun") != 0)
1042 return 0;
1044 cmXCodeObject* buildPhase =
1045 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
1046 buildPhase->AddAttribute("buildActionMask",
1047 this->CreateString("2147483647"));
1048 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1049 buildPhase->AddAttribute("files", buildFiles);
1050 buildPhase->AddAttribute("name",
1051 this->CreateString(name));
1052 buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1053 this->CreateString("0"));
1054 buildPhase->AddAttribute("shellPath",
1055 this->CreateString("/bin/sh"));
1056 this->AddCommandsToBuildPhase(buildPhase, cmtarget, commands,
1057 name2);
1058 return buildPhase;
1061 //----------------------------------------------------------------------------
1062 void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases,
1063 cmXCodeObject*
1064 sourceBuildPhase,
1065 cmXCodeObject*
1066 headerBuildPhase,
1067 cmXCodeObject*
1068 resourceBuildPhase,
1069 std::vector<cmXCodeObject*>
1070 contentBuildPhases,
1071 cmXCodeObject*
1072 frameworkBuildPhase,
1073 cmTarget& cmtarget)
1075 std::vector<cmCustomCommand> const & prebuild
1076 = cmtarget.GetPreBuildCommands();
1077 std::vector<cmCustomCommand> const & prelink
1078 = cmtarget.GetPreLinkCommands();
1079 std::vector<cmCustomCommand> const & postbuild
1080 = cmtarget.GetPostBuildCommands();
1081 std::vector<cmSourceFile*>const &classes = cmtarget.GetSourceFiles();
1082 // add all the sources
1083 std::vector<cmCustomCommand> commands;
1084 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
1085 i != classes.end(); ++i)
1087 if((*i)->GetCustomCommand())
1089 commands.push_back(*(*i)->GetCustomCommand());
1092 std::vector<cmCustomCommand> reruncom;
1093 cmXCodeObject* cmakeReRunPhase =
1094 this->CreateBuildPhase("CMake ReRun", "cmakeReRunPhase",
1095 cmtarget, reruncom);
1096 buildPhases->AddObject(cmakeReRunPhase);
1097 // create prebuild phase
1098 cmXCodeObject* cmakeRulesBuildPhase =
1099 this->CreateBuildPhase("CMake Rules",
1100 "cmakeRulesBuildPhase",
1101 cmtarget, commands);
1102 // create prebuild phase
1103 cmXCodeObject* preBuildPhase =
1104 this->CreateBuildPhase("CMake PreBuild Rules", "preBuildCommands",
1105 cmtarget, prebuild);
1106 // create prelink phase
1107 cmXCodeObject* preLinkPhase =
1108 this->CreateBuildPhase("CMake PreLink Rules", "preLinkCommands",
1109 cmtarget, prelink);
1110 // create postbuild phase
1111 cmXCodeObject* postBuildPhase =
1112 this->CreateBuildPhase("CMake PostBuild Rules", "postBuildPhase",
1113 cmtarget, postbuild);
1115 // The order here is the order they will be built in.
1116 // The order "headers, resources, sources" mimics a native project generated
1117 // from an xcode template...
1119 if(preBuildPhase)
1121 buildPhases->AddObject(preBuildPhase);
1123 if(cmakeRulesBuildPhase)
1125 buildPhases->AddObject(cmakeRulesBuildPhase);
1127 if(headerBuildPhase)
1129 buildPhases->AddObject(headerBuildPhase);
1131 if(resourceBuildPhase)
1133 buildPhases->AddObject(resourceBuildPhase);
1135 std::vector<cmXCodeObject*>::iterator cit;
1136 for (cit = contentBuildPhases.begin(); cit != contentBuildPhases.end();
1137 ++cit)
1139 buildPhases->AddObject(*cit);
1141 if(sourceBuildPhase)
1143 buildPhases->AddObject(sourceBuildPhase);
1145 if(preLinkPhase)
1147 buildPhases->AddObject(preLinkPhase);
1149 if(frameworkBuildPhase)
1151 buildPhases->AddObject(frameworkBuildPhase);
1153 if(postBuildPhase)
1155 buildPhases->AddObject(postBuildPhase);
1159 //----------------------------------------------------------------------------
1160 std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
1161 std::string& flags)
1163 std::string retFlag;
1164 std::string::size_type pos = flags.find(flag);
1165 if(pos != flags.npos && (pos ==0 || flags[pos-1]==' '))
1167 while(pos < flags.size() && flags[pos] != ' ')
1169 retFlag += flags[pos];
1170 flags[pos] = ' ';
1171 pos++;
1174 return retFlag;
1177 //----------------------------------------------------------------------------
1178 void
1179 cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
1180 cmTarget& target,
1181 std::vector<cmCustomCommand>
1182 const & commands,
1183 const char* name)
1185 if(strcmp(name, "cmakeReRunPhase") == 0)
1187 std::string cdir = this->CurrentMakefile->GetHomeOutputDirectory();
1188 cdir = this->ConvertToRelativeForMake(cdir.c_str());
1189 std::string makecmd = "make -C ";
1190 makecmd += cdir;
1191 makecmd += " -f ";
1192 makecmd +=
1193 this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str());
1194 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1195 buildphase->AddAttribute("shellScript",
1196 this->CreateString(makecmd.c_str()));
1197 return;
1200 // collect multiple outputs of custom commands into a set
1201 // which will be used for every configuration
1202 std::map<cmStdString, cmStdString> multipleOutputPairs;
1203 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1204 i != commands.end(); ++i)
1206 cmCustomCommand const& cc = *i;
1207 if(!cc.GetCommandLines().empty())
1209 const std::vector<std::string>& outputs = cc.GetOutputs();
1210 if(!outputs.empty())
1212 // If there are more than one outputs treat the
1213 // first as the primary output and make the rest depend on it.
1214 std::vector<std::string>::const_iterator o = outputs.begin();
1215 std::string primaryOutput = this->ConvertToRelativeForMake(o->c_str());
1216 for(++o; o != outputs.end(); ++o)
1218 std::string currentOutput=this->ConvertToRelativeForMake(o->c_str());
1219 multipleOutputPairs[currentOutput] = primaryOutput;
1225 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
1226 dir += "/CMakeScripts";
1227 cmSystemTools::MakeDirectory(dir.c_str());
1228 std::string makefile = dir;
1229 makefile += "/";
1230 makefile += target.GetName();
1231 makefile += "_";
1232 makefile += name;
1233 makefile += ".make";
1235 for (std::vector<std::string>::const_iterator currentConfig=
1236 this->CurrentConfigurationTypes.begin();
1237 currentConfig!=this->CurrentConfigurationTypes.end();
1238 currentConfig++ )
1240 this->CreateCustomRulesMakefile(makefile.c_str(),
1241 target,
1242 commands,
1243 currentConfig->c_str(),
1244 multipleOutputPairs);
1247 std::string cdir = this->CurrentMakefile->GetCurrentOutputDirectory();
1248 cdir = this->ConvertToRelativeForXCode(cdir.c_str());
1249 std::string makecmd = "make -C ";
1250 makecmd += cdir;
1251 makecmd += " -f ";
1252 makecmd += this->ConvertToRelativeForMake(
1253 (makefile+"$CONFIGURATION").c_str());
1254 if(!multipleOutputPairs.empty())
1256 makecmd += " cmake_check_multiple_outputs";
1258 makecmd += " all";
1259 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1260 buildphase->AddAttribute("shellScript",
1261 this->CreateString(makecmd.c_str()));
1264 //----------------------------------------------------------------------------
1265 void cmGlobalXCodeGenerator
1266 ::CreateCustomRulesMakefile(const char* makefileBasename,
1267 cmTarget& target,
1268 std::vector<cmCustomCommand>
1269 const & commands,
1270 const char* configName,
1271 const std::map<cmStdString,
1272 cmStdString>& multipleOutputPairs
1275 std::string makefileName=makefileBasename;
1276 makefileName+=configName;
1277 cmGeneratedFileStream makefileStream(makefileName.c_str());
1278 if(!makefileStream)
1280 return;
1282 makefileStream.SetCopyIfDifferent(true);
1283 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
1284 makefileStream << "# Custom rules for " << target.GetName() << "\n";
1286 // have all depend on all outputs
1287 makefileStream << "all: ";
1288 std::map<const cmCustomCommand*, cmStdString> tname;
1289 int count = 0;
1290 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1291 i != commands.end(); ++i)
1293 cmCustomCommand const& cc = *i;
1294 if(!cc.GetCommandLines().empty())
1296 const std::vector<std::string>& outputs = cc.GetOutputs();
1297 if(!outputs.empty())
1299 for(std::vector<std::string>::const_iterator o = outputs.begin();
1300 o != outputs.end(); ++o)
1302 makefileStream
1303 << "\\\n\t" << this->ConvertToRelativeForMake(o->c_str());
1306 else
1308 cmOStringStream str;
1309 str << "_buildpart_" << count++ ;
1310 tname[&cc] = std::string(target.GetName()) + str.str();
1311 makefileStream << "\\\n\t" << tname[&cc];
1315 makefileStream << "\n\n";
1316 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1317 i != commands.end(); ++i)
1319 cmCustomCommand const& cc = *i;
1320 if(!cc.GetCommandLines().empty())
1322 bool escapeOldStyle = cc.GetEscapeOldStyle();
1323 bool escapeAllowMakeVars = cc.GetEscapeAllowMakeVars();
1324 makefileStream << "\n";
1325 const std::vector<std::string>& outputs = cc.GetOutputs();
1326 if(!outputs.empty())
1328 // There is at least one output, start the rule for it
1329 std::string primary_output =
1330 this->ConvertToRelativeForMake(outputs.begin()->c_str());
1331 makefileStream << primary_output << ": ";
1333 else
1335 // There are no outputs. Use the generated force rule name.
1336 makefileStream << tname[&cc] << ": ";
1338 for(std::vector<std::string>::const_iterator d =
1339 cc.GetDepends().begin();
1340 d != cc.GetDepends().end(); ++d)
1342 std::string dep =
1343 this->CurrentLocalGenerator->GetRealDependency(d->c_str(),
1344 configName);
1345 makefileStream << "\\\n" << this
1346 ->ConvertToRelativeForMake(dep.c_str());
1348 makefileStream << "\n";
1350 if(const char* comment = cc.GetComment())
1352 std::string echo_cmd = "echo ";
1353 echo_cmd += (this->CurrentLocalGenerator->
1354 EscapeForShell(comment, escapeAllowMakeVars));
1355 makefileStream << "\t" << echo_cmd.c_str() << "\n";
1358 // Add each command line to the set of commands.
1359 for(cmCustomCommandLines::const_iterator cl =
1360 cc.GetCommandLines().begin();
1361 cl != cc.GetCommandLines().end(); ++cl)
1363 // Build the command line in a single string.
1364 const cmCustomCommandLine& commandLine = *cl;
1365 std::string cmd2 = this->CurrentLocalGenerator
1366 ->GetRealLocation(commandLine[0].c_str(), configName);
1368 cmSystemTools::ReplaceString(cmd2, "/./", "/");
1369 cmd2 = this->ConvertToRelativeForMake(cmd2.c_str());
1370 std::string cmd;
1371 if(cc.GetWorkingDirectory())
1373 cmd += "cd ";
1374 cmd += this->ConvertToRelativeForMake(cc.GetWorkingDirectory());
1375 cmd += " && ";
1377 cmd += cmd2;
1378 for(unsigned int j=1; j < commandLine.size(); ++j)
1380 cmd += " ";
1381 if(escapeOldStyle)
1383 cmd += (this->CurrentLocalGenerator
1384 ->EscapeForShellOldStyle(commandLine[j].c_str()));
1386 else
1388 cmd += (this->CurrentLocalGenerator->
1389 EscapeForShell(commandLine[j].c_str(),
1390 escapeAllowMakeVars));
1393 makefileStream << "\t" << cmd.c_str() << "\n";
1398 // Add rules to deal with multiple outputs of custom commands.
1399 if(!multipleOutputPairs.empty())
1401 makefileStream <<
1402 "\n# Dependencies of multiple outputs to their primary outputs \n";
1404 for(std::map<cmStdString, cmStdString>::const_iterator o =
1405 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1407 makefileStream << o->first << ": " << o->second << "\n";
1410 makefileStream <<
1411 "\n"
1412 "cmake_check_multiple_outputs:\n";
1413 for(std::map<cmStdString, cmStdString>::const_iterator o =
1414 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1416 makefileStream << "\t@if [ ! -f "
1417 << o->first << " ]; then rm -f "
1418 << o->second << "; fi\n";
1423 //----------------------------------------------------------------------------
1424 void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
1425 cmXCodeObject* buildSettings,
1426 const char* configName)
1428 std::string flags;
1429 std::string defFlags;
1430 bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
1431 (target.GetType() == cmTarget::MODULE_LIBRARY));
1433 const char* lang = target.GetLinkerLanguage(configName);
1434 std::string cflags;
1435 if(lang)
1437 // for c++ projects get the c flags as well
1438 if(strcmp(lang, "CXX") == 0)
1440 this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName);
1441 this->CurrentLocalGenerator->AddSharedFlags(cflags, lang, shared);
1444 // Add language-specific flags.
1445 this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName);
1447 // Add shared-library flags if needed.
1448 this->CurrentLocalGenerator->AddSharedFlags(flags, lang, shared);
1451 // Add define flags
1452 this->CurrentLocalGenerator->
1453 AppendFlags(defFlags,
1454 this->CurrentMakefile->GetDefineFlags());
1456 // Add preprocessor definitions for this target and configuration.
1457 BuildObjectListOrString ppDefs(this, this->XcodeVersion >= 30);
1458 if(this->XcodeVersion > 15)
1460 this->AppendDefines(ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)\"");
1462 if(const char* exportMacro = target.GetExportMacro())
1464 // Add the export symbol definition for shared library objects.
1465 this->AppendDefines(ppDefs, exportMacro);
1467 this->AppendDefines
1468 (ppDefs, this->CurrentMakefile->GetProperty("COMPILE_DEFINITIONS"));
1469 this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS"));
1470 if(configName)
1472 std::string defVarName = "COMPILE_DEFINITIONS_";
1473 defVarName += cmSystemTools::UpperCase(configName);
1474 this->AppendDefines
1475 (ppDefs, this->CurrentMakefile->GetProperty(defVarName.c_str()));
1476 this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str()));
1478 buildSettings->AddAttribute
1479 ("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList());
1481 std::string extraLinkOptions;
1482 if(target.GetType() == cmTarget::EXECUTABLE)
1484 extraLinkOptions =
1485 this->CurrentMakefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
1486 std::string var = "CMAKE_EXE_LINKER_FLAGS_";
1487 var += cmSystemTools::UpperCase(configName);
1488 std::string val =
1489 this->CurrentMakefile->GetSafeDefinition(var.c_str());
1490 if(val.size())
1492 extraLinkOptions += " ";
1493 extraLinkOptions += val;
1496 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1498 extraLinkOptions = this->CurrentMakefile->
1499 GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
1501 if(target.GetType() == cmTarget::MODULE_LIBRARY)
1503 extraLinkOptions = this->CurrentMakefile->
1504 GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
1507 const char* targetLinkFlags = target.GetProperty("LINK_FLAGS");
1508 if(targetLinkFlags)
1510 extraLinkOptions += " ";
1511 extraLinkOptions += targetLinkFlags;
1514 // Get the product name components.
1515 std::string pnprefix;
1516 std::string pnbase;
1517 std::string pnsuffix;
1518 target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
1520 // Store the product name for all target types.
1521 buildSettings->AddAttribute("PRODUCT_NAME",
1522 this->CreateString(pnbase.c_str()));
1524 // Set attributes to specify the proper name for the target.
1525 if(target.GetType() == cmTarget::STATIC_LIBRARY ||
1526 target.GetType() == cmTarget::SHARED_LIBRARY ||
1527 target.GetType() == cmTarget::MODULE_LIBRARY ||
1528 target.GetType() == cmTarget::EXECUTABLE)
1530 std::string pndir = target.GetDirectory();
1531 buildSettings->AddAttribute("SYMROOT",
1532 this->CreateString(pndir.c_str()));
1533 buildSettings->AddAttribute("EXECUTABLE_PREFIX",
1534 this->CreateString(pnprefix.c_str()));
1535 buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
1536 this->CreateString(pnsuffix.c_str()));
1539 // Handle settings for each target type.
1540 switch(target.GetType())
1542 case cmTarget::STATIC_LIBRARY:
1544 buildSettings->AddAttribute("LIBRARY_STYLE",
1545 this->CreateString("STATIC"));
1546 break;
1549 case cmTarget::MODULE_LIBRARY:
1551 buildSettings->AddAttribute("LIBRARY_STYLE",
1552 this->CreateString("BUNDLE"));
1553 if(this->XcodeVersion >= 22)
1555 buildSettings->AddAttribute("MACH_O_TYPE",
1556 this->CreateString("mh_bundle"));
1557 buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
1558 this->CreateString("NO"));
1559 // Add the flags to create an executable.
1560 std::string createFlags =
1561 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1562 if(!createFlags.empty())
1564 extraLinkOptions += " ";
1565 extraLinkOptions += createFlags;
1568 else
1570 // Add the flags to create a module.
1571 std::string createFlags =
1572 this->LookupFlags("CMAKE_SHARED_MODULE_CREATE_", lang, "_FLAGS",
1573 "-bundle");
1574 if(!createFlags.empty())
1576 extraLinkOptions += " ";
1577 extraLinkOptions += createFlags;
1580 break;
1582 case cmTarget::SHARED_LIBRARY:
1584 if(target.GetPropertyAsBool("FRAMEWORK"))
1586 std::string version = target.GetFrameworkVersion();
1587 buildSettings->AddAttribute("FRAMEWORK_VERSION",
1588 this->CreateString(version.c_str()));
1590 std::string plist = this->ComputeInfoPListLocation(target);
1591 // Xcode will create the final version of Info.plist at build time,
1592 // so let it replace the framework name. This avoids creating
1593 // a per-configuration Info.plist file.
1594 this->CurrentLocalGenerator
1595 ->GenerateFrameworkInfoPList(&target, "$(EXECUTABLE_NAME)",
1596 plist.c_str());
1597 std::string path =
1598 this->ConvertToRelativeForXCode(plist.c_str());
1599 buildSettings->AddAttribute("INFOPLIST_FILE",
1600 this->CreateString(path.c_str()));
1602 else
1604 // Add the flags to create a shared library.
1605 std::string createFlags =
1606 this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", lang, "_FLAGS",
1607 "-dynamiclib");
1608 if(!createFlags.empty())
1610 extraLinkOptions += " ";
1611 extraLinkOptions += createFlags;
1615 buildSettings->AddAttribute("LIBRARY_STYLE",
1616 this->CreateString("DYNAMIC"));
1617 break;
1619 case cmTarget::EXECUTABLE:
1621 // Add the flags to create an executable.
1622 std::string createFlags =
1623 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1624 if(!createFlags.empty())
1626 extraLinkOptions += " ";
1627 extraLinkOptions += createFlags;
1630 // Handle bundles and normal executables separately.
1631 if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
1633 std::string plist = this->ComputeInfoPListLocation(target);
1634 // Xcode will create the final version of Info.plist at build time,
1635 // so let it replace the executable name. This avoids creating
1636 // a per-configuration Info.plist file.
1637 this->CurrentLocalGenerator
1638 ->GenerateAppleInfoPList(&target, "$(EXECUTABLE_NAME)",
1639 plist.c_str());
1640 std::string path =
1641 this->ConvertToRelativeForXCode(plist.c_str());
1642 buildSettings->AddAttribute("INFOPLIST_FILE",
1643 this->CreateString(path.c_str()));
1647 break;
1648 default:
1649 break;
1651 if(this->XcodeVersion >= 22)
1653 buildSettings->AddAttribute("PREBINDING",
1654 this->CreateString("NO"));
1657 BuildObjectListOrString dirs(this, this->XcodeVersion >= 30);
1658 BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30);
1659 std::vector<std::string> includes;
1660 this->CurrentLocalGenerator->GetIncludeDirectories(includes);
1661 std::set<cmStdString> emitted;
1662 emitted.insert("/System/Library/Frameworks");
1663 for(std::vector<std::string>::iterator i = includes.begin();
1664 i != includes.end(); ++i)
1666 if(this->NameResolvesToFramework(i->c_str()))
1668 std::string frameworkDir = *i;
1669 frameworkDir += "/../";
1670 frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str());
1671 if(emitted.insert(frameworkDir).second)
1673 fdirs.Add(this->XCodeEscapePath(frameworkDir.c_str()).c_str());
1676 else
1678 std::string incpath =
1679 this->XCodeEscapePath(i->c_str());
1680 dirs.Add(incpath.c_str());
1683 std::vector<std::string>& frameworks = target.GetFrameworks();
1684 if(frameworks.size())
1686 for(std::vector<std::string>::iterator fmIt = frameworks.begin();
1687 fmIt != frameworks.end(); ++fmIt)
1689 if(emitted.insert(*fmIt).second)
1691 fdirs.Add(this->XCodeEscapePath(fmIt->c_str()).c_str());
1695 if(!fdirs.IsEmpty())
1697 buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS",
1698 fdirs.CreateList());
1700 if(!dirs.IsEmpty())
1702 buildSettings->AddAttribute("HEADER_SEARCH_PATHS",
1703 dirs.CreateList());
1705 std::string oflagc = this->ExtractFlag("-O", cflags);
1706 char optLevel[2];
1707 optLevel[0] = '0';
1708 optLevel[1] = 0;
1709 if(oflagc.size() == 3)
1711 optLevel[0] = oflagc[2];
1713 if(oflagc.size() == 2)
1715 optLevel[0] = '1';
1717 std::string oflag = this->ExtractFlag("-O", flags);
1718 if(oflag.size() == 3)
1720 optLevel[0] = oflag[2];
1722 if(oflag.size() == 2)
1724 optLevel[0] = '1';
1726 std::string gflagc = this->ExtractFlag("-g", cflags);
1727 // put back gdwarf-2 if used since there is no way
1728 // to represent it in the gui, but we still want debug yes
1729 if(gflagc == "-gdwarf-2")
1731 cflags += " ";
1732 cflags += gflagc;
1734 std::string gflag = this->ExtractFlag("-g", flags);
1735 if(gflag == "-gdwarf-2")
1737 flags += " ";
1738 flags += gflag;
1740 const char* debugStr = "YES";
1741 if(gflagc.size() ==0 && gflag.size() == 0)
1743 debugStr = "NO";
1746 buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
1747 this->CreateString(debugStr));
1748 buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
1749 this->CreateString(optLevel));
1750 buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
1751 this->CreateString("NO"));
1752 buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
1753 this->CreateString("NO"));
1754 if(lang && strcmp(lang, "CXX") == 0)
1756 flags += " ";
1757 flags += defFlags;
1758 buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
1759 this->CreateString(flags.c_str()));
1760 cflags += " ";
1761 cflags += defFlags;
1762 buildSettings->AddAttribute("OTHER_CFLAGS",
1763 this->CreateString(cflags.c_str()));
1766 else
1768 flags += " ";
1769 flags += defFlags;
1770 buildSettings->AddAttribute("OTHER_CFLAGS",
1771 this->CreateString(flags.c_str()));
1774 // Create the INSTALL_PATH attribute.
1775 std::string install_name_dir;
1776 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1778 // Get the install_name directory for the build tree.
1779 install_name_dir = target.GetInstallNameDirForBuildTree(configName, true);
1780 if(install_name_dir.empty())
1782 // Xcode will not pass the -install_name option at all if INSTALL_PATH
1783 // is not given or is empty. We must explicitly put the flag in the
1784 // link flags to create an install_name with just the library soname.
1785 extraLinkOptions += " -install_name ";
1786 extraLinkOptions += target.GetFullName(configName);
1788 else
1790 // Convert to a path for the native build tool.
1791 cmSystemTools::ConvertToUnixSlashes(install_name_dir);
1792 // do not escape spaces on this since it is only a single path
1795 buildSettings->AddAttribute("INSTALL_PATH",
1796 this->CreateString(install_name_dir.c_str()));
1798 buildSettings->AddAttribute("OTHER_LDFLAGS",
1799 this->CreateString(extraLinkOptions.c_str()));
1800 buildSettings->AddAttribute("OTHER_REZFLAGS",
1801 this->CreateString(""));
1802 buildSettings->AddAttribute("SECTORDER_FLAGS",
1803 this->CreateString(""));
1804 buildSettings->AddAttribute("USE_HEADERMAP",
1805 this->CreateString("NO"));
1806 if (this->XcodeVersion >= 30)
1808 cmXCodeObject *group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1809 group->AddObject(this->CreateString("-Wmost"));
1810 group->AddObject(this->CreateString("-Wno-four-char-constants"));
1811 group->AddObject(this->CreateString("-Wno-unknown-pragmas"));
1812 buildSettings->AddAttribute("WARNING_CFLAGS", group);
1814 else
1816 buildSettings->AddAttribute("WARNING_CFLAGS",
1817 this->CreateString(
1818 "-Wmost -Wno-four-char-constants"
1819 " -Wno-unknown-pragmas"));
1822 // Runtime version information.
1823 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1825 int major;
1826 int minor;
1827 int patch;
1829 // VERSION -> current_version
1830 target.GetTargetVersion(false, major, minor, patch);
1831 if(major == 0 && minor == 0 && patch == 0)
1833 // Xcode always wants at least 1.0.0
1834 major = 1;
1836 cmOStringStream v;
1837 v << major << "." << minor << "." << patch;
1838 buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
1839 this->CreateString(v.str().c_str()));
1841 // SOVERSION -> compatibility_version
1842 target.GetTargetVersion(true, major, minor, patch);
1843 if(major == 0 && minor == 0 && patch == 0)
1845 // Xcode always wants at least 1.0.0
1846 major = 1;
1848 cmOStringStream vso;
1849 vso << major << "." << minor << "." << patch;
1850 buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
1851 this->CreateString(vso.str().c_str()));
1853 // put this last so it can override existing settings
1854 // Convert "XCODE_ATTRIBUTE_*" properties directly.
1856 cmPropertyMap const& props = target.GetProperties();
1857 for(cmPropertyMap::const_iterator i = props.begin();
1858 i != props.end(); ++i)
1860 if(i->first.find("XCODE_ATTRIBUTE_") == 0)
1862 buildSettings->AddAttribute(i->first.substr(16).c_str(),
1863 this->CreateString(i->second.GetValue()));
1869 //----------------------------------------------------------------------------
1870 cmXCodeObject*
1871 cmGlobalXCodeGenerator::CreateUtilityTarget(cmTarget& cmtarget)
1873 cmXCodeObject* shellBuildPhase =
1874 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
1875 shellBuildPhase->AddAttribute("buildActionMask",
1876 this->CreateString("2147483647"));
1877 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1878 shellBuildPhase->AddAttribute("files", buildFiles);
1879 cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1880 shellBuildPhase->AddAttribute("inputPaths", inputPaths);
1881 cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1882 shellBuildPhase->AddAttribute("outputPaths", outputPaths);
1883 shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1884 this->CreateString("0"));
1885 shellBuildPhase->AddAttribute("shellPath",
1886 this->CreateString("/bin/sh"));
1887 shellBuildPhase->AddAttribute("shellScript",
1888 this->CreateString(
1889 "# shell script goes here\nexit 0"));
1890 cmXCodeObject* target =
1891 this->CreateObject(cmXCodeObject::PBXAggregateTarget);
1892 target->SetComment(cmtarget.GetName());
1893 cmXCodeObject* buildPhases =
1894 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1895 std::vector<cmXCodeObject*> emptyContentVector;
1896 this->CreateCustomCommands(buildPhases, 0, 0, 0, emptyContentVector, 0,
1897 cmtarget);
1898 target->AddAttribute("buildPhases", buildPhases);
1899 if(this->XcodeVersion > 20)
1901 this->AddConfigurations(target, cmtarget);
1903 else
1905 const char* theConfig =
1906 this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
1907 cmXCodeObject* buildSettings =
1908 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1909 this->CreateBuildSettings(cmtarget, buildSettings, theConfig);
1910 target->AddAttribute("buildSettings", buildSettings);
1912 cmXCodeObject* dependencies =
1913 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1914 target->AddAttribute("dependencies", dependencies);
1915 target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
1916 target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
1917 target->SetTarget(&cmtarget);
1919 // Add source files without build rules for editing convenience.
1920 if(cmtarget.GetType() == cmTarget::UTILITY)
1922 std::vector<cmSourceFile*> const& sources = cmtarget.GetSourceFiles();
1923 for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
1924 i != sources.end(); ++i)
1926 if(!(*i)->GetPropertyAsBool("GENERATED"))
1928 this->CreateXCodeFileReference(*i, cmtarget);
1933 return target;
1936 //----------------------------------------------------------------------------
1937 std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
1938 cmTarget& cmtarget)
1940 std::string configTypes =
1941 this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
1942 std::vector<std::string> configVectorIn;
1943 std::vector<std::string> configVector;
1944 configVectorIn.push_back(configTypes);
1945 cmSystemTools::ExpandList(configVectorIn, configVector);
1946 cmXCodeObject* configlist =
1947 this->CreateObject(cmXCodeObject::XCConfigurationList);
1948 cmXCodeObject* buildConfigurations =
1949 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1950 configlist->AddAttribute("buildConfigurations", buildConfigurations);
1951 std::string comment = "Build configuration list for ";
1952 comment += cmXCodeObject::PBXTypeNames[target->GetIsA()];
1953 comment += " \"";
1954 comment += cmtarget.GetName();
1955 comment += "\"";
1956 configlist->SetComment(comment.c_str());
1957 target->AddAttribute("buildConfigurationList",
1958 this->CreateObjectReference(configlist));
1959 for(unsigned int i = 0; i < configVector.size(); ++i)
1961 cmXCodeObject* config =
1962 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
1963 buildConfigurations->AddObject(config);
1964 cmXCodeObject* buildSettings =
1965 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1966 this->CreateBuildSettings(cmtarget, buildSettings,
1967 configVector[i].c_str());
1968 config->AddAttribute("name", this->CreateString(configVector[i].c_str()));
1969 config->SetComment(configVector[i].c_str());
1970 config->AddAttribute("buildSettings", buildSettings);
1972 if(configVector.size())
1974 configlist->AddAttribute("defaultConfigurationName",
1975 this->CreateString(configVector[0].c_str()));
1976 configlist->AddAttribute("defaultConfigurationIsVisible",
1977 this->CreateString("0"));
1978 return configVector[0];
1980 return "";
1983 //----------------------------------------------------------------------------
1984 const char* cmGlobalXCodeGenerator::GetTargetFileType(cmTarget& cmtarget)
1986 switch(cmtarget.GetType())
1988 case cmTarget::STATIC_LIBRARY:
1989 return "archive.ar";
1990 case cmTarget::MODULE_LIBRARY:
1991 return ((this->XcodeVersion >= 22)?
1992 "compiled.mach-o.executable" : "compiled.mach-o.dylib");
1993 case cmTarget::SHARED_LIBRARY:
1994 return (cmtarget.GetPropertyAsBool("FRAMEWORK")?
1995 "wrapper.framework" : "compiled.mach-o.dylib");
1996 case cmTarget::EXECUTABLE:
1997 return "compiled.mach-o.executable";
1998 default: break;
2000 return 0;
2003 //----------------------------------------------------------------------------
2004 const char* cmGlobalXCodeGenerator::GetTargetProductType(cmTarget& cmtarget)
2006 switch(cmtarget.GetType())
2008 case cmTarget::STATIC_LIBRARY:
2009 return "com.apple.product-type.library.static";
2010 case cmTarget::MODULE_LIBRARY:
2011 return ((this->XcodeVersion >= 22)? "com.apple.product-type.tool" :
2012 "com.apple.product-type.library.dynamic");
2013 case cmTarget::SHARED_LIBRARY:
2014 return (cmtarget.GetPropertyAsBool("FRAMEWORK")?
2015 "com.apple.product-type.framework" :
2016 "com.apple.product-type.library.dynamic");
2017 case cmTarget::EXECUTABLE:
2018 return (cmtarget.GetPropertyAsBool("MACOSX_BUNDLE")?
2019 "com.apple.product-type.application" :
2020 "com.apple.product-type.tool");
2021 default: break;
2023 return 0;
2026 //----------------------------------------------------------------------------
2027 cmXCodeObject*
2028 cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
2029 cmXCodeObject* buildPhases)
2031 cmXCodeObject* target =
2032 this->CreateObject(cmXCodeObject::PBXNativeTarget);
2033 target->AddAttribute("buildPhases", buildPhases);
2034 cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2035 target->AddAttribute("buildRules", buildRules);
2036 std::string defConfig;
2037 if(this->XcodeVersion > 20)
2039 defConfig = this->AddConfigurations(target, cmtarget);
2041 else
2043 cmXCodeObject* buildSettings =
2044 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2045 defConfig = this->CurrentMakefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
2046 this->CreateBuildSettings(cmtarget, buildSettings, defConfig.c_str());
2047 target->AddAttribute("buildSettings", buildSettings);
2049 cmXCodeObject* dependencies =
2050 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2051 target->AddAttribute("dependencies", dependencies);
2052 target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
2053 target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
2055 cmXCodeObject* fileRef =
2056 this->CreateObject(cmXCodeObject::PBXFileReference);
2057 if(const char* fileType = this->GetTargetFileType(cmtarget))
2059 fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
2061 std::string fullName = cmtarget.GetFullName(defConfig.c_str());
2062 fileRef->AddAttribute("path", this->CreateString(fullName.c_str()));
2063 fileRef->AddAttribute("refType", this->CreateString("0"));
2064 fileRef->AddAttribute("sourceTree",
2065 this->CreateString("BUILT_PRODUCTS_DIR"));
2066 fileRef->SetComment(cmtarget.GetName());
2067 target->AddAttribute("productReference",
2068 this->CreateObjectReference(fileRef));
2069 if(const char* productType = this->GetTargetProductType(cmtarget))
2071 target->AddAttribute("productType", this->CreateString(productType));
2073 target->SetTarget(&cmtarget);
2074 return target;
2077 //----------------------------------------------------------------------------
2078 cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
2080 if(!t)
2082 return 0;
2084 for(std::vector<cmXCodeObject*>::iterator i = this->XCodeObjects.begin();
2085 i != this->XCodeObjects.end(); ++i)
2087 cmXCodeObject* o = *i;
2088 if(o->GetTarget() == t)
2090 return o;
2093 return 0;
2096 //----------------------------------------------------------------------------
2097 void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
2098 cmXCodeObject* dependTarget)
2100 // make sure a target does not depend on itself
2101 if(target == dependTarget)
2103 return;
2105 // now avoid circular references if dependTarget already
2106 // depends on target then skip it. Circular references crashes
2107 // xcode
2108 cmXCodeObject* dependTargetDepends =
2109 dependTarget->GetObject("dependencies");
2110 if(dependTargetDepends)
2112 if(dependTargetDepends->HasObject(target->GetPBXTargetDependency()))
2114 return;
2118 cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency();
2119 if(!targetdep)
2121 cmXCodeObject* container =
2122 this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
2123 container->SetComment("PBXContainerItemProxy");
2124 container->AddAttribute("containerPortal",
2125 this->CreateObjectReference(this->RootObject));
2126 container->AddAttribute("proxyType", this->CreateString("1"));
2127 container->AddAttribute("remoteGlobalIDString",
2128 this->CreateObjectReference(dependTarget));
2129 container->AddAttribute("remoteInfo",
2130 this->CreateString(
2131 dependTarget->GetTarget()->GetName()));
2132 targetdep =
2133 this->CreateObject(cmXCodeObject::PBXTargetDependency);
2134 targetdep->SetComment("PBXTargetDependency");
2135 targetdep->AddAttribute("target",
2136 this->CreateObjectReference(dependTarget));
2137 targetdep->AddAttribute("targetProxy",
2138 this->CreateObjectReference(container));
2139 dependTarget->SetPBXTargetDependency(targetdep);
2142 cmXCodeObject* depends = target->GetObject("dependencies");
2143 if(!depends)
2145 cmSystemTools::
2146 Error("target does not have dependencies attribute error..");
2149 else
2151 depends->AddUniqueObject(targetdep);
2155 //----------------------------------------------------------------------------
2156 void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
2157 const char* attribute,
2158 const char* value)
2160 if(settings)
2162 cmXCodeObject* attr = settings->GetObject(attribute);
2163 if(!attr)
2165 settings->AddAttribute(attribute, this->CreateString(value));
2167 else
2169 std::string oldValue = attr->GetString();
2170 oldValue += " ";
2171 oldValue += value;
2172 attr->SetString(oldValue.c_str());
2177 //----------------------------------------------------------------------------
2178 void cmGlobalXCodeGenerator
2179 ::AppendBuildSettingAttribute(cmXCodeObject* target,
2180 const char* attribute,
2181 const char* value,
2182 const char* configName)
2184 if(this->XcodeVersion < 21)
2186 // There is only one configuration. Add the setting to the buildSettings
2187 // of the target.
2188 this->AppendOrAddBuildSetting(target->GetObject("buildSettings"),
2189 attribute, value);
2191 else
2193 // There are multiple configurations. Add the setting to the
2194 // buildSettings of the configuration name given.
2195 cmXCodeObject* configurationList =
2196 target->GetObject("buildConfigurationList")->GetObject();
2197 cmXCodeObject* buildConfigs =
2198 configurationList->GetObject("buildConfigurations");
2199 std::vector<cmXCodeObject*> list = buildConfigs->GetObjectList();
2200 // each configuration and the target itself has a buildSettings in it
2201 //list.push_back(target);
2202 for(std::vector<cmXCodeObject*>::iterator i = list.begin();
2203 i != list.end(); ++i)
2205 if(configName)
2207 if(strcmp((*i)->GetObject("name")->GetString(), configName) == 0)
2209 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2210 this->AppendOrAddBuildSetting(settings, attribute, value);
2213 else
2215 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2216 this->AppendOrAddBuildSetting(settings, attribute, value);
2222 //----------------------------------------------------------------------------
2223 void cmGlobalXCodeGenerator
2224 ::AddDependAndLinkInformation(cmXCodeObject* target)
2226 cmTarget* cmtarget = target->GetTarget();
2227 if(!cmtarget)
2229 cmSystemTools::Error("Error no target on xobject\n");
2230 return;
2233 // Add dependencies on other CMake targets.
2234 TargetDependSet const& deps = this->GetTargetDirectDepends(*cmtarget);
2235 for(TargetDependSet::const_iterator i = deps.begin(); i != deps.end(); ++i)
2237 if(cmXCodeObject* dptarget = this->FindXCodeTarget(*i))
2239 this->AddDependTarget(target, dptarget);
2243 // Skip link information for static libraries.
2244 if(cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
2246 return;
2249 // Loop over configuration types and set per-configuration info.
2250 for(std::vector<std::string>::iterator i =
2251 this->CurrentConfigurationTypes.begin();
2252 i != this->CurrentConfigurationTypes.end(); ++i)
2254 // Get the current configuration name.
2255 const char* configName = i->c_str();
2256 if(!*configName)
2258 configName = 0;
2261 // Compute the link library and directory information.
2262 cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName);
2263 if(!pcli)
2265 continue;
2267 cmComputeLinkInformation& cli = *pcli;
2269 // Add dependencies directly on library files.
2271 std::vector<std::string> const& libDeps = cli.GetDepends();
2272 for(std::vector<std::string>::const_iterator j = libDeps.begin();
2273 j != libDeps.end(); ++j)
2275 target->AddDependLibrary(configName, j->c_str());
2279 // add the library search paths
2281 std::vector<std::string> const& libDirs = cli.GetDirectories();
2282 std::string linkDirs;
2283 for(std::vector<std::string>::const_iterator libDir = libDirs.begin();
2284 libDir != libDirs.end(); ++libDir)
2286 if(libDir->size() && *libDir != "/usr/lib")
2288 if(this->XcodeVersion > 15)
2290 // now add the same one but append $(CONFIGURATION) to it:
2291 linkDirs += " ";
2292 linkDirs += this->XCodeEscapePath(
2293 (*libDir + "/$(CONFIGURATION)").c_str());
2295 linkDirs += " ";
2296 linkDirs += this->XCodeEscapePath(libDir->c_str());
2299 this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
2300 linkDirs.c_str(), configName);
2303 // add the framework search paths
2305 const char* sep = "";
2306 std::string fdirs;
2307 std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
2308 for(std::vector<std::string>::const_iterator fdi = fwDirs.begin();
2309 fdi != fwDirs.end(); ++fdi)
2311 fdirs += sep;
2312 sep = " ";
2313 fdirs += this->XCodeEscapePath(fdi->c_str());
2315 if(!fdirs.empty())
2317 this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
2318 fdirs.c_str(), configName);
2322 // now add the link libraries
2324 std::string linkLibs;
2325 const char* sep = "";
2326 typedef cmComputeLinkInformation::ItemVector ItemVector;
2327 ItemVector const& libNames = cli.GetItems();
2328 for(ItemVector::const_iterator li = libNames.begin();
2329 li != libNames.end(); ++li)
2331 linkLibs += sep;
2332 sep = " ";
2333 if(li->IsPath)
2335 linkLibs += this->XCodeEscapePath(li->Value.c_str());
2337 else
2339 linkLibs += li->Value;
2342 this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
2343 linkLibs.c_str(), configName);
2348 //----------------------------------------------------------------------------
2349 void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
2350 std::vector<cmLocalGenerator*>&
2351 generators)
2353 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2354 i != generators.end(); ++i)
2356 if(this->IsExcluded(root, *i))
2358 continue;
2360 cmMakefile* mf = (*i)->GetMakefile();
2361 std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
2362 cmTargets &tgts = mf->GetTargets();
2363 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
2365 cmTarget& cmtarget = l->second;
2367 // Same skipping logic here as in CreateXCodeTargets so that we do not
2368 // end up with (empty anyhow) ALL_BUILD and XCODE_DEPEND_HELPER source
2369 // groups:
2371 if(cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
2373 continue;
2376 // add the soon to be generated Info.plist file as a source for a
2377 // MACOSX_BUNDLE file
2378 if(cmtarget.GetPropertyAsBool("MACOSX_BUNDLE"))
2380 std::string plist = this->ComputeInfoPListLocation(cmtarget);
2381 cmSourceFile* sf = mf->GetOrCreateSource(plist.c_str(), true);
2382 cmtarget.AddSourceFile(sf);
2385 std::vector<cmSourceFile*> classes = cmtarget.GetSourceFiles();
2387 for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
2388 s != classes.end(); s++)
2390 cmSourceFile* sf = *s;
2391 // Add the file to the list of sources.
2392 std::string const& source = sf->GetFullPath();
2393 cmSourceGroup& sourceGroup =
2394 mf->FindSourceGroup(source.c_str(), sourceGroups);
2395 cmXCodeObject* pbxgroup =
2396 this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
2397 cmStdString key = GetGroupMapKey(cmtarget, sf);
2398 this->GroupMap[key] = pbxgroup;
2404 //----------------------------------------------------------------------------
2405 cmXCodeObject* cmGlobalXCodeGenerator
2406 ::CreateOrGetPBXGroup(cmTarget& cmtarget, cmSourceGroup* sg)
2408 cmStdString s = cmtarget.GetName();
2409 s += "/";
2410 s += sg->GetName();
2411 std::map<cmStdString, cmXCodeObject* >::iterator i =
2412 this->GroupNameMap.find(s);
2413 if(i != this->GroupNameMap.end())
2415 return i->second;
2417 i = this->TargetGroup.find(cmtarget.GetName());
2418 cmXCodeObject* tgroup = 0;
2419 if(i != this->TargetGroup.end())
2421 tgroup = i->second;
2423 else
2425 tgroup = this->CreateObject(cmXCodeObject::PBXGroup);
2426 this->TargetGroup[cmtarget.GetName()] = tgroup;
2427 cmXCodeObject* tgroupChildren =
2428 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2429 tgroup->AddAttribute("name", this->CreateString(cmtarget.GetName()));
2430 tgroup->AddAttribute("children", tgroupChildren);
2431 if(this->XcodeVersion == 15)
2433 tgroup->AddAttribute("refType", this->CreateString("4"));
2435 tgroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2436 this->SourcesGroupChildren->AddObject(tgroup);
2439 // If it's the default source group (empty name) then put the source file
2440 // directly in the tgroup...
2442 if (cmStdString(sg->GetName()) == "")
2444 this->GroupNameMap[s] = tgroup;
2445 return tgroup;
2448 cmXCodeObject* tgroupChildren = tgroup->GetObject("children");
2449 cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
2450 cmXCodeObject* groupChildren =
2451 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2452 group->AddAttribute("name", this->CreateString(sg->GetName()));
2453 group->AddAttribute("children", groupChildren);
2454 if(this->XcodeVersion == 15)
2456 group->AddAttribute("refType", this->CreateString("4"));
2458 group->AddAttribute("sourceTree", this->CreateString("<group>"));
2459 tgroupChildren->AddObject(group);
2460 this->GroupNameMap[s] = group;
2461 return group;
2464 //----------------------------------------------------------------------------
2465 void cmGlobalXCodeGenerator
2466 ::CreateXCodeObjects(cmLocalGenerator* root,
2467 std::vector<cmLocalGenerator*>&
2468 generators)
2470 this->ClearXCodeObjects();
2471 this->RootObject = 0;
2472 this->SourcesGroupChildren = 0;
2473 this->ResourcesGroupChildren = 0;
2474 this->MainGroupChildren = 0;
2475 cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2476 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2477 cmXCodeObject* developBuildStyle =
2478 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2479 cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2480 if(this->XcodeVersion == 15)
2482 developBuildStyle->AddAttribute("name",
2483 this->CreateString("Development"));
2484 developBuildStyle->AddAttribute("buildSettings", group);
2485 listObjs->AddObject(developBuildStyle);
2486 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2487 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
2488 cmXCodeObject* deployBuildStyle =
2489 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2490 deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
2491 deployBuildStyle->AddAttribute("buildSettings", group);
2492 listObjs->AddObject(deployBuildStyle);
2494 else
2496 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2498 cmXCodeObject* buildStyle =
2499 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2500 const char* name = this->CurrentConfigurationTypes[i].c_str();
2501 buildStyle->AddAttribute("name", this->CreateString(name));
2502 buildStyle->SetComment(name);
2503 cmXCodeObject* sgroup =
2504 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2505 sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2506 buildStyle->AddAttribute("buildSettings", sgroup);
2507 listObjs->AddObject(buildStyle);
2511 cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2512 this->MainGroupChildren =
2513 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2514 mainGroup->AddAttribute("children", this->MainGroupChildren);
2515 if(this->XcodeVersion == 15)
2517 mainGroup->AddAttribute("refType", this->CreateString("4"));
2519 mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2521 cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2522 this->SourcesGroupChildren =
2523 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2524 sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
2525 sourcesGroup->AddAttribute("children", this->SourcesGroupChildren);
2526 if(this->XcodeVersion == 15)
2528 sourcesGroup->AddAttribute("refType", this->CreateString("4"));
2530 sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2531 this->MainGroupChildren->AddObject(sourcesGroup);
2533 cmXCodeObject* resourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2534 this->ResourcesGroupChildren =
2535 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2536 resourcesGroup->AddAttribute("name", this->CreateString("Resources"));
2537 resourcesGroup->AddAttribute("children", this->ResourcesGroupChildren);
2538 if(this->XcodeVersion == 15)
2540 resourcesGroup->AddAttribute("refType", this->CreateString("4"));
2542 resourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2543 this->MainGroupChildren->AddObject(resourcesGroup);
2545 // now create the cmake groups
2546 this->CreateGroups(root, generators);
2548 cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2549 productGroup->AddAttribute("name", this->CreateString("Products"));
2550 if(this->XcodeVersion == 15)
2552 productGroup->AddAttribute("refType", this->CreateString("4"));
2554 productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2555 cmXCodeObject* productGroupChildren =
2556 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2557 productGroup->AddAttribute("children", productGroupChildren);
2558 this->MainGroupChildren->AddObject(productGroup);
2561 this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
2562 this->RootObject->SetComment("Project object");
2563 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2564 this->RootObject->AddAttribute("mainGroup",
2565 this->CreateObjectReference(mainGroup));
2566 this->RootObject->AddAttribute("buildSettings", group);
2567 this->RootObject->AddAttribute("buildStyles", listObjs);
2568 this->RootObject->AddAttribute("hasScannedForEncodings",
2569 this->CreateString("0"));
2570 if (this->XcodeVersion >= 30)
2572 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2573 group->AddAttribute("BuildIndependentTargetsInParallel",
2574 this->CreateString("YES"));
2575 this->RootObject->AddAttribute("attributes", group);
2576 if (this->XcodeVersion >= 31)
2577 this->RootObject->AddAttribute("compatibilityVersion",
2578 this->CreateString("Xcode 3.1"));
2579 else
2580 this->RootObject->AddAttribute("compatibilityVersion",
2581 this->CreateString("Xcode 3.0"));
2583 // Point Xcode at the top of the source tree.
2585 std::string pdir =
2586 this->RelativeToBinary(root->GetMakefile()->GetCurrentDirectory());
2587 this->RootObject->AddAttribute("projectDirPath",
2588 this->CreateString(pdir.c_str()));
2589 this->RootObject->AddAttribute("projectRoot", this->CreateString(""));
2591 cmXCodeObject* configlist =
2592 this->CreateObject(cmXCodeObject::XCConfigurationList);
2593 cmXCodeObject* buildConfigurations =
2594 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2595 std::vector<cmXCodeObject*> configs;
2596 if(this->XcodeVersion == 15)
2598 cmXCodeObject* configDebug =
2599 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2600 configDebug->AddAttribute("name", this->CreateString("Debug"));
2601 configs.push_back(configDebug);
2602 cmXCodeObject* configRelease =
2603 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2604 configRelease->AddAttribute("name", this->CreateString("Release"));
2605 configs.push_back(configRelease);
2607 else
2609 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2611 const char* name = this->CurrentConfigurationTypes[i].c_str();
2612 cmXCodeObject* config =
2613 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2614 config->AddAttribute("name", this->CreateString(name));
2615 configs.push_back(config);
2618 for(std::vector<cmXCodeObject*>::iterator c = configs.begin();
2619 c != configs.end(); ++c)
2621 buildConfigurations->AddObject(*c);
2623 configlist->AddAttribute("buildConfigurations", buildConfigurations);
2625 std::string comment = "Build configuration list for PBXProject ";
2626 comment += " \"";
2627 comment += this->CurrentProject;
2628 comment += "\"";
2629 configlist->SetComment(comment.c_str());
2630 configlist->AddAttribute("defaultConfigurationIsVisible",
2631 this->CreateString("0"));
2632 configlist->AddAttribute("defaultConfigurationName",
2633 this->CreateString("Debug"));
2634 cmXCodeObject* buildSettings =
2635 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2636 const char* osxArch =
2637 this->CurrentMakefile->GetDefinition("CMAKE_OSX_ARCHITECTURES");
2638 if(strlen(osxArch) == 0)
2640 if(this->XcodeVersion >= 32)
2642 osxArch = "$(ARCHS_STANDARD_32_64_BIT)";
2644 else if(this->XcodeVersion <= 25)
2646 #ifdef __i386
2647 osxArch = "i386";
2648 #endif
2649 #ifdef __ppc__
2650 osxArch = "ppc";
2651 #endif
2653 else
2655 osxArch = "$(ARCHS_STANDARD_32_BIT)";
2657 buildSettings->AddAttribute("ONLY_ACTIVE_ARCH",
2658 this->CreateString("YES"));
2661 const char* sysroot =
2662 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
2663 const char* sysrootDefault =
2664 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT_DEFAULT");
2665 const char* deploymentTarget =
2666 this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
2667 if(osxArch && sysroot)
2669 bool flagsUsed = false;
2670 // recompute this as it may have been changed since enable language
2671 this->Architectures.clear();
2672 cmSystemTools::ExpandListArgument(std::string(osxArch),
2673 this->Architectures);
2674 flagsUsed = true;
2675 buildSettings->AddAttribute("SDKROOT",
2676 this->CreateString(sysroot));
2677 std::string archString;
2678 for( std::vector<std::string>::iterator i =
2679 this->Architectures.begin();
2680 i != this->Architectures.end(); ++i)
2682 archString += *i;
2683 archString += " ";
2685 buildSettings->AddAttribute("ARCHS",
2686 this->CreateString(archString.c_str()));
2687 if(!flagsUsed && sysrootDefault &&
2688 strcmp(sysroot, sysrootDefault) != 0)
2690 buildSettings->AddAttribute("SDKROOT",
2691 this->CreateString(sysroot));
2694 if(deploymentTarget && *deploymentTarget)
2696 buildSettings->AddAttribute("MACOSX_DEPLOYMENT_TARGET",
2697 this->CreateString(deploymentTarget));
2700 std::string symroot = root->GetMakefile()->GetCurrentOutputDirectory();
2701 symroot += "/build";
2702 buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot.c_str()));
2704 for( std::vector<cmXCodeObject*>::iterator i = configs.begin();
2705 i != configs.end(); ++i)
2707 (*i)->AddAttribute("buildSettings", buildSettings);
2710 this->RootObject->AddAttribute("buildConfigurationList",
2711 this->CreateObjectReference(configlist));
2713 std::vector<cmXCodeObject*> targets;
2714 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2715 i != generators.end(); ++i)
2717 if(!this->IsExcluded(root, *i))
2719 this->CreateXCodeTargets(*i, targets);
2722 // loop over all targets and add link and depend info
2723 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2724 i != targets.end(); ++i)
2726 cmXCodeObject* t = *i;
2727 this->AddDependAndLinkInformation(t);
2729 // now create xcode depend hack makefile
2730 this->CreateXCodeDependHackTarget(targets);
2731 // now add all targets to the root object
2732 cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2733 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2734 i != targets.end(); ++i)
2736 cmXCodeObject* t = *i;
2737 allTargets->AddObject(t);
2738 cmXCodeObject* productRef = t->GetObject("productReference");
2739 if(productRef)
2741 productGroupChildren->AddObject(productRef->GetObject());
2744 this->RootObject->AddAttribute("targets", allTargets);
2747 //----------------------------------------------------------------------------
2748 void
2749 cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
2750 std::vector<cmXCodeObject*>& targets)
2752 cmGeneratedFileStream
2753 makefileStream(this->CurrentXCodeHackMakefile.c_str());
2754 if(!makefileStream)
2756 cmSystemTools::Error("Could not create",
2757 this->CurrentXCodeHackMakefile.c_str());
2758 return;
2760 makefileStream.SetCopyIfDifferent(true);
2761 // one more pass for external depend information not handled
2762 // correctly by xcode
2763 makefileStream << "# DO NOT EDIT\n";
2764 makefileStream << "# This makefile makes sure all linkable targets are\n";
2765 makefileStream << "# up-to-date with anything they link to, avoiding a "
2766 "bug in XCode 1.5\n";
2767 for(std::vector<std::string>::const_iterator
2768 ct = this->CurrentConfigurationTypes.begin();
2769 ct != this->CurrentConfigurationTypes.end(); ++ct)
2771 if(this->XcodeVersion < 21 || ct->empty())
2773 makefileStream << "all: ";
2775 else
2777 makefileStream << "all." << *ct << ": ";
2779 const char* configName = 0;
2780 if(!ct->empty())
2782 configName = ct->c_str();
2784 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2785 i != targets.end(); ++i)
2787 cmXCodeObject* target = *i;
2788 cmTarget* t =target->GetTarget();
2789 if(t->GetType() == cmTarget::EXECUTABLE ||
2790 t->GetType() == cmTarget::SHARED_LIBRARY ||
2791 t->GetType() == cmTarget::MODULE_LIBRARY)
2793 std::string tfull = t->GetFullPath(configName);
2794 makefileStream << "\\\n\t" <<
2795 this->ConvertToRelativeForMake(tfull.c_str());
2798 makefileStream << "\n\n";
2800 makefileStream
2801 << "# For each target create a dummy rule "
2802 "so the target does not have to exist\n";
2803 std::set<cmStdString> emitted;
2804 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2805 i != targets.end(); ++i)
2807 cmXCodeObject* target = *i;
2808 std::map<cmStdString, cmXCodeObject::StringVec> const& deplibs =
2809 target->GetDependLibraries();
2810 for(std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator ci
2811 = deplibs.begin(); ci != deplibs.end(); ++ci)
2813 for(cmXCodeObject::StringVec::const_iterator d = ci->second.begin();
2814 d != ci->second.end(); ++d)
2816 if(emitted.insert(*d).second)
2818 makefileStream <<
2819 this->ConvertToRelativeForMake(d->c_str()) << ":\n";
2824 makefileStream << "\n\n";
2826 // Write rules to help Xcode relink things at the right time.
2827 makefileStream <<
2828 "# Rules to remove targets that are older than anything to which they\n"
2829 "# link. This forces Xcode to relink the targets from scratch. It\n"
2830 "# does not seem to check these dependencies itself.\n";
2831 for(std::vector<std::string>::const_iterator
2832 ct = this->CurrentConfigurationTypes.begin();
2833 ct != this->CurrentConfigurationTypes.end(); ++ct)
2835 const char* configName = 0;
2836 if(!ct->empty())
2838 configName = ct->c_str();
2840 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2841 i != targets.end(); ++i)
2843 cmXCodeObject* target = *i;
2844 cmTarget* t =target->GetTarget();
2845 if(t->GetType() == cmTarget::EXECUTABLE ||
2846 t->GetType() == cmTarget::SHARED_LIBRARY ||
2847 t->GetType() == cmTarget::MODULE_LIBRARY)
2849 // Create a rule for this target.
2850 std::string tfull = t->GetFullPath(configName);
2851 makefileStream << this->ConvertToRelativeForMake(tfull.c_str())
2852 << ":";
2854 // List dependencies if any exist.
2855 std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator
2856 x = target->GetDependLibraries().find(*ct);
2857 if(x != target->GetDependLibraries().end())
2859 std::vector<cmStdString> const& deplibs = x->second;
2860 for(std::vector<cmStdString>::const_iterator d = deplibs.begin();
2861 d != deplibs.end(); ++d)
2863 makefileStream << "\\\n\t" <<
2864 this->ConvertToRelativeForMake(d->c_str());
2867 // Write the action to remove the target if it is out of date.
2868 makefileStream << "\n";
2869 makefileStream << "\t/bin/rm -f "
2870 << this->ConvertToRelativeForMake(tfull.c_str())
2871 << "\n";
2872 // if building for more than one architecture
2873 // then remove those exectuables as well
2874 if(this->Architectures.size() > 1)
2876 std::string universal = t->GetDirectory();
2877 universal += "/";
2878 universal += this->CurrentProject;
2879 universal += ".build/";
2880 universal += configName;
2881 universal += "/";
2882 universal += t->GetName();
2883 universal += ".build/Objects-normal/";
2884 for( std::vector<std::string>::iterator arch =
2885 this->Architectures.begin();
2886 arch != this->Architectures.end(); ++arch)
2888 std::string universalFile = universal;
2889 universalFile += *arch;
2890 universalFile += "/";
2891 universalFile += t->GetFullName(configName);
2892 makefileStream << "\t/bin/rm -f "
2894 this->ConvertToRelativeForMake(universalFile.c_str())
2895 << "\n";
2898 makefileStream << "\n\n";
2904 //----------------------------------------------------------------------------
2905 void
2906 cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
2907 std::vector<cmLocalGenerator*>&
2908 generators)
2910 if(generators.size() == 0)
2912 return;
2914 // Skip local generators that are excluded from this project.
2915 for(std::vector<cmLocalGenerator*>::iterator g = generators.begin();
2916 g != generators.end(); ++g)
2918 if(this->IsExcluded(root, *g))
2920 continue;
2924 this->CreateXCodeObjects(root,
2925 generators);
2926 std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
2927 xcodeDir += "/";
2928 xcodeDir += root->GetMakefile()->GetProjectName();
2929 xcodeDir += ".xcode";
2930 if(this->XcodeVersion > 20)
2932 xcodeDir += "proj";
2934 cmSystemTools::MakeDirectory(xcodeDir.c_str());
2935 std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
2936 cmGeneratedFileStream fout(xcodeProjFile.c_str());
2937 fout.SetCopyIfDifferent(true);
2938 if(!fout)
2940 return;
2942 this->WriteXCodePBXProj(fout, root, generators);
2943 this->ClearXCodeObjects();
2946 //----------------------------------------------------------------------------
2947 void
2948 cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
2949 cmLocalGenerator* ,
2950 std::vector<cmLocalGenerator*>& )
2952 fout << "// !$*UTF8*$!\n";
2953 fout << "{\n";
2954 cmXCodeObject::Indent(1, fout);
2955 fout << "archiveVersion = 1;\n";
2956 cmXCodeObject::Indent(1, fout);
2957 fout << "classes = {\n";
2958 cmXCodeObject::Indent(1, fout);
2959 fout << "};\n";
2960 cmXCodeObject::Indent(1, fout);
2961 if(this->XcodeVersion >= 21)
2963 if (this->XcodeVersion >= 31)
2964 fout << "objectVersion = 45;\n";
2965 else if (this->XcodeVersion >= 30)
2966 fout << "objectVersion = 44;\n";
2967 else
2968 fout << "objectVersion = 42;\n";
2969 cmXCode21Object::PrintList(this->XCodeObjects, fout);
2971 else
2973 fout << "objectVersion = 39;\n";
2974 cmXCodeObject::PrintList(this->XCodeObjects, fout);
2976 cmXCodeObject::Indent(1, fout);
2977 fout << "rootObject = " << this->RootObject->GetId() << ";\n";
2978 fout << "}\n";
2981 //----------------------------------------------------------------------------
2982 const char* cmGlobalXCodeGenerator::GetCMakeCFGInitDirectory()
2984 return this->XcodeVersion >= 21? "$(CONFIGURATION)" : ".";
2987 //----------------------------------------------------------------------------
2988 void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
2989 const
2991 entry.Name = this->GetName();
2992 entry.Brief = "Generate XCode project files.";
2993 entry.Full = "";
2996 //----------------------------------------------------------------------------
2997 std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(const char* p)
2999 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
3001 return cmSystemTools::ConvertToOutputPath(p);
3003 else
3005 std::string ret =
3006 this->CurrentLocalGenerator->
3007 ConvertToRelativePath(this->CurrentOutputDirectoryComponents, p);
3008 return cmSystemTools::ConvertToOutputPath(ret.c_str());
3012 //----------------------------------------------------------------------------
3013 std::string cmGlobalXCodeGenerator::ConvertToRelativeForXCode(const char* p)
3015 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
3017 return cmSystemTools::ConvertToOutputPath(p);
3019 else
3021 std::string ret =
3022 this->CurrentLocalGenerator->
3023 ConvertToRelativePath(this->ProjectOutputDirectoryComponents, p);
3024 return cmSystemTools::ConvertToOutputPath(ret.c_str());
3028 //----------------------------------------------------------------------------
3029 std::string cmGlobalXCodeGenerator::RelativeToSource(const char* p)
3031 // We force conversion because Xcode breakpoints do not work unless
3032 // they are in a file named relative to the source tree.
3033 return this->CurrentLocalGenerator->
3034 ConvertToRelativePath(this->ProjectSourceDirectoryComponents, p, true);
3037 //----------------------------------------------------------------------------
3038 std::string cmGlobalXCodeGenerator::RelativeToBinary(const char* p)
3040 return this->CurrentLocalGenerator->
3041 ConvertToRelativePath(this->ProjectOutputDirectoryComponents, p);
3044 //----------------------------------------------------------------------------
3045 std::string cmGlobalXCodeGenerator::XCodeEscapePath(const char* p)
3047 std::string ret = p;
3048 if(ret.find(' ') != ret.npos)
3050 std::string t = ret;
3051 ret = "\"";
3052 ret += t;
3053 ret += "\"";
3055 return ret;
3058 //----------------------------------------------------------------------------
3059 void cmGlobalXCodeGenerator::
3060 GetTargetObjectFileDirectories(cmTarget* target,
3061 std::vector<std::string>&
3062 dirs)
3064 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
3065 dir += "/";
3066 dir += this->CurrentMakefile->GetProjectName();
3067 dir += ".build/";
3068 dir += this->GetCMakeCFGInitDirectory();
3069 dir += "/";
3070 dir += target->GetName();
3071 dir += ".build/Objects-normal/";
3072 std::string dirsave = dir;
3073 if(this->Architectures.size())
3075 for(std::vector<std::string>::iterator i = this->Architectures.begin();
3076 i != this->Architectures.end(); ++i)
3078 dir += *i;
3079 dirs.push_back(dir);
3080 dir = dirsave;
3083 else
3085 dirs.push_back(dir);
3089 //----------------------------------------------------------------------------
3090 void
3091 cmGlobalXCodeGenerator
3092 ::AppendDirectoryForConfig(const char* prefix,
3093 const char* config,
3094 const char* suffix,
3095 std::string& dir)
3097 if(this->XcodeVersion > 20)
3099 if(config)
3101 dir += prefix;
3102 dir += config;
3103 dir += suffix;
3108 //----------------------------------------------------------------------------
3109 std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix,
3110 const char* varNameLang,
3111 const char* varNameSuffix,
3112 const char* default_flags)
3114 if(varNameLang)
3116 std::string varName = varNamePrefix;
3117 varName += varNameLang;
3118 varName += varNameSuffix;
3119 if(const char* varValue =
3120 this->CurrentMakefile->GetDefinition(varName.c_str()))
3122 if(*varValue)
3124 return varValue;
3128 return default_flags;
3131 //----------------------------------------------------------------------------
3132 void cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
3133 const char* defines_list,
3134 bool dflag)
3136 // Skip this if there are no definitions.
3137 if(!defines_list)
3139 return;
3142 // Expand the list of definitions.
3143 std::vector<std::string> defines;
3144 cmSystemTools::ExpandListArgument(defines_list, defines);
3146 // Store the definitions in the string.
3147 this->AppendDefines(defs, defines, dflag);
3150 //----------------------------------------------------------------------------
3151 void
3152 cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
3153 std::vector<std::string> const& defines,
3154 bool dflag)
3156 // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
3157 std::string def;
3158 for(std::vector<std::string>::const_iterator di = defines.begin();
3159 di != defines.end(); ++di)
3161 // Start with -D if requested.
3162 def = dflag? "-D": "";
3163 def += *di;
3165 // Append the flag with needed escapes.
3166 std::string tmp;
3167 this->AppendFlag(tmp, def);
3168 defs.Add(tmp.c_str());
3172 //----------------------------------------------------------------------------
3173 void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
3174 std::string const& flag)
3176 // Short-circuit for an empty flag.
3177 if(flag.empty())
3179 return;
3182 // Separate from previous flags.
3183 if(!flags.empty())
3185 flags += " ";
3188 // Check if the flag needs quoting.
3189 bool quoteFlag =
3190 flag.find_first_of("`~!@#$%^&*()+={}[]|:;\"'<>,.? ") != flag.npos;
3192 // We escape a flag as follows:
3193 // - Place each flag in single quotes ''
3194 // - Escape a single quote as \\'
3195 // - Escape a backslash as \\\\ since it itself is an escape
3196 // Note that in the code below we need one more level of escapes for
3197 // C string syntax in this source file.
3199 // The final level of escaping is done when the string is stored
3200 // into the project file by cmXCodeObject::PrintString.
3202 if(quoteFlag)
3204 // Open single quote.
3205 flags += "'";
3208 // Flag value with escaped quotes and backslashes.
3209 for(const char* c = flag.c_str(); *c; ++c)
3211 if(*c == '\'')
3213 flags += "\\\\'";
3215 else if(*c == '\\')
3217 flags += "\\\\\\\\";
3219 else
3221 flags += *c;
3225 if(quoteFlag)
3227 // Close single quote.
3228 flags += "'";
3232 //----------------------------------------------------------------------------
3233 std::string
3234 cmGlobalXCodeGenerator::ComputeInfoPListLocation(cmTarget& target)
3236 std::string plist = target.GetMakefile()->GetCurrentOutputDirectory();
3237 plist += cmake::GetCMakeFilesDirectory();
3238 plist += "/";
3239 plist += target.GetName();
3240 plist += ".dir/Info.plist";
3241 return plist;