1946 lines
102 KiB
C#
1946 lines
102 KiB
C#
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using EpicGames.Core;
|
|
using Microsoft.Extensions.Logging;
|
|
using UnrealBuildBase;
|
|
using UnrealBuildTool.XcodeProjectXcconfig;
|
|
|
|
namespace UnrealBuildTool.XcodeProjectLegacy
|
|
{
|
|
/// <summary>
|
|
/// Represents a group of files shown in Xcode's project navigator as a folder
|
|
/// </summary>
|
|
class XcodeFileGroup
|
|
{
|
|
public XcodeFileGroup(string InName, string InPath, bool InIsReference)
|
|
{
|
|
GroupName = InName;
|
|
GroupPath = InPath;
|
|
GroupGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
bIsReference = InIsReference;
|
|
}
|
|
|
|
public string GroupGuid;
|
|
public string GroupName;
|
|
public string GroupPath;
|
|
public Dictionary<string, XcodeFileGroup> Children = new Dictionary<string, XcodeFileGroup>();
|
|
public List<XcodeSourceFile> Files = new List<XcodeSourceFile>();
|
|
public bool bIsReference;
|
|
}
|
|
|
|
class XcodeBuildConfig
|
|
{
|
|
public XcodeBuildConfig(string InDisplayName, string InBuildTarget, FileReference? InMacExecutablePath, FileReference? InIOSExecutablePath, FileReference? InTVOSExecutablePath,
|
|
ProjectTarget? InProjectTarget, UnrealTargetConfiguration InBuildConfig)
|
|
{
|
|
DisplayName = InDisplayName;
|
|
MacExecutablePath = InMacExecutablePath;
|
|
IOSExecutablePath = InIOSExecutablePath;
|
|
TVOSExecutablePath = InTVOSExecutablePath;
|
|
BuildTarget = InBuildTarget;
|
|
ProjectTarget = InProjectTarget;
|
|
BuildConfig = InBuildConfig;
|
|
}
|
|
|
|
public string DisplayName;
|
|
public FileReference? MacExecutablePath;
|
|
public FileReference? IOSExecutablePath;
|
|
public FileReference? TVOSExecutablePath;
|
|
public string BuildTarget;
|
|
public ProjectTarget? ProjectTarget;
|
|
public UnrealTargetConfiguration BuildConfig;
|
|
};
|
|
|
|
class XcodeExtensionInfo
|
|
{
|
|
public XcodeExtensionInfo(string InName)
|
|
{
|
|
Name = InName;
|
|
TargetDependencyGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
TargetProxyGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
TargetGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
ProductGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
ResourceBuildPhaseGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
ConfigListGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
AllConfigs = new Dictionary<string, XcodeBuildConfig>();
|
|
}
|
|
|
|
public string Name;
|
|
public string TargetDependencyGuid;
|
|
public string TargetProxyGuid;
|
|
public string TargetGuid;
|
|
public string ProductGuid;
|
|
public string ResourceBuildPhaseGuid;
|
|
public string ConfigListGuid;
|
|
public Dictionary<string, XcodeBuildConfig> AllConfigs;
|
|
|
|
public string? ConfigurationContents;
|
|
}
|
|
|
|
class XcodeProjectFile : ProjectFile
|
|
{
|
|
Dictionary<string, XcodeFileGroup> Groups = new Dictionary<string, XcodeFileGroup>();
|
|
|
|
/// <summary>
|
|
/// Constructs a new project file object
|
|
/// </summary>
|
|
/// <param name="InitFilePath">The path to the project file on disk</param>
|
|
/// <param name="BaseDir">The base directory for files within this project</param>
|
|
/// <param name="IsForDistribution">True for distribution builds</param>
|
|
/// <param name="BundleID">Override option for bundle identifier</param>
|
|
/// <param name="InAppName"></param>
|
|
/// <param name="bMakeProjectPerTarget"></param>
|
|
public XcodeProjectFile(FileReference InitFilePath, DirectoryReference BaseDir, bool IsForDistribution, string BundleID, string InAppName, bool bMakeProjectPerTarget)
|
|
: base(InitFilePath, BaseDir)
|
|
{
|
|
bForDistribution = IsForDistribution;
|
|
BundleIdentifier = BundleID;
|
|
AppName = InAppName;
|
|
this.bMakeProjectPerTarget = bMakeProjectPerTarget;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return ProjectFilePath.GetFileNameWithoutExtension();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Temporary for developing this feature
|
|
/// </summary>
|
|
bool bMakeProjectPerTarget;
|
|
|
|
/// <summary>
|
|
/// Used to mark the project for distribution (some platforms require this)
|
|
/// </summary>
|
|
bool bForDistribution = false;
|
|
|
|
/// <summary>
|
|
/// Override for bundle identifier
|
|
/// </summary>
|
|
string BundleIdentifier = "";
|
|
|
|
/// <summary>
|
|
/// Override AppName
|
|
/// </summary>
|
|
string AppName = "";
|
|
|
|
/// <summary>
|
|
/// Architectures supported for iOS
|
|
/// </summary>
|
|
UnrealArch[] SupportedIOSArchitectures = { UnrealArch.Arm64 };
|
|
|
|
/// <summary>
|
|
/// Gets Xcode file category based on its extension
|
|
/// </summary>
|
|
private string GetFileCategory(string Extension)
|
|
{
|
|
// @todo Mac: Handle more categories
|
|
switch (Extension)
|
|
{
|
|
case ".framework":
|
|
return "Frameworks";
|
|
default:
|
|
return "Sources";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets Xcode file type based on its extension
|
|
/// </summary>
|
|
private string GetFileType(string Extension)
|
|
{
|
|
// @todo Mac: Handle more file types
|
|
switch (Extension)
|
|
{
|
|
case ".c":
|
|
case ".m":
|
|
return "sourcecode.c.objc";
|
|
case ".cc":
|
|
case ".cpp":
|
|
case ".cxx":
|
|
case ".mm":
|
|
return "sourcecode.cpp.objcpp";
|
|
case ".h":
|
|
case ".inl":
|
|
case ".pch":
|
|
return "sourcecode.c.h";
|
|
case ".framework":
|
|
return "wrapper.framework";
|
|
case ".plist":
|
|
return "text.plist.xml";
|
|
case ".png":
|
|
return "image.png";
|
|
case ".icns":
|
|
return "image.icns";
|
|
default:
|
|
return "file.text";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if Extension is a known extension for files containing source code
|
|
/// </summary>
|
|
private bool IsSourceCode(string Extension)
|
|
{
|
|
return Extension == ".c" || Extension == ".cc" || Extension == ".cxx" || Extension == ".cpp" || Extension == ".m" || Extension == ".mm";
|
|
}
|
|
|
|
private bool ShouldIncludeFileInBuildPhaseSection(XcodeSourceFile SourceFile)
|
|
{
|
|
string FileExtension = SourceFile.Reference.GetExtension();
|
|
|
|
if (IsSourceCode(FileExtension))
|
|
{
|
|
foreach (string PlatformName in UnrealTargetPlatform.GetValidPlatformNames())
|
|
{
|
|
string AltName = PlatformName == "Win64" ? "windows" : PlatformName.ToLower();
|
|
if ((SourceFile.Reference.FullName.ToLower().Contains("/" + PlatformName.ToLower() + "/") || SourceFile.Reference.FullName.ToLower().Contains("/" + AltName + "/"))
|
|
&& PlatformName != "Mac" && PlatformName != "IOS" && PlatformName != "TVOS")
|
|
{
|
|
// Build phase is used for indexing only and indexing currently works only with files that can be compiled for Mac, so skip files for other platforms
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a project navigator group to which the file should belong based on its path.
|
|
/// Creates a group tree if it doesn't exist yet.
|
|
/// </summary>
|
|
public XcodeFileGroup? FindGroupByAbsolutePath(ref Dictionary<string, XcodeFileGroup> Groups, string AbsolutePath)
|
|
{
|
|
string[] Parts = AbsolutePath.Split(Path.DirectorySeparatorChar);
|
|
string CurrentPath = "/";
|
|
Dictionary<string, XcodeFileGroup> CurrentSubGroups = Groups;
|
|
|
|
for (int Index = 1; Index < Parts.Length; ++Index)
|
|
{
|
|
string Part = Parts[Index];
|
|
|
|
if (CurrentPath.Length > 1)
|
|
{
|
|
CurrentPath += Path.DirectorySeparatorChar;
|
|
}
|
|
|
|
CurrentPath += Part;
|
|
|
|
XcodeFileGroup CurrentGroup;
|
|
if (!CurrentSubGroups.ContainsKey(CurrentPath))
|
|
{
|
|
CurrentGroup = new XcodeFileGroup(Path.GetFileName(CurrentPath), CurrentPath, CurrentPath.EndsWith(".xcassets"));
|
|
CurrentSubGroups.Add(CurrentPath, CurrentGroup);
|
|
}
|
|
else
|
|
{
|
|
CurrentGroup = CurrentSubGroups[CurrentPath];
|
|
}
|
|
|
|
if (CurrentPath == AbsolutePath)
|
|
{
|
|
return CurrentGroup;
|
|
}
|
|
|
|
CurrentSubGroups = CurrentGroup.Children;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert all paths to Apple/Unix format (with forward slashes)
|
|
/// </summary>
|
|
/// <param name="InPath">The path to convert</param>
|
|
/// <returns>The normalized path</returns>
|
|
private static string ConvertPath(string InPath)
|
|
{
|
|
return InPath.Replace("\\", "/");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Allocates a generator-specific source file object
|
|
/// </summary>
|
|
/// <param name="InitFilePath">Path to the source file on disk</param>
|
|
/// <param name="InitProjectSubFolder">Optional sub-folder to put the file in. If empty, this will be determined automatically from the file's path relative to the project file</param>
|
|
/// <returns>The newly allocated source file object</returns>
|
|
public override SourceFile? AllocSourceFile(FileReference InitFilePath, DirectoryReference? InitProjectSubFolder)
|
|
{
|
|
if (InitFilePath.GetFileName().StartsWith("."))
|
|
{
|
|
return null;
|
|
}
|
|
return new XcodeSourceFile(InitFilePath, InitProjectSubFolder);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates bodies of all sections that contain a list of source files plus a dictionary of project navigator groups.
|
|
/// </summary>
|
|
private void GenerateSectionsWithSourceFiles(StringBuilder PBXBuildFileSection, StringBuilder PBXFileReferenceSection, StringBuilder PBXSourcesBuildPhaseSection, string TargetAppGuid, string TargetName, bool bIsAppBundle)
|
|
{
|
|
SourceFiles.Sort((x, y) => { return x.Reference.FullName.CompareTo(y.Reference.FullName); });
|
|
|
|
foreach (XcodeSourceFile SourceFile in SourceFiles.OfType<XcodeSourceFile>())
|
|
{
|
|
string FileName = SourceFile.Reference.GetFileName();
|
|
string FileExtension = Path.GetExtension(FileName);
|
|
string FilePath = SourceFile.Reference.MakeRelativeTo(ProjectFilePath.Directory);
|
|
string FilePathMac = Utils.CleanDirectorySeparators(FilePath, '/');
|
|
|
|
if (IsGeneratedProject)
|
|
{
|
|
PBXBuildFileSection.Append(String.Format("\t\t{0} /* {1} in {2} */ = {{isa = PBXBuildFile; fileRef = {3} /* {1} */; }};" + ProjectFileGenerator.NewLine,
|
|
SourceFile.FileGuid,
|
|
FileName,
|
|
GetFileCategory(FileExtension),
|
|
SourceFile.FileRefGuid));
|
|
}
|
|
|
|
PBXFileReferenceSection.Append(String.Format("\t\t{0} /* {1} */ = {{isa = PBXFileReference; explicitFileType = {2}; name = \"{1}\"; path = \"{3}\"; sourceTree = SOURCE_ROOT; }};" + ProjectFileGenerator.NewLine,
|
|
SourceFile.FileRefGuid,
|
|
FileName,
|
|
GetFileType(FileExtension),
|
|
FilePathMac));
|
|
|
|
if (ShouldIncludeFileInBuildPhaseSection(SourceFile))
|
|
{
|
|
PBXSourcesBuildPhaseSection.Append("\t\t\t\t" + SourceFile.FileGuid + " /* " + FileName + " in Sources */," + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
XcodeFileGroup? Group = FindGroupByAbsolutePath(ref Groups, SourceFile.Reference.Directory.FullName);
|
|
Group?.Files.Add(SourceFile);
|
|
}
|
|
|
|
PBXFileReferenceSection.Append(String.Format("\t\t{0} /* {1} */ = {{isa = PBXFileReference; explicitFileType = {2}; path = {1}; sourceTree = BUILT_PRODUCTS_DIR; }};" + ProjectFileGenerator.NewLine, TargetAppGuid, TargetName, bIsAppBundle ? "wrapper.application" : "\"compiled.mach-o.executable\""));
|
|
}
|
|
|
|
private void GenerateSectionsWithExtensions(StringBuilder PBXBuildFileSection, StringBuilder PBXFileReferenceSection, StringBuilder PBXCopyFilesBuildPhaseSection, StringBuilder PBXResourcesBuildPhaseSection,
|
|
List<XcodeExtensionInfo> AllExtensions, FileReference? UProjectPath, List<XcodeBuildConfig> BuildConfigs, ILogger Logger)
|
|
{
|
|
if (UProjectPath != null)
|
|
{
|
|
string ProjectExtensionsDir = Path.Combine(Path.GetDirectoryName(UProjectPath.FullName)!, "Build/IOS/Extensions");
|
|
//string ProjectIntermediateDir = Path.Combine(Path.GetDirectoryName(UProjectPath.FullName), "Intermediate/IOS/Extensions");
|
|
|
|
if (Directory.Exists(ProjectExtensionsDir))
|
|
{
|
|
foreach (DirectoryInfo DI in new System.IO.DirectoryInfo(ProjectExtensionsDir).EnumerateDirectories())
|
|
{
|
|
Console.WriteLine(" Project {0} has Extension {1}!", UProjectPath, DI);
|
|
|
|
// assume each Extension in here will create a resulting Extension.appex
|
|
string Extension = DI.Name + ".appex";
|
|
|
|
string ExtensionGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
|
|
// make an extension info object
|
|
XcodeExtensionInfo ExtensionInfo = new XcodeExtensionInfo(DI.Name);
|
|
AllExtensions.Add(ExtensionInfo);
|
|
|
|
PBXBuildFileSection.Append(String.Format("\t\t{0} /* {1} in Embed App Extensions */ = {{isa = PBXBuildFile; fileRef = {2} /* {1} */; settings = {{ATTRIBUTES = (RemoveHeadersOnCopy, ); }}; }};" + ProjectFileGenerator.NewLine,
|
|
ExtensionGuid,
|
|
Extension,
|
|
ExtensionInfo.ProductGuid));
|
|
|
|
PBXFileReferenceSection.Append(String.Format("\t\t{0} /* {1} */ = {{isa = PBXFileReference; explicitFileType = wrapper.app-extension; path = \"{1}\"; sourceTree = BUILT_PRODUCTS_DIR; }};" + ProjectFileGenerator.NewLine,
|
|
ExtensionInfo.ProductGuid,
|
|
Extension));
|
|
|
|
PBXCopyFilesBuildPhaseSection.Append(String.Format("\t\t\t\t{0} /* {1} in Embed App Extensions */," + ProjectFileGenerator.NewLine,
|
|
ExtensionGuid,
|
|
Extension));
|
|
|
|
PBXResourcesBuildPhaseSection.Append("/* Begin PBXResourcesBuildPhase section */" + ProjectFileGenerator.NewLine);
|
|
PBXResourcesBuildPhaseSection.Append("\t\t" + ExtensionInfo.ResourceBuildPhaseGuid + " /* Resources */ = {" + ProjectFileGenerator.NewLine);
|
|
PBXResourcesBuildPhaseSection.Append("\t\t\tisa = PBXResourcesBuildPhase;" + ProjectFileGenerator.NewLine);
|
|
PBXResourcesBuildPhaseSection.Append("\t\t\tbuildActionMask = 2147483647;" + ProjectFileGenerator.NewLine);
|
|
PBXResourcesBuildPhaseSection.Append("\t\t\tfiles = (" + ProjectFileGenerator.NewLine);
|
|
if (Directory.Exists(Path.Combine(DI.FullName, "Resources")))
|
|
{
|
|
DirectoryInfo ResourceDir = new System.IO.DirectoryInfo(Path.Combine(DI.FullName, "Resources"));
|
|
foreach (FileSystemInfo FSI in ResourceDir.EnumerateFileSystemInfos())
|
|
{
|
|
if (FSI.Name.StartsWith("."))
|
|
{
|
|
continue;
|
|
}
|
|
// for each resource, put it into the File/FileRef section, and into the CopyResuorceBuildPhase
|
|
string ResourceGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string ResourceRefGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
PBXBuildFileSection.Append(String.Format("\t\t{0} /* {1} in Embed App Extensions */ = {{isa = PBXBuildFile; fileRef = {2} /* {1} */; }};" + ProjectFileGenerator.NewLine,
|
|
ResourceGuid,
|
|
FSI.Name,
|
|
ResourceRefGuid));
|
|
|
|
// lastKnownFileType = wrapper.app-extension;
|
|
PBXFileReferenceSection.Append(String.Format("\t\t{0} /* {1} */ = {{isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = \"{2}\"; sourceTree = \"<absolute>\"; }};" + ProjectFileGenerator.NewLine,
|
|
ResourceRefGuid,
|
|
FSI.Name,
|
|
// @todo: make this relative path!!
|
|
FSI.FullName));
|
|
|
|
PBXResourcesBuildPhaseSection.Append("\t\t\t\t" + ResourceGuid + " /* " + FSI.Name + " in " + ResourceDir.Name + " */," + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
PBXResourcesBuildPhaseSection.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
PBXResourcesBuildPhaseSection.Append("\t\t\trunOnlyForDeploymentPostprocessing = 0;" + ProjectFileGenerator.NewLine);
|
|
PBXResourcesBuildPhaseSection.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
PBXResourcesBuildPhaseSection.Append("/* End PBXResourcesBuildPhase section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
|
|
StringBuilder ConfigSection = new StringBuilder();
|
|
// copy over the configs from the general project to the extension
|
|
foreach (XcodeBuildConfig Configuration in BuildConfigs)
|
|
{
|
|
string ConfigGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string ConfigName = Configuration.DisplayName;
|
|
|
|
ConfigSection.Append("\t\t" + ConfigGuid + " /* " + ConfigName + " */ = {" + ProjectFileGenerator.NewLine);
|
|
ConfigSection.Append("\t\t\tisa = XCBuildConfiguration;" + ProjectFileGenerator.NewLine);
|
|
ConfigSection.Append("\t\t\tbuildSettings = {" + ProjectFileGenerator.NewLine);
|
|
ConfigSection.Append("\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = \"iMessage App Icon\";" + ProjectFileGenerator.NewLine);
|
|
ConfigSection.Append("\t\t\t\tINFOPLIST_FILE = \"" + Path.Combine(DI.FullName, "Info.plist") + "\";" + ProjectFileGenerator.NewLine);
|
|
ConfigSection.Append("\t\t\t\tSKIP_INSTALL = YES;" + ProjectFileGenerator.NewLine);
|
|
ConfigSection.Append("\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";" + ProjectFileGenerator.NewLine);
|
|
|
|
bool bSupportIOS = true;
|
|
bool bSupportTVOS = true;
|
|
if (bSupportIOS && InstalledPlatformInfo.IsValidPlatform(UnrealTargetPlatform.IOS, EProjectType.Code))
|
|
{
|
|
IOSPlatform IOSPlatform = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS));
|
|
IOSProjectSettings ProjectSettings = IOSPlatform.ReadProjectSettings(UProjectPath);
|
|
ConfigSection.Append("\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]\" = " + ProjectSettings.BundleIdentifier + "." + ExtensionInfo.Name + ";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
if (bSupportTVOS && InstalledPlatformInfo.IsValidPlatform(UnrealTargetPlatform.TVOS, EProjectType.Code))
|
|
{
|
|
TVOSPlatform TVOSPlatform = ((TVOSPlatform)UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.TVOS));
|
|
TVOSProjectSettings ProjectSettings = TVOSPlatform.ReadProjectSettings(UProjectPath);
|
|
ConfigSection.Append("\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=appletvos*]\" = " + ProjectSettings.BundleIdentifier + "." + ExtensionInfo.Name + ";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
string? IOSRuntimeVersion, TVOSRuntimeVersion;
|
|
AppendPlatformConfiguration(ConfigSection, Configuration, ExtensionInfo.Name, UProjectPath, false, bSupportIOS, bSupportTVOS, Logger, out IOSRuntimeVersion, out TVOSRuntimeVersion);
|
|
|
|
ConfigSection.Append("\t\t\t};" + ProjectFileGenerator.NewLine);
|
|
ConfigSection.Append("\t\t\tname = \"" + ConfigName + "\";" + ProjectFileGenerator.NewLine);
|
|
ConfigSection.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
|
|
XcodeBuildConfig Config = new XcodeBuildConfig(ConfigName, ExtensionInfo.Name, null, null, null, null, Configuration.BuildConfig);
|
|
ExtensionInfo.AllConfigs.Add(ConfigGuid, Config);
|
|
}
|
|
|
|
ExtensionInfo.ConfigurationContents = ConfigSection.ToString();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AppendGroup(XcodeFileGroup Group, StringBuilder Content)
|
|
{
|
|
if (!Group.bIsReference)
|
|
{
|
|
Content.Append(String.Format("\t\t{0} = {{{1}", Group.GroupGuid, ProjectFileGenerator.NewLine));
|
|
Content.Append("\t\t\tisa = PBXGroup;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tchildren = (" + ProjectFileGenerator.NewLine);
|
|
|
|
foreach (XcodeFileGroup ChildGroup in Group.Children.Values)
|
|
{
|
|
Content.Append(String.Format("\t\t\t\t{0} /* {1} */,{2}", ChildGroup.GroupGuid, ChildGroup.GroupName, ProjectFileGenerator.NewLine));
|
|
}
|
|
|
|
foreach (XcodeSourceFile File in Group.Files)
|
|
{
|
|
Content.Append(String.Format("\t\t\t\t{0} /* {1} */,{2}", File.FileRefGuid, File.Reference.GetFileName(), ProjectFileGenerator.NewLine));
|
|
}
|
|
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = \"" + Group.GroupName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tpath = \"" + Group.GroupPath + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tsourceTree = \"<absolute>\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
|
|
foreach (XcodeFileGroup ChildGroup in Group.Children.Values)
|
|
{
|
|
AppendGroup(ChildGroup, Content);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AppendBuildFileSection(StringBuilder Content, StringBuilder SectionContent)
|
|
{
|
|
Content.Append("/* Begin PBXBuildFile section */" + ProjectFileGenerator.NewLine);
|
|
Content.Append(SectionContent);
|
|
Content.Append("/* End PBXBuildFile section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendFileReferenceSection(StringBuilder Content, StringBuilder SectionContent)
|
|
{
|
|
Content.Append("/* Begin PBXFileReference section */" + ProjectFileGenerator.NewLine);
|
|
Content.Append(SectionContent);
|
|
Content.Append("/* End PBXFileReference section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendSourcesBuildPhaseSection(StringBuilder Content, StringBuilder SectionContent, string SourcesBuildPhaseGuid)
|
|
{
|
|
Content.Append("/* Begin PBXSourcesBuildPhase section */" + ProjectFileGenerator.NewLine);
|
|
Content.Append(String.Format("\t\t{0} = {{{1}", SourcesBuildPhaseGuid, ProjectFileGenerator.NewLine));
|
|
Content.Append("\t\t\tisa = PBXSourcesBuildPhase;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildActionMask = 2147483647;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tfiles = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append(SectionContent);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\trunOnlyForDeploymentPostprocessing = 0;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("/* End PBXSourcesBuildPhase section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private XcodeFileGroup? FindRootFileGroup(Dictionary<string, XcodeFileGroup> GroupsDict)
|
|
{
|
|
foreach (XcodeFileGroup Group in GroupsDict.Values)
|
|
{
|
|
if (Group.Children.Count > 1 || Group.Files.Count > 0)
|
|
{
|
|
return Group;
|
|
}
|
|
else
|
|
{
|
|
XcodeFileGroup? Found = FindRootFileGroup(Group.Children);
|
|
if (Found != null)
|
|
{
|
|
return Found;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void AppendCopyExtensionsBuildPhaseSection(StringBuilder Content, StringBuilder SectionContent, string CopyFilesBuildPhaseGuid)
|
|
{
|
|
Content.Append("/* Begin PBXCopyFilesBuildPhase section */" + ProjectFileGenerator.NewLine);
|
|
Content.Append(String.Format("\t{0} /* Embed App Extensions */ = {{{1}", CopyFilesBuildPhaseGuid, ProjectFileGenerator.NewLine));
|
|
Content.Append("\t\tisa = PBXCopyFilesBuildPhase;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\tbuildActionMask = 2147483647;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\tdstPath = \"\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\tdstSubfolderSpec = 13;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\tfiles = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append(SectionContent);
|
|
Content.Append("\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\tname = \"Embed App Extensions\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\trunOnlyForDeploymentPostprocessing = 0;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("/* End PBXCopyFilesBuildPhase section */" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendGroupSection(StringBuilder Content, string MainGroupGuid, string ProductRefGroupGuid, string TargetAppGuid, string TargetName, List<XcodeExtensionInfo> AllExtensions)
|
|
{
|
|
XcodeFileGroup? RootGroup = FindRootFileGroup(Groups);
|
|
if (RootGroup == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Content.Append("/* Begin PBXGroup section */" + ProjectFileGenerator.NewLine);
|
|
|
|
// Main group
|
|
Content.Append(String.Format("\t\t{0} = {{{1}", MainGroupGuid, ProjectFileGenerator.NewLine));
|
|
Content.Append("\t\t\tisa = PBXGroup;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tchildren = (" + ProjectFileGenerator.NewLine);
|
|
|
|
foreach (XcodeFileGroup Group in RootGroup.Children.Values)
|
|
{
|
|
Content.Append(String.Format("\t\t\t\t{0} /* {1} */,{2}", Group.GroupGuid, Group.GroupName, ProjectFileGenerator.NewLine));
|
|
}
|
|
|
|
foreach (XcodeSourceFile File in RootGroup.Files)
|
|
{
|
|
Content.Append(String.Format("\t\t\t\t{0} /* {1} */,{2}", File.FileRefGuid, File.Reference.GetFileName(), ProjectFileGenerator.NewLine));
|
|
}
|
|
|
|
Content.Append(String.Format("\t\t\t\t{0} /* Products */,{1}", ProductRefGroupGuid, ProjectFileGenerator.NewLine));
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tsourceTree = \"<group>\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
|
|
// Sources groups
|
|
foreach (XcodeFileGroup Group in RootGroup.Children.Values)
|
|
{
|
|
AppendGroup(Group, Content);
|
|
}
|
|
|
|
// Products group
|
|
Content.Append(String.Format("\t\t{0} /* Products */ = {{{1}", ProductRefGroupGuid, ProjectFileGenerator.NewLine));
|
|
Content.Append("\t\t\tisa = PBXGroup;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tchildren = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append(String.Format("\t\t\t\t{0} /* {1} */,{2}", TargetAppGuid, TargetName, ProjectFileGenerator.NewLine));
|
|
foreach (XcodeExtensionInfo EI in AllExtensions)
|
|
{
|
|
Content.Append(String.Format("\t\t\t\t{0} /* {1} */,{2}", EI.ProductGuid, EI.Name, ProjectFileGenerator.NewLine));
|
|
}
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = Products;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tsourceTree = \"<group>\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("/* End PBXGroup section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendLegacyTargetSection(StringBuilder Content, string TargetName, string TargetGuid, string TargetBuildConfigGuid, FileReference? UProjectPath)
|
|
{
|
|
string UEDir = ConvertPath(Path.GetFullPath(Directory.GetCurrentDirectory() + "../../.."));
|
|
string BuildToolPath = UEDir + "/Engine/Build/BatchFiles/Mac/XcodeBuild.sh";
|
|
|
|
Content.Append("/* Begin PBXLegacyTarget section */" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("\t\t" + TargetGuid + " /* " + TargetName + " */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = PBXLegacyTarget;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildArgumentsString = \"$(ACTION) $(UE_BUILD_TARGET_NAME) $(PLATFORM_NAME) $(UE_BUILD_TARGET_CONFIG)"
|
|
+ (UProjectPath == null ? "" : " \\\"" + UProjectPath.FullName + "\\\"")
|
|
+ "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildConfigurationList = " + TargetBuildConfigGuid + " /* Build configuration list for PBXLegacyTarget \"" + TargetName + "\" */;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildPhases = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildToolPath = \"" + BuildToolPath + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildWorkingDirectory = \"" + UEDir + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tdependencies = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tpassBuildSettingsInEnvironment = 1;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tproductName = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("/* End PBXLegacyTarget section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendRunTargetSection(StringBuilder Content, string TargetName, string TargetGuid, string TargetBuildConfigGuid, string TargetDependencyGuid,
|
|
string TargetAppGuid, string CopyExtensionsBuildPhaseGuid, string ShellScriptSectionGuid, List<XcodeExtensionInfo> AllExtensions, bool bIsAppBundle)
|
|
{
|
|
List<string> DependencyGuids = new List<string>();
|
|
// depends on the Run target if we want one
|
|
if (!XcodeProjectFileGenerator.bGenerateRunOnlyProject)
|
|
{
|
|
DependencyGuids.Add(TargetDependencyGuid);
|
|
}
|
|
// make sure extensions get built
|
|
foreach (XcodeExtensionInfo EI in AllExtensions)
|
|
{
|
|
DependencyGuids.Add(EI.TargetDependencyGuid);
|
|
}
|
|
|
|
Dictionary<string, string> BuildPhases = new Dictionary<string, string>();
|
|
// add optional build phases
|
|
if (!String.IsNullOrEmpty(CopyExtensionsBuildPhaseGuid))
|
|
{
|
|
BuildPhases.Add(CopyExtensionsBuildPhaseGuid, "Embed App Extensions");
|
|
}
|
|
if (!String.IsNullOrEmpty(ShellScriptSectionGuid))
|
|
{
|
|
BuildPhases.Add(ShellScriptSectionGuid, "Shell Script");
|
|
}
|
|
|
|
// use generica target section function for an application type
|
|
AppendGenericTargetSection(Content, TargetName, TargetGuid, bIsAppBundle ? "com.apple.product-type.application" : "com.apple.product-type.tool", TargetBuildConfigGuid, TargetAppGuid, DependencyGuids, BuildPhases);
|
|
}
|
|
|
|
private void AppendGenericTargetSection(StringBuilder Content, string TargetName, string TargetGuid, string TargetType, string TargetBuildConfigGuid, string TargetAppGuid, IEnumerable<string>? TargetDependencyGuids, Dictionary<string, string> BuildPhases)
|
|
{
|
|
Content.Append("/* Begin PBXNativeTarget section */" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("\t\t" + TargetGuid + " /* " + TargetName + " */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = PBXNativeTarget;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildConfigurationList = " + TargetBuildConfigGuid + " /* Build configuration list for PBXNativeTarget \"" + TargetName + "\" */;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildPhases = (" + ProjectFileGenerator.NewLine);
|
|
if (BuildPhases != null)
|
|
{
|
|
foreach (KeyValuePair<string, string> BuildPhasePair in BuildPhases)
|
|
{
|
|
Content.Append("\t\t\t\t" + BuildPhasePair.Key + " /* " + BuildPhasePair.Value + " */, " + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tdependencies = (" + ProjectFileGenerator.NewLine);
|
|
if (TargetDependencyGuids != null)
|
|
{
|
|
foreach (string DependencyGuid in TargetDependencyGuids)
|
|
{
|
|
Content.Append("\t\t\t\t" + DependencyGuid + " /* PBXTargetDependency */," + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tpassBuildSettingsInEnvironment = 1;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tproductName = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tproductReference = \"" + TargetAppGuid + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tproductType = \"" + TargetType + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("/* End PBXNativeTarget section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendIndexTargetSection(StringBuilder Content, string TargetName, string TargetGuid, string TargetBuildConfigGuid, string SourcesBuildPhaseGuid)
|
|
{
|
|
Content.Append("/* Begin PBXNativeTarget section */" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("\t\t" + TargetGuid + " /* " + TargetName + " */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = PBXNativeTarget;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildConfigurationList = " + TargetBuildConfigGuid + " /* Build configuration list for PBXNativeTarget \"" + TargetName + "\" */;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildPhases = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t" + SourcesBuildPhaseGuid + " /* Sources */," + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tdependencies = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tpassBuildSettingsInEnvironment = 1;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tproductName = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tproductType = \"com.apple.product-type.library.static\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("/* End PBXNativeTarget section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendShellScriptSection(StringBuilder Content, string ShellScriptGuid, FileReference? UProjectPath)
|
|
{
|
|
StringBuilder FrameworkScript = new StringBuilder();
|
|
|
|
if (UProjectPath != null)
|
|
{
|
|
|
|
// @todo: look also in Project/Build/Frameworks directory!
|
|
ProjectDescriptor Project = ProjectDescriptor.FromFile(UProjectPath);
|
|
List<PluginInfo> AvailablePlugins = Plugins.ReadAvailablePlugins(Unreal.EngineDirectory, DirectoryReference.FromFile(UProjectPath), Project.AdditionalPluginDirectories);
|
|
|
|
// look in each plugin for frameworks
|
|
// @todo: Cache this kind of things since every target will re-do this work!
|
|
foreach (PluginInfo PI in AvailablePlugins)
|
|
{
|
|
if (!Plugins.IsPluginEnabledForTarget(PI, Project, UnrealTargetPlatform.IOS, UnrealTargetConfiguration.Development, TargetRules.TargetType.Game))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// for now, we copy and code sign all *.framework.zip, even if the have no code (non-code frameworks are assumed to be *.embeddedframework.zip
|
|
DirectoryReference FrameworkDir = DirectoryReference.Combine(PI.Directory, "Source/Frameworks");
|
|
if (!DirectoryReference.Exists(FrameworkDir))
|
|
{
|
|
FrameworkDir = DirectoryReference.Combine(PI.Directory, "Frameworks");
|
|
}
|
|
if (DirectoryReference.Exists(FrameworkDir))
|
|
{
|
|
// look at each zip
|
|
foreach (FileInfo FI in new System.IO.DirectoryInfo(FrameworkDir.FullName).EnumerateFiles("*.framework.zip"))
|
|
{
|
|
//string Guid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
//string RefGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
|
|
// for FI of foo.framework.zip, this will give us foo.framework
|
|
//string Framework = Path.GetFileNameWithoutExtension(FI.FullName);
|
|
|
|
// unzip the framework right into the .app
|
|
FrameworkScript.AppendFormat("\\techo Unzipping {0}...\\n", FI.FullName);
|
|
FrameworkScript.AppendFormat("\\tunzip -o -q {0} -d ${{FRAMEWORK_DIR}} -x \\\"__MACOSX/*\\\" \\\"*/.DS_Store\\\"\\n", FI.FullName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
string ShellScript = "set -e\\n\\nIFS=$'\\\\n'\\n\\n" +
|
|
"if [ $PLATFORM_NAME = iphoneos ] || [ $PLATFORM_NAME = tvos ]; then \\n" +
|
|
"\\tFRAMEWORK_DIR=$TARGET_BUILD_DIR/$EXECUTABLE_FOLDER_PATH/Frameworks\\n" +
|
|
FrameworkScript.ToString() +
|
|
// and now code sign anything that has been unzipped above
|
|
"\\tfor FRAMEWORK in ${FRAMEWORK_DIR}/*.framework; do\\n" +
|
|
"\\t\\t[ -d \\\"${FRAMEWORK}\\\" ] || continue\\n" +
|
|
"\\t\\techo Codesigning ${FRAMEWORK}\\n" +
|
|
"\\t\\tcodesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --generate-entitlement-der --verbose --preserve-metadata=identifier,entitlements,flags --timestamp=none \\\"${FRAMEWORK}\\\"\\n" +
|
|
"\\tdone\\n" +
|
|
"fi\\n";
|
|
|
|
Content.Append("/* Begin PBXShellScriptBuildPhase section */" + ProjectFileGenerator.NewLine);
|
|
Content.Append(String.Format("\t\t{0} /* Sign Frameworks */ = {{" + ProjectFileGenerator.NewLine, ShellScriptGuid));
|
|
Content.Append("\t\t\tisa = PBXShellScriptBuildPhase;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildActionMask = 2147483647;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tfiles = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tinputPaths = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\toutputPaths = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t/dev/null" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = \"Sign Manual Frameworks\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\trunOnlyForDeploymentPostprocessing = 0;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tshellPath = /bin/sh;" + ProjectFileGenerator.NewLine);
|
|
Content.Append(String.Format("\t\t\tshellScript = \"{0}\";" + ProjectFileGenerator.NewLine, ShellScript));
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("/* End PBXShellScriptBuildPhase section */" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendExtensionTargetSections(StringBuilder ProjectFileContent, List<XcodeExtensionInfo> AllExtensions)
|
|
{
|
|
foreach (XcodeExtensionInfo EI in AllExtensions)
|
|
{
|
|
Dictionary<string, string> BuildPhases = new Dictionary<string, string>();
|
|
BuildPhases.Add(EI.ResourceBuildPhaseGuid, "Resources");
|
|
|
|
AppendGenericTargetSection(ProjectFileContent, EI.Name, EI.TargetGuid, "com.apple.product-type.app-extension.messages-sticker-pack", EI.ConfigListGuid, EI.ProductGuid, null, BuildPhases);
|
|
}
|
|
}
|
|
|
|
private void AppendProjectSection(StringBuilder Content, string TargetName, string TargetGuid, string BuildTargetName, string BuildTargetGuid, string IndexTargetName, string IndexTargetGuid, string MainGroupGuid, string ProductRefGroupGuid, string ProjectGuid, string ProjectBuildConfigGuid, FileReference? ProjectFile, List<XcodeExtensionInfo> AllExtensions)
|
|
{
|
|
Content.Append("/* Begin PBXProject section */" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("\t\t" + ProjectGuid + " /* Project object */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = PBXProject;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tattributes = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tLastUpgradeCheck = 2000;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tORGANIZATIONNAME = \"Epic Games, Inc.\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tTargetAttributes = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t\t" + TargetGuid + " = {" + ProjectFileGenerator.NewLine);
|
|
|
|
bool bAutomaticSigning = false;
|
|
if (InstalledPlatformInfo.IsValidPlatform(UnrealTargetPlatform.IOS, EProjectType.Code))
|
|
{
|
|
IOSPlatform IOSPlatform = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS));
|
|
IOSProjectSettings ProjectSettings = IOSPlatform.ReadProjectSettings(ProjectFile);
|
|
bAutomaticSigning = ProjectSettings.bAutomaticSigning;
|
|
}
|
|
|
|
if (InstalledPlatformInfo.IsValidPlatform(UnrealTargetPlatform.TVOS, EProjectType.Code))
|
|
{
|
|
TVOSPlatform TVOSPlatform = ((TVOSPlatform)UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.TVOS));
|
|
TVOSProjectSettings ProjectSettings = TVOSPlatform.ReadProjectSettings(ProjectFile);
|
|
//TVOSProvisioningData ProvisioningData = TVOSPlatform.ReadProvisioningData(ProjectSettings, bForDistribution);
|
|
bAutomaticSigning = ProjectSettings.bAutomaticSigning;
|
|
}
|
|
|
|
if (bAutomaticSigning)
|
|
{
|
|
Content.Append("\t\t\t\t\t\tProvisioningStyle = Automatic;" + ProjectFileGenerator.NewLine);
|
|
}
|
|
else
|
|
{
|
|
Content.Append("\t\t\t\t\t\tProvisioningStyle = Manual;" + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildConfigurationList = " + ProjectBuildConfigGuid + " /* Build configuration list for PBXProject \"" + TargetName + "\" */;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tcompatibilityVersion = \"Xcode 8.0\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tdevelopmentRegion = English;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\thasScannedForEncodings = 0;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tknownRegions = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\ten" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tmainGroup = " + MainGroupGuid + ";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tproductRefGroup = " + ProductRefGroupGuid + ";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tprojectDirPath = \"\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tprojectRoot = \"\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\ttargets = (" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t" + TargetGuid + " /* " + TargetName + " */," + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t" + BuildTargetGuid + " /* " + BuildTargetName + " */," + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t" + IndexTargetGuid + " /* " + IndexTargetName + " */," + ProjectFileGenerator.NewLine);
|
|
foreach (XcodeExtensionInfo EI in AllExtensions)
|
|
{
|
|
Content.Append("\t\t\t" + EI.TargetGuid + " /* " + EI.Name + " */," + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("/* End PBXProject section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendContainerItemProxySection(StringBuilder Content, string TargetName, string TargetGuid, string TargetProxyGuid, string ProjectGuid)
|
|
{
|
|
Content.Append("/* Begin PBXContainerItemProxy section */" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t" + TargetProxyGuid + " /* PBXContainerItemProxy */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = PBXContainerItemProxy;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tcontainerPortal = " + ProjectGuid + " /* Project object */;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tproxyType = 1;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tremoteGlobalIDString = " + TargetGuid + ";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tremoteInfo = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("/* End PBXContainerItemProxy section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendTargetDependencySection(StringBuilder Content, string TargetName, string TargetGuid, string TargetDependencyGuid, string TargetProxyGuid)
|
|
{
|
|
Content.Append("/* Begin PBXTargetDependency section */" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t" + TargetDependencyGuid + " /* PBXTargetDependency */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = PBXTargetDependency;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\ttarget = " + TargetGuid + " /* " + TargetName + " */;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\ttargetProxy = " + TargetProxyGuid + " /* PBXContainerItemProxy */;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("/* End PBXTargetDependency section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendProjectBuildConfiguration(StringBuilder Content, string ConfigName, string ConfigGuid)
|
|
{
|
|
Content.Append("\t\t" + ConfigGuid + " /* \"" + ConfigName + "\" */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = XCBuildConfiguration;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildSettings = {" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (" + ProjectFileGenerator.NewLine);
|
|
foreach (string Definition in IntelliSensePreprocessorDefinitions)
|
|
{
|
|
Content.Append("\t\t\t\t\t\"" + Definition.Replace("\"", "").Replace("\\", "") + "\"," + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\t\t\"__INTELLISENSE__\"," + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t\t\"MONOLITHIC_BUILD=1\"," + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("\t\t\t\tHEADER_SEARCH_PATHS = (" + ProjectFileGenerator.NewLine);
|
|
foreach (string SearchPath in IntelliSenseSystemIncludeSearchPaths)
|
|
{
|
|
string Path = SearchPath.Contains(' ') ? "\\\"" + SearchPath + "\\\"" : SearchPath;
|
|
Content.Append("\t\t\t\t\t\"" + Path + "\"," + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("\t\t\t\tUSER_HEADER_SEARCH_PATHS = (" + ProjectFileGenerator.NewLine);
|
|
foreach (string SearchPath in IntelliSenseIncludeSearchPaths)
|
|
{
|
|
string Path = SearchPath.Contains(' ') ? "\\\"" + SearchPath + "\\\"" : SearchPath;
|
|
Content.Append("\t\t\t\t\t\"" + Path + "\"," + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tONLY_ACTIVE_ARCH = YES;" + ProjectFileGenerator.NewLine);
|
|
if (ConfigName == "Debug")
|
|
{
|
|
Content.Append("\t\t\t\tENABLE_TESTABILITY = YES;" + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++14\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tGCC_ENABLE_CPP_RTTI = NO;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tGCC_WARN_CHECK_SWITCH_STATEMENTS = NO;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tUSE_HEADERMAP = NO;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = \"" + ConfigName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
// cache for the below function
|
|
Dictionary<string, UnrealArchitectures> CachedMacProjectArcitectures = new();
|
|
|
|
/// <summary>
|
|
/// Returns the Mac architectures that should be configured for the provided target. If the target has a project we'll adhere
|
|
/// to whether it's set as Intel/Universal/Apple unless the type is denied (pretty much just Editor)
|
|
///
|
|
/// If the target has no project we'll support allow-listed targets for installed builds and all non-editor architectures
|
|
/// for source builds. Not all programs are going to compile for Apple Silicon, but being able to build and fail is useful...
|
|
/// </summary>
|
|
/// <param name="Config">Build config for the target we're generating</param>
|
|
/// <param name="InProjectFile">Path to the project file, or null if the target has no project</param>
|
|
/// <returns></returns>
|
|
UnrealArchitectures GetSupportedMacArchitectures(XcodeBuildConfig Config, FileReference? InProjectFile)
|
|
{
|
|
// All architectures supported
|
|
UnrealArchitectures AllArchitectures = new(new[] { UnrealArch.Arm64, UnrealArch.X64 });
|
|
|
|
// Add a way on the command line of forcing a project file with all architectures (there isn't a good way to let this be
|
|
// set and checked where we can access it).
|
|
bool ForceAllArchitectures = Environment.GetCommandLineArgs().Contains("AllArchitectures", StringComparer.OrdinalIgnoreCase);
|
|
|
|
if (ForceAllArchitectures)
|
|
{
|
|
return AllArchitectures;
|
|
}
|
|
|
|
string TargetName = Config.BuildTarget;
|
|
|
|
// First time seeing this target?
|
|
if (!CachedMacProjectArcitectures.ContainsKey(TargetName))
|
|
{
|
|
CachedMacProjectArcitectures[TargetName] = UnrealArchitectureConfig.ForPlatform(UnrealTargetPlatform.Mac).ProjectSupportedArchitectures(InProjectFile, TargetName);
|
|
}
|
|
|
|
return CachedMacProjectArcitectures[TargetName];
|
|
}
|
|
|
|
private void AppendPlatformConfiguration(StringBuilder Content, XcodeBuildConfig Config, string TargetName, FileReference? ProjectFile, bool bSupportMac, bool bSupportIOS, bool bSupportTVOS, ILogger Logger, out string? IOSRunTimeVersion, out string? TVOSRunTimeVersion, string BinariesSubDir = "/Payload")
|
|
{
|
|
FileReference MacExecutablePath = Config.MacExecutablePath!;
|
|
|
|
string UEDir = ConvertPath(Path.GetFullPath(Directory.GetCurrentDirectory() + "../../.."));
|
|
string MacExecutableDir = bSupportMac ? ConvertPath(MacExecutablePath.Directory.FullName) : "";
|
|
string MacExecutableFileName = bSupportMac ? MacExecutablePath.GetFileName() : "";
|
|
|
|
// Get Mac architectures supported by this project
|
|
UnrealArchitectures SupportedMacArchitectures = GetSupportedMacArchitectures(Config, ProjectFile);
|
|
|
|
IOSRunTimeVersion = null;
|
|
TVOSRunTimeVersion = null;
|
|
|
|
bool bIsUnrealGame = TargetName.Equals("UnrealGame", StringComparison.InvariantCultureIgnoreCase);
|
|
bool bIsUnrealClient = TargetName.Equals("UnrealClient", StringComparison.InvariantCultureIgnoreCase);
|
|
DirectoryReference? GameDir = ProjectFile?.Directory;
|
|
string? GamePath = GameDir != null ? ConvertPath(GameDir.FullName) : null;
|
|
|
|
string? IOSRunTimeDevices = null;
|
|
string? TVOSRunTimeDevices = null;
|
|
string SupportedPlatforms = bSupportMac ? "macosx" : "";
|
|
|
|
bool bAutomaticSigning = false;
|
|
string? UUID_IOS = "";
|
|
string? UUID_TVOS = "";
|
|
string? TEAM_IOS = "";
|
|
string? TEAM_TVOS = "";
|
|
string? IOS_CERT = "iPhone Developer";
|
|
string? TVOS_CERT = "iPhone Developer";
|
|
string IOS_BUNDLE = "";
|
|
string TVOS_BUNDLE = "";
|
|
if (bSupportIOS && InstalledPlatformInfo.IsValidPlatform(UnrealTargetPlatform.IOS, EProjectType.Code))
|
|
{
|
|
IOSPlatform IOSPlatform = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS));
|
|
IOSProjectSettings ProjectSettings = IOSPlatform.ReadProjectSettings(ProjectFile);
|
|
IOSProvisioningData ProvisioningData = IOSPlatform.ReadProvisioningData(ProjectSettings, bForDistribution);
|
|
IOSRunTimeVersion = ProjectSettings.RuntimeVersion;
|
|
IOSRunTimeDevices = ProjectSettings.RuntimeDevices;
|
|
SupportedPlatforms += " iphoneos";
|
|
bAutomaticSigning = ProjectSettings.bAutomaticSigning;
|
|
if (!bAutomaticSigning)
|
|
{
|
|
UUID_IOS = ProvisioningData.MobileProvisionUUID;
|
|
IOS_CERT = ProvisioningData.SigningCertificate;
|
|
}
|
|
TEAM_IOS = ProvisioningData.TeamUUID;
|
|
IOS_BUNDLE = ProjectSettings.BundleIdentifier;
|
|
}
|
|
|
|
if (bSupportTVOS && InstalledPlatformInfo.IsValidPlatform(UnrealTargetPlatform.TVOS, EProjectType.Code))
|
|
{
|
|
TVOSPlatform TVOSPlatform = ((TVOSPlatform)UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.TVOS));
|
|
TVOSProjectSettings ProjectSettings = TVOSPlatform.ReadProjectSettings(ProjectFile);
|
|
TVOSProvisioningData ProvisioningData = TVOSPlatform.ReadProvisioningData(ProjectSettings, bForDistribution);
|
|
TVOSRunTimeVersion = ProjectSettings.RuntimeVersion;
|
|
TVOSRunTimeDevices = ProjectSettings.RuntimeDevices;
|
|
SupportedPlatforms += " appletvos";
|
|
if (!bAutomaticSigning)
|
|
{
|
|
UUID_TVOS = ProvisioningData.MobileProvisionUUID;
|
|
TVOS_CERT = ProvisioningData.SigningCertificate;
|
|
}
|
|
TEAM_TVOS = ProvisioningData.TeamUUID;
|
|
TVOS_BUNDLE = ProjectSettings.BundleIdentifier;
|
|
}
|
|
|
|
Content.Append("\t\t\t\tSUPPORTED_PLATFORMS = \"" + SupportedPlatforms.Trim() + "\";" + ProjectFileGenerator.NewLine);
|
|
if (bAutomaticSigning)
|
|
{
|
|
Content.Append("\t\t\t\tCODE_SIGN_STYLE = Automatic;" + ProjectFileGenerator.NewLine);
|
|
}
|
|
if (IOSRunTimeVersion != null)
|
|
{
|
|
Content.Append("\t\t\t\t\"VALID_ARCHS[sdk=iphoneos*]\" = \"" + String.Join(" ", SupportedIOSArchitectures) + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = " + IOSRunTimeVersion + ";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t\"PRODUCT_NAME[sdk=iphoneos*]\" = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine); // @todo: change to Path.GetFileName(Config.IOSExecutablePath) when we stop using payload
|
|
Content.Append("\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=iphoneos*]\" = \"" + IOSRunTimeDevices + "\";" + ProjectFileGenerator.NewLine);
|
|
if (!String.IsNullOrEmpty(TEAM_IOS))
|
|
{
|
|
Content.Append("\t\t\t\t\"DEVELOPMENT_TEAM[sdk=iphoneos*]\" = " + TEAM_IOS + ";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"" + IOS_CERT + "\";" + ProjectFileGenerator.NewLine);
|
|
if (!bAutomaticSigning && !String.IsNullOrEmpty(UUID_IOS))
|
|
{
|
|
Content.Append("\t\t\t\t\"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]\" = \"" + UUID_IOS + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
if (ProjectFile != null)
|
|
{
|
|
Content.Append("\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]\" = " + IOS_BUNDLE + ";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
if (TVOSRunTimeVersion != null)
|
|
{
|
|
Content.Append("\t\t\t\t\"VALID_ARCHS[sdk=appletvos*]\" = \"" + String.Join(" ", SupportedIOSArchitectures) + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tTVOS_DEPLOYMENT_TARGET = " + TVOSRunTimeVersion + ";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t\"PRODUCT_NAME[sdk=appletvos*]\" = \"" + TargetName + "\";" + ProjectFileGenerator.NewLine); // @todo: change to Path.GetFileName(Config.TVOSExecutablePath) when we stop using payload
|
|
Content.Append("\t\t\t\t\"TARGETED_DEVICE_FAMILY[sdk=appletvos*]\" = \"" + TVOSRunTimeDevices + "\";" + ProjectFileGenerator.NewLine);
|
|
if (!String.IsNullOrEmpty(TEAM_TVOS))
|
|
{
|
|
Content.Append("\t\t\t\t\"DEVELOPMENT_TEAM[sdk=appletvos*]\" = " + TEAM_TVOS + ";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=appletvos*]\" = \"" + TVOS_CERT + "\";" + ProjectFileGenerator.NewLine);
|
|
if (!bAutomaticSigning && !String.IsNullOrEmpty(UUID_TVOS))
|
|
{
|
|
Content.Append("\t\t\t\t\"PROVISIONING_PROFILE_SPECIFIER[sdk=appletvos*]\" = \"" + UUID_TVOS + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
if (ProjectFile != null)
|
|
{
|
|
Content.Append("\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=appletvos*]\" = " + TVOS_BUNDLE + ";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
if (bSupportMac)
|
|
{
|
|
Content.Append("\t\t\t\t\"VALID_ARCHS[sdk=macosx*]\" = \"" + String.Join(" ", SupportedMacArchitectures.Architectures.Select(x => x.AppleName)) + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t\"PRODUCT_NAME[sdk=macosx*]\" = \"" + MacExecutableFileName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t\"CONFIGURATION_BUILD_DIR[sdk=macosx*]\" = \"" + MacExecutableDir + "\";" + ProjectFileGenerator.NewLine);
|
|
|
|
// MacToolchain uses the IOS bundle identifier
|
|
ConfigHierarchy IOSIni = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, ProjectFile?.Directory, UnrealTargetPlatform.IOS);
|
|
string IOSBundleIdentifier;
|
|
IOSIni.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleIdentifier", out IOSBundleIdentifier!);
|
|
|
|
// we are going to load/sign the UnrealEditor.app when doing modular editor builds, so reuse the shared identifier
|
|
bool bBuildingEditor = Config.ProjectTarget!.TargetRules!.Type == TargetType.Editor && Config.ProjectTarget!.TargetRules!.LinkType == TargetLinkType.Modular;
|
|
string MacBundleIdentifier = bBuildingEditor ? ("com.epicgames.UnrealEditor") : (IOSBundleIdentifier.Replace("[PROJECT_NAME]", TargetName).Replace("_", ""));
|
|
// Xcode 14 wants this to match what is in the final plist
|
|
Content.Append("\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*]\" = " + MacBundleIdentifier + ";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
if (IOSRunTimeVersion != null)
|
|
{
|
|
Content.Append("\t\t\t\t\"CONFIGURATION_BUILD_DIR[sdk=iphoneos*]\" = \"" + Config.IOSExecutablePath!.Directory!.FullName + BinariesSubDir + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
if (TVOSRunTimeVersion != null)
|
|
{
|
|
Content.Append("\t\t\t\t\"CONFIGURATION_BUILD_DIR[sdk=appletvos*]\" = \"" + Config.TVOSExecutablePath!.Directory!.FullName + BinariesSubDir + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
|
|
private void AppendNativeTargetBuildConfiguration(StringBuilder Content, XcodeBuildConfig Config, string ConfigGuid, FileReference? ProjectFile, ILogger Logger)
|
|
{
|
|
bool bMacOnly = true;
|
|
if (Config.ProjectTarget!.TargetRules != null)
|
|
{
|
|
if (XcodeProjectFileGenerator.XcodePlatforms.Contains(UnrealTargetPlatform.IOS) && Config.ProjectTarget.SupportedPlatforms.Contains(UnrealTargetPlatform.IOS))
|
|
{
|
|
bMacOnly = false;
|
|
}
|
|
if (XcodeProjectFileGenerator.XcodePlatforms.Contains(UnrealTargetPlatform.TVOS) && Config.ProjectTarget.SupportedPlatforms.Contains(UnrealTargetPlatform.TVOS))
|
|
{
|
|
bMacOnly = false;
|
|
}
|
|
}
|
|
|
|
Content.Append("\t\t" + ConfigGuid + " /* \"" + Config.DisplayName + "\" */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = XCBuildConfiguration;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildSettings = {" + ProjectFileGenerator.NewLine);
|
|
|
|
string UEDir = ConvertPath(Path.GetFullPath(Directory.GetCurrentDirectory() + "../../.."));
|
|
//string MacExecutableDir = ConvertPath(Config.MacExecutablePath.Directory.FullName);
|
|
string MacExecutableFileName = Config.MacExecutablePath!.GetFileName();
|
|
|
|
string? IOSRunTimeVersion, TVOSRunTimeVersion;
|
|
AppendPlatformConfiguration(Content, Config, Config.BuildTarget, ProjectFile, true, !bMacOnly, !bMacOnly, Logger, out IOSRunTimeVersion, out TVOSRunTimeVersion);
|
|
|
|
bool bIsUnrealGame = Config.BuildTarget.Equals("UnrealGame", StringComparison.InvariantCultureIgnoreCase);
|
|
bool bIsUnrealClient = Config.BuildTarget.Equals("UnrealClient", StringComparison.InvariantCultureIgnoreCase);
|
|
|
|
DirectoryReference? GameDir = ProjectFile?.Directory;
|
|
string? GamePath = GameDir != null ? ConvertPath(GameDir.FullName) : null;
|
|
|
|
string IOSInfoPlistPath;
|
|
string TVOSInfoPlistPath;
|
|
string MacInfoPlistPath;
|
|
string? IOSEntitlementPath = null;
|
|
string? TVOSEntitlementPath = null;
|
|
if (bIsUnrealGame)
|
|
{
|
|
IOSInfoPlistPath = UEDir + "/Engine/Intermediate/IOS/" + Config.BuildTarget + "-Info.plist";
|
|
TVOSInfoPlistPath = UEDir + "/Engine/Intermediate/TVOS/" + Config.BuildTarget + "-Info.plist";
|
|
MacInfoPlistPath = UEDir + "/Engine/Intermediate/Mac/" + MacExecutableFileName + "-Info.plist";
|
|
IOSEntitlementPath = "";
|
|
TVOSEntitlementPath = "";
|
|
}
|
|
else if (bIsUnrealClient)
|
|
{
|
|
IOSInfoPlistPath = UEDir + "/Engine/Intermediate/IOS/UnrealGame-Info.plist";
|
|
TVOSInfoPlistPath = UEDir + "/Engine/Intermediate/TVOS/UnrealGame-Info.plist";
|
|
MacInfoPlistPath = UEDir + "/Engine/Intermediate/Mac/" + MacExecutableFileName + "-Info.plist";
|
|
IOSEntitlementPath = "";
|
|
TVOSEntitlementPath = "";
|
|
}
|
|
else if (ProjectFile != null)
|
|
{
|
|
IOSInfoPlistPath = GamePath + "/Intermediate/IOS/" + Config.BuildTarget + "-Info.plist";
|
|
TVOSInfoPlistPath = GamePath + "/Intermediate/TVOS/" + Config.BuildTarget + "-Info.plist";
|
|
MacInfoPlistPath = GamePath + "/Intermediate/Mac/" + MacExecutableFileName + "-Info.plist";
|
|
IOSEntitlementPath = GamePath + "/Intermediate/IOS/" + Config.BuildTarget + ".entitlements";
|
|
TVOSEntitlementPath = GamePath + "/Intermediate/TVOS/" + Config.BuildTarget + ".entitlements";
|
|
}
|
|
else
|
|
{
|
|
if (GamePath == null)
|
|
{
|
|
IOSInfoPlistPath = UEDir + "/Engine/Intermediate/IOS/" + Config.BuildTarget + "-Info.plist";
|
|
TVOSInfoPlistPath = UEDir + "/Engine/Intermediate/TVOS/" + Config.BuildTarget + "-Info.plist";
|
|
MacInfoPlistPath = UEDir + "/Engine/Intermediate/Mac/" + MacExecutableFileName + "-Info.plist";
|
|
}
|
|
else
|
|
{
|
|
IOSInfoPlistPath = GamePath + "/Intermediate/IOS/" + Config.BuildTarget + "-Info.plist";
|
|
TVOSInfoPlistPath = GamePath + "/Intermediate/TVOS/" + Config.BuildTarget + "-Info.plist";
|
|
MacInfoPlistPath = GamePath + "/Intermediate/Mac/" + MacExecutableFileName + "-Info.plist";
|
|
}
|
|
}
|
|
|
|
if (XcodeProjectFileGenerator.bGenerateRunOnlyProject)
|
|
{
|
|
if (XcodeProjectFileGenerator.XcodePlatforms.Contains(UnrealTargetPlatform.IOS))
|
|
{
|
|
Content.Append("\t\t\t\tINFOPLIST_FILE = \"" + IOSInfoPlistPath + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"" + IOSEntitlementPath + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
else
|
|
{
|
|
Content.Append("\t\t\t\tINFOPLIST_FILE = \"" + TVOSInfoPlistPath + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"" + TVOSEntitlementPath + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Content.Append("\t\t\t\t\"INFOPLIST_FILE[sdk=macosx*]\" = \"" + MacInfoPlistPath + "\";" + ProjectFileGenerator.NewLine);
|
|
if (IOSRunTimeVersion != null)
|
|
{
|
|
Content.Append("\t\t\t\t\"INFOPLIST_FILE[sdk=iphoneos*]\" = \"" + IOSInfoPlistPath + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t\"CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]\" = \"" + IOSEntitlementPath + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
if (TVOSRunTimeVersion != null)
|
|
{
|
|
Content.Append("\t\t\t\t\"INFOPLIST_FILE[sdk=appletvos*]\" = \"" + TVOSInfoPlistPath + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\t\"CODE_SIGN_ENTITLEMENTS[sdk=appletvos*]\" = \"" + TVOSEntitlementPath + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
|
|
// Prepare a temp Info.plist file so Xcode has some basic info about the target immediately after opening the project.
|
|
// This is needed for the target to pass the settings validation before code signing. UBT will overwrite this plist file later, with proper contents.
|
|
if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
|
|
{
|
|
bool bCreateMacInfoPlist = !File.Exists(MacInfoPlistPath);
|
|
bool bCreateIOSInfoPlist = !File.Exists(IOSInfoPlistPath) && IOSRunTimeVersion != null;
|
|
bool bCreateTVOSInfoPlist = !File.Exists(TVOSInfoPlistPath) && TVOSRunTimeVersion != null;
|
|
if (bCreateMacInfoPlist || bCreateIOSInfoPlist || bCreateTVOSInfoPlist)
|
|
{
|
|
DirectoryReference? ProjectPath = GameDir;
|
|
DirectoryReference EngineDir = DirectoryReference.Combine(new DirectoryReference(UEDir), "Engine");
|
|
string GameName = Config.BuildTarget;
|
|
bool bIsClient = false;
|
|
if (ProjectPath == null)
|
|
{
|
|
ProjectPath = EngineDir;
|
|
}
|
|
if (bIsUnrealGame)
|
|
{
|
|
ProjectPath = EngineDir;
|
|
GameName = "UnrealGame";
|
|
bIsClient = (AppName == "UnrealClient");
|
|
}
|
|
|
|
if (bCreateMacInfoPlist)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(MacInfoPlistPath)!);
|
|
UEDeployMac.GeneratePList(ProjectPath.FullName, bIsUnrealGame, GameName, Config.BuildTarget, EngineDir.FullName, MacExecutableFileName, Config.ProjectTarget!.TargetRules!.Type);
|
|
}
|
|
if (bCreateIOSInfoPlist)
|
|
{
|
|
// get the receipt
|
|
FileReference ReceiptFilename;
|
|
UnrealArchitectures Architectures = UnrealArchitectureConfig.ForPlatform(UnrealTargetPlatform.IOS).ActiveArchitectures(ProjectFile, GameName);
|
|
if (bIsUnrealGame)
|
|
{
|
|
ReceiptFilename = TargetReceipt.GetDefaultPath(Unreal.EngineDirectory, "UnrealGame", UnrealTargetPlatform.IOS, Config.BuildConfig, Architectures);
|
|
}
|
|
else
|
|
{
|
|
ReceiptFilename = TargetReceipt.GetDefaultPath(ProjectPath, GameName, UnrealTargetPlatform.IOS, Config.BuildConfig, Architectures);
|
|
}
|
|
Directory.CreateDirectory(Path.GetDirectoryName(IOSInfoPlistPath)!);
|
|
TargetReceipt? Receipt;
|
|
TargetReceipt.TryRead(ReceiptFilename, out Receipt);
|
|
bool bBuildAsFramework = UEDeployIOS.GetCompileAsDll(Receipt);
|
|
UEDeployIOS.GenerateIOSPList(ProjectFile, Config.BuildConfig, ProjectPath.FullName, bIsUnrealGame, GameName, bIsClient, Config.BuildTarget, EngineDir.FullName, ProjectPath + "/Binaries/IOS/Payload", null, BundleIdentifier, bBuildAsFramework, Logger);
|
|
}
|
|
if (bCreateTVOSInfoPlist)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(TVOSInfoPlistPath)!);
|
|
UEDeployTVOS.GenerateTVOSPList(ProjectPath.FullName, bIsUnrealGame, GameName, bIsClient, Config.BuildTarget, EngineDir.FullName, ProjectPath + "/Binaries/TVOS/Payload", null, BundleIdentifier, Logger);
|
|
}
|
|
}
|
|
}
|
|
|
|
// #jira UE-143619: Pre Monterey macOS requires this option for a packaged app to run on iOS15 due to new code signature format. Could be removed once Monterey is minimum OS.
|
|
Content.Append("\t\t\t\tOTHER_CODE_SIGN_FLAGS = \"--generate-entitlement-der --deep\";" + ProjectFileGenerator.NewLine);
|
|
|
|
Content.Append("\t\t\t\tMACOSX_DEPLOYMENT_TARGET = " + MacToolChainSettings.MinMacDeploymentVersion(Config.ProjectTarget!.TargetRules!.Type) + ";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tINFOPLIST_OUTPUT_FORMAT = xml;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;" + ProjectFileGenerator.NewLine);
|
|
|
|
//#jira UE-50382 Xcode Address Sanitizer feature does not work on iOS
|
|
// address sanitizer dylib loader depends on the SDKROOT parameter. For macosx or default (missing, translated as macosx), the path is incorrect for iphone/appletv
|
|
if (XcodeProjectFileGenerator.bGenerateRunOnlyProject)
|
|
{
|
|
if (XcodeProjectFileGenerator.XcodePlatforms.Contains(UnrealTargetPlatform.IOS))
|
|
{
|
|
Content.Append("\t\t\t\tSDKROOT = iphoneos;" + ProjectFileGenerator.NewLine);
|
|
}
|
|
else
|
|
{
|
|
Content.Append("\t\t\t\tSDKROOT = appletvos;" + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Content.Append("\t\t\t\tSDKROOT = macosx;" + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tGCC_PREFIX_HEADER = \"" + UEDir + "/Engine/Source/Editor/UnrealEd/Public/UnrealEd.h\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = \"" + Config.DisplayName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendLegacyTargetBuildConfiguration(StringBuilder Content, XcodeBuildConfig Config, string ConfigGuid, FileReference? ProjectFile)
|
|
{
|
|
bool bMacOnly = true;
|
|
if (Config.ProjectTarget!.TargetRules != null)
|
|
{
|
|
if (XcodeProjectFileGenerator.XcodePlatforms.Contains(UnrealTargetPlatform.IOS) && Config.ProjectTarget.SupportedPlatforms.Contains(UnrealTargetPlatform.IOS))
|
|
{
|
|
bMacOnly = false;
|
|
}
|
|
if (XcodeProjectFileGenerator.XcodePlatforms.Contains(UnrealTargetPlatform.TVOS) && Config.ProjectTarget.SupportedPlatforms.Contains(UnrealTargetPlatform.TVOS))
|
|
{
|
|
bMacOnly = false;
|
|
}
|
|
}
|
|
|
|
// Get Mac architectures supported by this project
|
|
UnrealArchitectures SupportedMacArchitectures = GetSupportedMacArchitectures(Config, ProjectFilePath);
|
|
|
|
Content.Append("\t\t" + ConfigGuid + " /* \"" + Config.DisplayName + "\" */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = XCBuildConfiguration;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildSettings = {" + ProjectFileGenerator.NewLine);
|
|
if (bMacOnly)
|
|
{
|
|
Content.Append("\t\t\t\tVALID_ARCHS = \"" + String.Join(" ", SupportedMacArchitectures.Architectures.Select(x => x.AppleName)) + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tSUPPORTED_PLATFORMS = \"macosx\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
else
|
|
{
|
|
IEnumerable<UnrealArch> ValidArchs = SupportedMacArchitectures.Architectures;
|
|
string SupportedPlatforms = "macosx";
|
|
if (InstalledPlatformInfo.IsValidPlatform(UnrealTargetPlatform.IOS, EProjectType.Code))
|
|
{
|
|
ValidArchs = ValidArchs.Union(SupportedIOSArchitectures);
|
|
SupportedPlatforms += " iphoneos";
|
|
}
|
|
if (InstalledPlatformInfo.IsValidPlatform(UnrealTargetPlatform.TVOS, EProjectType.Code))
|
|
{
|
|
ValidArchs = ValidArchs.Union(SupportedIOSArchitectures);
|
|
SupportedPlatforms += " appletvos";
|
|
}
|
|
Content.Append("\t\t\t\tVALID_ARCHS = \"" + String.Join(" ", ValidArchs.Select(x => x.AppleName)) + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tSUPPORTED_PLATFORMS = \"" + SupportedPlatforms + "\";" + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = ();" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tHEADER_SEARCH_PATHS = ();" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tUSER_HEADER_SEARCH_PATHS = ();" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tUE_BUILD_TARGET_NAME = \"" + Config.BuildTarget + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t\tUE_BUILD_TARGET_CONFIG = \"" + Config.BuildConfig + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t};" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tname = \"" + Config.DisplayName + "\";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendXCBuildConfigurationSection(StringBuilder Content, Dictionary<string, XcodeBuildConfig> ProjectBuildConfigs, Dictionary<string, XcodeBuildConfig> TargetBuildConfigs,
|
|
Dictionary<string, XcodeBuildConfig> BuildTargetBuildConfigs, Dictionary<string, XcodeBuildConfig> IndexTargetBuildConfigs, FileReference? GameProjectPath,
|
|
List<XcodeExtensionInfo> AllExtensions, ILogger Logger)
|
|
{
|
|
Content.Append("/* Begin XCBuildConfiguration section */" + ProjectFileGenerator.NewLine);
|
|
|
|
foreach (KeyValuePair<string, XcodeBuildConfig> Config in ProjectBuildConfigs)
|
|
{
|
|
AppendProjectBuildConfiguration(Content, Config.Value.DisplayName, Config.Key);
|
|
}
|
|
|
|
foreach (KeyValuePair<string, XcodeBuildConfig> Config in TargetBuildConfigs)
|
|
{
|
|
AppendNativeTargetBuildConfiguration(Content, Config.Value, Config.Key, GameProjectPath, Logger);
|
|
}
|
|
|
|
foreach (KeyValuePair<string, XcodeBuildConfig> Config in BuildTargetBuildConfigs)
|
|
{
|
|
AppendLegacyTargetBuildConfiguration(Content, Config.Value, Config.Key, GameProjectPath);
|
|
}
|
|
|
|
foreach (KeyValuePair<string, XcodeBuildConfig> Config in IndexTargetBuildConfigs)
|
|
{
|
|
AppendNativeTargetBuildConfiguration(Content, Config.Value, Config.Key, GameProjectPath, Logger);
|
|
}
|
|
|
|
foreach (XcodeExtensionInfo EI in AllExtensions)
|
|
{
|
|
Content.Append(EI.ConfigurationContents);
|
|
}
|
|
|
|
Content.Append("/* End XCBuildConfiguration section */" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendXCConfigurationList(StringBuilder Content, string TypeName, string TargetName, string ConfigListGuid, Dictionary<string, XcodeBuildConfig> BuildConfigs, string Default = "Development")
|
|
{
|
|
Content.Append("\t\t" + ConfigListGuid + " /* Build configuration list for " + TypeName + " \"" + TargetName + "\" */ = {" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tisa = XCConfigurationList;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tbuildConfigurations = (" + ProjectFileGenerator.NewLine);
|
|
foreach (KeyValuePair<string, XcodeBuildConfig> Config in BuildConfigs)
|
|
{
|
|
Content.Append("\t\t\t\t" + Config.Key + " /* \"" + Config.Value.DisplayName + "\" */," + ProjectFileGenerator.NewLine);
|
|
}
|
|
Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tdefaultConfigurationIsVisible = 0;" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\tdefaultConfigurationName = " + Default + ";" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t};" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private void AppendXCConfigurationListSection(StringBuilder Content, string TargetName, string BuildTargetName, string IndexTargetName, string ProjectConfigListGuid,
|
|
Dictionary<string, XcodeBuildConfig> ProjectBuildConfigs, string TargetConfigListGuid, Dictionary<string, XcodeBuildConfig> TargetBuildConfigs,
|
|
string BuildTargetConfigListGuid, Dictionary<string, XcodeBuildConfig> BuildTargetBuildConfigs,
|
|
string IndexTargetConfigListGuid, Dictionary<string, XcodeBuildConfig> IndexTargetBuildConfigs,
|
|
List<XcodeExtensionInfo> AllExtensions)
|
|
{
|
|
Content.Append("/* Begin XCConfigurationList section */" + ProjectFileGenerator.NewLine);
|
|
|
|
AppendXCConfigurationList(Content, "PBXProject", TargetName, ProjectConfigListGuid, ProjectBuildConfigs);
|
|
AppendXCConfigurationList(Content, "PBXLegacyTarget", BuildTargetName, BuildTargetConfigListGuid, BuildTargetBuildConfigs);
|
|
AppendXCConfigurationList(Content, "PBXNativeTarget", TargetName, TargetConfigListGuid, TargetBuildConfigs);
|
|
AppendXCConfigurationList(Content, "PBXNativeTarget", IndexTargetName, IndexTargetConfigListGuid, IndexTargetBuildConfigs);
|
|
|
|
foreach (XcodeExtensionInfo EI in AllExtensions)
|
|
{
|
|
AppendXCConfigurationList(Content, "PBXNativeTarget", EI.Name, EI.ConfigListGuid, EI.AllConfigs);
|
|
}
|
|
|
|
Content.Append("/* End XCConfigurationList section */" + ProjectFileGenerator.NewLine);
|
|
}
|
|
|
|
private List<XcodeBuildConfig> GetSupportedBuildConfigs(List<UnrealTargetPlatform> Platforms, List<UnrealTargetConfiguration> Configurations, ILogger Logger)
|
|
{
|
|
List<XcodeBuildConfig> BuildConfigs = new List<XcodeBuildConfig>();
|
|
|
|
//string ProjectName = ProjectFilePath.GetFileNameWithoutExtension();
|
|
|
|
foreach (UnrealTargetConfiguration Configuration in Configurations)
|
|
{
|
|
if (InstalledPlatformInfo.IsValidConfiguration(Configuration, EProjectType.Code))
|
|
{
|
|
foreach (UnrealTargetPlatform Platform in Platforms)
|
|
{
|
|
if (InstalledPlatformInfo.IsValidPlatform(Platform, EProjectType.Code) && (Platform == UnrealTargetPlatform.Mac || Platform == UnrealTargetPlatform.IOS || Platform == UnrealTargetPlatform.TVOS)) // @todo support other platforms
|
|
{
|
|
UEBuildPlatform? BuildPlatform;
|
|
if (UEBuildPlatform.TryGetBuildPlatform(Platform, out BuildPlatform) && (BuildPlatform.HasRequiredSDKsInstalled() == SDKStatus.Valid))
|
|
{
|
|
// Check we have targets (Expected to be no Engine targets when generating for a single .uproject)
|
|
if (ProjectTargets.Count == 0 && BaseDir != Unreal.EngineDirectory)
|
|
{
|
|
throw new BuildException("Expecting at least one ProjectTarget to be associated with project '{0}' in the TargetProjects list ", ProjectFilePath);
|
|
}
|
|
|
|
// Now go through all of the target types for this project
|
|
foreach (ProjectTarget ProjectTarget in ProjectTargets.OfType<ProjectTarget>())
|
|
{
|
|
if (MSBuildProjectFile.IsValidProjectPlatformAndConfiguration(ProjectTarget, Platform, Configuration, Logger))
|
|
{
|
|
// Figure out if this is a monolithic build
|
|
bool bShouldCompileMonolithic = BuildPlatform.ShouldCompileMonolithicBinary(Platform);
|
|
try
|
|
{
|
|
bShouldCompileMonolithic |= (ProjectTarget.CreateRulesDelegate(Platform, Configuration).LinkType == TargetLinkType.Monolithic);
|
|
}
|
|
catch (BuildException)
|
|
{
|
|
}
|
|
|
|
string ConfigName = Configuration.ToString();
|
|
if (!bMakeProjectPerTarget && ProjectTarget.TargetRules!.Type != TargetType.Game && ProjectTarget.TargetRules.Type != TargetType.Program)
|
|
{
|
|
ConfigName += " " + ProjectTarget.TargetRules.Type.ToString();
|
|
}
|
|
|
|
if (BuildConfigs.Where(Config => Config.DisplayName == ConfigName).ToList().Count == 0)
|
|
{
|
|
string TargetName = ProjectTarget.TargetFilePath.GetFileNameWithoutAnyExtensions();
|
|
// Get the .uproject directory
|
|
DirectoryReference? UProjectDirectory = DirectoryReference.FromFile(ProjectTarget.UnrealProjectFilePath);
|
|
|
|
// Get the output directory
|
|
DirectoryReference RootDirectory;
|
|
if (UProjectDirectory != null &&
|
|
(bShouldCompileMonolithic || ProjectTarget.TargetRules!.BuildEnvironment == TargetBuildEnvironment.Unique) &&
|
|
ProjectTarget.TargetRules!.File!.IsUnderDirectory(UProjectDirectory))
|
|
{
|
|
RootDirectory = UEBuildTarget.GetOutputDirectoryForExecutable(UProjectDirectory, ProjectTarget.TargetRules.File!);
|
|
}
|
|
else
|
|
{
|
|
RootDirectory = UEBuildTarget.GetOutputDirectoryForExecutable(Unreal.EngineDirectory, ProjectTarget.TargetRules!.File!);
|
|
}
|
|
|
|
string ExeName = TargetName;
|
|
if (!bShouldCompileMonolithic && ProjectTarget.TargetRules.Type != TargetType.Program)
|
|
{
|
|
// Figure out what the compiled binary will be called so that we can point the IDE to the correct file
|
|
if (ProjectTarget.TargetRules.Type != TargetType.Game)
|
|
{
|
|
// Only if shared - unique retains the Target Name
|
|
if (ProjectTarget.TargetRules.BuildEnvironment == TargetBuildEnvironment.Shared)
|
|
{
|
|
ExeName = "Unreal" + ProjectTarget.TargetRules.Type.ToString();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the output directory
|
|
DirectoryReference OutputDirectory = DirectoryReference.Combine(RootDirectory, "Binaries");
|
|
DirectoryReference MacBinaryDir = DirectoryReference.Combine(OutputDirectory, "Mac");
|
|
DirectoryReference IOSBinaryDir = DirectoryReference.Combine(OutputDirectory, "IOS");
|
|
DirectoryReference TVOSBinaryDir = DirectoryReference.Combine(OutputDirectory, "TVOS");
|
|
if (!String.IsNullOrEmpty(ProjectTarget.TargetRules.ExeBinariesSubFolder))
|
|
{
|
|
MacBinaryDir = DirectoryReference.Combine(MacBinaryDir, ProjectTarget.TargetRules.ExeBinariesSubFolder);
|
|
IOSBinaryDir = DirectoryReference.Combine(IOSBinaryDir, ProjectTarget.TargetRules.ExeBinariesSubFolder);
|
|
TVOSBinaryDir = DirectoryReference.Combine(TVOSBinaryDir, ProjectTarget.TargetRules.ExeBinariesSubFolder);
|
|
}
|
|
|
|
if (BuildPlatform.Platform == UnrealTargetPlatform.Mac)
|
|
{
|
|
string MacExecutableName = MakeExecutableFileName(ExeName, UnrealTargetPlatform.Mac, Configuration, ProjectTarget.TargetRules.Architectures, ProjectTarget.TargetRules.UndecoratedConfiguration);
|
|
string IOSExecutableName = MacExecutableName.Replace("-Mac-", "-IOS-");
|
|
string TVOSExecutableName = MacExecutableName.Replace("-Mac-", "-TVOS-");
|
|
BuildConfigs.Add(new XcodeBuildConfig(ConfigName, TargetName, FileReference.Combine(MacBinaryDir, MacExecutableName), FileReference.Combine(IOSBinaryDir, IOSExecutableName), FileReference.Combine(TVOSBinaryDir, TVOSExecutableName), ProjectTarget, Configuration));
|
|
}
|
|
else if (BuildPlatform.Platform == UnrealTargetPlatform.IOS || BuildPlatform.Platform == UnrealTargetPlatform.TVOS)
|
|
{
|
|
string IOSExecutableName = MakeExecutableFileName(ExeName, UnrealTargetPlatform.IOS, Configuration, ProjectTarget.TargetRules.Architectures, ProjectTarget.TargetRules.UndecoratedConfiguration);
|
|
string TVOSExecutableName = IOSExecutableName.Replace("-IOS-", "-TVOS-");
|
|
//string MacExecutableName = IOSExecutableName.Replace("-IOS-", "-Mac-");
|
|
BuildConfigs.Add(new XcodeBuildConfig(ConfigName, TargetName, FileReference.Combine(MacBinaryDir, IOSExecutableName), FileReference.Combine(IOSBinaryDir, IOSExecutableName), FileReference.Combine(TVOSBinaryDir, TVOSExecutableName), ProjectTarget, Configuration));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return BuildConfigs;
|
|
}
|
|
|
|
private static string MakeExecutableFileName(string BinaryName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, UnrealArchitectures Architectures, UnrealTargetConfiguration UndecoratedConfiguration)
|
|
{
|
|
StringBuilder Result = new StringBuilder();
|
|
|
|
Result.Append(BinaryName);
|
|
|
|
if (Configuration != UndecoratedConfiguration)
|
|
{
|
|
Result.AppendFormat("-{0}-{1}", Platform.ToString(), Configuration.ToString());
|
|
}
|
|
|
|
UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(Platform);
|
|
if (UnrealArchitectureConfig.ForPlatform(Platform).RequiresArchitectureFilenames(Architectures))
|
|
{
|
|
Result.Append(Architectures.ToString());
|
|
}
|
|
|
|
return Result.ToString();
|
|
}
|
|
|
|
private FileReference GetUserSchemeManagementFilePath()
|
|
{
|
|
return new FileReference(ProjectFilePath.FullName + "/xcuserdata/" + Environment.UserName + ".xcuserdatad/xcschemes/xcschememanagement.plist");
|
|
}
|
|
|
|
private DirectoryReference GetProjectSchemeDirectory()
|
|
{
|
|
return new DirectoryReference(ProjectFilePath.FullName + "/xcshareddata/xcschemes");
|
|
}
|
|
|
|
private FileReference GetProjectSchemeFilePathForTarget(string TargetName)
|
|
{
|
|
return FileReference.Combine(GetProjectSchemeDirectory(), TargetName + ".xcscheme");
|
|
}
|
|
|
|
private void WriteSchemeFile(string TargetName, string TargetGuid, string BuildTargetGuid, string IndexTargetGuid, bool bHasEditorConfiguration, string GameProjectPath)
|
|
{
|
|
|
|
FileReference SchemeFilePath = GetProjectSchemeFilePathForTarget(TargetName);
|
|
|
|
DirectoryReference.CreateDirectory(SchemeFilePath.Directory);
|
|
|
|
string? OldCommandLineArguments = null;
|
|
if (FileReference.Exists(SchemeFilePath))
|
|
{
|
|
string OldContents = File.ReadAllText(SchemeFilePath.FullName);
|
|
int OldCommandLineArgumentsStart = OldContents.IndexOf("<CommandLineArguments>") + "<CommandLineArguments>".Length;
|
|
int OldCommandLineArgumentsEnd = OldContents.IndexOf("</CommandLineArguments>");
|
|
if (OldCommandLineArgumentsStart != -1 && OldCommandLineArgumentsEnd != -1)
|
|
{
|
|
OldCommandLineArguments = OldContents.Substring(OldCommandLineArgumentsStart, OldCommandLineArgumentsEnd - OldCommandLineArgumentsStart);
|
|
}
|
|
}
|
|
|
|
string DefaultConfiguration = bMakeProjectPerTarget && bHasEditorConfiguration && !XcodeProjectFileGenerator.bGenerateRunOnlyProject ? "Development Editor" : "Development";
|
|
|
|
StringBuilder Content = new StringBuilder();
|
|
|
|
Content.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("<Scheme" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" LastUpgradeVersion = \"2000\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" version = \"1.3\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildAction" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" parallelizeBuildables = \"YES\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildImplicitDependencies = \"YES\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildActionEntries>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildActionEntry" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildForTesting = \"YES\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildForRunning = \"YES\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildForProfiling = \"YES\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildForArchiving = \"YES\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildForAnalyzing = \"YES\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildableReference" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BlueprintIdentifier = \"" + TargetGuid + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BuildableName = \"" + TargetName + ".app\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BlueprintName = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" ReferencedContainer = \"container:" + TargetName + ".xcodeproj\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildableReference>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildActionEntry>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildActionEntries>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildAction>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <TestAction" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" shouldUseLaunchSchemeArgsEnv = \"YES\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <Testables>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </Testables>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <MacroExpansion>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildableReference" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BlueprintIdentifier = \"" + TargetGuid + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BuildableName = \"" + TargetName + ".app\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BlueprintName = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" ReferencedContainer = \"container:" + TargetName + ".xcodeproj\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildableReference>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </MacroExpansion>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <AdditionalOptions>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </AdditionalOptions>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </TestAction>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <LaunchAction" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" launchStyle = \"0\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" useCustomWorkingDirectory = \"NO\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" ignoresPersistentStateOnLaunch = \"NO\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" debugDocumentVersioning = \"NO\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" debugServiceExtension = \"internal\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" allowLocationSimulation = \"YES\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildableProductRunnable" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" runnableDebuggingMode = \"0\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildableReference" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BlueprintIdentifier = \"" + TargetGuid + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BuildableName = \"" + TargetName + ".app\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BlueprintName = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" ReferencedContainer = \"container:" + TargetName + ".xcodeproj\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildableReference>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildableProductRunnable>" + ProjectFileGenerator.NewLine);
|
|
if (String.IsNullOrEmpty(OldCommandLineArguments))
|
|
{
|
|
if (bHasEditorConfiguration && !String.IsNullOrEmpty(GameProjectPath))
|
|
{
|
|
Content.Append(" <CommandLineArguments>" + ProjectFileGenerator.NewLine);
|
|
if (IsForeignProject)
|
|
{
|
|
Content.Append(" <CommandLineArgument" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" argument = \""" + GameProjectPath + ""\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" isEnabled = \"YES\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </CommandLineArgument>" + ProjectFileGenerator.NewLine);
|
|
}
|
|
else
|
|
{
|
|
Content.Append(" <CommandLineArgument" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" argument = \"" + Path.GetFileNameWithoutExtension(GameProjectPath) + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" isEnabled = \"YES\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </CommandLineArgument>" + ProjectFileGenerator.NewLine);
|
|
}
|
|
// Always add a configuration argument
|
|
Content.Append(" <CommandLineArgument" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" argument = \"-RunConfig=$(Configuration)\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" isEnabled = \"YES\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </CommandLineArgument>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </CommandLineArguments>" + ProjectFileGenerator.NewLine);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Content.Append(" <CommandLineArguments>" + OldCommandLineArguments + "</CommandLineArguments>");
|
|
}
|
|
Content.Append(" <AdditionalOptions>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </AdditionalOptions>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </LaunchAction>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <ProfileAction" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" shouldUseLaunchSchemeArgsEnv = \"YES\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" savedToolIdentifier = \"\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" useCustomWorkingDirectory = \"NO\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" debugDocumentVersioning = \"NO\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildableProductRunnable" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" runnableDebuggingMode = \"0\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <BuildableReference" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BuildableIdentifier = \"primary\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BlueprintIdentifier = \"" + TargetGuid + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BuildableName = \"" + TargetName + ".app\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" BlueprintName = \"" + TargetName + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" ReferencedContainer = \"container:" + TargetName + ".xcodeproj\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildableReference>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </BuildableProductRunnable>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </ProfileAction>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <AnalyzeAction" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </AnalyzeAction>" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" <ArchiveAction" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" buildConfiguration = \"" + DefaultConfiguration + "\"" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" revealArchiveInOrganizer = \"YES\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append(" </ArchiveAction>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("</Scheme>" + ProjectFileGenerator.NewLine);
|
|
|
|
File.WriteAllText(SchemeFilePath.FullName, Content.ToString(), new UTF8Encoding());
|
|
|
|
Content.Clear();
|
|
|
|
Content.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append("<plist version=\"1.0\">" + ProjectFileGenerator.NewLine);
|
|
Content.Append("<dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t<key>SchemeUserState</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t<dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t<key>" + TargetName + ".xcscheme_^#shared#^_</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t<dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t<key>orderHint</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t<integer>1</integer>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t</dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t</dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t<key>SuppressBuildableAutocreation</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t<dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t<key>" + TargetGuid + "</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t<dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t<key>primary</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t<true/>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t</dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t<key>" + BuildTargetGuid + "</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t<dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t<key>primary</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t<true/>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t</dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t<key>" + IndexTargetGuid + "</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t<dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t<key>primary</key>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t\t<true/>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t\t</dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("\t</dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("</dict>" + ProjectFileGenerator.NewLine);
|
|
Content.Append("</plist>" + ProjectFileGenerator.NewLine);
|
|
|
|
FileReference ManagementFile = GetUserSchemeManagementFilePath();
|
|
if (!DirectoryReference.Exists(ManagementFile.Directory))
|
|
{
|
|
DirectoryReference.CreateDirectory(ManagementFile.Directory);
|
|
}
|
|
|
|
File.WriteAllText(ManagementFile.FullName, Content.ToString(), new UTF8Encoding());
|
|
}
|
|
|
|
public static IEnumerable<UnrealTargetConfiguration> GetSupportedConfigurations()
|
|
{
|
|
return new UnrealTargetConfiguration[] {
|
|
UnrealTargetConfiguration.Debug,
|
|
UnrealTargetConfiguration.DebugGame,
|
|
UnrealTargetConfiguration.Development,
|
|
UnrealTargetConfiguration.Test,
|
|
UnrealTargetConfiguration.Shipping
|
|
};
|
|
}
|
|
|
|
public bool ShouldIncludeProjectInWorkspace(ILogger Logger)
|
|
{
|
|
return CanBuildProjectLocally(Logger);
|
|
}
|
|
|
|
public bool CanBuildProjectLocally(ILogger Logger)
|
|
{
|
|
foreach (Project ProjectTarget in ProjectTargets)
|
|
{
|
|
foreach (UnrealTargetPlatform Platform in XcodeProjectFileGenerator.XcodePlatforms)
|
|
{
|
|
foreach (UnrealTargetConfiguration Config in GetSupportedConfigurations())
|
|
{
|
|
if (MSBuildProjectFile.IsValidProjectPlatformAndConfiguration(ProjectTarget, Platform, Config, Logger))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Implements Project interface
|
|
public override bool WriteProjectFile(List<UnrealTargetPlatform> InPlatforms, List<UnrealTargetConfiguration> InConfigurations, PlatformProjectGeneratorCollection PlatformProjectGenerators, ILogger Logger)
|
|
{
|
|
bool bSuccess = true;
|
|
|
|
string TargetName = ProjectFilePath.GetFileNameWithoutExtension();
|
|
string TargetGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string TargetConfigListGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string TargetDependencyGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string TargetProxyGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string TargetAppGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string BuildTargetName = TargetName + "_Build";
|
|
string BuildTargetGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string BuildTargetConfigListGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string IndexTargetName = TargetName + "_Index";
|
|
string IndexTargetGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string IndexTargetConfigListGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string ProjectGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string ProjectConfigListGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string MainGroupGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string ProductRefGroupGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string SourcesBuildPhaseGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string CopyExtensionsBuildPhaseGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
string ShellScriptSectionGuid = XcodeProjectFileGenerator.MakeXcodeGuid();
|
|
|
|
// Figure out all the desired configurations
|
|
List<XcodeBuildConfig> BuildConfigs = GetSupportedBuildConfigs(InPlatforms, InConfigurations, Logger);
|
|
if (BuildConfigs.Count == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// if a single project was specified then start with that, this will allow content-only projects to have
|
|
// their BundleID set in the stub xcode project when codesigning, which Xcode needs to have now)
|
|
// note that usually SingleGameProject is null
|
|
FileReference? GameProjectPath = XcodeProjectFileGenerator.SingleGameProject;
|
|
foreach (Project Target in ProjectTargets)
|
|
{
|
|
if (Target.UnrealProjectFilePath != null)
|
|
{
|
|
GameProjectPath = Target.UnrealProjectFilePath;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool bHasEditorConfiguration = false;
|
|
bool bIsAppBundle = true;
|
|
|
|
Dictionary<string, XcodeBuildConfig> ProjectBuildConfigs = new Dictionary<string, XcodeBuildConfig>();
|
|
Dictionary<string, XcodeBuildConfig> TargetBuildConfigs = new Dictionary<string, XcodeBuildConfig>();
|
|
Dictionary<string, XcodeBuildConfig> BuildTargetBuildConfigs = new Dictionary<string, XcodeBuildConfig>();
|
|
Dictionary<string, XcodeBuildConfig> IndexTargetBuildConfigs = new Dictionary<string, XcodeBuildConfig>();
|
|
foreach (XcodeBuildConfig Config in BuildConfigs)
|
|
{
|
|
ProjectBuildConfigs[XcodeProjectFileGenerator.MakeXcodeGuid()] = Config;
|
|
TargetBuildConfigs[XcodeProjectFileGenerator.MakeXcodeGuid()] = Config;
|
|
BuildTargetBuildConfigs[XcodeProjectFileGenerator.MakeXcodeGuid()] = Config;
|
|
IndexTargetBuildConfigs[XcodeProjectFileGenerator.MakeXcodeGuid()] = Config;
|
|
|
|
if (Config.ProjectTarget!.TargetRules!.Type == TargetType.Editor)
|
|
{
|
|
bHasEditorConfiguration = true;
|
|
}
|
|
else if (Config.ProjectTarget.TargetRules.bIsBuildingConsoleApplication || Config.ProjectTarget.TargetRules.bShouldCompileAsDLL)
|
|
{
|
|
bIsAppBundle = false;
|
|
}
|
|
}
|
|
|
|
StringBuilder PBXBuildFileSection = new StringBuilder();
|
|
StringBuilder PBXFileReferenceSection = new StringBuilder();
|
|
StringBuilder PBXSourcesBuildPhaseSection = new StringBuilder();
|
|
StringBuilder PBXCopyExtensionsBuildPhaseSection = new StringBuilder();
|
|
StringBuilder PBXResourcesBuildPhaseSection = new StringBuilder();
|
|
List<XcodeExtensionInfo> AllExtensions = new List<XcodeExtensionInfo>();
|
|
GenerateSectionsWithSourceFiles(PBXBuildFileSection, PBXFileReferenceSection, PBXSourcesBuildPhaseSection, TargetAppGuid, TargetName, bIsAppBundle);
|
|
GenerateSectionsWithExtensions(PBXBuildFileSection, PBXFileReferenceSection, PBXCopyExtensionsBuildPhaseSection, PBXResourcesBuildPhaseSection, AllExtensions, GameProjectPath, BuildConfigs, Logger);
|
|
|
|
StringBuilder ProjectFileContent = new StringBuilder();
|
|
|
|
ProjectFileContent.Append("// !$*UTF8*$!" + ProjectFileGenerator.NewLine);
|
|
ProjectFileContent.Append("{" + ProjectFileGenerator.NewLine);
|
|
ProjectFileContent.Append("\tarchiveVersion = 1;" + ProjectFileGenerator.NewLine);
|
|
ProjectFileContent.Append("\tclasses = {" + ProjectFileGenerator.NewLine);
|
|
ProjectFileContent.Append("\t};" + ProjectFileGenerator.NewLine);
|
|
ProjectFileContent.Append("\tobjectVersion = 46;" + ProjectFileGenerator.NewLine);
|
|
ProjectFileContent.Append("\tobjects = {" + ProjectFileGenerator.NewLine + ProjectFileGenerator.NewLine);
|
|
|
|
AppendBuildFileSection(ProjectFileContent, PBXBuildFileSection);
|
|
AppendFileReferenceSection(ProjectFileContent, PBXFileReferenceSection);
|
|
AppendSourcesBuildPhaseSection(ProjectFileContent, PBXSourcesBuildPhaseSection, SourcesBuildPhaseGuid);
|
|
AppendCopyExtensionsBuildPhaseSection(ProjectFileContent, PBXCopyExtensionsBuildPhaseSection, CopyExtensionsBuildPhaseGuid);
|
|
ProjectFileContent.Append(PBXResourcesBuildPhaseSection);
|
|
AppendContainerItemProxySection(ProjectFileContent, BuildTargetName, BuildTargetGuid, TargetProxyGuid, ProjectGuid);
|
|
if (!XcodeProjectFileGenerator.bGenerateRunOnlyProject)
|
|
{
|
|
AppendTargetDependencySection(ProjectFileContent, BuildTargetName, BuildTargetGuid, TargetDependencyGuid, TargetProxyGuid);
|
|
}
|
|
foreach (XcodeExtensionInfo EI in AllExtensions)
|
|
{
|
|
AppendContainerItemProxySection(ProjectFileContent, EI.Name, EI.TargetGuid, EI.TargetProxyGuid, ProjectGuid);
|
|
AppendTargetDependencySection(ProjectFileContent, EI.Name, EI.TargetGuid, EI.TargetDependencyGuid, EI.TargetProxyGuid);
|
|
}
|
|
AppendGroupSection(ProjectFileContent, MainGroupGuid, ProductRefGroupGuid, TargetAppGuid, TargetName, AllExtensions);
|
|
AppendLegacyTargetSection(ProjectFileContent, BuildTargetName, BuildTargetGuid, BuildTargetConfigListGuid, GameProjectPath);
|
|
AppendRunTargetSection(ProjectFileContent, TargetName, TargetGuid, TargetConfigListGuid, TargetDependencyGuid, TargetAppGuid, CopyExtensionsBuildPhaseGuid, ShellScriptSectionGuid, AllExtensions, bIsAppBundle);
|
|
AppendIndexTargetSection(ProjectFileContent, IndexTargetName, IndexTargetGuid, IndexTargetConfigListGuid, SourcesBuildPhaseGuid);
|
|
AppendExtensionTargetSections(ProjectFileContent, AllExtensions);
|
|
AppendProjectSection(ProjectFileContent, TargetName, TargetGuid, BuildTargetName, BuildTargetGuid, IndexTargetName, IndexTargetGuid, MainGroupGuid, ProductRefGroupGuid, ProjectGuid, ProjectConfigListGuid, GameProjectPath, AllExtensions);
|
|
AppendXCBuildConfigurationSection(ProjectFileContent, ProjectBuildConfigs, TargetBuildConfigs, BuildTargetBuildConfigs, IndexTargetBuildConfigs, GameProjectPath, AllExtensions, Logger);
|
|
AppendXCConfigurationListSection(ProjectFileContent, TargetName, BuildTargetName, IndexTargetName, ProjectConfigListGuid, ProjectBuildConfigs,
|
|
TargetConfigListGuid, TargetBuildConfigs, BuildTargetConfigListGuid, BuildTargetBuildConfigs, IndexTargetConfigListGuid, IndexTargetBuildConfigs, AllExtensions);
|
|
AppendShellScriptSection(ProjectFileContent, ShellScriptSectionGuid, GameProjectPath);
|
|
|
|
ProjectFileContent.Append("\t};" + ProjectFileGenerator.NewLine);
|
|
ProjectFileContent.Append("\trootObject = " + ProjectGuid + " /* Project object */;" + ProjectFileGenerator.NewLine);
|
|
ProjectFileContent.Append("}" + ProjectFileGenerator.NewLine);
|
|
|
|
if (bSuccess)
|
|
{
|
|
FileReference PBXProjFilePath = ProjectFilePath + "/project.pbxproj";
|
|
bSuccess = ProjectFileGenerator.WriteFileIfChanged(PBXProjFilePath.FullName, ProjectFileContent.ToString(), Logger, new UTF8Encoding());
|
|
}
|
|
|
|
bool bNeedScheme = CanBuildProjectLocally(Logger);
|
|
|
|
if (bNeedScheme)
|
|
{
|
|
if (bSuccess)
|
|
{
|
|
WriteSchemeFile(TargetName, TargetGuid, BuildTargetGuid, IndexTargetGuid, bHasEditorConfiguration, GameProjectPath != null ? GameProjectPath.FullName : "");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// clean this up because we don't want it persisting if we narrow our project list
|
|
DirectoryReference SchemeDir = GetProjectSchemeDirectory();
|
|
|
|
if (DirectoryReference.Exists(SchemeDir))
|
|
{
|
|
DirectoryReference.Delete(SchemeDir, true);
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
}
|
|
}
|