/// <summary> /// Appends a build configuration list section for specific target. /// </summary> /// <param name="Contents">StringBuilder object to append build configuration list string to</param> /// <param name="Target">Target for which we generate the build configuration list</param> private void AppendConfigList(ref StringBuilder Contents, XcodeProjectTarget Target) { string TargetType = IsXcodeTargetTypeNative(Target.Type) ? "Native" : Target.Type.ToString(); string TypeName = Target.Type == XcodeTargetType.Project ? "PBXProject" : "PBX" + TargetType + "Target"; if (!bGeneratingRocketProjectFiles) { Contents.Append( "\t\t" + Target.BuildConfigGuild + " /* Build configuration list for " + TypeName + " \"" + Target.DisplayName + "\" */ = {" + ProjectFileGenerator.NewLine + "\t\t\tisa = XCConfigurationList;" + ProjectFileGenerator.NewLine + "\t\t\tbuildConfigurations = (" + ProjectFileGenerator.NewLine + "\t\t\t\t" + Target.DebugConfigGuid + " /* Debug */," + ProjectFileGenerator.NewLine + "\t\t\t\t" + Target.DebugGameConfigGuid + " /* DebugGame */," + ProjectFileGenerator.NewLine + "\t\t\t\t" + Target.DevelopmentConfigGuid + " /* Development */," + ProjectFileGenerator.NewLine + "\t\t\t\t" + Target.ShippingConfigGuid + " /* Shipping */," + ProjectFileGenerator.NewLine + "\t\t\t\t" + Target.TestConfigGuid + " /* Test */," + ProjectFileGenerator.NewLine + "\t\t\t);" + ProjectFileGenerator.NewLine + "\t\t\tdefaultConfigurationIsVisible = 0;" + ProjectFileGenerator.NewLine + "\t\t\tdefaultConfigurationName = Development;" + ProjectFileGenerator.NewLine + "\t\t};" + ProjectFileGenerator.NewLine); } else { Contents.Append( "\t\t" + Target.BuildConfigGuild + " /* Build configuration list for " + TypeName + " \"" + Target.DisplayName + "\" */ = {" + ProjectFileGenerator.NewLine + "\t\t\tisa = XCConfigurationList;" + ProjectFileGenerator.NewLine + "\t\t\tbuildConfigurations = (" + ProjectFileGenerator.NewLine + "\t\t\t\t" + Target.DebugGameConfigGuid + " /* DebugGame */," + ProjectFileGenerator.NewLine + "\t\t\t\t" + Target.DevelopmentConfigGuid + " /* Development */," + ProjectFileGenerator.NewLine + "\t\t\t\t" + Target.ShippingConfigGuid + " /* Shipping */," + ProjectFileGenerator.NewLine + "\t\t\t);" + ProjectFileGenerator.NewLine + "\t\t\tdefaultConfigurationIsVisible = 0;" + ProjectFileGenerator.NewLine + "\t\t\tdefaultConfigurationName = Development;" + ProjectFileGenerator.NewLine + "\t\t};" + ProjectFileGenerator.NewLine); } }
/// <summary> /// Writes the project files to disk /// </summary> /// <returns>True if successful</returns> protected override bool WriteProjectFiles() { Log.TraceInformation("Generating project file..."); // Setup project file content var XcodeProjectFileContent = new StringBuilder(); XcodeProjectFileContent.Append( "// !$*UTF8*$!" + ProjectFileGenerator.NewLine + "{" + ProjectFileGenerator.NewLine + "\tarchiveVersion = 1;" + ProjectFileGenerator.NewLine + "\tclasses = {" + ProjectFileGenerator.NewLine + "\t};" + ProjectFileGenerator.NewLine + "\tobjectVersion = 46;" + ProjectFileGenerator.NewLine + "\tobjects = {" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine); // attempt to determine targets for the project List<XcodeProjectTarget> ProjectTargets = new List<XcodeProjectTarget>(); // add mandatory ones XcodeProjectTarget UE4ProjectTarget = new XcodeProjectTarget("UE4", "UE4", XcodeTargetType.Project, ""); XcodeProjectTarget UE4XcodeHelperTarget = new XcodeProjectTarget("UE4XcodeHelper", "UE4XcodeHelper", XcodeTargetType.XcodeHelper, "", "libUE4XcodeHelper.a"); ProjectTargets.AddRange(new XcodeProjectTarget[] { UE4ProjectTarget, UE4XcodeHelperTarget }); if (ProjectFilePlatform.HasFlag(XcodeProjectFilePlatform.iOS)) { XcodeProjectTarget UE4CmdLineRunTarget = new XcodeProjectTarget("UE4CmdLineRun", "UE4CmdLineRun", XcodeTargetType.XCTest, "", "UE4CmdLineRun.xctest", STTargetPlatform.IOS); ProjectTargets.Add(UE4CmdLineRunTarget); // This GUID will be referenced by each app's test action. UE4CmdLineGuid = UE4CmdLineRunTarget.Guid; } List<XcodeTargetDependency> TargetDependencies = new List<XcodeTargetDependency>(); List<XcodeContainerItemProxy> ContainerItemProxies = new List<XcodeContainerItemProxy>(); List<XcodeFramework> Frameworks = new List<XcodeFramework>(); Frameworks.Add(new XcodeFramework("OpenGLES.framework", "System/Library/Frameworks/OpenGLES.framework", "SDKROOT")); // @todo metal: putting this into the project will make for VERY slow Metal runtime by default... // Frameworks.Add(new XcodeFramework("Metal.framework", "System/Library/Frameworks/Metal.framework", "SDKROOT")); XcodeFramework XCTestFramework = new XcodeFramework("XCTest.framework", "Library/Frameworks/XCTest.framework", "DEVELOPER_DIR"); Frameworks.Add(XCTestFramework); var AllTargets = DiscoverTargets(); PopulateTargets(AllTargets, ProjectTargets, ContainerItemProxies, TargetDependencies, UE4ProjectTarget, Frameworks); Log.TraceInformation(string.Format("Found {0} targets!", ProjectTargets.Count)); string PBXBuildFileSection = "/* Begin PBXBuildFile section */" + ProjectFileGenerator.NewLine; string PBXFileReferenceSection = "/* Begin PBXFileReference section */" + ProjectFileGenerator.NewLine; string PBXResourcesBuildPhaseSection = "/* Begin PBXResourcesBuildPhase section */" + ProjectFileGenerator.NewLine; string PBXSourcesBuildPhaseSection = "/* Begin PBXSourcesBuildPhase section */" + ProjectFileGenerator.NewLine; string PBXFrameworksBuildPhaseSection = "/* Begin PBXFrameworksBuildPhase section */" + ProjectFileGenerator.NewLine; string PBXShellScriptBuildPhaseSection = "/* Begin PBXShellScriptBuildPhase section */" + ProjectFileGenerator.NewLine; Dictionary<string, XcodeFileGroup> Groups = new Dictionary<string, XcodeFileGroup>(); List<string> IncludeDirectories = new List<string>(); List<string> SystemIncludeDirectories = new List<string>(); List<string> PreprocessorDefinitions = new List<string>(); foreach (XcodeFramework Framework in Frameworks) { // Add file references. PBXFileReferenceSection += "\t\t" + Framework.Guid + " /* " + Framework.Name + " */ = {" + "isa = PBXFileReference; " + "lastKnownFileType = wrapper.framework; " + "name = " + Framework.Name + "; " + "path = " + Framework.Path + "; " + "sourceTree = " + Framework.SourceTree + "; " + "};" + ProjectFileGenerator.NewLine; } // Set up all the test guids that need to be explicitly referenced later string UE4CmdLineRunMFileGuid = MakeXcodeGuid(); UE4CmdLineRunMFileRefGuid = MakeXcodeGuid(); string XCTestBuildFileGUID = MakeXcodeGuid(); string TestFrameworkFiles = "\t\t\t\t" + XCTestBuildFileGUID + " /* XCTest.framework in Frameworks */," + ProjectFileGenerator.NewLine; PBXBuildFileSection += "\t\t" + XCTestBuildFileGUID + " /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; " + "fileRef = " + XCTestFramework.Guid + " /* UE4CmdLineRun.m */; };" + ProjectFileGenerator.NewLine; AppendBuildPhases(ProjectTargets, ref PBXBuildFileSection, ref PBXFileReferenceSection, ref PBXSourcesBuildPhaseSection, ref PBXResourcesBuildPhaseSection, ref PBXFrameworksBuildPhaseSection, ref PBXShellScriptBuildPhaseSection, TestFrameworkFiles, UE4CmdLineRunMFileGuid); AppendSourceFiles(ProjectTargets, ref PBXBuildFileSection, ref PBXFileReferenceSection, ref PBXSourcesBuildPhaseSection, ref Groups, UE4XcodeHelperTarget, UE4CmdLineRunMFileGuid, ref IncludeDirectories, ref SystemIncludeDirectories, ref PreprocessorDefinitions); foreach (XcodeProjectTarget Target in ProjectTargets) { if ((Target.Type == XcodeTargetType.Native || Target.Type == XcodeTargetType.XCTest)) { string FileType = Target.Type == XcodeTargetType.Native ? "wrapper.application" : "wrapper.cfbundle"; string PayloadDir = "Engine"; if (Target.Type == XcodeTargetType.Native && Target.TargetName != "UE4Game") { PayloadDir = Target.TargetName; } PBXFileReferenceSection += "\t\t" + Target.ProductGuid + " /* " + Target.ProductName + " */ = {isa = PBXFileReference; explicitFileType = " + FileType + "; includeInIndex = 0; path = " + PayloadDir + "/Binaries/IOS/Payload/" + Target.ProductName + "; sourceTree = \"<group>\"; };" + ProjectFileGenerator.NewLine; if (!string.IsNullOrEmpty(Target.PlistGuid)) { PBXFileReferenceSection += "\t\t" + Target.PlistGuid + " /* " + Target.TargetName + "-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = \"" + Target.TargetName + "-Info.plist\"; path = " + Target.TargetName + "/Build/IOS/" + Target.TargetName + "-Info.plist; sourceTree = \"<group>\"; };" + ProjectFileGenerator.NewLine; } } } if (bGeneratingRunIOSProject) { AppendReferenceGroups(ref PBXFileReferenceSection, ref Groups); } PBXBuildFileSection += "/* End PBXBuildFile section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine; PBXFileReferenceSection += "/* End PBXFileReference section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine; PBXResourcesBuildPhaseSection += "/* End PBXResourcesBuildPhase section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine; PBXSourcesBuildPhaseSection += "/* End PBXSourcesBuildPhase section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine; PBXFrameworksBuildPhaseSection += "/* End PBXFrameworksBuildPhase section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine; PBXShellScriptBuildPhaseSection += "/* End PBXShellScriptBuildPhase section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine; string PBXTargetDependencySection = "/* Begin PBXTargetDependency section */" + ProjectFileGenerator.NewLine; CreateTargetDependencySection(ref PBXTargetDependencySection, TargetDependencies); PBXTargetDependencySection += "/* End PBXTargetDependency section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine; string PBXContainerItemProxySection = "/* Begin PBXContainerItemProxy section */" + ProjectFileGenerator.NewLine; CreateContainerItemProxySection(ref PBXContainerItemProxySection, ContainerItemProxies); PBXContainerItemProxySection += "/* End PBXContainerItemProxy section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine; XcodeProjectFileContent.Append(PBXBuildFileSection); XcodeProjectFileContent.Append(PBXFileReferenceSection); XcodeProjectFileContent.Append(PBXContainerItemProxySection); XcodeProjectFileContent.Append(PBXTargetDependencySection); AppendGroups(ref XcodeProjectFileContent, ref Groups, ProjectTargets, Frameworks); XcodeProjectFileContent.Append(PBXShellScriptBuildPhaseSection); XcodeProjectFileContent.Append(PBXSourcesBuildPhaseSection); XcodeProjectFileContent.Append(PBXFrameworksBuildPhaseSection); XcodeProjectFileContent.Append("/* Begin PBXLegacyTarget section */" + ProjectFileGenerator.NewLine); foreach (var Target in ProjectTargets) { if (Target.Type == XcodeTargetType.Legacy) { AppendTarget(ref XcodeProjectFileContent, Target); } } XcodeProjectFileContent.Append("/* End PBXLegacyTarget section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine); XcodeProjectFileContent.Append("/* Begin PBXNativeTarget section */" + ProjectFileGenerator.NewLine); AppendTarget(ref XcodeProjectFileContent, UE4XcodeHelperTarget); foreach (XcodeProjectTarget Target in ProjectTargets) { if (Target.Type == XcodeTargetType.Native || Target.Type == XcodeTargetType.XCTest) { AppendTarget(ref XcodeProjectFileContent, Target); } } XcodeProjectFileContent.Append("/* End PBXNativeTarget section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine); XcodeProjectFileContent.Append( "/* Begin PBXProject section */" + ProjectFileGenerator.NewLine + "\t\t" + UE4ProjectTarget.Guid + " /* Project object */ = {" + ProjectFileGenerator.NewLine + "\t\t\tisa = PBXProject;" + ProjectFileGenerator.NewLine + "\t\t\tattributes = {" + ProjectFileGenerator.NewLine + "\t\t\t\tLastUpgradeCheck = 0510;" + ProjectFileGenerator.NewLine + "\t\t\t\tORGANIZATIONNAME = EpicGames;" + ProjectFileGenerator.NewLine + "\t\t\t};" + ProjectFileGenerator.NewLine + "\t\t\tbuildConfigurationList = " + UE4ProjectTarget.BuildConfigGuild + " /* Build configuration list for PBXProject \"" + UE4ProjectTarget.DisplayName + "\" */;" + ProjectFileGenerator.NewLine + "\t\t\tcompatibilityVersion = \"Xcode 3.2\";" + ProjectFileGenerator.NewLine + "\t\t\tdevelopmentRegion = English;" + ProjectFileGenerator.NewLine + "\t\t\thasScannedForEncodings = 0;" + ProjectFileGenerator.NewLine + "\t\t\tknownRegions = (" + ProjectFileGenerator.NewLine + "\t\t\t\ten," + ProjectFileGenerator.NewLine + "\t\t\t);" + ProjectFileGenerator.NewLine + "\t\t\tmainGroup = " + MainGroupGuid + ";" + ProjectFileGenerator.NewLine + "\t\t\tproductRefGroup = " + ProductRefGroupGuid + " /* Products */;" + ProjectFileGenerator.NewLine + "\t\t\tprojectDirPath = \"\";" + ProjectFileGenerator.NewLine + "\t\t\tprojectRoot = \"\";" + ProjectFileGenerator.NewLine + "\t\t\ttargets = (" + ProjectFileGenerator.NewLine ); foreach (var Target in ProjectTargets) { if (Target != UE4ProjectTarget) { XcodeProjectFileContent.AppendLine(string.Format("\t\t\t\t{0} /* {1} */,", Target.Guid, Target.DisplayName)); } } XcodeProjectFileContent.Append( "\t\t\t);" + ProjectFileGenerator.NewLine + "\t\t};" + ProjectFileGenerator.NewLine + "/* End PBXProject section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine ); string PreprocessorDefinitionsString = "\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (" + ProjectFileGenerator.NewLine; foreach (string Definition in PreprocessorDefinitions) { PreprocessorDefinitionsString += "\t\t\t\t\t\"" + Definition + "\"," + ProjectFileGenerator.NewLine; } PreprocessorDefinitionsString += "\t\t\t\t\t\"MONOLITHIC_BUILD=1\"," + ProjectFileGenerator.NewLine; PreprocessorDefinitionsString += "\t\t\t\t);" + ProjectFileGenerator.NewLine; string HeaderSearchPaths = "\t\t\t\tHEADER_SEARCH_PATHS = (" + ProjectFileGenerator.NewLine; foreach (string Path in SystemIncludeDirectories) { HeaderSearchPaths += "\t\t\t\t\t\"" + Path + "\"," + ProjectFileGenerator.NewLine; } HeaderSearchPaths += "\t\t\t\t);" + ProjectFileGenerator.NewLine; HeaderSearchPaths += "\t\t\t\tUSER_HEADER_SEARCH_PATHS = (" + ProjectFileGenerator.NewLine; foreach (string Path in IncludeDirectories) { HeaderSearchPaths += "\t\t\t\t\t\"" + Path + "\"," + ProjectFileGenerator.NewLine; } HeaderSearchPaths += "\t\t\t\t);" + ProjectFileGenerator.NewLine; XcodeProjectFileContent.Append("/* Begin XCBuildConfiguration section */" + ProjectFileGenerator.NewLine); AppendBuildConfigs(ref XcodeProjectFileContent, UE4ProjectTarget, HeaderSearchPaths, PreprocessorDefinitionsString); foreach (var Target in ProjectTargets) { if (Target.Type != XcodeTargetType.Project && Target.Type != XcodeTargetType.XcodeHelper) { AppendBuildConfigs(ref XcodeProjectFileContent, Target); } } AppendBuildConfigs(ref XcodeProjectFileContent, UE4XcodeHelperTarget); XcodeProjectFileContent.Append("/* End XCBuildConfiguration section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine); XcodeProjectFileContent.Append("/* Begin XCConfigurationList section */" + ProjectFileGenerator.NewLine); foreach (var Target in ProjectTargets) { if (Target.Type != XcodeTargetType.XcodeHelper) { AppendConfigList(ref XcodeProjectFileContent, Target); } } AppendConfigList(ref XcodeProjectFileContent, UE4XcodeHelperTarget); XcodeProjectFileContent.Append("/* End XCConfigurationList section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine); XcodeProjectFileContent.Append( "\t};" + ProjectFileGenerator.NewLine + "\trootObject = " + UE4ProjectTarget.Guid + " /* Project object */;" + ProjectFileGenerator.NewLine + "}" + ProjectFileGenerator.NewLine); WriteProject(XcodeProjectFileContent, ProjectTargets); // TODO: add any content for any files in the workspace here WriteWorkspace(); return true; }
/// <summary> /// Appends a build configuration section for specific target. /// </summary> /// <param name="Contents">StringBuilder object to append build configuration string to</param> /// <param name="Target">Target for which we generate the build configuration</param> /// <param name="HeaderSearchPaths">Optional string with header search paths section</param> /// <param name="PreprocessorDefinitions">Optional string with preprocessor definitions section</param> private void AppendBuildConfigs(ref StringBuilder Contents, XcodeProjectTarget Target, string HeaderSearchPaths = "", string PreprocessorDefinitions = "") { List<string> GameFolders = STBuildTarget.DiscoverAllGameFolders(); bool IsAGame = false; string GamePath = null; string GameNameFromClientName = Target.TargetName.EndsWith("Client") ? Target.TargetName.Remove(Target.TargetName.LastIndexOf("Client")) + "Game" : null; bool bIsUE4Game = Target.TargetName.Equals("UE4Game", StringComparison.InvariantCultureIgnoreCase); bool bIsUE4Client = Target.TargetName.Equals("UE4Client", StringComparison.InvariantCultureIgnoreCase); string EngineRelative = ""; ISTToolChain Toolchain = STToolChain.GetPlatformToolChain(CPPTargetPlatform.IOS); foreach (string GameFolder in GameFolders) { if (File.Exists(Path.Combine(GameFolder, Target.TargetName + ".uproject"))) { IsAGame = true; GamePath = Toolchain.ConvertPath(Path.GetFullPath(GameFolder)); break; } else if (!string.IsNullOrEmpty(GameNameFromClientName) && GameFolder.EndsWith(GameNameFromClientName)) { GamePath = Toolchain.ConvertPath(Path.GetFullPath(GameFolder)); break; } } EngineRelative = Path.GetFullPath(EngineRelativePath + "/../"); EngineRelative = Toolchain.ConvertPath(EngineRelative); if (!bGeneratingRocketProjectFiles) { AppendSingleConfig(ref Contents, Target, "Debug", Target.DebugConfigGuid, PreprocessorDefinitions, HeaderSearchPaths, EngineRelative, GamePath, bIsUE4Game, IsAGame, bIsUE4Client); AppendSingleConfig(ref Contents, Target, "Test", Target.TestConfigGuid, PreprocessorDefinitions, HeaderSearchPaths, EngineRelative, GamePath, bIsUE4Game, IsAGame, bIsUE4Client); } AppendSingleConfig(ref Contents, Target, "DebugGame", Target.DebugGameConfigGuid, PreprocessorDefinitions, HeaderSearchPaths, EngineRelative, GamePath, bIsUE4Game, IsAGame, bIsUE4Client); AppendSingleConfig(ref Contents, Target, "Development", Target.DevelopmentConfigGuid, PreprocessorDefinitions, HeaderSearchPaths, EngineRelative, GamePath, bIsUE4Game, IsAGame, bIsUE4Client); AppendSingleConfig(ref Contents, Target, "Shipping", Target.ShippingConfigGuid, PreprocessorDefinitions, HeaderSearchPaths, EngineRelative, GamePath, bIsUE4Game, IsAGame, bIsUE4Client); }
/// <summary> /// Writes a scheme file that holds user-specific info needed for debugging. /// </summary> /// <param name="Target">Target for which we write the scheme file</param> /// <param name="ExeExtension">Extension of the executable used to run and debug this target (".app" for bundles, "" for command line apps</param> /// <param name="ExeBaseName">Base name of the executable used to run and debug this target</param> /// <param name="Args">List of command line arguments for running this target</param> private void WriteSchemeFile(string XcodeProjectPath, XcodeProjectTarget Target, string ExeExtension = "", string ExeBaseName = "", List<string> Args = null) { if (ExeBaseName == "") { ExeBaseName = Target.TargetName; } string TargetBinariesFolder; if (ExeBaseName.StartsWith("/")) { TargetBinariesFolder = Path.GetDirectoryName(ExeBaseName); ExeBaseName = Path.GetFileName(ExeBaseName); } else { TargetBinariesFolder = Path.GetDirectoryName(Directory.GetCurrentDirectory()); if (ExeBaseName == Target.TargetName && ExeBaseName.EndsWith("Game") && ExeExtension == ".app") { TargetBinariesFolder = TargetBinariesFolder.Replace("/Engine", "/") + ExeBaseName + "/Binaries/"; } else { TargetBinariesFolder += "/Binaries/"; } // append the platform directory TargetBinariesFolder += Target.TargetPlatform.ToString(); } string SchemeFileContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + ProjectFileGenerator.NewLine + "<Scheme" + ProjectFileGenerator.NewLine + " LastUpgradeVersion = \"0500\"" + ProjectFileGenerator.NewLine + " version = \"1.3\">" + ProjectFileGenerator.NewLine + " <BuildAction" + ProjectFileGenerator.NewLine + " parallelizeBuildables = \"YES\"" + ProjectFileGenerator.NewLine + " buildImplicitDependencies = \"YES\">" + ProjectFileGenerator.NewLine + " <BuildActionEntries>" + ProjectFileGenerator.NewLine + " <BuildActionEntry" + ProjectFileGenerator.NewLine + " buildForTesting = \"YES\"" + ProjectFileGenerator.NewLine + " buildForRunning = \"YES\"" + ProjectFileGenerator.NewLine + " buildForProfiling = \"YES\"" + ProjectFileGenerator.NewLine + " buildForArchiving = \"YES\"" + ProjectFileGenerator.NewLine + " buildForAnalyzing = \"YES\">" + ProjectFileGenerator.NewLine + " <BuildableReference" + ProjectFileGenerator.NewLine + " BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine + " BlueprintIdentifier = \"" + Target.Guid + "\"" + ProjectFileGenerator.NewLine + " BuildableName = \"" + Target.ProductName + "\"" + ProjectFileGenerator.NewLine + " BlueprintName = \"" + Target.DisplayName + "\"" + ProjectFileGenerator.NewLine + " ReferencedContainer = \"container:" + MasterProjectName + ".xcodeproj\">" + ProjectFileGenerator.NewLine + " </BuildableReference>" + ProjectFileGenerator.NewLine + " </BuildActionEntry>" + ProjectFileGenerator.NewLine + " </BuildActionEntries>" + ProjectFileGenerator.NewLine + " </BuildAction>" + ProjectFileGenerator.NewLine + " <TestAction" + ProjectFileGenerator.NewLine + " selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"" + ProjectFileGenerator.NewLine + " selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"" + ProjectFileGenerator.NewLine + " shouldUseLaunchSchemeArgsEnv = \"YES\"" + ProjectFileGenerator.NewLine + " buildConfiguration = \"Debug" + (bGeneratingRocketProjectFiles ? "Game" : "") + "\">" + ProjectFileGenerator.NewLine + " <Testables>" + ProjectFileGenerator.NewLine + " <TestableReference" + ProjectFileGenerator.NewLine + " skipped = \"NO\">" + ProjectFileGenerator.NewLine + " <BuildableReference" + ProjectFileGenerator.NewLine + " BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine + " BlueprintIdentifier = \"" + UE4CmdLineGuid + "\"" + ProjectFileGenerator.NewLine + " BuildableName = \"UE4CmdLineRun.xctest\"" + ProjectFileGenerator.NewLine + " BlueprintName = \"UE4CmdLineRun\"" + ProjectFileGenerator.NewLine + " ReferencedContainer = \"container:" + MasterProjectName + ".xcodeproj\">" + ProjectFileGenerator.NewLine + " </BuildableReference>" + ProjectFileGenerator.NewLine + " </TestableReference>" + ProjectFileGenerator.NewLine + " </Testables>" + ProjectFileGenerator.NewLine + " <MacroExpansion>" + ProjectFileGenerator.NewLine + " <BuildableReference" + ProjectFileGenerator.NewLine + " BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine + " BlueprintIdentifier = \"" + Target.Guid + "\"" + ProjectFileGenerator.NewLine + " BuildableName = \"" + Target.ProductName + "\"" + ProjectFileGenerator.NewLine + " BlueprintName = \"" + Target.DisplayName + "\"" + ProjectFileGenerator.NewLine + " ReferencedContainer = \"container:" + MasterProjectName + ".xcodeproj\">" + ProjectFileGenerator.NewLine + " </BuildableReference>" + ProjectFileGenerator.NewLine + " </MacroExpansion>" + ProjectFileGenerator.NewLine + " </TestAction>" + ProjectFileGenerator.NewLine + " <LaunchAction" + ProjectFileGenerator.NewLine + " selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"" + ProjectFileGenerator.NewLine + " selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"" + ProjectFileGenerator.NewLine + " launchStyle = \"0\"" + ProjectFileGenerator.NewLine + " useCustomWorkingDirectory = \"NO\"" + ProjectFileGenerator.NewLine + " buildConfiguration = \"Debug" + (bGeneratingRocketProjectFiles ? "Game" : "") + "\"" + ProjectFileGenerator.NewLine + " ignoresPersistentStateOnLaunch = \"NO\"" + ProjectFileGenerator.NewLine + " debugDocumentVersioning = \"YES\"" + ProjectFileGenerator.NewLine + " allowLocationSimulation = \"YES\">" + ProjectFileGenerator.NewLine; if (Target.TargetPlatform == STTargetPlatform.Mac) { // For non-rocket projects the default Run targtet is always in Debug config, so we always add -Mac-Debug suffix. // For rocket projects, we have DebugGame config, so the editor runs in Development mode (no suffix), but the game in Debug (so it needs suffix). string ExeConfigSuffix = (!bGeneratingRocketProjectFiles || !ExeBaseName.EndsWith("Editor")) ? "-Mac-Debug" : ""; SchemeFileContent += " <PathRunnable" + ProjectFileGenerator.NewLine + " FilePath = \"" + TargetBinariesFolder + "/" + ExeBaseName + ExeConfigSuffix + ExeExtension + "\">" + ProjectFileGenerator.NewLine + " </PathRunnable>" + ProjectFileGenerator.NewLine; } else { SchemeFileContent += " <BuildableProductRunnable>" + ProjectFileGenerator.NewLine + " <BuildableReference" + ProjectFileGenerator.NewLine + " BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine + " BlueprintIdentifier = \"" + Target.Guid + "\"" + ProjectFileGenerator.NewLine + " BuildableName = \"" + Target.ProductName + "\"" + ProjectFileGenerator.NewLine + " BlueprintName = \"" + Target.DisplayName + "\"" + ProjectFileGenerator.NewLine + " ReferencedContainer = \"container:" + MasterProjectName + ".xcodeproj\">" + ProjectFileGenerator.NewLine + " </BuildableReference>" + ProjectFileGenerator.NewLine + " </BuildableProductRunnable>" + ProjectFileGenerator.NewLine; } if (Args != null) { SchemeFileContent += " <CommandLineArguments>" + ProjectFileGenerator.NewLine; Args.Add("-debug"); foreach (string Arg in Args) { SchemeFileContent += " <CommandLineArgument" + ProjectFileGenerator.NewLine + " argument = \"" + Arg + "\"" + ProjectFileGenerator.NewLine + " isEnabled = \"YES\">" + ProjectFileGenerator.NewLine + " </CommandLineArgument>" + ProjectFileGenerator.NewLine; } SchemeFileContent += " </CommandLineArguments>" + ProjectFileGenerator.NewLine; } string Runnable = TargetBinariesFolder + "/" + ExeBaseName + ExeExtension; SchemeFileContent += " <AdditionalOptions>" + ProjectFileGenerator.NewLine + " </AdditionalOptions>" + ProjectFileGenerator.NewLine + " </LaunchAction>" + ProjectFileGenerator.NewLine + " <ProfileAction" + ProjectFileGenerator.NewLine + " shouldUseLaunchSchemeArgsEnv = \"YES\"" + ProjectFileGenerator.NewLine + " savedToolIdentifier = \"\"" + ProjectFileGenerator.NewLine + " useCustomWorkingDirectory = \"NO\"" + ProjectFileGenerator.NewLine + " buildConfiguration = \"Development\"" + ProjectFileGenerator.NewLine + " debugDocumentVersioning = \"YES\">" + ProjectFileGenerator.NewLine + " <PathRunnable" + ProjectFileGenerator.NewLine + " FilePath = \"" + Runnable + "\">" + ProjectFileGenerator.NewLine + " </PathRunnable>" + ProjectFileGenerator.NewLine + " <BuildableProductRunnable>" + ProjectFileGenerator.NewLine + " <BuildableReference" + ProjectFileGenerator.NewLine + " BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine + " BlueprintIdentifier = \"" + Target.Guid + "\"" + ProjectFileGenerator.NewLine + " BuildableName = \"" + ExeBaseName + ExeExtension + "\"" + ProjectFileGenerator.NewLine + " BlueprintName = \"" + ExeBaseName + "\"" + ProjectFileGenerator.NewLine + " ReferencedContainer = \"container:UE4.xcodeproj\">" + ProjectFileGenerator.NewLine + " </BuildableReference>" + ProjectFileGenerator.NewLine + " </BuildableProductRunnable>" + ProjectFileGenerator.NewLine + " </ProfileAction>" + ProjectFileGenerator.NewLine + " <AnalyzeAction" + ProjectFileGenerator.NewLine + " buildConfiguration = \"Debug" + (bGeneratingRocketProjectFiles ? "Game" : "") + "\">" + ProjectFileGenerator.NewLine + " </AnalyzeAction>" + ProjectFileGenerator.NewLine + " <ArchiveAction" + ProjectFileGenerator.NewLine + " buildConfiguration = \"Development\"" + ProjectFileGenerator.NewLine + " revealArchiveInOrganizer = \"YES\">" + ProjectFileGenerator.NewLine + " </ArchiveAction>" + ProjectFileGenerator.NewLine + "</Scheme>" + ProjectFileGenerator.NewLine; string SchemesDir = XcodeProjectPath + "/xcuserdata/" + Environment.UserName + ".xcuserdatad/xcschemes"; if (!Directory.Exists(SchemesDir)) { Directory.CreateDirectory(SchemesDir); } string SchemeFilePath = SchemesDir + Path.DirectorySeparatorChar + Target.DisplayName + ".xcscheme"; File.WriteAllText(SchemeFilePath, SchemeFileContent); }
private void PopulateTargets(List<string> GamePaths, List<XcodeProjectTarget> ProjectTargets, List<XcodeContainerItemProxy> ContainerItemProxies, List<XcodeTargetDependency> TargetDependencies, XcodeProjectTarget ProjectTarget, List<XcodeFramework> Frameworks) { foreach (string TargetPath in GamePaths) { string TargetName = Utils.GetFilenameWithoutAnyExtensions(Path.GetFileName(TargetPath)); bool WantProjectFileForTarget = true; bool IsEngineTarget = false; if (bGeneratingGameProjectFiles || bGeneratingRocketProjectFiles) { // Check to see if this is an Engine target. That is, the target is located under the "Engine" folder string TargetFileRelativeToEngineDirectory = Utils.MakePathRelativeTo(TargetPath, Path.Combine(EngineRelativePath), AlwaysTreatSourceAsDirectory: false); if (!TargetFileRelativeToEngineDirectory.StartsWith("..") && !Path.IsPathRooted(TargetFileRelativeToEngineDirectory)) { // This is an engine target IsEngineTarget = true; } if (IsEngineTarget) { if (!IncludeEngineSource) { // We were asked to exclude engine modules from the generated projects WantProjectFileForTarget = false; } if (bGeneratingGameProjectFiles && this.GameProjectName == TargetName) { WantProjectFileForTarget = true; } } } if (WantProjectFileForTarget) { string TargetFilePath; var Target = new TargetInfo(STTargetPlatform.Mac, STTargetConfiguration.Development); var TargetRulesObject = RulesCompiler.CreateTargetRules(TargetName, Target, false, out TargetFilePath); List<STTargetPlatform> SupportedPlatforms = new List<STTargetPlatform>(); TargetRulesObject.GetSupportedPlatforms(ref SupportedPlatforms); LinkEnvironmentConfiguration LinkConfiguration = new LinkEnvironmentConfiguration(); CPPEnvironmentConfiguration CPPConfiguration = new CPPEnvironmentConfiguration(); TargetRulesObject.SetupGlobalEnvironment(Target, ref LinkConfiguration, ref CPPConfiguration); if (!LinkConfiguration.bIsBuildingConsoleApplication) { TargetsThatNeedApp.Add(TargetName); } // if the project is not an engine project check to make sure we have the correct name string DisplayName = TargetName; if (!IsEngineTarget && TargetRulesObject.Type != TargetRules.TargetType.Program && TargetRulesObject.Type != TargetRules.TargetType.Client) { List<UProjectInfo> AllGames = UProjectInfo.FilterGameProjects(true, bGeneratingGameProjectFiles ? GameProjectName : null); UProjectInfo ProjectInfo = FindGameContainingFile(AllGames, TargetFilePath); if (ProjectInfo != null) { DisplayName = ProjectInfo.GameName; if (TargetName.Contains("Editor")) { DisplayName += "Editor"; } else if (TargetName.Contains("Server")) { DisplayName += "Server"; } } } // @todo: Remove target platform param and merge Mac and iOS targets. For now BuildTarget knows how to build iOS, but cannot run iOS apps, so we need separate DeployTarget. bool bIsMacOnly = !SupportedPlatforms.Contains(STTargetPlatform.IOS); XcodeProjectTarget BuildTarget = new XcodeProjectTarget(DisplayName + " - Mac", TargetName, XcodeTargetType.Legacy, TargetFilePath, "", STTargetPlatform.Mac, bIsMacOnly); if (!bGeneratingRunIOSProject) { ProjectTargets.Add(BuildTarget); } if (ProjectFilePlatform.HasFlag(XcodeProjectFilePlatform.iOS) && SupportedPlatforms.Contains(STTargetPlatform.IOS)) { if ((bGeneratingRocketProjectFiles && TargetName == "UE4Game") || bGeneratingRunIOSProject) { // Generate Framework references. List<XcodeFrameworkRef> FrameworkRefs = new List<XcodeFrameworkRef>(); foreach (XcodeFramework Framework in Frameworks) { FrameworkRefs.Add(new XcodeFrameworkRef(Framework)); } XcodeProjectTarget IOSDeployTarget = new XcodeProjectTarget(DisplayName + " - iOS", TargetName, XcodeTargetType.Native, TargetFilePath, TargetName + ".app", STTargetPlatform.IOS, false, null, true, FrameworkRefs); ProjectTargets.Add(IOSDeployTarget); } else { XcodeContainerItemProxy ContainerProxy = new XcodeContainerItemProxy(ProjectTarget.Guid, BuildTarget.Guid, BuildTarget.DisplayName); XcodeTargetDependency TargetDependency = new XcodeTargetDependency(BuildTarget.DisplayName, BuildTarget.Guid, ContainerProxy.Guid); XcodeProjectTarget IOSDeployTarget = new XcodeProjectTarget(DisplayName + " - iOS", TargetName, XcodeTargetType.Native, TargetFilePath, TargetName + ".app", STTargetPlatform.IOS, false, new List<XcodeTargetDependency>() { TargetDependency }, true); ProjectTargets.Add(IOSDeployTarget); ContainerItemProxies.Add(ContainerProxy); TargetDependencies.Add(TargetDependency); } } } } }
/// <summary> /// Appends a target to targets section. /// </summary> /// <param name="Contents">StringBuilder object to append target string to</param> /// <param name="Target">Target to append</param> private void AppendTarget(ref StringBuilder Contents, XcodeProjectTarget Target) { string TargetType = IsXcodeTargetTypeNative(Target.Type) ? "Native" : Target.Type.ToString(); Contents.Append( "\t\t" + Target.Guid + " /* " + Target.DisplayName + " */ = {" + ProjectFileGenerator.NewLine + "\t\t\tisa = PBX" + TargetType + "Target;" + ProjectFileGenerator.NewLine); if (Target.Type == XcodeTargetType.Legacy) { string UProjectPath = ""; if (STBuildTool.HasUProjectFile() && !string.IsNullOrEmpty(Target.TargetFilePath) && Utils.IsFileUnderDirectory(Target.TargetFilePath, STBuildTool.GetUProjectPath())) { if (MasterProjectRelativePath == STBuildTool.GetUProjectPath()) { UProjectPath = " " + "\\\"$(PROJECT_DIR)/" + Path.GetFileName(STBuildTool.GetUProjectFile()) + "\\\""; } else { UProjectPath = " " + "\\\"" + STBuildTool.GetUProjectFile() + "\\\""; } } // Xcode provides $ACTION argument for determining if we are building or cleaning a project Contents.Append("\t\t\tbuildArgumentsString = \"$(ACTION) " + Target.TargetName + " $(PLATFORM_NAME) $(CONFIGURATION)" + UProjectPath + "\";" + ProjectFileGenerator.NewLine); } Contents.Append("\t\t\tbuildConfigurationList = " + Target.BuildConfigGuild + " /* Build configuration list for PBX" + TargetType + "Target \"" + Target.DisplayName + "\" */;" + ProjectFileGenerator.NewLine); Contents.Append("\t\t\tbuildPhases = (" + ProjectFileGenerator.NewLine); if (IsXcodeTargetTypeNative(Target.Type)) { Contents.Append("\t\t\t\t" + Target.SourcesPhaseGuid + " /* Sources */," + ProjectFileGenerator.NewLine); //Contents.Append("\t\t\t\t" + Target.ResourcesPhaseGuid + " /* Resources */," + ProjectFileGenerator.NewLine); Contents.Append("\t\t\t\t" + Target.FrameworksPhaseGuid + " /* Frameworks */," + ProjectFileGenerator.NewLine); Contents.Append("\t\t\t\t" + Target.ShellScriptPhaseGuid + " /* ShellScript */," + ProjectFileGenerator.NewLine); } Contents.Append("\t\t\t);" + ProjectFileGenerator.NewLine); if (Target.Type == XcodeTargetType.Legacy) { string UE4Dir = Path.GetFullPath(Directory.GetCurrentDirectory() + "../../.."); if (bGeneratingRocketProjectFiles) { Contents.Append("\t\t\tbuildToolPath = \"" + UE4Dir + "/Engine/Build/BatchFiles/Mac/RocketBuild.sh\";" + ProjectFileGenerator.NewLine); } else { Contents.Append("\t\t\tbuildToolPath = \"" + UE4Dir + "/Engine/Build/BatchFiles/Mac/Build.sh\";" + ProjectFileGenerator.NewLine); } Contents.Append("\t\t\tbuildWorkingDirectory = \"" + UE4Dir + "\";" + ProjectFileGenerator.NewLine); } // This binds the "Run" targets to the "Build" targets. Contents.Append("\t\t\tdependencies = (" + ProjectFileGenerator.NewLine); foreach (XcodeTargetDependency Dependency in Target.Dependencies) { Contents.Append("\t\t\t\t" + Dependency.Guid + " /* PBXTargetDependency */" + ProjectFileGenerator.NewLine); } Contents.Append( "\t\t\t);" + ProjectFileGenerator.NewLine + "\t\t\tname = \"" + Target.DisplayName + "\";" + ProjectFileGenerator.NewLine); if (Target.Type == XcodeTargetType.Legacy) { Contents.Append("\t\t\tpassBuildSettingsInEnvironment = 0;" + ProjectFileGenerator.NewLine); } Contents.Append("\t\t\tproductName = \"" + Target.DisplayName + "\";" + ProjectFileGenerator.NewLine); if (Target.Type == XcodeTargetType.XcodeHelper) { Contents.Append( "\t\t\tproductReference = " + Target.ProductGuid + " /* " + Target.ProductName + " */;" + ProjectFileGenerator.NewLine + "\t\t\tproductType = \"com.apple.product-type.library.static\";" + ProjectFileGenerator.NewLine); } else if (Target.Type == XcodeTargetType.Native) { Contents.Append( "\t\t\tproductReference = " + Target.ProductGuid + " /* " + Target.ProductName + " */;" + ProjectFileGenerator.NewLine + "\t\t\tproductType = \"com.apple.product-type.application\";" + ProjectFileGenerator.NewLine); } else if (Target.Type == XcodeTargetType.XCTest) { Contents.Append( "\t\t\tproductReference = " + Target.ProductGuid + " /* " + Target.ProductName + " */;" + ProjectFileGenerator.NewLine + "\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";" + ProjectFileGenerator.NewLine); } Contents.Append("\t\t};" + ProjectFileGenerator.NewLine); }
private void AppendSourceFiles(List<XcodeProjectTarget> ProjectTargets, ref string PBXBuildFileSection, ref string PBXFileReferenceSection, ref string PBXSourcesBuildPhaseSection, ref Dictionary<string, XcodeFileGroup> Groups, XcodeProjectTarget UE4XcodeHelperTarget, string UE4CmdLineRunMFileGuid, ref List<string> IncludeDirectories, ref List<string> SystemIncludeDirectories, ref List<string> PreprocessorDefinitions) { PBXSourcesBuildPhaseSection += "\t\t" + UE4XcodeHelperTarget.SourcesPhaseGuid + " /* Sources */ = {" + ProjectFileGenerator.NewLine + "\t\t\tisa = PBXSourcesBuildPhase;" + ProjectFileGenerator.NewLine + "\t\t\tbuildActionMask = 2147483647;" + ProjectFileGenerator.NewLine + "\t\t\tfiles = (" + ProjectFileGenerator.NewLine; PBXFileReferenceSection += "\t\t" + UE4XcodeHelperTarget.ProductGuid + " /* " + UE4XcodeHelperTarget.ProductName + " */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = " + UE4XcodeHelperTarget.ProductName + "; sourceTree = BUILT_PRODUCTS_DIR; };" + ProjectFileGenerator.NewLine; foreach (var CurProject in GeneratedProjectFiles) { bool bHasTarget = false; foreach (var TargetFile in CurProject.ProjectTargets) { if (TargetFile.TargetFilePath != null) { string TargetFileName = Path.GetFileNameWithoutExtension(TargetFile.TargetFilePath); string TargetFileMinusTarget = TargetFileName.Substring(0, TargetFileName.LastIndexOf(".Target")); foreach (XcodeProjectTarget Target in ProjectTargets) { if (TargetFileMinusTarget == Target.TargetName) { bHasTarget = true; break; } } if (bHasTarget) { break; } } } if (!bHasTarget) { continue; } XcodeProjectFile XcodeProject = CurProject as XcodeProjectFile; if (XcodeProject == null) { continue; } // Necessary so that GenerateSectionContents can use the same GUID instead of // auto-generating one for this special-case file. XcodeProject.UE4CmdLineRunFileGuid = UE4CmdLineRunMFileGuid; XcodeProject.UE4CmdLineRunFileRefGuid = UE4CmdLineRunMFileRefGuid; if (bGeneratingRunIOSProject) { foreach (var CurSourceFile in XcodeProject.SourceFiles) { XcodeSourceFile SourceFile = CurSourceFile as XcodeSourceFile; string GroupPath = Path.GetFullPath(Path.GetDirectoryName(SourceFile.FilePath)); XcodeFileGroup Group = XcodeProject.FindGroupByFullPath(ref Groups, GroupPath); if (Group != null) { Group.bReference = true; } } } else { XcodeProject.GenerateSectionsContents(ref PBXBuildFileSection, ref PBXFileReferenceSection, ref PBXSourcesBuildPhaseSection, ref Groups); } foreach (var CurPath in XcodeProject.IntelliSenseIncludeSearchPaths) { AddIncludeDirectory(ref IncludeDirectories, CurPath, Path.GetDirectoryName(XcodeProject.ProjectFilePath)); } foreach (var CurPath in XcodeProject.IntelliSenseSystemIncludeSearchPaths) { AddIncludeDirectory(ref SystemIncludeDirectories, CurPath, Path.GetDirectoryName(XcodeProject.ProjectFilePath)); } foreach (var CurDefinition in XcodeProject.IntelliSensePreprocessorDefinitions) { string Definition = CurDefinition; string AlternateDefinition = Definition.Contains("=0") ? Definition.Replace("=0", "=1") : Definition.Replace("=1", "=0"); if (Definition.Equals("WITH_EDITORONLY_DATA=0") || Definition.Equals("WITH_DATABASE_SUPPORT=1")) { Definition = AlternateDefinition; } if (!PreprocessorDefinitions.Contains(Definition) && !PreprocessorDefinitions.Contains(AlternateDefinition) && !Definition.StartsWith("UE_ENGINE_DIRECTORY") && !Definition.StartsWith("ORIGINAL_FILE_NAME")) { PreprocessorDefinitions.Add(Definition); } } } PBXSourcesBuildPhaseSection += "\t\t\t);" + ProjectFileGenerator.NewLine + "\t\t\trunOnlyForDeploymentPostprocessing = 0;" + ProjectFileGenerator.NewLine + "\t\t};" + ProjectFileGenerator.NewLine; if (!bGeneratingRocketProjectFiles) { // Add STBuildTool to the master project string ProjectPath = System.IO.Path.Combine(System.IO.Path.Combine(EngineRelativePath, "Source"), "Programs", "STBuildTool", "STBuildTool_Mono.csproj"); AddPreGeneratedProject(ref PBXBuildFileSection, ref PBXFileReferenceSection, ref PBXSourcesBuildPhaseSection, ref Groups, ProjectPath); } }
private void AppendSingleConfig(ref StringBuilder Contents, XcodeProjectTarget Target, string ConfigName, string ConfigGuid, string PreprocessorDefinitions, string HeaderSearchPaths, string EngineRelative, string GamePath, bool bIsUE4Game, bool IsAGame, bool bIsUE4Client) { if (Target.Type == XcodeTargetType.Project) { AppendProjectConfig(ref Contents, ConfigName, ConfigGuid, PreprocessorDefinitions, HeaderSearchPaths); } else { if (Target.TargetPlatform == STTargetPlatform.Mac) { AppendMacBuildConfig(ref Contents, ConfigName, ConfigGuid, Target.bIsMacOnly); } else { if (Target.Type == XcodeTargetType.Legacy) { AppendIOSBuildConfig(ref Contents, ConfigName, ConfigGuid); } else { if (Target.Type != XcodeTargetType.XCTest) { AppendIOSRunConfig(ref Contents, ConfigName, ConfigGuid, Target.TargetName, EngineRelative, GamePath, bIsUE4Game, IsAGame, bIsUE4Client); } else { string EngineSubdir = (bGeneratingGameProjectFiles || bGeneratingRocketProjectFiles) ? "" : "Engine/"; AppendIOSXCTestConfig(ref Contents, ConfigName, ConfigGuid, Target.TargetName, EngineSubdir, EngineRelative); } } } } }