BUG: Fix find_* search order with path suffixes
[cmake.git] / Source / cmGlobalXCodeGenerator.cxx
blob1b3f7a3293f5f1c14a8c7d3a22f0c3a841e87a22
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalXCodeGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2008-10-09 15:01:47 $
7 Version: $Revision: 1.203 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmGlobalXCodeGenerator.h"
18 #include "cmGlobalXCode21Generator.h"
19 #include "cmLocalXCodeGenerator.h"
20 #include "cmMakefile.h"
21 #include "cmXCodeObject.h"
22 #include "cmXCode21Object.h"
23 #include "cmake.h"
24 #include "cmGeneratedFileStream.h"
25 #include "cmComputeLinkInformation.h"
26 #include "cmSourceFile.h"
28 //----------------------------------------------------------------------------
29 #if defined(CMAKE_BUILD_WITH_CMAKE)
30 #include "cmXMLParser.h"
32 // parse the xml file storing the installed version of Xcode on
33 // the machine
34 class cmXcodeVersionParser : public cmXMLParser
36 public:
37 void StartElement(const char* , const char** )
39 this->Data = "";
41 void EndElement(const char* name)
43 if(strcmp(name, "key") == 0)
45 this->Key = this->Data;
47 else if(strcmp(name, "string") == 0)
49 if(this->Key == "CFBundleShortVersionString")
51 this->Version = (int)(10.0 * atof(this->Data.c_str()));
55 void CharacterDataHandler(const char* data, int length)
57 this->Data.append(data, length);
59 int Version;
60 std::string Key;
61 std::string Data;
63 #endif
65 //----------------------------------------------------------------------------
66 cmGlobalXCodeGenerator::cmGlobalXCodeGenerator()
68 this->FindMakeProgramFile = "CMakeFindXCode.cmake";
69 this->RootObject = 0;
70 this->MainGroupChildren = 0;
71 this->SourcesGroupChildren = 0;
72 this->ResourcesGroupChildren = 0;
73 this->CurrentMakefile = 0;
74 this->CurrentLocalGenerator = 0;
75 this->XcodeVersion = 15;
78 //----------------------------------------------------------------------------
79 cmGlobalGenerator* cmGlobalXCodeGenerator::New()
81 #if defined(CMAKE_BUILD_WITH_CMAKE)
82 cmXcodeVersionParser parser;
83 parser.ParseFile
84 ("/Developer/Applications/Xcode.app/Contents/version.plist");
85 if(parser.Version == 15)
87 return new cmGlobalXCodeGenerator;
89 else if (parser.Version == 20)
91 cmSystemTools::Message("Xcode 2.0 not really supported by cmake, "
92 "using Xcode 15 generator\n");
93 return new cmGlobalXCodeGenerator;
95 cmGlobalXCodeGenerator* ret = new cmGlobalXCode21Generator;
96 ret->SetVersion(parser.Version);
97 return ret;
98 #else
99 std::cerr << "CMake should be built with cmake to use XCode, "
100 "default to Xcode 1.5\n";
101 return new cmGlobalXCodeGenerator;
102 #endif
105 //----------------------------------------------------------------------------
106 void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const&
107 lang,
108 cmMakefile * mf, bool optional)
110 mf->AddDefinition("XCODE","1");
111 if(this->XcodeVersion == 15)
114 else
116 mf->AddCacheDefinition(
117 "CMAKE_CONFIGURATION_TYPES",
118 "Debug;Release;MinSizeRel;RelWithDebInfo",
119 "Semicolon separated list of supported configuration types, "
120 "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
121 "anything else will be ignored.",
122 cmCacheManager::STRING);
124 mf->AddDefinition("CMAKE_GENERATOR_CC", "gcc");
125 mf->AddDefinition("CMAKE_GENERATOR_CXX", "g++");
126 mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
127 // initialize Architectures so it can be used by
128 // GetTargetObjectFileDirectories
129 this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
130 const char* osxArch =
131 mf->GetDefinition("CMAKE_OSX_ARCHITECTURES");
132 const char* sysroot =
133 mf->GetDefinition("CMAKE_OSX_SYSROOT");
134 if(osxArch && sysroot)
136 this->Architectures.clear();
137 cmSystemTools::ExpandListArgument(std::string(osxArch),
138 this->Architectures);
142 //----------------------------------------------------------------------------
143 std::string cmGlobalXCodeGenerator
144 ::GenerateBuildCommand(const char* makeProgram,
145 const char *projectName,
146 const char* additionalOptions,
147 const char *targetName,
148 const char* config,
149 bool ignoreErrors,
150 bool)
152 // Config is not used yet
153 (void) ignoreErrors;
155 // now build the test
156 if(makeProgram == 0 || !strlen(makeProgram))
158 cmSystemTools::Error(
159 "Generator cannot find the appropriate make command.");
160 return "";
162 std::string makeCommand =
163 cmSystemTools::ConvertToOutputPath(makeProgram);
164 std::string lowerCaseCommand = makeCommand;
165 cmSystemTools::LowerCase(lowerCaseCommand);
167 makeCommand += " -project ";
168 makeCommand += projectName;
169 makeCommand += ".xcode";
170 if(this->XcodeVersion > 20)
172 makeCommand += "proj";
175 bool clean = false;
176 if ( targetName && strcmp(targetName, "clean") == 0 )
178 clean = true;
179 targetName = "ALL_BUILD";
181 if(clean)
183 makeCommand += " clean";
185 else
187 makeCommand += " build";
189 makeCommand += " -target ";
190 // if it is a null string for config don't use it
191 if(config && *config == 0)
193 config = 0;
195 if (targetName && strlen(targetName))
197 makeCommand += targetName;
199 else
201 makeCommand += "ALL_BUILD";
203 if(this->XcodeVersion == 15)
205 makeCommand += " -buildstyle Development ";
207 else
209 makeCommand += " -configuration ";
210 makeCommand += config?config:"Debug";
212 if ( additionalOptions )
214 makeCommand += " ";
215 makeCommand += additionalOptions;
217 return makeCommand;
220 //----------------------------------------------------------------------------
221 ///! Create a local generator appropriate to this Global Generator
222 cmLocalGenerator *cmGlobalXCodeGenerator::CreateLocalGenerator()
224 cmLocalGenerator *lg = new cmLocalXCodeGenerator;
225 lg->SetGlobalGenerator(this);
226 return lg;
229 //----------------------------------------------------------------------------
230 void cmGlobalXCodeGenerator::Generate()
232 std::map<cmStdString, std::vector<cmLocalGenerator*> >::iterator it;
233 // make sure extra targets are added before calling
234 // the parent generate which will call trace depends
235 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
237 cmLocalGenerator* root = it->second[0];
238 this->SetGenerationRoot(root);
239 // add ALL_BUILD, INSTALL, etc
240 this->AddExtraTargets(root, it->second);
242 this->cmGlobalGenerator::Generate();
243 for(it = this->ProjectMap.begin(); it!= this->ProjectMap.end(); ++it)
245 cmLocalGenerator* root = it->second[0];
246 this->SetGenerationRoot(root);
247 // now create the project
248 this->OutputXCodeProject(root, it->second);
252 //----------------------------------------------------------------------------
253 void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
255 this->CurrentProject = root->GetMakefile()->GetProjectName();
256 this->SetCurrentLocalGenerator(root);
257 std::string outDir = this->CurrentMakefile->GetHomeOutputDirectory();
258 outDir =cmSystemTools::CollapseFullPath(outDir.c_str());
259 cmSystemTools::SplitPath(outDir.c_str(),
260 this->ProjectOutputDirectoryComponents);
262 this->CurrentXCodeHackMakefile =
263 root->GetMakefile()->GetCurrentOutputDirectory();
264 this->CurrentXCodeHackMakefile += "/CMakeScripts";
265 cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile.c_str());
266 this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
269 //----------------------------------------------------------------------------
270 void
271 cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
272 std::vector<cmLocalGenerator*>& gens)
274 cmMakefile* mf = root->GetMakefile();
276 // Add ALL_BUILD
277 const char* no_working_directory = 0;
278 std::vector<std::string> no_depends;
279 mf->AddUtilityCommand("ALL_BUILD", true, no_depends,
280 no_working_directory,
281 "echo", "Build all projects");
282 cmTarget* allbuild = mf->FindTarget("ALL_BUILD");
284 // Refer to the main build configuration file for easy editing.
285 std::string listfile = mf->GetStartDirectory();
286 listfile += "/";
287 listfile += "CMakeLists.txt";
288 allbuild->AddSource(listfile.c_str());
290 // Add XCODE depend helper
291 std::string dir = mf->GetCurrentOutputDirectory();
292 cmCustomCommandLine makecommand;
293 makecommand.push_back("make");
294 makecommand.push_back("-C");
295 makecommand.push_back(dir.c_str());
296 makecommand.push_back("-f");
297 makecommand.push_back(this->CurrentXCodeHackMakefile.c_str());
298 if(this->XcodeVersion > 20)
300 makecommand.push_back("all.$(CONFIGURATION)");
302 cmCustomCommandLines commandLines;
303 commandLines.push_back(makecommand);
304 // Add Re-Run CMake rules
305 this->CreateReRunCMakeFile(root);
307 // now make the allbuild depend on all the non-utility targets
308 // in the project
309 for(std::vector<cmLocalGenerator*>::iterator i = gens.begin();
310 i != gens.end(); ++i)
312 cmLocalGenerator* lg = *i;
313 if(this->IsExcluded(root, *i))
315 continue;
317 cmTargets& tgts = lg->GetMakefile()->GetTargets();
318 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
320 cmTarget& target = l->second;
321 // make all exe, shared libs and modules
322 // run the depend check makefile as a post build rule
323 // this will make sure that when the next target is built
324 // things are up-to-date
325 if((target.GetType() == cmTarget::EXECUTABLE ||
326 target.GetType() == cmTarget::STATIC_LIBRARY ||
327 target.GetType() == cmTarget::SHARED_LIBRARY ||
328 target.GetType() == cmTarget::MODULE_LIBRARY))
330 lg->GetMakefile()->AddCustomCommandToTarget(target.GetName(),
331 no_depends,
332 commandLines,
333 cmTarget::POST_BUILD,
334 "Depend check for xcode",
335 dir.c_str());
338 if(!target.GetPropertyAsBool("EXCLUDE_FROM_ALL"))
340 allbuild->AddUtility(target.GetName());
343 // Refer to the build configuration file for easy editing.
344 listfile = lg->GetMakefile()->GetStartDirectory();
345 listfile += "/";
346 listfile += "CMakeLists.txt";
347 target.AddSource(listfile.c_str());
352 //----------------------------------------------------------------------------
353 void cmGlobalXCodeGenerator::CreateReRunCMakeFile(cmLocalGenerator* root)
355 cmMakefile* mf = root->GetMakefile();
356 std::vector<std::string> lfiles = mf->GetListFiles();
357 // sort the array
358 std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
359 std::vector<std::string>::iterator new_end =
360 std::unique(lfiles.begin(), lfiles.end());
361 lfiles.erase(new_end, lfiles.end());
362 std::string dir = mf->GetHomeOutputDirectory();
363 this->CurrentReRunCMakeMakefile = dir;
364 this->CurrentReRunCMakeMakefile += "/CMakeScripts";
365 cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile.c_str());
366 this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
367 cmGeneratedFileStream makefileStream
368 (this->CurrentReRunCMakeMakefile.c_str());
369 makefileStream.SetCopyIfDifferent(true);
370 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
371 makefileStream << cmake::GetCMakeFilesDirectoryPostSlash();
372 makefileStream << "cmake.check_cache: ";
373 for(std::vector<std::string>::const_iterator i = lfiles.begin();
374 i != lfiles.end(); ++i)
376 makefileStream << "\\\n" << this->ConvertToRelativeForMake(i->c_str());
378 std::string cmake = mf->GetRequiredDefinition("CMAKE_COMMAND");
379 makefileStream << "\n\t" << this->ConvertToRelativeForMake(cmake.c_str())
380 << " -H" << this->ConvertToRelativeForMake(
381 mf->GetHomeDirectory())
382 << " -B" << this->ConvertToRelativeForMake(
383 mf->GetHomeOutputDirectory()) << "\n";
386 //----------------------------------------------------------------------------
387 void cmGlobalXCodeGenerator::ClearXCodeObjects()
389 this->TargetDoneSet.clear();
390 for(unsigned int i = 0; i < this->XCodeObjects.size(); ++i)
392 delete this->XCodeObjects[i];
394 this->XCodeObjects.clear();
395 this->GroupMap.clear();
396 this->GroupNameMap.clear();
397 this->TargetGroup.clear();
398 this->FileRefs.clear();
401 //----------------------------------------------------------------------------
402 cmXCodeObject*
403 cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::PBXType ptype)
405 cmXCodeObject* obj;
406 if(this->XcodeVersion == 15)
408 obj = new cmXCodeObject(ptype, cmXCodeObject::OBJECT);
410 else
412 obj = new cmXCode21Object(ptype, cmXCodeObject::OBJECT);
414 this->XCodeObjects.push_back(obj);
415 return obj;
418 //----------------------------------------------------------------------------
419 cmXCodeObject*
420 cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
422 cmXCodeObject* obj = new cmXCodeObject(cmXCodeObject::None, type);
423 this->XCodeObjects.push_back(obj);
424 return obj;
427 //----------------------------------------------------------------------------
428 cmXCodeObject*
429 cmGlobalXCodeGenerator::CreateString(const char* s)
431 cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
432 obj->SetString(s);
433 return obj;
436 //----------------------------------------------------------------------------
437 cmXCodeObject* cmGlobalXCodeGenerator
438 ::CreateObjectReference(cmXCodeObject* ref)
440 cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
441 obj->SetObject(ref);
442 return obj;
445 //----------------------------------------------------------------------------
446 cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
448 cmStdString key(cmtarget.GetName());
449 key += "-";
450 key += sf->GetFullPath();
451 return key;
454 //----------------------------------------------------------------------------
455 cmXCodeObject*
456 cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
457 cmSourceFile* sf,
458 cmTarget& cmtarget)
460 // Add flags from target and source file properties.
461 std::string flags;
462 if(cmtarget.GetProperty("COMPILE_FLAGS"))
464 lg->AppendFlags(flags, cmtarget.GetProperty("COMPILE_FLAGS"));
466 lg->AppendFlags(flags, sf->GetProperty("COMPILE_FLAGS"));
468 // Add per-source definitions.
469 this->AppendDefines(flags, sf->GetProperty("COMPILE_DEFINITIONS"), true);
471 // Using a map and the full path guarantees that we will always get the same
472 // fileRef object for any given full path.
474 cmXCodeObject* fileRef = this->CreateXCodeFileReference(sf, cmtarget);
476 cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
477 buildFile->SetComment(fileRef->GetComment());
478 buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
480 cmXCodeObject* settings =
481 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
482 settings->AddAttribute("COMPILER_FLAGS", this->CreateString(flags.c_str()));
484 // Is this a resource file in this target? Add it to the resources group...
486 cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf);
487 bool isResource = (tsFlags.Type == cmTarget::SourceFileTypeResource);
489 // Is this a "private" or "public" framework header file?
490 // Set the ATTRIBUTES attribute appropriately...
492 if(cmtarget.IsFrameworkOnApple())
494 if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader)
496 cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
497 attrs->AddObject(this->CreateString("Private"));
498 settings->AddAttribute("ATTRIBUTES", attrs);
499 isResource = true;
501 else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader)
503 cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
504 attrs->AddObject(this->CreateString("Public"));
505 settings->AddAttribute("ATTRIBUTES", attrs);
506 isResource = true;
510 // Add the fileRef to the top level Resources group/folder if it is not
511 // already there.
513 if(isResource && this->ResourcesGroupChildren &&
514 !this->ResourcesGroupChildren->HasObject(fileRef))
516 this->ResourcesGroupChildren->AddObject(fileRef);
519 buildFile->AddAttribute("settings", settings);
520 return buildFile;
523 //----------------------------------------------------------------------------
524 cmXCodeObject*
525 cmGlobalXCodeGenerator::CreateXCodeFileReference(cmSourceFile* sf,
526 cmTarget& cmtarget)
528 std::string fname = sf->GetFullPath();
529 cmXCodeObject* fileRef = this->FileRefs[fname];
530 if(!fileRef)
532 fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
533 std::string comment = fname;
534 //comment += " in ";
535 //std::string gname = group->GetObject("name")->GetString();
536 //comment += gname.substr(1, gname.size()-2);
537 fileRef->SetComment(fname.c_str());
538 this->FileRefs[fname] = fileRef;
540 cmStdString key = GetGroupMapKey(cmtarget, sf);
541 cmXCodeObject* group = this->GroupMap[key];
542 cmXCodeObject* children = group->GetObject("children");
543 if (!children->HasObject(fileRef))
545 children->AddObject(fileRef);
547 fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
549 const char* lang =
550 this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
551 std::string sourcecode = "sourcecode";
552 std::string ext = sf->GetExtension();
553 ext = cmSystemTools::LowerCase(ext);
555 if(ext == "o")
557 sourcecode = "compiled.mach-o.objfile";
559 else if(ext == "mm")
561 sourcecode += ".cpp.objcpp";
563 else if(ext == "m")
565 sourcecode += ".c.objc";
567 else if(ext == "plist")
569 sourcecode += ".text.plist";
571 else if(ext == "h" || ext == "hxx" || ext == "hpp")
573 const char* linkLanguage = cmtarget.GetLinkerLanguage(this);
574 if(linkLanguage && (std::string(linkLanguage) == "CXX"))
576 sourcecode += ".cpp.h";
578 else
580 sourcecode += ".c.h";
583 else if(lang && strcmp(lang, "CXX") == 0)
585 sourcecode += ".cpp.cpp";
587 else if(lang && strcmp(lang, "C") == 0)
589 sourcecode += ".c.c";
591 else if(ext == "txt")
593 sourcecode += ".text";
595 //else
596 // {
597 // // Already specialized above or we leave sourcecode == "sourcecode"
598 // // which is probably the most correct choice. Extensionless headers,
599 // // for example... Or file types unknown to Xcode that do not map to a
600 // // valid lastKnownFileType value.
601 // }
603 fileRef->AddAttribute("lastKnownFileType",
604 this->CreateString(sourcecode.c_str()));
606 std::string path =
607 this->ConvertToRelativeForXCode(sf->GetFullPath().c_str());
608 std::string dir;
609 std::string file;
610 cmSystemTools::SplitProgramPath(sf->GetFullPath().c_str(),
611 dir, file);
613 fileRef->AddAttribute("name", this->CreateString(file.c_str()));
614 fileRef->AddAttribute("path", this->CreateString(path.c_str()));
615 if(this->XcodeVersion == 15)
617 fileRef->AddAttribute("refType", this->CreateString("4"));
619 if(path.size() > 1 && path[0] == '.' && path[1] == '.')
621 fileRef->AddAttribute("sourceTree", this->CreateString("<group>"));
623 else
625 fileRef->AddAttribute("sourceTree", this->CreateString("<absolute>"));
628 return fileRef;
631 //----------------------------------------------------------------------------
632 bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
634 if(tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
635 tname == "install" || tname == "package" || tname == "RUN_TESTS" )
637 if(this->TargetDoneSet.find(tname) != this->TargetDoneSet.end())
639 return true;
641 this->TargetDoneSet.insert(tname);
642 return false;
644 return false;
647 //----------------------------------------------------------------------------
648 void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
650 this->CurrentLocalGenerator = gen;
651 this->CurrentMakefile = gen->GetMakefile();
652 std::string outdir =
653 cmSystemTools::CollapseFullPath(this->CurrentMakefile->
654 GetCurrentOutputDirectory());
655 cmSystemTools::SplitPath(outdir.c_str(),
656 this->CurrentOutputDirectoryComponents);
658 // Select the current set of configuration types.
659 this->CurrentConfigurationTypes.clear();
660 if(this->XcodeVersion > 20)
662 if(const char* types =
663 this->CurrentMakefile->GetDefinition("CMAKE_CONFIGURATION_TYPES"))
665 cmSystemTools::ExpandListArgument(types,
666 this->CurrentConfigurationTypes);
669 if(this->CurrentConfigurationTypes.empty())
671 if(const char* buildType =
672 this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE"))
674 this->CurrentConfigurationTypes.push_back(buildType);
676 else
678 this->CurrentConfigurationTypes.push_back("");
683 //----------------------------------------------------------------------------
684 void
685 cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
686 std::vector<cmXCodeObject*>&
687 targets)
689 this->SetCurrentLocalGenerator(gen);
690 cmTargets &tgts = this->CurrentMakefile->GetTargets();
691 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
693 cmTarget& cmtarget = l->second;
695 // make sure ALL_BUILD, INSTALL, etc are only done once
696 if(this->SpecialTargetEmitted(l->first.c_str()))
698 continue;
701 if(cmtarget.GetType() == cmTarget::UTILITY ||
702 cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
704 targets.push_back(this->CreateUtilityTarget(cmtarget));
705 continue;
708 // organize the sources
709 std::vector<cmSourceFile*> const &classes = cmtarget.GetSourceFiles();
710 std::vector<cmXCodeObject*> externalObjFiles;
711 std::vector<cmXCodeObject*> headerFiles;
712 std::vector<cmXCodeObject*> resourceFiles;
713 std::vector<cmXCodeObject*> sourceFiles;
714 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
715 i != classes.end(); ++i)
717 cmXCodeObject* xsf =
718 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
719 *i, cmtarget);
720 cmXCodeObject* fr = xsf->GetObject("fileRef");
721 cmXCodeObject* filetype =
722 fr->GetObject()->GetObject("lastKnownFileType");
724 cmTarget::SourceFileFlags tsFlags =
725 cmtarget.GetTargetSourceFileFlags(*i);
727 if(strcmp(filetype->GetString(), "compiled.mach-o.objfile") == 0)
729 externalObjFiles.push_back(xsf);
731 else if((*i)->GetPropertyAsBool("HEADER_FILE_ONLY") ||
732 (tsFlags.Type == cmTarget::SourceFileTypePrivateHeader) ||
733 (tsFlags.Type == cmTarget::SourceFileTypePublicHeader))
735 headerFiles.push_back(xsf);
737 else if(tsFlags.Type == cmTarget::SourceFileTypeResource)
739 resourceFiles.push_back(xsf);
741 else
743 // Include this file in the build if it has a known language
744 // and has not been listed as an ignored extension for this
745 // generator.
746 if(this->CurrentLocalGenerator->GetSourceFileLanguage(**i) &&
747 !this->IgnoreFile((*i)->GetExtension().c_str()))
749 sourceFiles.push_back(xsf);
754 // some build phases only apply to bundles and/or frameworks
755 bool isFrameworkTarget = cmtarget.IsFrameworkOnApple();
756 bool isBundleTarget = cmtarget.GetPropertyAsBool("MACOSX_BUNDLE");
758 cmXCodeObject* buildFiles = 0;
760 // create source build phase
761 cmXCodeObject* sourceBuildPhase = 0;
762 if (!sourceFiles.empty())
764 sourceBuildPhase =
765 this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
766 sourceBuildPhase->SetComment("Sources");
767 sourceBuildPhase->AddAttribute("buildActionMask",
768 this->CreateString("2147483647"));
769 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
770 for(std::vector<cmXCodeObject*>::iterator i = sourceFiles.begin();
771 i != sourceFiles.end(); ++i)
773 buildFiles->AddObject(*i);
775 sourceBuildPhase->AddAttribute("files", buildFiles);
776 sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
777 this->CreateString("0"));
780 // create header build phase - only for framework targets
781 cmXCodeObject* headerBuildPhase = 0;
782 if (!headerFiles.empty() && isFrameworkTarget)
784 headerBuildPhase =
785 this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
786 headerBuildPhase->SetComment("Headers");
787 headerBuildPhase->AddAttribute("buildActionMask",
788 this->CreateString("2147483647"));
789 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
790 for(std::vector<cmXCodeObject*>::iterator i = headerFiles.begin();
791 i != headerFiles.end(); ++i)
793 buildFiles->AddObject(*i);
795 headerBuildPhase->AddAttribute("files", buildFiles);
796 headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
797 this->CreateString("0"));
800 // create resource build phase - only for framework or bundle targets
801 cmXCodeObject* resourceBuildPhase = 0;
802 if (!resourceFiles.empty() && (isFrameworkTarget || isBundleTarget))
804 resourceBuildPhase =
805 this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
806 resourceBuildPhase->SetComment("Resources");
807 resourceBuildPhase->AddAttribute("buildActionMask",
808 this->CreateString("2147483647"));
809 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
810 for(std::vector<cmXCodeObject*>::iterator i = resourceFiles.begin();
811 i != resourceFiles.end(); ++i)
813 buildFiles->AddObject(*i);
815 resourceBuildPhase->AddAttribute("files", buildFiles);
816 resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
817 this->CreateString("0"));
820 // create vector of "non-resource content file" build phases - only for
821 // framework or bundle targets
822 std::vector<cmXCodeObject*> contentBuildPhases;
823 if (isFrameworkTarget || isBundleTarget)
825 typedef std::map<cmStdString, std::vector<cmSourceFile*> >
826 mapOfVectorOfSourceFiles;
827 mapOfVectorOfSourceFiles bundleFiles;
828 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
829 i != classes.end(); ++i)
831 cmTarget::SourceFileFlags tsFlags =
832 cmtarget.GetTargetSourceFileFlags(*i);
833 if(tsFlags.Type == cmTarget::SourceFileTypeMacContent)
835 bundleFiles[tsFlags.MacFolder].push_back(*i);
838 mapOfVectorOfSourceFiles::iterator mit;
839 for ( mit = bundleFiles.begin(); mit != bundleFiles.end(); ++ mit )
841 cmXCodeObject* copyFilesBuildPhase =
842 this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
843 copyFilesBuildPhase->SetComment("Copy files");
844 copyFilesBuildPhase->AddAttribute("buildActionMask",
845 this->CreateString("2147483647"));
846 copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
847 this->CreateString("6"));
848 cmOStringStream ostr;
849 if (cmtarget.IsFrameworkOnApple())
851 // dstPath in frameworks is relative to Versions/<version>
852 ostr << mit->first;
854 else if ( mit->first != "MacOS" )
856 // dstPath in bundles is relative to Contents/MacOS
857 ostr << "../" << mit->first.c_str();
859 copyFilesBuildPhase->AddAttribute("dstPath",
860 this->CreateString(ostr.str().c_str()));
861 copyFilesBuildPhase->AddAttribute(
862 "runOnlyForDeploymentPostprocessing", this->CreateString("0"));
863 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
864 copyFilesBuildPhase->AddAttribute("files", buildFiles);
865 std::vector<cmSourceFile*>::iterator sfIt;
866 for ( sfIt = mit->second.begin(); sfIt != mit->second.end(); ++ sfIt )
868 cmXCodeObject* xsf =
869 this->CreateXCodeSourceFile(this->CurrentLocalGenerator,
870 *sfIt, cmtarget);
871 buildFiles->AddObject(xsf);
873 contentBuildPhases.push_back(copyFilesBuildPhase);
877 // create framework build phase
878 cmXCodeObject* frameworkBuildPhase = 0;
879 if (!externalObjFiles.empty())
881 frameworkBuildPhase =
882 this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
883 frameworkBuildPhase->SetComment("Frameworks");
884 frameworkBuildPhase->AddAttribute("buildActionMask",
885 this->CreateString("2147483647"));
886 buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
887 frameworkBuildPhase->AddAttribute("files", buildFiles);
888 for(std::vector<cmXCodeObject*>::iterator i = externalObjFiles.begin();
889 i != externalObjFiles.end(); ++i)
891 buildFiles->AddObject(*i);
893 frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
894 this->CreateString("0"));
897 // create list of build phases and create the XCode target
898 cmXCodeObject* buildPhases =
899 this->CreateObject(cmXCodeObject::OBJECT_LIST);
901 this->CreateCustomCommands(buildPhases, sourceBuildPhase,
902 headerBuildPhase, resourceBuildPhase,
903 contentBuildPhases,
904 frameworkBuildPhase, cmtarget);
906 targets.push_back(this->CreateXCodeTarget(cmtarget, buildPhases));
910 //----------------------------------------------------------------------------
911 cmXCodeObject*
912 cmGlobalXCodeGenerator::CreateBuildPhase(const char* name,
913 const char* name2,
914 cmTarget& cmtarget,
915 const std::vector<cmCustomCommand>&
916 commands)
918 if(commands.size() == 0 && strcmp(name, "CMake ReRun") != 0)
920 return 0;
922 cmXCodeObject* buildPhase =
923 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
924 buildPhase->AddAttribute("buildActionMask",
925 this->CreateString("2147483647"));
926 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
927 buildPhase->AddAttribute("files", buildFiles);
928 buildPhase->AddAttribute("name",
929 this->CreateString(name));
930 buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
931 this->CreateString("0"));
932 buildPhase->AddAttribute("shellPath",
933 this->CreateString("/bin/sh"));
934 this->AddCommandsToBuildPhase(buildPhase, cmtarget, commands,
935 name2);
936 return buildPhase;
939 //----------------------------------------------------------------------------
940 void cmGlobalXCodeGenerator::CreateCustomCommands(cmXCodeObject* buildPhases,
941 cmXCodeObject*
942 sourceBuildPhase,
943 cmXCodeObject*
944 headerBuildPhase,
945 cmXCodeObject*
946 resourceBuildPhase,
947 std::vector<cmXCodeObject*>
948 contentBuildPhases,
949 cmXCodeObject*
950 frameworkBuildPhase,
951 cmTarget& cmtarget)
953 std::vector<cmCustomCommand> const & prebuild
954 = cmtarget.GetPreBuildCommands();
955 std::vector<cmCustomCommand> const & prelink
956 = cmtarget.GetPreLinkCommands();
957 std::vector<cmCustomCommand> const & postbuild
958 = cmtarget.GetPostBuildCommands();
959 std::vector<cmSourceFile*>const &classes = cmtarget.GetSourceFiles();
960 // add all the sources
961 std::vector<cmCustomCommand> commands;
962 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
963 i != classes.end(); ++i)
965 if((*i)->GetCustomCommand())
967 commands.push_back(*(*i)->GetCustomCommand());
970 std::vector<cmCustomCommand> reruncom;
971 cmXCodeObject* cmakeReRunPhase =
972 this->CreateBuildPhase("CMake ReRun", "cmakeReRunPhase",
973 cmtarget, reruncom);
974 buildPhases->AddObject(cmakeReRunPhase);
975 // create prebuild phase
976 cmXCodeObject* cmakeRulesBuildPhase =
977 this->CreateBuildPhase("CMake Rules",
978 "cmakeRulesBuildPhase",
979 cmtarget, commands);
980 // create prebuild phase
981 cmXCodeObject* preBuildPhase =
982 this->CreateBuildPhase("CMake PreBuild Rules", "preBuildCommands",
983 cmtarget, prebuild);
984 // create prelink phase
985 cmXCodeObject* preLinkPhase =
986 this->CreateBuildPhase("CMake PreLink Rules", "preLinkCommands",
987 cmtarget, prelink);
988 // create postbuild phase
989 cmXCodeObject* postBuildPhase =
990 this->CreateBuildPhase("CMake PostBuild Rules", "postBuildPhase",
991 cmtarget, postbuild);
993 // The order here is the order they will be built in.
994 // The order "headers, resources, sources" mimics a native project generated
995 // from an xcode template...
997 if(preBuildPhase)
999 buildPhases->AddObject(preBuildPhase);
1001 if(cmakeRulesBuildPhase)
1003 buildPhases->AddObject(cmakeRulesBuildPhase);
1005 if(headerBuildPhase)
1007 buildPhases->AddObject(headerBuildPhase);
1009 if(resourceBuildPhase)
1011 buildPhases->AddObject(resourceBuildPhase);
1013 std::vector<cmXCodeObject*>::iterator cit;
1014 for (cit = contentBuildPhases.begin(); cit != contentBuildPhases.end();
1015 ++cit)
1017 buildPhases->AddObject(*cit);
1019 if(sourceBuildPhase)
1021 buildPhases->AddObject(sourceBuildPhase);
1023 if(preLinkPhase)
1025 buildPhases->AddObject(preLinkPhase);
1027 if(frameworkBuildPhase)
1029 buildPhases->AddObject(frameworkBuildPhase);
1031 if(postBuildPhase)
1033 buildPhases->AddObject(postBuildPhase);
1037 //----------------------------------------------------------------------------
1038 std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
1039 std::string& flags)
1041 std::string retFlag;
1042 std::string::size_type pos = flags.find(flag);
1043 if(pos != flags.npos && (pos ==0 || flags[pos-1]==' '))
1045 while(pos < flags.size() && flags[pos] != ' ')
1047 retFlag += flags[pos];
1048 flags[pos] = ' ';
1049 pos++;
1052 return retFlag;
1055 //----------------------------------------------------------------------------
1056 void
1057 cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
1058 cmTarget& target,
1059 std::vector<cmCustomCommand>
1060 const & commands,
1061 const char* name)
1063 if(strcmp(name, "cmakeReRunPhase") == 0)
1065 std::string cdir = this->CurrentMakefile->GetHomeOutputDirectory();
1066 cdir = this->ConvertToRelativeForMake(cdir.c_str());
1067 std::string makecmd = "make -C ";
1068 makecmd += cdir;
1069 makecmd += " -f ";
1070 makecmd +=
1071 this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile.c_str());
1072 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1073 buildphase->AddAttribute("shellScript",
1074 this->CreateString(makecmd.c_str()));
1075 return;
1078 // collect multiple outputs of custom commands into a set
1079 // which will be used for every configuration
1080 std::map<cmStdString, cmStdString> multipleOutputPairs;
1081 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1082 i != commands.end(); ++i)
1084 cmCustomCommand const& cc = *i;
1085 if(!cc.GetCommandLines().empty())
1087 const std::vector<std::string>& outputs = cc.GetOutputs();
1088 if(!outputs.empty())
1090 // If there are more than one outputs treat the
1091 // first as the primary output and make the rest depend on it.
1092 std::vector<std::string>::const_iterator o = outputs.begin();
1093 std::string primaryOutput = this->ConvertToRelativeForMake(o->c_str());
1094 for(++o; o != outputs.end(); ++o)
1096 std::string currentOutput=this->ConvertToRelativeForMake(o->c_str());
1097 multipleOutputPairs[currentOutput] = primaryOutput;
1103 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
1104 dir += "/CMakeScripts";
1105 cmSystemTools::MakeDirectory(dir.c_str());
1106 std::string makefile = dir;
1107 makefile += "/";
1108 makefile += target.GetName();
1109 makefile += "_";
1110 makefile += name;
1111 makefile += ".make";
1113 for (std::vector<std::string>::const_iterator currentConfig=
1114 this->CurrentConfigurationTypes.begin();
1115 currentConfig!=this->CurrentConfigurationTypes.end();
1116 currentConfig++ )
1118 this->CreateCustomRulesMakefile(makefile.c_str(),
1119 target,
1120 commands,
1121 currentConfig->c_str(),
1122 multipleOutputPairs);
1125 std::string cdir = this->CurrentMakefile->GetCurrentOutputDirectory();
1126 cdir = this->ConvertToRelativeForXCode(cdir.c_str());
1127 std::string makecmd = "make -C ";
1128 makecmd += cdir;
1129 makecmd += " -f ";
1130 makecmd += this->ConvertToRelativeForMake(
1131 (makefile+"$CONFIGURATION").c_str());
1132 if(!multipleOutputPairs.empty())
1134 makecmd += " cmake_check_multiple_outputs";
1136 makecmd += " all";
1137 cmSystemTools::ReplaceString(makecmd, "\\ ", "\\\\ ");
1138 buildphase->AddAttribute("shellScript",
1139 this->CreateString(makecmd.c_str()));
1142 //----------------------------------------------------------------------------
1143 void cmGlobalXCodeGenerator
1144 ::CreateCustomRulesMakefile(const char* makefileBasename,
1145 cmTarget& target,
1146 std::vector<cmCustomCommand>
1147 const & commands,
1148 const char* configName,
1149 const std::map<cmStdString,
1150 cmStdString>& multipleOutputPairs
1153 std::string makefileName=makefileBasename;
1154 makefileName+=configName;
1155 cmGeneratedFileStream makefileStream(makefileName.c_str());
1156 if(!makefileStream)
1158 return;
1160 makefileStream.SetCopyIfDifferent(true);
1161 makefileStream << "# Generated by CMake, DO NOT EDIT\n";
1162 makefileStream << "# Custom rules for " << target.GetName() << "\n";
1164 // have all depend on all outputs
1165 makefileStream << "all: ";
1166 std::map<const cmCustomCommand*, cmStdString> tname;
1167 int count = 0;
1168 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1169 i != commands.end(); ++i)
1171 cmCustomCommand const& cc = *i;
1172 if(!cc.GetCommandLines().empty())
1174 const std::vector<std::string>& outputs = cc.GetOutputs();
1175 if(!outputs.empty())
1177 for(std::vector<std::string>::const_iterator o = outputs.begin();
1178 o != outputs.end(); ++o)
1180 makefileStream
1181 << "\\\n\t" << this->ConvertToRelativeForMake(o->c_str());
1184 else
1186 cmOStringStream str;
1187 str << "_buildpart_" << count++ ;
1188 tname[&cc] = std::string(target.GetName()) + str.str();
1189 makefileStream << "\\\n\t" << tname[&cc];
1193 makefileStream << "\n\n";
1194 for(std::vector<cmCustomCommand>::const_iterator i = commands.begin();
1195 i != commands.end(); ++i)
1197 cmCustomCommand const& cc = *i;
1198 if(!cc.GetCommandLines().empty())
1200 bool escapeOldStyle = cc.GetEscapeOldStyle();
1201 bool escapeAllowMakeVars = cc.GetEscapeAllowMakeVars();
1202 makefileStream << "\n";
1203 const std::vector<std::string>& outputs = cc.GetOutputs();
1204 if(!outputs.empty())
1206 // There is at least one output, start the rule for it
1207 std::string primary_output =
1208 this->ConvertToRelativeForMake(outputs.begin()->c_str());
1209 makefileStream << primary_output << ": ";
1211 else
1213 // There are no outputs. Use the generated force rule name.
1214 makefileStream << tname[&cc] << ": ";
1216 for(std::vector<std::string>::const_iterator d =
1217 cc.GetDepends().begin();
1218 d != cc.GetDepends().end(); ++d)
1220 std::string dep =
1221 this->CurrentLocalGenerator->GetRealDependency(d->c_str(),
1222 configName);
1223 makefileStream << "\\\n" << this
1224 ->ConvertToRelativeForMake(dep.c_str());
1226 makefileStream << "\n";
1228 if(const char* comment = cc.GetComment())
1230 std::string echo_cmd = "echo ";
1231 echo_cmd += (this->CurrentLocalGenerator->
1232 EscapeForShell(comment, escapeAllowMakeVars));
1233 makefileStream << "\t" << echo_cmd.c_str() << "\n";
1236 // Add each command line to the set of commands.
1237 for(cmCustomCommandLines::const_iterator cl =
1238 cc.GetCommandLines().begin();
1239 cl != cc.GetCommandLines().end(); ++cl)
1241 // Build the command line in a single string.
1242 const cmCustomCommandLine& commandLine = *cl;
1243 std::string cmd2 = this->CurrentLocalGenerator
1244 ->GetRealLocation(commandLine[0].c_str(), configName);
1246 cmSystemTools::ReplaceString(cmd2, "/./", "/");
1247 cmd2 = this->ConvertToRelativeForMake(cmd2.c_str());
1248 std::string cmd;
1249 if(cc.GetWorkingDirectory())
1251 cmd += "cd ";
1252 cmd += this->ConvertToRelativeForMake(cc.GetWorkingDirectory());
1253 cmd += " && ";
1255 cmd += cmd2;
1256 for(unsigned int j=1; j < commandLine.size(); ++j)
1258 cmd += " ";
1259 if(escapeOldStyle)
1261 cmd += (this->CurrentLocalGenerator
1262 ->EscapeForShellOldStyle(commandLine[j].c_str()));
1264 else
1266 cmd += (this->CurrentLocalGenerator->
1267 EscapeForShell(commandLine[j].c_str(),
1268 escapeAllowMakeVars));
1271 makefileStream << "\t" << cmd.c_str() << "\n";
1276 // Add rules to deal with multiple outputs of custom commands.
1277 if(!multipleOutputPairs.empty())
1279 makefileStream <<
1280 "\n# Dependencies of multiple outputs to their primary outputs \n";
1282 for(std::map<cmStdString, cmStdString>::const_iterator o =
1283 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1285 makefileStream << o->first << ": " << o->second << "\n";
1288 makefileStream <<
1289 "\n"
1290 "cmake_check_multiple_outputs:\n";
1291 for(std::map<cmStdString, cmStdString>::const_iterator o =
1292 multipleOutputPairs.begin(); o != multipleOutputPairs.end(); ++o)
1294 makefileStream << "\t@if [ ! -f "
1295 << o->first << " ]; then rm -f "
1296 << o->second << "; fi\n";
1301 //----------------------------------------------------------------------------
1302 void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
1303 cmXCodeObject* buildSettings,
1304 std::string& fileType,
1305 std::string& productType,
1306 std::string& productName,
1307 const char* configName)
1309 std::string flags;
1310 std::string defFlags;
1311 bool shared = ((target.GetType() == cmTarget::SHARED_LIBRARY) ||
1312 (target.GetType() == cmTarget::MODULE_LIBRARY));
1314 const char* lang = target.GetLinkerLanguage(this);
1315 std::string cflags;
1316 if(lang)
1318 // for c++ projects get the c flags as well
1319 if(strcmp(lang, "CXX") == 0)
1321 this->CurrentLocalGenerator->AddLanguageFlags(cflags, "C", configName);
1322 this->CurrentLocalGenerator->AddSharedFlags(cflags, lang, shared);
1325 // Add language-specific flags.
1326 this->CurrentLocalGenerator->AddLanguageFlags(flags, lang, configName);
1328 // Add shared-library flags if needed.
1329 this->CurrentLocalGenerator->AddSharedFlags(flags, lang, shared);
1332 // Add define flags
1333 this->CurrentLocalGenerator->
1334 AppendFlags(defFlags,
1335 this->CurrentMakefile->GetDefineFlags());
1337 // Add preprocessor definitions for this target and configuration.
1338 std::string ppDefs;
1339 if(this->XcodeVersion > 15)
1341 this->AppendDefines(ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)\"");
1343 if(const char* exportMacro = target.GetExportMacro())
1345 // Add the export symbol definition for shared library objects.
1346 this->AppendDefines(ppDefs, exportMacro);
1348 this->AppendDefines
1349 (ppDefs, this->CurrentMakefile->GetProperty("COMPILE_DEFINITIONS"));
1350 this->AppendDefines(ppDefs, target.GetProperty("COMPILE_DEFINITIONS"));
1351 if(configName)
1353 std::string defVarName = "COMPILE_DEFINITIONS_";
1354 defVarName += cmSystemTools::UpperCase(configName);
1355 this->AppendDefines
1356 (ppDefs, this->CurrentMakefile->GetProperty(defVarName.c_str()));
1357 this->AppendDefines(ppDefs, target.GetProperty(defVarName.c_str()));
1359 buildSettings->AddAttribute
1360 ("GCC_PREPROCESSOR_DEFINITIONS", this->CreateString(ppDefs.c_str()));
1362 std::string extraLinkOptions;
1363 if(target.GetType() == cmTarget::EXECUTABLE)
1365 extraLinkOptions =
1366 this->CurrentMakefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS");
1368 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1370 extraLinkOptions = this->CurrentMakefile->
1371 GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS");
1373 if(target.GetType() == cmTarget::MODULE_LIBRARY)
1375 extraLinkOptions = this->CurrentMakefile->
1376 GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS");
1379 const char* targetLinkFlags = target.GetProperty("LINK_FLAGS");
1380 if(targetLinkFlags)
1382 extraLinkOptions += " ";
1383 extraLinkOptions += targetLinkFlags;
1386 // The product name is the full name of the target for this configuration.
1387 productName = target.GetFullName(configName);
1389 // Get the product name components.
1390 std::string pnprefix;
1391 std::string pnbase;
1392 std::string pnsuffix;
1393 target.GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
1395 // Store the product name for all target types.
1396 buildSettings->AddAttribute("PRODUCT_NAME",
1397 this->CreateString(pnbase.c_str()));
1399 // Set attributes to specify the proper name for the target.
1400 if(target.GetType() == cmTarget::STATIC_LIBRARY ||
1401 target.GetType() == cmTarget::SHARED_LIBRARY ||
1402 target.GetType() == cmTarget::MODULE_LIBRARY ||
1403 target.GetType() == cmTarget::EXECUTABLE)
1405 std::string pndir = target.GetDirectory();
1406 buildSettings->AddAttribute("SYMROOT",
1407 this->CreateString(pndir.c_str()));
1408 buildSettings->AddAttribute("EXECUTABLE_PREFIX",
1409 this->CreateString(pnprefix.c_str()));
1410 buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
1411 this->CreateString(pnsuffix.c_str()));
1414 // Handle settings for each target type.
1415 switch(target.GetType())
1417 case cmTarget::STATIC_LIBRARY:
1419 fileType = "archive.ar";
1420 productType = "com.apple.product-type.library.static";
1422 buildSettings->AddAttribute("LIBRARY_STYLE",
1423 this->CreateString("STATIC"));
1424 break;
1427 case cmTarget::MODULE_LIBRARY:
1429 buildSettings->AddAttribute("LIBRARY_STYLE",
1430 this->CreateString("BUNDLE"));
1431 if(this->XcodeVersion >= 22)
1433 fileType = "compiled.mach-o.executable";
1434 productType = "com.apple.product-type.tool";
1436 buildSettings->AddAttribute("MACH_O_TYPE",
1437 this->CreateString("mh_bundle"));
1438 buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
1439 this->CreateString("NO"));
1440 // Add the flags to create an executable.
1441 std::string createFlags =
1442 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1443 if(!createFlags.empty())
1445 extraLinkOptions += " ";
1446 extraLinkOptions += createFlags;
1449 else
1451 fileType = "compiled.mach-o.dylib";
1452 productType = "com.apple.product-type.library.dynamic";
1454 // Add the flags to create a module.
1455 std::string createFlags =
1456 this->LookupFlags("CMAKE_SHARED_MODULE_CREATE_", lang, "_FLAGS",
1457 "-bundle");
1458 if(!createFlags.empty())
1460 extraLinkOptions += " ";
1461 extraLinkOptions += createFlags;
1464 break;
1466 case cmTarget::SHARED_LIBRARY:
1468 if(target.GetPropertyAsBool("FRAMEWORK"))
1470 fileType = "wrapper.framework";
1471 productType = "com.apple.product-type.framework";
1473 std::string version = target.GetFrameworkVersion();
1474 buildSettings->AddAttribute("FRAMEWORK_VERSION",
1475 this->CreateString(version.c_str()));
1477 std::string plist = this->ComputeInfoPListLocation(target);
1478 // Xcode will create the final version of Info.plist at build time,
1479 // so let it replace the framework name. This avoids creating
1480 // a per-configuration Info.plist file.
1481 this->CurrentLocalGenerator
1482 ->GenerateFrameworkInfoPList(&target, "$(EXECUTABLE_NAME)",
1483 plist.c_str());
1484 std::string path =
1485 this->ConvertToRelativeForXCode(plist.c_str());
1486 buildSettings->AddAttribute("INFOPLIST_FILE",
1487 this->CreateString(path.c_str()));
1489 else
1491 fileType = "compiled.mach-o.dylib";
1492 productType = "com.apple.product-type.library.dynamic";
1494 // Add the flags to create a shared library.
1495 std::string createFlags =
1496 this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", lang, "_FLAGS",
1497 "-dynamiclib");
1498 if(!createFlags.empty())
1500 extraLinkOptions += " ";
1501 extraLinkOptions += createFlags;
1505 buildSettings->AddAttribute("LIBRARY_STYLE",
1506 this->CreateString("DYNAMIC"));
1507 break;
1509 case cmTarget::EXECUTABLE:
1511 fileType = "compiled.mach-o.executable";
1513 // Add the flags to create an executable.
1514 std::string createFlags =
1515 this->LookupFlags("CMAKE_", lang, "_LINK_FLAGS", "");
1516 if(!createFlags.empty())
1518 extraLinkOptions += " ";
1519 extraLinkOptions += createFlags;
1522 // Handle bundles and normal executables separately.
1523 if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
1525 productType = "com.apple.product-type.application";
1526 std::string plist = this->ComputeInfoPListLocation(target);
1527 // Xcode will create the final version of Info.plist at build time,
1528 // so let it replace the executable name. This avoids creating
1529 // a per-configuration Info.plist file.
1530 this->CurrentLocalGenerator
1531 ->GenerateAppleInfoPList(&target, "$(EXECUTABLE_NAME)",
1532 plist.c_str());
1533 std::string path =
1534 this->ConvertToRelativeForXCode(plist.c_str());
1535 buildSettings->AddAttribute("INFOPLIST_FILE",
1536 this->CreateString(path.c_str()));
1539 else
1541 productType = "com.apple.product-type.tool";
1544 break;
1545 default:
1546 break;
1548 if(this->XcodeVersion >= 22)
1550 buildSettings->AddAttribute("PREBINDING",
1551 this->CreateString("NO"));
1553 std::string dirs;
1554 std::vector<std::string> includes;
1555 this->CurrentLocalGenerator->GetIncludeDirectories(includes);
1556 std::string fdirs;
1557 std::set<cmStdString> emitted;
1558 emitted.insert("/System/Library/Frameworks");
1559 for(std::vector<std::string>::iterator i = includes.begin();
1560 i != includes.end(); ++i)
1562 if(this->NameResolvesToFramework(i->c_str()))
1564 std::string frameworkDir = *i;
1565 frameworkDir += "/../";
1566 frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str());
1567 if(emitted.insert(frameworkDir).second)
1569 fdirs += this->XCodeEscapePath(frameworkDir.c_str());
1570 fdirs += " ";
1573 else
1575 std::string incpath =
1576 this->XCodeEscapePath(i->c_str());
1577 dirs += incpath + " ";
1580 std::vector<std::string>& frameworks = target.GetFrameworks();
1581 if(frameworks.size())
1583 for(std::vector<std::string>::iterator fmIt = frameworks.begin();
1584 fmIt != frameworks.end(); ++fmIt)
1586 if(emitted.insert(*fmIt).second)
1588 fdirs += this->XCodeEscapePath(fmIt->c_str());
1589 fdirs += " ";
1593 if(fdirs.size())
1595 buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS",
1596 this->CreateString(fdirs.c_str()));
1598 if(dirs.size())
1600 buildSettings->AddAttribute("HEADER_SEARCH_PATHS",
1601 this->CreateString(dirs.c_str()));
1603 std::string oflagc = this->ExtractFlag("-O", cflags);
1604 char optLevel[2];
1605 optLevel[0] = '0';
1606 optLevel[1] = 0;
1607 if(oflagc.size() == 3)
1609 optLevel[0] = oflagc[2];
1611 if(oflagc.size() == 2)
1613 optLevel[0] = '1';
1615 std::string oflag = this->ExtractFlag("-O", flags);
1616 if(oflag.size() == 3)
1618 optLevel[0] = oflag[2];
1620 if(oflag.size() == 2)
1622 optLevel[0] = '1';
1624 std::string gflagc = this->ExtractFlag("-g", cflags);
1625 // put back gdwarf-2 if used since there is no way
1626 // to represent it in the gui, but we still want debug yes
1627 if(gflagc == "-gdwarf-2")
1629 cflags += " ";
1630 cflags += gflagc;
1632 std::string gflag = this->ExtractFlag("-g", flags);
1633 if(gflag == "-gdwarf-2")
1635 flags += " ";
1636 flags += gflag;
1638 const char* debugStr = "YES";
1639 if(gflagc.size() ==0 && gflag.size() == 0)
1641 debugStr = "NO";
1644 buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
1645 this->CreateString(debugStr));
1646 buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
1647 this->CreateString(optLevel));
1648 buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
1649 this->CreateString("NO"));
1650 buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
1651 this->CreateString("NO"));
1652 if(lang && strcmp(lang, "CXX") == 0)
1654 flags += " ";
1655 flags += defFlags;
1656 buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
1657 this->CreateString(flags.c_str()));
1658 cflags += " ";
1659 cflags += defFlags;
1660 buildSettings->AddAttribute("OTHER_CFLAGS",
1661 this->CreateString(cflags.c_str()));
1664 else
1666 flags += " ";
1667 flags += defFlags;
1668 buildSettings->AddAttribute("OTHER_CFLAGS",
1669 this->CreateString(flags.c_str()));
1672 // Create the INSTALL_PATH attribute.
1673 std::string install_name_dir;
1674 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1676 // Get the install_name directory for the build tree.
1677 install_name_dir = target.GetInstallNameDirForBuildTree(configName, true);
1678 if(install_name_dir.empty())
1680 // Xcode will not pass the -install_name option at all if INSTALL_PATH
1681 // is not given or is empty. We must explicitly put the flag in the
1682 // link flags to create an install_name with just the library soname.
1683 extraLinkOptions += " -install_name ";
1684 extraLinkOptions += productName;
1686 else
1688 // Convert to a path for the native build tool.
1689 cmSystemTools::ConvertToUnixSlashes(install_name_dir);
1690 // do not escape spaces on this since it is only a single path
1693 buildSettings->AddAttribute("INSTALL_PATH",
1694 this->CreateString(install_name_dir.c_str()));
1696 buildSettings->AddAttribute("OTHER_LDFLAGS",
1697 this->CreateString(extraLinkOptions.c_str()));
1698 buildSettings->AddAttribute("OTHER_REZFLAGS",
1699 this->CreateString(""));
1700 buildSettings->AddAttribute("SECTORDER_FLAGS",
1701 this->CreateString(""));
1702 buildSettings->AddAttribute("USE_HEADERMAP",
1703 this->CreateString("NO"));
1704 buildSettings->AddAttribute("WARNING_CFLAGS",
1705 this->CreateString(
1706 "-Wmost -Wno-four-char-constants"
1707 " -Wno-unknown-pragmas"));
1709 // Runtime version information.
1710 if(target.GetType() == cmTarget::SHARED_LIBRARY)
1712 int major;
1713 int minor;
1714 int patch;
1716 // VERSION -> current_version
1717 target.GetTargetVersion(false, major, minor, patch);
1718 if(major == 0 && minor == 0 && patch == 0)
1720 // Xcode always wants at least 1.0.0
1721 major = 1;
1723 cmOStringStream v;
1724 v << major << "." << minor << "." << patch;
1725 buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
1726 this->CreateString(v.str().c_str()));
1728 // SOVERSION -> compatibility_version
1729 target.GetTargetVersion(true, major, minor, patch);
1730 if(major == 0 && minor == 0 && patch == 0)
1732 // Xcode always wants at least 1.0.0
1733 major = 1;
1735 cmOStringStream vso;
1736 vso << major << "." << minor << "." << patch;
1737 buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
1738 this->CreateString(vso.str().c_str()));
1740 // put this last so it can override existing settings
1741 // Convert "XCODE_ATTRIBUTE_*" properties directly.
1743 cmPropertyMap const& props = target.GetProperties();
1744 for(cmPropertyMap::const_iterator i = props.begin();
1745 i != props.end(); ++i)
1747 if(i->first.find("XCODE_ATTRIBUTE_") == 0)
1749 buildSettings->AddAttribute(i->first.substr(16).c_str(),
1750 this->CreateString(i->second.GetValue()));
1756 //----------------------------------------------------------------------------
1757 cmXCodeObject*
1758 cmGlobalXCodeGenerator::CreateUtilityTarget(cmTarget& cmtarget)
1760 cmXCodeObject* shellBuildPhase =
1761 this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
1762 shellBuildPhase->AddAttribute("buildActionMask",
1763 this->CreateString("2147483647"));
1764 cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1765 shellBuildPhase->AddAttribute("files", buildFiles);
1766 cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1767 shellBuildPhase->AddAttribute("inputPaths", inputPaths);
1768 cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1769 shellBuildPhase->AddAttribute("outputPaths", outputPaths);
1770 shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1771 this->CreateString("0"));
1772 shellBuildPhase->AddAttribute("shellPath",
1773 this->CreateString("/bin/sh"));
1774 shellBuildPhase->AddAttribute("shellScript",
1775 this->CreateString(
1776 "# shell script goes here\nexit 0"));
1777 cmXCodeObject* target =
1778 this->CreateObject(cmXCodeObject::PBXAggregateTarget);
1779 target->SetComment(cmtarget.GetName());
1780 cmXCodeObject* buildPhases =
1781 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1782 std::vector<cmXCodeObject*> emptyContentVector;
1783 this->CreateCustomCommands(buildPhases, 0, 0, 0, emptyContentVector, 0,
1784 cmtarget);
1785 target->AddAttribute("buildPhases", buildPhases);
1786 cmXCodeObject* buildSettings =
1787 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1788 std::string fileTypeString;
1789 std::string productTypeString;
1790 std::string productName;
1791 const char* globalConfig = 0;
1792 if(this->XcodeVersion > 20)
1794 this->AddConfigurations(target, cmtarget);
1796 else
1798 globalConfig = this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
1800 this->CreateBuildSettings(cmtarget,
1801 buildSettings, fileTypeString,
1802 productTypeString, productName, globalConfig);
1803 target->AddAttribute("buildSettings", buildSettings);
1804 cmXCodeObject* dependencies =
1805 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1806 target->AddAttribute("dependencies", dependencies);
1807 target->AddAttribute("name", this->CreateString(productName.c_str()));
1808 target->AddAttribute("productName",this->CreateString(productName.c_str()));
1809 target->SetTarget(&cmtarget);
1811 // Add source files without build rules for editing convenience.
1812 if(cmtarget.GetType() == cmTarget::UTILITY)
1814 std::vector<cmSourceFile*> const& sources = cmtarget.GetSourceFiles();
1815 for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
1816 i != sources.end(); ++i)
1818 if(!(*i)->GetPropertyAsBool("GENERATED"))
1820 this->CreateXCodeFileReference(*i, cmtarget);
1825 return target;
1828 //----------------------------------------------------------------------------
1829 void cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
1830 cmTarget& cmtarget)
1832 std::string configTypes =
1833 this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES");
1834 std::vector<std::string> configVectorIn;
1835 std::vector<std::string> configVector;
1836 configVectorIn.push_back(configTypes);
1837 cmSystemTools::ExpandList(configVectorIn, configVector);
1838 cmXCodeObject* configlist =
1839 this->CreateObject(cmXCodeObject::XCConfigurationList);
1840 cmXCodeObject* buildConfigurations =
1841 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1842 configlist->AddAttribute("buildConfigurations", buildConfigurations);
1843 std::string comment = "Build configuration list for ";
1844 comment += cmXCodeObject::PBXTypeNames[target->GetIsA()];
1845 comment += " \"";
1846 comment += cmtarget.GetName();
1847 comment += "\"";
1848 configlist->SetComment(comment.c_str());
1849 target->AddAttribute("buildConfigurationList",
1850 this->CreateObjectReference(configlist));
1851 for(unsigned int i = 0; i < configVector.size(); ++i)
1853 cmXCodeObject* config =
1854 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
1855 buildConfigurations->AddObject(config);
1856 cmXCodeObject* buildSettings =
1857 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1858 std::string fileTypeString;
1859 std::string productTypeString;
1860 std::string productName;
1861 this->CreateBuildSettings(cmtarget,
1862 buildSettings, fileTypeString,
1863 productTypeString, productName,
1864 configVector[i].c_str());
1865 config->AddAttribute("name", this->CreateString(configVector[i].c_str()));
1866 config->SetComment(configVector[i].c_str());
1867 config->AddAttribute("buildSettings", buildSettings);
1869 if(configVector.size())
1871 configlist->AddAttribute("defaultConfigurationName",
1872 this->CreateString(configVector[0].c_str()));
1873 configlist->AddAttribute("defaultConfigurationIsVisible",
1874 this->CreateString("0"));
1878 //----------------------------------------------------------------------------
1879 cmXCodeObject*
1880 cmGlobalXCodeGenerator::CreateXCodeTarget(cmTarget& cmtarget,
1881 cmXCodeObject* buildPhases)
1883 cmXCodeObject* target =
1884 this->CreateObject(cmXCodeObject::PBXNativeTarget);
1885 target->AddAttribute("buildPhases", buildPhases);
1886 cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1887 target->AddAttribute("buildRules", buildRules);
1888 cmXCodeObject* buildSettings =
1889 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
1890 std::string fileTypeString;
1891 std::string productTypeString;
1892 std::string productName;
1893 const char* globalConfig = 0;
1894 if(this->XcodeVersion > 20)
1896 this->AddConfigurations(target, cmtarget);
1898 else
1900 globalConfig = this->CurrentMakefile->GetDefinition("CMAKE_BUILD_TYPE");
1902 this->CreateBuildSettings(cmtarget,
1903 buildSettings, fileTypeString,
1904 productTypeString, productName, globalConfig);
1905 target->AddAttribute("buildSettings", buildSettings);
1906 cmXCodeObject* dependencies =
1907 this->CreateObject(cmXCodeObject::OBJECT_LIST);
1908 target->AddAttribute("dependencies", dependencies);
1909 target->AddAttribute("name", this->CreateString(productName.c_str()));
1910 target->AddAttribute("productName",this->CreateString(productName.c_str()));
1912 cmXCodeObject* fileRef =
1913 this->CreateObject(cmXCodeObject::PBXFileReference);
1914 fileRef->AddAttribute("explicitFileType",
1915 this->CreateString(fileTypeString.c_str()));
1916 fileRef->AddAttribute("path", this->CreateString(productName.c_str()));
1917 fileRef->AddAttribute("refType", this->CreateString("0"));
1918 fileRef->AddAttribute("sourceTree",
1919 this->CreateString("BUILT_PRODUCTS_DIR"));
1920 fileRef->SetComment(cmtarget.GetName());
1921 target->AddAttribute("productReference",
1922 this->CreateObjectReference(fileRef));
1923 target->AddAttribute("productType",
1924 this->CreateString(productTypeString.c_str()));
1925 target->SetTarget(&cmtarget);
1926 return target;
1929 //----------------------------------------------------------------------------
1930 cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(cmTarget* t)
1932 if(!t)
1934 return 0;
1936 for(std::vector<cmXCodeObject*>::iterator i = this->XCodeObjects.begin();
1937 i != this->XCodeObjects.end(); ++i)
1939 cmXCodeObject* o = *i;
1940 if(o->GetTarget() == t)
1942 return o;
1945 return 0;
1948 //----------------------------------------------------------------------------
1949 void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
1950 cmXCodeObject* dependTarget)
1952 // make sure a target does not depend on itself
1953 if(target == dependTarget)
1955 return;
1957 // now avoid circular references if dependTarget already
1958 // depends on target then skip it. Circular references crashes
1959 // xcode
1960 cmXCodeObject* dependTargetDepends =
1961 dependTarget->GetObject("dependencies");
1962 if(dependTargetDepends)
1964 if(dependTargetDepends->HasObject(target->GetPBXTargetDependency()))
1966 return;
1970 cmXCodeObject* targetdep = dependTarget->GetPBXTargetDependency();
1971 if(!targetdep)
1973 cmXCodeObject* container =
1974 this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
1975 container->SetComment("PBXContainerItemProxy");
1976 container->AddAttribute("containerPortal",
1977 this->CreateObjectReference(this->RootObject));
1978 container->AddAttribute("proxyType", this->CreateString("1"));
1979 container->AddAttribute("remoteGlobalIDString",
1980 this->CreateObjectReference(dependTarget));
1981 container->AddAttribute("remoteInfo",
1982 this->CreateString(
1983 dependTarget->GetTarget()->GetName()));
1984 targetdep =
1985 this->CreateObject(cmXCodeObject::PBXTargetDependency);
1986 targetdep->SetComment("PBXTargetDependency");
1987 targetdep->AddAttribute("target",
1988 this->CreateObjectReference(dependTarget));
1989 targetdep->AddAttribute("targetProxy",
1990 this->CreateObjectReference(container));
1991 dependTarget->SetPBXTargetDependency(targetdep);
1994 cmXCodeObject* depends = target->GetObject("dependencies");
1995 if(!depends)
1997 cmSystemTools::
1998 Error("target does not have dependencies attribute error..");
2001 else
2003 depends->AddUniqueObject(targetdep);
2007 //----------------------------------------------------------------------------
2008 void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
2009 const char* attribute,
2010 const char* value)
2012 if(settings)
2014 cmXCodeObject* attr = settings->GetObject(attribute);
2015 if(!attr)
2017 settings->AddAttribute(attribute, this->CreateString(value));
2019 else
2021 std::string oldValue = attr->GetString();
2022 oldValue += " ";
2023 oldValue += value;
2024 attr->SetString(oldValue.c_str());
2029 //----------------------------------------------------------------------------
2030 void cmGlobalXCodeGenerator
2031 ::AppendBuildSettingAttribute(cmXCodeObject* target,
2032 const char* attribute,
2033 const char* value,
2034 const char* configName)
2036 if(this->XcodeVersion < 21)
2038 // There is only one configuration. Add the setting to the buildSettings
2039 // of the target.
2040 this->AppendOrAddBuildSetting(target->GetObject("buildSettings"),
2041 attribute, value);
2043 else
2045 // There are multiple configurations. Add the setting to the
2046 // buildSettings of the configuration name given.
2047 cmXCodeObject* configurationList =
2048 target->GetObject("buildConfigurationList")->GetObject();
2049 cmXCodeObject* buildConfigs =
2050 configurationList->GetObject("buildConfigurations");
2051 std::vector<cmXCodeObject*> list = buildConfigs->GetObjectList();
2052 // each configuration and the target itself has a buildSettings in it
2053 //list.push_back(target);
2054 for(std::vector<cmXCodeObject*>::iterator i = list.begin();
2055 i != list.end(); ++i)
2057 if(configName)
2059 if(strcmp((*i)->GetObject("name")->GetString(), configName) == 0)
2061 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2062 this->AppendOrAddBuildSetting(settings, attribute, value);
2065 else
2067 cmXCodeObject* settings = (*i)->GetObject("buildSettings");
2068 this->AppendOrAddBuildSetting(settings, attribute, value);
2074 //----------------------------------------------------------------------------
2075 void cmGlobalXCodeGenerator
2076 ::AddDependAndLinkInformation(cmXCodeObject* target)
2078 cmTarget* cmtarget = target->GetTarget();
2079 if(!cmtarget)
2081 cmSystemTools::Error("Error no target on xobject\n");
2082 return;
2085 // Add dependencies on other CMake targets.
2086 TargetDependSet const& deps = this->GetTargetDirectDepends(*cmtarget);
2087 for(TargetDependSet::const_iterator i = deps.begin(); i != deps.end(); ++i)
2089 if(cmXCodeObject* dptarget = this->FindXCodeTarget(*i))
2091 this->AddDependTarget(target, dptarget);
2095 // Skip link information for static libraries.
2096 if(cmtarget->GetType() == cmTarget::STATIC_LIBRARY)
2098 return;
2101 // Loop over configuration types and set per-configuration info.
2102 for(std::vector<std::string>::iterator i =
2103 this->CurrentConfigurationTypes.begin();
2104 i != this->CurrentConfigurationTypes.end(); ++i)
2106 // Get the current configuration name.
2107 const char* configName = i->c_str();
2108 if(!*configName)
2110 configName = 0;
2113 // Compute the link library and directory information.
2114 cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName);
2115 if(!pcli)
2117 continue;
2119 cmComputeLinkInformation& cli = *pcli;
2121 // Add dependencies directly on library files.
2123 std::vector<std::string> const& libDeps = cli.GetDepends();
2124 for(std::vector<std::string>::const_iterator j = libDeps.begin();
2125 j != libDeps.end(); ++j)
2127 target->AddDependLibrary(configName, j->c_str());
2131 // add the library search paths
2133 std::vector<std::string> const& libDirs = cli.GetDirectories();
2134 std::string linkDirs;
2135 for(std::vector<std::string>::const_iterator libDir = libDirs.begin();
2136 libDir != libDirs.end(); ++libDir)
2138 if(libDir->size() && *libDir != "/usr/lib")
2140 if(this->XcodeVersion > 15)
2142 // now add the same one but append $(CONFIGURATION) to it:
2143 linkDirs += " ";
2144 linkDirs += this->XCodeEscapePath(
2145 (*libDir + "/$(CONFIGURATION)").c_str());
2147 linkDirs += " ";
2148 linkDirs += this->XCodeEscapePath(libDir->c_str());
2151 this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
2152 linkDirs.c_str(), configName);
2155 // add the framework search paths
2157 const char* sep = "";
2158 std::string fdirs;
2159 std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
2160 for(std::vector<std::string>::const_iterator fdi = fwDirs.begin();
2161 fdi != fwDirs.end(); ++fdi)
2163 fdirs += sep;
2164 sep = " ";
2165 fdirs += this->XCodeEscapePath(fdi->c_str());
2167 if(!fdirs.empty())
2169 this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
2170 fdirs.c_str(), configName);
2174 // now add the link libraries
2176 std::string linkLibs;
2177 const char* sep = "";
2178 typedef cmComputeLinkInformation::ItemVector ItemVector;
2179 ItemVector const& libNames = cli.GetItems();
2180 for(ItemVector::const_iterator li = libNames.begin();
2181 li != libNames.end(); ++li)
2183 linkLibs += sep;
2184 sep = " ";
2185 if(li->IsPath)
2187 linkLibs += this->XCodeEscapePath(li->Value.c_str());
2189 else
2191 linkLibs += li->Value;
2194 this->AppendBuildSettingAttribute(target, "OTHER_LDFLAGS",
2195 linkLibs.c_str(), configName);
2200 //----------------------------------------------------------------------------
2201 void cmGlobalXCodeGenerator::CreateGroups(cmLocalGenerator* root,
2202 std::vector<cmLocalGenerator*>&
2203 generators)
2205 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2206 i != generators.end(); ++i)
2208 if(this->IsExcluded(root, *i))
2210 continue;
2212 cmMakefile* mf = (*i)->GetMakefile();
2213 std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
2214 cmTargets &tgts = mf->GetTargets();
2215 for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
2217 cmTarget& cmtarget = l->second;
2219 // Same skipping logic here as in CreateXCodeTargets so that we do not
2220 // end up with (empty anyhow) ALL_BUILD and XCODE_DEPEND_HELPER source
2221 // groups:
2223 if(cmtarget.GetType() == cmTarget::GLOBAL_TARGET)
2225 continue;
2228 // add the soon to be generated Info.plist file as a source for a
2229 // MACOSX_BUNDLE file
2230 if(cmtarget.GetPropertyAsBool("MACOSX_BUNDLE"))
2232 std::string plist = this->ComputeInfoPListLocation(cmtarget);
2233 cmSourceFile* sf = mf->GetOrCreateSource(plist.c_str(), true);
2234 cmtarget.AddSourceFile(sf);
2237 std::vector<cmSourceFile*> classes = cmtarget.GetSourceFiles();
2239 for(std::vector<cmSourceFile*>::const_iterator s = classes.begin();
2240 s != classes.end(); s++)
2242 cmSourceFile* sf = *s;
2243 // Add the file to the list of sources.
2244 std::string const& source = sf->GetFullPath();
2245 cmSourceGroup& sourceGroup =
2246 mf->FindSourceGroup(source.c_str(), sourceGroups);
2247 cmXCodeObject* pbxgroup =
2248 this->CreateOrGetPBXGroup(cmtarget, &sourceGroup);
2249 cmStdString key = GetGroupMapKey(cmtarget, sf);
2250 this->GroupMap[key] = pbxgroup;
2256 //----------------------------------------------------------------------------
2257 cmXCodeObject* cmGlobalXCodeGenerator
2258 ::CreateOrGetPBXGroup(cmTarget& cmtarget, cmSourceGroup* sg)
2260 cmStdString s = cmtarget.GetName();
2261 s += "/";
2262 s += sg->GetName();
2263 std::map<cmStdString, cmXCodeObject* >::iterator i =
2264 this->GroupNameMap.find(s);
2265 if(i != this->GroupNameMap.end())
2267 return i->second;
2269 i = this->TargetGroup.find(cmtarget.GetName());
2270 cmXCodeObject* tgroup = 0;
2271 if(i != this->TargetGroup.end())
2273 tgroup = i->second;
2275 else
2277 tgroup = this->CreateObject(cmXCodeObject::PBXGroup);
2278 this->TargetGroup[cmtarget.GetName()] = tgroup;
2279 cmXCodeObject* tgroupChildren =
2280 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2281 tgroup->AddAttribute("name", this->CreateString(cmtarget.GetName()));
2282 tgroup->AddAttribute("children", tgroupChildren);
2283 if(this->XcodeVersion == 15)
2285 tgroup->AddAttribute("refType", this->CreateString("4"));
2287 tgroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2288 this->SourcesGroupChildren->AddObject(tgroup);
2291 // If it's the default source group (empty name) then put the source file
2292 // directly in the tgroup...
2294 if (cmStdString(sg->GetName()) == "")
2296 this->GroupNameMap[s] = tgroup;
2297 return tgroup;
2300 cmXCodeObject* tgroupChildren = tgroup->GetObject("children");
2301 cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
2302 cmXCodeObject* groupChildren =
2303 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2304 group->AddAttribute("name", this->CreateString(sg->GetName()));
2305 group->AddAttribute("children", groupChildren);
2306 if(this->XcodeVersion == 15)
2308 group->AddAttribute("refType", this->CreateString("4"));
2310 group->AddAttribute("sourceTree", this->CreateString("<group>"));
2311 tgroupChildren->AddObject(group);
2312 this->GroupNameMap[s] = group;
2313 return group;
2316 //----------------------------------------------------------------------------
2317 void cmGlobalXCodeGenerator
2318 ::CreateXCodeObjects(cmLocalGenerator* root,
2319 std::vector<cmLocalGenerator*>&
2320 generators)
2322 this->ClearXCodeObjects();
2323 this->RootObject = 0;
2324 this->SourcesGroupChildren = 0;
2325 this->ResourcesGroupChildren = 0;
2326 this->MainGroupChildren = 0;
2327 cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2328 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2329 cmXCodeObject* developBuildStyle =
2330 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2331 cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2332 if(this->XcodeVersion == 15)
2334 developBuildStyle->AddAttribute("name",
2335 this->CreateString("Development"));
2336 developBuildStyle->AddAttribute("buildSettings", group);
2337 listObjs->AddObject(developBuildStyle);
2338 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2339 group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("YES"));
2340 cmXCodeObject* deployBuildStyle =
2341 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2342 deployBuildStyle->AddAttribute("name", this->CreateString("Deployment"));
2343 deployBuildStyle->AddAttribute("buildSettings", group);
2344 listObjs->AddObject(deployBuildStyle);
2346 else
2348 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2350 cmXCodeObject* buildStyle =
2351 this->CreateObject(cmXCodeObject::PBXBuildStyle);
2352 const char* name = this->CurrentConfigurationTypes[i].c_str();
2353 buildStyle->AddAttribute("name", this->CreateString(name));
2354 buildStyle->SetComment(name);
2355 cmXCodeObject* sgroup =
2356 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2357 sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
2358 buildStyle->AddAttribute("buildSettings", sgroup);
2359 listObjs->AddObject(buildStyle);
2363 cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2364 this->MainGroupChildren =
2365 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2366 mainGroup->AddAttribute("children", this->MainGroupChildren);
2367 if(this->XcodeVersion == 15)
2369 mainGroup->AddAttribute("refType", this->CreateString("4"));
2371 mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2373 cmXCodeObject* sourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2374 this->SourcesGroupChildren =
2375 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2376 sourcesGroup->AddAttribute("name", this->CreateString("Sources"));
2377 sourcesGroup->AddAttribute("children", this->SourcesGroupChildren);
2378 if(this->XcodeVersion == 15)
2380 sourcesGroup->AddAttribute("refType", this->CreateString("4"));
2382 sourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2383 this->MainGroupChildren->AddObject(sourcesGroup);
2385 cmXCodeObject* resourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2386 this->ResourcesGroupChildren =
2387 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2388 resourcesGroup->AddAttribute("name", this->CreateString("Resources"));
2389 resourcesGroup->AddAttribute("children", this->ResourcesGroupChildren);
2390 if(this->XcodeVersion == 15)
2392 resourcesGroup->AddAttribute("refType", this->CreateString("4"));
2394 resourcesGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2395 this->MainGroupChildren->AddObject(resourcesGroup);
2397 // now create the cmake groups
2398 this->CreateGroups(root, generators);
2400 cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
2401 productGroup->AddAttribute("name", this->CreateString("Products"));
2402 if(this->XcodeVersion == 15)
2404 productGroup->AddAttribute("refType", this->CreateString("4"));
2406 productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
2407 cmXCodeObject* productGroupChildren =
2408 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2409 productGroup->AddAttribute("children", productGroupChildren);
2410 this->MainGroupChildren->AddObject(productGroup);
2413 this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
2414 this->RootObject->SetComment("Project object");
2415 group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2416 this->RootObject->AddAttribute("mainGroup",
2417 this->CreateObjectReference(mainGroup));
2418 this->RootObject->AddAttribute("buildSettings", group);
2419 this->RootObject->AddAttribute("buildStyles", listObjs);
2420 this->RootObject->AddAttribute("hasScannedForEncodings",
2421 this->CreateString("0"));
2422 // Point Xcode at the top of the source tree.
2424 std::string proot = root->GetMakefile()->GetCurrentDirectory();
2425 proot = this->ConvertToRelativeForXCode(proot.c_str());
2426 this->RootObject->AddAttribute("projectRoot",
2427 this->CreateString(proot.c_str()));
2429 cmXCodeObject* configlist =
2430 this->CreateObject(cmXCodeObject::XCConfigurationList);
2431 cmXCodeObject* buildConfigurations =
2432 this->CreateObject(cmXCodeObject::OBJECT_LIST);
2433 std::vector<cmXCodeObject*> configs;
2434 if(this->XcodeVersion == 15)
2436 cmXCodeObject* configDebug =
2437 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2438 configDebug->AddAttribute("name", this->CreateString("Debug"));
2439 configs.push_back(configDebug);
2440 cmXCodeObject* configRelease =
2441 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2442 configRelease->AddAttribute("name", this->CreateString("Release"));
2443 configs.push_back(configRelease);
2445 else
2447 for(unsigned int i = 0; i < this->CurrentConfigurationTypes.size(); ++i)
2449 const char* name = this->CurrentConfigurationTypes[i].c_str();
2450 cmXCodeObject* config =
2451 this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2452 config->AddAttribute("name", this->CreateString(name));
2453 configs.push_back(config);
2456 for(std::vector<cmXCodeObject*>::iterator c = configs.begin();
2457 c != configs.end(); ++c)
2459 buildConfigurations->AddObject(*c);
2461 configlist->AddAttribute("buildConfigurations", buildConfigurations);
2463 std::string comment = "Build configuration list for PBXProject ";
2464 comment += " \"";
2465 comment += this->CurrentProject;
2466 comment += "\"";
2467 configlist->SetComment(comment.c_str());
2468 configlist->AddAttribute("defaultConfigurationIsVisible",
2469 this->CreateString("0"));
2470 configlist->AddAttribute("defaultConfigurationName",
2471 this->CreateString("Debug"));
2472 cmXCodeObject* buildSettings =
2473 this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2474 const char* osxArch =
2475 this->CurrentMakefile->GetDefinition("CMAKE_OSX_ARCHITECTURES");
2476 const char* sysroot =
2477 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
2478 const char* sysrootDefault =
2479 this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT_DEFAULT");
2480 if(osxArch && sysroot)
2482 bool flagsUsed = false;
2483 // recompute this as it may have been changed since enable language
2484 this->Architectures.clear();
2485 cmSystemTools::ExpandListArgument(std::string(osxArch),
2486 this->Architectures);
2487 bool addArchFlag = true;
2488 if(this->Architectures.size() == 1)
2490 const char* archOrig =
2491 this->
2492 CurrentMakefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES_DEFAULT");
2493 if(this->Architectures[0] == archOrig)
2495 addArchFlag = false;
2498 if(addArchFlag)
2500 flagsUsed = true;
2501 buildSettings->AddAttribute("SDKROOT",
2502 this->CreateString(sysroot));
2503 std::string archString;
2504 for( std::vector<std::string>::iterator i =
2505 this->Architectures.begin();
2506 i != this->Architectures.end(); ++i)
2508 archString += *i;
2509 archString += " ";
2511 buildSettings->AddAttribute("ARCHS",
2512 this->CreateString(archString.c_str()));
2514 if(!flagsUsed && sysrootDefault &&
2515 strcmp(sysroot, sysrootDefault) != 0)
2517 buildSettings->AddAttribute("SDKROOT",
2518 this->CreateString(sysroot));
2521 for( std::vector<cmXCodeObject*>::iterator i = configs.begin();
2522 i != configs.end(); ++i)
2524 (*i)->AddAttribute("buildSettings", buildSettings);
2526 this->RootObject->AddAttribute("buildConfigurationList",
2527 this->CreateObjectReference(configlist));
2529 std::vector<cmXCodeObject*> targets;
2530 for(std::vector<cmLocalGenerator*>::iterator i = generators.begin();
2531 i != generators.end(); ++i)
2533 if(!this->IsExcluded(root, *i))
2535 this->CreateXCodeTargets(*i, targets);
2538 // loop over all targets and add link and depend info
2539 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2540 i != targets.end(); ++i)
2542 cmXCodeObject* t = *i;
2543 this->AddDependAndLinkInformation(t);
2545 // now create xcode depend hack makefile
2546 this->CreateXCodeDependHackTarget(targets);
2547 // now add all targets to the root object
2548 cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2549 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2550 i != targets.end(); ++i)
2552 cmXCodeObject* t = *i;
2553 allTargets->AddObject(t);
2554 cmXCodeObject* productRef = t->GetObject("productReference");
2555 if(productRef)
2557 productGroupChildren->AddObject(productRef->GetObject());
2560 this->RootObject->AddAttribute("targets", allTargets);
2563 //----------------------------------------------------------------------------
2564 void
2565 cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
2566 std::vector<cmXCodeObject*>& targets)
2568 cmGeneratedFileStream
2569 makefileStream(this->CurrentXCodeHackMakefile.c_str());
2570 if(!makefileStream)
2572 cmSystemTools::Error("Could not create",
2573 this->CurrentXCodeHackMakefile.c_str());
2574 return;
2576 makefileStream.SetCopyIfDifferent(true);
2577 // one more pass for external depend information not handled
2578 // correctly by xcode
2579 makefileStream << "# DO NOT EDIT\n";
2580 makefileStream << "# This makefile makes sure all linkable targets are\n";
2581 makefileStream << "# up-to-date with anything they link to, avoiding a "
2582 "bug in XCode 1.5\n";
2583 for(std::vector<std::string>::const_iterator
2584 ct = this->CurrentConfigurationTypes.begin();
2585 ct != this->CurrentConfigurationTypes.end(); ++ct)
2587 if(this->XcodeVersion < 21 || ct->empty())
2589 makefileStream << "all: ";
2591 else
2593 makefileStream << "all." << *ct << ": ";
2595 const char* configName = 0;
2596 if(!ct->empty())
2598 configName = ct->c_str();
2600 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2601 i != targets.end(); ++i)
2603 cmXCodeObject* target = *i;
2604 cmTarget* t =target->GetTarget();
2605 if(t->GetType() == cmTarget::EXECUTABLE ||
2606 t->GetType() == cmTarget::SHARED_LIBRARY ||
2607 t->GetType() == cmTarget::MODULE_LIBRARY)
2609 std::string tfull = t->GetFullPath(configName);
2610 if(t->IsAppBundleOnApple())
2612 tfull += ".app/Contents/MacOS/";
2613 tfull += t->GetFullName(configName);
2615 makefileStream << "\\\n\t" <<
2616 this->ConvertToRelativeForMake(tfull.c_str());
2619 makefileStream << "\n\n";
2621 makefileStream
2622 << "# For each target create a dummy rule "
2623 "so the target does not have to exist\n";
2624 std::set<cmStdString> emitted;
2625 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2626 i != targets.end(); ++i)
2628 cmXCodeObject* target = *i;
2629 std::map<cmStdString, cmXCodeObject::StringVec> const& deplibs =
2630 target->GetDependLibraries();
2631 for(std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator ci
2632 = deplibs.begin(); ci != deplibs.end(); ++ci)
2634 for(cmXCodeObject::StringVec::const_iterator d = ci->second.begin();
2635 d != ci->second.end(); ++d)
2637 if(emitted.insert(*d).second)
2639 makefileStream <<
2640 this->ConvertToRelativeForMake(d->c_str()) << ":\n";
2645 makefileStream << "\n\n";
2647 // Write rules to help Xcode relink things at the right time.
2648 makefileStream <<
2649 "# Rules to remove targets that are older than anything to which they\n"
2650 "# link. This forces Xcode to relink the targets from scratch. It\n"
2651 "# does not seem to check these dependencies itself.\n";
2652 for(std::vector<std::string>::const_iterator
2653 ct = this->CurrentConfigurationTypes.begin();
2654 ct != this->CurrentConfigurationTypes.end(); ++ct)
2656 const char* configName = 0;
2657 if(!ct->empty())
2659 configName = ct->c_str();
2661 for(std::vector<cmXCodeObject*>::iterator i = targets.begin();
2662 i != targets.end(); ++i)
2664 cmXCodeObject* target = *i;
2665 cmTarget* t =target->GetTarget();
2666 if(t->GetType() == cmTarget::EXECUTABLE ||
2667 t->GetType() == cmTarget::SHARED_LIBRARY ||
2668 t->GetType() == cmTarget::MODULE_LIBRARY)
2670 // Create a rule for this target.
2671 std::string tfull = t->GetFullPath(configName);
2672 if(t->IsAppBundleOnApple())
2674 tfull += ".app/Contents/MacOS/";
2675 tfull += t->GetFullName(configName);
2677 makefileStream << this->ConvertToRelativeForMake(tfull.c_str())
2678 << ":";
2680 // List dependencies if any exist.
2681 std::map<cmStdString, cmXCodeObject::StringVec>::const_iterator
2682 x = target->GetDependLibraries().find(*ct);
2683 if(x != target->GetDependLibraries().end())
2685 std::vector<cmStdString> const& deplibs = x->second;
2686 for(std::vector<cmStdString>::const_iterator d = deplibs.begin();
2687 d != deplibs.end(); ++d)
2689 makefileStream << "\\\n\t" <<
2690 this->ConvertToRelativeForMake(d->c_str());
2693 // Write the action to remove the target if it is out of date.
2694 makefileStream << "\n";
2695 makefileStream << "\t/bin/rm -f "
2696 << this->ConvertToRelativeForMake(tfull.c_str())
2697 << "\n";
2698 // if building for more than one architecture
2699 // then remove those exectuables as well
2700 if(this->Architectures.size() > 1)
2702 std::string universal = t->GetDirectory();
2703 universal += "/";
2704 universal += this->CurrentMakefile->GetProjectName();
2705 universal += ".build/";
2706 universal += configName;
2707 universal += "/";
2708 universal += t->GetName();
2709 universal += ".build/Objects-normal/";
2710 for( std::vector<std::string>::iterator arch =
2711 this->Architectures.begin();
2712 arch != this->Architectures.end(); ++arch)
2714 std::string universalFile = universal;
2715 universalFile += *arch;
2716 universalFile += "/";
2717 universalFile += t->GetName();
2718 makefileStream << "\t/bin/rm -f "
2720 this->ConvertToRelativeForMake(universalFile.c_str())
2721 << "\n";
2724 makefileStream << "\n\n";
2730 //----------------------------------------------------------------------------
2731 void
2732 cmGlobalXCodeGenerator::OutputXCodeProject(cmLocalGenerator* root,
2733 std::vector<cmLocalGenerator*>&
2734 generators)
2736 if(generators.size() == 0)
2738 return;
2740 // Skip local generators that are excluded from this project.
2741 for(std::vector<cmLocalGenerator*>::iterator g = generators.begin();
2742 g != generators.end(); ++g)
2744 if(this->IsExcluded(root, *g))
2746 continue;
2750 this->CreateXCodeObjects(root,
2751 generators);
2752 std::string xcodeDir = root->GetMakefile()->GetStartOutputDirectory();
2753 xcodeDir += "/";
2754 xcodeDir += root->GetMakefile()->GetProjectName();
2755 xcodeDir += ".xcode";
2756 if(this->XcodeVersion > 20)
2758 xcodeDir += "proj";
2760 cmSystemTools::MakeDirectory(xcodeDir.c_str());
2761 std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
2762 cmGeneratedFileStream fout(xcodeProjFile.c_str());
2763 fout.SetCopyIfDifferent(true);
2764 if(!fout)
2766 return;
2768 this->WriteXCodePBXProj(fout, root, generators);
2769 this->ClearXCodeObjects();
2772 //----------------------------------------------------------------------------
2773 void
2774 cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
2775 cmLocalGenerator* ,
2776 std::vector<cmLocalGenerator*>& )
2778 fout << "// !$*UTF8*$!\n";
2779 fout << "{\n";
2780 cmXCodeObject::Indent(1, fout);
2781 fout << "archiveVersion = 1;\n";
2782 cmXCodeObject::Indent(1, fout);
2783 fout << "classes = {\n";
2784 cmXCodeObject::Indent(1, fout);
2785 fout << "};\n";
2786 cmXCodeObject::Indent(1, fout);
2787 fout << "objectVersion = 39;\n";
2788 cmXCodeObject::PrintList(this->XCodeObjects, fout);
2789 cmXCodeObject::Indent(1, fout);
2790 fout << "rootObject = " << this->RootObject->GetId() << ";\n";
2791 fout << "}\n";
2794 //----------------------------------------------------------------------------
2795 void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
2796 const
2798 entry.Name = this->GetName();
2799 entry.Brief = "Generate XCode project files.";
2800 entry.Full = "";
2803 //----------------------------------------------------------------------------
2804 std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(const char* p)
2806 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
2808 return cmSystemTools::ConvertToOutputPath(p);
2810 else
2812 std::string ret =
2813 this->CurrentLocalGenerator->
2814 ConvertToRelativePath(this->CurrentOutputDirectoryComponents, p);
2815 return cmSystemTools::ConvertToOutputPath(ret.c_str());
2819 //----------------------------------------------------------------------------
2820 std::string cmGlobalXCodeGenerator::ConvertToRelativeForXCode(const char* p)
2822 if ( !this->CurrentMakefile->IsOn("CMAKE_USE_RELATIVE_PATHS") )
2824 return cmSystemTools::ConvertToOutputPath(p);
2826 else
2828 std::string ret =
2829 this->CurrentLocalGenerator->
2830 ConvertToRelativePath(this->ProjectOutputDirectoryComponents, p);
2831 return cmSystemTools::ConvertToOutputPath(ret.c_str());
2835 //----------------------------------------------------------------------------
2836 std::string cmGlobalXCodeGenerator::XCodeEscapePath(const char* p)
2838 std::string ret = p;
2839 if(ret.find(' ') != ret.npos)
2841 std::string t = ret;
2842 ret = "\"";
2843 ret += t;
2844 ret += "\"";
2846 return ret;
2849 //----------------------------------------------------------------------------
2850 void cmGlobalXCodeGenerator::
2851 GetTargetObjectFileDirectories(cmTarget* target,
2852 std::vector<std::string>&
2853 dirs)
2855 std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory();
2856 dir += "/";
2857 dir += this->CurrentMakefile->GetProjectName();
2858 dir += ".build/";
2859 dir += this->GetCMakeCFGInitDirectory();
2860 dir += "/";
2861 if(target->GetType() != cmTarget::EXECUTABLE)
2863 dir += "lib";
2865 dir += target->GetName();
2866 if(target->GetType() == cmTarget::STATIC_LIBRARY)
2868 dir += ".a";
2870 if(target->GetType() == cmTarget::SHARED_LIBRARY)
2872 dir += ".dylib";
2874 if(target->GetType() == cmTarget::MODULE_LIBRARY)
2876 dir += ".so";
2878 dir += ".build/Objects-normal/";
2879 std::string dirsave = dir;
2880 if(this->Architectures.size())
2882 for(std::vector<std::string>::iterator i = this->Architectures.begin();
2883 i != this->Architectures.end(); ++i)
2885 dir += *i;
2886 dirs.push_back(dir);
2887 dir = dirsave;
2890 else
2892 dirs.push_back(dir);
2896 //----------------------------------------------------------------------------
2897 void
2898 cmGlobalXCodeGenerator
2899 ::AppendDirectoryForConfig(const char* prefix,
2900 const char* config,
2901 const char* suffix,
2902 std::string& dir)
2904 if(this->XcodeVersion > 20)
2906 if(config)
2908 dir += prefix;
2909 dir += config;
2910 dir += suffix;
2915 //----------------------------------------------------------------------------
2916 std::string cmGlobalXCodeGenerator::LookupFlags(const char* varNamePrefix,
2917 const char* varNameLang,
2918 const char* varNameSuffix,
2919 const char* default_flags)
2921 if(varNameLang)
2923 std::string varName = varNamePrefix;
2924 varName += varNameLang;
2925 varName += varNameSuffix;
2926 if(const char* varValue =
2927 this->CurrentMakefile->GetDefinition(varName.c_str()))
2929 if(*varValue)
2931 return varValue;
2935 return default_flags;
2938 //----------------------------------------------------------------------------
2939 void cmGlobalXCodeGenerator::AppendDefines(std::string& defs,
2940 const char* defines_list,
2941 bool dflag)
2943 // Skip this if there are no definitions.
2944 if(!defines_list)
2946 return;
2949 // Expand the list of definitions.
2950 std::vector<std::string> defines;
2951 cmSystemTools::ExpandListArgument(defines_list, defines);
2953 // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
2954 // We escape everything as follows:
2955 // - Place each definition in single quotes ''
2956 // - Escape a single quote as \\'
2957 // - Escape a backslash as \\\\ since it itself is an escape
2958 // Note that in the code below we need one more level of escapes for
2959 // C string syntax in this source file.
2960 const char* sep = defs.empty()? "" : " ";
2961 for(std::vector<std::string>::const_iterator di = defines.begin();
2962 di != defines.end(); ++di)
2964 // Separate from previous definition.
2965 defs += sep;
2966 sep = " ";
2968 // Open single quote.
2969 defs += "'";
2971 // Add -D flag if requested.
2972 if(dflag)
2974 defs += "-D";
2977 // Escaped definition string.
2978 for(const char* c = di->c_str(); *c; ++c)
2980 if(*c == '\'')
2982 defs += "\\\\'";
2984 else if(*c == '\\')
2986 defs += "\\\\\\\\";
2988 else
2990 defs += *c;
2994 // Close single quote.
2995 defs += "'";
2999 //----------------------------------------------------------------------------
3000 std::string
3001 cmGlobalXCodeGenerator::ComputeInfoPListLocation(cmTarget& target)
3003 std::string plist = target.GetMakefile()->GetCurrentOutputDirectory();
3004 plist += cmake::GetCMakeFilesDirectory();
3005 plist += "/";
3006 plist += target.GetName();
3007 plist += ".dir/Info.plist";
3008 return plist;