You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
1376 lines
50 KiB
C#
1376 lines
50 KiB
C#
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
using System.Security.AccessControl;
|
|
using System.Xml;
|
|
using System.Text;
|
|
using Ionic.Zip;
|
|
using Ionic.Zlib;
|
|
|
|
namespace UnrealBuildTool
|
|
{
|
|
class IOSToolChain : RemoteToolChain
|
|
{
|
|
public override void RegisterToolChain()
|
|
{
|
|
RegisterRemoteToolChain(UnrealTargetPlatform.Mac, CPPTargetPlatform.IOS);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* NOTE:
|
|
* Do NOT change the defaults to set your values, instead you should set the environment variables
|
|
* properly in your system, as other tools make use of them to work properly!
|
|
* The defaults are there simply for examples so you know what to put in your env vars...
|
|
***********************************************************************/
|
|
|
|
// If you are looking for where to change the remote compile server name, look in RemoteToolChain.cs
|
|
|
|
/** If this is set, then we don't do any post-compile steps except moving the executable into the proper spot on the Mac */
|
|
[XmlConfig]
|
|
public static bool bUseDangerouslyFastMode = false;
|
|
|
|
/** Which version of the iOS SDK to target at build time */
|
|
[XmlConfig]
|
|
public static string IOSSDKVersion = "latest";
|
|
public static float IOSSDKVersionFloat = 0.0f;
|
|
|
|
/** Which version of the iOS to allow at build time */
|
|
[XmlConfig]
|
|
public static string BuildIOSVersion = "7.0";
|
|
|
|
/** Which developer directory to root from */
|
|
[XmlConfig]
|
|
public static string XcodeDeveloperDir = "/Applications/Xcode.app/Contents/Developer/";
|
|
|
|
/** Location of the SDKs */
|
|
private static string BaseSDKDir;
|
|
private static string BaseSDKDirSim;
|
|
|
|
/** Which compiler frontend to use */
|
|
private static string IOSCompiler = "clang++";
|
|
|
|
/** Which linker frontend to use */
|
|
private static string IOSLinker = "clang++";
|
|
|
|
/** Which library archiver to use */
|
|
private static string IOSArchiver = "libtool";
|
|
|
|
public List<string> BuiltBinaries = new List<string>();
|
|
|
|
/** Additional frameworks stored locally so we have access without LinkEnvironment */
|
|
public List<UEBuildFramework> RememberedAdditionalFrameworks = new List<UEBuildFramework>();
|
|
|
|
/// <summary>
|
|
/// Function to call to after reset default data.
|
|
/// </summary>
|
|
public static void PostReset()
|
|
{
|
|
/** Location of the SDKs */
|
|
BaseSDKDir = XcodeDeveloperDir + "Platforms/iPhoneOS.platform/Developer/SDKs";
|
|
BaseSDKDirSim = XcodeDeveloperDir + "Platforms/iPhoneSimulator.platform/Developer/SDKs";
|
|
}
|
|
|
|
/** Hunt down the latest IOS sdk if desired */
|
|
public override void SetUpGlobalEnvironment()
|
|
{
|
|
base.SetUpGlobalEnvironment();
|
|
|
|
if (IOSSDKVersion == "latest")
|
|
{
|
|
try
|
|
{
|
|
string[] SubDirs = null;
|
|
if (Utils.IsRunningOnMono)
|
|
{
|
|
// on the Mac, we can just get the directory name
|
|
SubDirs = System.IO.Directory.GetDirectories(BaseSDKDir);
|
|
if (!ProjectFileGenerator.bGenerateProjectFiles)
|
|
{
|
|
Log.TraceInformation(String.Format("Directories : {0} {1}", SubDirs, SubDirs[0]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Hashtable Results = RPCUtilHelper.Command("/", "ls", BaseSDKDir, null);
|
|
if (Results != null)
|
|
{
|
|
string Result = (string)Results["CommandOutput"];
|
|
SubDirs = Result.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
|
|
}
|
|
}
|
|
|
|
// loop over the subdirs and parse out the version
|
|
float MaxSDKVersion = 0.0f;
|
|
string MaxSDKVersionString = null;
|
|
foreach (string SubDir in SubDirs)
|
|
{
|
|
string SubDirName = Path.GetFileNameWithoutExtension(SubDir);
|
|
if (SubDirName.StartsWith("iPhoneOS"))
|
|
{
|
|
// get the SDK version from the directory name
|
|
string SDKString = SubDirName.Replace("iPhoneOS", "");
|
|
float SDKVersion = 0.0f;
|
|
try
|
|
{
|
|
SDKVersion = float.Parse(SDKString, System.Globalization.CultureInfo.InvariantCulture);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// weirdly formatted SDKs
|
|
continue;
|
|
}
|
|
|
|
// update largest SDK version number
|
|
if (SDKVersion > MaxSDKVersion)
|
|
{
|
|
MaxSDKVersion = SDKVersion;
|
|
MaxSDKVersionString = SDKString;
|
|
}
|
|
}
|
|
}
|
|
|
|
// convert back to a string with the exact format
|
|
if (MaxSDKVersionString != null)
|
|
{
|
|
IOSSDKVersion = MaxSDKVersionString;
|
|
}
|
|
}
|
|
catch (Exception Ex)
|
|
{
|
|
// on any exception, just use the backup version
|
|
Log.TraceInformation("Triggered an exception while looking for SDK directory in Xcode.app");
|
|
Log.TraceInformation("{0}", Ex.ToString());
|
|
}
|
|
|
|
if (IOSSDKVersion == "latest")
|
|
{
|
|
throw new BuildException("Unable to determine SDK version from Xcode, we cannot continue");
|
|
}
|
|
}
|
|
|
|
IOSSDKVersionFloat = float.Parse(IOSSDKVersion, System.Globalization.CultureInfo.InvariantCulture);
|
|
|
|
if (!ProjectFileGenerator.bGenerateProjectFiles)
|
|
{
|
|
if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
Log.TraceInformation("Compiling with IOS SDK {0} on Mac {1}", IOSSDKVersionFloat, RemoteServerName);
|
|
}
|
|
else
|
|
{
|
|
Log.TraceInformation("Compiling with IOS SDK {0}", IOSSDKVersionFloat);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void AddFilesToReceipt(BuildReceipt Receipt, UEBuildBinary Binary)
|
|
{
|
|
if (BuildConfiguration.bCreateStubIPA && Binary.Config.Type != UEBuildBinaryType.StaticLibrary)
|
|
{
|
|
string StubFile = Path.Combine (Path.GetDirectoryName (Binary.Config.OutputFilePath), Path.GetFileNameWithoutExtension (Binary.Config.OutputFilePath) + ".stub");
|
|
Receipt.AddBuildProduct(StubFile, BuildProductType.Executable);
|
|
}
|
|
}
|
|
|
|
static bool bHasPrinted = false;
|
|
static string GetArchitectureArgument(CPPTargetConfiguration Configuration, string UBTArchitecture)
|
|
{
|
|
IOSPlatform BuildPlat = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS) as IOSPlatform;
|
|
BuildPlat.SetUpProjectEnvironment(UnrealTargetPlatform.IOS);
|
|
|
|
// get the list of architectures to compile
|
|
string Archs =
|
|
UBTArchitecture == "-simulator" ? "i386" :
|
|
(Configuration == CPPTargetConfiguration.Shipping) ? IOSPlatform.ShippingArchitectures : IOSPlatform.NonShippingArchitectures;
|
|
|
|
if (!bHasPrinted)
|
|
{
|
|
bHasPrinted = true;
|
|
Console.WriteLine("Compiling with these architectures: " + Archs);
|
|
}
|
|
|
|
// parse the string
|
|
string[] Tokens = Archs.Split(",".ToCharArray());
|
|
|
|
string Result = "";
|
|
foreach (string Token in Tokens)
|
|
{
|
|
Result += " -arch " + Token;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
string GetCompileArguments_Global(CPPEnvironment CompileEnvironment)
|
|
{
|
|
IOSPlatform BuildPlat = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS) as IOSPlatform;
|
|
BuildPlat.SetUpProjectEnvironment(UnrealTargetPlatform.IOS);
|
|
|
|
string Result = "";
|
|
|
|
Result += " -fmessage-length=0";
|
|
Result += " -pipe";
|
|
Result += " -fpascal-strings";
|
|
|
|
Result += " -fno-exceptions";
|
|
Result += " -fno-rtti";
|
|
Result += " -fvisibility=hidden"; // hides the linker warnings with PhysX
|
|
|
|
// if (CompileEnvironment.Config.TargetConfiguration == CPPTargetConfiguration.Shipping)
|
|
// {
|
|
// Result += " -flto";
|
|
// }
|
|
|
|
Result += " -Wall -Werror";
|
|
|
|
if (BuildConfiguration.bEnableShadowVariableWarning)
|
|
{
|
|
Result += " -Wshadow";
|
|
}
|
|
|
|
Result += " -Wno-unused-variable";
|
|
Result += " -Wno-unused-value";
|
|
// this will hide the warnings about static functions in headers that aren't used in every single .cpp file
|
|
Result += " -Wno-unused-function";
|
|
// this hides the "enumeration value 'XXXXX' not handled in switch [-Wswitch]" warnings - we should maybe remove this at some point and add UE_LOG(, Fatal, ) to default cases
|
|
Result += " -Wno-switch";
|
|
// this hides the "warning : comparison of unsigned expression < 0 is always false" type warnings due to constant comparisons, which are possible with template arguments
|
|
Result += " -Wno-tautological-compare";
|
|
//This will prevent the issue of warnings for unused private variables.
|
|
Result += " -Wno-unused-private-field";
|
|
Result += " -Wno-invalid-offsetof"; // needed to suppress warnings about using offsetof on non-POD types.
|
|
|
|
Result += " -c";
|
|
|
|
// What architecture(s) to build for
|
|
Result += GetArchitectureArgument(CompileEnvironment.Config.Target.Configuration, CompileEnvironment.Config.Target.Architecture);
|
|
|
|
if (CompileEnvironment.Config.Target.Architecture == "-simulator")
|
|
{
|
|
Result += " -isysroot " + BaseSDKDirSim + "/iPhoneSimulator" + IOSSDKVersion + ".sdk";
|
|
}
|
|
else
|
|
{
|
|
Result += " -isysroot " + BaseSDKDir + "/iPhoneOS" + IOSSDKVersion + ".sdk";
|
|
}
|
|
|
|
Result += " -miphoneos-version-min=" + BuildPlat.GetRunTimeVersion();
|
|
|
|
// Optimize non- debug builds.
|
|
if (CompileEnvironment.Config.Target.Configuration != CPPTargetConfiguration.Debug)
|
|
{
|
|
if (UEBuildConfiguration.bCompileForSize)
|
|
{
|
|
Result += " -Oz";
|
|
}
|
|
else
|
|
{
|
|
Result += " -O3";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Result += " -O0";
|
|
}
|
|
|
|
// Create DWARF format debug info if wanted,
|
|
if (CompileEnvironment.Config.bCreateDebugInfo)
|
|
{
|
|
Result += " -gdwarf-2";
|
|
}
|
|
|
|
// Add additional frameworks so that their headers can be found
|
|
foreach (UEBuildFramework Framework in CompileEnvironment.Config.AdditionalFrameworks)
|
|
{
|
|
if (Framework.OwningModule != null && Framework.FrameworkZipPath != null && Framework.FrameworkZipPath != "")
|
|
{
|
|
Result += " -F \"" + GetRemoteIntermediateFrameworkZipPath(Framework) + "\"";
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static string GetCompileArguments_CPP()
|
|
{
|
|
string Result = "";
|
|
Result += " -x objective-c++";
|
|
Result += " -fno-rtti";
|
|
Result += " -fobjc-abi-version=2";
|
|
Result += " -fobjc-legacy-dispatch";
|
|
Result += " -std=c++11";
|
|
Result += " -stdlib=libc++";
|
|
return Result;
|
|
}
|
|
|
|
static string GetCompileArguments_MM()
|
|
{
|
|
string Result = "";
|
|
Result += " -x objective-c++";
|
|
Result += " -fobjc-abi-version=2";
|
|
Result += " -fobjc-legacy-dispatch";
|
|
Result += " -fno-rtti";
|
|
Result += " -std=c++11";
|
|
Result += " -stdlib=libc++";
|
|
return Result;
|
|
}
|
|
|
|
static string GetCompileArguments_M()
|
|
{
|
|
string Result = "";
|
|
Result += " -x objective-c";
|
|
Result += " -fobjc-abi-version=2";
|
|
Result += " -fobjc-legacy-dispatch";
|
|
Result += " -std=c++11";
|
|
Result += " -stdlib=libc++";
|
|
return Result;
|
|
}
|
|
|
|
static string GetCompileArguments_C()
|
|
{
|
|
string Result = "";
|
|
Result += " -x c";
|
|
return Result;
|
|
}
|
|
|
|
static string GetCompileArguments_PCH()
|
|
{
|
|
string Result = "";
|
|
Result += " -x objective-c++-header";
|
|
Result += " -fno-rtti";
|
|
Result += " -std=c++11";
|
|
Result += " -stdlib=libc++";
|
|
return Result;
|
|
}
|
|
|
|
string GetLocalFrameworkZipPath( UEBuildFramework Framework )
|
|
{
|
|
if ( Framework.OwningModule == null )
|
|
{
|
|
throw new BuildException( "GetLocalFrameworkZipPath: No owning module for framework {0}", Framework.FrameworkName );
|
|
}
|
|
|
|
return Path.GetFullPath( Framework.OwningModule.ModuleDirectory + "/" + Framework.FrameworkZipPath );
|
|
}
|
|
|
|
string GetRemoteFrameworkZipPath( UEBuildFramework Framework )
|
|
{
|
|
if ( BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac )
|
|
{
|
|
return ConvertPath( GetLocalFrameworkZipPath( Framework ) );
|
|
}
|
|
|
|
return GetLocalFrameworkZipPath( Framework );
|
|
}
|
|
|
|
string GetRemoteIntermediateFrameworkZipPath( UEBuildFramework Framework )
|
|
{
|
|
if ( Framework.OwningModule == null )
|
|
{
|
|
throw new BuildException( "GetRemoteIntermediateFrameworkZipPath: No owning module for framework {0}", Framework.FrameworkName );
|
|
}
|
|
|
|
string IntermediatePath = Framework.OwningModule.Target.ProjectDirectory + "/Intermediate/UnzippedFrameworks/" + Framework.OwningModule.Name;
|
|
IntermediatePath = Path.GetFullPath( ( IntermediatePath + Framework.FrameworkZipPath ).Replace( ".zip", "" ) );
|
|
|
|
if ( BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac )
|
|
{
|
|
return ConvertPath( IntermediatePath );
|
|
}
|
|
|
|
return IntermediatePath;
|
|
}
|
|
|
|
void CleanIntermediateDirectory( string Path )
|
|
{
|
|
if ( BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac )
|
|
{
|
|
// Delete the intermediate directory on the mac
|
|
RPCUtilHelper.Command( "/", String.Format( "rm -rf \"{0}\"", Path ), "", null );
|
|
|
|
// Create a fresh intermediate after we delete it
|
|
RPCUtilHelper.Command( "/", String.Format( "mkdir -p \"{0}\"", Path ), "", null );
|
|
}
|
|
else
|
|
{
|
|
// Delete the local dest directory if it exists
|
|
if ( Directory.Exists( Path ) )
|
|
{
|
|
Directory.Delete( Path, true );
|
|
}
|
|
|
|
// Create the intermediate local directory
|
|
string ResultsText;
|
|
RunExecutableAndWait( "mkdir", String.Format( "-p \"{0}\"", Path ), out ResultsText );
|
|
}
|
|
}
|
|
|
|
string GetLinkArguments_Global( LinkEnvironment LinkEnvironment )
|
|
{
|
|
IOSPlatform BuildPlat = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS) as IOSPlatform;
|
|
BuildPlat.SetUpProjectEnvironment(UnrealTargetPlatform.IOS);
|
|
|
|
string Result = "";
|
|
if (LinkEnvironment.Config.Target.Architecture == "-simulator")
|
|
{
|
|
Result += " -arch i386";
|
|
Result += " -isysroot " + XcodeDeveloperDir + "Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator" + IOSSDKVersion + ".sdk";
|
|
}
|
|
else
|
|
{
|
|
Result += Result += GetArchitectureArgument(LinkEnvironment.Config.Target.Configuration, LinkEnvironment.Config.Target.Architecture);
|
|
Result += " -isysroot " + XcodeDeveloperDir + "Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS" + IOSSDKVersion + ".sdk";
|
|
}
|
|
Result += " -dead_strip";
|
|
Result += " -miphoneos-version-min=" + BuildPlat.GetRunTimeVersion();
|
|
Result += " -Wl,-no_pie";
|
|
// Result += " -v";
|
|
|
|
// link in the frameworks
|
|
foreach (string Framework in LinkEnvironment.Config.Frameworks)
|
|
{
|
|
Result += " -framework " + Framework;
|
|
}
|
|
foreach (UEBuildFramework Framework in LinkEnvironment.Config.AdditionalFrameworks)
|
|
{
|
|
if ( Framework.OwningModule != null && Framework.FrameworkZipPath != null && Framework.FrameworkZipPath != "" )
|
|
{
|
|
// If this framework has a zip specified, we'll need to setup the path as well
|
|
Result += " -F \"" + GetRemoteIntermediateFrameworkZipPath( Framework ) + "\"";
|
|
}
|
|
|
|
Result += " -framework " + Framework.FrameworkName;
|
|
}
|
|
foreach (string Framework in LinkEnvironment.Config.WeakFrameworks)
|
|
{
|
|
Result += " -weak_framework " + Framework;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
static string GetArchiveArguments_Global(LinkEnvironment LinkEnvironment)
|
|
{
|
|
string Result = "";
|
|
|
|
Result += " -static";
|
|
|
|
return Result;
|
|
}
|
|
|
|
public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List<FileItem> SourceFiles, string ModuleName)
|
|
{
|
|
string Arguments = GetCompileArguments_Global(CompileEnvironment);
|
|
string PCHArguments = "";
|
|
|
|
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
|
|
{
|
|
// Add the precompiled header file's path to the include path so GCC can find it.
|
|
// This needs to be before the other include paths to ensure GCC uses it instead of the source header file.
|
|
var PrecompiledFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.IOS].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
|
|
PCHArguments += string.Format(" -include \"{0}\"", ConvertPath(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath.Replace(PrecompiledFileExtension, "")));
|
|
}
|
|
|
|
// Add include paths to the argument list.
|
|
HashSet<string> AllIncludes = new HashSet<string>(CompileEnvironment.Config.CPPIncludeInfo.IncludePaths);
|
|
AllIncludes.UnionWith(CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths);
|
|
foreach (string IncludePath in AllIncludes)
|
|
{
|
|
Arguments += string.Format(" -I\"{0}\"", ConvertPath(Path.GetFullPath(IncludePath)));
|
|
|
|
if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
// sync any third party headers we may need
|
|
if (IncludePath.Contains("ThirdParty"))
|
|
{
|
|
string[] FileList = Directory.GetFiles(IncludePath, "*.h", SearchOption.AllDirectories);
|
|
foreach (string File in FileList)
|
|
{
|
|
FileItem ExternalDependency = FileItem.GetItemByPath(File);
|
|
LocalToRemoteFileItem(ExternalDependency, true);
|
|
}
|
|
|
|
FileList = Directory.GetFiles(IncludePath, "*.cpp", SearchOption.AllDirectories);
|
|
foreach (string File in FileList)
|
|
{
|
|
FileItem ExternalDependency = FileItem.GetItemByPath(File);
|
|
LocalToRemoteFileItem(ExternalDependency, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (string Definition in CompileEnvironment.Config.Definitions)
|
|
{
|
|
Arguments += string.Format(" -D\"{0}\"", Definition);
|
|
}
|
|
|
|
var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);
|
|
|
|
CPPOutput Result = new CPPOutput();
|
|
// Create a compile action for each source file.
|
|
foreach (FileItem SourceFile in SourceFiles)
|
|
{
|
|
Action CompileAction = new Action(ActionType.Compile);
|
|
string FileArguments = "";
|
|
string Extension = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant();
|
|
|
|
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
|
|
{
|
|
// Compile the file as a C++ PCH.
|
|
FileArguments += GetCompileArguments_PCH();
|
|
}
|
|
else if (Extension == ".C")
|
|
{
|
|
// Compile the file as C code.
|
|
FileArguments += GetCompileArguments_C();
|
|
}
|
|
else if (Extension == ".CC")
|
|
{
|
|
// Compile the file as C++ code.
|
|
FileArguments += GetCompileArguments_CPP();
|
|
}
|
|
else if (Extension == ".MM")
|
|
{
|
|
// Compile the file as Objective-C++ code.
|
|
FileArguments += GetCompileArguments_MM();
|
|
}
|
|
else if (Extension == ".M")
|
|
{
|
|
// Compile the file as Objective-C++ code.
|
|
FileArguments += GetCompileArguments_M();
|
|
}
|
|
else
|
|
{
|
|
// Compile the file as C++ code.
|
|
FileArguments += GetCompileArguments_CPP();
|
|
|
|
// only use PCH for .cpp files
|
|
FileArguments += PCHArguments;
|
|
}
|
|
|
|
// Add the C++ source file and its included files to the prerequisite item list.
|
|
AddPrerequisiteSourceFile( Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems );
|
|
|
|
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
|
|
{
|
|
var PrecompiledFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.IOS].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
|
|
// Add the precompiled header file to the produced item list.
|
|
FileItem PrecompiledHeaderFile = FileItem.GetItemByPath(
|
|
Path.Combine(
|
|
CompileEnvironment.Config.OutputDirectory,
|
|
Path.GetFileName(SourceFile.AbsolutePath) + PrecompiledFileExtension
|
|
)
|
|
);
|
|
|
|
FileItem RemotePrecompiledHeaderFile = LocalToRemoteFileItem(PrecompiledHeaderFile, false);
|
|
CompileAction.ProducedItems.Add(RemotePrecompiledHeaderFile);
|
|
Result.PrecompiledHeaderFile = RemotePrecompiledHeaderFile;
|
|
|
|
// Add the parameters needed to compile the precompiled header file to the command-line.
|
|
FileArguments += string.Format(" -o \"{0}\"", RemotePrecompiledHeaderFile.AbsolutePath, false);
|
|
}
|
|
else
|
|
{
|
|
if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
|
|
{
|
|
CompileAction.bIsUsingPCH = true;
|
|
CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile);
|
|
}
|
|
var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.IOS].GetBinaryExtension(UEBuildBinaryType.Object);
|
|
// Add the object file to the produced item list.
|
|
FileItem ObjectFile = FileItem.GetItemByPath(
|
|
Path.Combine(
|
|
CompileEnvironment.Config.OutputDirectory,
|
|
Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
|
|
)
|
|
);
|
|
|
|
FileItem RemoteObjectFile = LocalToRemoteFileItem(ObjectFile, false);
|
|
CompileAction.ProducedItems.Add(RemoteObjectFile);
|
|
Result.ObjectFiles.Add(RemoteObjectFile);
|
|
FileArguments += string.Format(" -o \"{0}\"", RemoteObjectFile.AbsolutePath, false);
|
|
}
|
|
|
|
// Add the source file path to the command-line.
|
|
FileArguments += string.Format(" \"{0}\"", ConvertPath(SourceFile.AbsolutePath), false);
|
|
|
|
string CompilerPath = XcodeDeveloperDir + "Toolchains/XcodeDefault.xctoolchain/usr/bin/" + IOSCompiler;
|
|
if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
CompileAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
|
|
}
|
|
|
|
// RPC utility parameters are in terms of the Mac side
|
|
CompileAction.WorkingDirectory = GetMacDevSrcRoot();
|
|
CompileAction.CommandPath = CompilerPath;
|
|
CompileAction.CommandArguments = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
|
|
CompileAction.StatusDescription = string.Format("{0}", Path.GetFileName(SourceFile.AbsolutePath));
|
|
CompileAction.bIsGCCCompiler = true;
|
|
// We're already distributing the command by execution on Mac.
|
|
CompileAction.bCanExecuteRemotely = false;
|
|
CompileAction.bShouldOutputStatusDescription = true;
|
|
CompileAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly)
|
|
{
|
|
string LinkerPath = XcodeDeveloperDir + "Toolchains/XcodeDefault.xctoolchain/usr/bin/" +
|
|
(LinkEnvironment.Config.bIsBuildingLibrary ? IOSArchiver : IOSLinker);
|
|
|
|
// Create an action that invokes the linker.
|
|
Action LinkAction = new Action(ActionType.Link);
|
|
|
|
if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
LinkAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
|
|
}
|
|
|
|
// RPC utility parameters are in terms of the Mac side
|
|
LinkAction.WorkingDirectory = GetMacDevSrcRoot();
|
|
LinkAction.CommandPath = LinkerPath;
|
|
|
|
// build this up over the rest of the function
|
|
LinkAction.CommandArguments = LinkEnvironment.Config.bIsBuildingLibrary ? GetArchiveArguments_Global(LinkEnvironment) : GetLinkArguments_Global(LinkEnvironment);
|
|
|
|
if (!LinkEnvironment.Config.bIsBuildingLibrary)
|
|
{
|
|
// Add the library paths to the argument list.
|
|
foreach (string LibraryPath in LinkEnvironment.Config.LibraryPaths)
|
|
{
|
|
LinkAction.CommandArguments += string.Format(" -L\"{0}\"", LibraryPath);
|
|
}
|
|
|
|
// Add the additional libraries to the argument list.
|
|
foreach (string AdditionalLibrary in LinkEnvironment.Config.AdditionalLibraries)
|
|
{
|
|
// for absolute library paths, convert to remote filename
|
|
if (!String.IsNullOrEmpty(Path.GetDirectoryName(AdditionalLibrary)))
|
|
{
|
|
// add it to the prerequisites to make sure it's built first (this should be the case of non-system libraries)
|
|
FileItem LibFile = FileItem.GetItemByPath(Path.GetFullPath(AdditionalLibrary));
|
|
FileItem RemoteLibFile = LocalToRemoteFileItem(LibFile, false);
|
|
LinkAction.PrerequisiteItems.Add(RemoteLibFile);
|
|
|
|
// and add to the commandline
|
|
LinkAction.CommandArguments += string.Format(" \"{0}\"", ConvertPath(Path.GetFullPath(AdditionalLibrary)));
|
|
}
|
|
else
|
|
{
|
|
LinkAction.CommandArguments += string.Format(" -l\"{0}\"", AdditionalLibrary);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
// Add any additional files that we'll need in order to link the app
|
|
foreach (string AdditionalShadowFile in LinkEnvironment.Config.AdditionalShadowFiles)
|
|
{
|
|
FileItem ShadowFile = FileItem.GetExistingItemByPath(AdditionalShadowFile);
|
|
if (ShadowFile != null)
|
|
{
|
|
QueueFileForBatchUpload(ShadowFile);
|
|
LinkAction.PrerequisiteItems.Add(ShadowFile);
|
|
}
|
|
else
|
|
{
|
|
throw new BuildException("Couldn't find required additional file to shadow: {0}", AdditionalShadowFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle additional framework assets that might need to be shadowed
|
|
foreach ( UEBuildFramework Framework in LinkEnvironment.Config.AdditionalFrameworks )
|
|
{
|
|
if ( Framework.OwningModule == null || Framework.FrameworkZipPath == null || Framework.FrameworkZipPath == "" )
|
|
{
|
|
continue; // Only care about frameworks that have a zip specified
|
|
}
|
|
|
|
// If we've already remembered this framework, skip
|
|
if ( RememberedAdditionalFrameworks.Contains( Framework ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Remember any files we need to unzip
|
|
RememberedAdditionalFrameworks.Add( Framework );
|
|
|
|
// Copy them to remote mac if needed
|
|
if ( BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac )
|
|
{
|
|
FileItem ShadowFile = FileItem.GetExistingItemByPath( GetLocalFrameworkZipPath( Framework ) );
|
|
|
|
if ( ShadowFile != null )
|
|
{
|
|
QueueFileForBatchUpload( ShadowFile );
|
|
LinkAction.PrerequisiteItems.Add( ShadowFile );
|
|
}
|
|
else
|
|
{
|
|
throw new BuildException( "Couldn't find required additional file to shadow: {0}", Framework.FrameworkZipPath );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the output file as a production of the link action.
|
|
FileItem OutputFile = FileItem.GetItemByPath(Path.GetFullPath(LinkEnvironment.Config.OutputFilePath));
|
|
FileItem RemoteOutputFile = LocalToRemoteFileItem(OutputFile, false);
|
|
LinkAction.ProducedItems.Add(RemoteOutputFile);
|
|
|
|
// Add the input files to a response file, and pass the response file on the command-line.
|
|
List<string> InputFileNames = new List<string>();
|
|
foreach (FileItem InputFile in LinkEnvironment.InputFiles)
|
|
{
|
|
InputFileNames.Add(string.Format("\"{0}\"", InputFile.AbsolutePath));
|
|
LinkAction.PrerequisiteItems.Add(InputFile);
|
|
}
|
|
|
|
// Write the list of input files to a response file, with a tempfilename, on remote machine
|
|
if (LinkEnvironment.Config.bIsBuildingLibrary)
|
|
{
|
|
foreach (string Filename in InputFileNames)
|
|
{
|
|
LinkAction.CommandArguments += " " + Filename;
|
|
}
|
|
// @todo rocket lib: the -filelist command should take a response file (see else condition), except that it just says it can't
|
|
// find the file that's in there. Rocket.lib may overflow the commandline by putting all files on the commandline, so this
|
|
// may be needed:
|
|
// LinkAction.CommandArguments += string.Format(" -filelist \"{0}\"", ConvertPath(ResponsePath));
|
|
}
|
|
else
|
|
{
|
|
bool bIsUE4Game = LinkEnvironment.Config.OutputFilePath.Contains("UE4Game");
|
|
string ResponsePath = Path.GetFullPath(Path.Combine((!bIsUE4Game && !string.IsNullOrEmpty(UnrealBuildTool.GetUProjectPath())) ? UnrealBuildTool.GetUProjectPath() : BuildConfiguration.RelativeEnginePath, BuildConfiguration.PlatformIntermediateFolder, "LinkFileList_" + Path.GetFileNameWithoutExtension(LinkEnvironment.Config.OutputFilePath) + ".tmp"));
|
|
if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
ResponseFile.Create (ResponsePath, InputFileNames);
|
|
RPCUtilHelper.CopyFile (ResponsePath, ConvertPath (ResponsePath), true);
|
|
}
|
|
else
|
|
{
|
|
ResponseFile.Create(ConvertPath(ResponsePath), InputFileNames);
|
|
}
|
|
LinkAction.CommandArguments += string.Format(" @\"{0}\"", ConvertPath(ResponsePath));
|
|
}
|
|
|
|
// Add the output file to the command-line.
|
|
LinkAction.CommandArguments += string.Format(" -o \"{0}\"", RemoteOutputFile.AbsolutePath);
|
|
|
|
// Add the additional arguments specified by the environment.
|
|
LinkAction.CommandArguments += LinkEnvironment.Config.AdditionalArguments;
|
|
|
|
// Only execute linking on the local PC.
|
|
LinkAction.bCanExecuteRemotely = false;
|
|
|
|
LinkAction.StatusDescription = string.Format("{0}", OutputFile.AbsolutePath);
|
|
LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler);
|
|
// For iPhone, generate the dSYM file if the config file is set to do so
|
|
if (BuildConfiguration.bGeneratedSYMFile == true && Path.GetExtension(OutputFile.AbsolutePath) != ".a")
|
|
{
|
|
Log.TraceInformation("Generating the dSYM file - this will add some time to your build...");
|
|
RemoteOutputFile = GenerateDebugInfo(RemoteOutputFile);
|
|
}
|
|
|
|
return RemoteOutputFile;
|
|
}
|
|
|
|
/**
|
|
* Generates debug info for a given executable
|
|
*
|
|
* @param Executable FileItem describing the executable to generate debug info for
|
|
*/
|
|
static public FileItem GenerateDebugInfo(FileItem Executable)
|
|
{
|
|
// Make a file item for the source and destination files
|
|
string FullDestPathRoot = Executable.AbsolutePath + ".dSYM";
|
|
string FullDestPath = FullDestPathRoot;
|
|
|
|
FileItem DestFile;
|
|
if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
DestFile = FileItem.GetRemoteItemByPath (FullDestPath, UnrealTargetPlatform.IOS);
|
|
}
|
|
else
|
|
{
|
|
DestFile = FileItem.GetItemByPath (FullDestPath);
|
|
}
|
|
|
|
// Make the compile action
|
|
Action GenDebugAction = new Action(ActionType.GenerateDebugInfo);
|
|
if (!Utils.IsRunningOnMono)
|
|
{
|
|
GenDebugAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
|
|
}
|
|
|
|
IOSToolChain Toolchain = UEToolChain.GetPlatformToolChain(CPPTargetPlatform.IOS) as IOSToolChain;
|
|
GenDebugAction.WorkingDirectory = Toolchain.GetMacDevSrcRoot();
|
|
GenDebugAction.CommandPath = "sh";
|
|
|
|
// note that the source and dest are switched from a copy command
|
|
if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
GenDebugAction.CommandArguments = string.Format("-c '/usr/bin/dsymutil \"{0}\" -f -o \"{1}\"; cd \"{1}/..\"; zip -r -y -1 {2}.dSYM.zip {2}.dSYM'",
|
|
Executable.AbsolutePath,
|
|
FullDestPathRoot,
|
|
Path.GetFileName(Executable.AbsolutePath));
|
|
}
|
|
else
|
|
{
|
|
GenDebugAction.CommandArguments = string.Format("-c '/usr/bin/dsymutil \"{0}\" -f -o \"{1}\"'",
|
|
Executable.AbsolutePath,
|
|
FullDestPathRoot);
|
|
}
|
|
|
|
GenDebugAction.PrerequisiteItems.Add(Executable);
|
|
GenDebugAction.ProducedItems.Add(DestFile);
|
|
GenDebugAction.StatusDescription = GenDebugAction.CommandArguments;// string.Format("Generating debug info for {0}", Path.GetFileName(Executable.AbsolutePath));
|
|
GenDebugAction.bCanExecuteRemotely = false;
|
|
|
|
return DestFile;
|
|
}
|
|
|
|
private void PackageStub(string BinaryPath, string GameName, string ExeName)
|
|
{
|
|
// create the ipa
|
|
string IPAName = BinaryPath + "/" + ExeName + ".stub";
|
|
// delete the old one
|
|
if (File.Exists(IPAName))
|
|
{
|
|
File.Delete(IPAName);
|
|
}
|
|
|
|
// make the subdirectory if needed
|
|
string DestSubdir = Path.GetDirectoryName(IPAName);
|
|
if (!Directory.Exists(DestSubdir))
|
|
{
|
|
Directory.CreateDirectory(DestSubdir);
|
|
}
|
|
|
|
// set up the directories
|
|
string ZipWorkingDir = String.Format("Payload/{0}.app/", GameName);
|
|
string ZipSourceDir = string.Format("{0}/Payload/{1}.app", BinaryPath, GameName);
|
|
|
|
// create the file
|
|
using (ZipFile Zip = new ZipFile())
|
|
{
|
|
// add the entire directory
|
|
Zip.AddDirectory(ZipSourceDir, ZipWorkingDir);
|
|
|
|
// Update permissions to be UNIX-style
|
|
// Modify the file attributes of any added file to unix format
|
|
foreach (ZipEntry E in Zip.Entries)
|
|
{
|
|
const byte FileAttributePlatform_NTFS = 0x0A;
|
|
const byte FileAttributePlatform_UNIX = 0x03;
|
|
const byte FileAttributePlatform_FAT = 0x00;
|
|
|
|
const int UNIX_FILETYPE_NORMAL_FILE = 0x8000;
|
|
//const int UNIX_FILETYPE_SOCKET = 0xC000;
|
|
//const int UNIX_FILETYPE_SYMLINK = 0xA000;
|
|
//const int UNIX_FILETYPE_BLOCKSPECIAL = 0x6000;
|
|
const int UNIX_FILETYPE_DIRECTORY = 0x4000;
|
|
//const int UNIX_FILETYPE_CHARSPECIAL = 0x2000;
|
|
//const int UNIX_FILETYPE_FIFO = 0x1000;
|
|
|
|
const int UNIX_EXEC = 1;
|
|
const int UNIX_WRITE = 2;
|
|
const int UNIX_READ = 4;
|
|
|
|
|
|
int MyPermissions = UNIX_READ | UNIX_WRITE;
|
|
int OtherPermissions = UNIX_READ;
|
|
|
|
int PlatformEncodedBy = (E.VersionMadeBy >> 8) & 0xFF;
|
|
int LowerBits = 0;
|
|
|
|
// Try to preserve read-only if it was set
|
|
bool bIsDirectory = E.IsDirectory;
|
|
|
|
// Check to see if this
|
|
bool bIsExecutable = false;
|
|
if (Path.GetFileNameWithoutExtension(E.FileName).Equals(GameName, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
bIsExecutable = true;
|
|
}
|
|
|
|
if (bIsExecutable)
|
|
{
|
|
// The executable will be encrypted in the final distribution IPA and will compress very poorly, so keeping it
|
|
// uncompressed gives a better indicator of IPA size for our distro builds
|
|
E.CompressionLevel = CompressionLevel.None;
|
|
}
|
|
|
|
if ((PlatformEncodedBy == FileAttributePlatform_NTFS) || (PlatformEncodedBy == FileAttributePlatform_FAT))
|
|
{
|
|
FileAttributes OldAttributes = E.Attributes;
|
|
//LowerBits = ((int)E.Attributes) & 0xFFFF;
|
|
|
|
if ((OldAttributes & FileAttributes.Directory) != 0)
|
|
{
|
|
bIsDirectory = true;
|
|
}
|
|
|
|
// Permissions
|
|
if ((OldAttributes & FileAttributes.ReadOnly) != 0)
|
|
{
|
|
MyPermissions &= ~UNIX_WRITE;
|
|
OtherPermissions &= ~UNIX_WRITE;
|
|
}
|
|
}
|
|
|
|
if (bIsDirectory || bIsExecutable)
|
|
{
|
|
MyPermissions |= UNIX_EXEC;
|
|
OtherPermissions |= UNIX_EXEC;
|
|
}
|
|
|
|
// Re-jigger the external file attributes to UNIX style if they're not already that way
|
|
if (PlatformEncodedBy != FileAttributePlatform_UNIX)
|
|
{
|
|
int NewAttributes = bIsDirectory ? UNIX_FILETYPE_DIRECTORY : UNIX_FILETYPE_NORMAL_FILE;
|
|
|
|
NewAttributes |= (MyPermissions << 6);
|
|
NewAttributes |= (OtherPermissions << 3);
|
|
NewAttributes |= (OtherPermissions << 0);
|
|
|
|
// Now modify the properties
|
|
E.AdjustExternalFileAttributes(FileAttributePlatform_UNIX, (NewAttributes << 16) | LowerBits);
|
|
}
|
|
}
|
|
|
|
// Save it out
|
|
Zip.Save(IPAName);
|
|
}
|
|
}
|
|
|
|
public override void PreBuildSync()
|
|
{
|
|
if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
BuiltBinaries = new List<string>();
|
|
}
|
|
|
|
base.PreBuildSync();
|
|
|
|
// Unzip any third party frameworks that are stored as zips
|
|
foreach ( UEBuildFramework Framework in RememberedAdditionalFrameworks )
|
|
{
|
|
string ZipSrcPath = GetRemoteFrameworkZipPath( Framework );
|
|
string ZipDstPath = GetRemoteIntermediateFrameworkZipPath( Framework );
|
|
|
|
Log.TraceInformation( "Unzipping: {0} -> {1}", ZipSrcPath, ZipDstPath );
|
|
|
|
CleanIntermediateDirectory( ZipDstPath );
|
|
|
|
// Assume that there is another directory inside the zip with the same name as the zip
|
|
ZipDstPath = ZipDstPath.Substring( 0, ZipDstPath.LastIndexOf( '/' ) );
|
|
|
|
if ( BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac )
|
|
{
|
|
// If we're on the mac, just unzip using the shell
|
|
string ResultsText;
|
|
RunExecutableAndWait( "unzip", String.Format( "-o \"{0}\" -d \"{1}\"", ZipSrcPath, ZipDstPath ), out ResultsText );
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// Use RPC utility if the zip is on remote mac
|
|
Hashtable Result = RPCUtilHelper.Command( "/", String.Format( "unzip -o \"{0}\" -d \"{1}\"", ZipSrcPath, ZipDstPath ), "", null );
|
|
|
|
foreach ( DictionaryEntry Entry in Result )
|
|
{
|
|
Log.TraceInformation( "{0}", Entry.Value );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void PostBuildSync(UEBuildTarget Target)
|
|
{
|
|
base.PostBuildSync(Target);
|
|
|
|
string AppName = Target.TargetType == TargetRules.TargetType.Game ? Target.TargetName : Target.AppName;
|
|
|
|
if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
|
|
{
|
|
string RemoteShadowDirectoryMac = Path.GetDirectoryName(Target.OutputPath);
|
|
string FinalRemoteExecutablePath = String.Format("{0}/Payload/{1}.app/{1}", RemoteShadowDirectoryMac, AppName);
|
|
|
|
// strip the debug info from the executable if needed
|
|
if (BuildConfiguration.bStripSymbolsOnIOS || (Target.Configuration == UnrealTargetConfiguration.Shipping))
|
|
{
|
|
Process StripProcess = new Process();
|
|
StripProcess.StartInfo.WorkingDirectory = RemoteShadowDirectoryMac;
|
|
StripProcess.StartInfo.FileName = "/usr/bin/xcrun";
|
|
StripProcess.StartInfo.Arguments = "strip \"" + Target.OutputPath + "\"";
|
|
StripProcess.OutputDataReceived += new DataReceivedEventHandler(OutputReceivedDataEventHandler);
|
|
StripProcess.ErrorDataReceived += new DataReceivedEventHandler(OutputReceivedDataEventHandler);
|
|
|
|
OutputReceivedDataEventHandlerEncounteredError = false;
|
|
OutputReceivedDataEventHandlerEncounteredErrorMessage = "";
|
|
Utils.RunLocalProcess(StripProcess);
|
|
if (OutputReceivedDataEventHandlerEncounteredError)
|
|
{
|
|
throw new Exception(OutputReceivedDataEventHandlerEncounteredErrorMessage);
|
|
}
|
|
}
|
|
|
|
// copy the executable
|
|
if (!File.Exists(FinalRemoteExecutablePath))
|
|
{
|
|
Directory.CreateDirectory(String.Format("{0}/Payload/{1}.app", RemoteShadowDirectoryMac, AppName));
|
|
}
|
|
File.Copy(Target.OutputPath, FinalRemoteExecutablePath, true);
|
|
|
|
if (BuildConfiguration.bCreateStubIPA)
|
|
{
|
|
string Project = Target.ProjectDirectory + "/" + AppName + ".uproject";
|
|
|
|
// generate the dummy project so signing works
|
|
if (AppName == "UE4Game" || AppName == "UE4Client" || Utils.IsFileUnderDirectory(Target.ProjectDirectory + "/" + AppName + ".uproject", Path.GetFullPath("../..")))
|
|
{
|
|
UnrealBuildTool.GenerateProjectFiles (new XcodeProjectFileGenerator (), new string[] {"-platforms=IOS", "-NoIntellIsense", "-iosdeployonly", "-ignorejunk"});
|
|
Project = Path.GetFullPath("../..") + "/UE4_IOS.xcodeproj";
|
|
}
|
|
else
|
|
{
|
|
Project = Target.ProjectDirectory + "/" + AppName + ".xcodeproj";
|
|
}
|
|
|
|
if (Directory.Exists (Project))
|
|
{
|
|
// ensure the plist, entitlements, and provision files are properly copied
|
|
var DeployHandler = UEBuildDeploy.GetBuildDeploy(Target.Platform);
|
|
if (DeployHandler != null)
|
|
{
|
|
DeployHandler.PrepTargetForDeployment(Target);
|
|
}
|
|
|
|
// code sign the project
|
|
string CmdLine = XcodeDeveloperDir + "usr/bin/xcodebuild" +
|
|
" -project \"" + Project + "\"" +
|
|
" -configuration " + Target.Configuration +
|
|
" -scheme '" + AppName + " - iOS'" +
|
|
" -sdk iphoneos" +
|
|
" CODE_SIGN_IDENTITY=\"iPhone Developer\"";
|
|
|
|
Console.WriteLine("Code signing with command line: " + CmdLine);
|
|
|
|
Process SignProcess = new Process ();
|
|
SignProcess.StartInfo.WorkingDirectory = RemoteShadowDirectoryMac;
|
|
SignProcess.StartInfo.FileName = "/usr/bin/xcrun";
|
|
SignProcess.StartInfo.Arguments = CmdLine;
|
|
SignProcess.OutputDataReceived += new DataReceivedEventHandler (OutputReceivedDataEventHandler);
|
|
SignProcess.ErrorDataReceived += new DataReceivedEventHandler (OutputReceivedDataEventHandler);
|
|
|
|
OutputReceivedDataEventHandlerEncounteredError = false;
|
|
OutputReceivedDataEventHandlerEncounteredErrorMessage = "";
|
|
Utils.RunLocalProcess (SignProcess);
|
|
|
|
// delete the temp project
|
|
if (Project.Contains ("_IOS.xcodeproj"))
|
|
{
|
|
Directory.Delete (Project, true);
|
|
}
|
|
|
|
if (OutputReceivedDataEventHandlerEncounteredError)
|
|
{
|
|
throw new Exception (OutputReceivedDataEventHandlerEncounteredErrorMessage);
|
|
}
|
|
|
|
// Package the stub
|
|
PackageStub (RemoteShadowDirectoryMac, AppName, Path.GetFileNameWithoutExtension (Target.OutputPath));
|
|
}
|
|
}
|
|
|
|
{
|
|
// Copy bundled assets from additional frameworks to the intermediate assets directory (so they can get picked up during staging)
|
|
String LocalFrameworkAssets = Path.GetFullPath( Target.ProjectDirectory + "/Intermediate/IOS/FrameworkAssets" );
|
|
|
|
// Clean the local dest directory if it exists
|
|
CleanIntermediateDirectory( LocalFrameworkAssets );
|
|
|
|
foreach ( UEBuildFramework Framework in RememberedAdditionalFrameworks )
|
|
{
|
|
if ( Framework.OwningModule == null || Framework.CopyBundledAssets == null || Framework.CopyBundledAssets == "" )
|
|
{
|
|
continue; // Only care if we need to copy bundle assets
|
|
}
|
|
|
|
if ( Framework.OwningModule.Target != Target )
|
|
{
|
|
continue; // This framework item doesn't belong to this target, skip it
|
|
}
|
|
|
|
string LocalZipPath = GetLocalFrameworkZipPath( Framework );
|
|
|
|
LocalZipPath = LocalZipPath.Replace( ".zip", "" );
|
|
|
|
// For now, this is hard coded, but we need to loop over all modules, and copy bundled assets that need it
|
|
string LocalSource = LocalZipPath + "/" + Framework.CopyBundledAssets;
|
|
string BundleName = Framework.CopyBundledAssets.Substring( Framework.CopyBundledAssets.LastIndexOf( '/' ) + 1 );
|
|
string LocalDest = LocalFrameworkAssets + "/" + BundleName;
|
|
|
|
Log.TraceInformation( "Copying bundled asset... LocalSource: {0}, LocalDest: {1}", LocalSource, LocalDest );
|
|
|
|
string ResultsText;
|
|
RunExecutableAndWait( "cp", String.Format( "-R -L {0} {1}", LocalSource.Replace(" ", "\\ "), LocalDest.Replace(" ", "\\ ") ), out ResultsText );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// store off the binaries
|
|
foreach (UEBuildBinary Binary in Target.AppBinaries)
|
|
{
|
|
BuiltBinaries.Add(Path.GetFullPath(Binary.ToString()));
|
|
}
|
|
|
|
// check to see if the DangerouslyFast mode is valid (in other words, a build has gone through since a Rebuild/Clean operation)
|
|
string DangerouslyFastValidFile = Path.Combine(Target.GlobalLinkEnvironment.Config.IntermediateDirectory, "DangerouslyFastIsNotDangerous");
|
|
bool bUseDangerouslyFastModeWasRequested = bUseDangerouslyFastMode;
|
|
if (bUseDangerouslyFastMode)
|
|
{
|
|
if (!File.Exists(DangerouslyFastValidFile))
|
|
{
|
|
Log.TraceInformation("Dangeroulsy Fast mode was requested, but a slow mode hasn't completed. Performing slow now...");
|
|
bUseDangerouslyFastMode = false;
|
|
}
|
|
}
|
|
|
|
foreach (string FilePath in BuiltBinaries)
|
|
{
|
|
string RemoteExecutablePath = ConvertPath(FilePath);
|
|
|
|
// when going super fast, just copy the executable to the final resting spot
|
|
if (bUseDangerouslyFastMode)
|
|
{
|
|
Log.TraceInformation("==============================================================================");
|
|
Log.TraceInformation("USING DANGEROUSLY FAST MODE! IF YOU HAVE ANY PROBLEMS, TRY A REBUILD/CLEAN!!!!");
|
|
Log.TraceInformation("==============================================================================");
|
|
|
|
// copy the executable
|
|
string RemoteShadowDirectoryMac = ConvertPath(Path.GetDirectoryName(Target.OutputPath));
|
|
string FinalRemoteExecutablePath = String.Format("{0}/Payload/{1}.app/{1}", RemoteShadowDirectoryMac, Target.TargetName);
|
|
RPCUtilHelper.Command("/", String.Format("cp -f {0} {1}", RemoteExecutablePath, FinalRemoteExecutablePath), "", null);
|
|
}
|
|
else if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
|
|
{
|
|
RPCUtilHelper.CopyFile(RemoteExecutablePath, FilePath, false);
|
|
|
|
if (BuildConfiguration.bGeneratedSYMFile == true)
|
|
{
|
|
string DSYMExt = ".app.dSYM.zip";
|
|
RPCUtilHelper.CopyFile(RemoteExecutablePath + DSYMExt, FilePath + DSYMExt, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Generate the stub
|
|
if (BuildConfiguration.bCreateStubIPA || bUseDangerouslyFastMode)
|
|
{
|
|
// ensure the plist, entitlements, and provision files are properly copied
|
|
var DeployHandler = UEBuildDeploy.GetBuildDeploy(Target.Platform);
|
|
if (DeployHandler != null)
|
|
{
|
|
DeployHandler.PrepTargetForDeployment(Target);
|
|
}
|
|
|
|
if (!bUseDangerouslyFastMode)
|
|
{
|
|
// generate the dummy project so signing works
|
|
UnrealBuildTool.GenerateProjectFiles(new XcodeProjectFileGenerator(), new string[] { "-NoIntellisense", "-iosdeployonly", (!string.IsNullOrEmpty(UnrealBuildTool.GetUProjectPath()) ? "-game" : "") });
|
|
}
|
|
|
|
// now that
|
|
Process StubGenerateProcess = new Process();
|
|
StubGenerateProcess.StartInfo.WorkingDirectory = Path.GetFullPath("..\\Binaries\\DotNET\\IOS");
|
|
StubGenerateProcess.StartInfo.FileName = Path.Combine(StubGenerateProcess.StartInfo.WorkingDirectory, "iPhonePackager.exe");
|
|
|
|
string Arguments = "";
|
|
string PathToApp = RulesCompiler.GetTargetFilename(AppName);
|
|
|
|
// right now, no programs have a Source subdirectory, so assume the PathToApp is directly in the root
|
|
if (Path.GetDirectoryName(PathToApp).Contains(@"\Engine\Source\Programs"))
|
|
{
|
|
PathToApp = Path.GetDirectoryName(PathToApp);
|
|
}
|
|
else
|
|
{
|
|
Int32 SourceIndex = PathToApp.LastIndexOf(@"\Intermediate\Source");
|
|
if (SourceIndex != -1)
|
|
{
|
|
PathToApp = PathToApp.Substring(0, SourceIndex);
|
|
}
|
|
else
|
|
{
|
|
SourceIndex = PathToApp.LastIndexOf(@"\Source");
|
|
if (SourceIndex != -1)
|
|
{
|
|
PathToApp = PathToApp.Substring(0, SourceIndex);
|
|
}
|
|
else
|
|
{
|
|
throw new BuildException("The target was not in a /Source subdirectory");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bUseDangerouslyFastMode)
|
|
{
|
|
// the quickness!
|
|
Arguments += "DangerouslyFast " + PathToApp;
|
|
}
|
|
else
|
|
{
|
|
Arguments += "PackageIPA \"" + PathToApp + "\" -createstub";
|
|
// if we are making the dsym, then we can strip the debug info from the executable
|
|
if (BuildConfiguration.bStripSymbolsOnIOS || (Target.Configuration == UnrealTargetConfiguration.Shipping))
|
|
{
|
|
Arguments += " -strip";
|
|
}
|
|
}
|
|
Arguments += " -config " + Target.Configuration + " -mac " + RemoteServerName;
|
|
|
|
var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Target.Platform);
|
|
string Architecture = BuildPlatform.GetActiveArchitecture();
|
|
if (Architecture != "")
|
|
{
|
|
// pass along the architecture if we need, skipping the initial -, so we have "-architecture simulator"
|
|
Arguments += " -architecture " + Architecture.Substring(1);
|
|
}
|
|
|
|
if (!bUseRPCUtil )
|
|
{
|
|
Arguments += " -usessh";
|
|
Arguments += " -sshexe \"" + ResolvedSSHExe + "\"";
|
|
Arguments += " -sshauth \"" + ResolvedSSHAuthentication + "\"";
|
|
Arguments += " -sshuser \"" + ResolvedRSyncUsername + "\"";
|
|
Arguments += " -rsyncexe \"" + ResolvedRSyncExe + "\"";
|
|
Arguments += " -overridedevroot \"" + UserDevRootMac + "\"";
|
|
}
|
|
|
|
// programmers that use Xcode packaging mode should use the following commandline instead, as it will package for Xcode on each compile
|
|
// Arguments = "PackageApp " + GameName + " " + Configuration;
|
|
StubGenerateProcess.StartInfo.Arguments = Arguments;
|
|
|
|
StubGenerateProcess.OutputDataReceived += new DataReceivedEventHandler(OutputReceivedDataEventHandler);
|
|
StubGenerateProcess.ErrorDataReceived += new DataReceivedEventHandler(OutputReceivedDataEventHandler);
|
|
|
|
OutputReceivedDataEventHandlerEncounteredError = false;
|
|
OutputReceivedDataEventHandlerEncounteredErrorMessage = "";
|
|
Utils.RunLocalProcess(StubGenerateProcess);
|
|
if (OutputReceivedDataEventHandlerEncounteredError)
|
|
{
|
|
throw new Exception(OutputReceivedDataEventHandlerEncounteredErrorMessage);
|
|
}
|
|
|
|
// now that a slow mode sync has finished, we can now do DangerouslyFast mode again (if requested)
|
|
if (bUseDangerouslyFastModeWasRequested)
|
|
{
|
|
File.Create(DangerouslyFastValidFile);
|
|
}
|
|
else
|
|
{
|
|
// if we didn't want dangerously fast, then delete the file so that setting/unsetting the flag will do the right thing without a Rebuild
|
|
File.Delete(DangerouslyFastValidFile);
|
|
}
|
|
}
|
|
|
|
{
|
|
// Copy bundled assets from additional frameworks to the intermediate assets directory (so they can get picked up during staging)
|
|
String LocalFrameworkAssets = Path.GetFullPath( Target.ProjectDirectory + "/Intermediate/IOS/FrameworkAssets" );
|
|
String RemoteFrameworkAssets = ConvertPath( LocalFrameworkAssets );
|
|
|
|
CleanIntermediateDirectory( RemoteFrameworkAssets );
|
|
|
|
// Delete the local dest directory if it exists
|
|
if ( Directory.Exists( LocalFrameworkAssets ) )
|
|
{
|
|
Directory.Delete( LocalFrameworkAssets, true );
|
|
}
|
|
|
|
foreach ( UEBuildFramework Framework in RememberedAdditionalFrameworks )
|
|
{
|
|
if ( Framework.OwningModule == null || Framework.CopyBundledAssets == null || Framework.CopyBundledAssets == "" )
|
|
{
|
|
continue; // Only care if we need to copy bundle assets
|
|
}
|
|
|
|
if ( Framework.OwningModule.Target != Target )
|
|
{
|
|
continue; // This framework item doesn't belong to this target, skip it
|
|
}
|
|
|
|
string RemoteZipPath = GetRemoteIntermediateFrameworkZipPath( Framework );
|
|
|
|
RemoteZipPath = RemoteZipPath.Replace( ".zip", "" );
|
|
|
|
// For now, this is hard coded, but we need to loop over all modules, and copy bundled assets that need it
|
|
string RemoteSource = RemoteZipPath + "/" + Framework.CopyBundledAssets;
|
|
string BundleName = Framework.CopyBundledAssets.Substring( Framework.CopyBundledAssets.LastIndexOf( '/' ) + 1 );
|
|
|
|
String RemoteDest = RemoteFrameworkAssets + "/" + BundleName;
|
|
String LocalDest = LocalFrameworkAssets + "\\" + BundleName;
|
|
|
|
Log.TraceInformation( "Copying bundled asset... RemoteSource: {0}, RemoteDest: {1}, LocalDest: {2}", RemoteSource, RemoteDest, LocalDest );
|
|
|
|
Hashtable Results = RPCUtilHelper.Command( "/", String.Format( "cp -R -L {0} {1}", RemoteSource.Replace(" ", "\\ "), RemoteDest.Replace(" ", "\\ ") ), "", null );
|
|
|
|
foreach ( DictionaryEntry Entry in Results )
|
|
{
|
|
Log.TraceInformation( "{0}", Entry.Value );
|
|
}
|
|
|
|
// Copy the bundled resource from the remote mac to the local dest
|
|
RPCUtilHelper.CopyDirectory( RemoteDest, LocalDest, RPCUtilHelper.ECopyOptions.None );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override UnrealTargetPlatform GetPlatform()
|
|
{
|
|
return UnrealTargetPlatform.IOS;
|
|
}
|
|
|
|
public static int RunExecutableAndWait( string ExeName, string ArgumentList, out string StdOutResults )
|
|
{
|
|
// Create the process
|
|
ProcessStartInfo PSI = new ProcessStartInfo( ExeName, ArgumentList );
|
|
PSI.RedirectStandardOutput = true;
|
|
PSI.UseShellExecute = false;
|
|
PSI.CreateNoWindow = true;
|
|
Process NewProcess = Process.Start( PSI );
|
|
|
|
// Wait for the process to exit and grab it's output
|
|
StdOutResults = NewProcess.StandardOutput.ReadToEnd();
|
|
NewProcess.WaitForExit();
|
|
return NewProcess.ExitCode;
|
|
}
|
|
|
|
public override void StripSymbols(string SourceFileName, string TargetFileName)
|
|
{
|
|
File.Copy(SourceFileName, TargetFileName, true);
|
|
|
|
ProcessStartInfo StartInfo = new ProcessStartInfo();
|
|
StartInfo.FileName = Path.Combine(XcodeDeveloperDir, "usr/bin/xcrun");
|
|
StartInfo.Arguments = String.Format("strip \"{0}\" -S", TargetFileName);
|
|
StartInfo.UseShellExecute = false;
|
|
StartInfo.CreateNoWindow = true;
|
|
Utils.RunLocalProcessAndLogOutput(StartInfo);
|
|
}
|
|
};
|
|
}
|