// Copyright 1998-2017 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 IOSToolChainSettings : AppleToolChainSettings
{
///
/// Which version of the iOS SDK to target at build time
///
[XmlConfigFile(Category = "IOSToolChain")]
public string IOSSDKVersion = "latest";
public readonly float IOSSDKVersionFloat = 0.0f;
///
/// Which version of the iOS to allow at build time
///
[XmlConfigFile(Category = "IOSToolChain")]
public string BuildIOSVersion = "7.0";
///
/// Directory for the developer binaries
///
public string ToolchainDir = "";
///
/// Location of the SDKs
///
public readonly string BaseSDKDir;
public readonly string BaseSDKDirSim;
public readonly string DevicePlatformName;
public readonly string SimulatorPlatformName;
public IOSToolChainSettings() : this("iPhoneOS", "iPhoneSimulator")
{
}
protected IOSToolChainSettings(string DevicePlatformName, string SimulatorPlatformName) : base(true)
{
XmlConfig.ApplyTo(this);
this.DevicePlatformName = DevicePlatformName;
this.SimulatorPlatformName = SimulatorPlatformName;
// update cached paths
BaseSDKDir = XcodeDeveloperDir + "Platforms/" + DevicePlatformName + ".platform/Developer/SDKs";
BaseSDKDirSim = XcodeDeveloperDir + "Platforms/" + SimulatorPlatformName + ".platform/Developer/SDKs";
ToolchainDir = XcodeDeveloperDir + "Toolchains/XcodeDefault.xctoolchain/usr/bin/";
// make sure SDK is selected
SelectSDK(BaseSDKDir, DevicePlatformName, ref IOSSDKVersion, true);
// convert to float for easy comparison
IOSSDKVersionFloat = float.Parse(IOSSDKVersion, System.Globalization.CultureInfo.InvariantCulture);
}
}
class IOSToolChain : AppleToolChain
{
protected IOSProjectSettings ProjectSettings;
public IOSToolChain(FileReference InProjectFile, IOSProjectSettings InProjectSettings)
: this(CppPlatform.IOS, InProjectFile, InProjectSettings, () => new IOSToolChainSettings())
{
}
protected IOSToolChain(CppPlatform TargetPlatform, FileReference InProjectFile, IOSProjectSettings InProjectSettings, Func InCreateSettings)
: base(TargetPlatform, UnrealTargetPlatform.Mac, InProjectFile)
{
ProjectSettings = InProjectSettings;
Settings = new Lazy(InCreateSettings);
}
// ***********************************************************************
// * 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
///
[XmlConfigFile]
public static bool bUseDangerouslyFastMode = false;
///
/// The lazily constructed settings for the toolchain
///
private Lazy Settings;
///
/// Which compiler frontend to use
///
private const string IOSCompiler = "clang++";
///
/// Which linker frontend to use
///
private const string IOSLinker = "clang++";
///
/// Which library archiver to use
///
private const string IOSArchiver = "libtool";
public static List BuiltBinaries = new List();
///
/// Additional frameworks stored locally so we have access without LinkEnvironment
///
public static List RememberedAdditionalFrameworks = new List();
public override void ModifyBuildProducts(ReadOnlyTargetRules Target, UEBuildBinary Binary, List Libraries, List BundleResources, Dictionary BuildProducts)
{
if (Target.bCreateStubIPA && Binary.Config.Type != UEBuildBinaryType.StaticLibrary)
{
FileReference StubFile = FileReference.Combine(Binary.Config.OutputFilePath.Directory, Binary.Config.OutputFilePath.GetFileNameWithoutExtension() + ".stub");
BuildProducts.Add(StubFile, BuildProductType.Executable);
if (CppPlatform == CppPlatform.TVOS)
{
FileReference AssetFile = FileReference.Combine(Binary.Config.OutputFilePath.Directory, "Assets.car");
BuildProducts.Add(AssetFile, BuildProductType.Executable);
}
}
}
///
/// Adds a build product and its associated debug file to a receipt.
///
/// Build product to add
/// Type of build product
public override bool ShouldAddDebugFileToReceipt(FileReference OutputFile, BuildProductType OutputType)
{
return OutputType == BuildProductType.Executable;
}
string GetCompileArguments_Global(CppCompileEnvironment CompileEnvironment)
{
string Result = "";
Result += " -fmessage-length=0";
Result += " -pipe";
Result += " -fpascal-strings";
// Optionally enable exception handling (off by default since it generates extra code needed to propagate exceptions)
if (CompileEnvironment.bEnableExceptions)
{
Result += " -fexceptions";
}
else
{
Result += " -fno-exceptions";
}
string SanitizerMode = Environment.GetEnvironmentVariable("ENABLE_ADDRESS_SANITIZER");
if(SanitizerMode != null && SanitizerMode == "YES")
{
Result += " -fsanitize=address";
}
Result += GetRTTIFlag(CompileEnvironment);
Result += " -fvisibility=hidden"; // hides the linker warnings with PhysX
// if (CompileEnvironment.TargetConfiguration == CPPTargetConfiguration.Shipping)
// {
// Result += " -flto";
// }
Result += " -Wall -Werror";
if (CompileEnvironment.bEnableShadowVariableWarnings)
{
Result += " -Wshadow" + (CompileEnvironment.bShadowVariableWarningsAsErrors? "" : " -Wno-error=shadow");
}
if (CompileEnvironment.bEnableUndefinedIdentifierWarnings)
{
Result += " -Wundef" + (CompileEnvironment.bUndefinedIdentifierWarningsAsErrors ? "" : " -Wno-error=undef");
}
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";
// needed to suppress warnings about using offsetof on non-POD types.
Result += " -Wno-invalid-offsetof";
// we use this feature to allow static FNames.
Result += " -Wno-gnu-string-literal-operator-template";
if (Settings.Value.IOSSDKVersionFloat >= 9.0)
{
Result += " -Wno-inconsistent-missing-override"; // too many missing overrides...
Result += " -Wno-unused-local-typedef"; // PhysX has some, hard to remove
}
// fix for Xcode 8.3 enabling nonportable include checks, but p4 has some invalid cases in it
if (Settings.Value.IOSSDKVersionFloat >= 10.3)
{
Result += " -Wno-nonportable-include-path";
}
if (IsBitcodeCompilingEnabled(CompileEnvironment.Configuration))
{
Result += " -fembed-bitcode";
}
Result += " -c";
// What architecture(s) to build for
Result += GetArchitectureArgument(CompileEnvironment.Configuration, CompileEnvironment.Architecture);
if (CompileEnvironment.Architecture == "-simulator")
{
Result += " -isysroot " + Settings.Value.BaseSDKDirSim + "/" + Settings.Value.SimulatorPlatformName + Settings.Value.IOSSDKVersion + ".sdk";
}
else
{
Result += " -isysroot " + Settings.Value.BaseSDKDir + "/" + Settings.Value.DevicePlatformName + Settings.Value.IOSSDKVersion + ".sdk";
}
Result += " -m" + GetXcodeMinVersionParam() + "=" + ProjectSettings.RuntimeVersion;
// Optimize non- debug builds.
if (CompileEnvironment.bOptimizeCode)
{
if (CompileEnvironment.bOptimizeForSize)
{
Result += " -Oz";
}
else
{
Result += " -O3";
}
}
else
{
Result += " -O0";
}
// Create DWARF format debug info if wanted,
if (CompileEnvironment.bCreateDebugInfo)
{
Result += " -gdwarf-2";
}
// Add additional frameworks so that their headers can be found
foreach (UEBuildFramework Framework in CompileEnvironment.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 += " -fobjc-abi-version=2";
Result += " -fobjc-legacy-dispatch";
Result += " -std=c++14";
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 += " -std=c++14";
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++14";
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 += " -std=c++14";
Result += " -stdlib=libc++";
return Result;
}
// Conditionally enable (default disabled) generation of information about every class with virtual functions for use by the C++ runtime type identification features
// (`dynamic_cast' and `typeid'). If you don't use those parts of the language, you can save some space by using -fno-rtti.
// Note that exception handling uses the same information, but it will generate it as needed.
static string GetRTTIFlag(CppCompileEnvironment CompileEnvironment)
{
string Result = "";
if (CompileEnvironment.bUseRTTI)
{
Result = " -frtti";
}
else
{
Result = " -fno-rtti";
}
return Result;
}
static 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);
}
static string GetRemoteFrameworkZipPath(UEBuildFramework Framework)
{
if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
{
return ConvertPath(GetLocalFrameworkZipPath(Framework));
}
return GetLocalFrameworkZipPath(Framework);
}
static string GetRemoteIntermediateFrameworkZipPath(UEBuildFramework Framework)
{
if (Framework.OwningModule == null)
{
throw new BuildException("GetRemoteIntermediateFrameworkZipPath: No owning module for framework {0}", Framework.FrameworkName);
}
string IntermediatePath = UnrealBuildTool.EngineDirectory + "/Intermediate/UnzippedFrameworks/" + Framework.OwningModule.Name;
IntermediatePath = Path.GetFullPath((IntermediatePath + Framework.FrameworkZipPath).Replace(".zip", ""));
if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
{
return ConvertPath(IntermediatePath);
}
return IntermediatePath;
}
static 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);
}
}
bool IsBitcodeCompilingEnabled(CppConfiguration Configuration)
{
return Configuration == CppConfiguration.Shipping && ProjectSettings.bShipForBitcode;
}
public virtual string GetXcodeMinVersionParam()
{
return "iphoneos-version-min";
}
public virtual string GetArchitectureArgument(CppConfiguration Configuration, string UBTArchitecture)
{
// get the list of architectures to compile
string Archs =
UBTArchitecture == "-simulator" ? "i386" :
String.Join(",", (Configuration == CppConfiguration.Shipping) ? ProjectSettings.ShippingArchitectures : ProjectSettings.NonShippingArchitectures);
Log.TraceLogOnce("Compiling with these architectures: " + Archs);
// parse the string
string[] Tokens = Archs.Split(",".ToCharArray());
string Result = "";
foreach (string Token in Tokens)
{
Result += " -arch " + Token;
}
// Remove this in 4.16
// Commented this out, for now. @Pete let's conditionally check this when we re-implement this fix.
// Result += " -mcpu=cortex-a9";
return Result;
}
public string GetAdditionalLinkerFlags(CppConfiguration InConfiguration)
{
if (InConfiguration != CppConfiguration.Shipping)
{
return ProjectSettings.AdditionalLinkerFlags;
}
else
{
return ProjectSettings.AdditionalShippingLinkerFlags;
}
}
string GetLinkArguments_Global(LinkEnvironment LinkEnvironment)
{
string Result = "";
Result += GetArchitectureArgument(LinkEnvironment.Configuration, LinkEnvironment.Architecture);
bool bIsDevice = (LinkEnvironment.Architecture != "-simulator");
Result += String.Format(" -isysroot {0}Platforms/{1}.platform/Developer/SDKs/{1}{2}.sdk",
Settings.Value.XcodeDeveloperDir, bIsDevice? Settings.Value.DevicePlatformName : Settings.Value.SimulatorPlatformName, Settings.Value.IOSSDKVersion);
if(IsBitcodeCompilingEnabled(LinkEnvironment.Configuration))
{
FileItem OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.OutputFilePath);
FileItem RemoteOutputFile = LocalToRemoteFileItem(OutputFile, false);
Result += " -fembed-bitcode -Xlinker -bitcode_verify -Xlinker -bitcode_hide_symbols -Xlinker -bitcode_symbol_map ";
Result += " -Xlinker " + Path.GetDirectoryName(RemoteOutputFile.AbsolutePath);
}
Result += " -dead_strip";
Result += " -m" + GetXcodeMinVersionParam() + "=" + ProjectSettings.RuntimeVersion;
Result += " -Wl";
if(!IsBitcodeCompilingEnabled(LinkEnvironment.Configuration))
{
Result += "-no_pie";
}
Result += " -stdlib=libc++";
Result += " -ObjC";
// Result += " -v";
string SanitizerMode = Environment.GetEnvironmentVariable("ENABLE_ADDRESS_SANITIZER");
if(SanitizerMode != null && SanitizerMode == "YES")
{
Result += " -rpath \"@executable_path/Frameworks/libclang_rt.asan_ios_dynamic.dylib\"";
Result += " -fsanitize=address";
}
Result += " " + GetAdditionalLinkerFlags(LinkEnvironment.Configuration);
// link in the frameworks
foreach (string Framework in LinkEnvironment.Frameworks)
{
Result += " -framework " + Framework;
}
foreach (UEBuildFramework Framework in LinkEnvironment.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.WeakFrameworks)
{
Result += " -weak_framework " + Framework;
}
return Result;
}
static string GetArchiveArguments_Global(LinkEnvironment LinkEnvironment)
{
string Result = "";
Result += " -static";
return Result;
}
public override CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List SourceFiles, string ModuleName, ActionGraph ActionGraph)
{
string Arguments = GetCompileArguments_Global(CompileEnvironment);
string PCHArguments = "";
if (CompileEnvironment.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.GetBuildPlatform(UnrealTargetPlatform.IOS).GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
PCHArguments += string.Format(" -include \"{0}\"", ConvertPath(CompileEnvironment.PrecompiledHeaderFile.AbsolutePath.Replace(PrecompiledFileExtension, "")));
}
foreach(FileReference ForceIncludeFile in CompileEnvironment.ForceIncludeFiles)
{
PCHArguments += String.Format(" -include \"{0}\"", ConvertPath(ForceIncludeFile.FullName));
}
// Add include paths to the argument list.
HashSet AllIncludes = new HashSet(CompileEnvironment.IncludePaths.UserIncludePaths);
AllIncludes.UnionWith(CompileEnvironment.IncludePaths.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.Definitions)
{
Arguments += string.Format(" -D\"{0}\"", Definition);
}
CPPOutput Result = new CPPOutput();
// Create a compile action for each source file.
foreach (FileItem SourceFile in SourceFiles)
{
Action CompileAction = ActionGraph.Add(ActionType.Compile);
string FileArguments = "";
string Extension = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant();
if (CompileEnvironment.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
{
// Compile the file as a C++ PCH.
FileArguments += GetCompileArguments_PCH();
FileArguments += GetRTTIFlag(CompileEnvironment);
}
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();
FileArguments += GetRTTIFlag(CompileEnvironment);
}
else if (Extension == ".MM")
{
// Compile the file as Objective-C++ code.
FileArguments += GetCompileArguments_MM();
FileArguments += GetRTTIFlag(CompileEnvironment);
}
else if (Extension == ".M")
{
// Compile the file as Objective-C++ code.
FileArguments += GetCompileArguments_M();
}
else
{
// Compile the file as C++ code.
FileArguments += GetCompileArguments_CPP();
FileArguments += GetRTTIFlag(CompileEnvironment);
// only use PCH for .cpp files
FileArguments += PCHArguments;
}
// Add the C++ source file and its included files to the prerequisite item list.
AddPrerequisiteSourceFile(CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems);
if (CompileEnvironment.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
{
var PrecompiledFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS).GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);
// Add the precompiled header file to the produced item list.
FileItem PrecompiledHeaderFile = FileItem.GetItemByFileReference(
FileReference.Combine(
CompileEnvironment.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);
}
else
{
if (CompileEnvironment.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
{
CompileAction.bIsUsingPCH = true;
CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile);
}
var ObjectFileExtension = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS).GetBinaryExtension(UEBuildBinaryType.Object);
// Add the object file to the produced item list.
FileItem ObjectFile = FileItem.GetItemByFileReference(
FileReference.Combine(
CompileEnvironment.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);
}
// Add the source file path to the command-line.
FileArguments += string.Format(" \"{0}\"", ConvertPath(SourceFile.AbsolutePath));
string CompilerPath = Settings.Value.ToolchainDir + IOSCompiler;
if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
{
CompileAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
}
string AllArgs = Arguments + FileArguments + CompileEnvironment.AdditionalArguments;
string SourceText = System.IO.File.ReadAllText(SourceFile.AbsolutePath);
if (CompileEnvironment.bOptimizeForSize && (SourceFile.AbsolutePath.Contains("ElementBatcher.cpp") || SourceText.Contains("ElementBatcher.cpp") || SourceFile.AbsolutePath.Contains("AnimationRuntime.cpp") || SourceText.Contains("AnimationRuntime.cpp")
|| SourceFile.AbsolutePath.Contains("AnimEncoding.cpp") || SourceText.Contains("AnimEncoding.cpp") || SourceFile.AbsolutePath.Contains("TextRenderComponent.cpp") || SourceText.Contains("TextRenderComponent.cpp")
|| SourceFile.AbsolutePath.Contains("SWidget.cpp") || SourceText.Contains("SWidget.cpp") || SourceFile.AbsolutePath.Contains("SCanvas.cpp") || SourceText.Contains("SCanvas.cpp") || SourceFile.AbsolutePath.Contains("ShaderCore.cpp") || SourceText.Contains("ShaderCore.cpp")
|| SourceFile.AbsolutePath.Contains("ParticleSystemRender.cpp") || SourceText.Contains("ParticleSystemRender.cpp")))
{
Console.WriteLine("Forcing {0} to --O3!", SourceFile.AbsolutePath);
AllArgs = AllArgs.Replace("-Oz", "-O3");
}
// RPC utility parameters are in terms of the Mac side
CompileAction.WorkingDirectory = GetMacDevSrcRoot();
CompileAction.CommandPath = CompilerPath;
CompileAction.CommandArguments = AllArgs; // Arguments + FileArguments + CompileEnvironment.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, ActionGraph ActionGraph)
{
string LinkerPath = Settings.Value.ToolchainDir +
(LinkEnvironment.bIsBuildingLibrary ? IOSArchiver : IOSLinker);
// Create an action that invokes the linker.
Action LinkAction = ActionGraph.Add(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();
// build this up over the rest of the function
string LinkCommandArguments = LinkEnvironment.bIsBuildingLibrary ? GetArchiveArguments_Global(LinkEnvironment) : GetLinkArguments_Global(LinkEnvironment);
if (!LinkEnvironment.bIsBuildingLibrary)
{
// Add the library paths to the argument list.
foreach (string LibraryPath in LinkEnvironment.LibraryPaths)
{
LinkCommandArguments += string.Format(" -L\"{0}\"", LibraryPath);
}
// Add the additional libraries to the argument list.
foreach (string AdditionalLibrary in LinkEnvironment.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(AdditionalLibrary);
FileItem RemoteLibFile = LocalToRemoteFileItem(LibFile, true);
LinkAction.PrerequisiteItems.Add(RemoteLibFile);
// and add to the commandline
LinkCommandArguments += string.Format(" \"{0}\"", ConvertPath(Path.GetFullPath(AdditionalLibrary)));
}
else
{
LinkCommandArguments += 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.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.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.GetItemByFileReference(LinkEnvironment.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 InputFileNames = new List();
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.bIsBuildingLibrary)
{
foreach (string Filename in InputFileNames)
{
LinkCommandArguments += " " + 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:
// LinkCommandArguments += string.Format(" -filelist \"{0}\"", ConvertPath(ResponsePath));
}
else
{
bool bIsUE4Game = LinkEnvironment.OutputFilePath.FullName.Contains("UE4Game");
FileReference ResponsePath = FileReference.Combine(((!bIsUE4Game && ProjectFile != null) ? ProjectFile.Directory : UnrealBuildTool.EngineDirectory), "Intermediate", "Build", LinkEnvironment.Platform.ToString(), "LinkFileList_" + LinkEnvironment.OutputFilePath.GetFileNameWithoutExtension() + ".tmp");
if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
{
ResponseFile.Create(ResponsePath, InputFileNames);
RPCUtilHelper.CopyFile(ResponsePath.FullName, ConvertPath(ResponsePath.FullName), true);
}
else
{
ResponseFile.Create(new FileReference(ConvertPath(ResponsePath.FullName)), InputFileNames);
}
LinkCommandArguments += string.Format(" @\"{0}\"", ConvertPath(ResponsePath.FullName));
}
// Add the output file to the command-line.
LinkCommandArguments += string.Format(" -o \"{0}\"", RemoteOutputFile.AbsolutePath);
// Add the additional arguments specified by the environment.
LinkCommandArguments += LinkEnvironment.AdditionalArguments;
// Only execute linking on the local PC.
LinkAction.bCanExecuteRemotely = false;
LinkAction.StatusDescription = string.Format("{0}", OutputFile.AbsolutePath);
LinkAction.OutputEventHandler = new DataReceivedEventHandler(RemoteOutputReceivedEventHandler);
LinkAction.CommandPath = "sh";
if(LinkEnvironment.Configuration == CppConfiguration.Shipping && Path.GetExtension(RemoteOutputFile.AbsolutePath) != ".a")
{
// When building a shipping package, symbols are stripped from the exe as the last build step. This is a problem
// when re-packaging and no source files change because the linker skips symbol generation and dsymutil will
// recreate a new .dsym file from a symboless exe file. It's just sad. To make things happy we need to delete
// the output file to force the linker to recreate it with symbols again.
string linkCommandArguments = "-c '";
linkCommandArguments += string.Format("rm -f \"{0}\";", RemoteOutputFile.AbsolutePath);
linkCommandArguments += string.Format("rm -f \"{0}\\*.bcsymbolmap\";", Path.GetDirectoryName(RemoteOutputFile.AbsolutePath));
linkCommandArguments += LinkerPath + " " + LinkCommandArguments + ";";
linkCommandArguments += "'";
LinkAction.CommandArguments = linkCommandArguments;
}
else
{
// This is not a shipping build so no need to delete the output file since symbols will not have been stripped from it.
LinkAction.CommandArguments = string.Format("-c '{0} {1}'", LinkerPath, LinkCommandArguments);
}
return RemoteOutputFile;
}
public FileItem CompileAssetCatalog(FileItem Executable, string EngineDir, string BuildDir, string IntermediateDir, ActionGraph ActionGraph)
{
// Make a file item for the source and destination files
FileItem LocalExecutable = RemoteToLocalFileItem(Executable);
string FullDestPathRoot = Path.Combine(Path.GetDirectoryName(LocalExecutable.AbsolutePath), "Assets.car");
FileItem OutputFile;
/* if (!Utils.IsRunningOnMono && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
{
OutputFile = FileItem.GetRemoteItemByPath(FullDestPathRoot, UnrealTargetPlatform.IOS);
}
else*/
{
OutputFile = FileItem.GetItemByPath(FullDestPathRoot);
}
// Make the compile action
Action CompileAssetAction = ActionGraph.Add(ActionType.CreateAppBundle);
if (!Utils.IsRunningOnMono)
{
CompileAssetAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
}
CompileAssetAction.WorkingDirectory = GetMacDevSrcRoot();
CompileAssetAction.CommandPath = "/usr/bin/xcrun";
FileItem AssetCat = FileItem.GetItemByPath(Path.Combine(IntermediateDir, "Assets.xcassets"));
FileItem DestFile = LocalToRemoteFileItem(OutputFile, false);
FileItem InputFile = LocalToRemoteFileItem(AssetCat, BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac);
string Arguments = "";
Arguments += " actool --output-format human-readable-text --notices --warnings";
Arguments += " --output-partial-info-plist \"";
Arguments += Path.GetDirectoryName(DestFile.AbsolutePath).Replace("\\", "/") + "/assetcatalog_generated_info.plist\"";
Arguments += " --app-icon AppIcon --launch-image LaunchImage --compress-pngs";
Arguments += " --enable-on-demand-resources YES --filter-for-device-model AppleTV5,3 --filter-for-device-os-version 9.2";
Arguments += " --target-device tv --minimum-deployment-target 9.2 --platform appletvos --compile \"";
Arguments += Path.GetDirectoryName(DestFile.AbsolutePath).Replace("\\", "/") + "\" \"" + InputFile.AbsolutePath + "\"";
CompileAssetAction.CommandArguments = Arguments;
CompileAssetAction.PrerequisiteItems.Add(Executable);
CompileAssetAction.ProducedItems.Add(DestFile);
CompileAssetAction.StatusDescription = CompileAssetAction.CommandArguments;// string.Format("Generating debug info for {0}", Path.GetFileName(Executable.AbsolutePath));
CompileAssetAction.bCanExecuteRemotely = false;
return DestFile;
}
///
/// Generates debug info for a given executable
///
/// FileItem describing the executable to generate debug info for
///
public FileItem GenerateDebugInfo(FileItem Executable, ActionGraph ActionGraph)
{
// Make a file item for the source and destination files
FileItem LocalExecutable = RemoteToLocalFileItem(Executable);
string FullDestPathRoot = Path.Combine(Path.GetDirectoryName(LocalExecutable.AbsolutePath), Path.GetFileName(LocalExecutable.AbsolutePath) + ".dSYM");
FileItem OutputFile;
OutputFile = FileItem.GetItemByPath(FullDestPathRoot);
FileItem DestFile = LocalToRemoteFileItem(OutputFile, false);
// Make the compile action
Action GenDebugAction = ActionGraph.Add(ActionType.GenerateDebugInfo);
if (!Utils.IsRunningOnMono)
{
GenDebugAction.ActionHandler = new Action.BlockingActionHandler(RPCUtilHelper.RPCActionHandler);
}
GenDebugAction.WorkingDirectory = GetMacDevSrcRoot();
GenDebugAction.CommandPath = "sh";
if(ProjectSettings.bGeneratedSYMBundle)
{
GenDebugAction.CommandArguments = string.Format("-c 'rm -rf \"{1}\"; /usr/bin/dsymutil \"{0}\" -o \"{1}\"; cd \"{1}/..\"; zip -r -y -1 {2}.zip {2}'",
Executable.AbsolutePath,
DestFile.AbsolutePath,
Path.GetFileName(FullDestPathRoot));
}
else
{
GenDebugAction.CommandArguments = string.Format("-c 'rm -rf \"{1}\"; /usr/bin/dsymutil \"{0}\" -f -o \"{1}\"'",
Executable.AbsolutePath,
DestFile.AbsolutePath);
}
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 static 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 static new void PreBuildSync()
{
if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
{
BuiltBinaries = new List();
}
RemoteToolChain.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 void GenerateAssetCatalog(string EngineDir, string BuildDir, string IntermediateDir)
{
string[] Directories = { "Assets.xcassets",
Path.Combine("Assets.xcassets", "AppIcon.brandassets"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconLarge.imagestack"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconLarge.imagestack", "Back.imagestacklayer"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconLarge.imagestack", "Back.imagestacklayer", "Content.imageset"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconLarge.imagestack", "Front.imagestacklayer"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconLarge.imagestack", "Front.imagestacklayer", "Content.imageset"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconLarge.imagestack", "Middle.imagestacklayer"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconLarge.imagestack", "Middle.imagestacklayer", "Content.imageset"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconSmall.imagestack"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconSmall.imagestack", "Back.imagestacklayer"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconSmall.imagestack", "Back.imagestacklayer", "Content.imageset"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconSmall.imagestack", "Front.imagestacklayer"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconSmall.imagestack", "Front.imagestacklayer", "Content.imageset"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconSmall.imagestack", "Middle.imagestacklayer"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "AppIconSmall.imagestack", "Middle.imagestacklayer", "Content.imageset"),
Path.Combine("Assets.xcassets", "AppIcon.brandassets", "TopShelf.imageset"),
Path.Combine("Assets.xcassets", "LaunchImage.launchimage"),
};
string[] Contents = { "{\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"assets\" : [\n\t\t{\n\t\t\t\"size\" : \"1280x768\",\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"AppIconLarge.imagestack\",\n\t\t\t\"role\" : \"primary-app-icon\"\n\t\t},\n\t\t{\n\t\t\t\"size\" : \"400x240\",\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"AppIconSmall.imagestack\",\n\t\t\t\"role\" : \"primary-app-icon\"\n\t\t},\n\t\t{\n\t\t\t\"size\" : \"1920x720\",\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"TopShelf.imageset\",\n\t\t\t\"role\" : \"top-shelf-image\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"layers\" : [\n\t\t{\n\t\t\t\"filename\" : \"Front.imagestacklayer\"\n\t\t},\n\t\t{\n\t\t\t\"filename\" : \"Middle.imagestacklayer\"\n\t\t},\n\t\t{\n\t\t\t\"filename\" : \"Back.imagestacklayer\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"images\" : [\n\t\t{\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"Icon_Large_Back.png\",\n\t\t\t\"scale\" : \"1x\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"images\" : [\n\t\t{\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"Icon_Large_Front.png\",\n\t\t\t\"scale\" : \"1x\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"images\" : [\n\t\t{\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"Icon_Large_Middle.png\",\n\t\t\t\"scale\" : \"1x\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"layers\" : [\n\t\t{\n\t\t\t\"filename\" : \"Front.imagestacklayer\"\n\t\t},\n\t\t{\n\t\t\t\"filename\" : \"Middle.imagestacklayer\"\n\t\t},\n\t\t{\n\t\t\t\"filename\" : \"Back.imagestacklayer\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"images\" : [\n\t\t{\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"Icon_Small_Back.png\",\n\t\t\t\"scale\" : \"1x\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"images\" : [\n\t\t{\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"Icon_Small_Front.png\",\n\t\t\t\"scale\" : \"1x\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"images\" : [\n\t\t{\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"Icon_Small_Middle.png\",\n\t\t\t\"scale\" : \"1x\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"images\" : [\n\t\t{\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"TopShelf.png\",\n\t\t\t\"scale\" : \"1x\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
"{\n\t\"images\" : [\n\t\t{\n\t\t\t\"orientation\" : \"landscape\",\n\t\t\t\"idiom\" : \"tv\",\n\t\t\t\"filename\" : \"Launch.png\",\n\t\t\t\"extent\" : \"full-screen\",\n\t\t\t\"minimum-system-version\" : \"9.0\",\n\t\t\t\"scale\" : \"1x\"\n\t\t}\n\t],\n\t\"info\" : {\n\t\t\"version\" : 1,\n\t\t\"author\" : \"xcode\"\n\t}\n}",
};
string[] Images = { null,
null,
null,
null,
"Icon_Large_Back.png",
null,
"Icon_Large_Front.png",
null,
"Icon_Large_Middle.png",
null,
null,
"Icon_Small_Back.png",
null,
"Icon_Small_Front.png",
null,
"Icon_Small_Middle.png",
"TopShelf.png",
"Launch.png"
};
// create asset catalog for images
for (int i = 0; i < Directories.Length; ++i)
{
string Dir = Path.Combine(IntermediateDir, Directories[i]);
if (!Directory.Exists(Dir))
{
Directory.CreateDirectory(Dir);
}
File.WriteAllText(Path.Combine(Dir, "Contents.json"), Contents[i]);
LocalToRemoteFileItem(FileItem.GetItemByPath(Path.Combine(Dir, "Contents.json")), BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac);
if (Images[i] != null)
{
string Image = Path.Combine((Directory.Exists(Path.Combine(BuildDir, "Resource", "Graphics")) ? (BuildDir) : (Path.Combine(EngineDir,"Build", "TVOS"))), "Resources", "Graphics", Images[i]);
if (File.Exists(Image))
{
File.Copy(Image, Path.Combine(Dir, Images[i]), true);
LocalToRemoteFileItem(FileItem.GetItemByPath(Path.Combine(Dir, Images[i])), BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac);
FileInfo DestFileInfo = new FileInfo(Path.Combine(Dir, Images[i]));
DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
}
}
}
}
public override ICollection PostBuild(FileItem Executable, LinkEnvironment BinaryLinkEnvironment, ActionGraph ActionGraph)
{
var OutputFiles = base.PostBuild(Executable, BinaryLinkEnvironment, ActionGraph);
if (BinaryLinkEnvironment.bIsBuildingLibrary)
{
return OutputFiles;
}
// For IOS/tvOS, generate the dSYM file if the config file is set to do so
if (ProjectSettings.bGeneratedSYMFile == true || ProjectSettings.bGeneratedSYMBundle == true || BinaryLinkEnvironment.bUsePDBFiles == true)
{
OutputFiles.Add(GenerateDebugInfo(Executable, ActionGraph));
}
// for tvOS generate the asset catalog
if (CppPlatform == CppPlatform.TVOS)
{
string EngineDir = UnrealBuildTool.EngineDirectory.ToString();
string BuildDir = (((ProjectFile != null) ? ProjectFile.Directory : UnrealBuildTool.EngineDirectory)) + "/Build/TVOS";
string IntermediateDir = (((ProjectFile != null) ? ProjectFile.Directory : UnrealBuildTool.EngineDirectory)) + "/Intermediate/TVOS";
GenerateAssetCatalog(EngineDir, BuildDir, IntermediateDir);
OutputFiles.Add(CompileAssetCatalog(Executable, EngineDir, BuildDir, IntermediateDir, ActionGraph));
}
return OutputFiles;
}
public static string GetCodesignPlatformName(UnrealTargetPlatform Platform)
{
switch(Platform)
{
case UnrealTargetPlatform.TVOS:
return "appletvos";
case UnrealTargetPlatform.IOS:
return "iphoneos";
default:
throw new BuildException("Invalid platform for GetCodesignPlatformName()");
}
}
public static void PostBuildSync(UEBuildTarget Target)
{
IOSProjectSettings ProjectSettings = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.IOS)).ReadProjectSettings(Target.ProjectFile);
string AppName = Target.TargetType == TargetType.Game ? Target.TargetName : Target.AppName;
if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
{
string RemoteShadowDirectoryMac = Path.GetDirectoryName(Target.OutputPath.FullName);
string FinalRemoteExecutablePath = String.Format("{0}/Payload/{1}.app/{1}", RemoteShadowDirectoryMac, AppName);
// strip the debug info from the executable if needed
if (Target.Rules.bStripSymbolsOnIOS || (Target.Configuration == UnrealTargetConfiguration.Shipping))
{
Process StripProcess = new Process();
StripProcess.StartInfo.WorkingDirectory = RemoteShadowDirectoryMac;
StripProcess.StartInfo.FileName = new IOSToolChainSettings().ToolchainDir + "strip";
StripProcess.StartInfo.Arguments = "\"" + 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.FullName, FinalRemoteExecutablePath, true);
if (Target.Rules.bCreateStubIPA)
{
string Project = Target.ProjectDirectory + "/" + AppName + ".uproject";
string SchemeName = AppName;
// generate the dummy project so signing works
if (AppName == "UE4Game" || AppName == "UE4Client" || Utils.IsFileUnderDirectory(Target.ProjectDirectory + "/" + AppName + ".uproject", Path.GetFullPath("../..")))
{
UnrealBuildTool.GenerateProjectFiles(new XcodeProjectFileGenerator(Target.ProjectFile), new string[] { "-platforms=" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS"), "-NoIntellIsense", (Target.Platform == UnrealTargetPlatform.IOS ? "-iosdeployonly" : "-tvosdeployonly"), "-ignorejunk" });
Project = Path.GetFullPath("../..") + "/UE4_" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS") + ".xcworkspace";
SchemeName = "UE4";
}
else
{
UnrealBuildTool.GenerateProjectFiles(new XcodeProjectFileGenerator(Target.ProjectFile), new string[] { "-platforms" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS"), "-NoIntellIsense", (Target.Platform == UnrealTargetPlatform.IOS ? "-iosdeployonly" : "-tvosdeployonly"), "-ignorejunk", "-project=\"" + Target.ProjectDirectory + "/" + AppName + ".uproject\"", "-game" });
Project = Target.ProjectDirectory + "/" + AppName + "_" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS") + ".xcworkspace";
}
if (Directory.Exists(Project))
{
// ensure the plist, entitlements, and provision files are properly copied
var DeployHandler = (Target.Platform == UnrealTargetPlatform.IOS ? new UEDeployIOS() : new UEDeployTVOS());
DeployHandler.PrepTargetForDeployment(new UEBuildDeployTarget(Target));
var ConfigName = Target.Configuration.ToString();
if (Target.Rules.Type != TargetType.Game && Target.Rules.Type != TargetType.Program)
{
ConfigName += " " + Target.Rules.Type.ToString();
}
// code sign the project
IOSProvisioningData ProvisioningData = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(Target.Platform)).ReadProvisioningData(ProjectSettings);
string CmdLine = new IOSToolChainSettings().XcodeDeveloperDir + "usr/bin/xcodebuild" +
" -workspace \"" + Project + "\"" +
" -configuration \"" + ConfigName + "\"" +
" -scheme '" + SchemeName + "'" +
" -sdk " + GetCodesignPlatformName(Target.Platform) +
" -destination generic/platform=" + (Target.Platform == UnrealTargetPlatform.IOS ? "iOS" : "tvOS") +
(!string.IsNullOrEmpty(ProvisioningData.TeamUUID) ? " DEVELOPMENT_TEAM=" + ProvisioningData.TeamUUID : "");
if (!ProjectSettings.bAutomaticSigning)
{
CmdLine += " CODE_SIGN_IDENTITY=\"" + (!string.IsNullOrEmpty(ProvisioningData.SigningCertificate) ? ProvisioningData.SigningCertificate : "IPhoneDeveloper") + "\"" +
(!string.IsNullOrEmpty(ProvisioningData.MobileProvisionUUID) ? (" PROVISIONING_PROFILE_SPECIFIER=" + ProvisioningData.MobileProvisionUUID) : "");
}
else
{
CmdLine += " 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("_" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS") + ".xcodeproj"))
{
Directory.Delete(Project, true);
}
if (OutputReceivedDataEventHandlerEncounteredError)
{
throw new Exception(OutputReceivedDataEventHandlerEncounteredErrorMessage);
}
// Package the stub
PackageStub(RemoteShadowDirectoryMac, AppName, Target.OutputPath.GetFileNameWithoutExtension());
}
}
{
// 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/" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS") + "/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
}
string UnpackedZipPath = GetRemoteIntermediateFrameworkZipPath(Framework);
// For now, this is hard coded, but we need to loop over all modules, and copy bundled assets that need it
string LocalSource = UnpackedZipPath + "/" + 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, LocalDest), out ResultsText);
}
}
}
else
{
// store off the binaries
foreach (UEBuildBinary Binary in Target.AppBinaries)
{
BuiltBinaries.Add(Binary.Config.OutputFilePath);
}
// check to see if the DangerouslyFast mode is valid (in other words, a build has gone through since a Rebuild/Clean operation)
FileReference DangerouslyFastValidFile = FileReference.Combine(Target.ProjectIntermediateDirectory, "DangerouslyFastIsNotDangerous");
bool bUseDangerouslyFastModeWasRequested = bUseDangerouslyFastMode;
if (bUseDangerouslyFastMode)
{
if (!FileReference.Exists(DangerouslyFastValidFile))
{
Log.TraceInformation("Dangeroulsy Fast mode was requested, but a slow mode hasn't completed. Performing slow now...");
bUseDangerouslyFastMode = false;
}
}
foreach (FileReference FilePath in BuiltBinaries)
{
string RemoteExecutablePath = ConvertPath(FilePath.FullName);
// 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.FullName));
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.FullName, false);
if ((ProjectSettings.bGeneratedSYMFile == true || ProjectSettings.bGeneratedSYMBundle == true) && Path.GetExtension(FilePath.FullName) != ".a")
{
string DSYMExt;
if(ProjectSettings.bGeneratedSYMBundle)
{
DSYMExt = ".dSYM.zip";
}
else
{
DSYMExt = ".dSYM";
}
RPCUtilHelper.CopyFile(RemoteExecutablePath + DSYMExt, FilePath.FullName + DSYMExt, false);
}
}
}
// Generate the stub
if (Target.Rules.bCreateStubIPA || bUseDangerouslyFastMode)
{
// ensure the plist, entitlements, and provision files are properly copied
var DeployHandler = (Target.Platform == UnrealTargetPlatform.IOS ? new UEDeployIOS() : new UEDeployTVOS());
DeployHandler.PrepTargetForDeployment(new UEBuildDeployTarget(Target));
if (!bUseDangerouslyFastMode)
{
// generate the dummy project so signing works
UnrealBuildTool.GenerateProjectFiles(new XcodeProjectFileGenerator(Target.ProjectFile), new string[] { "-NoIntellisense", (Target.Platform == UnrealTargetPlatform.IOS ? "-iosdeployonly" : "-tvosdeployonly"), ((Target.ProjectFile != null) ? "-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 = Target.RulesAssembly.GetTargetFileName(AppName).FullName;
string SchemeName = 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 (AppName != "UE4Game" && AppName != "UE4Client")
{
PathToApp += "\\" + AppName + ".uproject";
}
else
{
SchemeName = "UE4";
}
}
var SchemeConfiguration = Target.Configuration.ToString();
if (Target.Rules.Type != TargetType.Game && Target.Rules.Type != TargetType.Program)
{
SchemeConfiguration += " " + Target.Rules.Type.ToString();
}
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 (Target.Rules.bStripSymbolsOnIOS || (Target.Configuration == UnrealTargetConfiguration.Shipping))
{
Arguments += " -strip";
}
}
Arguments += " -config " + Target.Configuration + " -mac " + RemoteServerName + " -schemename " + SchemeName + " -schemeconfig \"" + SchemeConfiguration + "\"";
string Architecture = Target.Architecture;
if (Architecture != "")
{
// pass along the architecture if we need, skipping the initial -, so we have "-architecture simulator"
Arguments += " -architecture " + Architecture.Substring(1);
}
if (Target.Platform == UnrealTargetPlatform.TVOS)
{
Arguments += " -tvos";
}
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 = "";
int ExitCode = Utils.RunLocalProcess(StubGenerateProcess);
if (OutputReceivedDataEventHandlerEncounteredError)
{
UnrealBuildTool.ExtendedErrorCode = ExitCode;
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.FullName);
}
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.FullName);
}
}
{
// 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/" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS") + "/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
}
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, RemoteDest), "", 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);
}
}
if (Target.Platform == UnrealTargetPlatform.TVOS)
{
// copy back the built asset catalog
string CatPath = Path.GetDirectoryName(Target.OutputPath.FullName) + "\\Assets.car";
RPCUtilHelper.CopyFile(ConvertPath(CatPath), CatPath, false);
}
// If it is requested, send the app bundle back to the platform executing these commands.
if (Target.Rules.bCopyAppBundleBackToDevice)
{
Log.TraceInformation("Copying binaries back to this device...");
try
{
string BinaryDir = Path.GetDirectoryName(Target.OutputPath.FullName) + "\\";
if (BinaryDir.EndsWith(Target.AppName + "\\Binaries\\" + (Target.Platform == UnrealTargetPlatform.IOS ? "IOS" : "TVOS") + "\\") && Target.TargetType != TargetType.Game)
{
BinaryDir = BinaryDir.Replace(Target.TargetType.ToString(), "Game");
}
// Get the app bundle's name
string AppFullName = Target.AppName;
if (Target.Configuration != UnrealTargetConfiguration.Development)
{
AppFullName += "-" + Target.Platform.ToString();
AppFullName += "-" + Target.Configuration.ToString();
}
foreach (string BinaryPath in BuiltBinaries.Select(x => x.FullName))
{
if (!BinaryPath.Contains("Dummy"))
{
RPCUtilHelper.CopyFile(ConvertPath(BinaryPath), BinaryPath, false);
}
}
Log.TraceInformation("Copied binaries successfully.");
}
catch (Exception)
{
Log.TraceInformation("Copying binaries back to this device failed.");
}
}
}
}
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 void StripSymbols(FileReference SourceFile, FileReference TargetFile)
{
StripSymbolsWithXcode(SourceFile, TargetFile, Settings.Value.ToolchainDir);
}
};
}