| /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying | 
 |    file LICENSE.rst or https://cmake.org/licensing for details.  */ | 
 | #include "cmGlobalXCodeGenerator.h" | 
 |  | 
 | #include <algorithm> | 
 | #include <cassert> | 
 | #include <cstdio> | 
 | #include <cstring> | 
 | #include <functional> | 
 | #include <iomanip> | 
 | #include <sstream> | 
 | #include <unordered_set> | 
 | #include <utility> | 
 |  | 
 | #include <cm/memory> | 
 | #include <cm/optional> | 
 | #include <cm/string_view> | 
 | #include <cmext/algorithm> | 
 | #include <cmext/string_view> | 
 |  | 
 | #include "cmsys/RegularExpression.hxx" | 
 |  | 
 | #include "cmComputeLinkInformation.h" | 
 | #include "cmCryptoHash.h" | 
 | #include "cmCustomCommand.h" | 
 | #include "cmCustomCommandGenerator.h" | 
 | #include "cmCustomCommandLines.h" | 
 | #include "cmCustomCommandTypes.h" | 
 | #include "cmGeneratedFileStream.h" | 
 | #include "cmGeneratorExpression.h" | 
 | #include "cmGeneratorOptions.h" | 
 | #include "cmGeneratorTarget.h" | 
 | #include "cmGlobalGeneratorFactory.h" | 
 | #include "cmLinkItem.h" | 
 | #include "cmList.h" | 
 | #include "cmListFileCache.h" | 
 | #include "cmLocalGenerator.h" | 
 | #include "cmLocalXCodeGenerator.h" | 
 | #include "cmMakefile.h" | 
 | #include "cmMessageType.h" | 
 | #include "cmOutputConverter.h" | 
 | #include "cmPolicies.h" | 
 | #include "cmSourceFile.h" | 
 | #include "cmSourceFileLocation.h" | 
 | #include "cmSourceFileLocationKind.h" | 
 | #include "cmSourceGroup.h" | 
 | #include "cmState.h" | 
 | #include "cmStateSnapshot.h" | 
 | #include "cmStateTypes.h" | 
 | #include "cmStringAlgorithms.h" | 
 | #include "cmSystemTools.h" | 
 | #include "cmTarget.h" | 
 | #include "cmTargetDepend.h" | 
 | #include "cmXCode21Object.h" | 
 | #include "cmXCodeObject.h" | 
 | #include "cmXCodeScheme.h" | 
 | #include "cmXMLWriter.h" | 
 | #include "cmXcFramework.h" | 
 | #include "cmake.h" | 
 |  | 
 | #if !defined(CMAKE_BOOTSTRAP) && defined(__APPLE__) | 
 | #  include <CoreFoundation/CFBundle.h> | 
 | #  include <CoreFoundation/CFString.h> | 
 | #  include <CoreFoundation/CFURL.h> | 
 | #  include <CoreFoundation/CFUUID.h> | 
 | #  if !TARGET_OS_IPHONE | 
 | #    define HAVE_APPLICATION_SERVICES | 
 | #    include <ApplicationServices/ApplicationServices.h> | 
 | #  endif | 
 | #endif | 
 |  | 
 | #if !defined(CMAKE_BOOTSTRAP) | 
 | #  include "cmXMLParser.h" | 
 |  | 
 | // parse the xml file storing the installed version of Xcode on | 
 | // the machine | 
 | class cmXcodeVersionParser : public cmXMLParser | 
 | { | 
 | public: | 
 |   cmXcodeVersionParser() | 
 |     : Version("1.5") | 
 |   { | 
 |   } | 
 |   void StartElement(std::string const&, char const**) override | 
 |   { | 
 |     this->Data = ""; | 
 |   } | 
 |   void EndElement(std::string const& name) override | 
 |   { | 
 |     if (name == "key"_s) { | 
 |       this->Key = this->Data; | 
 |     } else if (name == "string"_s) { | 
 |       if (this->Key == "CFBundleShortVersionString"_s) { | 
 |         this->Version = this->Data; | 
 |       } | 
 |     } | 
 |   } | 
 |   void CharacterDataHandler(char const* data, int length) override | 
 |   { | 
 |     this->Data.append(data, length); | 
 |   } | 
 |   std::string Version; | 
 |   std::string Key; | 
 |   std::string Data; | 
 | }; | 
 | #endif | 
 |  | 
 | // Builds either an object list or a space-separated string from the | 
 | // given inputs. | 
 | class cmGlobalXCodeGenerator::BuildObjectListOrString | 
 | { | 
 |   cmGlobalXCodeGenerator* Generator; | 
 |   cmXCodeObject* Group = nullptr; | 
 |   bool Empty = true; | 
 |   std::string String; | 
 |  | 
 | public: | 
 |   BuildObjectListOrString(cmGlobalXCodeGenerator* gen, bool buildObjectList) | 
 |     : Generator(gen) | 
 |   { | 
 |     if (buildObjectList) { | 
 |       this->Group = this->Generator->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |     } | 
 |   } | 
 |  | 
 |   bool IsEmpty() const { return this->Empty; } | 
 |  | 
 |   void Add(std::string const& newString) | 
 |   { | 
 |     this->Empty = false; | 
 |  | 
 |     if (this->Group) { | 
 |       this->Group->AddObject(this->Generator->CreateString(newString)); | 
 |     } else { | 
 |       this->String += newString; | 
 |       this->String += ' '; | 
 |     } | 
 |   } | 
 |  | 
 |   std::string const& GetString() const { return this->String; } | 
 |  | 
 |   cmXCodeObject* CreateList() | 
 |   { | 
 |     if (this->Group) { | 
 |       return this->Group; | 
 |     } | 
 |     return this->Generator->CreateString(this->String); | 
 |   } | 
 | }; | 
 |  | 
 | class cmGlobalXCodeGenerator::Factory : public cmGlobalGeneratorFactory | 
 | { | 
 | public: | 
 |   std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( | 
 |     std::string const& name, cmake* cm) const override; | 
 |  | 
 |   cmDocumentationEntry GetDocumentation() const override | 
 |   { | 
 |     return cmGlobalXCodeGenerator::GetDocumentation(); | 
 |   } | 
 |  | 
 |   std::vector<std::string> GetGeneratorNames() const override | 
 |   { | 
 |     std::vector<std::string> names; | 
 |     names.push_back(cmGlobalXCodeGenerator::GetActualName()); | 
 |     return names; | 
 |   } | 
 |  | 
 |   bool SupportsToolset() const override { return true; } | 
 |   bool SupportsPlatform() const override { return false; } | 
 |  | 
 |   std::vector<std::string> GetKnownPlatforms() const override | 
 |   { | 
 |     return std::vector<std::string>(); | 
 |   } | 
 |  | 
 |   std::string GetDefaultPlatformName() const override { return std::string(); } | 
 | }; | 
 |  | 
 | cmGlobalXCodeGenerator::cmGlobalXCodeGenerator( | 
 |   cmake* cm, std::string const& version_string, unsigned int version_number) | 
 |   : cmGlobalGenerator(cm) | 
 | { | 
 |   this->VersionString = version_string; | 
 |   this->XcodeVersion = version_number; | 
 |   if (this->XcodeVersion >= 120) { | 
 |     this->XcodeBuildSystem = BuildSystem::Twelve; | 
 |   } else { | 
 |     this->XcodeBuildSystem = BuildSystem::One; | 
 |   } | 
 |  | 
 |   this->RootObject = nullptr; | 
 |   this->MainGroupChildren = nullptr; | 
 |   this->FrameworkGroup = nullptr; | 
 |   this->CurrentMakefile = nullptr; | 
 |   this->CurrentLocalGenerator = nullptr; | 
 |   this->XcodeBuildCommandInitialized = false; | 
 |  | 
 |   this->ObjectDirArchDefault = "$(CURRENT_ARCH)"; | 
 |   this->ObjectDirArch = this->ObjectDirArchDefault; | 
 |  | 
 |   cm->GetState()->SetIsGeneratorMultiConfig(true); | 
 | } | 
 |  | 
 | std::unique_ptr<cmGlobalGeneratorFactory> cmGlobalXCodeGenerator::NewFactory() | 
 | { | 
 |   return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory); | 
 | } | 
 |  | 
 | std::unique_ptr<cmGlobalGenerator> | 
 | cmGlobalXCodeGenerator::Factory::CreateGlobalGenerator(std::string const& name, | 
 |                                                        cmake* cm) const | 
 | { | 
 |   if (name != GetActualName()) { | 
 |     return std::unique_ptr<cmGlobalGenerator>(); | 
 |   } | 
 | #if !defined(CMAKE_BOOTSTRAP) | 
 |   cmXcodeVersionParser parser; | 
 |   std::string versionFile; | 
 |   { | 
 |     std::string out; | 
 |     bool commandResult = cmSystemTools::RunSingleCommand( | 
 |       "xcode-select --print-path", &out, nullptr, nullptr, nullptr, | 
 |       cmSystemTools::OUTPUT_NONE); | 
 |     if (commandResult) { | 
 |       std::string::size_type pos = out.find(".app/"); | 
 |       if (pos != std::string::npos) { | 
 |         versionFile = | 
 |           cmStrCat(out.substr(0, pos + 5), "Contents/version.plist"); | 
 |       } | 
 |     } | 
 |   } | 
 |   if (!versionFile.empty() && cmSystemTools::FileExists(versionFile)) { | 
 |     parser.ParseFile(versionFile.c_str()); | 
 |   } else if (cmSystemTools::FileExists( | 
 |                "/Applications/Xcode.app/Contents/version.plist")) { | 
 |     parser.ParseFile("/Applications/Xcode.app/Contents/version.plist"); | 
 |   } else { | 
 |     parser.ParseFile( | 
 |       "/Developer/Applications/Xcode.app/Contents/version.plist"); | 
 |   } | 
 |   std::string const& version_string = parser.Version; | 
 |  | 
 |   // Compute an integer form of the version number. | 
 |   unsigned int v[2] = { 0, 0 }; | 
 |   sscanf(version_string.c_str(), "%u.%u", &v[0], &v[1]); | 
 |   unsigned int version_number = 10 * v[0] + v[1]; | 
 |  | 
 |   if (version_number < 50) { | 
 |     cm->IssueMessage(MessageType::FATAL_ERROR, | 
 |                      cmStrCat("Xcode ", version_string, " not supported.")); | 
 |     return std::unique_ptr<cmGlobalGenerator>(); | 
 |   } | 
 |  | 
 |   return std::unique_ptr<cmGlobalGenerator>( | 
 |     cm::make_unique<cmGlobalXCodeGenerator>(cm, version_string, | 
 |                                             version_number)); | 
 | #else | 
 |   std::cerr << "CMake should be built with cmake to use Xcode, " | 
 |                "default to Xcode 1.5\n"; | 
 |   return std::unique_ptr<cmGlobalGenerator>( | 
 |     cm::make_unique<cmGlobalXCodeGenerator>(cm)); | 
 | #endif | 
 | } | 
 |  | 
 | namespace { | 
 | std::string ConvertToMakefilePath(std::string const& path) | 
 | { | 
 |   std::string result; | 
 |   result.reserve(path.size()); | 
 |   for (char c : path) { | 
 |     switch (c) { | 
 |       case '\\': | 
 |       case ' ': | 
 |       case '#': | 
 |         result.push_back('\\'); | 
 |         CM_FALLTHROUGH; | 
 |       default: | 
 |         result.push_back(c); | 
 |         break; | 
 |     } | 
 |   } | 
 |   return result; | 
 | } | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::FindMakeProgram(cmMakefile* mf) | 
 | { | 
 |   // The Xcode generator knows how to lookup its build tool | 
 |   // directly instead of needing a helper module to do it, so we | 
 |   // do not actually need to put CMAKE_MAKE_PROGRAM into the cache. | 
 |   if (mf->GetDefinition("CMAKE_MAKE_PROGRAM").IsOff()) { | 
 |     mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetXcodeBuildCommand()); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::GetAppleSpecificPlatformName() | 
 | { | 
 |   std::string sdkRoot = | 
 |     this->GetCMakeInstance()->GetState()->GetCacheEntryValue( | 
 |       "CMAKE_OSX_SYSROOT"); | 
 |   sdkRoot = cmSystemTools::LowerCase(sdkRoot); | 
 |  | 
 |   struct SdkDatabaseEntry | 
 |   { | 
 |     cm::string_view Name; | 
 |     cm::string_view AppleName; | 
 |   }; | 
 |  | 
 |   std::array<SdkDatabaseEntry, 6> const sdkDatabase{ { | 
 |     { "appletvos"_s, "tvOS"_s }, | 
 |     { "appletvsimulator"_s, "tvOS Simulator"_s }, | 
 |     { "iphoneos"_s, "iOS"_s }, | 
 |     { "iphonesimulator"_s, "iOS Simulator"_s }, | 
 |     { "watchos"_s, "watchOS"_s }, | 
 |     { "watchsimulator"_s, "watchOS Simulator"_s }, | 
 |   } }; | 
 |  | 
 |   cm::string_view platformName = "MacOS"_s; | 
 |   for (SdkDatabaseEntry const& entry : sdkDatabase) { | 
 |     if (cmHasPrefix(sdkRoot, entry.Name) || | 
 |         sdkRoot.find(cmStrCat('/', entry.Name)) != std::string::npos) { | 
 |       platformName = entry.AppleName; | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   return std::string(platformName); | 
 | } | 
 |  | 
 | std::string const& cmGlobalXCodeGenerator::GetXcodeBuildCommand() | 
 | { | 
 |   if (!this->XcodeBuildCommandInitialized) { | 
 |     this->XcodeBuildCommandInitialized = true; | 
 |     this->XcodeBuildCommand = this->FindXcodeBuildCommand(); | 
 |   } | 
 |   return this->XcodeBuildCommand; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::FindXcodeBuildCommand() | 
 | { | 
 |   std::string makeProgram = cmSystemTools::FindProgram("xcodebuild"); | 
 |   if (makeProgram.empty()) { | 
 |     makeProgram = "xcodebuild"; | 
 |   } | 
 |   return makeProgram; | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::SetSystemName(std::string const& s, | 
 |                                            cmMakefile* mf) | 
 | { | 
 |   this->SystemName = s; | 
 |   return this->cmGlobalGenerator::SetSystemName(s, mf); | 
 | } | 
 |  | 
 | namespace { | 
 | cm::string_view cmXcodeBuildSystemString(cmGlobalXCodeGenerator::BuildSystem b) | 
 | { | 
 |   switch (b) { | 
 |     case cmGlobalXCodeGenerator::BuildSystem::One: | 
 |       return "1"_s; | 
 |     case cmGlobalXCodeGenerator::BuildSystem::Twelve: | 
 |       return "12"_s; | 
 |   } | 
 |   return {}; | 
 | } | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts, | 
 |                                                  bool build, cmMakefile* mf) | 
 | { | 
 |   if (!this->ParseGeneratorToolset(ts, mf)) { | 
 |     return false; | 
 |   } | 
 |   if (build) { | 
 |     return true; | 
 |   } | 
 |   if (!this->GeneratorToolset.empty()) { | 
 |     mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET", this->GeneratorToolset); | 
 |   } | 
 |   mf->AddDefinition("CMAKE_XCODE_BUILD_SYSTEM", | 
 |                     cmXcodeBuildSystemString(this->XcodeBuildSystem)); | 
 |   return true; | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::ParseGeneratorToolset(std::string const& ts, | 
 |                                                    cmMakefile* mf) | 
 | { | 
 |   std::vector<std::string> const fields = | 
 |     cmTokenize(ts, ',', cmTokenizerMode::New); | 
 |   if (fields.empty()) { | 
 |     return true; | 
 |   } | 
 |  | 
 |   auto fi = fields.cbegin(); | 
 |   // The first field may be the Xcode GCC_VERSION. | 
 |   if (fi->find('=') == fi->npos) { | 
 |     this->GeneratorToolset = *fi; | 
 |     ++fi; | 
 |   } | 
 |  | 
 |   std::unordered_set<std::string> handled; | 
 |  | 
 |   // The rest of the fields must be key=value pairs. | 
 |   for (; fi != fields.cend(); ++fi) { | 
 |     std::string::size_type pos = fi->find('='); | 
 |     if (pos == fi->npos) { | 
 |       /* clang-format off */ | 
 |       std::string const& e = cmStrCat( | 
 |         "Generator\n" | 
 |         "  ", this->GetName(), "\n" | 
 |         "given toolset specification\n" | 
 |         "  ", ts, "\n" | 
 |         "that contains a field after the first ',' with no '='." | 
 |         ); | 
 |       /* clang-format on */ | 
 |       mf->IssueMessage(MessageType::FATAL_ERROR, e); | 
 |       return false; | 
 |     } | 
 |     std::string const key = fi->substr(0, pos); | 
 |     std::string const value = fi->substr(pos + 1); | 
 |     if (!handled.insert(key).second) { | 
 |       /* clang-format off */ | 
 |       std::string const& e = cmStrCat( | 
 |         "Generator\n" | 
 |         "  ", this->GetName(), "\n" | 
 |         "given toolset specification\n" | 
 |         "  ", ts, "\n" | 
 |         "that contains duplicate field key '", key, "'." | 
 |         ); | 
 |       /* clang-format on */ | 
 |       mf->IssueMessage(MessageType::FATAL_ERROR, e); | 
 |       return false; | 
 |     } | 
 |     if (!this->ProcessGeneratorToolsetField(key, value, mf)) { | 
 |       return false; | 
 |     } | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::ProcessGeneratorToolsetField( | 
 |   std::string const& key, std::string const& value, cmMakefile* mf) | 
 | { | 
 |   if (key == "buildsystem"_s) { | 
 |     if (value == "1"_s) { | 
 |       this->XcodeBuildSystem = BuildSystem::One; | 
 |     } else if (value == "12"_s) { | 
 |       this->XcodeBuildSystem = BuildSystem::Twelve; | 
 |     } else { | 
 |       /* clang-format off */ | 
 |       std::string const& e = cmStrCat( | 
 |         "Generator\n" | 
 |         "  ",  this->GetName(), "\n" | 
 |         "toolset specification field\n" | 
 |         "  buildsystem=", value, "\n" | 
 |         "value is unknown.  It must be '1' or '12'." | 
 |         ); | 
 |       /* clang-format on */ | 
 |       mf->IssueMessage(MessageType::FATAL_ERROR, e); | 
 |       return false; | 
 |     } | 
 |     if ((this->XcodeBuildSystem == BuildSystem::Twelve && | 
 |          this->XcodeVersion < 120) || | 
 |         (this->XcodeBuildSystem == BuildSystem::One && | 
 |          this->XcodeVersion >= 140)) { | 
 |       /* clang-format off */ | 
 |       std::string const& e = cmStrCat( | 
 |         "Generator\n" | 
 |         "  ",  this->GetName(), "\n" | 
 |         "toolset specification field\n" | 
 |         "  buildsystem=", value, "\n" | 
 |         "is not allowed with Xcode ", this->VersionString, '.' | 
 |         ); | 
 |       /* clang-format on */ | 
 |       mf->IssueMessage(MessageType::FATAL_ERROR, e); | 
 |       return false; | 
 |     } | 
 |     return true; | 
 |   } | 
 |   /* clang-format off */ | 
 |   std::string const& e = cmStrCat( | 
 |     "Generator\n" | 
 |     "  ", this->GetName(), "\n" | 
 |     "given toolset specification that contains invalid field '", key, "'." | 
 |     ); | 
 |   /* clang-format on */ | 
 |   mf->IssueMessage(MessageType::FATAL_ERROR, e); | 
 |   return false; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::EnableLanguage( | 
 |   std::vector<std::string> const& lang, cmMakefile* mf, bool optional) | 
 | { | 
 |   mf->AddDefinition("XCODE", "1"); | 
 |   mf->AddDefinition("XCODE_VERSION", this->VersionString); | 
 |   mf->InitCMAKE_CONFIGURATION_TYPES("Debug;Release;MinSizeRel;RelWithDebInfo"); | 
 |   mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1"); | 
 |   this->cmGlobalGenerator::EnableLanguage(lang, mf, optional); | 
 |   this->ComputeArchitectures(mf); | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::Open(std::string const& bindir, | 
 |                                   std::string const& projectName, bool dryRun) | 
 | { | 
 |   bool ret = false; | 
 |  | 
 | #ifdef HAVE_APPLICATION_SERVICES | 
 |   // If an external tool created a workspace then open it instead. | 
 |   std::string url = cmStrCat(bindir, '/', projectName, ".xcworkspace"); | 
 |   bool const isWorkspace = cmSystemTools::FileIsDirectory(url); | 
 |   if (!isWorkspace) { | 
 |     url = cmStrCat(bindir, '/', projectName, ".xcodeproj"); | 
 |   } | 
 |  | 
 |   if (dryRun) { | 
 |     return cmSystemTools::FileIsDirectory(url); | 
 |   } | 
 |  | 
 |   CFStringRef cfStr = CFStringCreateWithCString( | 
 |     kCFAllocatorDefault, url.c_str(), kCFStringEncodingUTF8); | 
 |   if (cfStr) { | 
 |     CFURLRef cfUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfStr, | 
 |                                                    kCFURLPOSIXPathStyle, true); | 
 |     if (cfUrl) { | 
 |       OSStatus err = LSOpenCFURLRef(cfUrl, nullptr); | 
 |       ret = err == noErr; | 
 |       CFRelease(cfUrl); | 
 |     } | 
 |     CFRelease(cfStr); | 
 |   } | 
 | #else | 
 |   (void)bindir; | 
 |   (void)projectName; | 
 |   (void)dryRun; | 
 | #endif | 
 |  | 
 |   return ret; | 
 | } | 
 |  | 
 | std::vector<cmGlobalGenerator::GeneratedMakeCommand> | 
 | cmGlobalXCodeGenerator::GenerateBuildCommand( | 
 |   std::string const& makeProgram, std::string const& projectName, | 
 |   std::string const& /*projectDir*/, | 
 |   std::vector<std::string> const& targetNames, std::string const& config, | 
 |   int jobs, bool /*verbose*/, cmBuildOptions /*buildOptions*/, | 
 |   std::vector<std::string> const& makeOptions) | 
 | { | 
 |   std::string const xcodebuild = | 
 |     this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()); | 
 |  | 
 |   // Note that projectName can be empty, such as from a command like this one: | 
 |   //   ctest --build-and-test . build --build-generator Xcode | 
 |   // If projectName is empty, then isWorkspace set further below will always | 
 |   // be false because workspacePath will never point to a valid workspace file. | 
 |   // And if projectName is empty, we don't add any -workspace or -project | 
 |   // option to the xcodebuild command line because we don't know what to put | 
 |   // after either option. For that scenario, we rely on xcodebuild finding | 
 |   // exactly one .xcodeproj file in the working directory. | 
 |  | 
 |   std::string const workspacePath = cmStrCat(projectName, ".xcworkspace"); | 
 |   std::string const projectPath = cmStrCat(projectName, ".xcodeproj"); | 
 |  | 
 |   // If an external tool created a workspace then build it instead. | 
 |   bool const isWorkspace = cmSystemTools::FileIsDirectory(workspacePath); | 
 |  | 
 |   std::string const targetFlag = isWorkspace ? "-scheme" : "-target"; | 
 |  | 
 |   std::vector<std::string> requiredArgs; | 
 |  | 
 |   if (isWorkspace) { | 
 |     requiredArgs.insert(requiredArgs.end(), { "-workspace", workspacePath }); | 
 |   } else if (!projectName.empty()) { | 
 |     requiredArgs.insert(requiredArgs.end(), { "-project", projectPath }); | 
 |   } | 
 |  | 
 |   bool const isCleanBuild = cm::contains(targetNames, "clean"); | 
 |   bool const isTargetEmpty = targetNames.empty() || | 
 |     ((targetNames.size() == 1) && targetNames.front().empty()); | 
 |  | 
 |   if (isCleanBuild) { | 
 |     requiredArgs.push_back("clean"); | 
 |   } else { | 
 |     requiredArgs.push_back("build"); | 
 |   } | 
 |  | 
 |   requiredArgs.insert(requiredArgs.end(), | 
 |                       { "-configuration", config.empty() ? "Debug" : config }); | 
 |  | 
 |   if (isWorkspace) { | 
 |     requiredArgs.insert( | 
 |       requiredArgs.end(), | 
 |       { "-destination", | 
 |         cmStrCat("generic/platform=", this->GetAppleSpecificPlatformName()) }); | 
 |   } | 
 |  | 
 |   if ((this->XcodeBuildSystem >= BuildSystem::Twelve) || | 
 |       (jobs != cmake::NO_BUILD_PARALLEL_LEVEL)) { | 
 |     requiredArgs.push_back("-parallelizeTargets"); | 
 |   } | 
 |  | 
 |   if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) && | 
 |       (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) { | 
 |     requiredArgs.insert(requiredArgs.end(), { "-jobs", std::to_string(jobs) }); | 
 |   } | 
 |  | 
 |   if (this->XcodeVersion >= 70) { | 
 |     requiredArgs.push_back("-hideShellScriptEnvironment"); | 
 |   } | 
 |  | 
 |   requiredArgs.insert(requiredArgs.end(), makeOptions.begin(), | 
 |                       makeOptions.end()); | 
 |  | 
 |   if (isWorkspace && !isCleanBuild && targetNames.size() > 1) { | 
 |     // For workspaces we need a separate command for each target, | 
 |     // because xcodebuild can pass only one -scheme arg | 
 |     std::vector<GeneratedMakeCommand> makeCommands; | 
 |     for (auto const& target : targetNames) { | 
 |       if (target.empty()) { | 
 |         continue; | 
 |       } | 
 |       GeneratedMakeCommand makeCommand; | 
 |       makeCommand.Add(xcodebuild); | 
 |       makeCommand.Add(requiredArgs.cbegin(), requiredArgs.cend()); | 
 |       makeCommand.Add(targetFlag, target); | 
 |       makeCommands.emplace_back(std::move(makeCommand)); | 
 |     } | 
 |     return makeCommands; | 
 |   } | 
 |  | 
 |   if (isTargetEmpty || isCleanBuild) { | 
 |     requiredArgs.insert(requiredArgs.end(), { targetFlag, "ALL_BUILD" }); | 
 |   } else { | 
 |     for (auto const& target : targetNames) { | 
 |       if (target.empty()) { | 
 |         continue; | 
 |       } | 
 |       requiredArgs.insert(requiredArgs.end(), { targetFlag, target }); | 
 |     } | 
 |   } | 
 |   GeneratedMakeCommand makeCommand; | 
 |   makeCommand.Add(xcodebuild); | 
 |   makeCommand.Add(requiredArgs.cbegin(), requiredArgs.cend()); | 
 |   return { std::move(makeCommand) }; | 
 | } | 
 |  | 
 | //! Create a local generator appropriate to this Global Generator | 
 | std::unique_ptr<cmLocalGenerator> cmGlobalXCodeGenerator::CreateLocalGenerator( | 
 |   cmMakefile* mf) | 
 | { | 
 |   std::unique_ptr<cmLocalGenerator> lg( | 
 |     cm::make_unique<cmLocalXCodeGenerator>(this, mf)); | 
 |   if (this->XcodeBuildSystem >= BuildSystem::Twelve) { | 
 |     // For this build system variant we generate custom commands as | 
 |     // shell scripts directly rather than inside Makefiles. | 
 |     // FIXME: Rename or refactor this option for clarity. | 
 |     lg->SetLinkScriptShell(true); | 
 |   } | 
 |   return lg; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddExtraIDETargets() | 
 | { | 
 |   // make sure extra targets are added before calling | 
 |   // the parent generate which will call trace depends | 
 |   for (auto keyVal : this->ProjectMap) { | 
 |     cmLocalGenerator* root = keyVal.second[0]; | 
 |     this->SetGenerationRoot(root); | 
 |     // add ALL_BUILD, INSTALL, etc | 
 |     this->AddExtraTargets(root, keyVal.second); | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::Generate() | 
 | { | 
 |   this->cmGlobalGenerator::Generate(); | 
 |   if (cmSystemTools::GetErrorOccurredFlag()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   for (auto keyVal : this->ProjectMap) { | 
 |     cmLocalGenerator* root = keyVal.second[0]; | 
 |  | 
 |     bool generateTopLevelProjectOnly = | 
 |       root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY"); | 
 |  | 
 |     if (generateTopLevelProjectOnly) { | 
 |       cmStateSnapshot snp = root->GetStateSnapshot(); | 
 |       if (snp.GetBuildsystemDirectoryParent().IsValid()) { | 
 |         continue; | 
 |       } | 
 |     } | 
 |  | 
 |     // cache the enabled languages for source file type queries | 
 |     this->GetEnabledLanguages(this->EnabledLangs); | 
 |  | 
 |     this->SetGenerationRoot(root); | 
 |     // now create the project | 
 |     this->OutputXCodeProject(root, keyVal.second); | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::SetGenerationRoot(cmLocalGenerator* root) | 
 | { | 
 |   this->CurrentProject = root->GetProjectName(); | 
 |   this->SetCurrentLocalGenerator(root); | 
 |   this->CurrentRootGenerator = root; | 
 |   this->CurrentXCodeHackMakefile = | 
 |     cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeScripts"); | 
 |   cmSystemTools::MakeDirectory(this->CurrentXCodeHackMakefile); | 
 |   this->CurrentXCodeHackMakefile += "/XCODE_DEPEND_HELPER.make"; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::PostBuildMakeTarget( | 
 |   std::string const& tName, std::string const& configName) | 
 | { | 
 |   std::string target = tName; | 
 |   std::replace(target.begin(), target.end(), ' ', '_'); | 
 |   std::string out = cmStrCat("PostBuild.", target, '.', configName); | 
 |   return out; | 
 | } | 
 |  | 
 | #define CMAKE_CHECK_BUILD_SYSTEM_TARGET "ZERO_CHECK" | 
 |  | 
 | void cmGlobalXCodeGenerator::AddExtraTargets( | 
 |   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens) | 
 | { | 
 |   // Add ALL_BUILD | 
 |   auto cc = cm::make_unique<cmCustomCommand>(); | 
 |   cc->SetCommandLines( | 
 |     cmMakeSingleCommandLine({ "echo", "Build all projects" })); | 
 |   cmTarget* allbuild = | 
 |     root->AddUtilityCommand("ALL_BUILD", true, std::move(cc)); | 
 |  | 
 |   // Add xcconfig files to ALL_BUILD sources | 
 |   for (auto& config : this->CurrentConfigurationTypes) { | 
 |     auto xcconfig = cmGeneratorExpression::Evaluate( | 
 |       this->CurrentMakefile->GetSafeDefinition("CMAKE_XCODE_XCCONFIG"), | 
 |       this->CurrentLocalGenerator, config); | 
 |     if (!xcconfig.empty()) { | 
 |       auto* xcconfig_sf = allbuild->AddSource(xcconfig); | 
 |       xcconfig_sf->SetSpecialSourceType( | 
 |         cmSourceFile::SpecialSourceType::XcodeXCConfigFile); | 
 |     } | 
 |   } | 
 |  | 
 |   root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(allbuild, root)); | 
 |  | 
 |   // Add XCODE depend helper | 
 |   std::string legacyDependHelperDir = root->GetCurrentBinaryDirectory(); | 
 |   cmCustomCommandLines legacyDependHelperCommandLines; | 
 |   if (this->XcodeBuildSystem == BuildSystem::One) { | 
 |     legacyDependHelperCommandLines = cmMakeSingleCommandLine( | 
 |       { "make", "-C", legacyDependHelperDir, "-f", | 
 |         this->CurrentXCodeHackMakefile, "OBJDIR=$(OBJDIR)", | 
 |         /* placeholder, see below */ "" }); | 
 |   } | 
 |  | 
 |   // Add ZERO_CHECK | 
 |   bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION"); | 
 |   bool generateTopLevelProjectOnly = | 
 |     root->GetMakefile()->IsOn("CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY"); | 
 |   bool isTopLevel = | 
 |     !root->GetStateSnapshot().GetBuildsystemDirectoryParent().IsValid(); | 
 |   bool isGenerateProject = isTopLevel || !generateTopLevelProjectOnly; | 
 |   if (regenerate && isGenerateProject) { | 
 |     this->CreateReRunCMakeFile(root, gens); | 
 |     std::string file = | 
 |       cmSystemTools::ConvertToOutputPath(this->CurrentReRunCMakeMakefile); | 
 |     cmSystemTools::ReplaceString(file, "\\ ", " "); | 
 |     cc = cm::make_unique<cmCustomCommand>(); | 
 |     cc->SetCommandLines(cmMakeSingleCommandLine({ "make", "-f", file })); | 
 |     cmTarget* check = root->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, | 
 |                                               true, std::move(cc)); | 
 |  | 
 |     root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(check, root)); | 
 |   } | 
 |  | 
 |   // now make the allbuild depend on all the non-utility targets | 
 |   // in the project | 
 |   for (auto& gen : gens) { | 
 |     for (auto const& target : gen->GetGeneratorTargets()) { | 
 |       if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { | 
 |         continue; | 
 |       } | 
 |  | 
 |       if (regenerate && | 
 |           (target->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET)) { | 
 |         target->Target->AddUtility(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false); | 
 |       } | 
 |  | 
 |       // make all exe, shared libs and modules | 
 |       // run the depend check makefile as a post build rule | 
 |       // this will make sure that when the next target is built | 
 |       // things are up-to-date | 
 |       if (this->XcodeBuildSystem == BuildSystem::One && isGenerateProject && | 
 |           target->GetType() == cmStateEnums::OBJECT_LIBRARY) { | 
 |         legacyDependHelperCommandLines.front().back() = // fill placeholder | 
 |           this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)"); | 
 |         cc = cm::make_unique<cmCustomCommand>(); | 
 |         cc->SetCommandLines(legacyDependHelperCommandLines); | 
 |         cc->SetComment("Depend check for xcode"); | 
 |         cc->SetWorkingDirectory(legacyDependHelperDir.c_str()); | 
 |         gen->AddCustomCommandToTarget( | 
 |           target->GetName(), cmCustomCommandType::POST_BUILD, std::move(cc), | 
 |           cmObjectLibraryCommands::Accept); | 
 |       } | 
 |  | 
 |       if (!this->IsExcluded(gens[0], target.get())) { | 
 |         allbuild->AddUtility(target->GetName(), false); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateReRunCMakeFile( | 
 |   cmLocalGenerator* root, std::vector<cmLocalGenerator*> const& gens) | 
 | { | 
 |   std::vector<std::string> lfiles; | 
 |   for (auto* gen : gens) { | 
 |     cm::append(lfiles, gen->GetMakefile()->GetListFiles()); | 
 |   } | 
 |  | 
 |   // sort the array | 
 |   std::sort(lfiles.begin(), lfiles.end()); | 
 |   lfiles.erase(std::unique(lfiles.begin(), lfiles.end()), lfiles.end()); | 
 |  | 
 |   cmake* cm = this->GetCMakeInstance(); | 
 |   if (cm->DoWriteGlobVerifyTarget()) { | 
 |     lfiles.emplace_back(cm->GetGlobVerifyStamp()); | 
 |   } | 
 |  | 
 |   this->CurrentReRunCMakeMakefile = | 
 |     cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeScripts"); | 
 |   cmSystemTools::MakeDirectory(this->CurrentReRunCMakeMakefile); | 
 |   this->CurrentReRunCMakeMakefile += "/ReRunCMake.make"; | 
 |   cmGeneratedFileStream makefileStream(this->CurrentReRunCMakeMakefile); | 
 |   makefileStream.SetCopyIfDifferent(true); | 
 |   makefileStream << "# Generated by CMake, DO NOT EDIT\n\n" | 
 |  | 
 |                     "TARGETS:= \n" | 
 |                     "empty:= \n" | 
 |                     "space:= $(empty) $(empty)\n" | 
 |                     "spaceplus:= $(empty)\\ $(empty)\n\n"; | 
 |  | 
 |   for (auto const& lfile : lfiles) { | 
 |     makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard " | 
 |                    << ConvertToMakefilePath(lfile) << "))\n"; | 
 |   } | 
 |   makefileStream << '\n'; | 
 |  | 
 |   std::string checkCache = | 
 |     cmStrCat(root->GetBinaryDirectory(), "/CMakeFiles/cmake.check_cache"); | 
 |  | 
 |   if (cm->DoWriteGlobVerifyTarget()) { | 
 |     makefileStream << ".NOTPARALLEL:\n\n" | 
 |                       ".PHONY: all VERIFY_GLOBS\n\n" | 
 |                       "all: VERIFY_GLOBS " | 
 |                    << ConvertToMakefilePath(checkCache) | 
 |                    << "\n\n" | 
 |                       "VERIFY_GLOBS:\n" | 
 |                       "\t" | 
 |                    << ConvertToMakefilePath(cmSystemTools::GetCMakeCommand()) | 
 |                    << " -P " | 
 |                    << ConvertToMakefilePath(cm->GetGlobVerifyScript()) | 
 |                    << "\n\n"; | 
 |   } | 
 |  | 
 |   makefileStream << ConvertToMakefilePath(checkCache) << ": $(TARGETS)\n"; | 
 |   makefileStream | 
 |     << '\t' << ConvertToMakefilePath(cmSystemTools::GetCMakeCommand()) << " -S" | 
 |     << ConvertToMakefilePath(root->GetSourceDirectory()) << " -B" | 
 |     << ConvertToMakefilePath(root->GetBinaryDirectory()) | 
 |     << (cm->GetIgnoreCompileWarningAsError() ? " --compile-no-warning-as-error" | 
 |                                              : "") | 
 |     << (cm->GetIgnoreLinkWarningAsError() ? " --link-no-warning-as-error" : "") | 
 |     << '\n'; | 
 | } | 
 |  | 
 | static bool objectIdLessThan(std::unique_ptr<cmXCodeObject> const& l, | 
 |                              std::unique_ptr<cmXCodeObject> const& r) | 
 | { | 
 |   return l->GetId() < r->GetId(); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::SortXCodeObjects() | 
 | { | 
 |   std::sort(this->XCodeObjects.begin(), this->XCodeObjects.end(), | 
 |             objectIdLessThan); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::ClearXCodeObjects() | 
 | { | 
 |   this->TargetDoneSet.clear(); | 
 |   this->XCodeObjects.clear(); | 
 |   this->XCodeObjectIDs.clear(); | 
 |   this->XCodeObjectMap.clear(); | 
 |   this->GroupMap.clear(); | 
 |   this->GroupNameMap.clear(); | 
 |   this->TargetGroup.clear(); | 
 |   this->FileRefs.clear(); | 
 |   this->ExternalLibRefs.clear(); | 
 |   this->FileRefToBuildFileMap.clear(); | 
 |   this->FileRefToEmbedBuildFileMap.clear(); | 
 |   this->CommandsVisited.clear(); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj) | 
 | { | 
 |   if (obj->GetType() == cmXCodeObject::OBJECT) { | 
 |     std::string const& id = obj->GetId(); | 
 |  | 
 |     // If this is a duplicate id, it's an error: | 
 |     // | 
 |     if (this->XCodeObjectIDs.count(id)) { | 
 |       cmSystemTools::Error( | 
 |         "Xcode generator: duplicate object ids not allowed"); | 
 |     } | 
 |  | 
 |     this->XCodeObjectIDs.insert(id); | 
 |   } | 
 |  | 
 |   this->XCodeObjects.push_back(std::move(obj)); | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateObject( | 
 |   cmXCodeObject::PBXType ptype, cm::string_view key) | 
 | { | 
 |   auto obj = cm::make_unique<cmXCode21Object>(ptype, cmXCodeObject::OBJECT, | 
 |                                               this->GetObjectId(ptype, key)); | 
 |   auto* ptr = obj.get(); | 
 |   this->addObject(std::move(obj)); | 
 |   return ptr; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateObject(cmXCodeObject::Type type) | 
 | { | 
 |   auto obj = cm::make_unique<cmXCodeObject>( | 
 |     cmXCodeObject::None, type, | 
 |     "Temporary cmake object, should not be referred to in Xcode file"); | 
 |   auto* ptr = obj.get(); | 
 |   this->addObject(std::move(obj)); | 
 |   return ptr; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateString(cm::string_view s) | 
 | { | 
 |   cmXCodeObject* obj = this->CreateObject(cmXCodeObject::STRING); | 
 |   obj->SetString(s); | 
 |   return obj; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateObjectReference( | 
 |   cmXCodeObject* ref) | 
 | { | 
 |   cmXCodeObject* obj = this->CreateObject(cmXCodeObject::OBJECT_REF); | 
 |   obj->SetObject(ref); | 
 |   return obj; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateFlatClone(cmXCodeObject* orig) | 
 | { | 
 |   cmXCodeObject* obj = this->CreateObject(orig->GetType()); | 
 |   obj->CopyAttributes(orig); | 
 |   return obj; | 
 | } | 
 |  | 
 | static std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target, | 
 |                                           std::string const& fullpath) | 
 | { | 
 |   return cmStrCat(target->GetName(), '-', fullpath); | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeBuildFileFromPath( | 
 |   std::string const& fullpath, cmGeneratorTarget* target, | 
 |   std::string const& lang, cmSourceFile* sf) | 
 | { | 
 |   // Using a map and the full path guarantees that we will always get the same | 
 |   // fileRef object for any given full path. Same goes for the buildFile | 
 |   // object. | 
 |   cmXCodeObject* fileRef = | 
 |     this->CreateXCodeFileReferenceFromPath(fullpath, target, lang, sf); | 
 |   if (fileRef) { | 
 |     auto it = this->FileRefToBuildFileMap.find(fileRef); | 
 |     if (it == this->FileRefToBuildFileMap.end()) { | 
 |       cmXCodeObject* buildFile = | 
 |         this->CreateObject(cmXCodeObject::PBXBuildFile); | 
 |       buildFile->SetComment(fileRef->GetComment()); | 
 |       buildFile->AddAttribute("fileRef", this->CreateObjectReference(fileRef)); | 
 |       this->FileRefToBuildFileMap[fileRef] = buildFile; | 
 |       return buildFile; | 
 |     } | 
 |     return it->second; | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | class XCodeGeneratorExpressionInterpreter | 
 |   : public cmGeneratorExpressionInterpreter | 
 | { | 
 | public: | 
 |   XCodeGeneratorExpressionInterpreter(cmSourceFile* sourceFile, | 
 |                                       cmLocalGenerator* localGenerator, | 
 |                                       cmGeneratorTarget* headTarget, | 
 |                                       std::string const& lang) | 
 |     : cmGeneratorExpressionInterpreter( | 
 |         localGenerator, "NO-PER-CONFIG-SUPPORT-IN-XCODE", headTarget, lang) | 
 |     , SourceFile(sourceFile) | 
 |   { | 
 |   } | 
 |  | 
 |   XCodeGeneratorExpressionInterpreter( | 
 |     XCodeGeneratorExpressionInterpreter const&) = delete; | 
 |   XCodeGeneratorExpressionInterpreter& operator=( | 
 |     XCodeGeneratorExpressionInterpreter const&) = delete; | 
 |  | 
 |   std::string const& Evaluate(char const* expression, | 
 |                               std::string const& property) | 
 |   { | 
 |     return this->Evaluate(std::string(expression ? expression : ""), property); | 
 |   } | 
 |  | 
 |   std::string const& Evaluate(std::string const& expression, | 
 |                               std::string const& property) | 
 |   { | 
 |     std::string const& processed = | 
 |       this->cmGeneratorExpressionInterpreter::Evaluate(expression, property); | 
 |     if (this->CompiledGeneratorExpression->GetHadContextSensitiveCondition()) { | 
 |       std::ostringstream e; | 
 |       /* clang-format off */ | 
 |       e << | 
 |           "Xcode does not support per-config per-source " << property << ":\n" | 
 |           "  " << expression << "\n" | 
 |           "specified for source:\n" | 
 |           "  " << this->SourceFile->ResolveFullPath() << '\n'; | 
 |       /* clang-format on */ | 
 |       this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str()); | 
 |     } | 
 |  | 
 |     return processed; | 
 |   } | 
 |  | 
 | private: | 
 |   cmSourceFile* SourceFile = nullptr; | 
 | }; | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( | 
 |   cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt) | 
 | { | 
 |   std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf); | 
 |  | 
 |   XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt, lang); | 
 |  | 
 |   // Add flags from target and source file properties. | 
 |   std::string flags; | 
 |   std::string const& srcfmt = sf->GetSafeProperty("Fortran_FORMAT"); | 
 |   switch (cmOutputConverter::GetFortranFormat(srcfmt)) { | 
 |     case cmOutputConverter::FortranFormatFixed: | 
 |       flags = cmStrCat("-fixed ", flags); | 
 |       break; | 
 |     case cmOutputConverter::FortranFormatFree: | 
 |       flags = cmStrCat("-free ", flags); | 
 |       break; | 
 |     default: | 
 |       break; | 
 |   } | 
 |  | 
 |   // Explicitly add the explicit language flag before any other flag | 
 |   // so user flags can override it. | 
 |   gtgt->AddExplicitLanguageFlags(flags, *sf); | 
 |  | 
 |   std::string const COMPILE_FLAGS("COMPILE_FLAGS"); | 
 |   if (cmValue cflags = sf->GetProperty(COMPILE_FLAGS)) { | 
 |     lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); | 
 |   } | 
 |   std::string const COMPILE_OPTIONS("COMPILE_OPTIONS"); | 
 |   if (cmValue coptions = sf->GetProperty(COMPILE_OPTIONS)) { | 
 |     lg->AppendCompileOptions( | 
 |       flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); | 
 |   } | 
 |  | 
 |   // Add per-source definitions. | 
 |   BuildObjectListOrString flagsBuild(this, false); | 
 |   std::string const COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); | 
 |   if (cmValue compile_defs = sf->GetProperty(COMPILE_DEFINITIONS)) { | 
 |     this->AppendDefines( | 
 |       flagsBuild, | 
 |       genexInterpreter.Evaluate(*compile_defs, COMPILE_DEFINITIONS).c_str(), | 
 |       true); | 
 |   } | 
 |  | 
 |   if (sf->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) { | 
 |     this->AppendDefines(flagsBuild, "CMAKE_SKIP_PRECOMPILE_HEADERS", true); | 
 |   } | 
 |  | 
 |   if (!flagsBuild.IsEmpty()) { | 
 |     if (!flags.empty()) { | 
 |       flags += ' '; | 
 |     } | 
 |     flags += flagsBuild.GetString(); | 
 |   } | 
 |  | 
 |   // Add per-source include directories. | 
 |   std::vector<std::string> includes; | 
 |   std::string const INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); | 
 |   if (cmValue cincludes = sf->GetProperty(INCLUDE_DIRECTORIES)) { | 
 |     lg->AppendIncludeDirectories( | 
 |       includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES), | 
 |       *sf); | 
 |   } | 
 |   lg->AppendFlags(flags, | 
 |                   lg->GetIncludeFlags(includes, gtgt, lang, std::string())); | 
 |  | 
 |   cmXCodeObject* buildFile = | 
 |     this->CreateXCodeBuildFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf); | 
 |  | 
 |   cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |   settings->AddAttributeIfNotEmpty("COMPILER_FLAGS", | 
 |                                    this->CreateString(flags)); | 
 |  | 
 |   cmGeneratorTarget::SourceFileFlags tsFlags = | 
 |     gtgt->GetTargetSourceFileFlags(sf); | 
 |  | 
 |   cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |  | 
 |   // Is this a "private" or "public" framework header file? | 
 |   // Set the ATTRIBUTES attribute appropriately... | 
 |   // | 
 |   if (gtgt->IsFrameworkOnApple()) { | 
 |     if (tsFlags.Type == cmGeneratorTarget::SourceFileTypePrivateHeader) { | 
 |       attrs->AddObject(this->CreateString("Private")); | 
 |     } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypePublicHeader) { | 
 |       attrs->AddObject(this->CreateString("Public")); | 
 |     } | 
 |   } | 
 |  | 
 |   // Add user-specified file attributes. | 
 |   cmValue extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES"); | 
 |   if (extraFileAttributes) { | 
 |     // Expand the list of attributes. | 
 |     cmList attributes{ *extraFileAttributes }; | 
 |  | 
 |     // Store the attributes. | 
 |     for (auto const& attribute : attributes) { | 
 |       attrs->AddObject(this->CreateString(attribute)); | 
 |     } | 
 |   } | 
 |  | 
 |   settings->AddAttributeIfNotEmpty("ATTRIBUTES", attrs); | 
 |  | 
 |   if (buildFile) { | 
 |     buildFile->AddAttributeIfNotEmpty("settings", settings); | 
 |   } | 
 |   return buildFile; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddXCodeProjBuildRule( | 
 |   cmGeneratorTarget* target, std::vector<cmSourceFile*>& sources) const | 
 | { | 
 |   std::string listfile = this->GetCMakeInstance()->GetCMakeListFile( | 
 |     target->GetLocalGenerator()->GetCurrentSourceDirectory()); | 
 |   cmSourceFile* srcCMakeLists = target->Makefile->GetOrCreateSource( | 
 |     listfile, false, cmSourceFileLocationKind::Known); | 
 |   srcCMakeLists->SetSpecialSourceType( | 
 |     cmSourceFile::SpecialSourceType::CMakeLists); | 
 |   if (!cm::contains(sources, srcCMakeLists)) { | 
 |     sources.push_back(srcCMakeLists); | 
 |   } | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | bool IsLinkPhaseLibraryExtension(std::string const& fileExt) | 
 | { | 
 |   // Empty file extension is a special case for paths to framework's | 
 |   // internal binary which could be MyFw.framework/Versions/*/MyFw | 
 |   return (fileExt == ".framework"_s || fileExt == ".xcframework"_s || | 
 |           fileExt == ".a"_s || fileExt == ".o"_s || fileExt == ".dylib"_s || | 
 |           fileExt == ".tbd"_s || fileExt.empty()); | 
 | } | 
 | bool IsLibraryType(std::string const& fileType) | 
 | { | 
 |   return (fileType == "wrapper.framework"_s || | 
 |           fileType == "wrapper.xcframework"_s || fileType == "archive.ar"_s || | 
 |           fileType == "compiled.mach-o.objfile"_s || | 
 |           fileType == "compiled.mach-o.dylib"_s || | 
 |           fileType == "compiled.mach-o.executable"_s || | 
 |           fileType == "sourcecode.text-based-dylib-definition"_s); | 
 | } | 
 |  | 
 | std::string GetDirectoryValueFromFileExtension(std::string const& dirExt) | 
 | { | 
 |   std::string ext = cmSystemTools::LowerCase(dirExt); | 
 |   if (ext == "framework"_s) { | 
 |     return "wrapper.framework"; | 
 |   } | 
 |   if (ext == "xcframework"_s) { | 
 |     return "wrapper.xcframework"; | 
 |   } | 
 |   if (ext == "xcassets"_s) { | 
 |     return "folder.assetcatalog"; | 
 |   } | 
 |   return "folder"; | 
 | } | 
 |  | 
 | std::string GetSourcecodeValueFromFileExtension( | 
 |   std::string const& _ext, std::string const& lang, | 
 |   bool& keepLastKnownFileType, std::vector<std::string> const& enabled_langs) | 
 | { | 
 |   std::string ext = cmSystemTools::LowerCase(_ext); | 
 |   std::string sourcecode = "default"; | 
 |  | 
 |   if (ext == "o"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "compiled.mach-o.objfile"; | 
 |   } else if (ext == "xctest"_s) { | 
 |     sourcecode = "wrapper.cfbundle"; | 
 |   } else if (ext == "xib"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "file.xib"; | 
 |   } else if (ext == "storyboard"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "file.storyboard"; | 
 |     // NOLINTNEXTLINE(bugprone-branch-clone) | 
 |   } else if (ext == "mm"_s && !cm::contains(enabled_langs, "OBJCXX")) { | 
 |     sourcecode = "sourcecode.cpp.objcpp"; | 
 |     // NOLINTNEXTLINE(bugprone-branch-clone) | 
 |   } else if (ext == "m"_s && !cm::contains(enabled_langs, "OBJC")) { | 
 |     sourcecode = "sourcecode.c.objc"; | 
 |   } else if (ext == "swift"_s) { | 
 |     sourcecode = "sourcecode.swift"; | 
 |   } else if (ext == "plist"_s) { | 
 |     sourcecode = "sourcecode.text.plist"; | 
 |   } else if (ext == "h"_s) { | 
 |     sourcecode = "sourcecode.c.h"; | 
 |   } else if (ext == "hxx"_s || ext == "hpp"_s || ext == "txx"_s || | 
 |              ext == "pch"_s || ext == "hh"_s || ext == "inl"_s) { | 
 |     sourcecode = "sourcecode.cpp.h"; | 
 |   } else if (ext == "png"_s || ext == "gif"_s || ext == "jpg"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "image"; | 
 |   } else if (ext == "txt"_s) { | 
 |     sourcecode = "sourcecode.text"; | 
 |   } else if (lang == "CXX"_s) { | 
 |     sourcecode = "sourcecode.cpp.cpp"; | 
 |   } else if (lang == "C"_s) { | 
 |     sourcecode = "sourcecode.c.c"; | 
 |   } else if (lang == "OBJCXX"_s) { | 
 |     sourcecode = "sourcecode.cpp.objcpp"; | 
 |   } else if (lang == "OBJC"_s) { | 
 |     sourcecode = "sourcecode.c.objc"; | 
 |   } else if (lang == "Fortran"_s) { | 
 |     sourcecode = "sourcecode.fortran.f90"; | 
 |   } else if (lang == "ASM"_s) { | 
 |     sourcecode = "sourcecode.asm"; | 
 |   } else if (ext == "metal"_s) { | 
 |     sourcecode = "sourcecode.metal"; | 
 |   } else if (ext == "mig"_s) { | 
 |     sourcecode = "sourcecode.mig"; | 
 |   } else if (ext == "tbd"_s) { | 
 |     sourcecode = "sourcecode.text-based-dylib-definition"; | 
 |   } else if (ext == "a"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "archive.ar"; | 
 |   } else if (ext == "dylib"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "compiled.mach-o.dylib"; | 
 |   } else if (ext == "framework"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "wrapper.framework"; | 
 |   } else if (ext == "xcassets"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "folder.assetcatalog"; | 
 |   } else if (ext == "xcconfig"_s) { | 
 |     keepLastKnownFileType = true; | 
 |     sourcecode = "text.xcconfig"; | 
 |   } | 
 |   // else | 
 |   //  { | 
 |   //  // Already specialized above or we leave sourcecode == "sourcecode" | 
 |   //  // which is probably the most correct choice. Extensionless headers, | 
 |   //  // for example... Or file types unknown to Xcode that do not map to a | 
 |   //  // valid explicitFileType value. | 
 |   //  } | 
 |  | 
 |   return sourcecode; | 
 | } | 
 |  | 
 | template <class T> | 
 | std::string GetTargetObjectDirArch(T const& target, | 
 |                                    std::string const& defaultVal) | 
 | { | 
 |   cmList archs{ target.GetSafeProperty("OSX_ARCHITECTURES") }; | 
 |   if (archs.size() > 1) { | 
 |     return "$(CURRENT_ARCH)"; | 
 |   } | 
 |   if (archs.size() == 1) { | 
 |     return archs.front(); | 
 |   } | 
 |   return defaultVal; | 
 | } | 
 |  | 
 | } // anonymous | 
 |  | 
 | // Extracts the framework directory, if path matches the framework syntax | 
 | // otherwise returns the path untouched | 
 | std::string cmGlobalXCodeGenerator::GetLibraryOrFrameworkPath( | 
 |   std::string const& path) const | 
 | { | 
 |   auto fwDescriptor = this->SplitFrameworkPath(path); | 
 |   if (fwDescriptor) { | 
 |     return fwDescriptor->GetFrameworkPath(); | 
 |   } | 
 |  | 
 |   return path; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( | 
 |   std::string const& fullpath, cmGeneratorTarget* target, | 
 |   std::string const& lang, cmSourceFile* sf) | 
 | { | 
 |   bool useLastKnownFileType = false; | 
 |   std::string fileType; | 
 |   if (sf) { | 
 |     if (cmValue e = sf->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) { | 
 |       fileType = *e; | 
 |     } else if (cmValue l = sf->GetProperty("XCODE_LAST_KNOWN_FILE_TYPE")) { | 
 |       useLastKnownFileType = true; | 
 |       fileType = *l; | 
 |     } | 
 |   } | 
 |   // Make a copy so that we can override it later | 
 |   std::string path = cmSystemTools::CollapseFullPath(fullpath); | 
 |   // Compute the extension without leading '.'. | 
 |   std::string ext = cmSystemTools::GetFilenameLastExtension(path); | 
 |   if (!ext.empty()) { | 
 |     ext = ext.substr(1); | 
 |   } | 
 |   if (fileType.empty()) { | 
 |     path = this->GetLibraryOrFrameworkPath(path); | 
 |     ext = cmSystemTools::GetFilenameLastExtension(path); | 
 |     if (!ext.empty()) { | 
 |       ext = ext.substr(1); | 
 |     } | 
 |     // If fullpath references a directory, then we need to specify | 
 |     // lastKnownFileType as folder in order for Xcode to be able to | 
 |     // open the contents of the folder. | 
 |     // (Xcode 4.6 does not like explicitFileType=folder). | 
 |     if (cmSystemTools::FileIsDirectory(path)) { | 
 |       fileType = GetDirectoryValueFromFileExtension(ext); | 
 |       useLastKnownFileType = true; | 
 |     } else { | 
 |       if (ext.empty() && !sf) { | 
 |         // Special case for executable or library without extension | 
 |         // that is not a source file. We can't tell which without reading | 
 |         // its Mach-O header, but the file might not exist yet, so we | 
 |         // have to pick one here. | 
 |         useLastKnownFileType = true; | 
 |         fileType = "compiled.mach-o.executable"; | 
 |       } else { | 
 |         fileType = GetSourcecodeValueFromFileExtension( | 
 |           ext, lang, useLastKnownFileType, this->EnabledLangs); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   std::string key = GetGroupMapKeyFromPath(target, path); | 
 |   cmXCodeObject* fileRef = this->FileRefs[key]; | 
 |   if (!fileRef) { | 
 |     fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); | 
 |     fileRef->SetComment(path); | 
 |     this->FileRefs[key] = fileRef; | 
 |   } | 
 |   fileRef->AddAttribute("fileEncoding", this->CreateString("4")); | 
 |   fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType" | 
 |                                              : "explicitFileType", | 
 |                         this->CreateString(fileType)); | 
 |   // Store the file path relative to the top of the source tree. | 
 |   if (!IsLibraryType(fileType)) { | 
 |     path = this->RelativeToSource(path); | 
 |   } | 
 |   std::string name = cmSystemTools::GetFilenameName(path); | 
 |   char const* sourceTree = | 
 |     cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT"; | 
 |   fileRef->AddAttribute("name", this->CreateString(name)); | 
 |   fileRef->AddAttribute("path", this->CreateString(path)); | 
 |   fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree)); | 
 |  | 
 |   cmXCodeObject* group = this->GroupMap[key]; | 
 |   if (!group) { | 
 |     if (IsLibraryType(fileType)) { | 
 |       group = this->FrameworkGroup; | 
 |     } else if (fileType == "folder") { | 
 |       group = this->ResourcesGroup; | 
 |     } | 
 |     if (group) | 
 |       this->GroupMap[key] = group; | 
 |   } | 
 |  | 
 |   if (!group) { | 
 |     cmSystemTools::Error(cmStrCat("Could not find a PBX group for ", key)); | 
 |     return nullptr; | 
 |   } | 
 |   cmXCodeObject* children = group->GetAttribute("children"); | 
 |   if (!children->HasObject(fileRef)) { | 
 |     children->AddObject(fileRef); | 
 |   } | 
 |   return fileRef; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReference( | 
 |   cmSourceFile* sf, cmGeneratorTarget* target) | 
 | { | 
 |   std::string lang = this->CurrentLocalGenerator->GetSourceFileLanguage(*sf); | 
 |  | 
 |   return this->CreateXCodeFileReferenceFromPath(sf->ResolveFullPath(), target, | 
 |                                                 lang, sf); | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::SpecialTargetEmitted(std::string const& tname) | 
 | { | 
 |   if (tname == "ALL_BUILD"_s || tname == "install"_s || tname == "package"_s || | 
 |       tname == "RUN_TESTS"_s || tname == CMAKE_CHECK_BUILD_SYSTEM_TARGET) { | 
 |     if (this->TargetDoneSet.find(tname) != this->TargetDoneSet.end()) { | 
 |       return true; | 
 |     } | 
 |     this->TargetDoneSet.insert(tname); | 
 |     return false; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen) | 
 | { | 
 |   this->CurrentLocalGenerator = gen; | 
 |   this->CurrentMakefile = gen->GetMakefile(); | 
 |  | 
 |   // Select the current set of configuration types. | 
 |   this->CurrentConfigurationTypes = | 
 |     this->CurrentMakefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); | 
 | } | 
 |  | 
 | struct cmSourceFilePathCompare | 
 | { | 
 |   bool operator()(cmSourceFile* l, cmSourceFile* r) | 
 |   { | 
 |     return l->ResolveFullPath() < r->ResolveFullPath(); | 
 |   } | 
 | }; | 
 |  | 
 | struct cmCompareTargets | 
 | { | 
 |   bool operator()(cmXCodeObject* l, cmXCodeObject* r) const | 
 |   { | 
 |     std::string const& a = l->GetTarget()->GetName(); | 
 |     std::string const& b = r->GetTarget()->GetName(); | 
 |     if (a == b) { | 
 |       return false; | 
 |     } | 
 |     if (a == "ALL_BUILD"_s) { | 
 |       return true; | 
 |     } | 
 |     if (b == "ALL_BUILD"_s) { | 
 |       return false; | 
 |     } | 
 |     std::string a_low = cmSystemTools::LowerCase(l->GetTarget()->GetName()); | 
 |     std::string b_low = cmSystemTools::LowerCase(r->GetTarget()->GetName()); | 
 |     if (a_low != b_low) { | 
 |       return a_low < b_low; | 
 |     } | 
 |     return a < b; | 
 |   } | 
 | }; | 
 |  | 
 | bool cmGlobalXCodeGenerator::CreateXCodeTargets( | 
 |   cmLocalGenerator* gen, std::vector<cmXCodeObject*>& targets) | 
 | { | 
 |   this->SetCurrentLocalGenerator(gen); | 
 |   std::vector<cmGeneratorTarget*> gts = | 
 |     this->GetLocalGeneratorTargetsInOrder(gen); | 
 |   for (auto* gtgt : gts) { | 
 |     if (!this->CreateXCodeTarget(gtgt, targets)) { | 
 |       return false; | 
 |     } | 
 |   } | 
 |   std::sort(targets.begin(), targets.end(), cmCompareTargets()); | 
 |   return true; | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::CreateXCodeTarget( | 
 |   cmGeneratorTarget* gtgt, std::vector<cmXCodeObject*>& targets) | 
 | { | 
 |   std::string targetName = gtgt->GetName(); | 
 |  | 
 |   // make sure ALL_BUILD, INSTALL, etc are only done once | 
 |   if (this->SpecialTargetEmitted(targetName)) { | 
 |     return true; | 
 |   } | 
 |  | 
 |   if (!gtgt->IsInBuildSystem()) { | 
 |     return true; | 
 |   } | 
 |  | 
 |   for (std::string const& configName : this->CurrentConfigurationTypes) { | 
 |     gtgt->CheckCxxModuleStatus(configName); | 
 |   } | 
 |  | 
 |   auto& gtgt_visited = this->CommandsVisited[gtgt]; | 
 |   auto const& deps = this->GetTargetDirectDepends(gtgt); | 
 |   for (auto const& d : deps) { | 
 |     // Take the union of visited source files of custom commands so far. | 
 |     // ComputeTargetOrder ensures our dependencies already visited their | 
 |     // custom commands and updated CommandsVisited. | 
 |     auto& dep_visited = this->CommandsVisited[d]; | 
 |     gtgt_visited.insert(dep_visited.begin(), dep_visited.end()); | 
 |   } | 
 |  | 
 |   if (gtgt->GetType() == cmStateEnums::UTILITY || | 
 |       gtgt->GetType() == cmStateEnums::INTERFACE_LIBRARY || | 
 |       gtgt->GetType() == cmStateEnums::GLOBAL_TARGET) { | 
 |     cmXCodeObject* t = this->CreateUtilityTarget(gtgt); | 
 |     if (!t) { | 
 |       return false; | 
 |     } | 
 |     targets.push_back(t); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // organize the sources | 
 |   std::vector<cmSourceFile*> commonSourceFiles; | 
 |   if (!gtgt->GetConfigCommonSourceFilesForXcode(commonSourceFiles)) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Add CMakeLists.txt file for user convenience. | 
 |   this->AddXCodeProjBuildRule(gtgt, commonSourceFiles); | 
 |  | 
 |   // Add the Info.plist we are about to generate for an App Bundle. | 
 |   if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { | 
 |     std::string plist = this->ComputeInfoPListLocation(gtgt); | 
 |     cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource( | 
 |       plist, true, cmSourceFileLocationKind::Known); | 
 |     sf->SetSpecialSourceType(cmSourceFile::SpecialSourceType::BundleInfoPlist); | 
 |     commonSourceFiles.push_back(sf); | 
 |   } | 
 |  | 
 |   std::sort(commonSourceFiles.begin(), commonSourceFiles.end(), | 
 |             cmSourceFilePathCompare()); | 
 |  | 
 |   gtgt->ComputeObjectMapping(); | 
 |  | 
 |   std::vector<cmXCodeObject*> externalObjFiles; | 
 |   std::vector<cmXCodeObject*> headerFiles; | 
 |   std::vector<cmXCodeObject*> resourceFiles; | 
 |   std::vector<cmXCodeObject*> sourceFiles; | 
 |   for (auto* sourceFile : commonSourceFiles) { | 
 |     cmXCodeObject* xsf = this->CreateXCodeSourceFile( | 
 |       this->CurrentLocalGenerator, sourceFile, gtgt); | 
 |     cmXCodeObject* fr = xsf->GetAttribute("fileRef"); | 
 |     cmXCodeObject* filetype = | 
 |       fr->GetObject()->GetAttribute("explicitFileType"); | 
 |     if (!filetype) { | 
 |       filetype = fr->GetObject()->GetAttribute("lastKnownFileType"); | 
 |     } | 
 |  | 
 |     cmGeneratorTarget::SourceFileFlags tsFlags = | 
 |       gtgt->GetTargetSourceFileFlags(sourceFile); | 
 |  | 
 |     if (filetype && filetype->GetString() == "compiled.mach-o.objfile"_s) { | 
 |       if (sourceFile->GetObjectLibrary().empty()) { | 
 |         externalObjFiles.push_back(xsf); | 
 |       } | 
 |     } else if (this->IsHeaderFile(sourceFile) || | 
 |                (tsFlags.Type == | 
 |                 cmGeneratorTarget::SourceFileTypePrivateHeader) || | 
 |                (tsFlags.Type == | 
 |                 cmGeneratorTarget::SourceFileTypePublicHeader)) { | 
 |       headerFiles.push_back(xsf); | 
 |     } else if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeResource) { | 
 |       resourceFiles.push_back(xsf); | 
 |     } else if (!sourceFile->GetPropertyAsBool("HEADER_FILE_ONLY") && | 
 |                !gtgt->IsSourceFilePartOfUnityBatch( | 
 |                  sourceFile->ResolveFullPath())) { | 
 |       // Include this file in the build if it has a known language | 
 |       // and has not been listed as an ignored extension for this | 
 |       // generator. | 
 |       if (!this->CurrentLocalGenerator->GetSourceFileLanguage(*sourceFile) | 
 |              .empty() && | 
 |           !this->IgnoreFile(sourceFile->GetExtension().c_str())) { | 
 |         sourceFiles.push_back(xsf); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // some build phases only apply to bundles and/or frameworks | 
 |   bool isFrameworkTarget = gtgt->IsFrameworkOnApple(); | 
 |   bool isBundleTarget = gtgt->GetPropertyAsBool("MACOSX_BUNDLE"); | 
 |   bool isCFBundleTarget = gtgt->IsCFBundleOnApple(); | 
 |  | 
 |   cmXCodeObject* buildFiles = nullptr; | 
 |  | 
 |   // create source build phase | 
 |   cmXCodeObject* sourceBuildPhase = nullptr; | 
 |   if (!sourceFiles.empty()) { | 
 |     sourceBuildPhase = this->CreateObject(cmXCodeObject::PBXSourcesBuildPhase); | 
 |     sourceBuildPhase->SetComment("Sources"); | 
 |     sourceBuildPhase->AddAttribute("buildActionMask", | 
 |                                    this->CreateString("2147483647")); | 
 |     buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |     for (auto& sourceFile : sourceFiles) { | 
 |       buildFiles->AddObject(sourceFile); | 
 |     } | 
 |     sourceBuildPhase->AddAttribute("files", buildFiles); | 
 |     sourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                                    this->CreateString("0")); | 
 |   } | 
 |  | 
 |   // create header build phase - only for framework targets | 
 |   cmXCodeObject* headerBuildPhase = nullptr; | 
 |   if (!headerFiles.empty() && isFrameworkTarget) { | 
 |     headerBuildPhase = this->CreateObject(cmXCodeObject::PBXHeadersBuildPhase); | 
 |     headerBuildPhase->SetComment("Headers"); | 
 |     headerBuildPhase->AddAttribute("buildActionMask", | 
 |                                    this->CreateString("2147483647")); | 
 |     buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |     for (auto& headerFile : headerFiles) { | 
 |       buildFiles->AddObject(headerFile); | 
 |     } | 
 |     headerBuildPhase->AddAttribute("files", buildFiles); | 
 |     headerBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                                    this->CreateString("0")); | 
 |   } | 
 |  | 
 |   // create resource build phase - only for framework or bundle targets | 
 |   cmXCodeObject* resourceBuildPhase = nullptr; | 
 |   if (!resourceFiles.empty() && | 
 |       (isFrameworkTarget || isBundleTarget || isCFBundleTarget)) { | 
 |     resourceBuildPhase = | 
 |       this->CreateObject(cmXCodeObject::PBXResourcesBuildPhase); | 
 |     resourceBuildPhase->SetComment("Resources"); | 
 |     resourceBuildPhase->AddAttribute("buildActionMask", | 
 |                                      this->CreateString("2147483647")); | 
 |     buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |     for (auto& resourceFile : resourceFiles) { | 
 |       buildFiles->AddObject(resourceFile); | 
 |     } | 
 |     resourceBuildPhase->AddAttribute("files", buildFiles); | 
 |     resourceBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                                      this->CreateString("0")); | 
 |   } | 
 |  | 
 |   // create vector of "non-resource content file" build phases - only for | 
 |   // framework or bundle targets | 
 |   std::vector<cmXCodeObject*> contentBuildPhases; | 
 |   if (isFrameworkTarget || isBundleTarget || isCFBundleTarget) { | 
 |     using mapOfVectorOfSourceFiles = | 
 |       std::map<std::string, std::vector<cmSourceFile*>>; | 
 |     mapOfVectorOfSourceFiles bundleFiles; | 
 |     for (auto* sourceFile : commonSourceFiles) { | 
 |       cmGeneratorTarget::SourceFileFlags tsFlags = | 
 |         gtgt->GetTargetSourceFileFlags(sourceFile); | 
 |       if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeMacContent) { | 
 |         bundleFiles[tsFlags.MacFolder].push_back(sourceFile); | 
 |       } | 
 |     } | 
 |     for (auto const& keySources : bundleFiles) { | 
 |       cmXCodeObject* copyFilesBuildPhase = | 
 |         this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase); | 
 |       copyFilesBuildPhase->SetComment("Copy files"); | 
 |       copyFilesBuildPhase->AddAttribute("buildActionMask", | 
 |                                         this->CreateString("2147483647")); | 
 |       copyFilesBuildPhase->AddAttribute("dstSubfolderSpec", | 
 |                                         this->CreateString("6")); | 
 |       std::ostringstream ostr; | 
 |       if (gtgt->IsFrameworkOnApple()) { | 
 |         // dstPath in frameworks is relative to Versions/<version> | 
 |         ostr << keySources.first; | 
 |       } else if (keySources.first != "MacOS"_s) { | 
 |         if (gtgt->Target->GetMakefile()->PlatformIsAppleEmbedded()) { | 
 |           ostr << keySources.first; | 
 |         } else { | 
 |           // dstPath in bundles is relative to Contents/MacOS | 
 |           ostr << "../" << keySources.first; | 
 |         } | 
 |       } | 
 |       copyFilesBuildPhase->AddAttribute("dstPath", | 
 |                                         this->CreateString(ostr.str())); | 
 |       copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                                         this->CreateString("0")); | 
 |       buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |       copyFilesBuildPhase->AddAttribute("files", buildFiles); | 
 |       for (auto* sourceFile : keySources.second) { | 
 |         cmXCodeObject* xsf = this->CreateXCodeSourceFile( | 
 |           this->CurrentLocalGenerator, sourceFile, gtgt); | 
 |         buildFiles->AddObject(xsf); | 
 |       } | 
 |       contentBuildPhases.push_back(copyFilesBuildPhase); | 
 |     } | 
 |   } | 
 |  | 
 |   // create vector of "resource content file" build phases - only for | 
 |   // framework or bundle targets | 
 |   if (isFrameworkTarget || isBundleTarget || isCFBundleTarget) { | 
 |     using mapOfVectorOfSourceFiles = | 
 |       std::map<std::string, std::vector<cmSourceFile*>>; | 
 |     mapOfVectorOfSourceFiles bundleFiles; | 
 |     for (auto* sourceFile : commonSourceFiles) { | 
 |       cmGeneratorTarget::SourceFileFlags tsFlags = | 
 |         gtgt->GetTargetSourceFileFlags(sourceFile); | 
 |       if (tsFlags.Type == cmGeneratorTarget::SourceFileTypeDeepResource) { | 
 |         bundleFiles[tsFlags.MacFolder].push_back(sourceFile); | 
 |       } | 
 |     } | 
 |     for (auto const& keySources : bundleFiles) { | 
 |       cmXCodeObject* copyFilesBuildPhase = | 
 |         this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase); | 
 |       copyFilesBuildPhase->SetComment("Copy files"); | 
 |       copyFilesBuildPhase->AddAttribute("buildActionMask", | 
 |                                         this->CreateString("2147483647")); | 
 |       copyFilesBuildPhase->AddAttribute("dstSubfolderSpec", | 
 |                                         this->CreateString("7")); | 
 |       copyFilesBuildPhase->AddAttribute("dstPath", | 
 |                                         this->CreateString(keySources.first)); | 
 |       copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                                         this->CreateString("0")); | 
 |       buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |       copyFilesBuildPhase->AddAttribute("files", buildFiles); | 
 |       for (auto* sourceFile : keySources.second) { | 
 |         cmXCodeObject* xsf = this->CreateXCodeSourceFile( | 
 |           this->CurrentLocalGenerator, sourceFile, gtgt); | 
 |         buildFiles->AddObject(xsf); | 
 |       } | 
 |       contentBuildPhases.push_back(copyFilesBuildPhase); | 
 |     } | 
 |   } | 
 |  | 
 |   // Always create Link Binary With Libraries build phase | 
 |   cmXCodeObject* frameworkBuildPhase = nullptr; | 
 |   frameworkBuildPhase = | 
 |     this->CreateObject(cmXCodeObject::PBXFrameworksBuildPhase); | 
 |   frameworkBuildPhase->SetComment("Frameworks"); | 
 |   frameworkBuildPhase->AddAttribute("buildActionMask", | 
 |                                     this->CreateString("2147483647")); | 
 |   buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   frameworkBuildPhase->AddAttribute("files", buildFiles); | 
 |   // Add all collected .o files to this build phase | 
 |   for (auto& externalObjFile : externalObjFiles) { | 
 |     buildFiles->AddObject(externalObjFile); | 
 |   } | 
 |   frameworkBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                                     this->CreateString("0")); | 
 |  | 
 |   // create list of build phases and create the Xcode target | 
 |   cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |  | 
 |   this->CreateCustomCommands(buildPhases, sourceBuildPhase, headerBuildPhase, | 
 |                              resourceBuildPhase, contentBuildPhases, | 
 |                              frameworkBuildPhase, gtgt); | 
 |  | 
 |   targets.push_back(this->CreateXCodeTarget(gtgt, buildPhases)); | 
 |   return true; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::ForceLinkerLanguages() | 
 | { | 
 |   for (auto const& localGenerator : this->LocalGenerators) { | 
 |     // All targets depend on the build-system check target. | 
 |     for (auto const& tgt : localGenerator->GetGeneratorTargets()) { | 
 |       // This makes sure all targets link using the proper language. | 
 |       this->ForceLinkerLanguage(tgt.get()); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt) | 
 | { | 
 |   // This matters only for targets that link. | 
 |   if (gtgt->GetType() != cmStateEnums::EXECUTABLE && | 
 |       gtgt->GetType() != cmStateEnums::SHARED_LIBRARY && | 
 |       gtgt->GetType() != cmStateEnums::MODULE_LIBRARY) { | 
 |     return; | 
 |   } | 
 |  | 
 |   std::string llang = gtgt->GetLinkerLanguage("NOCONFIG"); | 
 |   if (llang.empty()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // If the language is compiled as a source trust Xcode to link with it. | 
 |   for (auto const& Language : | 
 |        gtgt->GetLinkImplementation("NOCONFIG", cmGeneratorTarget::UseTo::Link) | 
 |          ->Languages) { | 
 |     if (Language == llang) { | 
 |       return; | 
 |     } | 
 |   } | 
 |  | 
 |   // Allow empty source file list for iOS Sticker packs | 
 |   cm::string_view productType = this->GetTargetProductType(gtgt); | 
 |   if (productType == | 
 |       "com.apple.product-type.app-extension.messages-sticker-pack"_s) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // Add an empty source file to the target that compiles with the | 
 |   // linker language.  This should convince Xcode to choose the proper | 
 |   // language. | 
 |   cmMakefile* mf = gtgt->Target->GetMakefile(); | 
 |   std::string fname = cmStrCat( | 
 |     gtgt->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/CMakeFiles/", | 
 |     gtgt->GetName(), "-CMakeForceLinker.", cmSystemTools::LowerCase(llang)); | 
 |   { | 
 |     cmGeneratedFileStream fout(fname); | 
 |     fout << '\n'; | 
 |   } | 
 |   if (cmSourceFile* sf = mf->GetOrCreateSource(fname)) { | 
 |     sf->SetSpecialSourceType( | 
 |       cmSourceFile::SpecialSourceType::XcodeForceLinkerSource); | 
 |     sf->SetProperty("LANGUAGE", llang); | 
 |     sf->SetProperty("CXX_SCAN_FOR_MODULES", "0"); | 
 |     gtgt->AddSource(fname); | 
 |   } | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::IsHeaderFile(cmSourceFile* sf) | 
 | { | 
 |   return cm::contains(this->CMakeInstance->GetHeaderExtensions(), | 
 |                       sf->GetExtension()); | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateLegacyRunScriptBuildPhase( | 
 |   char const* name, char const* name2, cmGeneratorTarget* target, | 
 |   std::vector<cmCustomCommand> const& commands) | 
 | { | 
 |   if (commands.empty() && strcmp(name, "CMake ReRun") != 0) { | 
 |     return nullptr; | 
 |   } | 
 |   cmXCodeObject* buildPhase = | 
 |     this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase); | 
 |   buildPhase->AddAttribute("buildActionMask", | 
 |                            this->CreateString("2147483647")); | 
 |   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   buildPhase->AddAttribute("files", buildFiles); | 
 |   buildPhase->AddAttribute("name", this->CreateString(name)); | 
 |   buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                            this->CreateString("0")); | 
 |   buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh")); | 
 |   this->AddCommandsToBuildPhase(buildPhase, target, commands, name2); | 
 |   return buildPhase; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateCustomCommands( | 
 |   cmXCodeObject* buildPhases, cmXCodeObject* sourceBuildPhase, | 
 |   cmXCodeObject* headerBuildPhase, cmXCodeObject* resourceBuildPhase, | 
 |   std::vector<cmXCodeObject*> const& contentBuildPhases, | 
 |   cmXCodeObject* frameworkBuildPhase, cmGeneratorTarget* gtgt) | 
 | { | 
 |   std::vector<cmCustomCommand> const& prebuild = gtgt->GetPreBuildCommands(); | 
 |   std::vector<cmCustomCommand> const& prelink = gtgt->GetPreLinkCommands(); | 
 |   std::vector<cmCustomCommand> postbuild = gtgt->GetPostBuildCommands(); | 
 |  | 
 |   if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY && | 
 |       !gtgt->IsFrameworkOnApple()) { | 
 |     std::string str_file = cmStrCat("$<TARGET_FILE:", gtgt->GetName(), '>'); | 
 |     std::string str_so_file = | 
 |       cmStrCat("$<TARGET_SONAME_FILE:", gtgt->GetName(), '>'); | 
 |     std::string str_link_file = | 
 |       cmStrCat("$<TARGET_LINKER_LIBRARY_FILE:", gtgt->GetName(), '>'); | 
 |     cmCustomCommandLines cmd = cmMakeSingleCommandLine( | 
 |       { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", | 
 |         str_file, str_so_file, str_link_file }); | 
 |  | 
 |     cmCustomCommand command; | 
 |     command.SetCommandLines(cmd); | 
 |     command.SetComment("Creating symlinks"); | 
 |     command.SetWorkingDirectory(""); | 
 |     command.SetBacktrace(this->CurrentMakefile->GetBacktrace()); | 
 |     command.SetStdPipesUTF8(true); | 
 |  | 
 |     postbuild.push_back(std::move(command)); | 
 |   } | 
 |  | 
 |   if (gtgt->HasImportLibrary("") && !gtgt->IsFrameworkOnApple()) { | 
 |     // create symbolic links for .tbd file | 
 |     std::string file = cmStrCat("$<TARGET_IMPORT_FILE:", gtgt->GetName(), '>'); | 
 |     std::string soFile = | 
 |       cmStrCat("$<TARGET_SONAME_IMPORT_FILE:", gtgt->GetName(), '>'); | 
 |     std::string linkFile = | 
 |       cmStrCat("$<TARGET_LINKER_IMPORT_FILE:", gtgt->GetName(), '>'); | 
 |     cmCustomCommandLines symlink_command = cmMakeSingleCommandLine( | 
 |       { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", file, | 
 |         soFile, linkFile }); | 
 |  | 
 |     cmCustomCommand command; | 
 |     command.SetCommandLines(symlink_command); | 
 |     command.SetComment("Creating import symlinks"); | 
 |     command.SetWorkingDirectory(""); | 
 |     command.SetBacktrace(this->CurrentMakefile->GetBacktrace()); | 
 |     command.SetStdPipesUTF8(true); | 
 |  | 
 |     postbuild.push_back(std::move(command)); | 
 |   } | 
 |  | 
 |   cmXCodeObject* legacyCustomCommandsBuildPhase = nullptr; | 
 |   cmXCodeObject* preBuildPhase = nullptr; | 
 |   cmXCodeObject* preLinkPhase = nullptr; | 
 |   cmXCodeObject* postBuildPhase = nullptr; | 
 |  | 
 |   if (this->XcodeBuildSystem >= BuildSystem::Twelve) { | 
 |     // create prebuild phase | 
 |     preBuildPhase = | 
 |       this->CreateRunScriptBuildPhase("CMake PreBuild Rules", gtgt, prebuild); | 
 |     // create prelink phase | 
 |     preLinkPhase = | 
 |       this->CreateRunScriptBuildPhase("CMake PreLink Rules", gtgt, prelink); | 
 |  | 
 |     std::vector<std::string> depends; | 
 |     if (gtgt->IsBundleOnApple()) { | 
 |       // In Xcode 16+ the POST_BUILD phase needs explicit dependencies to | 
 |       // ensure it runs after certain bundle files are generated. | 
 |       depends = { | 
 |         "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/" | 
 |         "Contents/Resources/DWARF/${PRODUCT_NAME}", | 
 |         "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/" | 
 |         "Contents/Info.plist", | 
 |         "$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)", | 
 |         "$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)", | 
 |       }; | 
 |       if (resourceBuildPhase) { | 
 |         auto resourceFiles = resourceBuildPhase->GetAttribute("files"); | 
 |         for (auto xsf : resourceFiles->GetObjectList()) { | 
 |           auto fileRef = xsf->GetAttribute("fileRef"); | 
 |           auto fileObj = fileRef->GetObject(); | 
 |           auto path = fileObj->GetAttribute("path"); | 
 |           auto fileName = cmSystemTools::GetFilenameName(path->GetString()); | 
 |           if (cmSystemTools::GetFilenameLastExtension(fileName) == ".plist") { | 
 |             depends.push_back( | 
 |               "$(TARGET_BUILD_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/" + | 
 |               fileName); | 
 |           } | 
 |         } | 
 |       } | 
 |     } | 
 |     // create postbuild phase | 
 |     postBuildPhase = this->CreateRunScriptBuildPhase("CMake PostBuild Rules", | 
 |                                                      gtgt, postbuild, depends); | 
 |   } else { | 
 |     std::vector<cmSourceFile*> classes; | 
 |     if (!gtgt->GetConfigCommonSourceFilesForXcode(classes)) { | 
 |       return; | 
 |     } | 
 |     // add all the sources | 
 |     std::vector<cmCustomCommand> commands; | 
 |     auto& visited = this->CommandsVisited[gtgt]; | 
 |     for (auto* sourceFile : classes) { | 
 |       if (sourceFile->GetCustomCommand() && | 
 |           visited.insert(sourceFile).second) { | 
 |         commands.push_back(*sourceFile->GetCustomCommand()); | 
 |       } | 
 |     } | 
 |     // create custom commands phase | 
 |     legacyCustomCommandsBuildPhase = this->CreateLegacyRunScriptBuildPhase( | 
 |       "CMake Rules", "cmakeRulesBuildPhase", gtgt, commands); | 
 |     // create prebuild phase | 
 |     preBuildPhase = this->CreateLegacyRunScriptBuildPhase( | 
 |       "CMake PreBuild Rules", "preBuildCommands", gtgt, prebuild); | 
 |     // create prelink phase | 
 |     preLinkPhase = this->CreateLegacyRunScriptBuildPhase( | 
 |       "CMake PreLink Rules", "preLinkCommands", gtgt, prelink); | 
 |     // create postbuild phase | 
 |     postBuildPhase = this->CreateLegacyRunScriptBuildPhase( | 
 |       "CMake PostBuild Rules", "postBuildPhase", gtgt, postbuild); | 
 |   } | 
 |  | 
 |   // The order here is the order they will be built in. | 
 |   // The order "headers, resources, sources" mimics a native project generated | 
 |   // from an xcode template... | 
 |   // | 
 |   if (preBuildPhase) { | 
 |     buildPhases->AddObject(preBuildPhase); | 
 |   } | 
 |   if (legacyCustomCommandsBuildPhase) { | 
 |     buildPhases->AddObject(legacyCustomCommandsBuildPhase); | 
 |   } | 
 |   if (this->XcodeBuildSystem >= BuildSystem::Twelve) { | 
 |     this->CreateRunScriptBuildPhases(buildPhases, gtgt); | 
 |   } | 
 |   if (headerBuildPhase) { | 
 |     buildPhases->AddObject(headerBuildPhase); | 
 |   } | 
 |   if (resourceBuildPhase) { | 
 |     buildPhases->AddObject(resourceBuildPhase); | 
 |   } | 
 |   for (auto* obj : contentBuildPhases) { | 
 |     buildPhases->AddObject(obj); | 
 |   } | 
 |   if (sourceBuildPhase) { | 
 |     buildPhases->AddObject(sourceBuildPhase); | 
 |   } | 
 |   if (preLinkPhase) { | 
 |     buildPhases->AddObject(preLinkPhase); | 
 |   } | 
 |   if (frameworkBuildPhase) { | 
 |     buildPhases->AddObject(frameworkBuildPhase); | 
 |   } | 
 |  | 
 |   // When this build phase is present, it must be last. More build phases may | 
 |   // be added later for embedding things and they will insert themselves just | 
 |   // before this last build phase. | 
 |   if (postBuildPhase) { | 
 |     buildPhases->AddObject(postBuildPhase); | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases( | 
 |   cmXCodeObject* buildPhases, cmGeneratorTarget const* gt) | 
 | { | 
 |   std::vector<cmSourceFile*> sources; | 
 |   if (!gt->GetConfigCommonSourceFilesForXcode(sources)) { | 
 |     return; | 
 |   } | 
 |   auto& visited = this->CommandsVisited[gt]; | 
 |   for (auto* sf : sources) { | 
 |     this->CreateRunScriptBuildPhases(buildPhases, sf, gt, visited); | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases( | 
 |   cmXCodeObject* buildPhases, cmSourceFile const* sf, | 
 |   cmGeneratorTarget const* gt, std::set<cmSourceFile const*>& visited) | 
 | { | 
 |   cmCustomCommand const* cc = sf->GetCustomCommand(); | 
 |   if (cc && visited.insert(sf).second) { | 
 |     this->CustomCommandRoots[sf].insert(gt); | 
 |     if (std::vector<cmSourceFile*> const* depends = gt->GetSourceDepends(sf)) { | 
 |       for (cmSourceFile const* di : *depends) { | 
 |         this->CreateRunScriptBuildPhases(buildPhases, di, gt, visited); | 
 |       } | 
 |     } | 
 |     cmXCodeObject* buildPhase = this->CreateRunScriptBuildPhase(sf, gt, *cc); | 
 |     buildPhases->AddObject(buildPhase); | 
 |   } | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase( | 
 |   cmSourceFile const* sf, cmGeneratorTarget const* gt, | 
 |   cmCustomCommand const& cc) | 
 | { | 
 |   std::set<std::string> allConfigInputs; | 
 |   std::set<std::string> allConfigOutputs; | 
 |  | 
 |   cmXCodeObject* buildPhase = | 
 |     this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase, | 
 |                        cmStrCat(gt->GetName(), ':', sf->GetFullPath())); | 
 |  | 
 |   auto depfilesDirectory = cmStrCat( | 
 |     gt->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/CMakeFiles/d/"); | 
 |   auto depfilesPrefix = cmStrCat(depfilesDirectory, buildPhase->GetId(), '.'); | 
 |  | 
 |   std::string shellScript = "set -e\n"; | 
 |   for (std::string const& configName : this->CurrentConfigurationTypes) { | 
 |     cmCustomCommandGenerator ccg( | 
 |       cc, configName, this->CurrentLocalGenerator, true, {}, | 
 |       [&depfilesPrefix](std::string const& config, std::string const&) | 
 |         -> std::string { return cmStrCat(depfilesPrefix, config, ".d"); }); | 
 |     std::vector<std::string> realDepends; | 
 |     realDepends.reserve(ccg.GetDepends().size()); | 
 |     for (auto const& d : ccg.GetDepends()) { | 
 |       std::string dep; | 
 |       if (this->CurrentLocalGenerator->GetRealDependency(d, configName, dep)) { | 
 |         realDepends.emplace_back(std::move(dep)); | 
 |       } | 
 |     } | 
 |  | 
 |     allConfigInputs.insert(realDepends.begin(), realDepends.end()); | 
 |     allConfigOutputs.insert(ccg.GetByproducts().begin(), | 
 |                             ccg.GetByproducts().end()); | 
 |     allConfigOutputs.insert(ccg.GetOutputs().begin(), ccg.GetOutputs().end()); | 
 |  | 
 |     shellScript = | 
 |       cmStrCat(shellScript, R"(if test "$CONFIGURATION" = ")", configName, | 
 |                "\"; then :\n", this->ConstructScript(ccg), "fi\n"); | 
 |   } | 
 |  | 
 |   if (!cc.GetDepfile().empty()) { | 
 |     buildPhase->AddAttribute( | 
 |       "dependencyFile", | 
 |       this->CreateString(cmStrCat(depfilesDirectory, buildPhase->GetId(), | 
 |                                   ".$(CONFIGURATION).d"))); | 
 |     // to avoid spurious errors during first build,  create empty dependency | 
 |     // files | 
 |     cmSystemTools::MakeDirectory(depfilesDirectory); | 
 |     for (std::string const& configName : this->CurrentConfigurationTypes) { | 
 |       auto file = cmStrCat(depfilesPrefix, configName, ".d"); | 
 |       if (!cmSystemTools::FileExists(file)) { | 
 |         cmSystemTools::Touch(file, true); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   buildPhase->AddAttribute("buildActionMask", | 
 |                            this->CreateString("2147483647")); | 
 |   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   buildPhase->AddAttribute("files", buildFiles); | 
 |   { | 
 |     std::string name; | 
 |     if (!allConfigOutputs.empty()) { | 
 |       name = cmStrCat("Generate ", | 
 |                       this->RelativeToBinary(*allConfigOutputs.begin())); | 
 |     } else { | 
 |       name = sf->GetLocation().GetName(); | 
 |     } | 
 |     buildPhase->AddAttribute("name", this->CreateString(name)); | 
 |   } | 
 |   buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                            this->CreateString("0")); | 
 |   buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh")); | 
 |   buildPhase->AddAttribute("shellScript", this->CreateString(shellScript)); | 
 |   buildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0")); | 
 |  | 
 |   bool symbolic = false; | 
 |   { | 
 |     cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |     for (std::string const& i : allConfigInputs) { | 
 |       inputPaths->AddUniqueObject(this->CreateString(i)); | 
 |       if (!symbolic) { | 
 |         if (cmSourceFile* isf = | 
 |               gt->GetLocalGenerator()->GetMakefile()->GetSource( | 
 |                 i, cmSourceFileLocationKind::Known)) { | 
 |           symbolic = isf->GetPropertyAsBool("SYMBOLIC"); | 
 |         } | 
 |       } | 
 |     } | 
 |     buildPhase->AddAttribute("inputPaths", inputPaths); | 
 |   } | 
 |   { | 
 |     cmXCodeObject* outputPaths = | 
 |       this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |     for (std::string const& o : allConfigOutputs) { | 
 |       outputPaths->AddUniqueObject(this->CreateString(o)); | 
 |       if (!symbolic) { | 
 |         if (cmSourceFile* osf = | 
 |               gt->GetLocalGenerator()->GetMakefile()->GetSource( | 
 |                 o, cmSourceFileLocationKind::Known)) { | 
 |           symbolic = osf->GetPropertyAsBool("SYMBOLIC"); | 
 |         } | 
 |       } | 
 |     } | 
 |     buildPhase->AddAttribute("outputPaths", outputPaths); | 
 |   } | 
 |   if (symbolic) { | 
 |     buildPhase->AddAttribute("alwaysOutOfDate", this->CreateString("1")); | 
 |   } | 
 |  | 
 |   return buildPhase; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateRunScriptBuildPhase( | 
 |   std::string const& name, cmGeneratorTarget const* gt, | 
 |   std::vector<cmCustomCommand> const& commands, | 
 |   std::vector<std::string> const& depends) | 
 | { | 
 |   if (commands.empty()) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   std::set<std::string> allConfigOutputs; | 
 |  | 
 |   std::string shellScript = "set -e\n"; | 
 |   for (std::string const& configName : this->CurrentConfigurationTypes) { | 
 |     shellScript = cmStrCat(shellScript, R"(if test "$CONFIGURATION" = ")", | 
 |                            configName, "\"; then :\n"); | 
 |     for (cmCustomCommand const& cc : commands) { | 
 |       cmCustomCommandGenerator ccg(cc, configName, | 
 |                                    this->CurrentLocalGenerator); | 
 |       shellScript = cmStrCat(shellScript, this->ConstructScript(ccg)); | 
 |       allConfigOutputs.insert(ccg.GetByproducts().begin(), | 
 |                               ccg.GetByproducts().end()); | 
 |     } | 
 |     shellScript = cmStrCat(shellScript, "fi\n"); | 
 |   } | 
 |  | 
 |   cmXCodeObject* buildPhase = | 
 |     this->CreateObject(cmXCodeObject::PBXShellScriptBuildPhase, | 
 |                        cmStrCat(gt->GetName(), ':', name)); | 
 |   buildPhase->AddAttribute("buildActionMask", | 
 |                            this->CreateString("2147483647")); | 
 |   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   buildPhase->AddAttribute("files", buildFiles); | 
 |   buildPhase->AddAttribute("name", this->CreateString(name)); | 
 |   buildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                            this->CreateString("0")); | 
 |   buildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh")); | 
 |   buildPhase->AddAttribute("shellScript", this->CreateString(shellScript)); | 
 |   buildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0")); | 
 |   { | 
 |     cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |     for (std::string const& s : depends) { | 
 |       inputPaths->AddUniqueObject(this->CreateString(s)); | 
 |     } | 
 |     buildPhase->AddAttribute("inputPaths", inputPaths); | 
 |   } | 
 |   { | 
 |     cmXCodeObject* outputPaths = | 
 |       this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |     for (std::string const& o : allConfigOutputs) { | 
 |       outputPaths->AddUniqueObject(this->CreateString(o)); | 
 |     } | 
 |     buildPhase->AddAttribute("outputPaths", outputPaths); | 
 |   } | 
 |   buildPhase->AddAttribute("alwaysOutOfDate", this->CreateString("1")); | 
 |  | 
 |   return buildPhase; | 
 | } | 
 |  | 
 | namespace { | 
 | void ReplaceScriptVars(std::string& cmd) | 
 | { | 
 |   cmSystemTools::ReplaceString(cmd, "$(CONFIGURATION)", "$CONFIGURATION"); | 
 |   cmSystemTools::ReplaceString(cmd, "$(EFFECTIVE_PLATFORM_NAME)", | 
 |                                "$EFFECTIVE_PLATFORM_NAME"); | 
 | } | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::ConstructScript( | 
 |   cmCustomCommandGenerator const& ccg) | 
 | { | 
 |   std::string script; | 
 |   cmLocalGenerator* lg = this->CurrentLocalGenerator; | 
 |   std::string wd = ccg.GetWorkingDirectory(); | 
 |   if (wd.empty()) { | 
 |     wd = lg->GetCurrentBinaryDirectory(); | 
 |   } | 
 |   wd = lg->ConvertToOutputFormat(wd, cmOutputConverter::SHELL); | 
 |   ReplaceScriptVars(wd); | 
 |   script = cmStrCat(script, "  cd ", wd, '\n'); | 
 |   for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) { | 
 |     std::string cmd = ccg.GetCommand(c); | 
 |     if (cmd.empty()) { | 
 |       continue; | 
 |     } | 
 |     cmSystemTools::ReplaceString(cmd, "/./", "/"); | 
 |     cmd = lg->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL); | 
 |     ccg.AppendArguments(c, cmd); | 
 |     ReplaceScriptVars(cmd); | 
 |     script = cmStrCat(script, "  ", cmd, '\n'); | 
 |   } | 
 |   return script; | 
 | } | 
 |  | 
 | // This function removes each occurrence of the flag and returns the last one | 
 | // (i.e., the dominant flag in GCC) | 
 | std::string cmGlobalXCodeGenerator::ExtractFlag(char const* flag, | 
 |                                                 std::string& flags) | 
 | { | 
 |   std::string retFlag; | 
 |   std::string::size_type lastOccurrencePos = flags.rfind(flag); | 
 |   bool saved = false; | 
 |   while (lastOccurrencePos != std::string::npos) { | 
 |     // increment pos, we use lastOccurrencePos to reduce search space on next | 
 |     // inc | 
 |     std::string::size_type pos = lastOccurrencePos; | 
 |     if (pos == 0 || flags[pos - 1] == ' ') { | 
 |       while (pos < flags.size() && flags[pos] != ' ') { | 
 |         if (!saved) { | 
 |           retFlag += flags[pos]; | 
 |         } | 
 |         flags[pos] = ' '; | 
 |         pos++; | 
 |       } | 
 |       saved = true; | 
 |     } | 
 |     // decrement lastOccurrencePos while making sure we don't loop around | 
 |     // and become a very large positive number since size_type is unsigned | 
 |     lastOccurrencePos = lastOccurrencePos == 0 ? 0 : lastOccurrencePos - 1; | 
 |     lastOccurrencePos = flags.rfind(flag, lastOccurrencePos); | 
 |   } | 
 |   return retFlag; | 
 | } | 
 |  | 
 | // This function removes each matching occurrence of the expression and | 
 | // returns the last one (i.e., the dominant flag in GCC) | 
 | std::string cmGlobalXCodeGenerator::ExtractFlagRegex(char const* exp, | 
 |                                                      int matchIndex, | 
 |                                                      std::string& flags) | 
 | { | 
 |   std::string retFlag; | 
 |  | 
 |   cmsys::RegularExpression regex(exp); | 
 |   assert(regex.is_valid()); | 
 |   if (!regex.is_valid()) { | 
 |     return retFlag; | 
 |   } | 
 |  | 
 |   std::string::size_type offset = 0; | 
 |  | 
 |   while (regex.find(&flags[offset])) { | 
 |     std::string::size_type const startPos = offset + regex.start(matchIndex); | 
 |     std::string::size_type const endPos = offset + regex.end(matchIndex); | 
 |     std::string::size_type const size = endPos - startPos; | 
 |  | 
 |     offset = startPos + 1; | 
 |  | 
 |     retFlag.assign(flags, startPos, size); | 
 |     flags.replace(startPos, size, size, ' '); | 
 |   } | 
 |  | 
 |   return retFlag; | 
 | } | 
 |  | 
 | //---------------------------------------------------------------------------- | 
 | // This function strips off Xcode attributes that do not target the current | 
 | // configuration | 
 | void cmGlobalXCodeGenerator::FilterConfigurationAttribute( | 
 |   std::string const& configName, std::string& attribute) | 
 | { | 
 |   // Handle [variant=<config>] condition explicitly here. | 
 |   std::string::size_type beginVariant = attribute.find("[variant="); | 
 |   if (beginVariant == std::string::npos) { | 
 |     // There is no variant in this attribute. | 
 |     return; | 
 |   } | 
 |  | 
 |   std::string::size_type endVariant = attribute.find(']', beginVariant + 9); | 
 |   if (endVariant == std::string::npos) { | 
 |     // There is no terminating bracket. | 
 |     return; | 
 |   } | 
 |  | 
 |   // Compare the variant to the configuration. | 
 |   std::string variant = | 
 |     attribute.substr(beginVariant + 9, endVariant - beginVariant - 9); | 
 |   if (variant == configName) { | 
 |     // The variant matches the configuration so use this | 
 |     // attribute but drop the [variant=<config>] condition. | 
 |     attribute.erase(beginVariant, endVariant - beginVariant + 1); | 
 |   } else { | 
 |     // The variant does not match the configuration so | 
 |     // do not use this attribute. | 
 |     attribute.clear(); | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddCommandsToBuildPhase( | 
 |   cmXCodeObject* buildphase, cmGeneratorTarget* target, | 
 |   std::vector<cmCustomCommand> const& commands, char const* name) | 
 | { | 
 |   std::string dir = cmStrCat( | 
 |     this->CurrentLocalGenerator->GetCurrentBinaryDirectory(), "/CMakeScripts"); | 
 |   cmSystemTools::MakeDirectory(dir); | 
 |   std::string makefile = | 
 |     cmStrCat(dir, '/', target->GetName(), '_', name, ".make"); | 
 |  | 
 |   for (auto const& currentConfig : this->CurrentConfigurationTypes) { | 
 |     this->CreateCustomRulesMakefile(makefile.c_str(), target, commands, | 
 |                                     currentConfig); | 
 |   } | 
 |  | 
 |   std::string cdir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory(); | 
 |   cdir = cmSystemTools::ConvertToOutputPath(cdir); | 
 |   std::string makecmd = cmStrCat( | 
 |     "make -C ", cdir, " -f ", cmSystemTools::ConvertToOutputPath(makefile), | 
 |     "$CONFIGURATION OBJDIR=$(basename \"$OBJECT_FILE_DIR_normal\") all"); | 
 |   buildphase->AddAttribute("shellScript", this->CreateString(makecmd)); | 
 |   buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0")); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( | 
 |   char const* makefileBasename, cmGeneratorTarget* target, | 
 |   std::vector<cmCustomCommand> const& commands, std::string const& configName) | 
 | { | 
 |   std::string makefileName = cmStrCat(makefileBasename, configName); | 
 |   cmGeneratedFileStream makefileStream(makefileName); | 
 |   if (!makefileStream) { | 
 |     return; | 
 |   } | 
 |   makefileStream.SetCopyIfDifferent(true); | 
 |   makefileStream << "# Generated by CMake, DO NOT EDIT\n" | 
 |                     "# Custom rules for " | 
 |                  << target->GetName() << '\n'; | 
 |  | 
 |   // disable the implicit rules | 
 |   makefileStream << ".SUFFIXES: " | 
 |                     "\n"; | 
 |  | 
 |   // have all depend on all outputs | 
 |   makefileStream << "all: "; | 
 |   std::map<cmCustomCommand const*, std::string> tname; | 
 |   int count = 0; | 
 |   for (auto const& command : commands) { | 
 |     cmCustomCommandGenerator ccg(command, configName, | 
 |                                  this->CurrentLocalGenerator); | 
 |     if (ccg.GetNumberOfCommands() > 0) { | 
 |       std::vector<std::string> const& outputs = ccg.GetOutputs(); | 
 |       if (!outputs.empty()) { | 
 |         for (auto const& output : outputs) { | 
 |           makefileStream << "\\\n\t" << ConvertToMakefilePath(output); | 
 |         } | 
 |       } else { | 
 |         std::ostringstream str; | 
 |         str << "_buildpart_" << count++; | 
 |         tname[&ccg.GetCC()] = cmStrCat(target->GetName(), str.str()); | 
 |         makefileStream << "\\\n\t" << tname[&ccg.GetCC()]; | 
 |       } | 
 |     } | 
 |   } | 
 |   makefileStream << "\n\n"; | 
 |  | 
 |   auto depfilesDirectory = | 
 |     cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), | 
 |              "/CMakeFiles/d/"); | 
 |  | 
 |   for (auto const& command : commands) { | 
 |     cmCustomCommandGenerator ccg( | 
 |       command, configName, this->CurrentLocalGenerator, true, {}, | 
 |       [this, &depfilesDirectory](std::string const& config, | 
 |                                  std::string const& file) -> std::string { | 
 |         return cmStrCat( | 
 |           depfilesDirectory, | 
 |           this->GetObjectId(cmXCodeObject::PBXShellScriptBuildPhase, file), | 
 |           '.', config, ".d"); | 
 |       }); | 
 |  | 
 |     auto depfile = ccg.GetInternalDepfile(); | 
 |     if (!depfile.empty()) { | 
 |       makefileStream << "include " | 
 |                      << cmSystemTools::ConvertToOutputPath(depfile) << "\n\n"; | 
 |  | 
 |       cmSystemTools::MakeDirectory(depfilesDirectory); | 
 |       if (!cmSystemTools::FileExists(depfile)) { | 
 |         cmSystemTools::Touch(depfile, true); | 
 |       } | 
 |     } | 
 |  | 
 |     std::vector<std::string> realDepends; | 
 |     realDepends.reserve(ccg.GetDepends().size()); | 
 |     for (auto const& d : ccg.GetDepends()) { | 
 |       std::string dep; | 
 |       if (this->CurrentLocalGenerator->GetRealDependency(d, configName, dep)) { | 
 |         realDepends.emplace_back(std::move(dep)); | 
 |       } | 
 |     } | 
 |  | 
 |     if (ccg.GetNumberOfCommands() > 0) { | 
 |       makefileStream << '\n'; | 
 |       std::vector<std::string> const& outputs = ccg.GetOutputs(); | 
 |       if (!outputs.empty()) { | 
 |         // There is at least one output, start the rule for it | 
 |         char const* sep = ""; | 
 |         for (auto const& output : outputs) { | 
 |           makefileStream << sep << ConvertToMakefilePath(output); | 
 |           sep = " "; | 
 |         } | 
 |         makefileStream << ": "; | 
 |       } else { | 
 |         // There are no outputs.  Use the generated force rule name. | 
 |         makefileStream << tname[&ccg.GetCC()] << ": "; | 
 |       } | 
 |       for (auto const& dep : realDepends) { | 
 |         makefileStream << "\\\n" << ConvertToMakefilePath(dep); | 
 |       } | 
 |       makefileStream << '\n'; | 
 |  | 
 |       if (cm::optional<std::string> comment = ccg.GetComment()) { | 
 |         std::string echo_cmd = | 
 |           cmStrCat("echo ", | 
 |                    (this->CurrentLocalGenerator->EscapeForShell( | 
 |                      *comment, ccg.GetCC().GetEscapeAllowMakeVars()))); | 
 |         makefileStream << '\t' << echo_cmd << '\n'; | 
 |       } | 
 |  | 
 |       // Add each command line to the set of commands. | 
 |       for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) { | 
 |         // Build the command line in a single string. | 
 |         std::string cmd2 = ccg.GetCommand(c); | 
 |         cmSystemTools::ReplaceString(cmd2, "/./", "/"); | 
 |         cmd2 = ConvertToMakefilePath(cmd2); | 
 |         std::string cmd; | 
 |         std::string wd = ccg.GetWorkingDirectory(); | 
 |         if (!wd.empty()) { | 
 |           cmd += "cd "; | 
 |           cmd += ConvertToMakefilePath(wd); | 
 |           cmd += " && "; | 
 |         } | 
 |         cmd += cmd2; | 
 |         ccg.AppendArguments(c, cmd); | 
 |         makefileStream << '\t' << cmd << '\n'; | 
 |       } | 
 |  | 
 |       // Symbolic inputs are not expected to exist, so add dummy rules. | 
 |       for (auto const& dep : realDepends) { | 
 |         if (cmSourceFile* dsf = | 
 |               target->GetLocalGenerator()->GetMakefile()->GetSource( | 
 |                 dep, cmSourceFileLocationKind::Known)) { | 
 |           if (dsf->GetPropertyAsBool("SYMBOLIC")) { | 
 |             makefileStream << ConvertToMakefilePath(dep) << ":\n"; | 
 |           } | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddPositionIndependentLinkAttribute( | 
 |   cmGeneratorTarget* target, cmXCodeObject* buildSettings, | 
 |   std::string const& configName) | 
 | { | 
 |   // For now, only EXECUTABLE is concerned | 
 |   if (target->GetType() != cmStateEnums::EXECUTABLE) { | 
 |     return; | 
 |   } | 
 |  | 
 |   char const* PICValue = target->GetLinkPIEProperty(configName); | 
 |   if (PICValue == nullptr) { | 
 |     // POSITION_INDEPENDENT_CODE is not set | 
 |     return; | 
 |   } | 
 |  | 
 |   buildSettings->AddAttribute( | 
 |     "LD_NO_PIE", this->CreateString(cmIsOn(PICValue) ? "NO" : "YES")); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, | 
 |                                                  cmXCodeObject* buildSettings, | 
 |                                                  std::string const& configName) | 
 | { | 
 |   if (!gtgt->IsInBuildSystem()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   std::string defFlags; | 
 |   bool shared = ((gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) || | 
 |                  (gtgt->GetType() == cmStateEnums::MODULE_LIBRARY)); | 
 |   bool binary = ((gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) || | 
 |                  (gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) || | 
 |                  (gtgt->GetType() == cmStateEnums::EXECUTABLE) || shared); | 
 |  | 
 |   // Compute the compilation flags for each language. | 
 |   std::set<std::string> languages; | 
 |   gtgt->GetLanguages(languages, configName); | 
 |   std::map<std::string, std::string> cflags; | 
 |   for (auto const& lang : languages) { | 
 |     std::string& flags = cflags[lang]; | 
 |  | 
 |     // Add language-specific flags. | 
 |     this->CurrentLocalGenerator->AddLanguageFlags( | 
 |       flags, gtgt, cmBuildStep::Compile, lang, configName); | 
 |  | 
 |     if (gtgt->IsIPOEnabled(lang, configName)) { | 
 |       this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO"); | 
 |     } | 
 |  | 
 |     this->CurrentLocalGenerator->AddFeatureFlags(flags, gtgt, lang, | 
 |                                                  configName); | 
 |  | 
 |     this->CurrentLocalGenerator->AddVisibilityPresetFlags(flags, gtgt, lang); | 
 |  | 
 |     this->CurrentLocalGenerator->AddCompileOptions(flags, gtgt, lang, | 
 |                                                    configName); | 
 |   } | 
 |  | 
 |   std::string llang = gtgt->GetLinkerLanguage(configName); | 
 |   if (binary && llang.empty()) { | 
 |     cmSystemTools::Error( | 
 |       cmStrCat("CMake can not determine linker language for target: ", | 
 |                gtgt->GetName())); | 
 |     return; | 
 |   } | 
 |  | 
 |   // Choose a language to use for target-wide preprocessor definitions. | 
 |   static char const* ppLangs[] = { "CXX", "C", "OBJCXX", "OBJC" }; | 
 |   std::string langForPreprocessorDefinitions; | 
 |   if (cm::contains(ppLangs, llang)) { | 
 |     langForPreprocessorDefinitions = llang; | 
 |   } else { | 
 |     for (char const* l : ppLangs) { | 
 |       if (languages.count(l)) { | 
 |         langForPreprocessorDefinitions = l; | 
 |         break; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   if (gtgt->IsIPOEnabled(llang, configName)) { | 
 |     char const* ltoValue = | 
 |       this->CurrentMakefile->IsOn("_CMAKE_LTO_THIN") ? "YES_THIN" : "YES"; | 
 |     buildSettings->AddAttribute("LLVM_LTO", this->CreateString(ltoValue)); | 
 |   } | 
 |  | 
 |   // Handle PIE linker configuration | 
 |   this->AddPositionIndependentLinkAttribute(gtgt, buildSettings, configName); | 
 |  | 
 |   // Add define flags | 
 |   this->CurrentLocalGenerator->AppendFlags( | 
 |     defFlags, this->CurrentMakefile->GetDefineFlags()); | 
 |  | 
 |   // Add preprocessor definitions for this target and configuration. | 
 |   BuildObjectListOrString ppDefs(this, true); | 
 |   this->AppendDefines( | 
 |     ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\""); | 
 |   if (std::string const* exportMacro = gtgt->GetExportMacro()) { | 
 |     // Add the export symbol definition for shared library objects. | 
 |     this->AppendDefines(ppDefs, exportMacro->c_str()); | 
 |   } | 
 |   std::vector<std::string> targetDefines; | 
 |   if (!langForPreprocessorDefinitions.empty()) { | 
 |     gtgt->GetCompileDefinitions(targetDefines, configName, | 
 |                                 langForPreprocessorDefinitions); | 
 |   } | 
 |   this->AppendDefines(ppDefs, targetDefines); | 
 |   buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS", | 
 |                               ppDefs.CreateList()); | 
 |   if (languages.count("Swift")) { | 
 |     // Swift uses a separate attribute for definitions. | 
 |     std::vector<std::string> targetSwiftDefines; | 
 |     gtgt->GetCompileDefinitions(targetSwiftDefines, configName, "Swift"); | 
 |     // Remove the '=value' parts, as Swift does not support them. | 
 |     std::for_each(targetSwiftDefines.begin(), targetSwiftDefines.end(), | 
 |                   [](std::string& def) { | 
 |                     std::string::size_type pos = def.find('='); | 
 |                     if (pos != std::string::npos) { | 
 |                       def.erase(pos); | 
 |                     } | 
 |                   }); | 
 |     if (this->XcodeVersion < 80) { | 
 |       std::string defineString; | 
 |       std::set<std::string> defines(targetSwiftDefines.begin(), | 
 |                                     targetSwiftDefines.end()); | 
 |       this->CurrentLocalGenerator->JoinDefines(defines, defineString, "Swift"); | 
 |       cflags["Swift"] += cmStrCat(' ', defineString); | 
 |     } else { | 
 |       BuildObjectListOrString swiftDefs(this, true); | 
 |       this->AppendDefines(swiftDefs, targetSwiftDefines); | 
 |       buildSettings->AddAttribute("SWIFT_ACTIVE_COMPILATION_CONDITIONS", | 
 |                                   swiftDefs.CreateList()); | 
 |     } | 
 |  | 
 |     if (cm::optional<cmSwiftCompileMode> swiftCompileMode = | 
 |           this->CurrentLocalGenerator->GetSwiftCompileMode(gtgt, configName)) { | 
 |       switch (*swiftCompileMode) { | 
 |         case cmSwiftCompileMode::Wholemodule: | 
 |           buildSettings->AddAttribute("SWIFT_COMPILATION_MODE", | 
 |                                       this->CreateString("wholemodule")); | 
 |           break; | 
 |         case cmSwiftCompileMode::Incremental: | 
 |         case cmSwiftCompileMode::Singlefile: | 
 |           break; | 
 |         case cmSwiftCompileMode::Unknown: | 
 |           this->CurrentLocalGenerator->IssueMessage( | 
 |             MessageType::AUTHOR_WARNING, | 
 |             cmStrCat("Unknown Swift_COMPILATION_MODE on target '", | 
 |                      gtgt->GetName(), '\'')); | 
 |           break; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   std::string extraLinkOptionsVar; | 
 |   std::string extraLinkOptions; | 
 |   if (gtgt->GetType() == cmStateEnums::EXECUTABLE) { | 
 |     extraLinkOptionsVar = "CMAKE_EXE_LINKER_FLAGS"; | 
 |   } else if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) { | 
 |     extraLinkOptionsVar = "CMAKE_SHARED_LINKER_FLAGS"; | 
 |   } else if (gtgt->GetType() == cmStateEnums::MODULE_LIBRARY) { | 
 |     extraLinkOptionsVar = "CMAKE_MODULE_LINKER_FLAGS"; | 
 |   } | 
 |   if (!extraLinkOptionsVar.empty()) { | 
 |     this->CurrentLocalGenerator->AddConfigVariableFlags( | 
 |       extraLinkOptions, extraLinkOptionsVar, gtgt, cmBuildStep::Link, llang, | 
 |       configName); | 
 |   } | 
 |  | 
 |   if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY || | 
 |       gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) { | 
 |     this->CurrentLocalGenerator->GetStaticLibraryFlags( | 
 |       extraLinkOptions, configName, llang, gtgt); | 
 |   } else { | 
 |     this->CurrentLocalGenerator->AppendLinkerTypeFlags(extraLinkOptions, gtgt, | 
 |                                                        configName, llang); | 
 |     this->CurrentLocalGenerator->AppendWarningAsErrorLinkerFlags( | 
 |       extraLinkOptions, gtgt, llang); | 
 |  | 
 |     cmValue targetLinkFlags = gtgt->GetProperty("LINK_FLAGS"); | 
 |     if (targetLinkFlags) { | 
 |       this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, | 
 |                                                *targetLinkFlags); | 
 |     } | 
 |     if (!configName.empty()) { | 
 |       std::string linkFlagsVar = | 
 |         cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(configName)); | 
 |       if (cmValue linkFlags = gtgt->GetProperty(linkFlagsVar)) { | 
 |         this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, *linkFlags); | 
 |       } | 
 |     } | 
 |     std::vector<std::string> opts; | 
 |     gtgt->GetLinkOptions(opts, configName, llang); | 
 |     // LINK_OPTIONS are escaped. | 
 |     this->CurrentLocalGenerator->AppendCompileOptions(extraLinkOptions, opts); | 
 |   } | 
 |  | 
 |   // Set target-specific architectures. | 
 |   std::vector<std::string> archs = | 
 |     gtgt->GetAppleArchs(configName, cm::nullopt); | 
 |  | 
 |   if (!archs.empty()) { | 
 |     // Enable ARCHS attribute. | 
 |     buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("NO")); | 
 |  | 
 |     // Store ARCHS value. | 
 |     if (archs.size() == 1) { | 
 |       buildSettings->AddAttribute("ARCHS", this->CreateString(archs[0])); | 
 |     } else { | 
 |       cmXCodeObject* archObjects = | 
 |         this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |       for (auto& arch : archs) { | 
 |         archObjects->AddObject(this->CreateString(arch)); | 
 |       } | 
 |       buildSettings->AddAttribute("ARCHS", archObjects); | 
 |     } | 
 |   } | 
 |  | 
 |   // Get the product name components. | 
 |   cmGeneratorTarget::NameComponents const& components = | 
 |     gtgt->GetFullNameComponents(configName); | 
 |  | 
 |   cmValue version = gtgt->GetProperty("VERSION"); | 
 |   cmValue soversion = gtgt->GetProperty("SOVERSION"); | 
 |   if (!gtgt->HasSOName(configName) || gtgt->IsFrameworkOnApple()) { | 
 |     version = nullptr; | 
 |     soversion = nullptr; | 
 |   } | 
 |   if (version && !soversion) { | 
 |     soversion = version; | 
 |   } | 
 |   if (!version && soversion) { | 
 |     version = soversion; | 
 |   } | 
 |  | 
 |   std::string realName = components.base; | 
 |   std::string soName = components.base; | 
 |   if (version && soversion) { | 
 |     realName += '.'; | 
 |     realName += *version; | 
 |     soName += '.'; | 
 |     soName += *soversion; | 
 |   } | 
 |  | 
 |   if (gtgt->CanCompileSources()) { | 
 |     std::string const tmpDir = | 
 |       this->GetTargetTempDir(gtgt, this->GetCMakeCFGIntDir()); | 
 |     buildSettings->AddAttribute("TARGET_TEMP_DIR", this->CreateString(tmpDir)); | 
 |  | 
 |     std::string outDir; | 
 |     if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) { | 
 |       // We cannot suppress the archive, so hide it with intermediate files. | 
 |       outDir = tmpDir; | 
 |     } else { | 
 |       outDir = gtgt->GetDirectory(configName); | 
 |     } | 
 |     buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR", | 
 |                                 this->CreateString(outDir)); | 
 |   } | 
 |  | 
 |   // Set attributes to specify the proper name for the target. | 
 |   std::string pndir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory(); | 
 |   if (gtgt->GetType() == cmStateEnums::STATIC_LIBRARY || | 
 |       gtgt->GetType() == cmStateEnums::SHARED_LIBRARY || | 
 |       gtgt->GetType() == cmStateEnums::MODULE_LIBRARY || | 
 |       gtgt->GetType() == cmStateEnums::EXECUTABLE) { | 
 |     std::string prefix = components.prefix; | 
 |     if (gtgt->IsFrameworkOnApple() || gtgt->IsCFBundleOnApple()) { | 
 |       prefix = ""; | 
 |     } | 
 |  | 
 |     buildSettings->AddAttribute("EXECUTABLE_PREFIX", | 
 |                                 this->CreateString(prefix)); | 
 |     buildSettings->AddAttribute("EXECUTABLE_SUFFIX", | 
 |                                 this->CreateString(components.suffix)); | 
 |   } | 
 |  | 
 |   // Store the product name for all target types. | 
 |   buildSettings->AddAttribute("PRODUCT_NAME", this->CreateString(realName)); | 
 |  | 
 |   // Handle settings for each target type. | 
 |   switch (gtgt->GetType()) { | 
 |     case cmStateEnums::STATIC_LIBRARY: | 
 |       if (gtgt->GetPropertyAsBool("FRAMEWORK")) { | 
 |         std::string fw_version = gtgt->GetFrameworkVersion(); | 
 |         buildSettings->AddAttribute("FRAMEWORK_VERSION", | 
 |                                     this->CreateString(fw_version)); | 
 |         cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION"); | 
 |         if (ext) { | 
 |           buildSettings->AddAttribute("WRAPPER_EXTENSION", | 
 |                                       this->CreateString(*ext)); | 
 |         } | 
 |  | 
 |         std::string plist = this->ComputeInfoPListLocation(gtgt); | 
 |         // Xcode will create the final version of Info.plist at build time, | 
 |         // so let it replace the framework name. This avoids creating | 
 |         // a per-configuration Info.plist file. | 
 |         this->CurrentLocalGenerator->GenerateFrameworkInfoPList( | 
 |           gtgt, "$(EXECUTABLE_NAME)", plist); | 
 |         buildSettings->AddAttribute("INFOPLIST_FILE", | 
 |                                     this->CreateString(plist)); | 
 |         buildSettings->AddAttribute("MACH_O_TYPE", | 
 |                                     this->CreateString("staticlib")); | 
 |       } else { | 
 |         buildSettings->AddAttribute("LIBRARY_STYLE", | 
 |                                     this->CreateString("STATIC")); | 
 |       } | 
 |       break; | 
 |  | 
 |     case cmStateEnums::OBJECT_LIBRARY: { | 
 |       buildSettings->AddAttribute("LIBRARY_STYLE", | 
 |                                   this->CreateString("STATIC")); | 
 |       break; | 
 |     } | 
 |  | 
 |     case cmStateEnums::MODULE_LIBRARY: { | 
 |       buildSettings->AddAttribute("LIBRARY_STYLE", | 
 |                                   this->CreateString("BUNDLE")); | 
 |       // Add the flags to create a module library (bundle). | 
 |       std::string createFlags = this->LookupFlags( | 
 |         "CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", gtgt); | 
 |       if (this->GetTargetProductType(gtgt) != | 
 |           "com.apple.product-type.app-extension"_s) { | 
 |         // Xcode passes -bundle automatically. | 
 |         cmSystemTools::ReplaceString(createFlags, "-bundle", ""); | 
 |       } | 
 |       createFlags = cmTrimWhitespace(createFlags); | 
 |       if (!createFlags.empty()) { | 
 |         extraLinkOptions += ' '; | 
 |         extraLinkOptions += createFlags; | 
 |       } | 
 |       if (gtgt->IsCFBundleOnApple()) { | 
 |         cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION"); | 
 |         if (ext) { | 
 |           buildSettings->AddAttribute("WRAPPER_EXTENSION", | 
 |                                       this->CreateString(*ext)); | 
 |         } | 
 |         std::string plist = this->ComputeInfoPListLocation(gtgt); | 
 |         // Xcode will create the final version of Info.plist at build time, | 
 |         // so let it replace the cfbundle name. This avoids creating | 
 |         // a per-configuration Info.plist file. The cfbundle plist | 
 |         // is very similar to the application bundle plist | 
 |         this->CurrentLocalGenerator->GenerateAppleInfoPList( | 
 |           gtgt, "$(EXECUTABLE_NAME)", plist); | 
 |         buildSettings->AddAttribute("INFOPLIST_FILE", | 
 |                                     this->CreateString(plist)); | 
 |       } else { | 
 |         buildSettings->AddAttribute("MACH_O_TYPE", | 
 |                                     this->CreateString("mh_bundle")); | 
 |         buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC", | 
 |                                     this->CreateString("NO")); | 
 |       } | 
 |       break; | 
 |     } | 
 |     case cmStateEnums::SHARED_LIBRARY: { | 
 |       if (gtgt->GetPropertyAsBool("FRAMEWORK")) { | 
 |         std::string fw_version = gtgt->GetFrameworkVersion(); | 
 |         buildSettings->AddAttribute("FRAMEWORK_VERSION", | 
 |                                     this->CreateString(fw_version)); | 
 |         cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION"); | 
 |         if (ext) { | 
 |           buildSettings->AddAttribute("WRAPPER_EXTENSION", | 
 |                                       this->CreateString(*ext)); | 
 |         } | 
 |  | 
 |         std::string plist = this->ComputeInfoPListLocation(gtgt); | 
 |         // Xcode will create the final version of Info.plist at build time, | 
 |         // so let it replace the framework name. This avoids creating | 
 |         // a per-configuration Info.plist file. | 
 |         this->CurrentLocalGenerator->GenerateFrameworkInfoPList( | 
 |           gtgt, "$(EXECUTABLE_NAME)", plist); | 
 |         buildSettings->AddAttribute("INFOPLIST_FILE", | 
 |                                     this->CreateString(plist)); | 
 |       } else { | 
 |         // Add the flags to create a shared library. | 
 |         std::string createFlags = this->LookupFlags( | 
 |           "CMAKE_SHARED_LIBRARY_CREATE_", llang, "_FLAGS", gtgt); | 
 |         // Xcode passes -dynamiclib automatically. | 
 |         cmSystemTools::ReplaceString(createFlags, "-dynamiclib", ""); | 
 |         createFlags = cmTrimWhitespace(createFlags); | 
 |         if (!createFlags.empty()) { | 
 |           extraLinkOptions += ' '; | 
 |           extraLinkOptions += createFlags; | 
 |         } | 
 |       } | 
 |  | 
 |       buildSettings->AddAttribute("LIBRARY_STYLE", | 
 |                                   this->CreateString("DYNAMIC")); | 
 |  | 
 |       if (gtgt->HasImportLibrary(configName)) { | 
 |         // Request .tbd file generation | 
 |         buildSettings->AddAttribute("GENERATE_TEXT_BASED_STUBS", | 
 |                                     this->CreateString("YES")); | 
 |       } | 
 |       break; | 
 |     } | 
 |     case cmStateEnums::EXECUTABLE: { | 
 |       // Add the flags to create an executable. | 
 |       std::string createFlags = | 
 |         this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", gtgt); | 
 |       if (!createFlags.empty()) { | 
 |         extraLinkOptions += ' '; | 
 |         extraLinkOptions += createFlags; | 
 |       } | 
 |  | 
 |       // Handle bundles and normal executables separately. | 
 |       if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { | 
 |         cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION"); | 
 |         if (ext) { | 
 |           buildSettings->AddAttribute("WRAPPER_EXTENSION", | 
 |                                       this->CreateString(*ext)); | 
 |         } | 
 |         std::string plist = this->ComputeInfoPListLocation(gtgt); | 
 |         // Xcode will create the final version of Info.plist at build time, | 
 |         // so let it replace the executable name.  This avoids creating | 
 |         // a per-configuration Info.plist file. | 
 |         this->CurrentLocalGenerator->GenerateAppleInfoPList( | 
 |           gtgt, "$(EXECUTABLE_NAME)", plist); | 
 |         buildSettings->AddAttribute("INFOPLIST_FILE", | 
 |                                     this->CreateString(plist)); | 
 |       } | 
 |     } break; | 
 |     default: | 
 |       break; | 
 |   } | 
 |  | 
 |   BuildObjectListOrString dirs(this, true); | 
 |   BuildObjectListOrString fdirs(this, true); | 
 |   BuildObjectListOrString sysdirs(this, true); | 
 |   BuildObjectListOrString sysfdirs(this, true); | 
 |   bool const emitSystemIncludes = this->XcodeVersion >= 83; | 
 |  | 
 |   // Choose a language to use for target-wide include directories. | 
 |   std::string const& langForIncludes = llang; | 
 |   std::vector<std::string> includes; | 
 |   if (!langForIncludes.empty()) { | 
 |     this->CurrentLocalGenerator->GetIncludeDirectories( | 
 |       includes, gtgt, langForIncludes, configName); | 
 |   } | 
 |   std::set<std::string> emitted; | 
 |   emitted.insert("/System/Library/Frameworks"); | 
 |  | 
 |   for (auto& include : includes) { | 
 |     if (this->NameResolvesToFramework(include)) { | 
 |       std::string frameworkDir = cmStrCat(include, "/../"); | 
 |       frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir); | 
 |       if (emitted.insert(frameworkDir).second) { | 
 |         std::string incpath = this->XCodeEscapePath(frameworkDir); | 
 |         if (emitSystemIncludes && | 
 |             gtgt->IsSystemIncludeDirectory(frameworkDir, configName, | 
 |                                            langForIncludes)) { | 
 |           sysfdirs.Add(incpath); | 
 |         } else { | 
 |           fdirs.Add(incpath); | 
 |         } | 
 |       } | 
 |     } else { | 
 |       std::string incpath = this->XCodeEscapePath(include); | 
 |       if (emitSystemIncludes && | 
 |           gtgt->IsSystemIncludeDirectory(include, configName, | 
 |                                          langForIncludes)) { | 
 |         sysdirs.Add(incpath); | 
 |       } else { | 
 |         dirs.Add(incpath); | 
 |       } | 
 |     } | 
 |   } | 
 |   // Add framework search paths needed for linking. | 
 |   if (cmComputeLinkInformation* cli = gtgt->GetLinkInformation(configName)) { | 
 |     for (auto const& fwDir : cli->GetFrameworkPaths()) { | 
 |       if (emitted.insert(fwDir).second) { | 
 |         std::string incpath = this->XCodeEscapePath(fwDir); | 
 |         if (emitSystemIncludes && | 
 |             gtgt->IsSystemIncludeDirectory(fwDir, configName, | 
 |                                            langForIncludes)) { | 
 |           sysfdirs.Add(incpath); | 
 |         } else { | 
 |           fdirs.Add(incpath); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |   if (!fdirs.IsEmpty()) { | 
 |     buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS", fdirs.CreateList()); | 
 |   } | 
 |   if (!dirs.IsEmpty()) { | 
 |     buildSettings->AddAttribute("HEADER_SEARCH_PATHS", dirs.CreateList()); | 
 |     if (languages.count("Swift")) { | 
 |       buildSettings->AddAttribute("SWIFT_INCLUDE_PATHS", dirs.CreateList()); | 
 |     } | 
 |   } | 
 |   if (!sysfdirs.IsEmpty()) { | 
 |     buildSettings->AddAttribute("SYSTEM_FRAMEWORK_SEARCH_PATHS", | 
 |                                 sysfdirs.CreateList()); | 
 |   } | 
 |   if (!sysdirs.IsEmpty()) { | 
 |     buildSettings->AddAttribute("SYSTEM_HEADER_SEARCH_PATHS", | 
 |                                 sysdirs.CreateList()); | 
 |   } | 
 |  | 
 |   if (this->XcodeVersion >= 60 && !emitSystemIncludes) { | 
 |     // Add those per-language flags in addition to HEADER_SEARCH_PATHS to gain | 
 |     // system include directory awareness. We need to also keep on setting | 
 |     // HEADER_SEARCH_PATHS to work around a missing compile options flag for | 
 |     // GNU assembly files (#16449) | 
 |     for (auto const& language : languages) { | 
 |       std::string includeFlags = this->CurrentLocalGenerator->GetIncludeFlags( | 
 |         includes, gtgt, language, configName); | 
 |  | 
 |       if (!includeFlags.empty()) { | 
 |         cflags[language] += cmStrCat(' ', includeFlags); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   bool same_gflags = true; | 
 |   std::map<std::string, std::string> gflags; | 
 |   std::string const* last_gflag = nullptr; | 
 |   std::string optLevel = "0"; | 
 |  | 
 |   // Minimal map of flags to build settings. | 
 |   for (auto const& language : languages) { | 
 |     std::string& flags = cflags[language]; | 
 |     std::string& gflag = gflags[language]; | 
 |     std::string oflag = | 
 |       this->ExtractFlagRegex("(^| )(-Ofast|-Os|-O[0-9]*)( |$)", 2, flags); | 
 |     if (oflag.size() == 2) { | 
 |       optLevel = "1"; | 
 |     } else if (oflag.size() > 2) { | 
 |       optLevel = oflag.substr(2); | 
 |     } | 
 |     gflag = this->ExtractFlag("-g", flags); | 
 |     // put back gdwarf-2 if used since there is no way | 
 |     // to represent it in the gui, but we still want debug yes | 
 |     if (gflag == "-gdwarf-2"_s) { | 
 |       flags += ' '; | 
 |       flags += gflag; | 
 |     } | 
 |     if (last_gflag && *last_gflag != gflag) { | 
 |       same_gflags = false; | 
 |     } | 
 |     last_gflag = &gflag; | 
 |   } | 
 |  | 
 |   char const* debugStr = "YES"; | 
 |   if (!same_gflags) { | 
 |     // We can't set the Xcode flag differently depending on the language, | 
 |     // so put them back in this case. | 
 |     for (auto const& language : languages) { | 
 |       cflags[language] += ' '; | 
 |       cflags[language] += gflags[language]; | 
 |     } | 
 |     debugStr = "NO"; | 
 |   } else if (last_gflag && (last_gflag->empty() || *last_gflag == "-g0"_s)) { | 
 |     debugStr = "NO"; | 
 |   } | 
 |  | 
 |   // extract C++ stdlib | 
 |   for (auto const& language : languages) { | 
 |     if (language != "CXX"_s && language != "OBJCXX"_s) { | 
 |       continue; | 
 |     } | 
 |     std::string& flags = cflags[language]; | 
 |  | 
 |     auto stdlib = | 
 |       this->ExtractFlagRegex("(^| )(-stdlib=[^ ]+)( |$)", 2, flags); | 
 |     if (stdlib.size() > 8) { | 
 |       auto const cxxLibrary = stdlib.substr(8); | 
 |       if (language == "CXX"_s || | 
 |           !buildSettings->GetAttribute("CLANG_CXX_LIBRARY")) { | 
 |         buildSettings->AddAttribute("CLANG_CXX_LIBRARY", | 
 |                                     this->CreateString(cxxLibrary)); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   buildSettings->AddAttribute("COMBINE_HIDPI_IMAGES", | 
 |                               this->CreateString("YES")); | 
 |   buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS", | 
 |                               this->CreateString(debugStr)); | 
 |   buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL", | 
 |                               this->CreateString(optLevel)); | 
 |   buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN", | 
 |                               this->CreateString("NO")); | 
 |   buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN", | 
 |                               this->CreateString("NO")); | 
 |  | 
 |   for (auto const& language : languages) { | 
 |     std::string flags = cmStrCat(cflags[language], ' ', defFlags); | 
 |     if (language == "CXX"_s || language == "OBJCXX"_s) { | 
 |       if (language == "CXX"_s || | 
 |           !buildSettings->GetAttribute("OTHER_CPLUSPLUSFLAGS")) { | 
 |         buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS", | 
 |                                     this->CreateString(flags)); | 
 |       } | 
 |     } else if (language == "Fortran"_s) { | 
 |       buildSettings->AddAttribute("IFORT_OTHER_FLAGS", | 
 |                                   this->CreateString(flags)); | 
 |     } else if (language == "C"_s || language == "OBJC"_s) { | 
 |       if (language == "C"_s || !buildSettings->GetAttribute("OTHER_CFLAGS")) { | 
 |         buildSettings->AddAttribute("OTHER_CFLAGS", this->CreateString(flags)); | 
 |       } | 
 |     } else if (language == "Swift"_s) { | 
 |       buildSettings->AddAttribute("OTHER_SWIFT_FLAGS", | 
 |                                   this->CreateString(flags)); | 
 |     } | 
 |   } | 
 |  | 
 |   // Add Fortran source format attribute if property is set. | 
 |   char const* format = nullptr; | 
 |   std::string const& tgtfmt = gtgt->GetSafeProperty("Fortran_FORMAT"); | 
 |   switch (cmOutputConverter::GetFortranFormat(tgtfmt)) { | 
 |     case cmOutputConverter::FortranFormatFixed: | 
 |       format = "fixed"; | 
 |       break; | 
 |     case cmOutputConverter::FortranFormatFree: | 
 |       format = "free"; | 
 |       break; | 
 |     default: | 
 |       break; | 
 |   } | 
 |   if (format) { | 
 |     buildSettings->AddAttribute("IFORT_LANG_SRCFMT", | 
 |                                 this->CreateString(format)); | 
 |   } | 
 |  | 
 |   // Create the INSTALL_PATH attribute. | 
 |   std::string install_name_dir; | 
 |   if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) { | 
 |     // Get the install_name directory for the build tree. | 
 |     install_name_dir = gtgt->GetInstallNameDirForBuildTree(configName); | 
 |     // Xcode doesn't create the correct install_name in some cases. | 
 |     // That is, if the INSTALL_PATH is empty, or if we have versioning | 
 |     // of dylib libraries, we want to specify the install_name. | 
 |     // This is done by adding a link flag to create an install_name | 
 |     // with just the library soname. | 
 |     std::string install_name; | 
 |     if (!install_name_dir.empty()) { | 
 |       // Convert to a path for the native build tool. | 
 |       cmSystemTools::ConvertToUnixSlashes(install_name_dir); | 
 |       install_name += install_name_dir; | 
 |       install_name += '/'; | 
 |     } | 
 |     install_name += gtgt->GetSOName(configName); | 
 |  | 
 |     if ((realName != soName) || install_name_dir.empty()) { | 
 |       install_name_dir = ""; | 
 |       extraLinkOptions += " -install_name "; | 
 |       extraLinkOptions += XCodeEscapePath(install_name); | 
 |     } | 
 |   } | 
 |   buildSettings->AddAttribute("INSTALL_PATH", | 
 |                               this->CreateString(install_name_dir)); | 
 |  | 
 |   // Create the LD_RUNPATH_SEARCH_PATHS | 
 |   cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName); | 
 |   if (pcli) { | 
 |     std::string search_paths; | 
 |     std::vector<std::string> runtimeDirs; | 
 |     pcli->GetRPath(runtimeDirs, false); | 
 |     // runpath dirs needs to be unique to prevent corruption | 
 |     std::set<std::string> unique_dirs; | 
 |  | 
 |     for (auto runpath : runtimeDirs) { | 
 |       runpath = this->ExpandCFGIntDir(runpath, configName); | 
 |  | 
 |       if (unique_dirs.find(runpath) == unique_dirs.end()) { | 
 |         unique_dirs.insert(runpath); | 
 |         if (!search_paths.empty()) { | 
 |           search_paths += ' '; | 
 |         } | 
 |         search_paths += this->XCodeEscapePath(runpath); | 
 |       } | 
 |     } | 
 |     if (!search_paths.empty()) { | 
 |       buildSettings->AddAttribute("LD_RUNPATH_SEARCH_PATHS", | 
 |                                   this->CreateString(search_paths)); | 
 |     } | 
 |   } | 
 |  | 
 |   buildSettings->AddAttribute(this->GetTargetLinkFlagsVar(gtgt), | 
 |                               this->CreateString(extraLinkOptions)); | 
 |   buildSettings->AddAttribute("OTHER_REZFLAGS", this->CreateString("")); | 
 |   buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString("")); | 
 |   buildSettings->AddAttribute("ALWAYS_SEARCH_USER_PATHS", | 
 |                               this->CreateString("NO")); | 
 |   buildSettings->AddAttribute("USE_HEADERMAP", this->CreateString("NO")); | 
 |   cmXCodeObject* group = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   group->AddObject(this->CreateString("$(inherited)")); | 
 |   buildSettings->AddAttribute("WARNING_CFLAGS", group); | 
 |  | 
 |   // Runtime version information. | 
 |   if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) { | 
 |     int major; | 
 |     int minor; | 
 |     int patch; | 
 |  | 
 |     // MACHO_CURRENT_VERSION or VERSION -> current_version | 
 |     gtgt->GetTargetVersionFallback("MACHO_CURRENT_VERSION", "VERSION", major, | 
 |                                    minor, patch); | 
 |     std::ostringstream v; | 
 |  | 
 |     // Xcode always wants at least 1.0.0 or nothing | 
 |     if (!(major == 0 && minor == 0 && patch == 0)) { | 
 |       v << major << '.' << minor << '.' << patch; | 
 |     } | 
 |     buildSettings->AddAttribute("DYLIB_CURRENT_VERSION", | 
 |                                 this->CreateString(v.str())); | 
 |  | 
 |     // MACHO_COMPATIBILITY_VERSION or SOVERSION -> compatibility_version | 
 |     gtgt->GetTargetVersionFallback("MACHO_COMPATIBILITY_VERSION", "SOVERSION", | 
 |                                    major, minor, patch); | 
 |     std::ostringstream vso; | 
 |  | 
 |     // Xcode always wants at least 1.0.0 or nothing | 
 |     if (!(major == 0 && minor == 0 && patch == 0)) { | 
 |       vso << major << '.' << minor << '.' << patch; | 
 |     } | 
 |     buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION", | 
 |                                 this->CreateString(vso.str())); | 
 |   } | 
 |  | 
 |   // Precompile Headers | 
 |   std::string pchHeader = | 
 |     gtgt->GetPchHeader(configName, langForPreprocessorDefinitions); | 
 |   if (!pchHeader.empty()) { | 
 |     buildSettings->AddAttribute("GCC_PREFIX_HEADER", | 
 |                                 this->CreateString(pchHeader)); | 
 |     buildSettings->AddAttribute("GCC_PRECOMPILE_PREFIX_HEADER", | 
 |                                 this->CreateString("YES")); | 
 |   } | 
 |  | 
 |   // put this last so it can override existing settings | 
 |   // Convert "XCODE_ATTRIBUTE_*" properties directly. | 
 |   { | 
 |     for (auto const& prop : gtgt->GetPropertyKeys()) { | 
 |       if (cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) { | 
 |         std::string attribute = prop.substr(16); | 
 |         this->FilterConfigurationAttribute(configName, attribute); | 
 |         if (!attribute.empty()) { | 
 |           std::string const& pr = gtgt->GetSafeProperty(prop); | 
 |           std::string processed = cmGeneratorExpression::Evaluate( | 
 |             pr, this->CurrentLocalGenerator, configName); | 
 |           buildSettings->AddAttribute(attribute, | 
 |                                       this->CreateString(processed)); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget( | 
 |   cmGeneratorTarget* gtgt) | 
 | { | 
 |   cmXCodeObject* shellBuildPhase = this->CreateObject( | 
 |     cmXCodeObject::PBXShellScriptBuildPhase, gtgt->GetName()); | 
 |   shellBuildPhase->AddAttribute("buildActionMask", | 
 |                                 this->CreateString("2147483647")); | 
 |   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   shellBuildPhase->AddAttribute("files", buildFiles); | 
 |   cmXCodeObject* inputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   shellBuildPhase->AddAttribute("inputPaths", inputPaths); | 
 |   cmXCodeObject* outputPaths = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   shellBuildPhase->AddAttribute("outputPaths", outputPaths); | 
 |   shellBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                                 this->CreateString("0")); | 
 |   shellBuildPhase->AddAttribute("shellPath", this->CreateString("/bin/sh")); | 
 |   shellBuildPhase->AddAttribute( | 
 |     "shellScript", this->CreateString("# shell script goes here\nexit 0")); | 
 |   shellBuildPhase->AddAttribute("showEnvVarsInLog", this->CreateString("0")); | 
 |  | 
 |   std::string targetBinaryPath = cmStrCat( | 
 |     gtgt->Makefile->GetCurrentBinaryDirectory(), '/', gtgt->GetName()); | 
 |  | 
 |   cmXCodeObject* target = this->CreateObject( | 
 |     cmXCodeObject::PBXAggregateTarget, | 
 |     cmStrCat("PBXAggregateTarget:", gtgt->GetName(), ':', targetBinaryPath)); | 
 |   target->SetComment(gtgt->GetName()); | 
 |   cmXCodeObject* buildPhases = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   std::vector<cmXCodeObject*> emptyContentVector; | 
 |   this->CreateCustomCommands(buildPhases, nullptr, nullptr, nullptr, | 
 |                              emptyContentVector, nullptr, gtgt); | 
 |   target->AddAttribute("buildPhases", buildPhases); | 
 |   this->AddConfigurations(target, gtgt); | 
 |   cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   target->AddAttribute("dependencies", dependencies); | 
 |   target->AddAttribute("name", this->CreateString(gtgt->GetName())); | 
 |   target->AddAttribute("productName", this->CreateString(gtgt->GetName())); | 
 |   target->SetTarget(gtgt); | 
 |   this->XCodeObjectMap[gtgt] = target; | 
 |  | 
 |   // Add source files without build rules for editing convenience. | 
 |   if (gtgt->GetType() != cmStateEnums::GLOBAL_TARGET && | 
 |       gtgt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { | 
 |     std::vector<cmSourceFile*> sources; | 
 |     if (!gtgt->GetConfigCommonSourceFilesForXcode(sources)) { | 
 |       return nullptr; | 
 |     } | 
 |  | 
 |     // Add CMakeLists.txt file for user convenience. | 
 |     this->AddXCodeProjBuildRule(gtgt, sources); | 
 |  | 
 |     for (auto* sourceFile : sources) { | 
 |       if (!sourceFile->GetIsGenerated()) { | 
 |         this->CreateXCodeFileReference(sourceFile, gtgt); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   target->SetId(this->GetOrCreateId(gtgt->GetName(), target->GetId())); | 
 |  | 
 |   return target; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target, | 
 |                                                       cmGeneratorTarget* gtgt) | 
 | { | 
 |   cmList const configList{ this->CurrentMakefile->GetRequiredDefinition( | 
 |     "CMAKE_CONFIGURATION_TYPES") }; | 
 |   cmXCodeObject* configlist = | 
 |     this->CreateObject(cmXCodeObject::XCConfigurationList); | 
 |   cmXCodeObject* buildConfigurations = | 
 |     this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   configlist->AddAttribute("buildConfigurations", buildConfigurations); | 
 |   std::string comment = cmStrCat("Build configuration list for ", | 
 |                                  cmXCodeObject::PBXTypeNames[target->GetIsA()], | 
 |                                  " \"", gtgt->GetName(), '"'); | 
 |   configlist->SetComment(comment); | 
 |   target->AddAttribute("buildConfigurationList", | 
 |                        this->CreateObjectReference(configlist)); | 
 |   for (auto const& i : configList) { | 
 |     cmXCodeObject* config = | 
 |       this->CreateObject(cmXCodeObject::XCBuildConfiguration); | 
 |     buildConfigurations->AddObject(config); | 
 |     cmXCodeObject* buildSettings = | 
 |       this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |     this->CreateBuildSettings(gtgt, buildSettings, i); | 
 |     config->AddAttribute("name", this->CreateString(i)); | 
 |     config->SetComment(i); | 
 |     config->AddAttribute("buildSettings", buildSettings); | 
 |  | 
 |     this->CreateTargetXCConfigSettings(gtgt, config, i); | 
 |   } | 
 |   if (!configList.empty()) { | 
 |     configlist->AddAttribute("defaultConfigurationName", | 
 |                              this->CreateString(configList[0])); | 
 |     configlist->AddAttribute("defaultConfigurationIsVisible", | 
 |                              this->CreateString("0")); | 
 |     return configList[0]; | 
 |   } | 
 |   return ""; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateGlobalXCConfigSettings( | 
 |   cmLocalGenerator* root, cmXCodeObject* config, std::string const& configName) | 
 | { | 
 |   auto xcconfig = cmGeneratorExpression::Evaluate( | 
 |     this->CurrentMakefile->GetSafeDefinition("CMAKE_XCODE_XCCONFIG"), | 
 |     this->CurrentLocalGenerator, configName); | 
 |   if (xcconfig.empty()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   auto* sf = this->CurrentMakefile->GetSource(xcconfig); | 
 |   if (!sf) { | 
 |     cmSystemTools::Error( | 
 |       cmStrCat("sources for ALL_BUILD do not contain xcconfig file: '", | 
 |                xcconfig, "' (configuration: ", configName, ')')); | 
 |     return; | 
 |   } | 
 |  | 
 |   cmXCodeObject* fileRef = this->CreateXCodeFileReferenceFromPath( | 
 |     sf->ResolveFullPath(), root->FindGeneratorTargetToUse("ALL_BUILD"), "", | 
 |     sf); | 
 |  | 
 |   if (!fileRef) { | 
 |     // error is already reported by CreateXCodeFileReferenceFromPath | 
 |     return; | 
 |   } | 
 |  | 
 |   config->AddAttribute("baseConfigurationReference", | 
 |                        this->CreateObjectReference(fileRef)); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateTargetXCConfigSettings( | 
 |   cmGeneratorTarget* target, cmXCodeObject* config, | 
 |   std::string const& configName) | 
 | { | 
 |   auto xcconfig = | 
 |     cmGeneratorExpression::Evaluate(target->GetSafeProperty("XCODE_XCCONFIG"), | 
 |                                     this->CurrentLocalGenerator, configName); | 
 |   if (xcconfig.empty()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   auto* sf = target->Makefile->GetSource(xcconfig); | 
 |   if (!sf) { | 
 |     cmSystemTools::Error(cmStrCat("target sources for target ", | 
 |                                   target->Target->GetName(), | 
 |                                   " do not contain xcconfig file: '", xcconfig, | 
 |                                   "' (configuration: ", configName, ')')); | 
 |     return; | 
 |   } | 
 |  | 
 |   cmXCodeObject* fileRef = this->CreateXCodeFileReferenceFromPath( | 
 |     sf->ResolveFullPath(), target, "", sf); | 
 |   if (!fileRef) { | 
 |     // error is already reported by CreateXCodeFileReferenceFromPath | 
 |     return; | 
 |   } | 
 |   config->AddAttribute("baseConfigurationReference", | 
 |                        this->CreateObjectReference(fileRef)); | 
 | } | 
 |  | 
 | char const* cmGlobalXCodeGenerator::GetTargetLinkFlagsVar( | 
 |   cmGeneratorTarget const* target) const | 
 | { | 
 |   if (this->XcodeVersion >= 60 && | 
 |       (target->GetType() == cmStateEnums::STATIC_LIBRARY || | 
 |        target->GetType() == cmStateEnums::OBJECT_LIBRARY)) { | 
 |     return "OTHER_LIBTOOLFLAGS"; | 
 |   } | 
 |   return "OTHER_LDFLAGS"; | 
 | } | 
 |  | 
 | char const* cmGlobalXCodeGenerator::GetTargetFileType( | 
 |   cmGeneratorTarget* target) | 
 | { | 
 |   if (cmValue e = target->GetProperty("XCODE_EXPLICIT_FILE_TYPE")) { | 
 |     return e->c_str(); | 
 |   } | 
 |  | 
 |   switch (target->GetType()) { | 
 |     case cmStateEnums::OBJECT_LIBRARY: | 
 |       return "archive.ar"; | 
 |     case cmStateEnums::STATIC_LIBRARY: | 
 |       return (target->GetPropertyAsBool("FRAMEWORK") ? "wrapper.framework" | 
 |                                                      : "archive.ar"); | 
 |     case cmStateEnums::MODULE_LIBRARY: | 
 |       if (target->IsXCTestOnApple()) { | 
 |         return "wrapper.cfbundle"; | 
 |       } | 
 |       if (target->IsCFBundleOnApple()) { | 
 |         return "wrapper.plug-in"; | 
 |       } | 
 |       return "compiled.mach-o.executable"; | 
 |     case cmStateEnums::SHARED_LIBRARY: | 
 |       return (target->GetPropertyAsBool("FRAMEWORK") | 
 |                 ? "wrapper.framework" | 
 |                 : "compiled.mach-o.dylib"); | 
 |     case cmStateEnums::EXECUTABLE: | 
 |       return "compiled.mach-o.executable"; | 
 |     default: | 
 |       break; | 
 |   } | 
 |   return nullptr; | 
 | } | 
 |  | 
 | cm::string_view cmGlobalXCodeGenerator::GetTargetProductType( | 
 |   cmGeneratorTarget* target) | 
 | { | 
 |   if (cmValue e = target->GetProperty("XCODE_PRODUCT_TYPE")) { | 
 |     return cm::string_view(*e); | 
 |   } | 
 |  | 
 |   switch (target->GetType()) { | 
 |     case cmStateEnums::OBJECT_LIBRARY: | 
 |       return "com.apple.product-type.library.static"_s; | 
 |     case cmStateEnums::STATIC_LIBRARY: | 
 |       return target->GetPropertyAsBool("FRAMEWORK") | 
 |         ? "com.apple.product-type.framework"_s | 
 |         : "com.apple.product-type.library.static"_s; | 
 |     case cmStateEnums::MODULE_LIBRARY: | 
 |       if (target->IsXCTestOnApple()) { | 
 |         return "com.apple.product-type.bundle.unit-test"_s; | 
 |       } else if (target->IsCFBundleOnApple()) { | 
 |         return "com.apple.product-type.bundle"_s; | 
 |       } else { | 
 |         return "com.apple.product-type.tool"_s; | 
 |       } | 
 |     case cmStateEnums::SHARED_LIBRARY: | 
 |       return target->GetPropertyAsBool("FRAMEWORK") | 
 |         ? "com.apple.product-type.framework"_s | 
 |         : "com.apple.product-type.library.dynamic"_s; | 
 |     case cmStateEnums::EXECUTABLE: | 
 |       return target->GetPropertyAsBool("MACOSX_BUNDLE") | 
 |         ? "com.apple.product-type.application"_s | 
 |         : "com.apple.product-type.tool"_s; | 
 |     default: | 
 |       break; | 
 |   } | 
 |   return ""_s; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeTarget( | 
 |   cmGeneratorTarget* gtgt, cmXCodeObject* buildPhases) | 
 | { | 
 |   if (!gtgt->IsInBuildSystem()) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   std::string targetBinaryPath = this->RelativeToRootBinary(cmStrCat( | 
 |     gtgt->Makefile->GetCurrentBinaryDirectory(), '/', gtgt->GetName())); | 
 |  | 
 |   cmXCodeObject* target = this->CreateObject( | 
 |     cmXCodeObject::PBXNativeTarget, | 
 |     cmStrCat("PBXNativeTarget:", gtgt->GetName(), ':', targetBinaryPath)); | 
 |  | 
 |   target->AddAttribute("buildPhases", buildPhases); | 
 |   cmXCodeObject* buildRules = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   target->AddAttribute("buildRules", buildRules); | 
 |   std::string defConfig; | 
 |   defConfig = this->AddConfigurations(target, gtgt); | 
 |   cmXCodeObject* dependencies = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   target->AddAttribute("dependencies", dependencies); | 
 |   target->AddAttribute("name", this->CreateString(gtgt->GetName())); | 
 |   target->AddAttribute("productName", this->CreateString(gtgt->GetName())); | 
 |  | 
 |   cmXCodeObject* fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); | 
 |   if (char const* fileType = this->GetTargetFileType(gtgt)) { | 
 |     fileRef->AddAttribute("explicitFileType", this->CreateString(fileType)); | 
 |   } | 
 |   std::string fullName; | 
 |   if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) { | 
 |     fullName = cmStrCat("lib", gtgt->GetName(), ".a"); | 
 |   } else { | 
 |     fullName = gtgt->GetFullName(defConfig); | 
 |   } | 
 |   fileRef->AddAttribute("path", this->CreateString(fullName)); | 
 |   fileRef->AddAttribute("sourceTree", | 
 |                         this->CreateString("BUILT_PRODUCTS_DIR")); | 
 |   fileRef->SetComment(gtgt->GetName()); | 
 |   target->AddAttribute("productReference", | 
 |                        this->CreateObjectReference(fileRef)); | 
 |   cm::string_view productType = this->GetTargetProductType(gtgt); | 
 |   if (!productType.empty()) { | 
 |     target->AddAttribute("productType", this->CreateString(productType)); | 
 |   } | 
 |   target->SetTarget(gtgt); | 
 |   this->XCodeObjectMap[gtgt] = target; | 
 |   target->SetId(this->GetOrCreateId(gtgt->GetName(), target->GetId())); | 
 |   return target; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::FindXCodeTarget( | 
 |   cmGeneratorTarget const* t) | 
 | { | 
 |   if (!t) { | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   auto const i = this->XCodeObjectMap.find(t); | 
 |   if (i == this->XCodeObjectMap.end()) { | 
 |     return nullptr; | 
 |   } | 
 |   return i->second; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::GetObjectId(cmXCodeObject::PBXType ptype, | 
 |                                                 cm::string_view key) | 
 | { | 
 |   std::string objectId; | 
 |   if (!key.empty()) { | 
 |     cmCryptoHash hash(cmCryptoHash::AlgoSHA256); | 
 |     hash.Initialize(); | 
 |     hash.Append(&ptype, sizeof(ptype)); | 
 |     hash.Append(key); | 
 |     objectId = cmSystemTools::UpperCase(hash.FinalizeHex().substr(0, 24)); | 
 |   } else { | 
 |     char cUuid[40] = { 0 }; | 
 |     CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); | 
 |     CFStringRef s = CFUUIDCreateString(kCFAllocatorDefault, uuid); | 
 |     CFStringGetCString(s, cUuid, sizeof(cUuid), kCFStringEncodingUTF8); | 
 |     objectId = cUuid; | 
 |     CFRelease(s); | 
 |     CFRelease(uuid); | 
 |     cmSystemTools::ReplaceString(objectId, "-", ""); | 
 |     if (objectId.size() > 24) { | 
 |       objectId = objectId.substr(0, 24); | 
 |     } | 
 |   } | 
 |   return objectId; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::GetOrCreateId(std::string const& name, | 
 |                                                   std::string const& id) | 
 | { | 
 |   std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE"); | 
 |   cmValue storedGUID = this->CMakeInstance->GetCacheDefinition(guidStoreName); | 
 |  | 
 |   if (storedGUID) { | 
 |     return *storedGUID; | 
 |   } | 
 |  | 
 |   this->CMakeInstance->AddCacheEntry( | 
 |     guidStoreName, id, "Stored Xcode object GUID", cmStateEnums::INTERNAL); | 
 |  | 
 |   return id; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddDependTarget(cmXCodeObject* target, | 
 |                                              cmXCodeObject* dependTarget) | 
 | { | 
 |   // This is called once for every edge in the target dependency graph. | 
 |   cmXCodeObject* container = | 
 |     this->CreateObject(cmXCodeObject::PBXContainerItemProxy); | 
 |   container->SetComment("PBXContainerItemProxy"); | 
 |   container->AddAttribute("containerPortal", | 
 |                           this->CreateObjectReference(this->RootObject)); | 
 |   container->AddAttribute("proxyType", this->CreateString("1")); | 
 |   container->AddAttribute("remoteGlobalIDString", | 
 |                           this->CreateObjectReference(dependTarget)); | 
 |   container->AddAttribute( | 
 |     "remoteInfo", this->CreateString(dependTarget->GetTarget()->GetName())); | 
 |   cmXCodeObject* targetdep = | 
 |     this->CreateObject(cmXCodeObject::PBXTargetDependency); | 
 |   targetdep->SetComment("PBXTargetDependency"); | 
 |   targetdep->AddAttribute("target", this->CreateObjectReference(dependTarget)); | 
 |   targetdep->AddAttribute("targetProxy", | 
 |                           this->CreateObjectReference(container)); | 
 |  | 
 |   cmXCodeObject* depends = target->GetAttribute("dependencies"); | 
 |   if (!depends) { | 
 |     cmSystemTools::Error( | 
 |       "target does not have dependencies attribute error.."); | 
 |  | 
 |   } else { | 
 |     depends->AddUniqueObject(targetdep); | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings, | 
 |                                                      char const* attribute, | 
 |                                                      cmXCodeObject* value) | 
 | { | 
 |   if (settings) { | 
 |     cmXCodeObject* attr = settings->GetAttribute(attribute); | 
 |     if (!attr) { | 
 |       settings->AddAttribute(attribute, value); | 
 |     } else { | 
 |       this->AppendBuildSettingAttribute(settings, attribute, attr, value); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AppendBuildSettingAttribute( | 
 |   cmXCodeObject* settings, char const* attribute, cmXCodeObject* attr, | 
 |   cmXCodeObject* value) | 
 | { | 
 |   if (value->GetType() != cmXCodeObject::OBJECT_LIST && | 
 |       value->GetType() != cmXCodeObject::STRING) { | 
 |     cmSystemTools::Error( | 
 |       cmStrCat("Unsupported value type for appending: ", attribute)); | 
 |     return; | 
 |   } | 
 |   if (attr->GetType() == cmXCodeObject::OBJECT_LIST) { | 
 |     if (value->GetType() == cmXCodeObject::OBJECT_LIST) { | 
 |       for (auto* obj : value->GetObjectList()) { | 
 |         attr->AddObject(obj); | 
 |       } | 
 |     } else { | 
 |       attr->AddObject(value); | 
 |     } | 
 |   } else if (attr->GetType() == cmXCodeObject::STRING) { | 
 |     if (value->GetType() == cmXCodeObject::OBJECT_LIST) { | 
 |       // Add old value as a list item to new object list | 
 |       // and replace the attribute with the new list | 
 |       value->PrependObject(attr); | 
 |       settings->AddAttribute(attribute, value); | 
 |     } else { | 
 |       std::string newValue = | 
 |         cmStrCat(attr->GetString(), ' ', value->GetString()); | 
 |       attr->SetString(newValue); | 
 |     } | 
 |   } else { | 
 |     cmSystemTools::Error( | 
 |       cmStrCat("Unsupported attribute type for appending: ", attribute)); | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AppendBuildSettingAttribute( | 
 |   cmXCodeObject* target, char const* attribute, cmXCodeObject* value, | 
 |   std::string const& configName) | 
 | { | 
 |   // There are multiple configurations.  Add the setting to the | 
 |   // buildSettings of the configuration name given. | 
 |   cmXCodeObject* configurationList = | 
 |     target->GetAttribute("buildConfigurationList")->GetObject(); | 
 |   cmXCodeObject* buildConfigs = | 
 |     configurationList->GetAttribute("buildConfigurations"); | 
 |   for (auto* obj : buildConfigs->GetObjectList()) { | 
 |     if (configName.empty() || | 
 |         obj->GetAttribute("name")->GetString() == configName) { | 
 |       cmXCodeObject* settings = obj->GetAttribute("buildSettings"); | 
 |       this->AppendOrAddBuildSetting(settings, attribute, value); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::InheritBuildSettingAttribute( | 
 |   cmXCodeObject* target, char const* attribute) | 
 | { | 
 |   cmXCodeObject* configurationList = | 
 |     target->GetAttribute("buildConfigurationList")->GetObject(); | 
 |   cmXCodeObject* buildConfigs = | 
 |     configurationList->GetAttribute("buildConfigurations"); | 
 |   for (auto* obj : buildConfigs->GetObjectList()) { | 
 |     cmXCodeObject* settings = obj->GetAttribute("buildSettings"); | 
 |     if (cmXCodeObject* attr = settings->GetAttribute(attribute)) { | 
 |       BuildObjectListOrString inherited(this, true); | 
 |       inherited.Add("$(inherited)"); | 
 |       this->AppendBuildSettingAttribute(settings, attribute, attr, | 
 |                                         inherited.CreateList()); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) | 
 | { | 
 |   cmGeneratorTarget* gt = target->GetTarget(); | 
 |   if (!gt) { | 
 |     cmSystemTools::Error("Error no target on xobject\n"); | 
 |     return; | 
 |   } | 
 |   if (!gt->IsInBuildSystem()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // Add dependencies on other CMake targets. | 
 |   for (auto const& dep : this->GetTargetDirectDepends(gt)) { | 
 |     if (cmXCodeObject* dptarget = this->FindXCodeTarget(dep)) { | 
 |       this->AddDependTarget(target, dptarget); | 
 |     } | 
 |   } | 
 |  | 
 |   // Separate libraries into ones that can be linked using "Link Binary With | 
 |   // Libraries" build phase and the ones that can't. Only targets that build | 
 |   // Apple bundles (.app, .framework, .bundle), executables and dylibs can use | 
 |   // this feature and only targets that represent actual libraries (object, | 
 |   // static, dynamic or bundle, excluding executables) will be used. These are | 
 |   // limitations imposed by CMake use-cases - otherwise a lot of things break. | 
 |   // The rest will be linked using linker flags (OTHER_LDFLAGS setting in Xcode | 
 |   // project). | 
 |   std::map<std::string, std::vector<cmComputeLinkInformation::Item const*>> | 
 |     configItemMap; | 
 |   auto addToLinkerArguments = | 
 |     [&configItemMap](std::string const& configName, | 
 |                      cmComputeLinkInformation::Item const* libItemPtr) { | 
 |       auto& linkVector = configItemMap[configName]; | 
 |       if (std::find_if(linkVector.begin(), linkVector.end(), | 
 |                        [libItemPtr](cmComputeLinkInformation::Item const* p) { | 
 |                          return p == libItemPtr; | 
 |                        }) == linkVector.end()) { | 
 |         linkVector.push_back(libItemPtr); | 
 |       } | 
 |     }; | 
 |   std::vector<cmComputeLinkInformation::Item const*> linkPhaseTargetVector; | 
 |   std::map<std::string, std::vector<std::string>> targetConfigMap; | 
 |   using ConfigItemPair = | 
 |     std::pair<std::string, cmComputeLinkInformation::Item const*>; | 
 |   std::map<std::string, std::vector<ConfigItemPair>> targetItemMap; | 
 |   std::map<std::string, std::vector<std::string>> targetProductNameMap; | 
 |   bool useLinkPhase = false; | 
 |   bool forceLinkPhase = false; | 
 |   cmValue prop = | 
 |     target->GetTarget()->GetProperty("XCODE_LINK_BUILD_PHASE_MODE"); | 
 |   if (prop) { | 
 |     if (*prop == "BUILT_ONLY"_s) { | 
 |       useLinkPhase = true; | 
 |     } else if (*prop == "KNOWN_LOCATION"_s) { | 
 |       useLinkPhase = true; | 
 |       forceLinkPhase = true; | 
 |     } else if (*prop != "NONE"_s) { | 
 |       cmSystemTools::Error( | 
 |         cmStrCat("Invalid value for XCODE_LINK_BUILD_PHASE_MODE: ", *prop)); | 
 |       return; | 
 |     } | 
 |   } | 
 |   for (auto const& configName : this->CurrentConfigurationTypes) { | 
 |     cmComputeLinkInformation* cli = gt->GetLinkInformation(configName); | 
 |     if (!cli) { | 
 |       continue; | 
 |     } | 
 |     for (auto const& libItem : cli->GetItems()) { | 
 |       // Explicitly ignore OBJECT libraries as Xcode emulates them as static | 
 |       // libraries without an artifact. Avoid exposing this to the rest of | 
 |       // CMake's compilation model. | 
 |       if (libItem.Target && | 
 |           libItem.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { | 
 |         continue; | 
 |       } | 
 |       // We want to put only static libraries, dynamic libraries, frameworks | 
 |       // and bundles that are built from targets that are not imported in "Link | 
 |       // Binary With Libraries" build phase. Except if the target property | 
 |       // XCODE_LINK_BUILD_PHASE_MODE is KNOWN_LOCATION then all imported and | 
 |       // non-target libraries will be added as well. | 
 |       if (useLinkPhase && | 
 |           (gt->GetType() == cmStateEnums::EXECUTABLE || | 
 |            gt->GetType() == cmStateEnums::SHARED_LIBRARY || | 
 |            gt->GetType() == cmStateEnums::MODULE_LIBRARY) && | 
 |           ((libItem.Target && | 
 |             (!libItem.Target->IsImported() || forceLinkPhase) && | 
 |             (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY || | 
 |              libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY || | 
 |              libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY || | 
 |              libItem.Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY)) || | 
 |            (!libItem.Target && | 
 |             libItem.IsPath == cmComputeLinkInformation::ItemIsPath::Yes && | 
 |             forceLinkPhase))) { | 
 |         std::string libName; | 
 |         bool canUseLinkPhase = !libItem.HasFeature() || | 
 |           libItem.GetFeatureName() == "__CMAKE_LINK_FRAMEWORK"_s || | 
 |           libItem.GetFeatureName() == "FRAMEWORK"_s || | 
 |           libItem.GetFeatureName() == "__CMAKE_LINK_XCFRAMEWORK"_s || | 
 |           libItem.GetFeatureName() == "XCFRAMEWORK"_s || | 
 |           libItem.GetFeatureName() == "WEAK_FRAMEWORK"_s || | 
 |           libItem.GetFeatureName() == "WEAK_LIBRARY"_s; | 
 |         if (canUseLinkPhase) { | 
 |           if (libItem.Target) { | 
 |             if (libItem.Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY) { | 
 |               canUseLinkPhase = canUseLinkPhase && forceLinkPhase; | 
 |             } else { | 
 |               // If a library target uses custom build output directory Xcode | 
 |               // won't pick it up so we have to resort back to linker flags, | 
 |               // but that's OK as long as the custom output dir is absolute | 
 |               // path. | 
 |               for (auto const& libConfigName : | 
 |                    this->CurrentConfigurationTypes) { | 
 |                 canUseLinkPhase = canUseLinkPhase && | 
 |                   libItem.Target->UsesDefaultOutputDir( | 
 |                     libConfigName, cmStateEnums::RuntimeBinaryArtifact); | 
 |               } | 
 |             } | 
 |             libName = libItem.Target->GetName(); | 
 |           } else { | 
 |             libName = cmSystemTools::GetFilenameName(libItem.Value.Value); | 
 |             // We don't want all the possible files here, just standard | 
 |             // libraries | 
 |             auto const libExt = cmSystemTools::GetFilenameExtension(libName); | 
 |             if (!IsLinkPhaseLibraryExtension(libExt)) { | 
 |               canUseLinkPhase = false; | 
 |             } | 
 |           } | 
 |         } | 
 |         if (canUseLinkPhase) { | 
 |           // Add unique configuration name to target-config map for later | 
 |           // checks | 
 |           auto& configVector = targetConfigMap[libName]; | 
 |           if (std::find(configVector.begin(), configVector.end(), | 
 |                         configName) == configVector.end()) { | 
 |             configVector.push_back(configName); | 
 |           } | 
 |           // Add a pair of config and item to target-item map | 
 |           auto& itemVector = targetItemMap[libName]; | 
 |           itemVector.emplace_back(configName, &libItem); | 
 |           // Add product file-name to a lib-product map | 
 |           auto productName = | 
 |             cmSystemTools::GetFilenameName(libItem.Value.Value); | 
 |           auto& productVector = targetProductNameMap[libName]; | 
 |           if (std::find(productVector.begin(), productVector.end(), | 
 |                         productName) == productVector.end()) { | 
 |             productVector.push_back(productName); | 
 |           } | 
 |           continue; | 
 |         } | 
 |       } | 
 |       // Add this library item to a regular linker flag list | 
 |       addToLinkerArguments(configName, &libItem); | 
 |     } | 
 |   } | 
 |  | 
 |   // Go through target library map and separate libraries that are linked | 
 |   // in all configurations and produce only single product, from the rest. | 
 |   // Only these will be linked through "Link Binary With Libraries" build | 
 |   // phase. | 
 |   for (auto const& targetLibConfigs : targetConfigMap) { | 
 |     // Add this library to "Link Binary With Libraries" build phase if it's | 
 |     // linked in all configurations and it has only one product name | 
 |     auto& itemVector = targetItemMap[targetLibConfigs.first]; | 
 |     auto& productVector = targetProductNameMap[targetLibConfigs.first]; | 
 |     if (targetLibConfigs.second == this->CurrentConfigurationTypes && | 
 |         productVector.size() == 1) { | 
 |       // Add this library to "Link Binary With Libraries" list | 
 |       linkPhaseTargetVector.push_back(itemVector[0].second); | 
 |     } else { | 
 |       for (auto const& libItem : targetItemMap[targetLibConfigs.first]) { | 
 |         // Add this library item to a regular linker flag list | 
 |         addToLinkerArguments(libItem.first, libItem.second); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Add libraries to "Link Binary With Libraries" build phase and collect | 
 |   // their search paths. Xcode does not support per-configuration linking | 
 |   // in this build phase so we don't have to do this for each configuration | 
 |   // separately. | 
 |   std::vector<std::string> linkSearchPaths; | 
 |   std::vector<std::string> frameworkSearchPaths; | 
 |   std::set<std::pair<cmXCodeObject*, std::string>> linkBuildFileSet; | 
 |   for (auto const& libItem : linkPhaseTargetVector) { | 
 |     // Add target output directory as a library search path | 
 |     std::string linkDir; | 
 |     if (libItem->Target) { | 
 |       linkDir = libItem->Target->GetLocationForBuild(); | 
 |     } else { | 
 |       linkDir = libItem->Value.Value; | 
 |     } | 
 |     if (cmHasSuffix(libItem->GetFeatureName(), "FRAMEWORK"_s)) { | 
 |       auto fwDescriptor = this->SplitFrameworkPath( | 
 |         linkDir, cmGlobalGenerator::FrameworkFormat::Extended); | 
 |       if (fwDescriptor && !fwDescriptor->Directory.empty()) { | 
 |         linkDir = fwDescriptor->Directory; | 
 |         if (std::find(frameworkSearchPaths.begin(), frameworkSearchPaths.end(), | 
 |                       linkDir) == frameworkSearchPaths.end()) { | 
 |           frameworkSearchPaths.push_back(linkDir); | 
 |         } | 
 |       } | 
 |     } else { | 
 |       linkDir = cmSystemTools::GetParentDirectory(linkDir); | 
 |       if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) == | 
 |           linkSearchPaths.end()) { | 
 |         linkSearchPaths.push_back(linkDir); | 
 |       } | 
 |     } | 
 |  | 
 |     if (libItem->Target && !libItem->Target->IsImported()) { | 
 |       for (auto const& configName : this->CurrentConfigurationTypes) { | 
 |         target->AddDependTarget(configName, libItem->Target->GetName()); | 
 |       } | 
 |     } | 
 |     // Get the library target | 
 |     auto* libTarget = FindXCodeTarget(libItem->Target); | 
 |     cmXCodeObject* buildFile; | 
 |     if (!libTarget) { | 
 |       if (libItem->IsPath == cmComputeLinkInformation::ItemIsPath::Yes) { | 
 |         // Get or create a direct file ref in the root project | 
 |         auto cleanPath = libItem->Value.Value; | 
 |         if (cmSystemTools::FileIsFullPath(cleanPath)) { | 
 |           // Some arguments are reported as paths, but they are actually not, | 
 |           // so we can't collapse them, and neither can we collapse relative | 
 |           // paths | 
 |           cleanPath = cmSystemTools::CollapseFullPath(cleanPath); | 
 |         } | 
 |         auto it = this->ExternalLibRefs.find(cleanPath); | 
 |         if (it == this->ExternalLibRefs.end()) { | 
 |           buildFile = CreateXCodeBuildFileFromPath(cleanPath, gt, "", nullptr); | 
 |           if (!buildFile) { | 
 |             // Add this library item back to a regular linker flag list | 
 |             for (auto const& conf : configItemMap) { | 
 |               addToLinkerArguments(conf.first, libItem); | 
 |             } | 
 |             continue; | 
 |           } | 
 |           this->ExternalLibRefs.emplace(cleanPath, buildFile); | 
 |         } else { | 
 |           buildFile = it->second; | 
 |         } | 
 |       } else { | 
 |         // Add this library item back to a regular linker flag list | 
 |         for (auto const& conf : configItemMap) { | 
 |           addToLinkerArguments(conf.first, libItem); | 
 |         } | 
 |         continue; | 
 |       } | 
 |     } else { | 
 |       // Add the target output file as a build reference for other targets | 
 |       // to link against | 
 |       auto* fileRefObject = libTarget->GetAttribute("productReference"); | 
 |       if (!fileRefObject) { | 
 |         // Add this library item back to a regular linker flag list | 
 |         for (auto const& conf : configItemMap) { | 
 |           addToLinkerArguments(conf.first, libItem); | 
 |         } | 
 |         continue; | 
 |       } | 
 |       auto it = FileRefToBuildFileMap.find(fileRefObject); | 
 |       if (it == FileRefToBuildFileMap.end()) { | 
 |         buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); | 
 |         buildFile->AddAttribute("fileRef", fileRefObject); | 
 |         FileRefToBuildFileMap[fileRefObject] = buildFile; | 
 |       } else { | 
 |         buildFile = it->second; | 
 |       } | 
 |     } | 
 |     // Add this reference to current target | 
 |     auto* buildPhases = target->GetAttribute("buildPhases"); | 
 |     if (!buildPhases) { | 
 |       cmSystemTools::Error("Missing buildPhase of target"); | 
 |       continue; | 
 |     } | 
 |     auto* frameworkBuildPhase = | 
 |       buildPhases->GetObject(cmXCodeObject::PBXFrameworksBuildPhase); | 
 |     if (!frameworkBuildPhase) { | 
 |       cmSystemTools::Error("Missing PBXFrameworksBuildPhase of buildPhase"); | 
 |       continue; | 
 |     } | 
 |     auto* buildFiles = frameworkBuildPhase->GetAttribute("files"); | 
 |     if (!buildFiles) { | 
 |       cmSystemTools::Error("Missing files of PBXFrameworksBuildPhase"); | 
 |       continue; | 
 |     } | 
 |     if (buildFile) { | 
 |       if (cmHasPrefix(libItem->GetFeatureName(), "WEAK_"_s)) { | 
 |         auto key = std::make_pair(buildFile->GetAttribute("fileRef"), | 
 |                                   libItem->GetFeatureName()); | 
 |         if (linkBuildFileSet.find(key) != linkBuildFileSet.end()) { | 
 |           continue; | 
 |         } | 
 |         linkBuildFileSet.insert(key); | 
 |  | 
 |         cmXCodeObject* buildObject = | 
 |           this->CreateObject(cmXCodeObject::PBXBuildFile); | 
 |         buildObject->AddAttribute("fileRef", key.first); | 
 |         // Add settings, ATTRIBUTES, Weak flag | 
 |         cmXCodeObject* settings = | 
 |           this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |         cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |         attrs->AddObject(this->CreateString("Weak")); | 
 |         settings->AddAttribute("ATTRIBUTES", attrs); | 
 |         buildObject->AddAttribute("settings", settings); | 
 |         buildFile = buildObject; | 
 |       } | 
 |       if (!buildFiles->HasObject(buildFile)) { | 
 |         buildFiles->AddObject(buildFile); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Loop over configuration types and set per-configuration info. | 
 |   for (auto const& configName : this->CurrentConfigurationTypes) { | 
 |     { | 
 |       // Add object library contents as link flags. | 
 |       BuildObjectListOrString libSearchPaths(this, true); | 
 |       std::vector<cmSourceFile const*> objs; | 
 |       gt->GetExternalObjects(objs, configName); | 
 |       for (auto const* sourceFile : objs) { | 
 |         if (sourceFile->GetObjectLibrary().empty()) { | 
 |           continue; | 
 |         } | 
 |         libSearchPaths.Add(this->XCodeEscapePath(sourceFile->GetFullPath())); | 
 |       } | 
 |       this->AppendBuildSettingAttribute( | 
 |         target, this->GetTargetLinkFlagsVar(gt), libSearchPaths.CreateList(), | 
 |         configName); | 
 |     } | 
 |  | 
 |     // Compute the link library and directory information. | 
 |     cmComputeLinkInformation* cli = gt->GetLinkInformation(configName); | 
 |     if (!cli) { | 
 |       continue; | 
 |     } | 
 |  | 
 |     // add .xcframework include paths | 
 |     { | 
 |       // Keep track of framework search paths we've already added or that are | 
 |       // part of the set of implicit search paths. We don't want to repeat | 
 |       // them and we also need to avoid hard-coding any SDK-specific paths. | 
 |       // This is essential for getting device-and-simulator builds to work, | 
 |       // otherwise we end up hard-coding a path to the wrong SDK for | 
 |       // SDK-provided frameworks that are added by their full path. | 
 |       std::set<std::string> emitted(cli->GetFrameworkPathsEmitted()); | 
 |       BuildObjectListOrString includePaths(this, true); | 
 |       BuildObjectListOrString fwSearchPaths(this, true); | 
 |       for (auto const& libItem : configItemMap[configName]) { | 
 |         auto const& libName = *libItem; | 
 |         if (libName.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) { | 
 |           auto cleanPath = libName.Value.Value; | 
 |           if (cmSystemTools::FileIsFullPath(cleanPath)) { | 
 |             cleanPath = cmSystemTools::CollapseFullPath(cleanPath); | 
 |           } | 
 |           bool isXcFramework = | 
 |             cmHasSuffix(libName.GetFeatureName(), "XCFRAMEWORK"_s); | 
 |           if (isXcFramework) { | 
 |             auto plist = cmParseXcFrameworkPlist( | 
 |               cleanPath, *this->Makefiles.front(), libName.Value.Backtrace); | 
 |             if (!plist) { | 
 |               return; | 
 |             } | 
 |             if (auto const* library = plist->SelectSuitableLibrary( | 
 |                   *this->Makefiles.front(), libName.Value.Backtrace)) { | 
 |               auto libraryPath = | 
 |                 cmStrCat(cleanPath, '/', library->LibraryIdentifier, '/', | 
 |                          library->LibraryPath); | 
 |               if (auto const fwDescriptor = this->SplitFrameworkPath( | 
 |                     libraryPath, | 
 |                     cmGlobalGenerator::FrameworkFormat::Relaxed)) { | 
 |                 if (!fwDescriptor->Directory.empty() && | 
 |                     emitted.insert(fwDescriptor->Directory).second) { | 
 |                   // This is a search path we had not added before and it | 
 |                   // isn't an implicit search path, so we need it | 
 |                   fwSearchPaths.Add( | 
 |                     this->XCodeEscapePath(fwDescriptor->Directory)); | 
 |                 } | 
 |               } else { | 
 |                 if (!library->HeadersPath.empty()) { | 
 |                   includePaths.Add(this->XCodeEscapePath( | 
 |                     cmStrCat(cleanPath, '/', library->LibraryIdentifier, '/', | 
 |                              library->HeadersPath))); | 
 |                 } | 
 |               } | 
 |             } else { | 
 |               return; | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |       if (!includePaths.IsEmpty()) { | 
 |         this->AppendBuildSettingAttribute(target, "HEADER_SEARCH_PATHS", | 
 |                                           includePaths.CreateList(), | 
 |                                           configName); | 
 |       } | 
 |       if (!fwSearchPaths.IsEmpty()) { | 
 |         this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS", | 
 |                                           fwSearchPaths.CreateList(), | 
 |                                           configName); | 
 |       } | 
 |     } | 
 |  | 
 |     // Skip link information for object libraries. | 
 |     if (gt->GetType() == cmStateEnums::OBJECT_LIBRARY || | 
 |         gt->GetType() == cmStateEnums::STATIC_LIBRARY) { | 
 |       continue; | 
 |     } | 
 |  | 
 |     // Add dependencies directly on library files. | 
 |     for (auto const& libDep : cli->GetDepends()) { | 
 |       target->AddDependLibrary(configName, libDep); | 
 |     } | 
 |  | 
 |     // add the library search paths | 
 |     { | 
 |       BuildObjectListOrString libSearchPaths(this, true); | 
 |  | 
 |       for (auto const& libDir : cli->GetDirectories()) { | 
 |         if (!libDir.empty() && libDir != "/usr/lib"_s) { | 
 |           cmPolicies::PolicyStatus cmp0142 = | 
 |             target->GetTarget()->GetPolicyStatusCMP0142(); | 
 |           if (cmp0142 == cmPolicies::OLD || cmp0142 == cmPolicies::WARN) { | 
 |             libSearchPaths.Add(this->XCodeEscapePath(cmStrCat( | 
 |               libDir, "/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"))); | 
 |           } | 
 |           libSearchPaths.Add(this->XCodeEscapePath(libDir)); | 
 |         } | 
 |       } | 
 |  | 
 |       // Add previously collected paths where to look for libraries | 
 |       // that were added to "Link Binary With Libraries" | 
 |       for (auto& libDir : linkSearchPaths) { | 
 |         libSearchPaths.Add(this->XCodeEscapePath(libDir)); | 
 |       } | 
 |  | 
 |       // Add toolchain specified language link directories | 
 |       std::string const& linkDirsString = | 
 |         this->Makefiles.front()->GetSafeDefinition(cmStrCat( | 
 |           "CMAKE_", cli->GetLinkLanguage(), "_STANDARD_LINK_DIRECTORIES")); | 
 |  | 
 |       for (auto const& libDir : cmList(linkDirsString)) { | 
 |         libSearchPaths.Add(this->XCodeEscapePath(libDir)); | 
 |       } | 
 |  | 
 |       if (!libSearchPaths.IsEmpty()) { | 
 |         this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS", | 
 |                                           libSearchPaths.CreateList(), | 
 |                                           configName); | 
 |       } | 
 |     } | 
 |  | 
 |     // add framework search paths | 
 |     { | 
 |       BuildObjectListOrString fwSearchPaths(this, true); | 
 |       // Add previously collected paths where to look for frameworks | 
 |       // that were added to "Link Binary With Libraries" | 
 |       for (auto& fwDir : frameworkSearchPaths) { | 
 |         fwSearchPaths.Add(this->XCodeEscapePath(fwDir)); | 
 |       } | 
 |       if (!fwSearchPaths.IsEmpty()) { | 
 |         this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS", | 
 |                                           fwSearchPaths.CreateList(), | 
 |                                           configName); | 
 |       } | 
 |     } | 
 |  | 
 |     // now add the left-over link libraries | 
 |     { | 
 |       // Keep track of framework search paths we've already added or that are | 
 |       // part of the set of implicit search paths. We don't want to repeat | 
 |       // them and we also need to avoid hard-coding any SDK-specific paths. | 
 |       // This is essential for getting device-and-simulator builds to work, | 
 |       // otherwise we end up hard-coding a path to the wrong SDK for | 
 |       // SDK-provided frameworks that are added by their full path. | 
 |       std::set<std::string> emitted(cli->GetFrameworkPathsEmitted()); | 
 |       BuildObjectListOrString libPaths(this, true); | 
 |       BuildObjectListOrString fwSearchPaths(this, true); | 
 |       for (auto const& libItem : configItemMap[configName]) { | 
 |         auto const& libName = *libItem; | 
 |         if (libName.IsPath == cmComputeLinkInformation::ItemIsPath::Yes) { | 
 |           auto cleanPath = libName.Value.Value; | 
 |           if (cmSystemTools::FileIsFullPath(cleanPath)) { | 
 |             cleanPath = cmSystemTools::CollapseFullPath(cleanPath); | 
 |           } | 
 |           bool isXcFramework = | 
 |             cmHasSuffix(libName.GetFeatureName(), "XCFRAMEWORK"_s); | 
 |           bool isFramework = !isXcFramework && | 
 |             cmHasSuffix(libName.GetFeatureName(), "FRAMEWORK"_s); | 
 |           if (isFramework) { | 
 |             auto const fwDescriptor = this->SplitFrameworkPath( | 
 |               cleanPath, cmGlobalGenerator::FrameworkFormat::Extended); | 
 |             if (isFramework && !fwDescriptor->Directory.empty() && | 
 |                 emitted.insert(fwDescriptor->Directory).second) { | 
 |               // This is a search path we had not added before and it isn't | 
 |               // an implicit search path, so we need it | 
 |               fwSearchPaths.Add( | 
 |                 this->XCodeEscapePath(fwDescriptor->Directory)); | 
 |             } | 
 |             if (libName.GetFeatureName() == "__CMAKE_LINK_FRAMEWORK"_s) { | 
 |               // use the full path | 
 |               libPaths.Add( | 
 |                 libName.GetFormattedItem(this->XCodeEscapePath(cleanPath)) | 
 |                   .Value); | 
 |             } else { | 
 |               libPaths.Add(libName | 
 |                              .GetFormattedItem(this->XCodeEscapePath( | 
 |                                fwDescriptor->GetLinkName())) | 
 |                              .Value); | 
 |             } | 
 |           } else if (isXcFramework) { | 
 |             auto plist = cmParseXcFrameworkPlist( | 
 |               cleanPath, *this->Makefiles.front(), libName.Value.Backtrace); | 
 |             if (!plist) { | 
 |               return; | 
 |             } | 
 |             if (auto const* library = plist->SelectSuitableLibrary( | 
 |                   *this->Makefiles.front(), libName.Value.Backtrace)) { | 
 |               auto libraryPath = | 
 |                 cmStrCat(cleanPath, '/', library->LibraryIdentifier, '/', | 
 |                          library->LibraryPath); | 
 |               if (auto const fwDescriptor = this->SplitFrameworkPath( | 
 |                     libraryPath, | 
 |                     cmGlobalGenerator::FrameworkFormat::Relaxed)) { | 
 |                 libPaths.Add(cmStrCat( | 
 |                   "-framework ", | 
 |                   this->XCodeEscapePath(fwDescriptor->GetLinkName()))); | 
 |               } else { | 
 |                 libPaths.Add( | 
 |                   libName.GetFormattedItem(this->XCodeEscapePath(libraryPath)) | 
 |                     .Value); | 
 |               } | 
 |             } else { | 
 |               return; | 
 |             } | 
 |           } else { | 
 |             libPaths.Add( | 
 |               libName.GetFormattedItem(this->XCodeEscapePath(cleanPath)) | 
 |                 .Value); | 
 |           } | 
 |           if ((!libName.Target || libName.Target->IsImported()) && | 
 |               (isFramework || isXcFramework || | 
 |                IsLinkPhaseLibraryExtension(cleanPath))) { | 
 |             // Create file reference for embedding | 
 |             auto it = this->ExternalLibRefs.find(cleanPath); | 
 |             if (it == this->ExternalLibRefs.end()) { | 
 |               auto* buildFile = | 
 |                 this->CreateXCodeBuildFileFromPath(cleanPath, gt, "", nullptr); | 
 |               if (buildFile) { | 
 |                 this->ExternalLibRefs.emplace(cleanPath, buildFile); | 
 |               } | 
 |             } | 
 |           } | 
 |         } else if (!libName.Target || | 
 |                    libName.Target->GetType() != | 
 |                      cmStateEnums::INTERFACE_LIBRARY) { | 
 |           libPaths.Add(libName.Value.Value); | 
 |         } | 
 |         if (libName.Target && !libName.Target->IsImported()) { | 
 |           target->AddDependTarget(configName, libName.Target->GetName()); | 
 |         } | 
 |       } | 
 |       if (!libPaths.IsEmpty()) { | 
 |         this->AppendBuildSettingAttribute(target, | 
 |                                           this->GetTargetLinkFlagsVar(gt), | 
 |                                           libPaths.CreateList(), configName); | 
 |       } | 
 |       if (!fwSearchPaths.IsEmpty()) { | 
 |         this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS", | 
 |                                           fwSearchPaths.CreateList(), | 
 |                                           configName); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddEmbeddedObjects( | 
 |   cmXCodeObject* target, std::string const& copyFilesBuildPhaseName, | 
 |   std::string const& embedPropertyName, std::string const& dstSubfolderSpec, | 
 |   int actionsOnByDefault, std::string const& defaultDstPath) | 
 | { | 
 |   cmGeneratorTarget* gt = target->GetTarget(); | 
 |   if (!gt) { | 
 |     cmSystemTools::Error("Error no target on xobject\n"); | 
 |     return; | 
 |   } | 
 |   if (!gt->IsInBuildSystem()) { | 
 |     return; | 
 |   } | 
 |   bool isFrameworkTarget = gt->IsFrameworkOnApple(); | 
 |   bool isBundleTarget = gt->GetPropertyAsBool("MACOSX_BUNDLE"); | 
 |   bool isCFBundleTarget = gt->IsCFBundleOnApple(); | 
 |   if (!(isFrameworkTarget || isBundleTarget || isCFBundleTarget)) { | 
 |     return; | 
 |   } | 
 |   cmValue files = gt->GetProperty(embedPropertyName); | 
 |   if (!files) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // Create an "Embedded Frameworks" build phase | 
 |   auto* copyFilesBuildPhase = | 
 |     this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase); | 
 |   copyFilesBuildPhase->SetComment(copyFilesBuildPhaseName); | 
 |   copyFilesBuildPhase->AddAttribute("buildActionMask", | 
 |                                     this->CreateString("2147483647")); | 
 |   copyFilesBuildPhase->AddAttribute("dstSubfolderSpec", | 
 |                                     this->CreateString(dstSubfolderSpec)); | 
 |   copyFilesBuildPhase->AddAttribute( | 
 |     "name", this->CreateString(copyFilesBuildPhaseName)); | 
 |   if (cmValue fwEmbedPath = | 
 |         gt->GetProperty(cmStrCat(embedPropertyName, "_PATH"))) { | 
 |     copyFilesBuildPhase->AddAttribute("dstPath", | 
 |                                       this->CreateString(*fwEmbedPath)); | 
 |   } else { | 
 |     copyFilesBuildPhase->AddAttribute("dstPath", | 
 |                                       this->CreateString(defaultDstPath)); | 
 |   } | 
 |   copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", | 
 |                                     this->CreateString("0")); | 
 |   cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   // Collect all embedded frameworks and dylibs and add them to build phase | 
 |   cmList relFiles{ *files }; | 
 |   for (std::string const& relFile : relFiles) { | 
 |     cmXCodeObject* buildFile{ nullptr }; | 
 |     std::string filePath = relFile; | 
 |     auto* genTarget = this->FindGeneratorTarget(relFile); | 
 |     if (genTarget) { | 
 |       // This is a target - get it's product path reference | 
 |       auto* xcTarget = this->FindXCodeTarget(genTarget); | 
 |       if (!xcTarget) { | 
 |         cmSystemTools::Error( | 
 |           cmStrCat("Can not find a target for ", genTarget->GetName())); | 
 |         continue; | 
 |       } | 
 |       // Add the target output file as a build reference for other targets | 
 |       // to link against | 
 |       auto* fileRefObject = xcTarget->GetAttribute("productReference"); | 
 |       if (!fileRefObject) { | 
 |         cmSystemTools::Error(cmStrCat("Target ", genTarget->GetName(), | 
 |                                       " is missing product reference")); | 
 |         continue; | 
 |       } | 
 |       auto it = this->FileRefToEmbedBuildFileMap.find(fileRefObject); | 
 |       if (it == this->FileRefToEmbedBuildFileMap.end()) { | 
 |         buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); | 
 |         buildFile->AddAttribute("fileRef", fileRefObject); | 
 |         this->FileRefToEmbedBuildFileMap[fileRefObject] = buildFile; | 
 |       } else { | 
 |         buildFile = it->second; | 
 |       } | 
 |     } else if (cmSystemTools::IsPathToFramework(relFile) || | 
 |                cmSystemTools::IsPathToMacOSSharedLibrary(relFile) || | 
 |                cmSystemTools::FileIsDirectory(filePath)) { | 
 |       // This is a regular string path - create file reference | 
 |       cmXCodeObject* fileRef = | 
 |         this->CreateXCodeFileReferenceFromPath(relFile, gt, "", nullptr); | 
 |       if (fileRef) { | 
 |         buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); | 
 |         buildFile->SetComment(fileRef->GetComment()); | 
 |         buildFile->AddAttribute("fileRef", | 
 |                                 this->CreateObjectReference(fileRef)); | 
 |       } | 
 |       if (!buildFile) { | 
 |         cmSystemTools::Error( | 
 |           cmStrCat("Can't create build file for ", relFile)); | 
 |         continue; | 
 |       } | 
 |     } | 
 |     if (!buildFile) { | 
 |       cmSystemTools::Error(cmStrCat("Can't find a build file for ", relFile)); | 
 |       continue; | 
 |     } | 
 |     // Set build file configuration | 
 |     cmXCodeObject* settings = | 
 |       this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |     cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |  | 
 |     bool removeHeaders = actionsOnByDefault & RemoveHeadersOnCopyByDefault; | 
 |     if (cmValue prop = gt->GetProperty( | 
 |           cmStrCat(embedPropertyName, "_REMOVE_HEADERS_ON_COPY"))) { | 
 |       removeHeaders = prop.IsOn(); | 
 |     } | 
 |     if (removeHeaders) { | 
 |       attrs->AddObject(this->CreateString("RemoveHeadersOnCopy")); | 
 |     } | 
 |  | 
 |     bool codeSign = actionsOnByDefault & CodeSignOnCopyByDefault; | 
 |     if (cmValue prop = | 
 |           gt->GetProperty(cmStrCat(embedPropertyName, "_CODE_SIGN_ON_COPY"))) { | 
 |       codeSign = prop.IsOn(); | 
 |     } | 
 |     if (codeSign) { | 
 |       attrs->AddObject(this->CreateString("CodeSignOnCopy")); | 
 |     } | 
 |  | 
 |     settings->AddAttributeIfNotEmpty("ATTRIBUTES", attrs); | 
 |     buildFile->AddAttributeIfNotEmpty("settings", settings); | 
 |     if (!buildFiles->HasObject(buildFile)) { | 
 |       buildFiles->AddObject(buildFile); | 
 |     } | 
 |   } | 
 |   copyFilesBuildPhase->AddAttribute("files", buildFiles); | 
 |   auto* buildPhases = target->GetAttribute("buildPhases"); | 
 |   // Embed-something build phases must be inserted before the post-build | 
 |   // command because that command is expected to be last | 
 |   buildPhases->InsertObject(buildPhases->GetObjectCount() - 1, | 
 |                             copyFilesBuildPhase); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddEmbeddedFrameworks(cmXCodeObject* target) | 
 | { | 
 |   static auto const* const dstSubfolderSpec = "10"; | 
 |  | 
 |   // Despite the name, by default Xcode uses "Embed Frameworks" build phase | 
 |   // for both frameworks and dynamic libraries | 
 |   this->AddEmbeddedObjects(target, "Embed Frameworks", | 
 |                            "XCODE_EMBED_FRAMEWORKS", dstSubfolderSpec, | 
 |                            NoActionOnCopyByDefault); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddEmbeddedPlugIns(cmXCodeObject* target) | 
 | { | 
 |   static auto const* const dstSubfolderSpec = "13"; | 
 |  | 
 |   this->AddEmbeddedObjects(target, "Embed PlugIns", "XCODE_EMBED_PLUGINS", | 
 |                            dstSubfolderSpec, NoActionOnCopyByDefault); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddEmbeddedAppExtensions(cmXCodeObject* target) | 
 | { | 
 |   static auto const* const dstSubfolderSpec = "13"; | 
 |  | 
 |   this->AddEmbeddedObjects(target, "Embed App Extensions", | 
 |                            "XCODE_EMBED_APP_EXTENSIONS", dstSubfolderSpec, | 
 |                            RemoveHeadersOnCopyByDefault); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddEmbeddedExtensionKitExtensions( | 
 |   cmXCodeObject* target) | 
 | { | 
 |   static auto const* const dstSubfolderSpec = "16"; | 
 |  | 
 |   this->AddEmbeddedObjects(target, "Embed App Extensions", | 
 |                            "XCODE_EMBED_EXTENSIONKIT_EXTENSIONS", | 
 |                            dstSubfolderSpec, RemoveHeadersOnCopyByDefault, | 
 |                            "$(EXTENSIONS_FOLDER_PATH)"); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddEmbeddedResources(cmXCodeObject* target) | 
 | { | 
 |   static auto const dstSubfolderSpec = "7"; | 
 |  | 
 |   this->AddEmbeddedObjects(target, "Embed Resources", "XCODE_EMBED_RESOURCES", | 
 |                            dstSubfolderSpec, NoActionOnCopyByDefault); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AddEmbeddedXPCServices(cmXCodeObject* target) | 
 | { | 
 |   static auto const dstSubfolderSpec = "16"; | 
 |  | 
 |   this->AddEmbeddedObjects( | 
 |     target, "Embed XPC Services", "XCODE_EMBED_XPC_SERVICES", dstSubfolderSpec, | 
 |     NoActionOnCopyByDefault, "$(CONTENTS_FOLDER_PATH)/XPCServices"); | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::CreateGroups( | 
 |   std::vector<cmLocalGenerator*>& generators) | 
 | { | 
 |   for (auto& generator : generators) { | 
 |     cmMakefile* mf = generator->GetMakefile(); | 
 |     std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups(); | 
 |     for (auto const& gtgt : generator->GetGeneratorTargets()) { | 
 |       // Same skipping logic here as in CreateXCodeTargets so that we do not | 
 |       // end up with (empty anyhow) ZERO_CHECK, install, or test source | 
 |       // groups: | 
 |       // | 
 |       if (!gtgt->IsInBuildSystem() || | 
 |           gtgt->GetType() == cmStateEnums::GLOBAL_TARGET || | 
 |           gtgt->GetName() == CMAKE_CHECK_BUILD_SYSTEM_TARGET) { | 
 |         continue; | 
 |       } | 
 |  | 
 |       auto addSourceToGroup = [this, mf, >gt, | 
 |                                &sourceGroups](std::string const& source) { | 
 |         cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups); | 
 |         cmXCodeObject* pbxgroup = | 
 |           this->CreateOrGetPBXGroup(gtgt.get(), sourceGroup); | 
 |         std::string key = GetGroupMapKeyFromPath(gtgt.get(), source); | 
 |         this->GroupMap[key] = pbxgroup; | 
 |       }; | 
 |  | 
 |       // Put cmSourceFile instances in proper groups: | 
 |       for (auto const& si : gtgt->GetAllConfigSources()) { | 
 |         cmSourceFile const* sf = si.Source; | 
 |         if (!sf->GetObjectLibrary().empty()) { | 
 |           // Object library files go on the link line instead. | 
 |           continue; | 
 |         } | 
 |         addSourceToGroup(sf->GetFullPath()); | 
 |       } | 
 |  | 
 |       // Add CMakeLists.txt file for user convenience. | 
 |       { | 
 |         std::string listfile = this->GetCMakeInstance()->GetCMakeListFile( | 
 |           gtgt->GetLocalGenerator()->GetCurrentSourceDirectory()); | 
 |         cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource( | 
 |           listfile, false, cmSourceFileLocationKind::Known); | 
 |         sf->SetSpecialSourceType(cmSourceFile::SpecialSourceType::CMakeLists); | 
 |         addSourceToGroup(sf->ResolveFullPath()); | 
 |       } | 
 |  | 
 |       // Add the Info.plist we are about to generate for an App Bundle. | 
 |       if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { | 
 |         std::string plist = this->ComputeInfoPListLocation(gtgt.get()); | 
 |         cmSourceFile* sf = gtgt->Makefile->GetOrCreateSource( | 
 |           plist, true, cmSourceFileLocationKind::Known); | 
 |         sf->SetSpecialSourceType( | 
 |           cmSourceFile::SpecialSourceType::BundleInfoPlist); | 
 |         addSourceToGroup(sf->ResolveFullPath()); | 
 |       } | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreatePBXGroup(cmXCodeObject* parent, | 
 |                                                       std::string const& name) | 
 | { | 
 |   cmXCodeObject* parentChildren = nullptr; | 
 |   if (parent) { | 
 |     parentChildren = parent->GetAttribute("children"); | 
 |   } | 
 |   cmXCodeObject* group = this->CreateObject(cmXCodeObject::PBXGroup); | 
 |   cmXCodeObject* groupChildren = | 
 |     this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   group->AddAttribute("name", this->CreateString(name)); | 
 |   group->AddAttribute("children", groupChildren); | 
 |   group->AddAttribute("sourceTree", this->CreateString("<group>")); | 
 |   if (parentChildren) { | 
 |     parentChildren->AddObject(group); | 
 |   } | 
 |   return group; | 
 | } | 
 |  | 
 | cmXCodeObject* cmGlobalXCodeGenerator::CreateOrGetPBXGroup( | 
 |   cmGeneratorTarget* gtgt, cmSourceGroup* sg) | 
 | { | 
 |   std::string s; | 
 |   std::string target; | 
 |   std::string const targetFolder = gtgt->GetEffectiveFolderName(); | 
 |   if (!targetFolder.empty()) { | 
 |     target = cmStrCat(targetFolder, '/'); | 
 |   } | 
 |   target += gtgt->GetName(); | 
 |   s = cmStrCat(target, '/', sg->GetFullName()); | 
 |   auto it = this->GroupNameMap.find(s); | 
 |   if (it != this->GroupNameMap.end()) { | 
 |     return it->second; | 
 |   } | 
 |  | 
 |   it = this->TargetGroup.find(target); | 
 |   cmXCodeObject* tgroup = nullptr; | 
 |   if (it != this->TargetGroup.end()) { | 
 |     tgroup = it->second; | 
 |   } else { | 
 |     std::vector<std::string> const tgt_folders = cmTokenize(target, '/'); | 
 |     std::string curr_tgt_folder; | 
 |     for (std::vector<std::string>::size_type i = 0; i < tgt_folders.size(); | 
 |          i++) { | 
 |       if (i != 0) { | 
 |         curr_tgt_folder += '/'; | 
 |       } | 
 |       curr_tgt_folder += tgt_folders[i]; | 
 |       it = this->TargetGroup.find(curr_tgt_folder); | 
 |       if (it != this->TargetGroup.end()) { | 
 |         tgroup = it->second; | 
 |         continue; | 
 |       } | 
 |       tgroup = this->CreatePBXGroup(tgroup, tgt_folders[i]); | 
 |       this->TargetGroup[curr_tgt_folder] = tgroup; | 
 |       if (i == 0) { | 
 |         this->MainGroupChildren->AddObject(tgroup); | 
 |       } | 
 |     } | 
 |   } | 
 |   this->TargetGroup[target] = tgroup; | 
 |  | 
 |   // If it's the default source group (empty name) then put the source file | 
 |   // directly in the tgroup... | 
 |   // | 
 |   if (sg->GetFullName().empty()) { | 
 |     this->GroupNameMap[s] = tgroup; | 
 |     return tgroup; | 
 |   } | 
 |  | 
 |   // It's a recursive folder structure, let's find the real parent group | 
 |   if (sg->GetFullName() != sg->GetName()) { | 
 |     std::string curr_folder = cmStrCat(target, '/'); | 
 |     for (auto const& folder : cmTokenize(sg->GetFullName(), '\\')) { | 
 |       curr_folder += folder; | 
 |       auto const i_folder = this->GroupNameMap.find(curr_folder); | 
 |       // Create new folder | 
 |       if (i_folder == this->GroupNameMap.end()) { | 
 |         cmXCodeObject* group = this->CreatePBXGroup(tgroup, folder); | 
 |         this->GroupNameMap[curr_folder] = group; | 
 |         tgroup = group; | 
 |       } else { | 
 |         tgroup = i_folder->second; | 
 |       } | 
 |       curr_folder += '\\'; | 
 |     } | 
 |     return tgroup; | 
 |   } | 
 |   cmXCodeObject* group = this->CreatePBXGroup(tgroup, sg->GetName()); | 
 |   this->GroupNameMap[s] = group; | 
 |   return group; | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::CreateXCodeObjects( | 
 |   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators) | 
 | { | 
 |   this->ClearXCodeObjects(); | 
 |   this->RootObject = nullptr; | 
 |   this->MainGroupChildren = nullptr; | 
 |   this->FrameworkGroup = nullptr; | 
 |   cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |   group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO")); | 
 |   cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   for (std::string const& CurrentConfigurationType : | 
 |        this->CurrentConfigurationTypes) { | 
 |     cmXCodeObject* buildStyle = | 
 |       this->CreateObject(cmXCodeObject::PBXBuildStyle); | 
 |     std::string const& name = CurrentConfigurationType; | 
 |     buildStyle->AddAttribute("name", this->CreateString(name)); | 
 |     buildStyle->SetComment(name); | 
 |     cmXCodeObject* sgroup = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |     sgroup->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO")); | 
 |     buildStyle->AddAttribute("buildSettings", sgroup); | 
 |     listObjs->AddObject(buildStyle); | 
 |   } | 
 |  | 
 |   cmXCodeObject* mainGroup = this->CreateObject(cmXCodeObject::PBXGroup); | 
 |   this->MainGroupChildren = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   mainGroup->AddAttribute("children", this->MainGroupChildren); | 
 |   mainGroup->AddAttribute("sourceTree", this->CreateString("<group>")); | 
 |  | 
 |   // now create the cmake groups | 
 |   if (!this->CreateGroups(generators)) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   cmXCodeObject* productGroup = this->CreateObject(cmXCodeObject::PBXGroup); | 
 |   productGroup->AddAttribute("name", this->CreateString("Products")); | 
 |   productGroup->AddAttribute("sourceTree", this->CreateString("<group>")); | 
 |   cmXCodeObject* productGroupChildren = | 
 |     this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   productGroup->AddAttribute("children", productGroupChildren); | 
 |   this->MainGroupChildren->AddObject(productGroup); | 
 |  | 
 |   this->FrameworkGroup = this->CreateObject(cmXCodeObject::PBXGroup); | 
 |   this->FrameworkGroup->AddAttribute("name", this->CreateString("Frameworks")); | 
 |   this->FrameworkGroup->AddAttribute("sourceTree", | 
 |                                      this->CreateString("<group>")); | 
 |   cmXCodeObject* frameworkGroupChildren = | 
 |     this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   this->FrameworkGroup->AddAttribute("children", frameworkGroupChildren); | 
 |   this->MainGroupChildren->AddObject(this->FrameworkGroup); | 
 |  | 
 |   this->ResourcesGroup = this->CreateObject(cmXCodeObject::PBXGroup); | 
 |   this->ResourcesGroup->AddAttribute("name", this->CreateString("Resources")); | 
 |   this->ResourcesGroup->AddAttribute("sourceTree", | 
 |                                      this->CreateString("<group>")); | 
 |   cmXCodeObject* ResourcesGroupChildren = | 
 |     this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   this->ResourcesGroup->AddAttribute("children", ResourcesGroupChildren); | 
 |   this->MainGroupChildren->AddObject(this->ResourcesGroup); | 
 |  | 
 |   this->RootObject = this->CreateObject(cmXCodeObject::PBXProject); | 
 |   this->RootObject->SetComment("Project object"); | 
 |  | 
 |   std::string project_id = cmStrCat("PROJECT_", root->GetProjectName()); | 
 |   this->RootObject->SetId( | 
 |     this->GetOrCreateId(project_id, this->RootObject->GetId())); | 
 |  | 
 |   group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |   this->RootObject->AddAttribute("mainGroup", | 
 |                                  this->CreateObjectReference(mainGroup)); | 
 |   this->RootObject->AddAttribute("buildSettings", group); | 
 |   this->RootObject->AddAttribute("buildStyles", listObjs); | 
 |   this->RootObject->AddAttribute("hasScannedForEncodings", | 
 |                                  this->CreateString("0")); | 
 |   group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |   group->AddAttribute("BuildIndependentTargetsInParallel", | 
 |                       this->CreateString("YES")); | 
 |   std::ostringstream v; | 
 |   v << std::setfill('0') << std::setw(4) << XcodeVersion * 10; | 
 |   group->AddAttribute("LastUpgradeCheck", this->CreateString(v.str())); | 
 |   this->RootObject->AddAttribute("attributes", group); | 
 |   this->RootObject->AddAttribute("compatibilityVersion", | 
 |                                  this->CreateString("Xcode 3.2")); | 
 |   // Point Xcode at the top of the source tree. | 
 |   { | 
 |     std::string pdir = | 
 |       this->RelativeToBinary(root->GetCurrentSourceDirectory()); | 
 |     this->RootObject->AddAttribute("projectDirPath", this->CreateString(pdir)); | 
 |     this->RootObject->AddAttribute("projectRoot", this->CreateString("")); | 
 |   } | 
 |   cmXCodeObject* configlist = | 
 |     this->CreateObject(cmXCodeObject::XCConfigurationList); | 
 |   cmXCodeObject* buildConfigurations = | 
 |     this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   using Configs = std::vector<std::pair<std::string, cmXCodeObject*>>; | 
 |   Configs configs; | 
 |   std::string defaultConfigName; | 
 |   for (auto const& name : this->CurrentConfigurationTypes) { | 
 |     if (defaultConfigName.empty()) { | 
 |       defaultConfigName = name; | 
 |     } | 
 |     cmXCodeObject* config = | 
 |       this->CreateObject(cmXCodeObject::XCBuildConfiguration); | 
 |     config->AddAttribute("name", this->CreateString(name)); | 
 |     configs.emplace_back(name, config); | 
 |   } | 
 |   if (defaultConfigName.empty()) { | 
 |     defaultConfigName = "Debug"; | 
 |   } | 
 |   for (auto& config : configs) { | 
 |     buildConfigurations->AddObject(config.second); | 
 |   } | 
 |   configlist->AddAttribute("buildConfigurations", buildConfigurations); | 
 |  | 
 |   std::string comment = cmStrCat("Build configuration list for PBXProject \"", | 
 |                                  this->CurrentProject, '"'); | 
 |   configlist->SetComment(comment); | 
 |   configlist->AddAttribute("defaultConfigurationIsVisible", | 
 |                            this->CreateString("0")); | 
 |   configlist->AddAttribute("defaultConfigurationName", | 
 |                            this->CreateString(defaultConfigName)); | 
 |   cmXCodeObject* buildSettings = | 
 |     this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); | 
 |   cmValue sysroot = this->CurrentMakefile->GetDefinition("CMAKE_OSX_SYSROOT"); | 
 |   cmValue deploymentTarget = | 
 |     this->CurrentMakefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET"); | 
 |   if (sysroot) { | 
 |     buildSettings->AddAttribute("SDKROOT", this->CreateString(*sysroot)); | 
 |   } | 
 |   // recompute this as it may have been changed since enable language | 
 |   this->ComputeArchitectures(this->CurrentMakefile); | 
 |   std::string const archs = cmJoin(this->Architectures, " "); | 
 |   if (archs.empty()) { | 
 |     // Tell Xcode to use NATIVE_ARCH instead of ARCHS. | 
 |     buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("YES")); | 
 |     // When targeting macOS, use only the host architecture. | 
 |     if (this->SystemName == "Darwin"_s && | 
 |         (!cmNonempty(sysroot) || | 
 |          cmSystemTools::LowerCase(*sysroot).find("macos") != | 
 |            std::string::npos)) { | 
 |       buildSettings->AddAttribute("ARCHS", | 
 |                                   this->CreateString("$(NATIVE_ARCH_ACTUAL)")); | 
 |     } | 
 |   } else { | 
 |     // Tell Xcode to use ARCHS (ONLY_ACTIVE_ARCH defaults to NO). | 
 |     buildSettings->AddAttribute("ARCHS", this->CreateString(archs)); | 
 |   } | 
 |   if (cmNonempty(deploymentTarget)) { | 
 |     buildSettings->AddAttribute(GetDeploymentPlatform(root->GetMakefile()), | 
 |                                 this->CreateString(*deploymentTarget)); | 
 |   } | 
 |   if (!this->GeneratorToolset.empty()) { | 
 |     buildSettings->AddAttribute("GCC_VERSION", | 
 |                                 this->CreateString(this->GeneratorToolset)); | 
 |   } | 
 |   if (this->GetLanguageEnabled("Swift")) { | 
 |     std::string swiftVersion; | 
 |     if (cmValue vers = this->CurrentMakefile->GetDefinition( | 
 |           "CMAKE_Swift_LANGUAGE_VERSION")) { | 
 |       swiftVersion = *vers; | 
 |     } else if (this->XcodeVersion >= 102) { | 
 |       swiftVersion = "4.0"; | 
 |     } else if (this->XcodeVersion >= 83) { | 
 |       swiftVersion = "3.0"; | 
 |     } else { | 
 |       swiftVersion = "2.3"; | 
 |     } | 
 |     buildSettings->AddAttribute("SWIFT_VERSION", | 
 |                                 this->CreateString(swiftVersion)); | 
 |   } | 
 |  | 
 |   std::string const symroot = this->GetSymrootDir(); | 
 |   buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot)); | 
 |  | 
 |   // Inside a try_compile project, do not require signing on any platform. | 
 |   if (this->CMakeInstance->GetIsInTryCompile()) { | 
 |     buildSettings->AddAttribute("CODE_SIGNING_ALLOWED", | 
 |                                 this->CreateString("NO")); | 
 |   } | 
 |  | 
 |   // This code supports the OLD behavior of CMP0157. We should be able to | 
 |   // remove computing the debug configuration set once the old behavior is | 
 |   // removed. | 
 |   auto debugConfigs = this->GetCMakeInstance()->GetDebugConfigs(); | 
 |   std::set<std::string> debugConfigSet(debugConfigs.begin(), | 
 |                                        debugConfigs.end()); | 
 |  | 
 |   for (auto& config : configs) { | 
 |     CreateGlobalXCConfigSettings(root, config.second, config.first); | 
 |  | 
 |     cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings); | 
 |  | 
 |     // Supports the OLD behavior of CMP0157. CMP0157 OLD behavior globally set | 
 |     // wholemodule compilation for all non-debug configurations, for all | 
 |     // targets. | 
 |     if (this->CurrentMakefile | 
 |           ->GetDefinition("CMAKE_Swift_COMPILATION_MODE_DEFAULT") | 
 |           .IsEmpty()) { | 
 |       if (debugConfigSet.count(cmSystemTools::UpperCase(config.first)) == 0) { | 
 |         buildSettingsForCfg->AddAttribute("SWIFT_COMPILATION_MODE", | 
 |                                           this->CreateString("wholemodule")); | 
 |       } | 
 |     } | 
 |  | 
 |     // Put this last so it can override existing settings | 
 |     // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly. | 
 |     for (auto const& var : this->CurrentMakefile->GetDefinitions()) { | 
 |       if (cmHasLiteralPrefix(var, "CMAKE_XCODE_ATTRIBUTE_")) { | 
 |         std::string attribute = var.substr(22); | 
 |         this->FilterConfigurationAttribute(config.first, attribute); | 
 |         if (!attribute.empty()) { | 
 |           std::string processed = cmGeneratorExpression::Evaluate( | 
 |             this->CurrentMakefile->GetSafeDefinition(var), | 
 |             this->CurrentLocalGenerator, config.first); | 
 |           buildSettingsForCfg->AddAttribute(attribute, | 
 |                                             this->CreateString(processed)); | 
 |         } | 
 |       } | 
 |     } | 
 |     // store per-config buildSettings into configuration object | 
 |     config.second->AddAttribute("buildSettings", buildSettingsForCfg); | 
 |   } | 
 |  | 
 |   this->RootObject->AddAttribute("buildConfigurationList", | 
 |                                  this->CreateObjectReference(configlist)); | 
 |  | 
 |   std::vector<cmXCodeObject*> targets; | 
 |   for (auto& generator : generators) { | 
 |     if (!this->CreateXCodeTargets(generator, targets)) { | 
 |       return false; | 
 |     } | 
 |     for (auto const& ccRoot : this->CustomCommandRoots) { | 
 |       if (ccRoot.second.size() > 1) { | 
 |         std::string e = "The custom command "; | 
 |         std::vector<std::string> const& outputs = | 
 |           ccRoot.first->GetCustomCommand()->GetOutputs(); | 
 |         if (!outputs.empty()) { | 
 |           e = cmStrCat(e, "generating\n  ", outputs[0]); | 
 |         } else { | 
 |           e = cmStrCat(e, "driven by\n  ", ccRoot.first->GetFullPath()); | 
 |         } | 
 |         e = cmStrCat(e, "\nis attached to multiple targets:"); | 
 |         for (cmGeneratorTarget const* gt : ccRoot.second) { | 
 |           e = cmStrCat(e, "\n  ", gt->GetName()); | 
 |         } | 
 |         e = cmStrCat( | 
 |           e, | 
 |           "\nbut none of these is a common dependency of the other(s).  " | 
 |           "This is not allowed by the Xcode \"new build system\"."); | 
 |         generator->IssueMessage(MessageType::FATAL_ERROR, e); | 
 |         return false; | 
 |       } | 
 |     } | 
 |     this->CustomCommandRoots.clear(); | 
 |   } | 
 |   // loop over all targets and add link and depend info | 
 |   for (auto* t : targets) { | 
 |     this->AddDependAndLinkInformation(t); | 
 |     this->AddEmbeddedFrameworks(t); | 
 |     this->AddEmbeddedPlugIns(t); | 
 |     this->AddEmbeddedAppExtensions(t); | 
 |     this->AddEmbeddedExtensionKitExtensions(t); | 
 |     this->AddEmbeddedResources(t); | 
 |     this->AddEmbeddedXPCServices(t); | 
 |     // Inherit project-wide values for any target-specific search paths. | 
 |     this->InheritBuildSettingAttribute(t, "HEADER_SEARCH_PATHS"); | 
 |     this->InheritBuildSettingAttribute(t, "SYSTEM_HEADER_SEARCH_PATHS"); | 
 |     this->InheritBuildSettingAttribute(t, "FRAMEWORK_SEARCH_PATHS"); | 
 |     this->InheritBuildSettingAttribute(t, "SYSTEM_FRAMEWORK_SEARCH_PATHS"); | 
 |     this->InheritBuildSettingAttribute(t, "LIBRARY_SEARCH_PATHS"); | 
 |     this->InheritBuildSettingAttribute(t, "LD_RUNPATH_SEARCH_PATHS"); | 
 |     this->InheritBuildSettingAttribute(t, "GCC_PREPROCESSOR_DEFINITIONS"); | 
 |     this->InheritBuildSettingAttribute(t, "OTHER_CFLAGS"); | 
 |     this->InheritBuildSettingAttribute(t, "OTHER_LDFLAGS"); | 
 |     this->InheritBuildSettingAttribute(t, "OTHER_SWIFT_FLAGS"); | 
 |     this->InheritBuildSettingAttribute(t, | 
 |                                        "SWIFT_ACTIVE_COMPILATION_CONDITIONS"); | 
 |   } | 
 |  | 
 |   if (this->XcodeBuildSystem == BuildSystem::One) { | 
 |     this->CreateXCodeDependHackMakefile(targets); | 
 |   } | 
 |   // now add all targets to the root object | 
 |   cmXCodeObject* allTargets = this->CreateObject(cmXCodeObject::OBJECT_LIST); | 
 |   for (auto* t : targets) { | 
 |     allTargets->AddObject(t); | 
 |     cmXCodeObject* productRef = t->GetAttribute("productReference"); | 
 |     if (productRef) { | 
 |       productGroupChildren->AddObject(productRef->GetObject()); | 
 |     } | 
 |   } | 
 |   this->RootObject->AddAttribute("targets", allTargets); | 
 |   return true; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::GetSymrootDir() const | 
 | { | 
 |   return cmStrCat(this->CMakeInstance->GetHomeOutputDirectory(), "/build"); | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::GetTargetTempDir( | 
 |   cmGeneratorTarget const* gt, std::string const& configName) const | 
 | { | 
 |   // Use a path inside the SYMROOT. | 
 |   return cmStrCat(this->GetSymrootDir(), '/', gt->GetName(), ".build/", | 
 |                   configName); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf) | 
 | { | 
 |   this->Architectures.clear(); | 
 |   cmList::append(this->Architectures, | 
 |                  mf->GetDefinition("CMAKE_OSX_ARCHITECTURES")); | 
 |  | 
 |   if (this->Architectures.empty()) { | 
 |     cmList::append(this->Architectures, | 
 |                    mf->GetDefinition("_CMAKE_APPLE_ARCHS_DEFAULT")); | 
 |   } | 
 |  | 
 |   if (this->Architectures.empty()) { | 
 |     // With no ARCHS we use ONLY_ACTIVE_ARCH and possibly a | 
 |     // platform-specific default ARCHS placeholder value. | 
 |     // Look up the arch that Xcode chooses in this case. | 
 |     if (cmValue arch = mf->GetDefinition("CMAKE_XCODE_ARCHS")) { | 
 |       this->ObjectDirArchDefault = *arch; | 
 |       // We expect only one arch but choose the first just in case. | 
 |       std::string::size_type pos = this->ObjectDirArchDefault.find(';'); | 
 |       if (pos != std::string::npos) { | 
 |         this->ObjectDirArchDefault = this->ObjectDirArchDefault.substr(0, pos); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   this->ComputeObjectDirArch(mf); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::ComputeObjectDirArch(cmMakefile* mf) | 
 | { | 
 |   if (this->Architectures.size() > 1 || this->UseEffectivePlatformName(mf)) { | 
 |     this->ObjectDirArch = "$(CURRENT_ARCH)"; | 
 |   } else if (!this->Architectures.empty()) { | 
 |     this->ObjectDirArch = this->Architectures[0]; | 
 |   } else { | 
 |     this->ObjectDirArch = this->ObjectDirArchDefault; | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::CreateXCodeDependHackMakefile( | 
 |   std::vector<cmXCodeObject*>& targets) | 
 | { | 
 |   cmGeneratedFileStream makefileStream(this->CurrentXCodeHackMakefile); | 
 |   if (!makefileStream) { | 
 |     cmSystemTools::Error( | 
 |       cmStrCat("Could not create ", this->CurrentXCodeHackMakefile)); | 
 |     return; | 
 |   } | 
 |   makefileStream.SetCopyIfDifferent(true); | 
 |   // one more pass for external depend information not handled | 
 |   // correctly by xcode | 
 |   /* clang-format off */ | 
 |   makefileStream << "# DO NOT EDIT\n" | 
 |                     "# This makefile makes sure all linkable targets are\n" | 
 |                     "# up-to-date with anything they link to\n" | 
 |     "default:\n" | 
 |     "\techo \"Do not invoke directly\"\n" | 
 |     "\n"; | 
 |   /* clang-format on */ | 
 |  | 
 |   std::set<std::string> dummyRules; | 
 |  | 
 |   // Write rules to help Xcode relink things at the right time. | 
 |   /* clang-format off */ | 
 |   makefileStream << | 
 |     "# Rules to remove targets that are older than anything to which they\n" | 
 |     "# link.  This forces Xcode to relink the targets from scratch.  It\n" | 
 |     "# does not seem to check these dependencies itself.\n"; | 
 |   /* clang-format on */ | 
 |   for (auto const& configName : this->CurrentConfigurationTypes) { | 
 |     for (auto* target : targets) { | 
 |       cmGeneratorTarget* gt = target->GetTarget(); | 
 |  | 
 |       if (gt->GetType() == cmStateEnums::EXECUTABLE || | 
 |           gt->GetType() == cmStateEnums::OBJECT_LIBRARY || | 
 |           gt->GetType() == cmStateEnums::STATIC_LIBRARY || | 
 |           gt->GetType() == cmStateEnums::SHARED_LIBRARY || | 
 |           gt->GetType() == cmStateEnums::MODULE_LIBRARY) { | 
 |         // Declare an entry point for the target post-build phase. | 
 |         makefileStream << this->PostBuildMakeTarget(gt->GetName(), configName) | 
 |                        << ":\n"; | 
 |       } | 
 |  | 
 |       if (gt->GetType() == cmStateEnums::EXECUTABLE || | 
 |           gt->GetType() == cmStateEnums::STATIC_LIBRARY || | 
 |           gt->GetType() == cmStateEnums::SHARED_LIBRARY || | 
 |           gt->GetType() == cmStateEnums::MODULE_LIBRARY) { | 
 |         std::string tfull = gt->GetFullPath(configName); | 
 |         std::string trel = ConvertToMakefilePath(tfull); | 
 |  | 
 |         // Add this target to the post-build phases of its dependencies. | 
 |         auto const y = target->GetDependTargets().find(configName); | 
 |         if (y != target->GetDependTargets().end()) { | 
 |           for (auto const& deptgt : y->second) { | 
 |             makefileStream << this->PostBuildMakeTarget(deptgt, configName) | 
 |                            << ": " << trel << '\n'; | 
 |           } | 
 |         } | 
 |  | 
 |         std::vector<cmGeneratorTarget*> objlibs; | 
 |         gt->GetObjectLibrariesInSources(objlibs); | 
 |         for (auto* objLib : objlibs) { | 
 |           makefileStream << this->PostBuildMakeTarget(objLib->GetName(), | 
 |                                                       configName) | 
 |                          << ": " << trel << '\n'; | 
 |         } | 
 |  | 
 |         // Create a rule for this target. | 
 |         makefileStream << trel << ':'; | 
 |  | 
 |         // List dependencies if any exist. | 
 |         auto const x = target->GetDependLibraries().find(configName); | 
 |         if (x != target->GetDependLibraries().end()) { | 
 |           for (auto const& deplib : x->second) { | 
 |             std::string file = ConvertToMakefilePath(deplib); | 
 |             makefileStream << "\\\n\t" << file; | 
 |             dummyRules.insert(file); | 
 |           } | 
 |         } | 
 |  | 
 |         for (auto* objLib : objlibs) { | 
 |  | 
 |           std::string const objLibName = objLib->GetName(); | 
 |           std::string d = cmStrCat(this->GetTargetTempDir(gt, configName), | 
 |                                    "/lib", objLibName, ".a"); | 
 |  | 
 |           std::string dependency = ConvertToMakefilePath(d); | 
 |           makefileStream << "\\\n\t" << dependency; | 
 |           dummyRules.insert(dependency); | 
 |         } | 
 |  | 
 |         // Write the action to remove the target if it is out of date. | 
 |         makefileStream << "\n" | 
 |                           "\t/bin/rm -f " | 
 |                        << ConvertToMakefilePath(tfull) << '\n'; | 
 |         // if building for more than one architecture | 
 |         // then remove those executables as well | 
 |         if (this->Architectures.size() > 1) { | 
 |           std::string universal = | 
 |             cmStrCat(this->GetTargetTempDir(gt, configName), "/$(OBJDIR)/"); | 
 |           for (auto const& architecture : this->Architectures) { | 
 |             std::string universalFile = cmStrCat(universal, architecture, '/', | 
 |                                                  gt->GetFullName(configName)); | 
 |             makefileStream << "\t/bin/rm -f " | 
 |                            << ConvertToMakefilePath(universalFile) << '\n'; | 
 |           } | 
 |         } | 
 |         makefileStream << "\n\n"; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   makefileStream << "\n\n" | 
 |                     "# For each target create a dummy rule" | 
 |                     "so the target does not have to exist\n"; | 
 |   for (auto const& dummyRule : dummyRules) { | 
 |     makefileStream << dummyRule << ":\n"; | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::OutputXCodeProject( | 
 |   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators) | 
 | { | 
 |   if (generators.empty()) { | 
 |     return; | 
 |   } | 
 |   if (!this->CreateXCodeObjects(root, generators)) { | 
 |     return; | 
 |   } | 
 |   std::string xcodeDir = cmStrCat(root->GetCurrentBinaryDirectory(), '/', | 
 |                                   root->GetProjectName(), ".xcodeproj"); | 
 |   cmSystemTools::MakeDirectory(xcodeDir); | 
 |   std::string xcodeProjFile = cmStrCat(xcodeDir, "/project.pbxproj"); | 
 |   cmGeneratedFileStream fout(xcodeProjFile); | 
 |   fout.SetCopyIfDifferent(true); | 
 |   if (!fout) { | 
 |     return; | 
 |   } | 
 |   this->WriteXCodePBXProj(fout, root, generators); | 
 |  | 
 |   bool hasGeneratedSchemes = this->OutputXCodeSharedSchemes(xcodeDir, root); | 
 |   this->OutputXCodeWorkspaceSettings(xcodeDir, hasGeneratedSchemes); | 
 |  | 
 |   this->ClearXCodeObjects(); | 
 |  | 
 |   // Since this call may have created new cache entries, save the cache: | 
 |   // | 
 |   root->GetMakefile()->GetCMakeInstance()->SaveCache( | 
 |     root->GetBinaryDirectory()); | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::OutputXCodeSharedSchemes( | 
 |   std::string const& xcProjDir, cmLocalGenerator* root) | 
 | { | 
 |   // collect all tests for the targets | 
 |   std::map<std::string, cmXCodeScheme::TestObjects> testables; | 
 |  | 
 |   for (auto const& obj : this->XCodeObjects) { | 
 |     if (obj->GetType() != cmXCodeObject::OBJECT || | 
 |         obj->GetIsA() != cmXCodeObject::PBXNativeTarget) { | 
 |       continue; | 
 |     } | 
 |  | 
 |     if (!obj->GetTarget()->IsXCTestOnApple()) { | 
 |       continue; | 
 |     } | 
 |  | 
 |     cmValue testee = obj->GetTarget()->GetProperty("XCTEST_TESTEE"); | 
 |     if (!testee) { | 
 |       continue; | 
 |     } | 
 |  | 
 |     testables[*testee].push_back(obj.get()); | 
 |   } | 
 |  | 
 |   // generate scheme | 
 |   bool ret = false; | 
 |  | 
 |   // Since the lowest available Xcode version for testing was 6.4, | 
 |   // I'm setting this as a limit then | 
 |   if (this->XcodeVersion >= 64) { | 
 |     for (auto const& obj : this->XCodeObjects) { | 
 |       if (obj->GetType() == cmXCodeObject::OBJECT && | 
 |           (obj->GetIsA() == cmXCodeObject::PBXNativeTarget || | 
 |            obj->GetIsA() == cmXCodeObject::PBXAggregateTarget) && | 
 |           (root->GetMakefile()->GetCMakeInstance()->GetIsInTryCompile() || | 
 |            obj->GetTarget()->GetPropertyAsBool("XCODE_GENERATE_SCHEME"))) { | 
 |         std::string const& targetName = obj->GetTarget()->GetName(); | 
 |         cmXCodeScheme schm(root, obj.get(), testables[targetName], | 
 |                            this->CurrentConfigurationTypes, | 
 |                            this->XcodeVersion); | 
 |         schm.WriteXCodeSharedScheme(xcProjDir, | 
 |                                     this->RelativeToSource(xcProjDir)); | 
 |         ret = true; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   return ret; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::OutputXCodeWorkspaceSettings( | 
 |   std::string const& xcProjDir, bool hasGeneratedSchemes) | 
 | { | 
 |   std::string xcodeSharedDataDir = | 
 |     cmStrCat(xcProjDir, "/project.xcworkspace/xcshareddata"); | 
 |   cmSystemTools::MakeDirectory(xcodeSharedDataDir); | 
 |  | 
 |   std::string workspaceSettingsFile = | 
 |     cmStrCat(xcodeSharedDataDir, "/WorkspaceSettings.xcsettings"); | 
 |  | 
 |   cmGeneratedFileStream fout(workspaceSettingsFile); | 
 |   fout.SetCopyIfDifferent(true); | 
 |   if (!fout) { | 
 |     return; | 
 |   } | 
 |  | 
 |   cmXMLWriter xout(fout); | 
 |   xout.StartDocument(); | 
 |   xout.Doctype("plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\"" | 
 |                "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\""); | 
 |   xout.StartElement("plist"); | 
 |   xout.Attribute("version", "1.0"); | 
 |   xout.StartElement("dict"); | 
 |   if (this->XcodeVersion >= 100) { | 
 |     xout.Element("key", "BuildSystemType"); | 
 |     switch (this->XcodeBuildSystem) { | 
 |       case BuildSystem::One: | 
 |         xout.Element("string", "Original"); | 
 |         if (this->XcodeVersion >= 130) { | 
 |           xout.Element("key", "DisableBuildSystemDeprecationDiagnostic"); | 
 |         } else { | 
 |           xout.Element("key", "DisableBuildSystemDeprecationWarning"); | 
 |         } | 
 |         xout.Element("true"); | 
 |         break; | 
 |       case BuildSystem::Twelve: | 
 |         xout.Element("string", "Latest"); | 
 |         break; | 
 |     } | 
 |   } | 
 |   if (hasGeneratedSchemes) { | 
 |     xout.Element("key", | 
 |                  "IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded"); | 
 |     xout.Element("false"); | 
 |   } | 
 |   xout.EndElement(); // dict | 
 |   xout.EndElement(); // plist | 
 |   xout.EndDocument(); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::WriteXCodePBXProj(std::ostream& fout, | 
 |                                                cmLocalGenerator*, | 
 |                                                std::vector<cmLocalGenerator*>&) | 
 | { | 
 |   SortXCodeObjects(); | 
 |  | 
 |   fout << "// !$*UTF8*$!\n" | 
 |           "{\n"; | 
 |   cmXCodeObject::Indent(1, fout); | 
 |   fout << "archiveVersion = 1;\n"; | 
 |   cmXCodeObject::Indent(1, fout); | 
 |   fout << "classes = {\n"; | 
 |   cmXCodeObject::Indent(1, fout); | 
 |   fout << "};\n"; | 
 |   cmXCodeObject::Indent(1, fout); | 
 |   fout << "objectVersion = 46;\n"; | 
 |   cmXCode21Object::PrintList(this->XCodeObjects, fout); | 
 |   cmXCodeObject::Indent(1, fout); | 
 |   fout << "rootObject = " << this->RootObject->GetId() | 
 |        << " /* Project object */;\n" | 
 |           "}\n"; | 
 | } | 
 |  | 
 | char const* cmGlobalXCodeGenerator::GetCMakeCFGIntDir() const | 
 | { | 
 |   return "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::ExpandCFGIntDir( | 
 |   std::string const& str, std::string const& config) const | 
 | { | 
 |   std::string replace1 = "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"; | 
 |   std::string replace2 = "$(CONFIGURATION)"; | 
 |  | 
 |   std::string tmp = str; | 
 |   for (std::string::size_type i = tmp.find(replace1); i != std::string::npos; | 
 |        i = tmp.find(replace1, i)) { | 
 |     tmp.replace(i, replace1.size(), config); | 
 |     i += config.size(); | 
 |   } | 
 |   for (std::string::size_type i = tmp.find(replace2); i != std::string::npos; | 
 |        i = tmp.find(replace2, i)) { | 
 |     tmp.replace(i, replace2.size(), config); | 
 |     i += config.size(); | 
 |   } | 
 |   return tmp; | 
 | } | 
 |  | 
 | cmDocumentationEntry cmGlobalXCodeGenerator::GetDocumentation() | 
 | { | 
 |   return { cmGlobalXCodeGenerator::GetActualName(), | 
 |            "Generate Xcode project files." }; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::RelativeToSource(std::string const& p) | 
 | { | 
 |   std::string const& rootSrc = | 
 |     this->CurrentRootGenerator->GetCurrentSourceDirectory(); | 
 |   if (cmSystemTools::IsSubDirectory(p, rootSrc)) { | 
 |     return cmSystemTools::ForceToRelativePath(rootSrc, p); | 
 |   } | 
 |   return p; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::RelativeToRootBinary(std::string const& p) | 
 | { | 
 |   std::string binaryDirectory = | 
 |     this->CurrentRootGenerator->GetCurrentBinaryDirectory(); | 
 |   if (cmSystemTools::IsSubDirectory(p, binaryDirectory)) { | 
 |     binaryDirectory = cmSystemTools::ForceToRelativePath(binaryDirectory, p); | 
 |   } | 
 |  | 
 |   return binaryDirectory; | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::RelativeToBinary(std::string const& p) | 
 | { | 
 |   return this->CurrentRootGenerator->MaybeRelativeToCurBinDir(p); | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::XCodeEscapePath(std::string const& p) | 
 | { | 
 |   if (p.find_first_of(" []") != std::string::npos) { | 
 |     std::string t = cmStrCat('"', p, '"'); | 
 |     return t; | 
 |   } | 
 |   return p; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AppendDirectoryForConfig( | 
 |   std::string const& prefix, std::string const& config, | 
 |   std::string const& suffix, std::string& dir) | 
 | { | 
 |   if (!config.empty()) { | 
 |     dir += prefix; | 
 |     dir += config; | 
 |     dir += suffix; | 
 |   } | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::LookupFlags( | 
 |   std::string const& varNamePrefix, std::string const& varNameLang, | 
 |   std::string const& varNameSuffix, cmGeneratorTarget const* gt) | 
 | { | 
 |   std::string flags; | 
 |   if (!varNameLang.empty()) { | 
 |     std::string varName = cmStrCat(varNamePrefix, varNameLang, varNameSuffix); | 
 |     if (cmValue varValue = this->CurrentMakefile->GetDefinition(varName)) { | 
 |       if (!varValue->empty()) { | 
 |         this->CurrentLocalGenerator->AppendFlags( | 
 |           flags, *varValue, varName, gt, cmBuildStep::Link, varNameLang); | 
 |       } | 
 |     } | 
 |   } | 
 |   return flags; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs, | 
 |                                            char const* defines_list, | 
 |                                            bool dflag) | 
 | { | 
 |   // Skip this if there are no definitions. | 
 |   if (!defines_list) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // Expand the list of definitions. | 
 |   cmList defines{ defines_list }; | 
 |  | 
 |   // Store the definitions in the string. | 
 |   this->AppendDefines(defs, defines, dflag); | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AppendDefines( | 
 |   BuildObjectListOrString& defs, std::vector<std::string> const& defines, | 
 |   bool dflag) | 
 | { | 
 |   // GCC_PREPROCESSOR_DEFINITIONS is a space-separated list of definitions. | 
 |   std::string def; | 
 |   for (auto const& define : defines) { | 
 |     // Start with -D if requested. | 
 |     if (dflag && !cmHasLiteralPrefix(define, "-D")) { | 
 |       def = cmStrCat("-D", define); | 
 |     } else if (!dflag && cmHasLiteralPrefix(define, "-D")) { | 
 |       def = define.substr(2); | 
 |     } else { | 
 |       def = define; | 
 |     } | 
 |  | 
 |     // Append the flag with needed escapes. | 
 |     std::string tmp; | 
 |     this->AppendFlag(tmp, def); | 
 |     defs.Add(tmp); | 
 |   } | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::AppendFlag(std::string& flags, | 
 |                                         std::string const& flag) const | 
 | { | 
 |   // Short-circuit for an empty flag. | 
 |   if (flag.empty()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // Separate from previous flags. | 
 |   if (!flags.empty()) { | 
 |     flags += ' '; | 
 |   } | 
 |  | 
 |   // Check if the flag needs quoting. | 
 |   bool quoteFlag = | 
 |     flag.find_first_of("`~!@#$%^&*()+={}[]|:;\"'<>,.? ") != std::string::npos; | 
 |  | 
 |   // We escape a flag as follows: | 
 |   //   - Place each flag in single quotes '' | 
 |   //   - Escape a single quote as \' | 
 |   //   - Escape a backslash as \\ since it itself is an escape | 
 |   // Note that in the code below we need one more level of escapes for | 
 |   // C string syntax in this source file. | 
 |   // | 
 |   // The final level of escaping is done when the string is stored | 
 |   // into the project file by cmXCodeObject::PrintString. | 
 |  | 
 |   if (quoteFlag) { | 
 |     // Open single quote. | 
 |     flags += '\''; | 
 |   } | 
 |  | 
 |   // Flag value with escaped quotes and backslashes. | 
 |   for (auto c : flag) { | 
 |     if (c == '\'') { | 
 |       flags += "'\\''"; | 
 |     } else if (c == '\\') { | 
 |       flags += "\\\\"; | 
 |     } else { | 
 |       flags += c; | 
 |     } | 
 |   } | 
 |  | 
 |   if (quoteFlag) { | 
 |     // Close single quote. | 
 |     flags += '\''; | 
 |   } | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::ComputeInfoPListLocation( | 
 |   cmGeneratorTarget* target) | 
 | { | 
 |   std::string plist = cmStrCat(target->GetSupportDirectory(), "/Info.plist"); | 
 |   return plist; | 
 | } | 
 |  | 
 | // Return true if the generated build tree may contain multiple builds. | 
 | // i.e. "Can I build Debug and Release in the same tree?" | 
 | bool cmGlobalXCodeGenerator::IsMultiConfig() const | 
 | { | 
 |   // Newer Xcode versions are multi config: | 
 |   return true; | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation( | 
 |   cmTarget const& target, std::string* reason) const | 
 | { | 
 |   auto objectDirArch = GetTargetObjectDirArch(target, this->ObjectDirArch); | 
 |  | 
 |   if (objectDirArch.find('$') != std::string::npos) { | 
 |     if (reason != nullptr) { | 
 |       *reason = " under Xcode with multiple architectures"; | 
 |     } | 
 |     return false; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const | 
 | { | 
 |   cmValue epnValue = this->GetCMakeInstance()->GetState()->GetGlobalProperty( | 
 |     "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME"); | 
 |  | 
 |   if (!epnValue) { | 
 |     return mf->PlatformIsAppleEmbedded(); | 
 |   } | 
 |  | 
 |   return epnValue.IsOn(); | 
 | } | 
 |  | 
 | bool cmGlobalXCodeGenerator::ShouldStripResourcePath(cmMakefile*) const | 
 | { | 
 |   // Xcode determines Resource location itself | 
 |   return true; | 
 | } | 
 |  | 
 | void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory( | 
 |   cmGeneratorTarget* gt) const | 
 | { | 
 |   auto objectDirArch = GetTargetObjectDirArch(*gt, this->ObjectDirArch); | 
 |   gt->ObjectDirectory = | 
 |     cmStrCat(this->GetTargetTempDir(gt, this->GetCMakeCFGIntDir()), | 
 |              "/$(OBJECT_FILE_DIR_normal:base)/", objectDirArch, '/'); | 
 | } | 
 |  | 
 | std::string cmGlobalXCodeGenerator::GetDeploymentPlatform(cmMakefile const* mf) | 
 | { | 
 |   switch (mf->GetAppleSDKType()) { | 
 |     case cmMakefile::AppleSDK::AppleTVOS: | 
 |     case cmMakefile::AppleSDK::AppleTVSimulator: | 
 |       return "TVOS_DEPLOYMENT_TARGET"; | 
 |  | 
 |     case cmMakefile::AppleSDK::IPhoneOS: | 
 |     case cmMakefile::AppleSDK::IPhoneSimulator: | 
 |       return "IPHONEOS_DEPLOYMENT_TARGET"; | 
 |  | 
 |     case cmMakefile::AppleSDK::WatchOS: | 
 |     case cmMakefile::AppleSDK::WatchSimulator: | 
 |       return "WATCHOS_DEPLOYMENT_TARGET"; | 
 |  | 
 |     case cmMakefile::AppleSDK::XROS: | 
 |     case cmMakefile::AppleSDK::XRSimulator: | 
 |       return "XROS_DEPLOYMENT_TARGET"; | 
 |  | 
 |     case cmMakefile::AppleSDK::MacOS: | 
 |     default: | 
 |       return "MACOSX_DEPLOYMENT_TARGET"; | 
 |   } | 
 | } | 
 |  | 
 | cmValue cmGlobalXCodeGenerator::GetDebuggerWorkingDirectory( | 
 |   cmGeneratorTarget* gt) const | 
 | { | 
 |   if (cmValue ret = gt->GetProperty("XCODE_SCHEME_WORKING_DIRECTORY")) { | 
 |     return ret; | 
 |   } | 
 |   return cmGlobalGenerator::GetDebuggerWorkingDirectory(gt); | 
 | } |