1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmGlobalXCodeGenerator.h"
13 #include "cmLocalXCodeGenerator.h"
14 #include "cmMakefile.h"
15 #include "cmXCodeObject.h"
16 #include "cmXCode21Object.h"
18 #include "cmGeneratedFileStream.h"
19 #include "cmComputeLinkInformation.h"
20 #include "cmSourceFile.h"
21 #include "cmCustomCommandGenerator.h"
22 #include "cmGeneratorTarget.h"
24 #include <cmsys/auto_ptr.hxx>
26 //----------------------------------------------------------------------------
27 #if defined(CMAKE_BUILD_WITH_CMAKE)
28 #include "cmXMLParser.h"
30 // parse the xml file storing the installed version of Xcode on
32 class cmXcodeVersionParser : public cmXMLParser
35 cmXcodeVersionParser(): Version("1.5") {}
36 void StartElement(const char* , const char** )
40 void EndElement(const char* name)
42 if(strcmp(name, "key") == 0)
44 this->Key = this->Data;
46 else if(strcmp(name, "string") == 0)
48 if(this->Key == "CFBundleShortVersionString")
50 this->Version = this->Data;
54 void CharacterDataHandler(const char* data, int length)
56 this->Data.append(data, length);
64 // Builds either an object list or a space-separated string from the
66 class cmGlobalXCodeGenerator::BuildObjectListOrString
68 cmGlobalXCodeGenerator *Generator;
74 BuildObjectListOrString(cmGlobalXCodeGenerator *gen, bool buildObjectList)
75 : Generator(gen), Group(0), Empty(true)
79 this->Group = this->Generator->CreateObject(cmXCodeObject::OBJECT_LIST);
83 bool IsEmpty() const { return this->Empty; }
85 void Add(const char *newString)
91 this->Group->AddObject(this->Generator->CreateString(newString));
95 this->String += newString;
100 const std::string &GetString() const { return this->String; }
102 cmXCodeObject *CreateList()
110 return this->Generator->CreateString(this->String.c_str());
115 //----------------------------------------------------------------------------
116 cmGlobalXCodeGenerator::cmGlobalXCodeGenerator(std::string const& version)
118 this->VersionString = version;
120 // Compute an integer form of the version number.
121 unsigned int v[2] = {0,0};
122 sscanf(this->VersionString.c_str(), "%u.%u", &v[0], &v[1]);
123 this->XcodeVersion = 10*v[0] + v[1];
125 this->FindMakeProgramFile = "CMakeFindXCode.cmake";
126 this->RootObject = 0;
127 this->MainGroupChildren = 0;
128 this->SourcesGroupChildren = 0;
129 this->ResourcesGroupChildren = 0;
130 this->CurrentMakefile = 0;
131 this->CurrentLocalGenerator = 0;
134 //----------------------------------------------------------------------------
135 cmGlobalGenerator* cmGlobalXCodeGenerator::New()
137 #if defined(CMAKE_BUILD_WITH_CMAKE)
138 cmXcodeVersionParser parser;
139 if (cmSystemTools::FileExists(
140 "/Applications/Xcode.app/Contents/version.plist"))
143 ("/Applications/Xcode.app/Contents/version.plist");
148 ("/Developer/Applications/Xcode.app/Contents/version.plist");
150 cmsys::auto_ptr<cmGlobalXCodeGenerator>
151 gg(new cmGlobalXCodeGenerator(parser.Version));
152 if (gg->XcodeVersion == 20)
154 cmSystemTools::Message("Xcode 2.0 not really supported by cmake, "
155 "using Xcode 15 generator\n");
156 gg->XcodeVersion = 15;
160 std::cerr << "CMake should be built with cmake to use Xcode, "
161 "default to Xcode 1.5\n";
162 return new cmGlobalXCodeGenerator;
166 //----------------------------------------------------------------------------
167 void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const&
169 cmMakefile * mf, bool optional)
171 mf->AddDefinition("XCODE","1");
172 mf->AddDefinition("XCODE_VERSION", this->VersionString.c_str());
173 if(this->XcodeVersion == 15)
178 if(!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
180 mf->AddCacheDefinition(
181 "CMAKE_CONFIGURATION_TYPES",
182 "Debug;Release;MinSizeRel;RelWithDebInfo",
183 "Semicolon separated list of supported configuration types, "
184 "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
185 "anything else will be ignored.",
186 cmCacheManager::STRING);
189 mf->AddDefinition("CMAKE_GENERATOR_CC", "gcc");
190 mf->AddDefinition("CMAKE_GENERATOR_CXX", "g++");
191 mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
192 this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
193 const char* osxArch =
194 mf->GetDefinition("CMAKE_OSX_ARCHITECTURES");
195 const char* sysroot =
196 mf->GetDefinition("CMAKE_OSX_SYSROOT");
197 if(osxArch && sysroot)
199 this->Architectures.clear();
200 cmSystemTools::ExpandListArgument(std::string(osxArch),
201 this->Architectures);
205 //----------------------------------------------------------------------------
206 std::string cmGlobalXCodeGenerator
207 ::GenerateBuildCommand(const char* makeProgram,
208 const char *projectName,
209 const char* additionalOptions,
210 const char *targetName,
215 // Config is not used yet
218 // now build the test
219 if(makeProgram == 0 || !strlen(makeProgram))
221 cmSystemTools::Error(
222 "Generator cannot find the appropriate make command.");
225 std::string makeCommand =
226 cmSystemTools::ConvertToOutputPath(makeProgram);
227 std::string lowerCaseCommand = makeCommand;
228 cmSystemTools::LowerCase(lowerCaseCommand);
230 makeCommand += " -project ";
231 makeCommand += projectName;
232 makeCommand += ".xcode";
233 if(this->XcodeVersion > 20)
235 makeCommand += "proj";
239 if ( targetName && strcmp(targetName, "clean") == 0 )
242 targetName = "ALL_BUILD";
246 makeCommand += " clean";
250 makeCommand += " build";
252 makeCommand += " -target ";
253 // if it is a null string for config don't use it
254 if(config && *config == 0)
258 if (targetName && strlen(targetName))
260 makeCommand += targetName;
264 makeCommand += "ALL_BUILD";
266 if(this->XcodeVersion == 15)
268 makeCommand += " -buildstyle Development ";
272 makeCommand += " -configuration ";
273 makeCommand += config?config:"Debug";
275 if ( additionalOptions )
278 makeCommand += additionalOptions;
283 //----------------------------------------------------------------------------
284 ///! Create a local generator appropriate to this Global Generator
285 cmLocalGenerator *cmGlobalXCodeGenerator::CreateLocalGenerator()
287 cmLocalGenerator *lg = new cmLocalXCodeGenerator;
288 lg->SetGlobalGenerator(this);
292 //----------------------------------------------------------------------------
293 void cmGlobalXCodeGenerator::Generate()
295 std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
296 // make sure extra targets are added before calling
297 // the parent generate which will call trace depends
298 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
300 cmLocalGenerator* root = it->second[0];
301 this->SetGenerationRoot(root);
302 // add ALL_BUILD, INSTALL, etc
303 this->AddExtraTargets(root, it->second);
305 this->ForceLinkerLanguages();
306 this->cmGlobalGenerator::Generate();
307 if(cmSystemTools::GetErrorOccuredFlag())
311 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
313 cmLocalGenerator* root = it->second[0];
314 this->SetGenerationRoot(root);
315 // now create the project
316 this->OutputXCodeProject(root, it->second);
320 //----------------------------------------------------------------------------
321 void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
323 this->CurrentProject = root->GetMakefile()->GetProjectName();
324 this->SetCurrentLocalGenerator(root);
325 cmSystemTools::SplitPath(this->CurrentMakefile->GetCurrentDirectory(),
326 this->ProjectSourceDirectoryComponents);
327 cmSystemTools::SplitPath(this->CurrentMakefile->GetCurrentOutputDirectory(),
328 this->ProjectOutputDirectoryComponents);
330 this->CurrentXCodeHackMakefile =
331 root->GetMakefile()->GetCurrentOutputDirectory();
332 this->CurrentXCodeHackMakefile += "/CMakeScripts";
333 cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile.c_str());
334 this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
337 //----------------------------------------------------------------------------
339 cmGlobalXCodeGenerator::PostBuildMakeTarget(std::string const& tName,
340 std::string const& configName)
342 std::string target = tName;
343 cmSystemTools::ReplaceString(target, " ", "_");
344 std::string out = "PostBuild." + target;
345 if(this->XcodeVersion > 20)
347 out += "." + configName;
352 //----------------------------------------------------------------------------
353 #define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK"
355 //----------------------------------------------------------------------------
357 cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
358 std::vector<cmLocalGenerator*>& gens)
360 cmMakefile* mf = root->GetMakefile();
363 const char* no_working_directory = 0;
364 std::vector<std::string> no_depends;
365 mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
366 no_working_directory,
367 "echo", "Build all projects");
368 cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
370 // Refer to the main build configuration file for easy editing.
371 std::string listfile = mf->GetStartDirectory();
373 listfile += "CMakeLists.txt";
374 allbuild->AddSource(listfile.c_str());
376 // Add XCODE depend helper
377 std::string dir = mf->GetCurrentOutputDirectory();
378 cmCustomCommandLine makecommand;
379 makecommand.push_back("make");
380 makecommand.push_back("-C");
381 makecommand.push_back(dir.c_str());
382 makecommand.push_back("-f");
383 makecommand.push_back(this->CurrentXCodeHackMakefile.c_str());
384 makecommand.push_back(""); // placeholder, see below
387 bool regenerate = !mf->IsOn("CMAKE_SUPPRESS_REGENERATION");
390 this->CreateReRunCMakeFile(root, gens);
391 std::string file = this->ConvertToRelativeForMake(
392 this->CurrentReRunCMakeMakefile.c_str());
393 cmSystemTools::ReplaceString(file, "\\ ", " ");
394 mf->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, no_depends,
395 no_working_directory,
396 "make", "-f", file.c_str());
399 // now make the allbuild depend on all the non-utility targets
401 for(std::vector<cmLocalGenerator*>::iterator i = gens.begin();
402 i != gens.end(); ++i)
404 cmLocalGenerator* lg = *i;
405 if(this->IsExcluded(root, *i))
410 cmTargets& tgts = lg->GetMakefile()->GetTargets();
411 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
413 cmTarget& target = l->second;
415 if (regenerate && (l->first != CMAKE_CHECK_BUILD_SYSTEM_TARGET))
417 target.AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET);
420 // make all exe, shared libs and modules
421 // run the depend check makefile as a post build rule
422 // this will make sure that when the next target is built
423 // things are up-to-date
424 if((target.GetType() == cmTarget::EXECUTABLE ||
425 // Nope - no post-build for OBJECT_LIRBRARY
426 // target.GetType() == cmTarget::OBJECT_LIBRARY ||
427 target.GetType() == cmTarget::STATIC_LIBRARY ||
428 target.GetType() == cmTarget::SHARED_LIBRARY ||
429 target.GetType() == cmTarget::MODULE_LIBRARY))
431 makecommand[makecommand.size()-1] =
432 this->PostBuildMakeTarget(target.GetName(), "$(CONFIGURATION)");
433 cmCustomCommandLines commandLines;
434 commandLines.push_back(makecommand);
435 lg->GetMakefile()->AddCustomCommandToTarget(target.GetName(),
438 cmTarget::POST_BUILD,
439 "Depend check for xcode",
443 if(!target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
445 allbuild->AddUtility(target.GetName());
448 // Refer to the build configuration file for easy editing.
449 listfile = lg->GetMakefile()->GetStartDirectory();
451 listfile += "CMakeLists.txt";
452 target.AddSource(listfile.c_str());
457 //----------------------------------------------------------------------------
458 void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
459 cmLocalGenerator* root, std::vector<cmLocalGenerator*> const& gens)
461 cmMakefile* mf = root->GetMakefile();
462 std::vector<std::string> lfiles;
463 for(std::vector<cmLocalGenerator*>::const_iterator gi = gens.begin();
464 gi != gens.end(); ++gi)
466 std::vector<std::string> const& lf = (*gi)->GetMakefile()->GetListFiles();
467 lfiles.insert(lfiles.end(), lf.begin(), lf.end());
471 std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
472 std::vector<std::string>::iterator new_end =
473 std::unique(lfiles.begin(), lfiles.end());
474 lfiles.erase(new_end, lfiles.end());
475 this->CurrentReRunCMakeMakefile = mf->GetStartOutputDirectory();
476 this->CurrentReRunCMakeMakefile += "/CMakeScripts";
477 cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
478 this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
479 cmGeneratedFileStream makefileStream
480 (this->CurrentReRunCMakeMakefile.c_str());
481 makefileStream.SetCopyIfDifferent(true);
482 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
483 makefileStream << cmake::GetCMakeFilesDirectoryPostSlash();
484 makefileStream << "cmake.check_cache: ";
485 for(std::vector<std::string>::const_iterator i = lfiles.begin();
486 i != lfiles.end(); ++i)
488 makefileStream << "\\\n" << this->ConvertToRelativeForMake(i->c_str());
490 std::string cmake = mf->GetRequiredDefinition("CMAKE_COMMAND");
491 makefileStream << "\n\t" << this->ConvertToRelativeForMake(cmake.c_str())
492 << " -H" << this->ConvertToRelativeForMake(
493 mf->GetHomeDirectory())
494 << " -B" << this->ConvertToRelativeForMake(
495 mf->GetHomeOutputDirectory()) << "\n";
498 //----------------------------------------------------------------------------
499 void cmGlobalXCodeGenerator::ClearXCodeObjects()
501 this->TargetDoneSet.clear();
502 for(unsigned int i = 0; i < this->XCodeObjects.size(); ++i)
504 delete this->XCodeObjects[i];
506 this->XCodeObjects.clear();
507 this->XCodeObjectIDs.clear();
508 this->GroupMap.clear();
509 this->GroupNameMap.clear();
510 this->TargetGroup.clear();
511 this->FileRefs.clear();
514 //----------------------------------------------------------------------------
515 void cmGlobalXCodeGenerator::addObject(cmXCodeObject *obj)
517 if(obj->GetType() == cmXCodeObject::OBJECT)
519 cmStdString id = obj->GetId();
521 // If this is a duplicate id, it's an error:
523 if(this->XCodeObjectIDs.count(id))
525 cmSystemTools::Error(
526 "Xcode generator: duplicate object ids not allowed");
529 this->XCodeObjectIDs.insert(id);
532 this->XCodeObjects.push_back(obj);
535 //----------------------------------------------------------------------------
537 cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype)
540 if(this->XcodeVersion == 15)
542 obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
546 obj = new cmXCode21Object(ptype, cmXCodeObject::OBJECT);
548 this->addObject(obj);
552 //----------------------------------------------------------------------------
554 cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
556 cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
557 this->addObject(obj);
561 //----------------------------------------------------------------------------
563 cmGlobalXCodeGenerator::CreateString(const char* s)
565 cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
570 //----------------------------------------------------------------------------
571 cmXCodeObject* cmGlobalXCodeGenerator
572 ::CreateObjectReference(cmXCodeObject* ref)
574 cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
579 //----------------------------------------------------------------------------
581 GetGroupMapKeyFromPath(cmTarget& cmtarget, const std::string& fullpath)
583 cmStdString key(cmtarget.GetName());
589 //----------------------------------------------------------------------------
591 GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
593 return GetGroupMapKeyFromPath(cmtarget, sf->GetFullPath());
596 //----------------------------------------------------------------------------
598 cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
599 const std::string &fullpath,
601 const std::string &lang)
603 // Using a map and the full path guarantees that we will always get the same
604 // fileRef object for any given full path.
606 cmXCodeObject* fileRef =
607 this->CreateXCodeFileReferenceFromPath(fullpath, cmtarget, lang);
609 cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
610 buildFile->SetComment(fileRef->GetComment());
611 buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
616 //----------------------------------------------------------------------------
618 cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
622 // Add flags from target and source file properties.
624 if(cmtarget.GetProperty("COMPILE_FLAGS"))
626 lg->AppendFlags(flags, cmtarget.GetProperty("COMPILE_FLAGS"));
628 const char* srcfmt = sf->GetProperty("Fortran_FORMAT");
629 switch(this->CurrentLocalGenerator->GetFortranFormat(srcfmt))
631 case cmLocalGenerator::FortranFormatFixed: flags="-fixed "+flags; break;
632 case cmLocalGenerator::FortranFormatFree: flags="-free "+flags; break;
635 lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
637 // Add per-source definitions.
638 BuildObjectListOrString flagsBuild(this, false);
639 this->AppendDefines(flagsBuild,
640 sf->GetProperty("COMPILE_DEFINITIONS"), true);
641 if (!flagsBuild.IsEmpty())
647 flags += flagsBuild.GetString();
651 this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
657 cmXCodeObject* buildFile =
658 this->CreateXCodeSourceFileFromPath(sf->GetFullPath(), cmtarget, lang);
659 cmXCodeObject* fileRef = buildFile->GetObject("fileRef")->GetObject();
661 cmXCodeObject* settings =
662 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
663 settings->AddAttribute("COMPILER_FLAGS", this->CreateString(flags.c_str()));
665 // Is this a resource file in this target? Add it to the resources group...
667 cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf);
668 bool isResource = (tsFlags.Type == cmTarget::SourceFileTypeResource);
670 // Is this a "private" or "public" framework header file?
671 // Set the ATTRIBUTES attribute appropriately...
673 if(cmtarget.IsFrameworkOnApple())
675 if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader)
677 cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
678 attrs->AddObject(this->CreateString("Private"));
679 settings->AddAttribute("ATTRIBUTES", attrs);
682 else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader)
684 cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
685 attrs->AddObject(this->CreateString("Public"));
686 settings->AddAttribute("ATTRIBUTES", attrs);
691 if(cmtarget.IsCFBundleOnApple())
693 cmtarget.SetProperty("PREFIX", "");
694 cmtarget.SetProperty("SUFFIX", "");
697 // Add the fileRef to the top level Resources group/folder if it is not
700 if(isResource && this->ResourcesGroupChildren &&
701 !this->ResourcesGroupChildren->HasObject(fileRef))
703 this->ResourcesGroupChildren->AddObject(fileRef);
706 buildFile->AddAttribute("settings", settings);
710 //----------------------------------------------------------------------------
712 GetSourcecodeValueFromFileExtension(const std::string& _ext,
713 const std::string& lang)
715 std::string ext = cmSystemTools::LowerCase(_ext);
716 std::string sourcecode = "sourcecode";
720 sourcecode = "compiled.mach-o.objfile";
722 else if(ext == "xib")
724 sourcecode = "file.xib";
726 else if(ext == "storyboard")
728 sourcecode = "file.storyboard";
732 sourcecode += ".cpp.objcpp";
736 sourcecode += ".c.objc";
738 else if(ext == "xib")
740 sourcecode += ".file.xib";
742 else if(ext == "plist")
744 sourcecode += ".text.plist";
748 sourcecode += ".c.h";
750 else if(ext == "hxx" || ext == "hpp" || ext == "txx"
751 || ext == "pch" || ext == "hh")
753 sourcecode += ".cpp.h";
755 else if(ext == "png" || ext == "gif" || ext == "jpg")
757 sourcecode = "image";
759 else if(ext == "txt")
761 sourcecode += ".text";
763 else if(lang == "CXX")
765 sourcecode += ".cpp.cpp";
769 sourcecode += ".c.c";
771 else if(lang == "Fortran")
773 sourcecode += ".fortran.f90";
777 // // Already specialized above or we leave sourcecode == "sourcecode"
778 // // which is probably the most correct choice. Extensionless headers,
779 // // for example... Or file types unknown to Xcode that do not map to a
780 // // valid lastKnownFileType value.
786 //----------------------------------------------------------------------------
788 cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
789 const std::string &fullpath,
791 const std::string &lang)
793 std::string fname = fullpath;
794 cmXCodeObject* fileRef = this->FileRefs[fname];
797 fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
798 std::string comment = fname;
799 fileRef->SetComment(fname.c_str());
800 this->FileRefs[fname] = fileRef;
802 cmStdString key = GetGroupMapKeyFromPath(cmtarget, fullpath);
803 cmXCodeObject* group = this->GroupMap[key];
804 cmXCodeObject* children = group->GetObject("children");
805 if (!children->HasObject(fileRef))
807 children->AddObject(fileRef);
809 fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
811 // Compute the extension.
813 std::string realExt =
814 cmSystemTools::GetFilenameLastExtension(fullpath);
817 // Extension without the leading '.'.
818 ext = realExt.substr(1);
821 std::string sourcecode = GetSourcecodeValueFromFileExtension(ext, lang);
823 fileRef->AddAttribute("lastKnownFileType",
824 this->CreateString(sourcecode.c_str()));
826 // Store the file path relative to the top of the source tree.
827 std::string path = this->RelativeToSource(fullpath.c_str());
828 std::string name = cmSystemTools::GetFilenameName(path.c_str());
829 const char* sourceTree = (cmSystemTools::FileIsFullPath(path.c_str())?
830 "<absolute>" : "SOURCE_ROOT");
831 fileRef->AddAttribute("name", this->CreateString(name.c_str()));
832 fileRef->AddAttribute("path", this->CreateString(path.c_str()));
833 fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
834 if(this->XcodeVersion == 15)
836 fileRef->AddAttribute("refType", this->CreateString("4"));
841 //----------------------------------------------------------------------------
843 cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
847 this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
853 return this->CreateXCodeFileReferenceFromPath(
854 sf->GetFullPath(), cmtarget, lang);
857 //----------------------------------------------------------------------------
858 bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
860 if(tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
861 tname == "install" || tname == "package" || tname == "RUN_TESTS" ||
862 tname == CMAKE_CHECK_BUILD_SYSTEM_TARGET )
864 if(this->TargetDoneSet.find(tname) != this->TargetDoneSet.end())
868 this->TargetDoneSet.insert(tname);
874 //----------------------------------------------------------------------------
875 void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
877 this->CurrentLocalGenerator = gen;
878 this->CurrentMakefile = gen->GetMakefile();
880 cmSystemTools::CollapseFullPath(this->CurrentMakefile->
881 GetCurrentOutputDirectory());
882 cmSystemTools::SplitPath(outdir.c_str(),
883 this->CurrentOutputDirectoryComponents);
885 // Select the current set of configuration types.
886 this->CurrentConfigurationTypes.clear();
887 this->CurrentMakefile->GetConfigurations(this->CurrentConfigurationTypes);
888 if(this->CurrentConfigurationTypes.empty())
890 this->CurrentConfigurationTypes.push_back("");
894 //----------------------------------------------------------------------------
896 cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
897 std::vector<cmXCodeObject*>&
900 this->SetCurrentLocalGenerator(gen);
901 cmTargets &tgts = this->CurrentMakefile->GetTargets();
902 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
904 cmTarget& cmtarget = l->second;
906 // make sure ALL_BUILD, INSTALL, etc are only done once
907 if(this->SpecialTargetEmitted(l->first.c_str()))
912 if(cmtarget.GetType() == cmTarget::UTILITY ||
913 cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
915 targets.push_back(this->CreateUtilityTarget(cmtarget));
919 // organize the sources
920 std::vector<cmSourceFile*> const &classes = cmtarget.GetSourceFiles();
921 std::vector<cmXCodeObject*> externalObjFiles;
922 std::vector<cmXCodeObject*> headerFiles;
923 std::vector<cmXCodeObject*> resourceFiles;
924 std::vector<cmXCodeObject*> sourceFiles;
925 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
926 i != classes.end(); ++i)
929 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
931 cmXCodeObject* fr = xsf->GetObject("fileRef");
932 cmXCodeObject* filetype =
933 fr->GetObject()->GetObject("lastKnownFileType");
935 cmTarget::SourceFileFlags tsFlags =
936 cmtarget.GetTargetSourceFileFlags(*i);
938 if(strcmp(filetype->GetString(), "compiled.mach-o.objfile") == 0)
940 externalObjFiles.push_back(xsf);
942 else if(this->IsHeaderFile(*i) ||
943 (tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) ||
944 (tsFlags.Type == cmTarget::SourceFileTypePublicHeader))
946 headerFiles.push_back(xsf);
948 else if(tsFlags.Type == cmTarget::SourceFileTypeResource)
950 resourceFiles.push_back(xsf);
952 else if(!(*i)->GetPropertyAsBool("HEADER_FILE_ONLY"))
954 // Include this file in the build if it has a known language
955 // and has not been listed as an ignored extension for this
957 if(this->CurrentLocalGenerator->GetSourceFileLanguage(**i) &&
958 !this->IgnoreFile((*i)->GetExtension().c_str()))
960 sourceFiles.push_back(xsf);
965 // Add object library contents as external objects. (Equivalent to
966 // the externalObjFiles above, except each one is not a cmSourceFile
967 // within the target.)
968 std::vector<std::string> objs;
969 this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs);
970 for(std::vector<std::string>::const_iterator
971 oi = objs.begin(); oi != objs.end(); ++oi)
973 std::string obj = *oi;
975 this->CreateXCodeSourceFileFromPath(obj, cmtarget, "");
976 externalObjFiles.push_back(xsf);
979 // some build phases only apply to bundles and/or frameworks
980 bool isFrameworkTarget = cmtarget.IsFrameworkOnApple();
981 bool isBundleTarget = cmtarget.GetPropertyAsBool("MACOSX_BUNDLE");
982 bool isCFBundleTarget = cmtarget.IsCFBundleOnApple();
984 cmXCodeObject* buildFiles = 0;
986 // create source build phase
987 cmXCodeObject* sourceBuildPhase = 0;
988 if (!sourceFiles.empty())
991 this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
992 sourceBuildPhase->SetComment("Sources");
993 sourceBuildPhase->AddAttribute("buildActionMask",
994 this->CreateString("2147483647"));
995 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
996 for(std::vector<cmXCodeObject*>::iterator i = sourceFiles.begin();
997 i != sourceFiles.end(); ++i)
999 buildFiles->AddObject(*i);
1001 sourceBuildPhase->AddAttribute("files", buildFiles);
1002 sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1003 this->CreateString("0"));
1006 // create header build phase - only for framework targets
1007 cmXCodeObject* headerBuildPhase = 0;
1008 if (!headerFiles.empty() && isFrameworkTarget)
1011 this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
1012 headerBuildPhase->SetComment("Headers");
1013 headerBuildPhase->AddAttribute("buildActionMask",
1014 this->CreateString("2147483647"));
1015 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1016 for(std::vector<cmXCodeObject*>::iterator i = headerFiles.begin();
1017 i != headerFiles.end(); ++i)
1019 buildFiles->AddObject(*i);
1021 headerBuildPhase->AddAttribute("files", buildFiles);
1022 headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1023 this->CreateString("0"));
1026 // create resource build phase - only for framework or bundle targets
1027 cmXCodeObject* resourceBuildPhase = 0;
1028 if (!resourceFiles.empty() &&
1029 (isFrameworkTarget || isBundleTarget || isCFBundleTarget))
1031 resourceBuildPhase =
1032 this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
1033 resourceBuildPhase->SetComment("Resources");
1034 resourceBuildPhase->AddAttribute("buildActionMask",
1035 this->CreateString("2147483647"));
1036 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1037 for(std::vector<cmXCodeObject*>::iterator i = resourceFiles.begin();
1038 i != resourceFiles.end(); ++i)
1040 buildFiles->AddObject(*i);
1042 resourceBuildPhase->AddAttribute("files", buildFiles);
1043 resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1044 this->CreateString("0"));
1047 // create vector of "non-resource content file" build phases - only for
1048 // framework or bundle targets
1049 std::vector<cmXCodeObject*> contentBuildPhases;
1050 if (isFrameworkTarget || isBundleTarget || isCFBundleTarget)
1052 typedef std::map<cmStdString, std::vector<cmSourceFile*> >
1053 mapOfVectorOfSourceFiles;
1054 mapOfVectorOfSourceFiles bundleFiles;
1055 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
1056 i != classes.end(); ++i)
1058 cmTarget::SourceFileFlags tsFlags =
1059 cmtarget.GetTargetSourceFileFlags(*i);
1060 if(tsFlags.Type == cmTarget::SourceFileTypeMacContent)
1062 bundleFiles[tsFlags.MacFolder].push_back(*i);
1065 mapOfVectorOfSourceFiles::iterator mit;
1066 for ( mit = bundleFiles.begin(); mit != bundleFiles.end(); ++ mit )
1068 cmXCodeObject* copyFilesBuildPhase =
1069 this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
1070 copyFilesBuildPhase->SetComment("Copy files");
1071 copyFilesBuildPhase->AddAttribute("buildActionMask",
1072 this->CreateString("2147483647"));
1073 copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
1074 this->CreateString("6"));
1075 cmOStringStream ostr;
1076 if (cmtarget.IsFrameworkOnApple())
1078 // dstPath in frameworks is relative to Versions/<version>
1081 else if ( mit->first != "MacOS" )
1083 // dstPath in bundles is relative to Contents/MacOS
1084 ostr << "../" << mit->first.c_str();
1086 copyFilesBuildPhase->AddAttribute("dstPath",
1087 this->CreateString(ostr.str().c_str()));
1088 copyFilesBuildPhase->AddAttribute(
1089 "runOnlyForDeploymentPostprocessing", this->CreateString("0"));
1090 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1091 copyFilesBuildPhase->AddAttribute("files", buildFiles);
1092 std::vector<cmSourceFile*>::iterator sfIt;
1093 for ( sfIt = mit->second.begin(); sfIt != mit->second.end(); ++ sfIt )
1095 cmXCodeObject* xsf =
1096 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
1098 buildFiles->AddObject(xsf);
1100 contentBuildPhases.push_back(copyFilesBuildPhase);
1104 // create framework build phase
1105 cmXCodeObject* frameworkBuildPhase = 0;
1106 if (!externalObjFiles.empty())
1108 frameworkBuildPhase =
1109 this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
1110 frameworkBuildPhase->SetComment("Frameworks");
1111 frameworkBuildPhase->AddAttribute("buildActionMask",
1112 this->CreateString("2147483647"));
1113 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1114 frameworkBuildPhase->AddAttribute("files", buildFiles);
1115 for(std::vector<cmXCodeObject*>::iterator i = externalObjFiles.begin();
1116 i != externalObjFiles.end(); ++i)
1118 buildFiles->AddObject(*i);
1120 frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1121 this->CreateString("0"));
1124 // create list of build phases and create the Xcode target
1125 cmXCodeObject* buildPhases =
1126 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1128 this->CreateCustomCommands(buildPhases, sourceBuildPhase,
1129 headerBuildPhase, resourceBuildPhase,
1131 frameworkBuildPhase, cmtarget);
1133 targets.push_back(this->CreateXCodeTarget(cmtarget, buildPhases));
1137 //----------------------------------------------------------------------------
1138 void cmGlobalXCodeGenerator::ForceLinkerLanguages()
1140 // This makes sure all targets link using the proper language.
1141 for(std::map<cmStdString, cmTarget*>::const_iterator
1142 ti = this->TotalTargets.begin(); ti != this->TotalTargets.end(); ++ti)
1144 this->ForceLinkerLanguage(*ti->second);
1148 //----------------------------------------------------------------------------
1149 void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmTarget& cmtarget)
1151 // This matters only for targets that link.
1152 if(cmtarget.GetType() != cmTarget::EXECUTABLE &&
1153 cmtarget.GetType() != cmTarget::SHARED_LIBRARY &&
1154 cmtarget.GetType() != cmTarget::MODULE_LIBRARY)
1159 const char* llang = cmtarget.GetLinkerLanguage("NOCONFIG");
1160 if(!llang) { return; }
1162 // If the language is compiled as a source trust Xcode to link with it.
1163 cmTarget::LinkImplementation const* impl =
1164 cmtarget.GetLinkImplementation("NOCONFIG");
1165 for(std::vector<std::string>::const_iterator li = impl->Languages.begin();
1166 li != impl->Languages.end(); ++li)
1168 if(*li == llang) { return; }
1171 // Add an empty source file to the target that compiles with the
1172 // linker language. This should convince Xcode to choose the proper
1174 cmMakefile* mf = cmtarget.GetMakefile();
1175 std::string fname = mf->GetCurrentOutputDirectory();
1176 fname += cmake::GetCMakeFilesDirectory();
1178 fname += cmtarget.GetName();
1179 fname += "-CMakeForceLinker";
1181 fname += cmSystemTools::LowerCase(llang);
1183 cmGeneratedFileStream fout(fname.c_str());
1186 if(cmSourceFile* sf = mf->GetOrCreateSource(fname.c_str()))
1188 sf->SetProperty("LANGUAGE", llang);
1189 cmtarget.AddSourceFile(sf);
1193 //----------------------------------------------------------------------------
1194 bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf)
1196 const std::vector<std::string>& hdrExts =
1197 this->CurrentMakefile->GetHeaderExtensions();
1198 return (std::find(hdrExts.begin(), hdrExts.end(), sf->GetExtension()) !=
1202 //----------------------------------------------------------------------------
1204 cmGlobalXCodeGenerator::CreateBuildPhase(const char* name,
1207 const std::vector<cmCustomCommand>&
1210 if(commands.size() == 0 && strcmp(name, "CMake ReRun") != 0)
1214 cmXCodeObject* buildPhase =
1215 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
1216 buildPhase->AddAttribute("buildActionMask",
1217 this->CreateString("2147483647"));
1218 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1219 buildPhase->AddAttribute("files", buildFiles);
1220 buildPhase->AddAttribute("name",
1221 this->CreateString(name));
1222 buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1223 this->CreateString("0"));
1224 buildPhase->AddAttribute("shellPath",
1225 this->CreateString("/bin/sh"));
1226 this->AddCommandsToBuildPhase(buildPhase, cmtarget, commands,
1231 //----------------------------------------------------------------------------
1232 void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases,
1239 std::vector<cmXCodeObject*>
1242 frameworkBuildPhase,
1245 std::vector<cmCustomCommand> const & prebuild
1246 = cmtarget.GetPreBuildCommands();
1247 std::vector<cmCustomCommand> const & prelink
1248 = cmtarget.GetPreLinkCommands();
1249 std::vector<cmCustomCommand> const & postbuild
1250 = cmtarget.GetPostBuildCommands();
1251 std::vector<cmSourceFile*>const &classes = cmtarget.GetSourceFiles();
1252 // add all the sources
1253 std::vector<cmCustomCommand> commands;
1254 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
1255 i != classes.end(); ++i)
1257 if((*i)->GetCustomCommand())
1259 commands.push_back(*(*i)->GetCustomCommand());
1262 // create prebuild phase
1263 cmXCodeObject* cmakeRulesBuildPhase =
1264 this->CreateBuildPhase("CMake Rules",
1265 "cmakeRulesBuildPhase",
1266 cmtarget, commands);
1267 // create prebuild phase
1268 cmXCodeObject* preBuildPhase =
1269 this->CreateBuildPhase("CMake PreBuild Rules", "preBuildCommands",
1270 cmtarget, prebuild);
1271 // create prelink phase
1272 cmXCodeObject* preLinkPhase =
1273 this->CreateBuildPhase("CMake PreLink Rules", "preLinkCommands",
1275 // create postbuild phase
1276 cmXCodeObject* postBuildPhase =
1277 this->CreateBuildPhase("CMake PostBuild Rules", "postBuildPhase",
1278 cmtarget, postbuild);
1280 // The order here is the order they will be built in.
1281 // The order "headers, resources, sources" mimics a native project generated
1282 // from an xcode template...
1286 buildPhases->AddObject(preBuildPhase);
1288 if(cmakeRulesBuildPhase)
1290 buildPhases->AddObject(cmakeRulesBuildPhase);
1292 if(headerBuildPhase)
1294 buildPhases->AddObject(headerBuildPhase);
1296 if(resourceBuildPhase)
1298 buildPhases->AddObject(resourceBuildPhase);
1300 std::vector<cmXCodeObject*>::iterator cit;
1301 for (cit = contentBuildPhases.begin(); cit != contentBuildPhases.end();
1304 buildPhases->AddObject(*cit);
1306 if(sourceBuildPhase)
1308 buildPhases->AddObject(sourceBuildPhase);
1312 buildPhases->AddObject(preLinkPhase);
1314 if(frameworkBuildPhase)
1316 buildPhases->AddObject(frameworkBuildPhase);
1320 buildPhases->AddObject(postBuildPhase);
1324 //----------------------------------------------------------------------------
1325 // This function removes each occurence of the flag and returns the last one
1326 // (i.e., the dominant flag in GCC)
1327 std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
1330 std::string retFlag;
1331 std::string::size_type pos = flags.rfind(flag);
1333 while(pos != flags.npos)
1335 if(pos == 0 || flags[pos-1]==' ')
1337 while(pos < flags.size() && flags[pos] != ' ')
1341 retFlag += flags[pos];
1348 pos = flags.rfind(flag);
1353 //----------------------------------------------------------------------------
1355 cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
1357 std::vector<cmCustomCommand>
1362 // collect multiple outputs of custom commands into a set
1363 // which will be used for every configuration
1364 std::map<cmStdString, cmStdString> multipleOutputPairs;
1365 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1366 i != commands.end(); ++i)
1368 cmCustomCommand const& cc = *i;
1369 if(!cc.GetCommandLines().empty())
1371 const std::vector<std::string>& outputs = cc.GetOutputs();
1372 if(!outputs.empty())
1374 // If there are more than one outputs treat the
1375 // first as the primary output and make the rest depend on it.
1376 std::vector<std::string>::const_iterator o = outputs.begin();
1377 std::string primaryOutput = this->ConvertToRelativeForMake(o->c_str());
1378 for(++o; o != outputs.end(); ++o)
1380 std::string currentOutput=this->ConvertToRelativeForMake(o->c_str());
1381 multipleOutputPairs[currentOutput] = primaryOutput;
1387 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
1388 dir += "/CMakeScripts";
1389 cmSystemTools::MakeDirectory(dir.c_str());
1390 std::string makefile = dir;
1392 makefile += target.GetName();
1395 makefile += ".make";
1397 for (std::vector<std::string>::const_iterator currentConfig=
1398 this->CurrentConfigurationTypes.begin();
1399 currentConfig!=this->CurrentConfigurationTypes.end();
1402 this->CreateCustomRulesMakefile(makefile.c_str(),
1405 currentConfig->c_str(),
1406 multipleOutputPairs);
1409 std::string cdir = this->CurrentMakefile->GetCurrentOutputDirectory();
1410 cdir = this->ConvertToRelativeForXCode(cdir.c_str());
1411 std::string makecmd = "make -C ";
1414 makecmd += this->ConvertToRelativeForMake(
1415 (makefile+"$CONFIGURATION").c_str());
1416 if(!multipleOutputPairs.empty())
1418 makecmd += " cmake_check_multiple_outputs";
1421 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1422 buildphase->AddAttribute("shellScript",
1423 this->CreateString(makecmd.c_str()));
1424 buildphase->AddAttribute("showEnvVarsInLog",
1425 this->CreateString("0"));
1428 //----------------------------------------------------------------------------
1429 void cmGlobalXCodeGenerator
1430 ::CreateCustomRulesMakefile(const char* makefileBasename,
1432 std::vector<cmCustomCommand>
1434 const char* configName,
1435 const std::map<cmStdString,
1436 cmStdString>& multipleOutputPairs
1439 std::string makefileName=makefileBasename;
1440 if(this->XcodeVersion > 20)
1442 makefileName+=configName;
1444 cmGeneratedFileStream makefileStream(makefileName.c_str());
1449 makefileStream.SetCopyIfDifferent(true);
1450 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
1451 makefileStream << "# Custom rules for " << target.GetName() << "\n";
1453 // disable the implicit rules
1454 makefileStream << ".SUFFIXES: " << "\n";
1456 // have all depend on all outputs
1457 makefileStream << "all: ";
1458 std::map<const cmCustomCommand*, cmStdString> tname;
1460 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1461 i != commands.end(); ++i)
1463 cmCustomCommand const& cc = *i;
1464 if(!cc.GetCommandLines().empty())
1466 const std::vector<std::string>& outputs = cc.GetOutputs();
1467 if(!outputs.empty())
1469 for(std::vector<std::string>::const_iterator o = outputs.begin();
1470 o != outputs.end(); ++o)
1473 << "\\\n\t" << this->ConvertToRelativeForMake(o->c_str());
1478 cmOStringStream str;
1479 str << "_buildpart_" << count++ ;
1480 tname[&cc] = std::string(target.GetName()) + str.str();
1481 makefileStream << "\\\n\t" << tname[&cc];
1485 makefileStream << "\n\n";
1486 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1487 i != commands.end(); ++i)
1489 cmCustomCommand const& cc = *i;
1490 if(!cc.GetCommandLines().empty())
1492 cmCustomCommandGenerator ccg(cc, configName, this->CurrentMakefile);
1493 makefileStream << "\n";
1494 const std::vector<std::string>& outputs = cc.GetOutputs();
1495 if(!outputs.empty())
1497 // There is at least one output, start the rule for it
1498 std::string primary_output =
1499 this->ConvertToRelativeForMake(outputs.begin()->c_str());
1500 makefileStream << primary_output << ": ";
1504 // There are no outputs. Use the generated force rule name.
1505 makefileStream << tname[&cc] << ": ";
1507 for(std::vector<std::string>::const_iterator d =
1508 cc.GetDepends().begin();
1509 d != cc.GetDepends().end(); ++d)
1512 if(this->CurrentLocalGenerator
1513 ->GetRealDependency(d->c_str(), configName, dep))
1515 makefileStream << "\\\n" <<
1516 this->ConvertToRelativeForMake(dep.c_str());
1519 makefileStream << "\n";
1521 if(const char* comment = cc.GetComment())
1523 std::string echo_cmd = "echo ";
1524 echo_cmd += (this->CurrentLocalGenerator->
1525 EscapeForShell(comment, cc.GetEscapeAllowMakeVars()));
1526 makefileStream << "\t" << echo_cmd.c_str() << "\n";
1529 // Add each command line to the set of commands.
1530 for(unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c)
1532 // Build the command line in a single string.
1533 std::string cmd2 = ccg.GetCommand(c);
1534 cmSystemTools::ReplaceString(cmd2, "/./", "/");
1535 cmd2 = this->ConvertToRelativeForMake(cmd2.c_str());
1537 if(cc.GetWorkingDirectory())
1540 cmd += this->ConvertToRelativeForMake(cc.GetWorkingDirectory());
1544 ccg.AppendArguments(c, cmd);
1545 makefileStream << "\t" << cmd.c_str() << "\n";
1550 // Add rules to deal with multiple outputs of custom commands.
1551 if(!multipleOutputPairs.empty())
1554 "\n# Dependencies of multiple outputs to their primary outputs \n";
1556 for(std::map<cmStdString, cmStdString>::const_iterator o =
1557 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1559 makefileStream << o->first << ": " << o->second << "\n";
1564 "cmake_check_multiple_outputs:\n";
1565 for(std::map<cmStdString, cmStdString>::const_iterator o =
1566 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1568 makefileStream << "\t@if [ ! -f "
1569 << o->first << " ]; then rm -f "
1570 << o->second << "; fi\n";
1575 //----------------------------------------------------------------------------
1576 void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
1577 cmXCodeObject* buildSettings,
1578 const char* configName)
1581 std::string defFlags;
1582 bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
1583 (target.GetType() == cmTarget::MODULE_LIBRARY));
1584 bool binary = ((target.GetType() == cmTarget::OBJECT_LIBRARY) ||
1585 (target.GetType() == cmTarget::STATIC_LIBRARY) ||
1586 (target.GetType() == cmTarget::EXECUTABLE) ||
1589 const char* lang = target.GetLinkerLanguage(configName);
1593 // for c++ projects get the c flags as well
1594 if(strcmp(lang, "CXX") == 0)
1596 this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName);
1597 this->CurrentLocalGenerator->AddCMP0018Flags(cflags, &target, "C");
1600 // Add language-specific flags.
1601 this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName);
1603 // Add shared-library flags if needed.
1604 this->CurrentLocalGenerator->AddCMP0018Flags(flags, &target, lang);
1608 cmSystemTools::Error
1609 ("CMake can not determine linker language for target:",
1615 this->CurrentLocalGenerator->
1616 AppendFlags(defFlags,
1617 this->CurrentMakefile->GetDefineFlags());
1619 // Add preprocessor definitions for this target and configuration.
1620 BuildObjectListOrString ppDefs(this, this->XcodeVersion >= 30);
1621 if(this->XcodeVersion > 15)
1623 this->AppendDefines(ppDefs,
1624 "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"");
1626 if(const char* exportMacro = target.GetExportMacro())
1628 // Add the export symbol definition for shared library objects.
1629 this->AppendDefines(ppDefs, exportMacro);
1632 (ppDefs, this->CurrentMakefile->GetProperty("COMPILE_DEFINITIONS"));
1633 this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS"));
1636 std::string defVarName = "COMPILE_DEFINITIONS_";
1637 defVarName += cmSystemTools::UpperCase(configName);
1639 (ppDefs, this->CurrentMakefile->GetProperty(defVarName.c_str()));
1640 this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str()));
1642 buildSettings->AddAttribute
1643 ("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList());
1645 std::string extraLinkOptions;
1646 if(target.GetType() == cmTarget::EXECUTABLE)
1649 this->CurrentMakefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
1650 std::string var = "CMAKE_EXE_LINKER_FLAGS_";
1651 var += cmSystemTools::UpperCase(configName);
1653 this->CurrentMakefile->GetSafeDefinition(var.c_str());
1656 extraLinkOptions += " ";
1657 extraLinkOptions += val;
1660 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1662 extraLinkOptions = this->CurrentMakefile->
1663 GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
1665 if(target.GetType() == cmTarget::MODULE_LIBRARY)
1667 extraLinkOptions = this->CurrentMakefile->
1668 GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
1671 const char* linkFlagsProp = "LINK_FLAGS";
1672 if(target.GetType() == cmTarget::OBJECT_LIBRARY ||
1673 target.GetType() == cmTarget::STATIC_LIBRARY)
1675 linkFlagsProp = "STATIC_LIBRARY_FLAGS";
1677 const char* targetLinkFlags = target.GetProperty(linkFlagsProp);
1680 extraLinkOptions += " ";
1681 extraLinkOptions += targetLinkFlags;
1683 if(configName && *configName)
1685 std::string linkFlagsVar = linkFlagsProp;
1686 linkFlagsVar += "_";
1687 linkFlagsVar += cmSystemTools::UpperCase(configName);
1688 if(const char* linkFlags = target.GetProperty(linkFlagsVar.c_str()))
1690 extraLinkOptions += " ";
1691 extraLinkOptions += linkFlags;
1695 // Set target-specific architectures.
1696 std::vector<std::string> archs;
1697 target.GetAppleArchs(configName, archs);
1700 // Enable ARCHS attribute.
1701 buildSettings->AddAttribute("ONLY_ACTIVE_ARCH",
1702 this->CreateString("NO"));
1704 // Store ARCHS value.
1705 if(archs.size() == 1)
1707 buildSettings->AddAttribute("ARCHS",
1708 this->CreateString(archs[0].c_str()));
1712 cmXCodeObject* archObjects =
1713 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1714 for(std::vector<std::string>::iterator i = archs.begin();
1715 i != archs.end(); i++)
1717 archObjects->AddObject(this->CreateString((*i).c_str()));
1719 buildSettings->AddAttribute("ARCHS", archObjects);
1723 // Get the product name components.
1724 std::string pnprefix;
1726 std::string pnsuffix;
1728 target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
1730 // Set attributes to specify the proper name for the target.
1731 std::string pndir = this->CurrentMakefile->GetCurrentOutputDirectory();
1732 if(target.GetType() == cmTarget::STATIC_LIBRARY ||
1733 target.GetType() == cmTarget::SHARED_LIBRARY ||
1734 target.GetType() == cmTarget::MODULE_LIBRARY ||
1735 target.GetType() == cmTarget::EXECUTABLE)
1737 if(this->XcodeVersion >= 21)
1739 if(!target.UsesDefaultOutputDir(configName, false))
1741 std::string pncdir = target.GetDirectory(configName);
1742 buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
1743 this->CreateString(pncdir.c_str()));
1748 buildSettings->AddAttribute("OBJROOT",
1749 this->CreateString(pndir.c_str()));
1750 pndir = target.GetDirectory(configName);
1753 buildSettings->AddAttribute("EXECUTABLE_PREFIX",
1754 this->CreateString(pnprefix.c_str()));
1755 buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
1756 this->CreateString(pnsuffix.c_str()));
1758 else if(target.GetType() == cmTarget::OBJECT_LIBRARY)
1761 pnbase = target.GetName();
1764 if(this->XcodeVersion >= 21)
1766 std::string pncdir = this->GetObjectsNormalDirectory(
1767 this->CurrentProject, configName, &target);
1768 buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
1769 this->CreateString(pncdir.c_str()));
1773 buildSettings->AddAttribute("OBJROOT",
1774 this->CreateString(pndir.c_str()));
1775 pndir = this->GetObjectsNormalDirectory(
1776 this->CurrentProject, configName, &target);
1780 // Store the product name for all target types.
1781 buildSettings->AddAttribute("PRODUCT_NAME",
1782 this->CreateString(pnbase.c_str()));
1783 buildSettings->AddAttribute("SYMROOT",
1784 this->CreateString(pndir.c_str()));
1786 // Handle settings for each target type.
1787 switch(target.GetType())
1789 case cmTarget::OBJECT_LIBRARY:
1790 case cmTarget::STATIC_LIBRARY:
1792 buildSettings->AddAttribute("LIBRARY_STYLE",
1793 this->CreateString("STATIC"));
1797 case cmTarget::MODULE_LIBRARY:
1799 buildSettings->AddAttribute("LIBRARY_STYLE",
1800 this->CreateString("BUNDLE"));
1801 if (target.GetPropertyAsBool("BUNDLE"))
1803 // It turns out that a BUNDLE is basically the same
1804 // in many ways as an application bundle, as far as
1806 std::string createFlags =
1807 this->LookupFlags("CMAKE_SHARED_MODULE_CREATE_", lang, "_FLAGS",
1809 if(!createFlags.empty())
1811 extraLinkOptions += " ";
1812 extraLinkOptions += createFlags;
1814 std::string plist = this->ComputeInfoPListLocation(target);
1815 // Xcode will create the final version of Info.plist at build time,
1816 // so let it replace the cfbundle name. This avoids creating
1817 // a per-configuration Info.plist file. The cfbundle plist
1818 // is very similar to the application bundle plist
1819 this->CurrentLocalGenerator
1820 ->GenerateAppleInfoPList(&target, "$(EXECUTABLE_NAME)",
1823 this->ConvertToRelativeForXCode(plist.c_str());
1824 buildSettings->AddAttribute("INFOPLIST_FILE",
1825 this->CreateString(path.c_str()));
1827 else if(this->XcodeVersion >= 22)
1829 buildSettings->AddAttribute("MACH_O_TYPE",
1830 this->CreateString("mh_bundle"));
1831 buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
1832 this->CreateString("NO"));
1833 // Add the flags to create an executable.
1834 std::string createFlags =
1835 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1836 if(!createFlags.empty())
1838 extraLinkOptions += " ";
1839 extraLinkOptions += createFlags;
1844 // Add the flags to create a module.
1845 std::string createFlags =
1846 this->LookupFlags("CMAKE_SHARED_MODULE_CREATE_", lang, "_FLAGS",
1848 if(!createFlags.empty())
1850 extraLinkOptions += " ";
1851 extraLinkOptions += createFlags;
1856 case cmTarget::SHARED_LIBRARY:
1858 if(target.GetPropertyAsBool("FRAMEWORK"))
1860 std::string version = target.GetFrameworkVersion();
1861 buildSettings->AddAttribute("FRAMEWORK_VERSION",
1862 this->CreateString(version.c_str()));
1864 std::string plist = this->ComputeInfoPListLocation(target);
1865 // Xcode will create the final version of Info.plist at build time,
1866 // so let it replace the framework name. This avoids creating
1867 // a per-configuration Info.plist file.
1868 this->CurrentLocalGenerator
1869 ->GenerateFrameworkInfoPList(&target, "$(EXECUTABLE_NAME)",
1872 this->ConvertToRelativeForXCode(plist.c_str());
1873 buildSettings->AddAttribute("INFOPLIST_FILE",
1874 this->CreateString(path.c_str()));
1878 // Add the flags to create a shared library.
1879 std::string createFlags =
1880 this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", lang, "_FLAGS",
1882 if(!createFlags.empty())
1884 extraLinkOptions += " ";
1885 extraLinkOptions += createFlags;
1889 buildSettings->AddAttribute("LIBRARY_STYLE",
1890 this->CreateString("DYNAMIC"));
1893 case cmTarget::EXECUTABLE:
1895 // Add the flags to create an executable.
1896 std::string createFlags =
1897 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1898 if(!createFlags.empty())
1900 extraLinkOptions += " ";
1901 extraLinkOptions += createFlags;
1904 // Handle bundles and normal executables separately.
1905 if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
1907 std::string plist = this->ComputeInfoPListLocation(target);
1908 // Xcode will create the final version of Info.plist at build time,
1909 // so let it replace the executable name. This avoids creating
1910 // a per-configuration Info.plist file.
1911 this->CurrentLocalGenerator
1912 ->GenerateAppleInfoPList(&target, "$(EXECUTABLE_NAME)",
1915 this->ConvertToRelativeForXCode(plist.c_str());
1916 buildSettings->AddAttribute("INFOPLIST_FILE",
1917 this->CreateString(path.c_str()));
1925 if(this->XcodeVersion >= 22 && this->XcodeVersion < 40)
1927 buildSettings->AddAttribute("PREBINDING",
1928 this->CreateString("NO"));
1931 BuildObjectListOrString dirs(this, this->XcodeVersion >= 30);
1932 BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30);
1933 std::vector<std::string> includes;
1934 this->CurrentLocalGenerator->GetIncludeDirectories(includes, &target);
1935 std::set<cmStdString> emitted;
1936 emitted.insert("/System/Library/Frameworks");
1937 for(std::vector<std::string>::iterator i = includes.begin();
1938 i != includes.end(); ++i)
1940 if(this->NameResolvesToFramework(i->c_str()))
1942 std::string frameworkDir = *i;
1943 frameworkDir += "/../";
1944 frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str());
1945 if(emitted.insert(frameworkDir).second)
1947 fdirs.Add(this->XCodeEscapePath(frameworkDir.c_str()).c_str());
1952 std::string incpath =
1953 this->XCodeEscapePath(i->c_str());
1954 dirs.Add(incpath.c_str());
1957 std::vector<std::string>& frameworks = target.GetFrameworks();
1958 if(frameworks.size())
1960 for(std::vector<std::string>::iterator fmIt = frameworks.begin();
1961 fmIt != frameworks.end(); ++fmIt)
1963 if(emitted.insert(*fmIt).second)
1965 fdirs.Add(this->XCodeEscapePath(fmIt->c_str()).c_str());
1969 if(!fdirs.IsEmpty())
1971 buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS",
1972 fdirs.CreateList());
1976 buildSettings->AddAttribute("HEADER_SEARCH_PATHS",
1979 std::string oflagc = this->ExtractFlag("-O", cflags);
1983 if(oflagc.size() == 3)
1985 optLevel[0] = oflagc[2];
1987 if(oflagc.size() == 2)
1991 std::string oflag = this->ExtractFlag("-O", flags);
1992 if(oflag.size() == 3)
1994 optLevel[0] = oflag[2];
1996 if(oflag.size() == 2)
2000 std::string gflagc = this->ExtractFlag("-g", cflags);
2001 // put back gdwarf-2 if used since there is no way
2002 // to represent it in the gui, but we still want debug yes
2003 if(gflagc == "-gdwarf-2")
2008 std::string gflag = this->ExtractFlag("-g", flags);
2009 if(gflag == "-gdwarf-2")
2014 const char* debugStr = "YES";
2015 // We can't set the Xcode flag differently depending on the language,
2016 // so put them back in this case.
2017 if( (lang && strcmp(lang, "CXX") == 0) && gflag != gflagc )
2025 if( gflag == "-g0" || gflag.size() == 0 )
2030 buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
2031 this->CreateString(debugStr));
2032 buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
2033 this->CreateString(optLevel));
2034 buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
2035 this->CreateString("NO"));
2036 buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
2037 this->CreateString("NO"));
2038 if(lang && strcmp(lang, "CXX") == 0)
2042 buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
2043 this->CreateString(flags.c_str()));
2046 buildSettings->AddAttribute("OTHER_CFLAGS",
2047 this->CreateString(cflags.c_str()));
2054 buildSettings->AddAttribute("OTHER_CFLAGS",
2055 this->CreateString(flags.c_str()));
2058 // Add Fortran source format attribute if property is set.
2059 const char* format = 0;
2060 const char* tgtfmt = target.GetProperty("Fortran_FORMAT");
2061 switch(this->CurrentLocalGenerator->GetFortranFormat(tgtfmt))
2063 case cmLocalGenerator::FortranFormatFixed: format = "fixed"; break;
2064 case cmLocalGenerator::FortranFormatFree: format = "free"; break;
2069 buildSettings->AddAttribute("IFORT_LANG_SRCFMT",
2070 this->CreateString(format));
2073 // Create the INSTALL_PATH attribute.
2074 std::string install_name_dir;
2075 if(target.GetType() == cmTarget::SHARED_LIBRARY)
2077 // Get the install_name directory for the build tree.
2078 install_name_dir = target.GetInstallNameDirForBuildTree(configName, true);
2079 if(install_name_dir.empty())
2081 // Xcode will not pass the -install_name option at all if INSTALL_PATH
2082 // is not given or is empty. We must explicitly put the flag in the
2083 // link flags to create an install_name with just the library soname.
2084 extraLinkOptions += " -install_name ";
2085 extraLinkOptions += target.GetFullName(configName);
2089 // Convert to a path for the native build tool.
2090 cmSystemTools::ConvertToUnixSlashes(install_name_dir);
2091 // do not escape spaces on this since it is only a single path
2094 buildSettings->AddAttribute("INSTALL_PATH",
2095 this->CreateString(install_name_dir.c_str()));
2097 buildSettings->AddAttribute("OTHER_LDFLAGS",
2098 this->CreateString(extraLinkOptions.c_str()));
2099 buildSettings->AddAttribute("OTHER_REZFLAGS",
2100 this->CreateString(""));
2101 buildSettings->AddAttribute("SECTORDER_FLAGS",
2102 this->CreateString(""));
2103 buildSettings->AddAttribute("USE_HEADERMAP",
2104 this->CreateString("NO"));
2105 if (this->XcodeVersion >= 30)
2107 cmXCodeObject *group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2108 group->AddObject(this->CreateString("-Wmost"));
2109 group->AddObject(this->CreateString("-Wno-four-char-constants"));
2110 group->AddObject(this->CreateString("-Wno-unknown-pragmas"));
2111 buildSettings->AddAttribute("WARNING_CFLAGS", group);
2115 buildSettings->AddAttribute("WARNING_CFLAGS",
2117 "-Wmost -Wno-four-char-constants"
2118 " -Wno-unknown-pragmas"));
2121 // Runtime version information.
2122 if(target.GetType() == cmTarget::SHARED_LIBRARY)
2128 // VERSION -> current_version
2129 target.GetTargetVersion(false, major, minor, patch);
2132 // Xcode always wants at least 1.0.0 or nothing
2133 if(!(major == 0 && minor == 0 && patch == 0))
2135 v << major << "." << minor << "." << patch;
2137 buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
2138 this->CreateString(v.str().c_str()));
2140 // SOVERSION -> compatibility_version
2141 target.GetTargetVersion(true, major, minor, patch);
2142 cmOStringStream vso;
2144 // Xcode always wants at least 1.0.0 or nothing
2145 if(!(major == 0 && minor == 0 && patch == 0))
2147 vso << major << "." << minor << "." << patch;
2149 buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
2150 this->CreateString(vso.str().c_str()));
2152 // put this last so it can override existing settings
2153 // Convert "XCODE_ATTRIBUTE_*" properties directly.
2155 cmPropertyMap const& props = target.GetProperties();
2156 for(cmPropertyMap::const_iterator i = props.begin();
2157 i != props.end(); ++i)
2159 if(i->first.find("XCODE_ATTRIBUTE_") == 0)
2161 buildSettings->AddAttribute(i->first.substr(16).c_str(),
2162 this->CreateString(i->second.GetValue()));
2168 //----------------------------------------------------------------------------
2170 cmGlobalXCodeGenerator::CreateUtilityTarget(cmTarget& cmtarget)
2172 cmXCodeObject* shellBuildPhase =
2173 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
2174 shellBuildPhase->AddAttribute("buildActionMask",
2175 this->CreateString("2147483647"));
2176 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2177 shellBuildPhase->AddAttribute("files", buildFiles);
2178 cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2179 shellBuildPhase->AddAttribute("inputPaths", inputPaths);
2180 cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2181 shellBuildPhase->AddAttribute("outputPaths", outputPaths);
2182 shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
2183 this->CreateString("0"));
2184 shellBuildPhase->AddAttribute("shellPath",
2185 this->CreateString("/bin/sh"));
2186 shellBuildPhase->AddAttribute("shellScript",
2188 "# shell script goes here\nexit 0"));
2189 shellBuildPhase->AddAttribute("showEnvVarsInLog",
2190 this->CreateString("0"));
2192 cmXCodeObject* target =
2193 this->CreateObject(cmXCodeObject::PBXAggregateTarget);
2194 target->SetComment(cmtarget.GetName());
2195 cmXCodeObject* buildPhases =
2196 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2197 std::vector<cmXCodeObject*> emptyContentVector;
2198 this->CreateCustomCommands(buildPhases, 0, 0, 0, emptyContentVector, 0,
2200 target->AddAttribute("buildPhases", buildPhases);
2201 if(this->XcodeVersion > 20)
2203 this->AddConfigurations(target, cmtarget);
2207 const char* theConfig =
2208 this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
2209 cmXCodeObject* buildSettings =
2210 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2211 this->CreateBuildSettings(cmtarget, buildSettings, theConfig);
2212 target->AddAttribute("buildSettings", buildSettings);
2214 cmXCodeObject* dependencies =
2215 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2216 target->AddAttribute("dependencies", dependencies);
2217 target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
2218 target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
2219 target->SetTarget(&cmtarget);
2221 // Add source files without build rules for editing convenience.
2222 if(cmtarget.GetType() == cmTarget::UTILITY)
2224 std::vector<cmSourceFile*> const& sources = cmtarget.GetSourceFiles();
2225 for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
2226 i != sources.end(); ++i)
2228 if(!(*i)->GetPropertyAsBool("GENERATED"))
2230 this->CreateXCodeFileReference(*i, cmtarget);
2235 target->SetId(this->GetOrCreateId(
2236 cmtarget.GetName(), target->GetId()).c_str());
2241 //----------------------------------------------------------------------------
2242 std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
2245 std::string configTypes =
2246 this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
2247 std::vector<std::string> configVectorIn;
2248 std::vector<std::string> configVector;
2249 configVectorIn.push_back(configTypes);
2250 cmSystemTools::ExpandList(configVectorIn, configVector);
2251 cmXCodeObject* configlist =
2252 this->CreateObject(cmXCodeObject::XCConfigurationList);
2253 cmXCodeObject* buildConfigurations =
2254 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2255 configlist->AddAttribute("buildConfigurations", buildConfigurations);
2256 std::string comment = "Build configuration list for ";
2257 comment += cmXCodeObject::PBXTypeNames[target->GetIsA()];
2259 comment += cmtarget.GetName();
2261 configlist->SetComment(comment.c_str());
2262 target->AddAttribute("buildConfigurationList",
2263 this->CreateObjectReference(configlist));
2264 for(unsigned int i = 0; i < configVector.size(); ++i)
2266 cmXCodeObject* config =
2267 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2268 buildConfigurations->AddObject(config);
2269 cmXCodeObject* buildSettings =
2270 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2271 this->CreateBuildSettings(cmtarget, buildSettings,
2272 configVector[i].c_str());
2273 config->AddAttribute("name", this->CreateString(configVector[i].c_str()));
2274 config->SetComment(configVector[i].c_str());
2275 config->AddAttribute("buildSettings", buildSettings);
2277 if(configVector.size())
2279 configlist->AddAttribute("defaultConfigurationName",
2280 this->CreateString(configVector[0].c_str()));
2281 configlist->AddAttribute("defaultConfigurationIsVisible",
2282 this->CreateString("0"));
2283 return configVector[0];
2288 //----------------------------------------------------------------------------
2289 const char* cmGlobalXCodeGenerator::GetTargetFileType(cmTarget& cmtarget)
2291 switch(cmtarget.GetType())
2293 case cmTarget::OBJECT_LIBRARY:
2294 case cmTarget::STATIC_LIBRARY:
2295 return "archive.ar";
2296 case cmTarget::MODULE_LIBRARY:
2297 if (cmtarget.IsCFBundleOnApple())
2298 return "wrapper.plug-in";
2300 return ((this->XcodeVersion >= 22)?
2301 "compiled.mach-o.executable" : "compiled.mach-o.dylib");
2302 case cmTarget::SHARED_LIBRARY:
2303 return (cmtarget.GetPropertyAsBool("FRAMEWORK")?
2304 "wrapper.framework" : "compiled.mach-o.dylib");
2305 case cmTarget::EXECUTABLE:
2306 return "compiled.mach-o.executable";
2312 //----------------------------------------------------------------------------
2313 const char* cmGlobalXCodeGenerator::GetTargetProductType(cmTarget& cmtarget)
2315 switch(cmtarget.GetType())
2317 case cmTarget::OBJECT_LIBRARY:
2318 case cmTarget::STATIC_LIBRARY:
2319 return "com.apple.product-type.library.static";
2320 case cmTarget::MODULE_LIBRARY:
2321 if (cmtarget.IsCFBundleOnApple())
2322 return "com.apple.product-type.bundle";
2324 return ((this->XcodeVersion >= 22)?
2325 "com.apple.product-type.tool" :
2326 "com.apple.product-type.library.dynamic");
2327 case cmTarget::SHARED_LIBRARY:
2328 return (cmtarget.GetPropertyAsBool("FRAMEWORK")?
2329 "com.apple.product-type.framework" :
2330 "com.apple.product-type.library.dynamic");
2331 case cmTarget::EXECUTABLE:
2332 return (cmtarget.GetPropertyAsBool("MACOSX_BUNDLE")?
2333 "com.apple.product-type.application" :
2334 "com.apple.product-type.tool");
2340 //----------------------------------------------------------------------------
2342 cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
2343 cmXCodeObject* buildPhases)
2345 cmXCodeObject* target =
2346 this->CreateObject(cmXCodeObject::PBXNativeTarget);
2347 target->AddAttribute("buildPhases", buildPhases);
2348 cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2349 target->AddAttribute("buildRules", buildRules);
2350 std::string defConfig;
2351 if(this->XcodeVersion > 20)
2353 defConfig = this->AddConfigurations(target, cmtarget);
2357 cmXCodeObject* buildSettings =
2358 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2359 defConfig = this->CurrentMakefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
2360 this->CreateBuildSettings(cmtarget, buildSettings, defConfig.c_str());
2361 target->AddAttribute("buildSettings", buildSettings);
2363 cmXCodeObject* dependencies =
2364 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2365 target->AddAttribute("dependencies", dependencies);
2366 target->AddAttribute("name", this->CreateString(cmtarget.GetName()));
2367 target->AddAttribute("productName",this->CreateString(cmtarget.GetName()));
2369 cmXCodeObject* fileRef =
2370 this->CreateObject(cmXCodeObject::PBXFileReference);
2371 if(const char* fileType = this->GetTargetFileType(cmtarget))
2373 fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
2375 std::string fullName;
2376 if(cmtarget.GetType() == cmTarget::OBJECT_LIBRARY)
2379 fullName += cmtarget.GetName();
2384 fullName = cmtarget.GetFullName(defConfig.c_str());
2386 fileRef->AddAttribute("path", this->CreateString(fullName.c_str()));
2387 fileRef->AddAttribute("refType", this->CreateString("0"));
2388 fileRef->AddAttribute("sourceTree",
2389 this->CreateString("BUILT_PRODUCTS_DIR"));
2390 fileRef->SetComment(cmtarget.GetName());
2391 target->AddAttribute("productReference",
2392 this->CreateObjectReference(fileRef));
2393 if(const char* productType = this->GetTargetProductType(cmtarget))
2395 target->AddAttribute("productType", this->CreateString(productType));
2397 target->SetTarget(&cmtarget);
2398 target->SetId(this->GetOrCreateId(
2399 cmtarget.GetName(), target->GetId()).c_str());
2403 //----------------------------------------------------------------------------
2404 cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
2410 for(std::vector<cmXCodeObject*>::iterator i = this->XCodeObjects.begin();
2411 i != this->XCodeObjects.end(); ++i)
2413 cmXCodeObject* o = *i;
2414 if(o->GetTarget() == t)
2422 //----------------------------------------------------------------------------
2423 std::string cmGlobalXCodeGenerator::GetOrCreateId(const char* name,
2426 std::string guidStoreName = name;
2427 guidStoreName += "_GUID_CMAKE";
2428 const char* storedGUID =
2429 this->CMakeInstance->GetCacheDefinition(guidStoreName.c_str());
2436 this->CMakeInstance->AddCacheEntry(guidStoreName.c_str(),
2437 id, "Stored Xcode object GUID", cmCacheManager::INTERNAL);
2442 //----------------------------------------------------------------------------
2443 void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
2444 cmXCodeObject* dependTarget)
2446 // make sure a target does not depend on itself
2447 if(target == dependTarget)
2451 // now avoid circular references if dependTarget already
2452 // depends on target then skip it. Circular references crashes
2454 cmXCodeObject* dependTargetDepends =
2455 dependTarget->GetObject("dependencies");
2456 if(dependTargetDepends)
2458 if(dependTargetDepends->HasObject(target->GetPBXTargetDependency()))
2464 cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency();
2467 cmXCodeObject* container =
2468 this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
2469 container->SetComment("PBXContainerItemProxy");
2470 container->AddAttribute("containerPortal",
2471 this->CreateObjectReference(this->RootObject));
2472 container->AddAttribute("proxyType", this->CreateString("1"));
2473 container->AddAttribute("remoteGlobalIDString",
2474 this->CreateObjectReference(dependTarget));
2475 container->AddAttribute("remoteInfo",
2477 dependTarget->GetTarget()->GetName()));
2479 this->CreateObject(cmXCodeObject::PBXTargetDependency);
2480 targetdep->SetComment("PBXTargetDependency");
2481 targetdep->AddAttribute("target",
2482 this->CreateObjectReference(dependTarget));
2483 targetdep->AddAttribute("targetProxy",
2484 this->CreateObjectReference(container));
2485 dependTarget->SetPBXTargetDependency(targetdep);
2488 cmXCodeObject* depends = target->GetObject("dependencies");
2492 Error("target does not have dependencies attribute error..");
2497 depends->AddUniqueObject(targetdep);
2501 //----------------------------------------------------------------------------
2502 void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
2503 const char* attribute,
2508 cmXCodeObject* attr = settings->GetObject(attribute);
2511 settings->AddAttribute(attribute, this->CreateString(value));
2515 std::string oldValue = attr->GetString();
2518 attr->SetString(oldValue.c_str());
2523 //----------------------------------------------------------------------------
2524 void cmGlobalXCodeGenerator
2525 ::AppendBuildSettingAttribute(cmXCodeObject* target,
2526 const char* attribute,
2528 const char* configName)
2530 if(this->XcodeVersion < 21)
2532 // There is only one configuration. Add the setting to the buildSettings
2534 this->AppendOrAddBuildSetting(target->GetObject("buildSettings"),
2539 // There are multiple configurations. Add the setting to the
2540 // buildSettings of the configuration name given.
2541 cmXCodeObject* configurationList =
2542 target->GetObject("buildConfigurationList")->GetObject();
2543 cmXCodeObject* buildConfigs =
2544 configurationList->GetObject("buildConfigurations");
2545 std::vector<cmXCodeObject*> list = buildConfigs->GetObjectList();
2546 // each configuration and the target itself has a buildSettings in it
2547 //list.push_back(target);
2548 for(std::vector<cmXCodeObject*>::iterator i = list.begin();
2549 i != list.end(); ++i)
2553 if(strcmp((*i)->GetObject("name")->GetString(), configName) == 0)
2555 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2556 this->AppendOrAddBuildSetting(settings, attribute, value);
2561 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2562 this->AppendOrAddBuildSetting(settings, attribute, value);
2568 //----------------------------------------------------------------------------
2569 void cmGlobalXCodeGenerator
2570 ::AddDependAndLinkInformation(cmXCodeObject* target)
2572 cmTarget* cmtarget = target->GetTarget();
2575 cmSystemTools::Error("Error no target on xobject\n");
2579 // Add dependencies on other CMake targets.
2580 TargetDependSet const& deps = this->GetTargetDirectDepends(*cmtarget);
2581 for(TargetDependSet::const_iterator i = deps.begin(); i != deps.end(); ++i)
2583 if(cmXCodeObject* dptarget = this->FindXCodeTarget(*i))
2585 this->AddDependTarget(target, dptarget);
2589 // Skip link information for static libraries.
2590 if(cmtarget->GetType() == cmTarget::OBJECT_LIBRARY ||
2591 cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
2596 // Loop over configuration types and set per-configuration info.
2597 for(std::vector<std::string>::iterator i =
2598 this->CurrentConfigurationTypes.begin();
2599 i != this->CurrentConfigurationTypes.end(); ++i)
2601 // Get the current configuration name.
2602 const char* configName = i->c_str();
2608 // Compute the link library and directory information.
2609 cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName);
2614 cmComputeLinkInformation& cli = *pcli;
2616 // Add dependencies directly on library files.
2618 std::vector<std::string> const& libDeps = cli.GetDepends();
2619 for(std::vector<std::string>::const_iterator j = libDeps.begin();
2620 j != libDeps.end(); ++j)
2622 target->AddDependLibrary(configName, j->c_str());
2626 // add the library search paths
2628 std::vector<std::string> const& libDirs = cli.GetDirectories();
2629 std::string linkDirs;
2630 for(std::vector<std::string>::const_iterator libDir = libDirs.begin();
2631 libDir != libDirs.end(); ++libDir)
2633 if(libDir->size() && *libDir != "/usr/lib")
2635 if(this->XcodeVersion > 15)
2637 // Now add the same one but append
2638 // $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) to it:
2640 linkDirs += this->XCodeEscapePath(
2641 (*libDir + "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)").c_str());
2644 linkDirs += this->XCodeEscapePath(libDir->c_str());
2647 this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
2648 linkDirs.c_str(), configName);
2651 // add the framework search paths
2653 const char* sep = "";
2655 std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
2656 for(std::vector<std::string>::const_iterator fdi = fwDirs.begin();
2657 fdi != fwDirs.end(); ++fdi)
2661 fdirs += this->XCodeEscapePath(fdi->c_str());
2665 this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
2666 fdirs.c_str(), configName);
2670 // now add the link libraries
2672 std::string linkLibs;
2673 const char* sep = "";
2674 typedef cmComputeLinkInformation::ItemVector ItemVector;
2675 ItemVector const& libNames = cli.GetItems();
2676 for(ItemVector::const_iterator li = libNames.begin();
2677 li != libNames.end(); ++li)
2683 linkLibs += this->XCodeEscapePath(li->Value.c_str());
2687 linkLibs += li->Value;
2689 if(li->Target && !li->Target->IsImported())
2691 target->AddDependTarget(configName, li->Target->GetName());
2694 this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
2695 linkLibs.c_str(), configName);
2700 //----------------------------------------------------------------------------
2701 void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
2702 std::vector<cmLocalGenerator*>&
2705 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2706 i != generators.end(); ++i)
2708 if(this->IsExcluded(root, *i))
2712 cmMakefile* mf = (*i)->GetMakefile();
2713 std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
2714 cmTargets &tgts = mf->GetTargets();
2715 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
2717 cmTarget& cmtarget = l->second;
2719 // Same skipping logic here as in CreateXCodeTargets so that we do not
2720 // end up with (empty anyhow) ALL_BUILD and XCODE_DEPEND_HELPER source
2723 if(cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
2728 // add the soon to be generated Info.plist file as a source for a
2729 // MACOSX_BUNDLE file
2730 if(cmtarget.GetPropertyAsBool("MACOSX_BUNDLE"))
2732 std::string plist = this->ComputeInfoPListLocation(cmtarget);
2733 cmSourceFile* sf = mf->GetOrCreateSource(plist.c_str(), true);
2734 cmtarget.AddSourceFile(sf);
2737 std::vector<cmSourceFile*> classes = cmtarget.GetSourceFiles();
2739 // Put cmSourceFile instances in proper groups:
2740 for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
2741 s != classes.end(); s++)
2743 cmSourceFile* sf = *s;
2744 // Add the file to the list of sources.
2745 std::string const& source = sf->GetFullPath();
2746 cmSourceGroup& sourceGroup =
2747 mf->FindSourceGroup(source.c_str(), sourceGroups);
2748 cmXCodeObject* pbxgroup =
2749 this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
2750 cmStdString key = GetGroupMapKey(cmtarget, sf);
2751 this->GroupMap[key] = pbxgroup;
2754 // Put OBJECT_LIBRARY objects in proper groups:
2755 std::vector<std::string> objs;
2756 this->GetGeneratorTarget(&cmtarget)->UseObjectLibraries(objs);
2757 for(std::vector<std::string>::const_iterator
2758 oi = objs.begin(); oi != objs.end(); ++oi)
2760 std::string const& source = *oi;
2761 cmSourceGroup& sourceGroup =
2762 mf->FindSourceGroup(source.c_str(), sourceGroups);
2763 cmXCodeObject* pbxgroup =
2764 this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
2765 cmStdString key = GetGroupMapKeyFromPath(cmtarget, source);
2766 this->GroupMap[key] = pbxgroup;
2772 cmXCodeObject *cmGlobalXCodeGenerator
2773 ::CreatePBXGroup(cmXCodeObject *parent, cmStdString name)
2775 cmXCodeObject* parentChildren = NULL;
2777 parentChildren = parent->GetObject("children");
2778 cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
2779 cmXCodeObject* groupChildren =
2780 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2781 group->AddAttribute("name", this->CreateString(name.c_str()));
2782 group->AddAttribute("children", groupChildren);
2783 if(this->XcodeVersion == 15)
2785 group->AddAttribute("refType", this->CreateString("4"));
2787 group->AddAttribute("sourceTree", this->CreateString("<group>"));
2789 parentChildren->AddObject(group);
2793 //----------------------------------------------------------------------------
2794 cmXCodeObject* cmGlobalXCodeGenerator
2795 ::CreateOrGetPBXGroup(cmTarget& cmtarget, cmSourceGroup* sg)
2799 const char *targetFolder= cmtarget.GetProperty("FOLDER");
2801 target = targetFolder;
2804 target += cmtarget.GetName();
2806 s += sg->GetFullName();
2807 std::map<cmStdString, cmXCodeObject* >::iterator it =
2808 this->GroupNameMap.find(s);
2809 if(it != this->GroupNameMap.end())
2814 it = this->TargetGroup.find(target);
2815 cmXCodeObject* tgroup = 0;
2816 if(it != this->TargetGroup.end())
2818 tgroup = it->second;
2822 std::vector<std::string> tgt_folders =
2823 cmSystemTools::tokenize(target, "/");
2824 cmStdString curr_tgt_folder;
2825 for(std::vector<std::string>::size_type i = 0; i < tgt_folders.size();i++)
2827 curr_tgt_folder += tgt_folders[i];
2828 it = this->TargetGroup.find(curr_tgt_folder);
2829 if(it == this->TargetGroup.end())
2831 tgroup = this->CreatePBXGroup(tgroup,tgt_folders[i]);
2832 this->TargetGroup[curr_tgt_folder] = tgroup;
2836 tgroup = it->second;
2841 this->SourcesGroupChildren->AddObject(tgroup);
2843 curr_tgt_folder += "/";
2846 this->TargetGroup[target] = tgroup;
2848 // If it's the default source group (empty name) then put the source file
2849 // directly in the tgroup...
2851 if (cmStdString(sg->GetFullName()) == "")
2853 this->GroupNameMap[s] = tgroup;
2857 //It's a recursive folder structure, let's find the real parent group
2858 if(std::string(sg->GetFullName()) != std::string(sg->GetName()))
2860 std::vector<std::string> folders =
2861 cmSystemTools::tokenize(sg->GetFullName(), "\\");
2862 cmStdString curr_folder = cmtarget.GetName();
2864 for(std::vector<std::string>::size_type i = 0; i < folders.size();i++)
2866 curr_folder += folders[i];
2867 std::map<cmStdString, cmXCodeObject* >::iterator i_folder =
2868 this->GroupNameMap.find(curr_folder);
2870 if(i_folder == this->GroupNameMap.end())
2872 cmXCodeObject *group = this->CreatePBXGroup(tgroup,folders[i]);
2873 this->GroupNameMap[curr_folder] = group;
2878 tgroup = i_folder->second;
2880 curr_folder = curr_folder + "\\";
2884 cmXCodeObject *group = this->CreatePBXGroup(tgroup,sg->GetName());
2885 this->GroupNameMap[s] = group;
2889 //----------------------------------------------------------------------------
2890 void cmGlobalXCodeGenerator
2891 ::CreateXCodeObjects(cmLocalGenerator* root,
2892 std::vector<cmLocalGenerator*>&
2895 this->ClearXCodeObjects();
2896 this->RootObject = 0;
2897 this->SourcesGroupChildren = 0;
2898 this->ResourcesGroupChildren = 0;
2899 this->MainGroupChildren = 0;
2900 cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2901 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2902 cmXCodeObject* developBuildStyle =
2903 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2904 cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2905 if(this->XcodeVersion == 15)
2907 developBuildStyle->AddAttribute("name",
2908 this->CreateString("Development"));
2909 developBuildStyle->AddAttribute("buildSettings", group);
2910 listObjs->AddObject(developBuildStyle);
2911 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2912 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
2913 cmXCodeObject* deployBuildStyle =
2914 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2915 deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
2916 deployBuildStyle->AddAttribute("buildSettings", group);
2917 listObjs->AddObject(deployBuildStyle);
2921 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2923 cmXCodeObject* buildStyle =
2924 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2925 const char* name = this->CurrentConfigurationTypes[i].c_str();
2926 buildStyle->AddAttribute("name", this->CreateString(name));
2927 buildStyle->SetComment(name);
2928 cmXCodeObject* sgroup =
2929 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2930 sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2931 buildStyle->AddAttribute("buildSettings", sgroup);
2932 listObjs->AddObject(buildStyle);
2936 cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2937 this->MainGroupChildren =
2938 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2939 mainGroup->AddAttribute("children", this->MainGroupChildren);
2940 if(this->XcodeVersion == 15)
2942 mainGroup->AddAttribute("refType", this->CreateString("4"));
2944 mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2946 cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2947 this->SourcesGroupChildren =
2948 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2949 sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
2950 sourcesGroup->AddAttribute("children", this->SourcesGroupChildren);
2951 if(this->XcodeVersion == 15)
2953 sourcesGroup->AddAttribute("refType", this->CreateString("4"));
2955 sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2956 this->MainGroupChildren->AddObject(sourcesGroup);
2958 cmXCodeObject* resourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2959 this->ResourcesGroupChildren =
2960 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2961 resourcesGroup->AddAttribute("name", this->CreateString("Resources"));
2962 resourcesGroup->AddAttribute("children", this->ResourcesGroupChildren);
2963 if(this->XcodeVersion == 15)
2965 resourcesGroup->AddAttribute("refType", this->CreateString("4"));
2967 resourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2968 this->MainGroupChildren->AddObject(resourcesGroup);
2970 // now create the cmake groups
2971 this->CreateGroups(root, generators);
2973 cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2974 productGroup->AddAttribute("name", this->CreateString("Products"));
2975 if(this->XcodeVersion == 15)
2977 productGroup->AddAttribute("refType", this->CreateString("4"));
2979 productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2980 cmXCodeObject* productGroupChildren =
2981 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2982 productGroup->AddAttribute("children", productGroupChildren);
2983 this->MainGroupChildren->AddObject(productGroup);
2986 this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
2987 this->RootObject->SetComment("Project object");
2989 std::string project_id = "PROJECT_";
2990 project_id += root->GetMakefile()->GetProjectName();
2991 this->RootObject->SetId(this->GetOrCreateId(
2992 project_id.c_str(), this->RootObject->GetId()).c_str());
2994 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2995 this->RootObject->AddAttribute("mainGroup",
2996 this->CreateObjectReference(mainGroup));
2997 this->RootObject->AddAttribute("buildSettings", group);
2998 this->RootObject->AddAttribute("buildStyles", listObjs);
2999 this->RootObject->AddAttribute("hasScannedForEncodings",
3000 this->CreateString("0"));
3001 if (this->XcodeVersion >= 30)
3003 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
3004 group->AddAttribute("BuildIndependentTargetsInParallel",
3005 this->CreateString("YES"));
3006 this->RootObject->AddAttribute("attributes", group);
3007 if (this->XcodeVersion >= 32)
3008 this->RootObject->AddAttribute("compatibilityVersion",
3009 this->CreateString("Xcode 3.2"));
3010 else if (this->XcodeVersion >= 31)
3011 this->RootObject->AddAttribute("compatibilityVersion",
3012 this->CreateString("Xcode 3.1"));
3014 this->RootObject->AddAttribute("compatibilityVersion",
3015 this->CreateString("Xcode 3.0"));
3017 // Point Xcode at the top of the source tree.
3020 this->RelativeToBinary(root->GetMakefile()->GetCurrentDirectory());
3021 this->RootObject->AddAttribute("projectDirPath",
3022 this->CreateString(pdir.c_str()));
3023 this->RootObject->AddAttribute("projectRoot", this->CreateString(""));
3025 cmXCodeObject* configlist =
3026 this->CreateObject(cmXCodeObject::XCConfigurationList);
3027 cmXCodeObject* buildConfigurations =
3028 this->CreateObject(cmXCodeObject::OBJECT_LIST);
3029 std::vector<cmXCodeObject*> configs;
3030 const char *defaultConfigName = "Debug";
3031 if(this->XcodeVersion == 15)
3033 cmXCodeObject* configDebug =
3034 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
3035 configDebug->AddAttribute("name", this->CreateString("Debug"));
3036 configs.push_back(configDebug);
3037 cmXCodeObject* configRelease =
3038 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
3039 configRelease->AddAttribute("name", this->CreateString("Release"));
3040 configs.push_back(configRelease);
3044 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
3046 const char* name = this->CurrentConfigurationTypes[i].c_str();
3049 defaultConfigName = name;
3051 cmXCodeObject* config =
3052 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
3053 config->AddAttribute("name", this->CreateString(name));
3054 configs.push_back(config);
3057 for(std::vector<cmXCodeObject*>::iterator c = configs.begin();
3058 c != configs.end(); ++c)
3060 buildConfigurations->AddObject(*c);
3062 configlist->AddAttribute("buildConfigurations", buildConfigurations);
3064 std::string comment = "Build configuration list for PBXProject ";
3066 comment += this->CurrentProject;
3068 configlist->SetComment(comment.c_str());
3069 configlist->AddAttribute("defaultConfigurationIsVisible",
3070 this->CreateString("0"));
3071 configlist->AddAttribute("defaultConfigurationName",
3072 this->CreateString(defaultConfigName));
3073 cmXCodeObject* buildSettings =
3074 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
3075 const char* osxArch =
3076 this->CurrentMakefile->GetDefinition("CMAKE_OSX_ARCHITECTURES");
3077 if(!osxArch || strlen(osxArch) == 0)
3079 if(this->XcodeVersion >= 32)
3081 osxArch = "$(ARCHS_STANDARD_32_64_BIT)";
3083 else if(this->XcodeVersion == 31)
3085 osxArch = "$(ARCHS_STANDARD_32_BIT)";
3087 else if(this->XcodeVersion <= 30)
3096 buildSettings->AddAttribute("ONLY_ACTIVE_ARCH",
3097 this->CreateString("YES"));
3100 const char* sysroot =
3101 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
3102 const char* sysrootDefault =
3103 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT_DEFAULT");
3104 const char* deploymentTarget =
3105 this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
3106 if(osxArch && sysroot)
3108 bool flagsUsed = false;
3109 // recompute this as it may have been changed since enable language
3110 this->Architectures.clear();
3111 cmSystemTools::ExpandListArgument(std::string(osxArch),
3112 this->Architectures);
3114 buildSettings->AddAttribute("SDKROOT",
3115 this->CreateString(sysroot));
3116 std::string archString;
3117 const char* sep = "";
3118 for( std::vector<std::string>::iterator i =
3119 this->Architectures.begin();
3120 i != this->Architectures.end(); ++i)
3126 buildSettings->AddAttribute("ARCHS",
3127 this->CreateString(archString.c_str()));
3128 if(!flagsUsed && sysrootDefault &&
3129 strcmp(sysroot, sysrootDefault) != 0)
3131 buildSettings->AddAttribute("SDKROOT",
3132 this->CreateString(sysroot));
3135 if(deploymentTarget && *deploymentTarget)
3137 buildSettings->AddAttribute("MACOSX_DEPLOYMENT_TARGET",
3138 this->CreateString(deploymentTarget));
3141 // Put this last so it can override existing settings
3142 // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly.
3144 std::vector<std::string> vars = this->CurrentMakefile->GetDefinitions();
3145 for(std::vector<std::string>::const_iterator i = vars.begin();
3146 i != vars.end(); ++i)
3148 if(i->find("CMAKE_XCODE_ATTRIBUTE_") == 0)
3150 buildSettings->AddAttribute(i->substr(22).c_str(),
3152 this->CurrentMakefile->GetDefinition(i->c_str())));
3157 std::string symroot = root->GetMakefile()->GetCurrentOutputDirectory();
3158 symroot += "/build";
3159 buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot.c_str()));
3161 for( std::vector<cmXCodeObject*>::iterator i = configs.begin();
3162 i != configs.end(); ++i)
3164 (*i)->AddAttribute("buildSettings", buildSettings);
3167 this->RootObject->AddAttribute("buildConfigurationList",
3168 this->CreateObjectReference(configlist));
3170 std::vector<cmXCodeObject*> targets;
3171 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
3172 i != generators.end(); ++i)
3174 if(!this->IsExcluded(root, *i))
3176 this->CreateXCodeTargets(*i, targets);
3179 // loop over all targets and add link and depend info
3180 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
3181 i != targets.end(); ++i)
3183 cmXCodeObject* t = *i;
3184 this->AddDependAndLinkInformation(t);
3186 // now create xcode depend hack makefile
3187 this->CreateXCodeDependHackTarget(targets);
3188 // now add all targets to the root object
3189 cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
3190 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
3191 i != targets.end(); ++i)
3193 cmXCodeObject* t = *i;
3194 allTargets->AddObject(t);
3195 cmXCodeObject* productRef = t->GetObject("productReference");
3198 productGroupChildren->AddObject(productRef->GetObject());
3201 this->RootObject->AddAttribute("targets", allTargets);
3204 //----------------------------------------------------------------------------
3206 cmGlobalXCodeGenerator::GetObjectsNormalDirectory(
3207 const std::string &projName,
3208 const std::string &configName,
3209 const cmTarget *t) const
3212 t->GetMakefile()->GetCurrentOutputDirectory();
3218 dir += t->GetName();
3219 dir += ".build/Objects-normal/";
3224 //----------------------------------------------------------------------------
3226 cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
3227 std::vector<cmXCodeObject*>& targets)
3229 cmGeneratedFileStream
3230 makefileStream(this->CurrentXCodeHackMakefile.c_str());
3233 cmSystemTools::Error("Could not create",
3234 this->CurrentXCodeHackMakefile.c_str());
3237 makefileStream.SetCopyIfDifferent(true);
3238 // one more pass for external depend information not handled
3239 // correctly by xcode
3240 makefileStream << "# DO NOT EDIT\n";
3241 makefileStream << "# This makefile makes sure all linkable targets are\n";
3242 makefileStream << "# up-to-date with anything they link to\n"
3244 "\techo \"Do not invoke directly\"\n"
3247 << "# For each target create a dummy rule "
3248 "so the target does not have to exist\n";
3249 std::set<cmStdString> emitted;
3250 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
3251 i != targets.end(); ++i)
3253 cmXCodeObject* target = *i;
3254 std::map<cmStdString, cmXCodeObject::StringVec> const& deplibs =
3255 target->GetDependLibraries();
3256 for(std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator ci
3257 = deplibs.begin(); ci != deplibs.end(); ++ci)
3259 for(cmXCodeObject::StringVec::const_iterator d = ci->second.begin();
3260 d != ci->second.end(); ++d)
3262 if(emitted.insert(*d).second)
3265 this->ConvertToRelativeForMake(d->c_str()) << ":\n";
3270 makefileStream << "\n\n";
3272 // Write rules to help Xcode relink things at the right time.
3274 "# Rules to remove targets that are older than anything to which they\n"
3275 "# link. This forces Xcode to relink the targets from scratch. It\n"
3276 "# does not seem to check these dependencies itself.\n";
3277 for(std::vector<std::string>::const_iterator
3278 ct = this->CurrentConfigurationTypes.begin();
3279 ct != this->CurrentConfigurationTypes.end(); ++ct)
3281 const char* configName = 0;
3284 configName = ct->c_str();
3286 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
3287 i != targets.end(); ++i)
3289 cmXCodeObject* target = *i;
3290 cmTarget* t =target->GetTarget();
3292 if(t->GetType() == cmTarget::EXECUTABLE ||
3293 // Nope - no post-build for OBJECT_LIRBRARY
3294 // t->GetType() == cmTarget::OBJECT_LIBRARY ||
3295 t->GetType() == cmTarget::STATIC_LIBRARY ||
3296 t->GetType() == cmTarget::SHARED_LIBRARY ||
3297 t->GetType() == cmTarget::MODULE_LIBRARY)
3299 // Declare an entry point for the target post-build phase.
3300 makefileStream << this->PostBuildMakeTarget(t->GetName(), *ct)
3304 if(t->GetType() == cmTarget::EXECUTABLE ||
3305 t->GetType() == cmTarget::SHARED_LIBRARY ||
3306 t->GetType() == cmTarget::MODULE_LIBRARY)
3308 std::string tfull = t->GetFullPath(configName);
3309 std::string trel = this->ConvertToRelativeForMake(tfull.c_str());
3311 // Add this target to the post-build phases of its dependencies.
3312 std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator
3313 y = target->GetDependTargets().find(*ct);
3314 if(y != target->GetDependTargets().end())
3316 std::vector<cmStdString> const& deptgts = y->second;
3317 for(std::vector<cmStdString>::const_iterator d = deptgts.begin();
3318 d != deptgts.end(); ++d)
3320 makefileStream << this->PostBuildMakeTarget(*d, *ct) << ": "
3325 // Create a rule for this target.
3326 makefileStream << trel << ":";
3328 // List dependencies if any exist.
3329 std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator
3330 x = target->GetDependLibraries().find(*ct);
3331 if(x != target->GetDependLibraries().end())
3333 std::vector<cmStdString> const& deplibs = x->second;
3334 for(std::vector<cmStdString>::const_iterator d = deplibs.begin();
3335 d != deplibs.end(); ++d)
3337 makefileStream << "\\\n\t" <<
3338 this->ConvertToRelativeForMake(d->c_str());
3341 // Write the action to remove the target if it is out of date.
3342 makefileStream << "\n";
3343 makefileStream << "\t/bin/rm -f "
3344 << this->ConvertToRelativeForMake(tfull.c_str())
3346 // if building for more than one architecture
3347 // then remove those exectuables as well
3348 if(this->Architectures.size() > 1)
3350 std::string universal = this->GetObjectsNormalDirectory(
3351 this->CurrentProject, configName, t);
3352 for( std::vector<std::string>::iterator arch =
3353 this->Architectures.begin();
3354 arch != this->Architectures.end(); ++arch)
3356 std::string universalFile = universal;
3357 universalFile += *arch;
3358 universalFile += "/";
3359 universalFile += t->GetFullName(configName);
3360 makefileStream << "\t/bin/rm -f "
3362 this->ConvertToRelativeForMake(universalFile.c_str())
3366 makefileStream << "\n\n";
3372 //----------------------------------------------------------------------------
3374 cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
3375 std::vector<cmLocalGenerator*>&
3378 if(generators.size() == 0)
3382 // Skip local generators that are excluded from this project.
3383 for(std::vector<cmLocalGenerator*>::iterator g = generators.begin();
3384 g != generators.end(); ++g)
3386 if(this->IsExcluded(root, *g))
3392 this->CreateXCodeObjects(root,
3394 std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
3396 xcodeDir += root->GetMakefile()->GetProjectName();
3397 xcodeDir += ".xcode";
3398 if(this->XcodeVersion > 20)
3402 cmSystemTools::MakeDirectory(xcodeDir.c_str());
3403 std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
3404 cmGeneratedFileStream fout(xcodeProjFile.c_str());
3405 fout.SetCopyIfDifferent(true);
3410 this->WriteXCodePBXProj(fout, root, generators);
3411 this->ClearXCodeObjects();
3413 // Since this call may have created new cache entries, save the cache:
3415 root->GetMakefile()->GetCacheManager()->SaveCache(
3416 root->GetMakefile()->GetHomeOutputDirectory());
3419 //----------------------------------------------------------------------------
3421 cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
3423 std::vector<cmLocalGenerator*>& )
3425 fout << "// !$*UTF8*$!\n";
3427 cmXCodeObject::Indent(1, fout);
3428 fout << "archiveVersion = 1;\n";
3429 cmXCodeObject::Indent(1, fout);
3430 fout << "classes = {\n";
3431 cmXCodeObject::Indent(1, fout);
3433 cmXCodeObject::Indent(1, fout);
3434 if(this->XcodeVersion >= 21)
3436 if (this->XcodeVersion >= 32)
3437 fout << "objectVersion = 46;\n";
3438 else if (this->XcodeVersion >= 31)
3439 fout << "objectVersion = 45;\n";
3440 else if (this->XcodeVersion >= 30)
3441 fout << "objectVersion = 44;\n";
3443 fout << "objectVersion = 42;\n";
3444 cmXCode21Object::PrintList(this->XCodeObjects, fout);
3448 fout << "objectVersion = 39;\n";
3449 cmXCodeObject::PrintList(this->XCodeObjects, fout);
3451 cmXCodeObject::Indent(1, fout);
3452 fout << "rootObject = " << this->RootObject->GetId() << ";\n";
3456 //----------------------------------------------------------------------------
3457 const char* cmGlobalXCodeGenerator::GetCMakeCFGIntDir() const
3459 return this->XcodeVersion >= 21 ?
3460 "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)" : ".";
3463 //----------------------------------------------------------------------------
3464 void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
3467 entry.Name = this->GetName();
3468 entry.Brief = "Generate Xcode project files.";
3472 //----------------------------------------------------------------------------
3473 std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(const char* p)
3475 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
3477 return cmSystemTools::ConvertToOutputPath(p);
3482 this->CurrentLocalGenerator->
3483 ConvertToRelativePath(this->CurrentOutputDirectoryComponents, p);
3484 return cmSystemTools::ConvertToOutputPath(ret.c_str());
3488 //----------------------------------------------------------------------------
3489 std::string cmGlobalXCodeGenerator::ConvertToRelativeForXCode(const char* p)
3491 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
3493 return cmSystemTools::ConvertToOutputPath(p);
3498 this->CurrentLocalGenerator->
3499 ConvertToRelativePath(this->ProjectOutputDirectoryComponents, p);
3500 return cmSystemTools::ConvertToOutputPath(ret.c_str());
3504 //----------------------------------------------------------------------------
3505 std::string cmGlobalXCodeGenerator::RelativeToSource(const char* p)
3507 // We force conversion because Xcode breakpoints do not work unless
3508 // they are in a file named relative to the source tree.
3509 return this->CurrentLocalGenerator->
3510 ConvertToRelativePath(this->ProjectSourceDirectoryComponents, p, true);
3513 //----------------------------------------------------------------------------
3514 std::string cmGlobalXCodeGenerator::RelativeToBinary(const char* p)
3516 return this->CurrentLocalGenerator->
3517 ConvertToRelativePath(this->ProjectOutputDirectoryComponents, p);
3520 //----------------------------------------------------------------------------
3521 std::string cmGlobalXCodeGenerator::XCodeEscapePath(const char* p)
3523 std::string ret = p;
3524 if(ret.find(' ') != ret.npos)
3526 std::string t = ret;
3534 //----------------------------------------------------------------------------
3536 cmGlobalXCodeGenerator
3537 ::AppendDirectoryForConfig(const char* prefix,
3542 if(this->XcodeVersion > 20)
3553 //----------------------------------------------------------------------------
3554 std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix,
3555 const char* varNameLang,
3556 const char* varNameSuffix,
3557 const char* default_flags)
3561 std::string varName = varNamePrefix;
3562 varName += varNameLang;
3563 varName += varNameSuffix;
3564 if(const char* varValue =
3565 this->CurrentMakefile->GetDefinition(varName.c_str()))
3573 return default_flags;
3576 //----------------------------------------------------------------------------
3577 void cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
3578 const char* defines_list,
3581 // Skip this if there are no definitions.
3587 // Expand the list of definitions.
3588 std::vector<std::string> defines;
3589 cmSystemTools::ExpandListArgument(defines_list, defines);
3591 // Store the definitions in the string.
3592 this->AppendDefines(defs, defines, dflag);
3595 //----------------------------------------------------------------------------
3597 cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
3598 std::vector<std::string> const& defines,
3601 // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
3603 for(std::vector<std::string>::const_iterator di = defines.begin();
3604 di != defines.end(); ++di)
3606 // Start with -D if requested.
3607 def = dflag? "-D": "";
3610 // Append the flag with needed escapes.
3612 this->AppendFlag(tmp, def);
3613 defs.Add(tmp.c_str());
3617 //----------------------------------------------------------------------------
3618 void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
3619 std::string const& flag)
3621 // Short-circuit for an empty flag.
3627 // Separate from previous flags.
3633 // Check if the flag needs quoting.
3635 flag.find_first_of("`~!@#$%^&*()+={}[]|:;\"'<>,.? ") != flag.npos;
3637 // We escape a flag as follows:
3638 // - Place each flag in single quotes ''
3639 // - Escape a single quote as \\'
3640 // - Escape a backslash as \\\\ since it itself is an escape
3641 // Note that in the code below we need one more level of escapes for
3642 // C string syntax in this source file.
3644 // The final level of escaping is done when the string is stored
3645 // into the project file by cmXCodeObject::PrintString.
3649 // Open single quote.
3653 // Flag value with escaped quotes and backslashes.
3654 for(const char* c = flag.c_str(); *c; ++c)
3658 if (this->XcodeVersion >= 40)
3669 flags += "\\\\\\\\";
3679 // Close single quote.
3684 //----------------------------------------------------------------------------
3686 cmGlobalXCodeGenerator::ComputeInfoPListLocation(cmTarget& target)
3688 std::string plist = target.GetMakefile()->GetCurrentOutputDirectory();
3689 plist += cmake::GetCMakeFilesDirectory();
3691 plist += target.GetName();
3692 plist += ".dir/Info.plist";
3696 //----------------------------------------------------------------------------
3697 // Return true if the generated build tree may contain multiple builds.
3698 // i.e. "Can I build Debug and Release in the same tree?"
3699 bool cmGlobalXCodeGenerator::IsMultiConfig()
3701 // Old Xcode 1.5 is single config:
3702 if(this->XcodeVersion == 15)
3707 // Newer Xcode versions are multi config:
3711 //----------------------------------------------------------------------------
3713 cmGlobalXCodeGenerator
3714 ::ComputeTargetObjects(cmGeneratorTarget* gt) const
3716 // Count the number of object files with each name. Warn about duplicate
3717 // names since Xcode names them uniquely automatically with a numeric suffix
3718 // to avoid exact duplicate file names. Note that Mac file names are not
3719 // typically case sensitive, hence the LowerCase.
3720 std::map<cmStdString, int> counts;
3721 for(std::vector<cmSourceFile*>::const_iterator
3722 si = gt->ObjectSources.begin();
3723 si != gt->ObjectSources.end(); ++si)
3725 cmSourceFile* sf = *si;
3726 std::string objectName =
3727 cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
3730 std::string objectNameLower = cmSystemTools::LowerCase(objectName);
3731 counts[objectNameLower] += 1;
3732 if (2 == counts[objectNameLower])
3734 // TODO: emit warning about duplicate name?
3737 gt->Objects[sf] = objectName;
3740 const char* configName = this->GetCMakeCFGIntDir();
3741 std::string dir = this->GetObjectsNormalDirectory(
3742 this->CurrentProject, configName, gt->Target);
3743 if(this->XcodeVersion >= 21)
3745 dir += "$(CURRENT_ARCH)/";
3756 gt->ObjectDirectory = dir;