Imported Upstream version 3.18.2
[platform/upstream/cmake.git] / Source / cmGlobalXCodeGenerator.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmGlobalXCodeGenerator.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cstdio>
8 #include <cstring>
9 #include <iomanip>
10 #include <sstream>
11 #include <utility>
12
13 #include <cm/memory>
14 #include <cmext/algorithm>
15 #include <cmext/string_view>
16
17 #include "cmsys/RegularExpression.hxx"
18
19 #include "cmComputeLinkInformation.h"
20 #include "cmCustomCommand.h"
21 #include "cmCustomCommandGenerator.h"
22 #include "cmCustomCommandLines.h"
23 #include "cmDocumentationEntry.h"
24 #include "cmGeneratedFileStream.h"
25 #include "cmGeneratorExpression.h"
26 #include "cmGeneratorTarget.h"
27 #include "cmGlobalGeneratorFactory.h"
28 #include "cmLocalGenerator.h"
29 #include "cmLocalXCodeGenerator.h"
30 #include "cmMakefile.h"
31 #include "cmMessageType.h"
32 #include "cmOutputConverter.h"
33 #include "cmSourceFile.h"
34 #include "cmSourceGroup.h"
35 #include "cmState.h"
36 #include "cmStateTypes.h"
37 #include "cmStringAlgorithms.h"
38 #include "cmSystemTools.h"
39 #include "cmTarget.h"
40 #include "cmXCode21Object.h"
41 #include "cmXCodeObject.h"
42 #include "cmXCodeScheme.h"
43 #include "cmake.h"
44
45 struct cmLinkImplementation;
46
47 #if !defined(CMAKE_BOOTSTRAP) && defined(__APPLE__)
48 #  define HAVE_APPLICATION_SERVICES
49 #  include <ApplicationServices/ApplicationServices.h>
50 #endif
51
52 #if !defined(CMAKE_BOOTSTRAP)
53 #  include "cmXMLParser.h"
54
55 // parse the xml file storing the installed version of Xcode on
56 // the machine
57 class cmXcodeVersionParser : public cmXMLParser
58 {
59 public:
60   cmXcodeVersionParser()
61     : Version("1.5")
62   {
63   }
64   void StartElement(const std::string&, const char**) override
65   {
66     this->Data = "";
67   }
68   void EndElement(const std::string& name) override
69   {
70     if (name == "key") {
71       this->Key = this->Data;
72     } else if (name == "string") {
73       if (this->Key == "CFBundleShortVersionString") {
74         this->Version = this->Data;
75       }
76     }
77   }
78   void CharacterDataHandler(const char* data, int length) override
79   {
80     this->Data.append(data, length);
81   }
82   std::string Version;
83   std::string Key;
84   std::string Data;
85 };
86 #endif
87
88 // Builds either an object list or a space-separated string from the
89 // given inputs.
90 class cmGlobalXCodeGenerator::BuildObjectListOrString
91 {
92   cmGlobalXCodeGenerator* Generator;
93   cmXCodeObject* Group;
94   bool Empty;
95   std::string String;
96
97 public:
98   BuildObjectListOrString(cmGlobalXCodeGenerator* gen, bool buildObjectList)
99     : Generator(gen)
100     , Group(nullptr)
101     , Empty(true)
102   {
103     if (buildObjectList) {
104       this->Group = this->Generator->CreateObject(cmXCodeObject::OBJECT_LIST);
105     }
106   }
107
108   bool IsEmpty() const { return this->Empty; }
109
110   void Add(const std::string& newString)
111   {
112     this->Empty = false;
113
114     if (this->Group) {
115       this->Group->AddObject(this->Generator->CreateString(newString));
116     } else {
117       this->String += newString;
118       this->String += ' ';
119     }
120   }
121
122   const std::string& GetString() const { return this->String; }
123
124   cmXCodeObject* CreateList()
125   {
126     if (this->Group) {
127       return this->Group;
128     }
129     return this->Generator->CreateString(this->String);
130   }
131 };
132
133 class cmGlobalXCodeGenerator::Factory : public cmGlobalGeneratorFactory
134 {
135 public:
136   std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
137     const std::string& name, cmake* cm) const override;
138
139   void GetDocumentation(cmDocumentationEntry& entry) const override
140   {
141     cmGlobalXCodeGenerator::GetDocumentation(entry);
142   }
143
144   std::vector<std::string> GetGeneratorNames() const override
145   {
146     std::vector<std::string> names;
147     names.push_back(cmGlobalXCodeGenerator::GetActualName());
148     return names;
149   }
150
151   std::vector<std::string> GetGeneratorNamesWithPlatform() const override
152   {
153     return std::vector<std::string>();
154   }
155
156   bool SupportsToolset() const override { return true; }
157   bool SupportsPlatform() const override { return false; }
158
159   std::vector<std::string> GetKnownPlatforms() const override
160   {
161     return std::vector<std::string>();
162   }
163
164   std::string GetDefaultPlatformName() const override { return std::string(); }
165 };
166
167 cmGlobalXCodeGenerator::cmGlobalXCodeGenerator(
168   cmake* cm, std::string const& version_string, unsigned int version_number)
169   : cmGlobalGenerator(cm)
170 {
171   this->VersionString = version_string;
172   this->XcodeVersion = version_number;
173
174   this->RootObject = nullptr;
175   this->MainGroupChildren = nullptr;
176   this->CurrentMakefile = nullptr;
177   this->CurrentLocalGenerator = nullptr;
178   this->XcodeBuildCommandInitialized = false;
179
180   this->ObjectDirArchDefault = "$(CURRENT_ARCH)";
181   this->ObjectDirArch = this->ObjectDirArchDefault;
182
183   cm->GetState()->SetIsGeneratorMultiConfig(true);
184 }
185
186 std::unique_ptr<cmGlobalGeneratorFactory> cmGlobalXCodeGenerator::NewFactory()
187 {
188   return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
189 }
190
191 std::unique_ptr<cmGlobalGenerator>
192 cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(const std::string& name,
193                                                        cmake* cm) const
194 {
195   if (name != GetActualName()) {
196     return std::unique_ptr<cmGlobalGenerator>();
197   }
198 #if !defined(CMAKE_BOOTSTRAP)
199   cmXcodeVersionParser parser;
200   std::string versionFile;
201   {
202     std::string out;
203     bool commandResult = cmSystemTools::RunSingleCommand(
204       "xcode-select --print-path", &out, nullptr, nullptr, nullptr,
205       cmSystemTools::OUTPUT_NONE);
206     if (commandResult) {
207       std::string::size_type pos = out.find(".app/");
208       if (pos != std::string::npos) {
209         versionFile = out.substr(0, pos + 5) + "Contents/version.plist";
210       }
211     }
212   }
213   if (!versionFile.empty() && cmSystemTools::FileExists(versionFile)) {
214     parser.ParseFile(versionFile.c_str());
215   } else if (cmSystemTools::FileExists(
216                "/Applications/Xcode.app/Contents/version.plist")) {
217     parser.ParseFile("/Applications/Xcode.app/Contents/version.plist");
218   } else {
219     parser.ParseFile(
220       "/Developer/Applications/Xcode.app/Contents/version.plist");
221   }
222   std::string const& version_string = parser.Version;
223
224   // Compute an integer form of the version number.
225   unsigned int v[2] = { 0, 0 };
226   sscanf(version_string.c_str(), "%u.%u", &v[0], &v[1]);
227   unsigned int version_number = 10 * v[0] + v[1];
228
229   if (version_number < 50) {
230     cm->IssueMessage(MessageType::FATAL_ERROR,
231                      "Xcode " + version_string + " not supported.");
232     return std::unique_ptr<cmGlobalGenerator>();
233   }
234
235   return std::unique_ptr<cmGlobalGenerator>(
236     cm::make_unique<cmGlobalXCodeGenerator>(cm, version_string,
237                                             version_number));
238 #else
239   std::cerr << "CMake should be built with cmake to use Xcode, "
240                "default to Xcode 1.5\n";
241   return std::unique_ptr<cmGlobalGenerator>(
242     cm::make_unique<cmGlobalXCodeGenerator>(cm));
243 #endif
244 }
245
246 bool cmGlobalXCodeGenerator::FindMakeProgram(cmMakefile* mf)
247 {
248   // The Xcode generator knows how to lookup its build tool
249   // directly instead of needing a helper module to do it, so we
250   // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
251   if (cmIsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
252     mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetXcodeBuildCommand());
253   }
254   return true;
255 }
256
257 std::string const& cmGlobalXCodeGenerator::GetXcodeBuildCommand()
258 {
259   if (!this->XcodeBuildCommandInitialized) {
260     this->XcodeBuildCommandInitialized = true;
261     this->XcodeBuildCommand = this->FindXcodeBuildCommand();
262   }
263   return this->XcodeBuildCommand;
264 }
265
266 std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand()
267 {
268   std::string makeProgram = cmSystemTools::FindProgram("xcodebuild");
269   if (makeProgram.empty()) {
270     makeProgram = "xcodebuild";
271   }
272   return makeProgram;
273 }
274
275 bool cmGlobalXCodeGenerator::SetSystemName(std::string const& s,
276                                            cmMakefile* mf)
277 {
278   this->SystemName = s;
279   return this->cmGlobalGenerator::SetSystemName(s, mf);
280 }
281
282 bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
283                                                  bool build, cmMakefile* mf)
284 {
285   if (ts.find_first_of(",=") != std::string::npos) {
286     std::ostringstream e;
287     /* clang-format off */
288     e <<
289       "Generator\n"
290       "  " << this->GetName() << "\n"
291       "does not recognize the toolset\n"
292       "  " << ts << "\n"
293       "that was specified.";
294     /* clang-format on */
295     mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
296     return false;
297   }
298   this->GeneratorToolset = ts;
299   if (build) {
300     return true;
301   }
302   if (!this->GeneratorToolset.empty()) {
303     mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET", this->GeneratorToolset);
304   }
305   return true;
306 }
307
308 void cmGlobalXCodeGenerator::EnableLanguage(
309   std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
310 {
311   mf->AddDefinition("XCODE", "1");
312   mf->AddDefinition("XCODE_VERSION", this->VersionString);
313   if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
314     mf->AddCacheDefinition(
315       "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo",
316       "Semicolon separated list of supported configuration types, "
317       "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
318       "anything else will be ignored.",
319       cmStateEnums::STRING);
320   }
321   mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1");
322   this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
323   this->ComputeArchitectures(mf);
324 }
325
326 bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
327                                   const std::string& projectName, bool dryRun)
328 {
329   bool ret = false;
330
331 #ifdef HAVE_APPLICATION_SERVICES
332   std::string url = bindir + "/" + projectName + ".xcodeproj";
333
334   if (dryRun) {
335     return cmSystemTools::FileExists(url, false);
336   }
337
338   CFStringRef cfStr = CFStringCreateWithCString(
339     kCFAllocatorDefault, url.c_str(), kCFStringEncodingUTF8);
340   if (cfStr) {
341     CFURLRef cfUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfStr,
342                                                    kCFURLPOSIXPathStyle, true);
343     if (cfUrl) {
344       OSStatus err = LSOpenCFURLRef(cfUrl, nullptr);
345       ret = err == noErr;
346       CFRelease(cfUrl);
347     }
348     CFRelease(cfStr);
349   }
350 #endif
351
352   return ret;
353 }
354
355 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
356 cmGlobalXCodeGenerator::GenerateBuildCommand(
357   const std::string& makeProgram, const std::string& projectName,
358   const std::string& /*projectDir*/,
359   std::vector<std::string> const& targetNames, const std::string& config,
360   bool /*fast*/, int jobs, bool /*verbose*/,
361   std::vector<std::string> const& makeOptions)
362 {
363   GeneratedMakeCommand makeCommand;
364   // now build the test
365   makeCommand.Add(
366     this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
367
368   if (!projectName.empty()) {
369     makeCommand.Add("-project");
370     std::string projectArg = cmStrCat(projectName, ".xcodeproj");
371     makeCommand.Add(projectArg);
372   }
373   if (cm::contains(targetNames, "clean")) {
374     makeCommand.Add("clean");
375     makeCommand.Add("-target", "ALL_BUILD");
376   } else {
377     makeCommand.Add("build");
378     if (targetNames.empty() ||
379         ((targetNames.size() == 1) && targetNames.front().empty())) {
380       makeCommand.Add("-target", "ALL_BUILD");
381     } else {
382       for (const auto& tname : targetNames) {
383         if (!tname.empty()) {
384           makeCommand.Add("-target", tname);
385         }
386       }
387     }
388   }
389
390   makeCommand.Add("-configuration", (config.empty() ? "Debug" : config));
391
392   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
393     makeCommand.Add("-jobs");
394     if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
395       makeCommand.Add(std::to_string(jobs));
396     }
397   }
398
399   if (this->XcodeVersion >= 70) {
400     makeCommand.Add("-hideShellScriptEnvironment");
401   }
402   makeCommand.Add(makeOptions.begin(), makeOptions.end());
403   return { std::move(makeCommand) };
404 }
405
406 //! Create a local generator appropriate to this Global Generator
407 std::unique_ptr<cmLocalGenerator> cmGlobalXCodeGenerator::CreateLocalGenerator(
408   cmMakefile* mf)
409 {
410   return std::unique_ptr<cmLocalGenerator>(
411     cm::make_unique<cmLocalXCodeGenerator>(this, mf));
412 }
413
414 void cmGlobalXCodeGenerator::AddExtraIDETargets()
415 {
416   // make sure extra targets are added before calling
417   // the parent generate which will call trace depends
418   for (auto keyVal : this->ProjectMap) {
419     cmLocalGenerator* root = keyVal.second[0];
420     this->SetGenerationRoot(root);
421     // add ALL_BUILD, INSTALL, etc
422     this->AddExtraTargets(root, keyVal.second);
423   }
424 }
425
426 void cmGlobalXCodeGenerator::ComputeTargetOrder()
427 {
428   size_t index = 0;
429   auto const& lgens = this->GetLocalGenerators();
430   for (auto const& lgen : lgens) {
431     const auto& targets = lgen->GetGeneratorTargets();
432     for (const auto& gt : targets) {
433       this->ComputeTargetOrder(gt.get(), index);
434     }
435   }
436   assert(index == this->TargetOrderIndex.size());
437 }
438
439 void cmGlobalXCodeGenerator::ComputeTargetOrder(cmGeneratorTarget const* gt,
440                                                 size_t& index)
441 {
442   std::map<cmGeneratorTarget const*, size_t>::value_type value(gt, 0);
443   auto insertion = this->TargetOrderIndex.insert(value);
444   if (!insertion.second) {
445     return;
446   }
447   auto entry = insertion.first;
448
449   auto& deps = this->GetTargetDirectDepends(gt);
450   for (auto& d : deps) {
451     this->ComputeTargetOrder(d, index);
452   }
453
454   entry->second = index++;
455 }
456
457 void cmGlobalXCodeGenerator::Generate()
458 {
459   this->cmGlobalGenerator::Generate();
460   if (cmSystemTools::GetErrorOccuredFlag()) {
461     return;
462   }
463
464   this->ComputeTargetOrder();
465
466   for (auto keyVal : this->ProjectMap) {
467     cmLocalGenerator* root = keyVal.second[0];
468
469     bool generateTopLevelProjectOnly =
470       root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY");
471
472     if (generateTopLevelProjectOnly) {
473       cmStateSnapshot snp = root->GetStateSnapshot();
474       if (snp.GetBuildsystemDirectoryParent().IsValid()) {
475         continue;
476       }
477     }
478
479     this->SetGenerationRoot(root);
480     // now create the project
481     this->OutputXCodeProject(root, keyVal.second);
482   }
483 }
484
485 void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root)
486 {
487   this->CurrentProject = root->GetProjectName();
488   this->SetCurrentLocalGenerator(root);
489   cmSystemTools::SplitPath(
490     this->CurrentLocalGenerator->GetCurrentSourceDirectory(),
491     this->ProjectSourceDirectoryComponents);
492   cmSystemTools::SplitPath(
493     this->CurrentLocalGenerator->GetCurrentBinaryDirectory(),
494     this->ProjectOutputDirectoryComponents);
495
496   this->CurrentXCodeHackMakefile =
497     cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeScripts");
498   cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile);
499   this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make";
500 }
501
502 std::string cmGlobalXCodeGenerator::PostBuildMakeTarget(
503   std::string const& tName, std::string const& configName)
504 {
505   std::string target = tName;
506   std::replace(target.begin(), target.end(), ' ', '_');
507   std::string out = cmStrCat("PostBuild.", target, '.', configName);
508   return out;
509 }
510
511 #define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK"
512 #define OBJECT_LIBRARY_ARTIFACT_DIR std::string()
513
514 void cmGlobalXCodeGenerator::AddExtraTargets(
515   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens)
516 {
517   const char* no_working_directory = nullptr;
518   std::vector<std::string> no_byproducts;
519   std::vector<std::string> no_depends;
520
521   // Add ALL_BUILD
522   cmTarget* allbuild = root->AddUtilityCommand(
523     "ALL_BUILD", true, no_working_directory, no_byproducts, no_depends,
524     cmMakeSingleCommandLine({ "echo", "Build all projects" }));
525
526   root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(allbuild, root));
527
528   // Add XCODE depend helper
529   std::string dir = root->GetCurrentBinaryDirectory();
530   cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
531     { "make", "-C", dir, "-f", this->CurrentXCodeHackMakefile,
532       "OBJDIR=$(OBJDIR)", /* placeholder, see below */ "" });
533
534   // Add ZERO_CHECK
535   bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
536   bool generateTopLevelProjectOnly =
537     root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY");
538   bool isTopLevel =
539     !root->GetStateSnapshot().GetBuildsystemDirectoryParent().IsValid();
540   bool isGenerateProject = isTopLevel || !generateTopLevelProjectOnly;
541   if (regenerate && isGenerateProject) {
542     this->CreateReRunCMakeFile(root, gens);
543     std::string file =
544       this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile);
545     cmSystemTools::ReplaceString(file, "\\ ", " ");
546     cmTarget* check =
547       root->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, true,
548                               no_working_directory, no_byproducts, no_depends,
549                               cmMakeSingleCommandLine({ "make", "-f", file }));
550
551     root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(check, root));
552   }
553
554   // now make the allbuild depend on all the non-utility targets
555   // in the project
556   for (auto& gen : gens) {
557     for (const auto& target : gen->GetGeneratorTargets()) {
558       if (target->GetType() == cmStateEnums::GLOBAL_TARGET) {
559         continue;
560       }
561
562       if (regenerate &&
563           (target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET)) {
564         target->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false);
565       }
566
567       // make all exe, shared libs and modules
568       // run the depend check makefile as a post build rule
569       // this will make sure that when the next target is built
570       // things are up-to-date
571       if (isGenerateProject &&
572           target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
573         commandLines.front().back() = // fill placeholder
574           this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)");
575         gen->AddCustomCommandToTarget(
576           target->GetName(), no_byproducts, no_depends, commandLines,
577           cmCustomCommandType::POST_BUILD, "Depend check for xcode",
578           dir.c_str(), true, false, "", "", false,
579           cmObjectLibraryCommands::Accept);
580       }
581
582       if (!this->IsExcluded(gens[0], target.get())) {
583         allbuild->AddUtility(target->GetName(), false);
584       }
585     }
586   }
587 }
588
589 void cmGlobalXCodeGenerator::CreateReRunCMakeFile(
590   cmLocalGenerator* root, std::vector<cmLocalGenerator*> const& gens)
591 {
592   std::vector<std::string> lfiles;
593   for (auto gen : gens) {
594     cm::append(lfiles, gen->GetMakefile()->GetListFiles());
595   }
596
597   // sort the array
598   std::sort(lfiles.begin(), lfiles.end());
599   lfiles.erase(std::unique(lfiles.begin(), lfiles.end()), lfiles.end());
600
601   cmake* cm = this->GetCMakeInstance();
602   if (cm->DoWriteGlobVerifyTarget()) {
603     lfiles.emplace_back(cm->GetGlobVerifyStamp());
604   }
605
606   this->CurrentReRunCMakeMakefile =
607     cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeScripts");
608   cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile);
609   this->CurrentReRunCMakeMakefile += "/ReRunCMake.make";
610   cmGeneratedFileStream makefileStream(this->CurrentReRunCMakeMakefile);
611   makefileStream.SetCopyIfDifferent(true);
612   makefileStream << "# Generated by CMake, DO NOT EDIT\n\n";
613
614   makefileStream << "TARGETS:= \n";
615   makefileStream << "empty:= \n";
616   makefileStream << "space:= $(empty) $(empty)\n";
617   makefileStream << "spaceplus:= $(empty)\\ $(empty)\n\n";
618
619   for (const auto& lfile : lfiles) {
620     makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard "
621                    << this->ConvertToRelativeForMake(lfile) << "))\n";
622   }
623   makefileStream << "\n";
624
625   std::string checkCache =
626     cmStrCat(root->GetBinaryDirectory(), "/CMakeFiles/cmake.check_cache");
627
628   if (cm->DoWriteGlobVerifyTarget()) {
629     makefileStream << ".NOTPARALLEL:\n\n";
630     makefileStream << ".PHONY: all VERIFY_GLOBS\n\n";
631     makefileStream << "all: VERIFY_GLOBS "
632                    << this->ConvertToRelativeForMake(checkCache) << "\n\n";
633     makefileStream << "VERIFY_GLOBS:\n";
634     makefileStream << "\t"
635                    << this->ConvertToRelativeForMake(
636                         cmSystemTools::GetCMakeCommand())
637                    << " -P "
638                    << this->ConvertToRelativeForMake(cm->GetGlobVerifyScript())
639                    << "\n\n";
640   }
641
642   makefileStream << this->ConvertToRelativeForMake(checkCache)
643                  << ": $(TARGETS)\n";
644   makefileStream << "\t"
645                  << this->ConvertToRelativeForMake(
646                       cmSystemTools::GetCMakeCommand())
647                  << " -H"
648                  << this->ConvertToRelativeForMake(root->GetSourceDirectory())
649                  << " -B"
650                  << this->ConvertToRelativeForMake(root->GetBinaryDirectory())
651                  << "\n";
652 }
653
654 static bool objectIdLessThan(const std::unique_ptr<cmXCodeObject>& l,
655                              const std::unique_ptr<cmXCodeObject>& r)
656 {
657   return l->GetId() < r->GetId();
658 }
659
660 void cmGlobalXCodeGenerator::SortXCodeObjects()
661 {
662   std::sort(this->XCodeObjects.begin(), this->XCodeObjects.end(),
663             objectIdLessThan);
664 }
665
666 void cmGlobalXCodeGenerator::ClearXCodeObjects()
667 {
668   this->TargetDoneSet.clear();
669   this->XCodeObjects.clear();
670   this->XCodeObjectIDs.clear();
671   this->XCodeObjectMap.clear();
672   this->GroupMap.clear();
673   this->GroupNameMap.clear();
674   this->TargetGroup.clear();
675   this->FileRefs.clear();
676 }
677
678 void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj)
679 {
680   if (obj->GetType() == cmXCodeObject::OBJECT) {
681     const std::string& id = obj->GetId();
682
683     // If this is a duplicate id, it's an error:
684     //
685     if (this->XCodeObjectIDs.count(id)) {
686       cmSystemTools::Error(
687         "Xcode generator: duplicate object ids not allowed");
688     }
689
690     this->XCodeObjectIDs.insert(id);
691   }
692
693   this->XCodeObjects.push_back(std::move(obj));
694 }
695
696 cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(
697   cmXCodeObject::PBXType ptype)
698 {
699   auto obj = cm::make_unique<cmXCode21Object>(ptype, cmXCodeObject::OBJECT);
700   auto ptr = obj.get();
701   this->addObject(std::move(obj));
702   return ptr;
703 }
704
705 cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type)
706 {
707   auto obj = cm::make_unique<cmXCodeObject>(cmXCodeObject::None, type);
708   auto ptr = obj.get();
709   this->addObject(std::move(obj));
710   return ptr;
711 }
712
713 cmXCodeObject* cmGlobalXCodeGenerator::CreateString(const std::string& s)
714 {
715   cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING);
716   obj->SetString(s);
717   return obj;
718 }
719
720 cmXCodeObject* cmGlobalXCodeGenerator::CreateObjectReference(
721   cmXCodeObject* ref)
722 {
723   cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF);
724   obj->SetObject(ref);
725   return obj;
726 }
727
728 cmXCodeObject* cmGlobalXCodeGenerator::CreateFlatClone(cmXCodeObject* orig)
729 {
730   cmXCodeObject* obj = this->CreateObject(orig->GetType());
731   obj->CopyAttributes(orig);
732   return obj;
733 }
734
735 std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target,
736                                    const std::string& fullpath)
737 {
738   std::string key(target->GetName());
739   key += "-";
740   key += fullpath;
741   return key;
742 }
743
744 cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
745   const std::string& fullpath, cmGeneratorTarget* target,
746   const std::string& lang, cmSourceFile* sf)
747 {
748   // Using a map and the full path guarantees that we will always get the same
749   // fileRef object for any given full path.
750   //
751   cmXCodeObject* fileRef =
752     this->CreateXCodeFileReferenceFromPath(fullpath, target, lang, sf);
753
754   cmXCodeObject* buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
755   buildFile->SetComment(fileRef->GetComment());
756   buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef));
757
758   return buildFile;
759 }
760
761 class XCodeGeneratorExpressionInterpreter
762   : public cmGeneratorExpressionInterpreter
763 {
764 public:
765   XCodeGeneratorExpressionInterpreter(cmSourceFile* sourceFile,
766                                       cmLocalGenerator* localGenerator,
767                                       cmGeneratorTarget* headTarget,
768                                       const std::string& lang)
769     : cmGeneratorExpressionInterpreter(
770         localGenerator, "NO-PER-CONFIG-SUPPORT-IN-XCODE", headTarget, lang)
771     , SourceFile(sourceFile)
772   {
773   }
774
775   XCodeGeneratorExpressionInterpreter(
776     XCodeGeneratorExpressionInterpreter const&) = delete;
777   XCodeGeneratorExpressionInterpreter& operator=(
778     XCodeGeneratorExpressionInterpreter const&) = delete;
779
780   const std::string& Evaluate(const char* expression,
781                               const std::string& property)
782   {
783     return this->Evaluate(std::string(expression ? expression : ""), property);
784   }
785
786   const std::string& Evaluate(const std::string& expression,
787                               const std::string& property)
788   {
789     const std::string& processed =
790       this->cmGeneratorExpressionInterpreter::Evaluate(expression, property);
791     if (this->CompiledGeneratorExpression->GetHadContextSensitiveCondition()) {
792       std::ostringstream e;
793       /* clang-format off */
794       e <<
795           "Xcode does not support per-config per-source " << property << ":\n"
796           "  " << expression << "\n"
797           "specified for source:\n"
798           "  " << this->SourceFile->ResolveFullPath() << "\n";
799       /* clang-format on */
800       this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
801     }
802
803     return processed;
804   }
805
806 private:
807   cmSourceFile* SourceFile = nullptr;
808 };
809
810 cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
811   cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt)
812 {
813   std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
814
815   XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt, lang);
816
817   // Add flags from target and source file properties.
818   std::string flags;
819   std::string const& srcfmt = sf->GetSafeProperty("Fortran_FORMAT");
820   switch (cmOutputConverter::GetFortranFormat(srcfmt)) {
821     case cmOutputConverter::FortranFormatFixed:
822       flags = "-fixed " + flags;
823       break;
824     case cmOutputConverter::FortranFormatFree:
825       flags = "-free " + flags;
826       break;
827     default:
828       break;
829   }
830   const std::string COMPILE_FLAGS("COMPILE_FLAGS");
831   if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) {
832     lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
833   }
834   const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
835   if (cmProp coptions = sf->GetProperty(COMPILE_OPTIONS)) {
836     lg->AppendCompileOptions(
837       flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
838   }
839
840   // Add per-source definitions.
841   BuildObjectListOrString flagsBuild(this, false);
842   const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
843   if (cmProp compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) {
844     this->AppendDefines(
845       flagsBuild,
846       genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS).c_str(),
847       true);
848   }
849
850   if (sf->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) {
851     this->AppendDefines(flagsBuild, "CMAKE_SKIP_PRECOMPILE_HEADERS", true);
852   }
853
854   if (!flagsBuild.IsEmpty()) {
855     if (!flags.empty()) {
856       flags += ' ';
857     }
858     flags += flagsBuild.GetString();
859   }
860
861   // Add per-source include directories.
862   std::vector<std::string> includes;
863   const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
864   if (cmProp cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) {
865     lg->AppendIncludeDirectories(
866       includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES),
867       *sf);
868   }
869   lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true));
870
871   cmXCodeObject* buildFile =
872     this->CreateXCodeSourceFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf);
873
874   cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
875   settings->AddAttributeIfNotEmpty("COMPILER_FLAGS",
876                                    this->CreateString(flags));
877
878   cmGeneratorTarget::SourceFileFlags tsFlags =
879     gtgt->GetTargetSourceFileFlags(sf);
880
881   cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
882
883   // Is this a "private" or "public" framework header file?
884   // Set the ATTRIBUTES attribute appropriately...
885   //
886   if (gtgt->IsFrameworkOnApple()) {
887     if (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) {
888       attrs->AddObject(this->CreateString("Private"));
889     } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader) {
890       attrs->AddObject(this->CreateString("Public"));
891     }
892   }
893
894   // Add user-specified file attributes.
895   cmProp extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES");
896   if (extraFileAttributes) {
897     // Expand the list of attributes.
898     std::vector<std::string> attributes = cmExpandedList(*extraFileAttributes);
899
900     // Store the attributes.
901     for (const auto& attribute : attributes) {
902       attrs->AddObject(this->CreateString(attribute));
903     }
904   }
905
906   settings->AddAttributeIfNotEmpty("ATTRIBUTES", attrs);
907
908   buildFile->AddAttributeIfNotEmpty("settings", settings);
909   return buildFile;
910 }
911
912 void cmGlobalXCodeGenerator::AddXCodeProjBuildRule(
913   cmGeneratorTarget* target, std::vector<cmSourceFile*>& sources) const
914 {
915   std::string listfile =
916     cmStrCat(target->GetLocalGenerator()->GetCurrentSourceDirectory(),
917              "/CMakeLists.txt");
918   cmSourceFile* srcCMakeLists = target->Makefile->GetOrCreateSource(
919     listfile, false, cmSourceFileLocationKind::Known);
920   if (!cm::contains(sources, srcCMakeLists)) {
921     sources.push_back(srcCMakeLists);
922   }
923 }
924
925 std::string GetSourcecodeValueFromFileExtension(const std::string& _ext,
926                                                 const std::string& lang,
927                                                 bool& keepLastKnownFileType)
928 {
929   std::string ext = cmSystemTools::LowerCase(_ext);
930   std::string sourcecode = "sourcecode";
931
932   if (ext == "o") {
933     sourcecode = "compiled.mach-o.objfile";
934   } else if (ext == "xctest") {
935     sourcecode = "wrapper.cfbundle";
936   } else if (ext == "xib") {
937     keepLastKnownFileType = true;
938     sourcecode = "file.xib";
939   } else if (ext == "storyboard") {
940     keepLastKnownFileType = true;
941     sourcecode = "file.storyboard";
942   } else if (ext == "mm") {
943     sourcecode += ".cpp.objcpp";
944   } else if (ext == "m") {
945     sourcecode += ".c.objc";
946   } else if (ext == "swift") {
947     sourcecode += ".swift";
948   } else if (ext == "plist") {
949     sourcecode += ".text.plist";
950   } else if (ext == "h") {
951     sourcecode += ".c.h";
952   } else if (ext == "hxx" || ext == "hpp" || ext == "txx" || ext == "pch" ||
953              ext == "hh") {
954     sourcecode += ".cpp.h";
955   } else if (ext == "png" || ext == "gif" || ext == "jpg") {
956     keepLastKnownFileType = true;
957     sourcecode = "image";
958   } else if (ext == "txt") {
959     sourcecode += ".text";
960   } else if (lang == "CXX") {
961     sourcecode += ".cpp.cpp";
962   } else if (lang == "C") {
963     sourcecode += ".c.c";
964   } else if (lang == "OBJCXX") {
965     sourcecode += ".cpp.objcpp";
966   } else if (lang == "OBJC") {
967     sourcecode += ".c.objc";
968   } else if (lang == "Fortran") {
969     sourcecode += ".fortran.f90";
970   } else if (lang == "ASM") {
971     sourcecode += ".asm";
972   } else if (ext == "metal") {
973     sourcecode += ".metal";
974   } else if (ext == "mig") {
975     sourcecode += ".mig";
976   }
977   // else
978   //  {
979   //  // Already specialized above or we leave sourcecode == "sourcecode"
980   //  // which is probably the most correct choice. Extensionless headers,
981   //  // for example... Or file types unknown to Xcode that do not map to a
982   //  // valid explicitFileType value.
983   //  }
984
985   return sourcecode;
986 }
987
988 cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath(
989   const std::string& fullpath, cmGeneratorTarget* target,
990   const std::string& lang, cmSourceFile* sf)
991 {
992   std::string key = GetGroupMapKeyFromPath(target, fullpath);
993   cmXCodeObject* fileRef = this->FileRefs[key];
994   if (!fileRef) {
995     fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
996     fileRef->SetComment(fullpath);
997     this->FileRefs[key] = fileRef;
998   }
999   cmXCodeObject* group = this->GroupMap[key];
1000   cmXCodeObject* children = group->GetObject("children");
1001   if (!children->HasObject(fileRef)) {
1002     children->AddObject(fileRef);
1003   }
1004   fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
1005
1006   bool useLastKnownFileType = false;
1007   std::string fileType;
1008   if (sf) {
1009     if (cmProp e = sf->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
1010       fileType = *e;
1011     } else if (cmProp l = sf->GetProperty("XCODE_LAST_KNOWN_FILE_TYPE")) {
1012       useLastKnownFileType = true;
1013       fileType = *l;
1014     }
1015   }
1016   if (fileType.empty()) {
1017     // Compute the extension without leading '.'.
1018     std::string ext = cmSystemTools::GetFilenameLastExtension(fullpath);
1019     if (!ext.empty()) {
1020       ext = ext.substr(1);
1021     }
1022
1023     // If fullpath references a directory, then we need to specify
1024     // lastKnownFileType as folder in order for Xcode to be able to
1025     // open the contents of the folder.
1026     // (Xcode 4.6 does not like explicitFileType=folder).
1027     if (cmSystemTools::FileIsDirectory(fullpath)) {
1028       fileType = (ext == "xcassets" ? "folder.assetcatalog" : "folder");
1029       useLastKnownFileType = true;
1030     } else {
1031       fileType =
1032         GetSourcecodeValueFromFileExtension(ext, lang, useLastKnownFileType);
1033     }
1034   }
1035
1036   fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType"
1037                                              : "explicitFileType",
1038                         this->CreateString(fileType));
1039
1040   // Store the file path relative to the top of the source tree.
1041   std::string path = this->RelativeToSource(fullpath);
1042   std::string name = cmSystemTools::GetFilenameName(path);
1043   const char* sourceTree =
1044     cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT";
1045   fileRef->AddAttribute("name", this->CreateString(name));
1046   fileRef->AddAttribute("path", this->CreateString(path));
1047   fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
1048   return fileRef;
1049 }
1050
1051 cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReference(
1052   cmSourceFile* sf, cmGeneratorTarget* target)
1053 {
1054   std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf);
1055
1056   return this->CreateXCodeFileReferenceFromPath(sf->ResolveFullPath(), target,
1057                                                 lang, sf);
1058 }
1059
1060 bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname)
1061 {
1062   if (tname == "ALL_BUILD" || tname == "XCODE_DEPEND_HELPER" ||
1063       tname == "install" || tname == "package" || tname == "RUN_TESTS" ||
1064       tname == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
1065     if (this->TargetDoneSet.find(tname) != this->TargetDoneSet.end()) {
1066       return true;
1067     }
1068     this->TargetDoneSet.insert(tname);
1069     return false;
1070   }
1071   return false;
1072 }
1073
1074 void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen)
1075 {
1076   this->CurrentLocalGenerator = gen;
1077   this->CurrentMakefile = gen->GetMakefile();
1078
1079   // Select the current set of configuration types.
1080   this->CurrentConfigurationTypes.clear();
1081   this->CurrentMakefile->GetConfigurations(this->CurrentConfigurationTypes);
1082   if (this->CurrentConfigurationTypes.empty()) {
1083     this->CurrentConfigurationTypes.emplace_back();
1084   }
1085 }
1086
1087 struct cmSourceFilePathCompare
1088 {
1089   bool operator()(cmSourceFile* l, cmSourceFile* r)
1090   {
1091     return l->ResolveFullPath() < r->ResolveFullPath();
1092   }
1093 };
1094
1095 struct cmCompareTargets
1096 {
1097   bool operator()(cmXCodeObject* l, cmXCodeObject* r) const
1098   {
1099     std::string const& a = l->GetTarget()->GetName();
1100     std::string const& b = r->GetTarget()->GetName();
1101     if (a == "ALL_BUILD") {
1102       return true;
1103     }
1104     if (b == "ALL_BUILD") {
1105       return false;
1106     }
1107     return a < b;
1108   }
1109 };
1110
1111 bool cmGlobalXCodeGenerator::CreateXCodeTargets(
1112   cmLocalGenerator* gen, std::vector<cmXCodeObject*>& targets)
1113 {
1114   this->SetCurrentLocalGenerator(gen);
1115   std::vector<cmGeneratorTarget*> gts;
1116   cm::append(gts, this->CurrentLocalGenerator->GetGeneratorTargets());
1117   std::sort(gts.begin(), gts.end(),
1118             [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) {
1119               return this->TargetOrderIndex[l] < this->TargetOrderIndex[r];
1120             });
1121   for (auto gtgt : gts) {
1122     if (!this->CreateXCodeTarget(gtgt, targets)) {
1123       return false;
1124     }
1125   }
1126   std::sort(targets.begin(), targets.end(), cmCompareTargets());
1127   return true;
1128 }
1129
1130 bool cmGlobalXCodeGenerator::CreateXCodeTarget(
1131   cmGeneratorTarget* gtgt, std::vector<cmXCodeObject*>& targets)
1132 {
1133   std::string targetName = gtgt->GetName();
1134
1135   // make sure ALL_BUILD, INSTALL, etc are only done once
1136   if (this->SpecialTargetEmitted(targetName)) {
1137     return true;
1138   }
1139
1140   if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1141     return true;
1142   }
1143
1144   if (gtgt->GetType() == cmStateEnums::UTILITY ||
1145       gtgt->GetType() == cmStateEnums::GLOBAL_TARGET) {
1146     cmXCodeObject* t = this->CreateUtilityTarget(gtgt);
1147     if (!t) {
1148       return false;
1149     }
1150     targets.push_back(t);
1151     return true;
1152   }
1153
1154   // organize the sources
1155   std::vector<cmSourceFile*> classes;
1156   if (!gtgt->GetConfigCommonSourceFiles(classes)) {
1157     return false;
1158   }
1159
1160   // Add CMakeLists.txt file for user convenience.
1161   this->AddXCodeProjBuildRule(gtgt, classes);
1162
1163   // Add the Info.plist we are about to generate for an App Bundle.
1164   if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
1165     std::string plist = this->ComputeInfoPListLocation(gtgt);
1166     cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(
1167       plist, true, cmSourceFileLocationKind::Known);
1168     classes.push_back(sf);
1169   }
1170
1171   std::sort(classes.begin(), classes.end(), cmSourceFilePathCompare());
1172
1173   gtgt->ComputeObjectMapping();
1174
1175   std::vector<cmXCodeObject*> externalObjFiles;
1176   std::vector<cmXCodeObject*> headerFiles;
1177   std::vector<cmXCodeObject*> resourceFiles;
1178   std::vector<cmXCodeObject*> sourceFiles;
1179   for (auto sourceFile : classes) {
1180     cmXCodeObject* xsf = this->CreateXCodeSourceFile(
1181       this->CurrentLocalGenerator, sourceFile, gtgt);
1182     cmXCodeObject* fr = xsf->GetObject("fileRef");
1183     cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType");
1184
1185     cmGeneratorTarget::SourceFileFlags tsFlags =
1186       gtgt->GetTargetSourceFileFlags(sourceFile);
1187
1188     if (filetype && filetype->GetString() == "compiled.mach-o.objfile") {
1189       if (sourceFile->GetObjectLibrary().empty()) {
1190         externalObjFiles.push_back(xsf);
1191       }
1192     } else if (this->IsHeaderFile(sourceFile) ||
1193                (tsFlags.Type ==
1194                 cmGeneratorTarget::SourceFileTypePrivateHeader) ||
1195                (tsFlags.Type ==
1196                 cmGeneratorTarget::SourceFileTypePublicHeader)) {
1197       headerFiles.push_back(xsf);
1198     } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource) {
1199       resourceFiles.push_back(xsf);
1200     } else if (!sourceFile->GetPropertyAsBool("HEADER_FILE_ONLY") &&
1201                !gtgt->IsSourceFilePartOfUnityBatch(
1202                  sourceFile->ResolveFullPath())) {
1203       // Include this file in the build if it has a known language
1204       // and has not been listed as an ignored extension for this
1205       // generator.
1206       if (!this->CurrentLocalGenerator->GetSourceFileLanguage(*sourceFile)
1207              .empty() &&
1208           !this->IgnoreFile(sourceFile->GetExtension().c_str())) {
1209         sourceFiles.push_back(xsf);
1210       }
1211     }
1212   }
1213
1214   // some build phases only apply to bundles and/or frameworks
1215   bool isFrameworkTarget = gtgt->IsFrameworkOnApple();
1216   bool isBundleTarget = gtgt->GetPropertyAsBool("MACOSX_BUNDLE");
1217   bool isCFBundleTarget = gtgt->IsCFBundleOnApple();
1218
1219   cmXCodeObject* buildFiles = nullptr;
1220
1221   // create source build phase
1222   cmXCodeObject* sourceBuildPhase = nullptr;
1223   if (!sourceFiles.empty()) {
1224     sourceBuildPhase = this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase);
1225     sourceBuildPhase->SetComment("Sources");
1226     sourceBuildPhase->AddAttribute("buildActionMask",
1227                                    this->CreateString("2147483647"));
1228     buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1229     for (auto& sourceFile : sourceFiles) {
1230       buildFiles->AddObject(sourceFile);
1231     }
1232     sourceBuildPhase->AddAttribute("files", buildFiles);
1233     sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1234                                    this->CreateString("0"));
1235   }
1236
1237   // create header build phase - only for framework targets
1238   cmXCodeObject* headerBuildPhase = nullptr;
1239   if (!headerFiles.empty() && isFrameworkTarget) {
1240     headerBuildPhase = this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase);
1241     headerBuildPhase->SetComment("Headers");
1242     headerBuildPhase->AddAttribute("buildActionMask",
1243                                    this->CreateString("2147483647"));
1244     buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1245     for (auto& headerFile : headerFiles) {
1246       buildFiles->AddObject(headerFile);
1247     }
1248     headerBuildPhase->AddAttribute("files", buildFiles);
1249     headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1250                                    this->CreateString("0"));
1251   }
1252
1253   // create resource build phase - only for framework or bundle targets
1254   cmXCodeObject* resourceBuildPhase = nullptr;
1255   if (!resourceFiles.empty() &&
1256       (isFrameworkTarget || isBundleTarget || isCFBundleTarget)) {
1257     resourceBuildPhase =
1258       this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase);
1259     resourceBuildPhase->SetComment("Resources");
1260     resourceBuildPhase->AddAttribute("buildActionMask",
1261                                      this->CreateString("2147483647"));
1262     buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1263     for (auto& resourceFile : resourceFiles) {
1264       buildFiles->AddObject(resourceFile);
1265     }
1266     resourceBuildPhase->AddAttribute("files", buildFiles);
1267     resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1268                                      this->CreateString("0"));
1269   }
1270
1271   // create vector of "non-resource content file" build phases - only for
1272   // framework or bundle targets
1273   std::vector<cmXCodeObject*> contentBuildPhases;
1274   if (isFrameworkTarget || isBundleTarget || isCFBundleTarget) {
1275     using mapOfVectorOfSourceFiles =
1276       std::map<std::string, std::vector<cmSourceFile*>>;
1277     mapOfVectorOfSourceFiles bundleFiles;
1278     for (auto sourceFile : classes) {
1279       cmGeneratorTarget::SourceFileFlags tsFlags =
1280         gtgt->GetTargetSourceFileFlags(sourceFile);
1281       if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) {
1282         bundleFiles[tsFlags.MacFolder].push_back(sourceFile);
1283       }
1284     }
1285     for (auto const& keySources : bundleFiles) {
1286       cmXCodeObject* copyFilesBuildPhase =
1287         this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
1288       copyFilesBuildPhase->SetComment("Copy files");
1289       copyFilesBuildPhase->AddAttribute("buildActionMask",
1290                                         this->CreateString("2147483647"));
1291       copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
1292                                         this->CreateString("6"));
1293       std::ostringstream ostr;
1294       if (gtgt->IsFrameworkOnApple()) {
1295         // dstPath in frameworks is relative to Versions/<version>
1296         ostr << keySources.first;
1297       } else if (keySources.first != "MacOS") {
1298         if (gtgt->Target->GetMakefile()->PlatformIsAppleEmbedded()) {
1299           ostr << keySources.first;
1300         } else {
1301           // dstPath in bundles is relative to Contents/MacOS
1302           ostr << "../" << keySources.first;
1303         }
1304       }
1305       copyFilesBuildPhase->AddAttribute("dstPath",
1306                                         this->CreateString(ostr.str()));
1307       copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1308                                         this->CreateString("0"));
1309       buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1310       copyFilesBuildPhase->AddAttribute("files", buildFiles);
1311       for (auto sourceFile : keySources.second) {
1312         cmXCodeObject* xsf = this->CreateXCodeSourceFile(
1313           this->CurrentLocalGenerator, sourceFile, gtgt);
1314         buildFiles->AddObject(xsf);
1315       }
1316       contentBuildPhases.push_back(copyFilesBuildPhase);
1317     }
1318   }
1319
1320   // create vector of "resource content file" build phases - only for
1321   // framework or bundle targets
1322   if (isFrameworkTarget || isBundleTarget || isCFBundleTarget) {
1323     using mapOfVectorOfSourceFiles =
1324       std::map<std::string, std::vector<cmSourceFile*>>;
1325     mapOfVectorOfSourceFiles bundleFiles;
1326     for (auto sourceFile : classes) {
1327       cmGeneratorTarget::SourceFileFlags tsFlags =
1328         gtgt->GetTargetSourceFileFlags(sourceFile);
1329       if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeDeepResource) {
1330         bundleFiles[tsFlags.MacFolder].push_back(sourceFile);
1331       }
1332     }
1333     for (auto const& keySources : bundleFiles) {
1334       cmXCodeObject* copyFilesBuildPhase =
1335         this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase);
1336       copyFilesBuildPhase->SetComment("Copy files");
1337       copyFilesBuildPhase->AddAttribute("buildActionMask",
1338                                         this->CreateString("2147483647"));
1339       copyFilesBuildPhase->AddAttribute("dstSubfolderSpec",
1340                                         this->CreateString("7"));
1341       copyFilesBuildPhase->AddAttribute("dstPath",
1342                                         this->CreateString(keySources.first));
1343       copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1344                                         this->CreateString("0"));
1345       buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1346       copyFilesBuildPhase->AddAttribute("files", buildFiles);
1347       for (auto sourceFile : keySources.second) {
1348         cmXCodeObject* xsf = this->CreateXCodeSourceFile(
1349           this->CurrentLocalGenerator, sourceFile, gtgt);
1350         buildFiles->AddObject(xsf);
1351       }
1352       contentBuildPhases.push_back(copyFilesBuildPhase);
1353     }
1354   }
1355
1356   // create framework build phase
1357   cmXCodeObject* frameworkBuildPhase = nullptr;
1358   if (!externalObjFiles.empty()) {
1359     frameworkBuildPhase =
1360       this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase);
1361     frameworkBuildPhase->SetComment("Frameworks");
1362     frameworkBuildPhase->AddAttribute("buildActionMask",
1363                                       this->CreateString("2147483647"));
1364     buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1365     frameworkBuildPhase->AddAttribute("files", buildFiles);
1366     for (auto& externalObjFile : externalObjFiles) {
1367       buildFiles->AddObject(externalObjFile);
1368     }
1369     frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1370                                       this->CreateString("0"));
1371   }
1372
1373   // create list of build phases and create the Xcode target
1374   cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1375
1376   this->CreateCustomCommands(buildPhases, sourceBuildPhase, headerBuildPhase,
1377                              resourceBuildPhase, contentBuildPhases,
1378                              frameworkBuildPhase, gtgt);
1379
1380   targets.push_back(this->CreateXCodeTarget(gtgt, buildPhases));
1381   return true;
1382 }
1383
1384 void cmGlobalXCodeGenerator::ForceLinkerLanguages()
1385 {
1386   for (const auto& localGenerator : this->LocalGenerators) {
1387     // All targets depend on the build-system check target.
1388     for (const auto& tgt : localGenerator->GetGeneratorTargets()) {
1389       // This makes sure all targets link using the proper language.
1390       this->ForceLinkerLanguage(tgt.get());
1391     }
1392   }
1393 }
1394
1395 void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt)
1396 {
1397   // This matters only for targets that link.
1398   if (gtgt->GetType() != cmStateEnums::EXECUTABLE &&
1399       gtgt->GetType() != cmStateEnums::SHARED_LIBRARY &&
1400       gtgt->GetType() != cmStateEnums::MODULE_LIBRARY) {
1401     return;
1402   }
1403
1404   std::string llang = gtgt->GetLinkerLanguage("NOCONFIG");
1405   if (llang.empty()) {
1406     return;
1407   }
1408
1409   // If the language is compiled as a source trust Xcode to link with it.
1410   for (auto const& Language :
1411        gtgt->GetLinkImplementation("NOCONFIG")->Languages) {
1412     if (Language == llang) {
1413       return;
1414     }
1415   }
1416
1417   // Add an empty source file to the target that compiles with the
1418   // linker language.  This should convince Xcode to choose the proper
1419   // language.
1420   cmMakefile* mf = gtgt->Target->GetMakefile();
1421   std::string fname = cmStrCat(
1422     gtgt->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/CMakeFiles/",
1423     gtgt->GetName(), "-CMakeForceLinker.", cmSystemTools::LowerCase(llang));
1424   {
1425     cmGeneratedFileStream fout(fname);
1426     fout << "\n";
1427   }
1428   if (cmSourceFile* sf = mf->GetOrCreateSource(fname)) {
1429     sf->SetProperty("LANGUAGE", llang.c_str());
1430     gtgt->AddSource(fname);
1431   }
1432 }
1433
1434 bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf)
1435 {
1436   return cm::contains(this->CMakeInstance->GetHeaderExtensions(),
1437                       sf->GetExtension());
1438 }
1439
1440 cmXCodeObject* cmGlobalXCodeGenerator::CreateBuildPhase(
1441   const char* name, const char* name2, cmGeneratorTarget* target,
1442   const std::vector<cmCustomCommand>& commands)
1443 {
1444   if (commands.empty() && strcmp(name, "CMake ReRun") != 0) {
1445     return nullptr;
1446   }
1447   cmXCodeObject* buildPhase =
1448     this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
1449   buildPhase->AddAttribute("buildActionMask",
1450                            this->CreateString("2147483647"));
1451   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
1452   buildPhase->AddAttribute("files", buildFiles);
1453   buildPhase->AddAttribute("name", this->CreateString(name));
1454   buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
1455                            this->CreateString("0"));
1456   buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
1457   this->AddCommandsToBuildPhase(buildPhase, target, commands, name2);
1458   return buildPhase;
1459 }
1460
1461 void cmGlobalXCodeGenerator::CreateCustomCommands(
1462   cmXCodeObject* buildPhases, cmXCodeObject* sourceBuildPhase,
1463   cmXCodeObject* headerBuildPhase, cmXCodeObject* resourceBuildPhase,
1464   std::vector<cmXCodeObject*> const& contentBuildPhases,
1465   cmXCodeObject* frameworkBuildPhase, cmGeneratorTarget* gtgt)
1466 {
1467   std::vector<cmCustomCommand> const& prebuild = gtgt->GetPreBuildCommands();
1468   std::vector<cmCustomCommand> const& prelink = gtgt->GetPreLinkCommands();
1469   std::vector<cmCustomCommand> postbuild = gtgt->GetPostBuildCommands();
1470
1471   if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
1472       !gtgt->IsFrameworkOnApple()) {
1473     std::string str_file = cmStrCat("$<TARGET_FILE:", gtgt->GetName(), '>');
1474     std::string str_so_file =
1475       cmStrCat("$<TARGET_SONAME_FILE:", gtgt->GetName(), '>');
1476     std::string str_link_file =
1477       cmStrCat("$<TARGET_LINKER_FILE:", gtgt->GetName(), '>');
1478     bool stdPipesUTF8 = true;
1479     cmCustomCommandLines cmd = cmMakeSingleCommandLine(
1480       { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library",
1481         str_file, str_so_file, str_link_file });
1482
1483     cmCustomCommand command(
1484       std::vector<std::string>(), std::vector<std::string>(),
1485       std::vector<std::string>(), cmd, this->CurrentMakefile->GetBacktrace(),
1486       "Creating symlinks", "", stdPipesUTF8);
1487
1488     postbuild.push_back(std::move(command));
1489   }
1490
1491   std::vector<cmSourceFile*> classes;
1492   if (!gtgt->GetConfigCommonSourceFiles(classes)) {
1493     return;
1494   }
1495   // add all the sources
1496   std::vector<cmCustomCommand> commands;
1497   for (auto sourceFile : classes) {
1498     if (sourceFile->GetCustomCommand()) {
1499       commands.push_back(*sourceFile->GetCustomCommand());
1500     }
1501   }
1502   // create prebuild phase
1503   cmXCodeObject* cmakeRulesBuildPhase = this->CreateBuildPhase(
1504     "CMake Rules", "cmakeRulesBuildPhase", gtgt, commands);
1505   // create prebuild phase
1506   cmXCodeObject* preBuildPhase = this->CreateBuildPhase(
1507     "CMake PreBuild Rules", "preBuildCommands", gtgt, prebuild);
1508   // create prelink phase
1509   cmXCodeObject* preLinkPhase = this->CreateBuildPhase(
1510     "CMake PreLink Rules", "preLinkCommands", gtgt, prelink);
1511   // create postbuild phase
1512   cmXCodeObject* postBuildPhase = this->CreateBuildPhase(
1513     "CMake PostBuild Rules", "postBuildPhase", gtgt, postbuild);
1514
1515   // The order here is the order they will be built in.
1516   // The order "headers, resources, sources" mimics a native project generated
1517   // from an xcode template...
1518   //
1519   if (preBuildPhase) {
1520     buildPhases->AddObject(preBuildPhase);
1521   }
1522   if (cmakeRulesBuildPhase) {
1523     buildPhases->AddObject(cmakeRulesBuildPhase);
1524   }
1525   if (headerBuildPhase) {
1526     buildPhases->AddObject(headerBuildPhase);
1527   }
1528   if (resourceBuildPhase) {
1529     buildPhases->AddObject(resourceBuildPhase);
1530   }
1531   for (auto obj : contentBuildPhases) {
1532     buildPhases->AddObject(obj);
1533   }
1534   if (sourceBuildPhase) {
1535     buildPhases->AddObject(sourceBuildPhase);
1536   }
1537   if (preLinkPhase) {
1538     buildPhases->AddObject(preLinkPhase);
1539   }
1540   if (frameworkBuildPhase) {
1541     buildPhases->AddObject(frameworkBuildPhase);
1542   }
1543   if (postBuildPhase) {
1544     buildPhases->AddObject(postBuildPhase);
1545   }
1546 }
1547
1548 // This function removes each occurrence of the flag and returns the last one
1549 // (i.e., the dominant flag in GCC)
1550 std::string cmGlobalXCodeGenerator::ExtractFlag(const char* flag,
1551                                                 std::string& flags)
1552 {
1553   std::string retFlag;
1554   std::string::size_type lastOccurancePos = flags.rfind(flag);
1555   bool saved = false;
1556   while (lastOccurancePos != std::string::npos) {
1557     // increment pos, we use lastOccurancePos to reduce search space on next
1558     // inc
1559     std::string::size_type pos = lastOccurancePos;
1560     if (pos == 0 || flags[pos - 1] == ' ') {
1561       while (pos < flags.size() && flags[pos] != ' ') {
1562         if (!saved) {
1563           retFlag += flags[pos];
1564         }
1565         flags[pos] = ' ';
1566         pos++;
1567       }
1568       saved = true;
1569     }
1570     // decrement lastOccurancePos while making sure we don't loop around
1571     // and become a very large positive number since size_type is unsigned
1572     lastOccurancePos = lastOccurancePos == 0 ? 0 : lastOccurancePos - 1;
1573     lastOccurancePos = flags.rfind(flag, lastOccurancePos);
1574   }
1575   return retFlag;
1576 }
1577
1578 // This function removes each matching occurrence of the expression and
1579 // returns the last one (i.e., the dominant flag in GCC)
1580 std::string cmGlobalXCodeGenerator::ExtractFlagRegex(const char* exp,
1581                                                      int matchIndex,
1582                                                      std::string& flags)
1583 {
1584   std::string retFlag;
1585
1586   cmsys::RegularExpression regex(exp);
1587   assert(regex.is_valid());
1588   if (!regex.is_valid()) {
1589     return retFlag;
1590   }
1591
1592   std::string::size_type offset = 0;
1593
1594   while (regex.find(&flags[offset])) {
1595     const std::string::size_type startPos = offset + regex.start(matchIndex);
1596     const std::string::size_type endPos = offset + regex.end(matchIndex);
1597     const std::string::size_type size = endPos - startPos;
1598
1599     offset = startPos + 1;
1600
1601     retFlag.assign(flags, startPos, size);
1602     flags.replace(startPos, size, size, ' ');
1603   }
1604
1605   return retFlag;
1606 }
1607
1608 //----------------------------------------------------------------------------
1609 // This function strips off Xcode attributes that do not target the current
1610 // configuration
1611 void cmGlobalXCodeGenerator::FilterConfigurationAttribute(
1612   std::string const& configName, std::string& attribute)
1613 {
1614   // Handle [variant=<config>] condition explicitly here.
1615   std::string::size_type beginVariant = attribute.find("[variant=");
1616   if (beginVariant == std::string::npos) {
1617     // There is no variant in this attribute.
1618     return;
1619   }
1620
1621   std::string::size_type endVariant = attribute.find(']', beginVariant + 9);
1622   if (endVariant == std::string::npos) {
1623     // There is no terminating bracket.
1624     return;
1625   }
1626
1627   // Compare the variant to the configuration.
1628   std::string variant =
1629     attribute.substr(beginVariant + 9, endVariant - beginVariant - 9);
1630   if (variant == configName) {
1631     // The variant matches the configuration so use this
1632     // attribute but drop the [variant=<config>] condition.
1633     attribute.erase(beginVariant, endVariant - beginVariant + 1);
1634   } else {
1635     // The variant does not match the configuration so
1636     // do not use this attribute.
1637     attribute.clear();
1638   }
1639 }
1640
1641 void cmGlobalXCodeGenerator::AddCommandsToBuildPhase(
1642   cmXCodeObject* buildphase, cmGeneratorTarget* target,
1643   std::vector<cmCustomCommand> const& commands, const char* name)
1644 {
1645   std::string dir = cmStrCat(
1646     this->CurrentLocalGenerator->GetCurrentBinaryDirectory(), "/CMakeScripts");
1647   cmSystemTools::MakeDirectory(dir);
1648   std::string makefile =
1649     cmStrCat(dir, '/', target->GetName(), '_', name, ".make");
1650
1651   for (const auto& currentConfig : this->CurrentConfigurationTypes) {
1652     this->CreateCustomRulesMakefile(makefile.c_str(), target, commands,
1653                                     currentConfig);
1654   }
1655
1656   std::string cdir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
1657   cdir = this->ConvertToRelativeForMake(cdir);
1658   std::string makecmd =
1659     cmStrCat("make -C ", cdir, " -f ",
1660              this->ConvertToRelativeForMake((makefile + "$CONFIGURATION")),
1661              " OBJDIR=$(basename \"$OBJECT_FILE_DIR_normal\") all");
1662   buildphase->AddAttribute("shellScript", this->CreateString(makecmd));
1663   buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
1664 }
1665
1666 void cmGlobalXCodeGenerator::CreateCustomRulesMakefile(
1667   const char* makefileBasename, cmGeneratorTarget* target,
1668   std::vector<cmCustomCommand> const& commands, const std::string& configName)
1669 {
1670   std::string makefileName = cmStrCat(makefileBasename, configName);
1671   cmGeneratedFileStream makefileStream(makefileName);
1672   if (!makefileStream) {
1673     return;
1674   }
1675   makefileStream.SetCopyIfDifferent(true);
1676   makefileStream << "# Generated by CMake, DO NOT EDIT\n";
1677   makefileStream << "# Custom rules for " << target->GetName() << "\n";
1678
1679   // disable the implicit rules
1680   makefileStream << ".SUFFIXES: "
1681                  << "\n";
1682
1683   // have all depend on all outputs
1684   makefileStream << "all: ";
1685   std::map<const cmCustomCommand*, std::string> tname;
1686   int count = 0;
1687   for (auto const& command : commands) {
1688     cmCustomCommandGenerator ccg(command, configName,
1689                                  this->CurrentLocalGenerator);
1690     if (ccg.GetNumberOfCommands() > 0) {
1691       const std::vector<std::string>& outputs = ccg.GetOutputs();
1692       if (!outputs.empty()) {
1693         for (auto const& output : outputs) {
1694           makefileStream << "\\\n\t" << this->ConvertToRelativeForMake(output);
1695         }
1696       } else {
1697         std::ostringstream str;
1698         str << "_buildpart_" << count++;
1699         tname[&ccg.GetCC()] = target->GetName() + str.str();
1700         makefileStream << "\\\n\t" << tname[&ccg.GetCC()];
1701       }
1702     }
1703   }
1704   makefileStream << "\n\n";
1705   for (auto const& command : commands) {
1706     cmCustomCommandGenerator ccg(command, configName,
1707                                  this->CurrentLocalGenerator);
1708     if (ccg.GetNumberOfCommands() > 0) {
1709       makefileStream << "\n";
1710       const std::vector<std::string>& outputs = ccg.GetOutputs();
1711       if (!outputs.empty()) {
1712         // There is at least one output, start the rule for it
1713         const char* sep = "";
1714         for (auto const& output : outputs) {
1715           makefileStream << sep << this->ConvertToRelativeForMake(output);
1716           sep = " ";
1717         }
1718         makefileStream << ": ";
1719       } else {
1720         // There are no outputs.  Use the generated force rule name.
1721         makefileStream << tname[&ccg.GetCC()] << ": ";
1722       }
1723       for (auto const& d : ccg.GetDepends()) {
1724         std::string dep;
1725         if (this->CurrentLocalGenerator->GetRealDependency(d, configName,
1726                                                            dep)) {
1727           makefileStream << "\\\n" << this->ConvertToRelativeForMake(dep);
1728         }
1729       }
1730       makefileStream << "\n";
1731
1732       if (const char* comment = ccg.GetComment()) {
1733         std::string echo_cmd =
1734           cmStrCat("echo ",
1735                    (this->CurrentLocalGenerator->EscapeForShell(
1736                      comment, ccg.GetCC().GetEscapeAllowMakeVars())));
1737         makefileStream << "\t" << echo_cmd << "\n";
1738       }
1739
1740       // Add each command line to the set of commands.
1741       for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
1742         // Build the command line in a single string.
1743         std::string cmd2 = ccg.GetCommand(c);
1744         cmSystemTools::ReplaceString(cmd2, "/./", "/");
1745         cmd2 = this->ConvertToRelativeForMake(cmd2);
1746         std::string cmd;
1747         std::string wd = ccg.GetWorkingDirectory();
1748         if (!wd.empty()) {
1749           cmd += "cd ";
1750           cmd += this->ConvertToRelativeForMake(wd);
1751           cmd += " && ";
1752         }
1753         cmd += cmd2;
1754         ccg.AppendArguments(c, cmd);
1755         makefileStream << "\t" << cmd << "\n";
1756       }
1757     }
1758   }
1759 }
1760
1761 void cmGlobalXCodeGenerator::AddPositionIndependentLinkAttribute(
1762   cmGeneratorTarget* target, cmXCodeObject* buildSettings,
1763   const std::string& configName)
1764 {
1765   // For now, only EXECUTABLE is concerned
1766   if (target->GetType() != cmStateEnums::EXECUTABLE) {
1767     return;
1768   }
1769
1770   const char* PICValue = target->GetLinkPIEProperty(configName);
1771   if (PICValue == nullptr) {
1772     // POSITION_INDEPENDENT_CODE is not set
1773     return;
1774   }
1775
1776   buildSettings->AddAttribute(
1777     "LD_NO_PIE", this->CreateString(cmIsOn(PICValue) ? "NO" : "YES"));
1778 }
1779
1780 void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
1781                                                  cmXCodeObject* buildSettings,
1782                                                  const std::string& configName)
1783 {
1784   if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1785     return;
1786   }
1787
1788   std::string defFlags;
1789   bool shared = ((gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) ||
1790                  (gtgt->GetType() == cmStateEnums::MODULE_LIBRARY));
1791   bool binary = ((gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
1792                  (gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) ||
1793                  (gtgt->GetType() == cmStateEnums::EXECUTABLE) || shared);
1794
1795   // Compute the compilation flags for each language.
1796   std::set<std::string> languages;
1797   gtgt->GetLanguages(languages, configName);
1798   std::map<std::string, std::string> cflags;
1799   for (auto const& lang : languages) {
1800     std::string& flags = cflags[lang];
1801
1802     // Add language-specific flags.
1803     this->CurrentLocalGenerator->AddLanguageFlags(flags, gtgt, lang,
1804                                                   configName);
1805
1806     if (gtgt->IsIPOEnabled(lang, configName)) {
1807       this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
1808     }
1809
1810     // Add shared-library flags if needed.
1811     this->CurrentLocalGenerator->AddCMP0018Flags(flags, gtgt, lang,
1812                                                  configName);
1813
1814     this->CurrentLocalGenerator->AddVisibilityPresetFlags(flags, gtgt, lang);
1815
1816     this->CurrentLocalGenerator->AddCompileOptions(flags, gtgt, lang,
1817                                                    configName);
1818   }
1819
1820   std::string llang = gtgt->GetLinkerLanguage(configName);
1821   if (binary && llang.empty()) {
1822     cmSystemTools::Error(
1823       "CMake can not determine linker language for target: " +
1824       gtgt->GetName());
1825     return;
1826   }
1827   std::string const& langForPreprocessor = llang;
1828
1829   if (gtgt->IsIPOEnabled(llang, configName)) {
1830     const char* ltoValue =
1831       this->CurrentMakefile->IsOn("_CMAKE_LTO_THIN") ? "YES_THIN" : "YES";
1832     buildSettings->AddAttribute("LLVM_LTO", this->CreateString(ltoValue));
1833   }
1834
1835   // Handle PIE linker configuration
1836   this->AddPositionIndependentLinkAttribute(gtgt, buildSettings, configName);
1837
1838   // Add define flags
1839   this->CurrentLocalGenerator->AppendFlags(
1840     defFlags, this->CurrentMakefile->GetDefineFlags());
1841
1842   // Add preprocessor definitions for this target and configuration.
1843   BuildObjectListOrString ppDefs(this, true);
1844   this->AppendDefines(
1845     ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"");
1846   if (const std::string* exportMacro = gtgt->GetExportMacro()) {
1847     // Add the export symbol definition for shared library objects.
1848     this->AppendDefines(ppDefs, exportMacro->c_str());
1849   }
1850   std::vector<std::string> targetDefines;
1851   if (!langForPreprocessor.empty()) {
1852     gtgt->GetCompileDefinitions(targetDefines, configName,
1853                                 langForPreprocessor);
1854   }
1855   this->AppendDefines(ppDefs, targetDefines);
1856   buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS",
1857                               ppDefs.CreateList());
1858
1859   std::string extraLinkOptionsVar;
1860   std::string extraLinkOptions;
1861   if (gtgt->GetType() == cmStateEnums::EXECUTABLE) {
1862     extraLinkOptionsVar = "CMAKE_EXE_LINKER_FLAGS";
1863   } else if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
1864     extraLinkOptionsVar = "CMAKE_SHARED_LINKER_FLAGS";
1865   } else if (gtgt->GetType() == cmStateEnums::MODULE_LIBRARY) {
1866     extraLinkOptionsVar = "CMAKE_MODULE_LINKER_FLAGS";
1867   }
1868   if (!extraLinkOptionsVar.empty()) {
1869     this->CurrentLocalGenerator->AddConfigVariableFlags(
1870       extraLinkOptions, extraLinkOptionsVar, configName);
1871   }
1872
1873   if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
1874       gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) {
1875     this->CurrentLocalGenerator->GetStaticLibraryFlags(
1876       extraLinkOptions, configName, llang, gtgt);
1877   } else {
1878     cmProp targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
1879     if (targetLinkFlags) {
1880       this->CurrentLocalGenerator->AppendFlags(extraLinkOptions,
1881                                                *targetLinkFlags);
1882     }
1883     if (!configName.empty()) {
1884       std::string linkFlagsVar =
1885         cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(configName));
1886       if (cmProp linkFlags = gtgt->GetProperty(linkFlagsVar)) {
1887         this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, *linkFlags);
1888       }
1889     }
1890     std::vector<std::string> opts;
1891     gtgt->GetLinkOptions(opts, configName, llang);
1892     // LINK_OPTIONS are escaped.
1893     this->CurrentLocalGenerator->AppendCompileOptions(extraLinkOptions, opts);
1894   }
1895
1896   // Set target-specific architectures.
1897   std::vector<std::string> archs;
1898   gtgt->GetAppleArchs(configName, archs);
1899
1900   if (!archs.empty()) {
1901     // Enable ARCHS attribute.
1902     buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("NO"));
1903
1904     // Store ARCHS value.
1905     if (archs.size() == 1) {
1906       buildSettings->AddAttribute("ARCHS", this->CreateString(archs[0]));
1907     } else {
1908       cmXCodeObject* archObjects =
1909         this->CreateObject(cmXCodeObject::OBJECT_LIST);
1910       for (auto& arch : archs) {
1911         archObjects->AddObject(this->CreateString(arch));
1912       }
1913       buildSettings->AddAttribute("ARCHS", archObjects);
1914     }
1915   }
1916
1917   // Get the product name components.
1918   std::string pnprefix;
1919   std::string pnbase;
1920   std::string pnsuffix;
1921   gtgt->GetFullNameComponents(pnprefix, pnbase, pnsuffix, configName);
1922
1923   cmProp version = gtgt->GetProperty("VERSION");
1924   cmProp soversion = gtgt->GetProperty("SOVERSION");
1925   if (!gtgt->HasSOName(configName) || gtgt->IsFrameworkOnApple()) {
1926     version = nullptr;
1927     soversion = nullptr;
1928   }
1929   if (version && !soversion) {
1930     soversion = version;
1931   }
1932   if (!version && soversion) {
1933     version = soversion;
1934   }
1935
1936   std::string realName = pnbase;
1937   std::string soName = pnbase;
1938   if (version && soversion) {
1939     realName += ".";
1940     realName += *version;
1941     soName += ".";
1942     soName += *soversion;
1943   }
1944
1945   // Set attributes to specify the proper name for the target.
1946   std::string pndir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
1947   if (gtgt->GetType() == cmStateEnums::STATIC_LIBRARY ||
1948       gtgt->GetType() == cmStateEnums::SHARED_LIBRARY ||
1949       gtgt->GetType() == cmStateEnums::MODULE_LIBRARY ||
1950       gtgt->GetType() == cmStateEnums::EXECUTABLE) {
1951     if (!gtgt->UsesDefaultOutputDir(configName,
1952                                     cmStateEnums::RuntimeBinaryArtifact)) {
1953       std::string pncdir = gtgt->GetDirectory(configName);
1954       buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
1955                                   this->CreateString(pncdir));
1956     }
1957
1958     if (gtgt->IsFrameworkOnApple() || gtgt->IsCFBundleOnApple()) {
1959       pnprefix = "";
1960     }
1961
1962     buildSettings->AddAttribute("EXECUTABLE_PREFIX",
1963                                 this->CreateString(pnprefix));
1964     buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
1965                                 this->CreateString(pnsuffix));
1966   } else if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1967     pnprefix = "lib";
1968     pnbase = gtgt->GetName();
1969     pnsuffix = ".a";
1970
1971     std::string pncdir = this->GetObjectsDirectory(
1972       this->CurrentProject, configName, gtgt, OBJECT_LIBRARY_ARTIFACT_DIR);
1973     buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
1974                                 this->CreateString(pncdir));
1975   }
1976
1977   // Store the product name for all target types.
1978   buildSettings->AddAttribute("PRODUCT_NAME", this->CreateString(realName));
1979   buildSettings->AddAttribute("SYMROOT", this->CreateString(pndir));
1980
1981   // Handle settings for each target type.
1982   switch (gtgt->GetType()) {
1983     case cmStateEnums::STATIC_LIBRARY:
1984       if (gtgt->GetPropertyAsBool("FRAMEWORK")) {
1985         std::string fw_version = gtgt->GetFrameworkVersion();
1986         buildSettings->AddAttribute("FRAMEWORK_VERSION",
1987                                     this->CreateString(fw_version));
1988         cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
1989         if (ext) {
1990           buildSettings->AddAttribute("WRAPPER_EXTENSION",
1991                                       this->CreateString(*ext));
1992         }
1993
1994         std::string plist = this->ComputeInfoPListLocation(gtgt);
1995         // Xcode will create the final version of Info.plist at build time,
1996         // so let it replace the framework name. This avoids creating
1997         // a per-configuration Info.plist file.
1998         this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
1999           gtgt, "$(EXECUTABLE_NAME)", plist);
2000         buildSettings->AddAttribute("INFOPLIST_FILE",
2001                                     this->CreateString(plist));
2002         buildSettings->AddAttribute("MACH_O_TYPE",
2003                                     this->CreateString("staticlib"));
2004       } else {
2005         buildSettings->AddAttribute("LIBRARY_STYLE",
2006                                     this->CreateString("STATIC"));
2007       }
2008       break;
2009
2010     case cmStateEnums::OBJECT_LIBRARY: {
2011       buildSettings->AddAttribute("LIBRARY_STYLE",
2012                                   this->CreateString("STATIC"));
2013       break;
2014     }
2015
2016     case cmStateEnums::MODULE_LIBRARY: {
2017       buildSettings->AddAttribute("LIBRARY_STYLE",
2018                                   this->CreateString("BUNDLE"));
2019       if (gtgt->IsCFBundleOnApple()) {
2020         // It turns out that a BUNDLE is basically the same
2021         // in many ways as an application bundle, as far as
2022         // link flags go
2023         std::string createFlags = this->LookupFlags(
2024           "CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", "-bundle");
2025         if (!createFlags.empty()) {
2026           extraLinkOptions += " ";
2027           extraLinkOptions += createFlags;
2028         }
2029         cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
2030         if (ext) {
2031           buildSettings->AddAttribute("WRAPPER_EXTENSION",
2032                                       this->CreateString(*ext));
2033         }
2034         std::string plist = this->ComputeInfoPListLocation(gtgt);
2035         // Xcode will create the final version of Info.plist at build time,
2036         // so let it replace the cfbundle name. This avoids creating
2037         // a per-configuration Info.plist file. The cfbundle plist
2038         // is very similar to the application bundle plist
2039         this->CurrentLocalGenerator->GenerateAppleInfoPList(
2040           gtgt, "$(EXECUTABLE_NAME)", plist);
2041         buildSettings->AddAttribute("INFOPLIST_FILE",
2042                                     this->CreateString(plist));
2043       } else {
2044         buildSettings->AddAttribute("MACH_O_TYPE",
2045                                     this->CreateString("mh_bundle"));
2046         buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
2047                                     this->CreateString("NO"));
2048         // Add the flags to create an executable.
2049         std::string createFlags =
2050           this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", "");
2051         if (!createFlags.empty()) {
2052           extraLinkOptions += " ";
2053           extraLinkOptions += createFlags;
2054         }
2055       }
2056       break;
2057     }
2058     case cmStateEnums::SHARED_LIBRARY: {
2059       if (gtgt->GetPropertyAsBool("FRAMEWORK")) {
2060         std::string fw_version = gtgt->GetFrameworkVersion();
2061         buildSettings->AddAttribute("FRAMEWORK_VERSION",
2062                                     this->CreateString(fw_version));
2063         cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
2064         if (ext) {
2065           buildSettings->AddAttribute("WRAPPER_EXTENSION",
2066                                       this->CreateString(*ext));
2067         }
2068
2069         std::string plist = this->ComputeInfoPListLocation(gtgt);
2070         // Xcode will create the final version of Info.plist at build time,
2071         // so let it replace the framework name. This avoids creating
2072         // a per-configuration Info.plist file.
2073         this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
2074           gtgt, "$(EXECUTABLE_NAME)", plist);
2075         buildSettings->AddAttribute("INFOPLIST_FILE",
2076                                     this->CreateString(plist));
2077       } else {
2078         // Add the flags to create a shared library.
2079         std::string createFlags = this->LookupFlags(
2080           "CMAKE_SHARED_LIBRARY_CREATE_", llang, "_FLAGS", "-dynamiclib");
2081         if (!createFlags.empty()) {
2082           extraLinkOptions += " ";
2083           extraLinkOptions += createFlags;
2084         }
2085       }
2086
2087       buildSettings->AddAttribute("LIBRARY_STYLE",
2088                                   this->CreateString("DYNAMIC"));
2089       break;
2090     }
2091     case cmStateEnums::EXECUTABLE: {
2092       // Add the flags to create an executable.
2093       std::string createFlags =
2094         this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", "");
2095       if (!createFlags.empty()) {
2096         extraLinkOptions += " ";
2097         extraLinkOptions += createFlags;
2098       }
2099
2100       // Handle bundles and normal executables separately.
2101       if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
2102         cmProp ext = gtgt->GetProperty("BUNDLE_EXTENSION");
2103         if (ext) {
2104           buildSettings->AddAttribute("WRAPPER_EXTENSION",
2105                                       this->CreateString(*ext));
2106         }
2107         std::string plist = this->ComputeInfoPListLocation(gtgt);
2108         // Xcode will create the final version of Info.plist at build time,
2109         // so let it replace the executable name.  This avoids creating
2110         // a per-configuration Info.plist file.
2111         this->CurrentLocalGenerator->GenerateAppleInfoPList(
2112           gtgt, "$(EXECUTABLE_NAME)", plist);
2113         buildSettings->AddAttribute("INFOPLIST_FILE",
2114                                     this->CreateString(plist));
2115       }
2116     } break;
2117     default:
2118       break;
2119   }
2120
2121   BuildObjectListOrString dirs(this, true);
2122   BuildObjectListOrString fdirs(this, true);
2123   BuildObjectListOrString sysdirs(this, true);
2124   BuildObjectListOrString sysfdirs(this, true);
2125   const bool emitSystemIncludes = this->XcodeVersion >= 83;
2126
2127   std::vector<std::string> includes;
2128   if (!langForPreprocessor.empty()) {
2129     this->CurrentLocalGenerator->GetIncludeDirectories(
2130       includes, gtgt, langForPreprocessor, configName);
2131   }
2132   std::set<std::string> emitted;
2133   emitted.insert("/System/Library/Frameworks");
2134
2135   for (auto& include : includes) {
2136     if (this->NameResolvesToFramework(include)) {
2137       std::string frameworkDir = cmStrCat(include, "/../");
2138       frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
2139       if (emitted.insert(frameworkDir).second) {
2140         std::string incpath = this->XCodeEscapePath(frameworkDir);
2141         if (emitSystemIncludes &&
2142             gtgt->IsSystemIncludeDirectory(frameworkDir, configName,
2143                                            langForPreprocessor)) {
2144           sysfdirs.Add(incpath);
2145         } else {
2146           fdirs.Add(incpath);
2147         }
2148       }
2149     } else {
2150       std::string incpath = this->XCodeEscapePath(include);
2151       if (emitSystemIncludes &&
2152           gtgt->IsSystemIncludeDirectory(include, configName,
2153                                          langForPreprocessor)) {
2154         sysdirs.Add(incpath);
2155       } else {
2156         dirs.Add(incpath);
2157       }
2158     }
2159   }
2160   // Add framework search paths needed for linking.
2161   if (cmComputeLinkInformation* cli = gtgt->GetLinkInformation(configName)) {
2162     for (auto const& fwDir : cli->GetFrameworkPaths()) {
2163       if (emitted.insert(fwDir).second) {
2164         std::string incpath = this->XCodeEscapePath(fwDir);
2165         if (emitSystemIncludes &&
2166             gtgt->IsSystemIncludeDirectory(fwDir, configName,
2167                                            langForPreprocessor)) {
2168           sysfdirs.Add(incpath);
2169         } else {
2170           fdirs.Add(incpath);
2171         }
2172       }
2173     }
2174   }
2175   if (!fdirs.IsEmpty()) {
2176     buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS", fdirs.CreateList());
2177   }
2178   if (!dirs.IsEmpty()) {
2179     buildSettings->AddAttribute("HEADER_SEARCH_PATHS", dirs.CreateList());
2180   }
2181   if (!sysfdirs.IsEmpty()) {
2182     buildSettings->AddAttribute("SYSTEM_FRAMEWORK_SEARCH_PATHS",
2183                                 sysfdirs.CreateList());
2184   }
2185   if (!sysdirs.IsEmpty()) {
2186     buildSettings->AddAttribute("SYSTEM_HEADER_SEARCH_PATHS",
2187                                 sysdirs.CreateList());
2188   }
2189
2190   if (this->XcodeVersion >= 60 && !emitSystemIncludes) {
2191     // Add those per-language flags in addition to HEADER_SEARCH_PATHS to gain
2192     // system include directory awareness. We need to also keep on setting
2193     // HEADER_SEARCH_PATHS to work around a missing compile options flag for
2194     // GNU assembly files (#16449)
2195     for (auto const& language : languages) {
2196       std::string includeFlags = this->CurrentLocalGenerator->GetIncludeFlags(
2197         includes, gtgt, language, true, false, configName);
2198
2199       if (!includeFlags.empty()) {
2200         cflags[language] += " " + includeFlags;
2201       }
2202     }
2203   }
2204
2205   bool same_gflags = true;
2206   std::map<std::string, std::string> gflags;
2207   std::string const* last_gflag = nullptr;
2208   std::string optLevel = "0";
2209
2210   // Minimal map of flags to build settings.
2211   for (auto const& language : languages) {
2212     std::string& flags = cflags[language];
2213     std::string& gflag = gflags[language];
2214     std::string oflag =
2215       this->ExtractFlagRegex("(^| )(-Ofast|-Os|-O[0-9]*)( |$)", 2, flags);
2216     if (oflag.size() == 2) {
2217       optLevel = "1";
2218     } else if (oflag.size() > 2) {
2219       optLevel = oflag.substr(2);
2220     }
2221     gflag = this->ExtractFlag("-g", flags);
2222     // put back gdwarf-2 if used since there is no way
2223     // to represent it in the gui, but we still want debug yes
2224     if (gflag == "-gdwarf-2") {
2225       flags += " ";
2226       flags += gflag;
2227     }
2228     if (last_gflag && *last_gflag != gflag) {
2229       same_gflags = false;
2230     }
2231     last_gflag = &gflag;
2232   }
2233
2234   const char* debugStr = "YES";
2235   if (!same_gflags) {
2236     // We can't set the Xcode flag differently depending on the language,
2237     // so put them back in this case.
2238     for (auto const& language : languages) {
2239       cflags[language] += " ";
2240       cflags[language] += gflags[language];
2241     }
2242     debugStr = "NO";
2243   } else if (last_gflag && (last_gflag->empty() || *last_gflag == "-g0")) {
2244     debugStr = "NO";
2245   }
2246
2247   // extract C++ stdlib
2248   for (auto const& language : languages) {
2249     if (language != "CXX" && language != "OBJCXX") {
2250       continue;
2251     }
2252     std::string& flags = cflags[language];
2253
2254     auto stdlib =
2255       this->ExtractFlagRegex("(^| )(-stdlib=[^ ]+)( |$)", 2, flags);
2256     if (stdlib.size() > 8) {
2257       const auto cxxLibrary = stdlib.substr(8);
2258       if (language == "CXX" ||
2259           !buildSettings->GetObject("CLANG_CXX_LIBRARY")) {
2260         buildSettings->AddAttribute("CLANG_CXX_LIBRARY",
2261                                     this->CreateString(cxxLibrary));
2262       }
2263     }
2264   }
2265
2266   buildSettings->AddAttribute("COMBINE_HIDPI_IMAGES",
2267                               this->CreateString("YES"));
2268   buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
2269                               this->CreateString(debugStr));
2270   buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
2271                               this->CreateString(optLevel));
2272   buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
2273                               this->CreateString("NO"));
2274   buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
2275                               this->CreateString("NO"));
2276
2277   for (auto const& language : languages) {
2278     std::string flags = cflags[language] + " " + defFlags;
2279     if (language == "CXX" || language == "OBJCXX") {
2280       if (language == "CXX" ||
2281           !buildSettings->GetObject("OTHER_CPLUSPLUSFLAGS")) {
2282         buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
2283                                     this->CreateString(flags));
2284       }
2285     } else if (language == "Fortran") {
2286       buildSettings->AddAttribute("IFORT_OTHER_FLAGS",
2287                                   this->CreateString(flags));
2288     } else if (language == "C" || language == "OBJC") {
2289       if (language == "C" || !buildSettings->GetObject("OTHER_CFLAGS")) {
2290         buildSettings->AddAttribute("OTHER_CFLAGS", this->CreateString(flags));
2291       }
2292     } else if (language == "Swift") {
2293       buildSettings->AddAttribute("OTHER_SWIFT_FLAGS",
2294                                   this->CreateString(flags));
2295     }
2296   }
2297
2298   // Add Fortran source format attribute if property is set.
2299   const char* format = nullptr;
2300   std::string const& tgtfmt = gtgt->GetSafeProperty("Fortran_FORMAT");
2301   switch (cmOutputConverter::GetFortranFormat(tgtfmt)) {
2302     case cmOutputConverter::FortranFormatFixed:
2303       format = "fixed";
2304       break;
2305     case cmOutputConverter::FortranFormatFree:
2306       format = "free";
2307       break;
2308     default:
2309       break;
2310   }
2311   if (format) {
2312     buildSettings->AddAttribute("IFORT_LANG_SRCFMT",
2313                                 this->CreateString(format));
2314   }
2315
2316   // Create the INSTALL_PATH attribute.
2317   std::string install_name_dir;
2318   if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
2319     // Get the install_name directory for the build tree.
2320     install_name_dir = gtgt->GetInstallNameDirForBuildTree(configName);
2321     // Xcode doesn't create the correct install_name in some cases.
2322     // That is, if the INSTALL_PATH is empty, or if we have versioning
2323     // of dylib libraries, we want to specify the install_name.
2324     // This is done by adding a link flag to create an install_name
2325     // with just the library soname.
2326     std::string install_name;
2327     if (!install_name_dir.empty()) {
2328       // Convert to a path for the native build tool.
2329       cmSystemTools::ConvertToUnixSlashes(install_name_dir);
2330       install_name += install_name_dir;
2331       install_name += "/";
2332     }
2333     install_name += gtgt->GetSOName(configName);
2334
2335     if ((realName != soName) || install_name_dir.empty()) {
2336       install_name_dir = "";
2337       extraLinkOptions += " -install_name ";
2338       extraLinkOptions += XCodeEscapePath(install_name);
2339     }
2340   }
2341   buildSettings->AddAttribute("INSTALL_PATH",
2342                               this->CreateString(install_name_dir));
2343
2344   // Create the LD_RUNPATH_SEARCH_PATHS
2345   cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName);
2346   if (pcli) {
2347     std::string search_paths;
2348     std::vector<std::string> runtimeDirs;
2349     pcli->GetRPath(runtimeDirs, false);
2350     // runpath dirs needs to be unique to prevent corruption
2351     std::set<std::string> unique_dirs;
2352
2353     for (auto runpath : runtimeDirs) {
2354       runpath = this->ExpandCFGIntDir(runpath, configName);
2355
2356       if (unique_dirs.find(runpath) == unique_dirs.end()) {
2357         unique_dirs.insert(runpath);
2358         if (!search_paths.empty()) {
2359           search_paths += " ";
2360         }
2361         search_paths += this->XCodeEscapePath(runpath);
2362       }
2363     }
2364     if (!search_paths.empty()) {
2365       buildSettings->AddAttribute("LD_RUNPATH_SEARCH_PATHS",
2366                                   this->CreateString(search_paths));
2367     }
2368   }
2369
2370   buildSettings->AddAttribute(this->GetTargetLinkFlagsVar(gtgt),
2371                               this->CreateString(extraLinkOptions));
2372   buildSettings->AddAttribute("OTHER_REZFLAGS", this->CreateString(""));
2373   buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString(""));
2374   buildSettings->AddAttribute("USE_HEADERMAP", this->CreateString("NO"));
2375   cmXCodeObject* group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2376   group->AddObject(this->CreateString("$(inherited)"));
2377   buildSettings->AddAttribute("WARNING_CFLAGS", group);
2378
2379   // Runtime version information.
2380   if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
2381     int major;
2382     int minor;
2383     int patch;
2384
2385     // MACHO_CURRENT_VERSION or VERSION -> current_version
2386     gtgt->GetTargetVersionFallback("MACHO_CURRENT_VERSION", "VERSION", major,
2387                                    minor, patch);
2388     std::ostringstream v;
2389
2390     // Xcode always wants at least 1.0.0 or nothing
2391     if (!(major == 0 && minor == 0 && patch == 0)) {
2392       v << major << "." << minor << "." << patch;
2393     }
2394     buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
2395                                 this->CreateString(v.str()));
2396
2397     // MACHO_COMPATIBILITY_VERSION or SOVERSION -> compatibility_version
2398     gtgt->GetTargetVersionFallback("MACHO_COMPATIBILITY_VERSION", "SOVERSION",
2399                                    major, minor, patch);
2400     std::ostringstream vso;
2401
2402     // Xcode always wants at least 1.0.0 or nothing
2403     if (!(major == 0 && minor == 0 && patch == 0)) {
2404       vso << major << "." << minor << "." << patch;
2405     }
2406     buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
2407                                 this->CreateString(vso.str()));
2408   }
2409
2410   // Precompile Headers
2411   std::string pchHeader = gtgt->GetPchHeader(configName, llang);
2412   if (!pchHeader.empty()) {
2413     buildSettings->AddAttribute("GCC_PREFIX_HEADER",
2414                                 this->CreateString(pchHeader));
2415     buildSettings->AddAttribute("GCC_PRECOMPILE_PREFIX_HEADER",
2416                                 this->CreateString("YES"));
2417   }
2418
2419   // put this last so it can override existing settings
2420   // Convert "XCODE_ATTRIBUTE_*" properties directly.
2421   {
2422     for (auto const& prop : gtgt->GetPropertyKeys()) {
2423       if (cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) {
2424         std::string attribute = prop.substr(16);
2425         this->FilterConfigurationAttribute(configName, attribute);
2426         if (!attribute.empty()) {
2427           std::string const& pr = gtgt->GetSafeProperty(prop);
2428           std::string processed = cmGeneratorExpression::Evaluate(
2429             pr, this->CurrentLocalGenerator, configName);
2430           buildSettings->AddAttribute(attribute,
2431                                       this->CreateString(processed));
2432         }
2433       }
2434     }
2435   }
2436 }
2437
2438 cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget(
2439   cmGeneratorTarget* gtgt)
2440 {
2441   cmXCodeObject* shellBuildPhase =
2442     this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase);
2443   shellBuildPhase->AddAttribute("buildActionMask",
2444                                 this->CreateString("2147483647"));
2445   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2446   shellBuildPhase->AddAttribute("files", buildFiles);
2447   cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2448   shellBuildPhase->AddAttribute("inputPaths", inputPaths);
2449   cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2450   shellBuildPhase->AddAttribute("outputPaths", outputPaths);
2451   shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
2452                                 this->CreateString("0"));
2453   shellBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh"));
2454   shellBuildPhase->AddAttribute(
2455     "shellScript", this->CreateString("# shell script goes here\nexit 0"));
2456   shellBuildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
2457
2458   cmXCodeObject* target =
2459     this->CreateObject(cmXCodeObject::PBXAggregateTarget);
2460   target->SetComment(gtgt->GetName());
2461   cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2462   std::vector<cmXCodeObject*> emptyContentVector;
2463   this->CreateCustomCommands(buildPhases, nullptr, nullptr, nullptr,
2464                              emptyContentVector, nullptr, gtgt);
2465   target->AddAttribute("buildPhases", buildPhases);
2466   this->AddConfigurations(target, gtgt);
2467   cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2468   target->AddAttribute("dependencies", dependencies);
2469   target->AddAttribute("name", this->CreateString(gtgt->GetName()));
2470   target->AddAttribute("productName", this->CreateString(gtgt->GetName()));
2471   target->SetTarget(gtgt);
2472   this->XCodeObjectMap[gtgt] = target;
2473
2474   // Add source files without build rules for editing convenience.
2475   if (gtgt->GetType() == cmStateEnums::UTILITY &&
2476       gtgt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
2477     std::vector<cmSourceFile*> sources;
2478     if (!gtgt->GetConfigCommonSourceFiles(sources)) {
2479       return nullptr;
2480     }
2481
2482     // Add CMakeLists.txt file for user convenience.
2483     this->AddXCodeProjBuildRule(gtgt, sources);
2484
2485     for (auto sourceFile : sources) {
2486       if (!sourceFile->GetIsGenerated()) {
2487         this->CreateXCodeFileReference(sourceFile, gtgt);
2488       }
2489     }
2490   }
2491
2492   target->SetId(this->GetOrCreateId(gtgt->GetName(), target->GetId()));
2493
2494   return target;
2495 }
2496
2497 std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target,
2498                                                       cmGeneratorTarget* gtgt)
2499 {
2500   std::vector<std::string> const configVector = cmExpandedList(
2501     this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES"));
2502   cmXCodeObject* configlist =
2503     this->CreateObject(cmXCodeObject::XCConfigurationList);
2504   cmXCodeObject* buildConfigurations =
2505     this->CreateObject(cmXCodeObject::OBJECT_LIST);
2506   configlist->AddAttribute("buildConfigurations", buildConfigurations);
2507   std::string comment = cmStrCat("Build configuration list for ",
2508                                  cmXCodeObject::PBXTypeNames[target->GetIsA()],
2509                                  " \"", gtgt->GetName(), '"');
2510   configlist->SetComment(comment);
2511   target->AddAttribute("buildConfigurationList",
2512                        this->CreateObjectReference(configlist));
2513   for (auto const& i : configVector) {
2514     cmXCodeObject* config =
2515       this->CreateObject(cmXCodeObject::XCBuildConfiguration);
2516     buildConfigurations->AddObject(config);
2517     cmXCodeObject* buildSettings =
2518       this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
2519     this->CreateBuildSettings(gtgt, buildSettings, i);
2520     config->AddAttribute("name", this->CreateString(i));
2521     config->SetComment(i);
2522     config->AddAttribute("buildSettings", buildSettings);
2523   }
2524   if (!configVector.empty()) {
2525     configlist->AddAttribute("defaultConfigurationName",
2526                              this->CreateString(configVector[0]));
2527     configlist->AddAttribute("defaultConfigurationIsVisible",
2528                              this->CreateString("0"));
2529     return configVector[0];
2530   }
2531   return "";
2532 }
2533
2534 const char* cmGlobalXCodeGenerator::GetTargetLinkFlagsVar(
2535   cmGeneratorTarget const* target) const
2536 {
2537   if (this->XcodeVersion >= 60 &&
2538       (target->GetType() == cmStateEnums::STATIC_LIBRARY ||
2539        target->GetType() == cmStateEnums::OBJECT_LIBRARY)) {
2540     return "OTHER_LIBTOOLFLAGS";
2541   }
2542   return "OTHER_LDFLAGS";
2543 }
2544
2545 const char* cmGlobalXCodeGenerator::GetTargetFileType(
2546   cmGeneratorTarget* target)
2547 {
2548   if (cmProp e = target->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) {
2549     return e->c_str();
2550   }
2551
2552   switch (target->GetType()) {
2553     case cmStateEnums::OBJECT_LIBRARY:
2554       return "archive.ar";
2555     case cmStateEnums::STATIC_LIBRARY:
2556       return (target->GetPropertyAsBool("FRAMEWORK") ? "wrapper.framework"
2557                                                      : "archive.ar");
2558     case cmStateEnums::MODULE_LIBRARY:
2559       if (target->IsXCTestOnApple()) {
2560         return "wrapper.cfbundle";
2561       }
2562       if (target->IsCFBundleOnApple()) {
2563         return "wrapper.plug-in";
2564       }
2565       return "compiled.mach-o.executable";
2566     case cmStateEnums::SHARED_LIBRARY:
2567       return (target->GetPropertyAsBool("FRAMEWORK")
2568                 ? "wrapper.framework"
2569                 : "compiled.mach-o.dylib");
2570     case cmStateEnums::EXECUTABLE:
2571       return "compiled.mach-o.executable";
2572     default:
2573       break;
2574   }
2575   return nullptr;
2576 }
2577
2578 const char* cmGlobalXCodeGenerator::GetTargetProductType(
2579   cmGeneratorTarget* target)
2580 {
2581   if (cmProp e = target->GetProperty("XCODE_PRODUCT_TYPE")) {
2582     return e->c_str();
2583   }
2584
2585   switch (target->GetType()) {
2586     case cmStateEnums::OBJECT_LIBRARY:
2587       return "com.apple.product-type.library.static";
2588     case cmStateEnums::STATIC_LIBRARY:
2589       return (target->GetPropertyAsBool("FRAMEWORK")
2590                 ? "com.apple.product-type.framework"
2591                 : "com.apple.product-type.library.static");
2592     case cmStateEnums::MODULE_LIBRARY:
2593       if (target->IsXCTestOnApple()) {
2594         return "com.apple.product-type.bundle.unit-test";
2595       } else if (target->IsCFBundleOnApple()) {
2596         return "com.apple.product-type.bundle";
2597       } else {
2598         return "com.apple.product-type.tool";
2599       }
2600     case cmStateEnums::SHARED_LIBRARY:
2601       return (target->GetPropertyAsBool("FRAMEWORK")
2602                 ? "com.apple.product-type.framework"
2603                 : "com.apple.product-type.library.dynamic");
2604     case cmStateEnums::EXECUTABLE:
2605       return (target->GetPropertyAsBool("MACOSX_BUNDLE")
2606                 ? "com.apple.product-type.application"
2607                 : "com.apple.product-type.tool");
2608     default:
2609       break;
2610   }
2611   return nullptr;
2612 }
2613
2614 cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeTarget(
2615   cmGeneratorTarget* gtgt, cmXCodeObject* buildPhases)
2616 {
2617   if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
2618     return nullptr;
2619   }
2620   cmXCodeObject* target = this->CreateObject(cmXCodeObject::PBXNativeTarget);
2621   target->AddAttribute("buildPhases", buildPhases);
2622   cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2623   target->AddAttribute("buildRules", buildRules);
2624   std::string defConfig;
2625   defConfig = this->AddConfigurations(target, gtgt);
2626   cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST);
2627   target->AddAttribute("dependencies", dependencies);
2628   target->AddAttribute("name", this->CreateString(gtgt->GetName()));
2629   target->AddAttribute("productName", this->CreateString(gtgt->GetName()));
2630
2631   cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
2632   if (const char* fileType = this->GetTargetFileType(gtgt)) {
2633     fileRef->AddAttribute("explicitFileType", this->CreateString(fileType));
2634   }
2635   std::string fullName;
2636   if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
2637     fullName = cmStrCat("lib", gtgt->GetName(), ".a");
2638   } else {
2639     fullName = gtgt->GetFullName(defConfig);
2640   }
2641   fileRef->AddAttribute("path", this->CreateString(fullName));
2642   fileRef->AddAttribute("sourceTree",
2643                         this->CreateString("BUILT_PRODUCTS_DIR"));
2644   fileRef->SetComment(gtgt->GetName());
2645   target->AddAttribute("productReference",
2646                        this->CreateObjectReference(fileRef));
2647   if (const char* productType = this->GetTargetProductType(gtgt)) {
2648     target->AddAttribute("productType", this->CreateString(productType));
2649   }
2650   target->SetTarget(gtgt);
2651   this->XCodeObjectMap[gtgt] = target;
2652   target->SetId(this->GetOrCreateId(gtgt->GetName(), target->GetId()));
2653   return target;
2654 }
2655
2656 cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget(
2657   cmGeneratorTarget const* t)
2658 {
2659   if (!t) {
2660     return nullptr;
2661   }
2662
2663   auto const i = this->XCodeObjectMap.find(t);
2664   if (i == this->XCodeObjectMap.end()) {
2665     return nullptr;
2666   }
2667   return i->second;
2668 }
2669
2670 std::string cmGlobalXCodeGenerator::GetOrCreateId(const std::string& name,
2671                                                   const std::string& id)
2672 {
2673   std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
2674   const char* storedGUID =
2675     this->CMakeInstance->GetCacheDefinition(guidStoreName);
2676
2677   if (storedGUID) {
2678     return storedGUID;
2679   }
2680
2681   this->CMakeInstance->AddCacheEntry(guidStoreName, id.c_str(),
2682                                      "Stored Xcode object GUID",
2683                                      cmStateEnums::INTERNAL);
2684
2685   return id;
2686 }
2687
2688 void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target,
2689                                              cmXCodeObject* dependTarget)
2690 {
2691   // This is called once for every edge in the target dependency graph.
2692   cmXCodeObject* container =
2693     this->CreateObject(cmXCodeObject::PBXContainerItemProxy);
2694   container->SetComment("PBXContainerItemProxy");
2695   container->AddAttribute("containerPortal",
2696                           this->CreateObjectReference(this->RootObject));
2697   container->AddAttribute("proxyType", this->CreateString("1"));
2698   container->AddAttribute("remoteGlobalIDString",
2699                           this->CreateObjectReference(dependTarget));
2700   container->AddAttribute(
2701     "remoteInfo", this->CreateString(dependTarget->GetTarget()->GetName()));
2702   cmXCodeObject* targetdep =
2703     this->CreateObject(cmXCodeObject::PBXTargetDependency);
2704   targetdep->SetComment("PBXTargetDependency");
2705   targetdep->AddAttribute("target", this->CreateObjectReference(dependTarget));
2706   targetdep->AddAttribute("targetProxy",
2707                           this->CreateObjectReference(container));
2708
2709   cmXCodeObject* depends = target->GetObject("dependencies");
2710   if (!depends) {
2711     cmSystemTools::Error(
2712       "target does not have dependencies attribute error..");
2713
2714   } else {
2715     depends->AddUniqueObject(targetdep);
2716   }
2717 }
2718
2719 void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
2720                                                      const char* attribute,
2721                                                      const char* value)
2722 {
2723   if (settings) {
2724     cmXCodeObject* attr = settings->GetObject(attribute);
2725     if (!attr) {
2726       settings->AddAttribute(attribute, this->CreateString(value));
2727     } else {
2728       std::string oldValue = cmStrCat(attr->GetString(), ' ', value);
2729       attr->SetString(oldValue);
2730     }
2731   }
2732 }
2733
2734 void cmGlobalXCodeGenerator::AppendBuildSettingAttribute(
2735   cmXCodeObject* target, const char* attribute, const char* value,
2736   const std::string& configName)
2737 {
2738   // There are multiple configurations.  Add the setting to the
2739   // buildSettings of the configuration name given.
2740   cmXCodeObject* configurationList =
2741     target->GetObject("buildConfigurationList")->GetObject();
2742   cmXCodeObject* buildConfigs =
2743     configurationList->GetObject("buildConfigurations");
2744   for (auto obj : buildConfigs->GetObjectList()) {
2745     if (configName.empty() ||
2746         obj->GetObject("name")->GetString() == configName) {
2747       cmXCodeObject* settings = obj->GetObject("buildSettings");
2748       this->AppendOrAddBuildSetting(settings, attribute, value);
2749     }
2750   }
2751 }
2752
2753 void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
2754 {
2755   cmGeneratorTarget* gt = target->GetTarget();
2756   if (!gt) {
2757     cmSystemTools::Error("Error no target on xobject\n");
2758     return;
2759   }
2760   if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
2761     return;
2762   }
2763
2764   // Add dependencies on other CMake targets.
2765   for (const auto& dep : this->GetTargetDirectDepends(gt)) {
2766     if (cmXCodeObject* dptarget = this->FindXCodeTarget(dep)) {
2767       this->AddDependTarget(target, dptarget);
2768     }
2769   }
2770
2771   // Loop over configuration types and set per-configuration info.
2772   for (auto const& configName : this->CurrentConfigurationTypes) {
2773     {
2774       // Add object library contents as link flags.
2775       std::string linkObjs;
2776       const char* sep = "";
2777       std::vector<cmSourceFile const*> objs;
2778       gt->GetExternalObjects(objs, configName);
2779       for (auto sourceFile : objs) {
2780         if (sourceFile->GetObjectLibrary().empty()) {
2781           continue;
2782         }
2783         linkObjs += sep;
2784         sep = " ";
2785         linkObjs += this->XCodeEscapePath(sourceFile->GetFullPath());
2786       }
2787       this->AppendBuildSettingAttribute(
2788         target, this->GetTargetLinkFlagsVar(gt), linkObjs.c_str(), configName);
2789     }
2790
2791     // Skip link information for object libraries.
2792     if (gt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
2793         gt->GetType() == cmStateEnums::STATIC_LIBRARY) {
2794       continue;
2795     }
2796
2797     // Compute the link library and directory information.
2798     cmComputeLinkInformation* pcli = gt->GetLinkInformation(configName);
2799     if (!pcli) {
2800       continue;
2801     }
2802     cmComputeLinkInformation& cli = *pcli;
2803
2804     // Add dependencies directly on library files.
2805     for (auto const& libDep : cli.GetDepends()) {
2806       target->AddDependLibrary(configName, libDep);
2807     }
2808
2809     // add the library search paths
2810     {
2811       std::string linkDirs;
2812       for (auto const& libDir : cli.GetDirectories()) {
2813         if (!libDir.empty() && libDir != "/usr/lib") {
2814           // Now add the same one but append
2815           // $(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) to it:
2816           linkDirs += " ";
2817           linkDirs += this->XCodeEscapePath(
2818             libDir + "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)");
2819           linkDirs += " ";
2820           linkDirs += this->XCodeEscapePath(libDir);
2821         }
2822       }
2823       this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
2824                                         linkDirs.c_str(), configName);
2825     }
2826
2827     // now add the link libraries
2828     {
2829       std::string linkLibs;
2830       const char* sep = "";
2831       for (auto const& libName : cli.GetItems()) {
2832         linkLibs += sep;
2833         sep = " ";
2834         if (libName.IsPath) {
2835           linkLibs += this->XCodeEscapePath(libName.Value.Value);
2836         } else if (!libName.Target ||
2837                    libName.Target->GetType() !=
2838                      cmStateEnums::INTERFACE_LIBRARY) {
2839           linkLibs += libName.Value.Value;
2840         }
2841         if (libName.Target && !libName.Target->IsImported()) {
2842           target->AddDependTarget(configName, libName.Target->GetName());
2843         }
2844       }
2845       this->AppendBuildSettingAttribute(
2846         target, this->GetTargetLinkFlagsVar(gt), linkLibs.c_str(), configName);
2847     }
2848   }
2849 }
2850
2851 bool cmGlobalXCodeGenerator::CreateGroups(
2852   std::vector<cmLocalGenerator*>& generators)
2853 {
2854   for (auto& generator : generators) {
2855     cmMakefile* mf = generator->GetMakefile();
2856     std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
2857     for (const auto& gtgt : generator->GetGeneratorTargets()) {
2858       // Same skipping logic here as in CreateXCodeTargets so that we do not
2859       // end up with (empty anyhow) ZERO_CHECK, install, or test source
2860       // groups:
2861       //
2862       if (gtgt->GetType() == cmStateEnums::GLOBAL_TARGET) {
2863         continue;
2864       }
2865       if (gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
2866         continue;
2867       }
2868       if (gtgt->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
2869         continue;
2870       }
2871
2872       auto addSourceToGroup = [this, mf, &gtgt,
2873                                &sourceGroups](std::string const& source) {
2874         cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups);
2875         cmXCodeObject* pbxgroup =
2876           this->CreateOrGetPBXGroup(gtgt.get(), sourceGroup);
2877         std::string key = GetGroupMapKeyFromPath(gtgt.get(), source);
2878         this->GroupMap[key] = pbxgroup;
2879       };
2880
2881       // Put cmSourceFile instances in proper groups:
2882       for (auto const& si : gtgt->GetAllConfigSources()) {
2883         cmSourceFile const* sf = si.Source;
2884         if (!sf->GetObjectLibrary().empty()) {
2885           // Object library files go on the link line instead.
2886           continue;
2887         }
2888         addSourceToGroup(sf->GetFullPath());
2889       }
2890
2891       // Add CMakeLists.txt file for user convenience.
2892       {
2893         std::string listfile =
2894           cmStrCat(gtgt->GetLocalGenerator()->GetCurrentSourceDirectory(),
2895                    "/CMakeLists.txt");
2896         cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(
2897           listfile, false, cmSourceFileLocationKind::Known);
2898         addSourceToGroup(sf->ResolveFullPath());
2899       }
2900
2901       // Add the Info.plist we are about to generate for an App Bundle.
2902       if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
2903         std::string plist = this->ComputeInfoPListLocation(gtgt.get());
2904         cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource(
2905           plist, true, cmSourceFileLocationKind::Known);
2906         addSourceToGroup(sf->ResolveFullPath());
2907       }
2908     }
2909   }
2910   return true;
2911 }
2912
2913 cmXCodeObject* cmGlobalXCodeGenerator::CreatePBXGroup(cmXCodeObject* parent,
2914                                                       const std::string& name)
2915 {
2916   cmXCodeObject* parentChildren = nullptr;
2917   if (parent) {
2918     parentChildren = parent->GetObject("children");
2919   }
2920   cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup);
2921   cmXCodeObject* groupChildren =
2922     this->CreateObject(cmXCodeObject::OBJECT_LIST);
2923   group->AddAttribute("name", this->CreateString(name));
2924   group->AddAttribute("children", groupChildren);
2925   group->AddAttribute("sourceTree", this->CreateString("<group>"));
2926   if (parentChildren) {
2927     parentChildren->AddObject(group);
2928   }
2929   return group;
2930 }
2931
2932 cmXCodeObject* cmGlobalXCodeGenerator::CreateOrGetPBXGroup(
2933   cmGeneratorTarget* gtgt, cmSourceGroup* sg)
2934 {
2935   std::string s;
2936   std::string target;
2937   const std::string targetFolder = gtgt->GetEffectiveFolderName();
2938   if (!targetFolder.empty()) {
2939     target = cmStrCat(targetFolder, '/');
2940   }
2941   target += gtgt->GetName();
2942   s = cmStrCat(target, '/', sg->GetFullName());
2943   auto it = this->GroupNameMap.find(s);
2944   if (it != this->GroupNameMap.end()) {
2945     return it->second;
2946   }
2947
2948   it = this->TargetGroup.find(target);
2949   cmXCodeObject* tgroup = nullptr;
2950   if (it != this->TargetGroup.end()) {
2951     tgroup = it->second;
2952   } else {
2953     std::vector<std::string> tgt_folders = cmTokenize(target, "/");
2954     std::string curr_tgt_folder;
2955     for (std::vector<std::string>::size_type i = 0; i < tgt_folders.size();
2956          i++) {
2957       if (i != 0) {
2958         curr_tgt_folder += "/";
2959       }
2960       curr_tgt_folder += tgt_folders[i];
2961       it = this->TargetGroup.find(curr_tgt_folder);
2962       if (it != this->TargetGroup.end()) {
2963         tgroup = it->second;
2964         continue;
2965       }
2966       tgroup = this->CreatePBXGroup(tgroup, tgt_folders[i]);
2967       this->TargetGroup[curr_tgt_folder] = tgroup;
2968       if (i == 0) {
2969         this->MainGroupChildren->AddObject(tgroup);
2970       }
2971     }
2972   }
2973   this->TargetGroup[target] = tgroup;
2974
2975   // If it's the default source group (empty name) then put the source file
2976   // directly in the tgroup...
2977   //
2978   if (sg->GetFullName().empty()) {
2979     this->GroupNameMap[s] = tgroup;
2980     return tgroup;
2981   }
2982
2983   // It's a recursive folder structure, let's find the real parent group
2984   if (sg->GetFullName() != sg->GetName()) {
2985     std::string curr_folder = cmStrCat(target, '/');
2986     for (auto const& folder : cmTokenize(sg->GetFullName(), "\\")) {
2987       curr_folder += folder;
2988       auto const i_folder = this->GroupNameMap.find(curr_folder);
2989       // Create new folder
2990       if (i_folder == this->GroupNameMap.end()) {
2991         cmXCodeObject* group = this->CreatePBXGroup(tgroup, folder);
2992         this->GroupNameMap[curr_folder] = group;
2993         tgroup = group;
2994       } else {
2995         tgroup = i_folder->second;
2996       }
2997       curr_folder += "\\";
2998     }
2999     return tgroup;
3000   }
3001   cmXCodeObject* group = this->CreatePBXGroup(tgroup, sg->GetName());
3002   this->GroupNameMap[s] = group;
3003   return group;
3004 }
3005
3006 bool cmGlobalXCodeGenerator::CreateXCodeObjects(
3007   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
3008 {
3009   this->ClearXCodeObjects();
3010   this->RootObject = nullptr;
3011   this->MainGroupChildren = nullptr;
3012   cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
3013   group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
3014   cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
3015   for (const std::string& CurrentConfigurationType :
3016        this->CurrentConfigurationTypes) {
3017     cmXCodeObject* buildStyle =
3018       this->CreateObject(cmXCodeObject::PBXBuildStyle);
3019     const std::string& name = CurrentConfigurationType;
3020     buildStyle->AddAttribute("name", this->CreateString(name));
3021     buildStyle->SetComment(name);
3022     cmXCodeObject* sgroup = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
3023     sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
3024     buildStyle->AddAttribute("buildSettings", sgroup);
3025     listObjs->AddObject(buildStyle);
3026   }
3027
3028   cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup);
3029   this->MainGroupChildren = this->CreateObject(cmXCodeObject::OBJECT_LIST);
3030   mainGroup->AddAttribute("children", this->MainGroupChildren);
3031   mainGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
3032
3033   // now create the cmake groups
3034   if (!this->CreateGroups(generators)) {
3035     return false;
3036   }
3037
3038   cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup);
3039   productGroup->AddAttribute("name", this->CreateString("Products"));
3040   productGroup->AddAttribute("sourceTree", this->CreateString("<group>"));
3041   cmXCodeObject* productGroupChildren =
3042     this->CreateObject(cmXCodeObject::OBJECT_LIST);
3043   productGroup->AddAttribute("children", productGroupChildren);
3044   this->MainGroupChildren->AddObject(productGroup);
3045
3046   this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
3047   this->RootObject->SetComment("Project object");
3048
3049   std::string project_id = cmStrCat("PROJECT_", root->GetProjectName());
3050   this->RootObject->SetId(
3051     this->GetOrCreateId(project_id, this->RootObject->GetId()));
3052
3053   group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
3054   this->RootObject->AddAttribute("mainGroup",
3055                                  this->CreateObjectReference(mainGroup));
3056   this->RootObject->AddAttribute("buildSettings", group);
3057   this->RootObject->AddAttribute("buildStyles", listObjs);
3058   this->RootObject->AddAttribute("hasScannedForEncodings",
3059                                  this->CreateString("0"));
3060   group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
3061   group->AddAttribute("BuildIndependentTargetsInParallel",
3062                       this->CreateString("YES"));
3063   std::ostringstream v;
3064   v << std::setfill('0') << std::setw(4) << XcodeVersion * 10;
3065   group->AddAttribute("LastUpgradeCheck", this->CreateString(v.str()));
3066   this->RootObject->AddAttribute("attributes", group);
3067   this->RootObject->AddAttribute("compatibilityVersion",
3068                                  this->CreateString("Xcode 3.2"));
3069   // Point Xcode at the top of the source tree.
3070   {
3071     std::string pdir =
3072       this->RelativeToBinary(root->GetCurrentSourceDirectory());
3073     this->RootObject->AddAttribute("projectDirPath", this->CreateString(pdir));
3074     this->RootObject->AddAttribute("projectRoot", this->CreateString(""));
3075   }
3076   cmXCodeObject* configlist =
3077     this->CreateObject(cmXCodeObject::XCConfigurationList);
3078   cmXCodeObject* buildConfigurations =
3079     this->CreateObject(cmXCodeObject::OBJECT_LIST);
3080   using Configs = std::vector<std::pair<std::string, cmXCodeObject*>>;
3081   Configs configs;
3082   std::string defaultConfigName;
3083   for (const auto& name : this->CurrentConfigurationTypes) {
3084     if (defaultConfigName.empty()) {
3085       defaultConfigName = name;
3086     }
3087     cmXCodeObject* config =
3088       this->CreateObject(cmXCodeObject::XCBuildConfiguration);
3089     config->AddAttribute("name", this->CreateString(name));
3090     configs.push_back(std::make_pair(name, config));
3091   }
3092   if (defaultConfigName.empty()) {
3093     defaultConfigName = "Debug";
3094   }
3095   for (auto& config : configs) {
3096     buildConfigurations->AddObject(config.second);
3097   }
3098   configlist->AddAttribute("buildConfigurations", buildConfigurations);
3099
3100   std::string comment = cmStrCat("Build configuration list for PBXProject \"",
3101                                  this->CurrentProject, '"');
3102   configlist->SetComment(comment);
3103   configlist->AddAttribute("defaultConfigurationIsVisible",
3104                            this->CreateString("0"));
3105   configlist->AddAttribute("defaultConfigurationName",
3106                            this->CreateString(defaultConfigName));
3107   cmXCodeObject* buildSettings =
3108     this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
3109   const char* sysroot =
3110     this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT");
3111   const char* deploymentTarget =
3112     this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
3113   if (sysroot) {
3114     buildSettings->AddAttribute("SDKROOT", this->CreateString(sysroot));
3115   }
3116   // recompute this as it may have been changed since enable language
3117   this->ComputeArchitectures(this->CurrentMakefile);
3118   std::string const archs = cmJoin(this->Architectures, " ");
3119   if (archs.empty()) {
3120     // Tell Xcode to use NATIVE_ARCH instead of ARCHS.
3121     buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("YES"));
3122     // When targeting macOS, use only the host architecture.
3123     if (this->SystemName == "Darwin"_s &&
3124         (!sysroot || !*sysroot ||
3125          cmSystemTools::LowerCase(sysroot).find("macos") !=
3126            std::string::npos)) {
3127       buildSettings->AddAttribute("ARCHS",
3128                                   this->CreateString("$(NATIVE_ARCH_ACTUAL)"));
3129     }
3130   } else {
3131     // Tell Xcode to use ARCHS (ONLY_ACTIVE_ARCH defaults to NO).
3132     buildSettings->AddAttribute("ARCHS", this->CreateString(archs));
3133   }
3134   if (deploymentTarget && *deploymentTarget) {
3135     buildSettings->AddAttribute(GetDeploymentPlatform(root->GetMakefile()),
3136                                 this->CreateString(deploymentTarget));
3137   }
3138   if (!this->GeneratorToolset.empty()) {
3139     buildSettings->AddAttribute("GCC_VERSION",
3140                                 this->CreateString(this->GeneratorToolset));
3141   }
3142   if (this->GetLanguageEnabled("Swift")) {
3143     std::string swiftVersion;
3144     if (const char* vers = this->CurrentMakefile->GetDefinition(
3145           "CMAKE_Swift_LANGUAGE_VERSION")) {
3146       swiftVersion = vers;
3147     } else if (this->XcodeVersion >= 102) {
3148       swiftVersion = "4.0";
3149     } else if (this->XcodeVersion >= 83) {
3150       swiftVersion = "3.0";
3151     } else {
3152       swiftVersion = "2.3";
3153     }
3154     buildSettings->AddAttribute("SWIFT_VERSION",
3155                                 this->CreateString(swiftVersion));
3156   }
3157
3158   std::string symroot = cmStrCat(root->GetCurrentBinaryDirectory(), "/build");
3159   buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot));
3160
3161   // Inside a try_compile project, do not require signing on any platform.
3162   if (this->CMakeInstance->GetIsInTryCompile()) {
3163     buildSettings->AddAttribute("CODE_SIGNING_ALLOWED",
3164                                 this->CreateString("NO"));
3165   }
3166
3167   for (auto& config : configs) {
3168     cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings);
3169
3170     // Put this last so it can override existing settings
3171     // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly.
3172     for (const auto& var : this->CurrentMakefile->GetDefinitions()) {
3173       if (cmHasLiteralPrefix(var, "CMAKE_XCODE_ATTRIBUTE_")) {
3174         std::string attribute = var.substr(22);
3175         this->FilterConfigurationAttribute(config.first, attribute);
3176         if (!attribute.empty()) {
3177           std::string processed = cmGeneratorExpression::Evaluate(
3178             this->CurrentMakefile->GetSafeDefinition(var),
3179             this->CurrentLocalGenerator, config.first);
3180           buildSettingsForCfg->AddAttribute(attribute,
3181                                             this->CreateString(processed));
3182         }
3183       }
3184     }
3185     // store per-config buildSettings into configuration object
3186     config.second->AddAttribute("buildSettings", buildSettingsForCfg);
3187   }
3188
3189   this->RootObject->AddAttribute("buildConfigurationList",
3190                                  this->CreateObjectReference(configlist));
3191
3192   std::vector<cmXCodeObject*> targets;
3193   for (auto& generator : generators) {
3194     if (!this->CreateXCodeTargets(generator, targets)) {
3195       return false;
3196     }
3197   }
3198   // loop over all targets and add link and depend info
3199   for (auto t : targets) {
3200     this->AddDependAndLinkInformation(t);
3201   }
3202   this->CreateXCodeDependHackTarget(targets);
3203   // now add all targets to the root object
3204   cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST);
3205   for (auto t : targets) {
3206     allTargets->AddObject(t);
3207     cmXCodeObject* productRef = t->GetObject("productReference");
3208     if (productRef) {
3209       productGroupChildren->AddObject(productRef->GetObject());
3210     }
3211   }
3212   this->RootObject->AddAttribute("targets", allTargets);
3213   return true;
3214 }
3215
3216 std::string cmGlobalXCodeGenerator::GetObjectsDirectory(
3217   const std::string& projName, const std::string& configName,
3218   const cmGeneratorTarget* t, const std::string& variant) const
3219 {
3220   std::string dir = cmStrCat(
3221     t->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', projName,
3222     ".build/", configName, '/', t->GetName(), ".build/", variant);
3223   return dir;
3224 }
3225
3226 void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf)
3227 {
3228   this->Architectures.clear();
3229   const char* sysroot = mf->GetDefinition("CMAKE_OSX_SYSROOT");
3230   if (sysroot) {
3231     mf->GetDefExpandList("CMAKE_OSX_ARCHITECTURES", this->Architectures);
3232   }
3233
3234   if (this->Architectures.empty()) {
3235     // With no ARCHS we use ONLY_ACTIVE_ARCH and possibly a
3236     // platform-specific default ARCHS placeholder value.
3237     // Look up the arch that Xcode chooses in this case.
3238     if (const char* arch = mf->GetDefinition("CMAKE_XCODE_ARCHS")) {
3239       this->ObjectDirArchDefault = arch;
3240       // We expect only one arch but choose the first just in case.
3241       std::string::size_type pos = this->ObjectDirArchDefault.find(';');
3242       if (pos != std::string::npos) {
3243         this->ObjectDirArchDefault = this->ObjectDirArchDefault.substr(0, pos);
3244       }
3245     }
3246   }
3247
3248   this->ComputeObjectDirArch(mf);
3249 }
3250
3251 void cmGlobalXCodeGenerator::ComputeObjectDirArch(cmMakefile* mf)
3252 {
3253   if (this->Architectures.size() > 1 || this->UseEffectivePlatformName(mf)) {
3254     this->ObjectDirArch = "$(CURRENT_ARCH)";
3255   } else if (!this->Architectures.empty()) {
3256     this->ObjectDirArch = this->Architectures[0];
3257   } else {
3258     this->ObjectDirArch = this->ObjectDirArchDefault;
3259   }
3260 }
3261
3262 void cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
3263   std::vector<cmXCodeObject*>& targets)
3264 {
3265   cmGeneratedFileStream makefileStream(this->CurrentXCodeHackMakefile);
3266   if (!makefileStream) {
3267     cmSystemTools::Error("Could not create " + this->CurrentXCodeHackMakefile);
3268     return;
3269   }
3270   makefileStream.SetCopyIfDifferent(true);
3271   // one more pass for external depend information not handled
3272   // correctly by xcode
3273   /* clang-format off */
3274   makefileStream << "# DO NOT EDIT\n";
3275   makefileStream << "# This makefile makes sure all linkable targets are\n";
3276   makefileStream << "# up-to-date with anything they link to\n"
3277     "default:\n"
3278     "\techo \"Do not invoke directly\"\n"
3279     "\n";
3280   /* clang-format on */
3281
3282   std::set<std::string> dummyRules;
3283
3284   // Write rules to help Xcode relink things at the right time.
3285   /* clang-format off */
3286   makefileStream <<
3287     "# Rules to remove targets that are older than anything to which they\n"
3288     "# link.  This forces Xcode to relink the targets from scratch.  It\n"
3289     "# does not seem to check these dependencies itself.\n";
3290   /* clang-format on */
3291   for (const auto& configName : this->CurrentConfigurationTypes) {
3292     for (auto target : targets) {
3293       cmGeneratorTarget* gt = target->GetTarget();
3294
3295       if (gt->GetType() == cmStateEnums::EXECUTABLE ||
3296           gt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
3297           gt->GetType() == cmStateEnums::STATIC_LIBRARY ||
3298           gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
3299           gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
3300         // Declare an entry point for the target post-build phase.
3301         makefileStream << this->PostBuildMakeTarget(gt->GetName(), configName)
3302                        << ":\n";
3303       }
3304
3305       if (gt->GetType() == cmStateEnums::EXECUTABLE ||
3306           gt->GetType() == cmStateEnums::STATIC_LIBRARY ||
3307           gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
3308           gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
3309         std::string tfull = gt->GetFullPath(configName);
3310         std::string trel = this->ConvertToRelativeForMake(tfull);
3311
3312         // Add this target to the post-build phases of its dependencies.
3313         auto const y = target->GetDependTargets().find(configName);
3314         if (y != target->GetDependTargets().end()) {
3315           for (auto const& deptgt : y->second) {
3316             makefileStream << this->PostBuildMakeTarget(deptgt, configName)
3317                            << ": " << trel << "\n";
3318           }
3319         }
3320
3321         std::vector<cmGeneratorTarget*> objlibs;
3322         gt->GetObjectLibrariesCMP0026(objlibs);
3323         for (auto objLib : objlibs) {
3324           makefileStream << this->PostBuildMakeTarget(objLib->GetName(),
3325                                                       configName)
3326                          << ": " << trel << "\n";
3327         }
3328
3329         // Create a rule for this target.
3330         makefileStream << trel << ":";
3331
3332         // List dependencies if any exist.
3333         auto const x = target->GetDependLibraries().find(configName);
3334         if (x != target->GetDependLibraries().end()) {
3335           for (auto const& deplib : x->second) {
3336             std::string file = this->ConvertToRelativeForMake(deplib);
3337             makefileStream << "\\\n\t" << file;
3338             dummyRules.insert(file);
3339           }
3340         }
3341
3342         for (auto objLib : objlibs) {
3343
3344           const std::string objLibName = objLib->GetName();
3345           std::string d = cmStrCat(
3346             this->GetObjectsDirectory(this->CurrentProject, configName, objLib,
3347                                       OBJECT_LIBRARY_ARTIFACT_DIR),
3348             "lib", objLibName, ".a");
3349
3350           std::string dependency = this->ConvertToRelativeForMake(d);
3351           makefileStream << "\\\n\t" << dependency;
3352           dummyRules.insert(dependency);
3353         }
3354
3355         // Write the action to remove the target if it is out of date.
3356         makefileStream << "\n";
3357         makefileStream << "\t/bin/rm -f "
3358                        << this->ConvertToRelativeForMake(tfull) << "\n";
3359         // if building for more than one architecture
3360         // then remove those executables as well
3361         if (this->Architectures.size() > 1) {
3362           std::string universal = this->GetObjectsDirectory(
3363             this->CurrentProject, configName, gt, "$(OBJDIR)/");
3364           for (const auto& architecture : this->Architectures) {
3365             std::string universalFile = cmStrCat(universal, architecture, '/',
3366                                                  gt->GetFullName(configName));
3367             makefileStream << "\t/bin/rm -f "
3368                            << this->ConvertToRelativeForMake(universalFile)
3369                            << "\n";
3370           }
3371         }
3372         makefileStream << "\n\n";
3373       }
3374     }
3375   }
3376
3377   makefileStream << "\n\n"
3378                  << "# For each target create a dummy rule"
3379                  << "so the target does not have to exist\n";
3380   for (auto const& dummyRule : dummyRules) {
3381     makefileStream << dummyRule << ":\n";
3382   }
3383 }
3384
3385 void cmGlobalXCodeGenerator::OutputXCodeProject(
3386   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
3387 {
3388   if (generators.empty()) {
3389     return;
3390   }
3391   if (!this->CreateXCodeObjects(root, generators)) {
3392     return;
3393   }
3394   std::string xcodeDir = cmStrCat(root->GetCurrentBinaryDirectory(), '/',
3395                                   root->GetProjectName(), ".xcodeproj");
3396   cmSystemTools::MakeDirectory(xcodeDir);
3397   std::string xcodeProjFile = xcodeDir + "/project.pbxproj";
3398   cmGeneratedFileStream fout(xcodeProjFile);
3399   fout.SetCopyIfDifferent(true);
3400   if (!fout) {
3401     return;
3402   }
3403   this->WriteXCodePBXProj(fout, root, generators);
3404
3405   bool hasGeneratedSchemes = this->OutputXCodeSharedSchemes(xcodeDir, root);
3406   this->OutputXCodeWorkspaceSettings(xcodeDir, hasGeneratedSchemes);
3407
3408   this->ClearXCodeObjects();
3409
3410   // Since this call may have created new cache entries, save the cache:
3411   //
3412   root->GetMakefile()->GetCMakeInstance()->SaveCache(
3413     root->GetBinaryDirectory());
3414 }
3415
3416 bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes(
3417   const std::string& xcProjDir, cmLocalGenerator* root)
3418 {
3419   // collect all tests for the targets
3420   std::map<std::string, cmXCodeScheme::TestObjects> testables;
3421
3422   for (const auto& obj : this->XCodeObjects) {
3423     if (obj->GetType() != cmXCodeObject::OBJECT ||
3424         obj->GetIsA() != cmXCodeObject::PBXNativeTarget) {
3425       continue;
3426     }
3427
3428     if (!obj->GetTarget()->IsXCTestOnApple()) {
3429       continue;
3430     }
3431
3432     cmProp testee = obj->GetTarget()->GetProperty("XCTEST_TESTEE");
3433     if (!testee) {
3434       continue;
3435     }
3436
3437     testables[*testee].push_back(obj.get());
3438   }
3439
3440   // generate scheme
3441   bool ret = false;
3442
3443   // Since the lowest available Xcode version for testing was 6.4,
3444   // I'm setting this as a limit then
3445   if (this->XcodeVersion >= 64) {
3446     for (const auto& obj : this->XCodeObjects) {
3447       if (obj->GetType() == cmXCodeObject::OBJECT &&
3448           (obj->GetIsA() == cmXCodeObject::PBXNativeTarget ||
3449            obj->GetIsA() == cmXCodeObject::PBXAggregateTarget) &&
3450           (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() ||
3451            obj->GetTarget()->GetPropertyAsBool("XCODE_GENERATE_SCHEME"))) {
3452         const std::string& targetName = obj->GetTarget()->GetName();
3453         cmXCodeScheme schm(root, obj.get(), testables[targetName],
3454                            this->CurrentConfigurationTypes,
3455                            this->XcodeVersion);
3456         schm.WriteXCodeSharedScheme(xcProjDir,
3457                                     this->RelativeToSource(xcProjDir));
3458         ret = true;
3459       }
3460     }
3461   }
3462
3463   return ret;
3464 }
3465
3466 void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings(
3467   const std::string& xcProjDir, bool hasGeneratedSchemes)
3468 {
3469   std::string xcodeSharedDataDir =
3470     cmStrCat(xcProjDir, "/project.xcworkspace/xcshareddata");
3471   cmSystemTools::MakeDirectory(xcodeSharedDataDir);
3472
3473   std::string workspaceSettingsFile =
3474     cmStrCat(xcodeSharedDataDir, "/WorkspaceSettings.xcsettings");
3475
3476   cmGeneratedFileStream fout(workspaceSettingsFile);
3477   fout.SetCopyIfDifferent(true);
3478   if (!fout) {
3479     return;
3480   }
3481
3482   cmXMLWriter xout(fout);
3483   xout.StartDocument();
3484   xout.Doctype("plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\""
3485                "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"");
3486   xout.StartElement("plist");
3487   xout.Attribute("version", "1.0");
3488   xout.StartElement("dict");
3489   if (this->XcodeVersion >= 100) {
3490     xout.Element("key", "BuildSystemType");
3491     xout.Element("string", "Original");
3492     xout.Element("key", "DisableBuildSystemDeprecationWarning");
3493     xout.Element("true");
3494   }
3495   if (hasGeneratedSchemes) {
3496     xout.Element("key",
3497                  "IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded");
3498     xout.Element("false");
3499   }
3500   xout.EndElement(); // dict
3501   xout.EndElement(); // plist
3502   xout.EndDocument();
3503 }
3504
3505 void cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout,
3506                                                cmLocalGenerator*,
3507                                                std::vector<cmLocalGenerator*>&)
3508 {
3509   SortXCodeObjects();
3510
3511   fout << "// !$*UTF8*$!\n";
3512   fout << "{\n";
3513   cmXCodeObject::Indent(1, fout);
3514   fout << "archiveVersion = 1;\n";
3515   cmXCodeObject::Indent(1, fout);
3516   fout << "classes = {\n";
3517   cmXCodeObject::Indent(1, fout);
3518   fout << "};\n";
3519   cmXCodeObject::Indent(1, fout);
3520   fout << "objectVersion = 46;\n";
3521   cmXCode21Object::PrintList(this->XCodeObjects, fout);
3522   cmXCodeObject::Indent(1, fout);
3523   fout << "rootObject = " << this->RootObject->GetId()
3524        << " /* Project object */;\n";
3525   fout << "}\n";
3526 }
3527
3528 const char* cmGlobalXCodeGenerator::GetCMakeCFGIntDir() const
3529 {
3530   return "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
3531 }
3532
3533 std::string cmGlobalXCodeGenerator::ExpandCFGIntDir(
3534   const std::string& str, const std::string& config) const
3535 {
3536   std::string replace1 = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)";
3537   std::string replace2 = "$(CONFIGURATION)";
3538
3539   std::string tmp = str;
3540   for (std::string::size_type i = tmp.find(replace1); i != std::string::npos;
3541        i = tmp.find(replace1, i)) {
3542     tmp.replace(i, replace1.size(), config);
3543     i += config.size();
3544   }
3545   for (std::string::size_type i = tmp.find(replace2); i != std::string::npos;
3546        i = tmp.find(replace2, i)) {
3547     tmp.replace(i, replace2.size(), config);
3548     i += config.size();
3549   }
3550   return tmp;
3551 }
3552
3553 void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry)
3554 {
3555   entry.Name = cmGlobalXCodeGenerator::GetActualName();
3556   entry.Brief = "Generate Xcode project files.";
3557 }
3558
3559 std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(
3560   std::string const& p)
3561 {
3562   return cmSystemTools::ConvertToOutputPath(p);
3563 }
3564
3565 std::string cmGlobalXCodeGenerator::RelativeToSource(const std::string& p)
3566 {
3567   // We force conversion because Xcode breakpoints do not work unless
3568   // they are in a file named relative to the source tree.
3569   return cmSystemTools::ForceToRelativePath(
3570     cmSystemTools::JoinPath(this->ProjectSourceDirectoryComponents), p);
3571 }
3572
3573 std::string cmGlobalXCodeGenerator::RelativeToBinary(const std::string& p)
3574 {
3575   return this->CurrentLocalGenerator->MaybeConvertToRelativePath(
3576     cmSystemTools::JoinPath(this->ProjectOutputDirectoryComponents), p);
3577 }
3578
3579 std::string cmGlobalXCodeGenerator::XCodeEscapePath(const std::string& p)
3580 {
3581   if (p.find_first_of(" []") != std::string::npos) {
3582     std::string t = cmStrCat('"', p, '"');
3583     return t;
3584   }
3585   return p;
3586 }
3587
3588 void cmGlobalXCodeGenerator::AppendDirectoryForConfig(
3589   const std::string& prefix, const std::string& config,
3590   const std::string& suffix, std::string& dir)
3591 {
3592   if (!config.empty()) {
3593     dir += prefix;
3594     dir += config;
3595     dir += suffix;
3596   }
3597 }
3598
3599 std::string cmGlobalXCodeGenerator::LookupFlags(
3600   const std::string& varNamePrefix, const std::string& varNameLang,
3601   const std::string& varNameSuffix, const std::string& default_flags)
3602 {
3603   if (!varNameLang.empty()) {
3604     std::string varName = cmStrCat(varNamePrefix, varNameLang, varNameSuffix);
3605     if (const char* varValue = this->CurrentMakefile->GetDefinition(varName)) {
3606       if (*varValue) {
3607         return varValue;
3608       }
3609     }
3610   }
3611   return default_flags;
3612 }
3613
3614 void cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs,
3615                                            const char* defines_list,
3616                                            bool dflag)
3617 {
3618   // Skip this if there are no definitions.
3619   if (!defines_list) {
3620     return;
3621   }
3622
3623   // Expand the list of definitions.
3624   std::vector<std::string> defines = cmExpandedList(defines_list);
3625
3626   // Store the definitions in the string.
3627   this->AppendDefines(defs, defines, dflag);
3628 }
3629
3630 void cmGlobalXCodeGenerator::AppendDefines(
3631   BuildObjectListOrString& defs, std::vector<std::string> const& defines,
3632   bool dflag)
3633 {
3634   // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions.
3635   std::string def;
3636   for (auto const& define : defines) {
3637     // Start with -D if requested.
3638     def = cmStrCat(dflag ? "-D" : "", define);
3639
3640     // Append the flag with needed escapes.
3641     std::string tmp;
3642     this->AppendFlag(tmp, def);
3643     defs.Add(tmp);
3644   }
3645 }
3646
3647 void cmGlobalXCodeGenerator::AppendFlag(std::string& flags,
3648                                         std::string const& flag) const
3649 {
3650   // Short-circuit for an empty flag.
3651   if (flag.empty()) {
3652     return;
3653   }
3654
3655   // Separate from previous flags.
3656   if (!flags.empty()) {
3657     flags += " ";
3658   }
3659
3660   // Check if the flag needs quoting.
3661   bool quoteFlag =
3662     flag.find_first_of("`~!@#$%^&*()+={}[]|:;\"'<>,.? ") != std::string::npos;
3663
3664   // We escape a flag as follows:
3665   //   - Place each flag in single quotes ''
3666   //   - Escape a single quote as \'
3667   //   - Escape a backslash as \\ since it itself is an escape
3668   // Note that in the code below we need one more level of escapes for
3669   // C string syntax in this source file.
3670   //
3671   // The final level of escaping is done when the string is stored
3672   // into the project file by cmXCodeObject::PrintString.
3673
3674   if (quoteFlag) {
3675     // Open single quote.
3676     flags += "'";
3677   }
3678
3679   // Flag value with escaped quotes and backslashes.
3680   for (auto c : flag) {
3681     if (c == '\'') {
3682       flags += "'\\''";
3683     } else if (c == '\\') {
3684       flags += "\\\\";
3685     } else {
3686       flags += c;
3687     }
3688   }
3689
3690   if (quoteFlag) {
3691     // Close single quote.
3692     flags += "'";
3693   }
3694 }
3695
3696 std::string cmGlobalXCodeGenerator::ComputeInfoPListLocation(
3697   cmGeneratorTarget* target)
3698 {
3699   std::string plist =
3700     cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
3701              "/CMakeFiles/", target->GetName(), ".dir/Info.plist");
3702   return plist;
3703 }
3704
3705 // Return true if the generated build tree may contain multiple builds.
3706 // i.e. "Can I build Debug and Release in the same tree?"
3707 bool cmGlobalXCodeGenerator::IsMultiConfig() const
3708 {
3709   // Newer Xcode versions are multi config:
3710   return true;
3711 }
3712
3713 bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation(
3714   std::string* reason) const
3715 {
3716   if (this->ObjectDirArch.find('$') != std::string::npos) {
3717     if (reason != nullptr) {
3718       *reason = " under Xcode with multiple architectures";
3719     }
3720     return false;
3721   }
3722   return true;
3723 }
3724
3725 bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const
3726 {
3727   cmProp epnValue = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
3728     "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME");
3729
3730   if (!epnValue) {
3731     return mf->PlatformIsAppleEmbedded();
3732   }
3733
3734   return cmIsOn(*epnValue);
3735 }
3736
3737 bool cmGlobalXCodeGenerator::ShouldStripResourcePath(cmMakefile*) const
3738 {
3739   // Xcode determines Resource location itself
3740   return true;
3741 }
3742
3743 void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory(
3744   cmGeneratorTarget* gt) const
3745 {
3746   std::string configName = this->GetCMakeCFGIntDir();
3747   std::string dir =
3748     cmStrCat(this->GetObjectsDirectory("$(PROJECT_NAME)", configName, gt,
3749                                        "$(OBJECT_FILE_DIR_normal:base)/"),
3750              this->ObjectDirArch, '/');
3751   gt->ObjectDirectory = dir;
3752 }
3753
3754 std::string cmGlobalXCodeGenerator::GetDeploymentPlatform(const cmMakefile* mf)
3755 {
3756   switch (mf->GetAppleSDKType()) {
3757     case cmMakefile::AppleSDK::AppleTVOS:
3758     case cmMakefile::AppleSDK::AppleTVSimulator:
3759       return "TVOS_DEPLOYMENT_TARGET";
3760
3761     case cmMakefile::AppleSDK::IPhoneOS:
3762     case cmMakefile::AppleSDK::IPhoneSimulator:
3763       return "IPHONEOS_DEPLOYMENT_TARGET";
3764
3765     case cmMakefile::AppleSDK::WatchOS:
3766     case cmMakefile::AppleSDK::WatchSimulator:
3767       return "WATCHOS_DEPLOYMENT_TARGET";
3768
3769     case cmMakefile::AppleSDK::MacOS:
3770     default:
3771       return "MACOSX_DEPLOYMENT_TARGET";
3772   }
3773 }