Ejemplo n.º 1
0
 /// <summary>
 /// Constructs a TargetInfo for passing to the TargetRules constructor.
 /// </summary>
 /// <param name="Name">Name of the target being built</param>
 /// <param name="Platform">The platform that the target is being built for</param>
 /// <param name="Configuration">The configuration being built</param>
 /// <param name="Architecture">The architecture being built for</param>
 /// <param name="ProjectFile">Path to the project file containing the target</param>
 /// <param name="Version">The current build version</param>
 public TargetInfo(string Name, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string Architecture, FileReference ProjectFile, ReadOnlyBuildVersion Version)
 {
     this.Name          = Name;
     this.Platform      = Platform;
     this.Configuration = Configuration;
     this.Architecture  = Architecture;
     this.ProjectFile   = ProjectFile;
     this.Version       = Version;
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Constructs a TargetInfo for passing to the ModuleRules constructor.
 /// </summary>
 /// <param name="Rules">The constructed target rules object. This is null when passed into a TargetRules constructor, but should be valid at all other times.</param>
 public TargetInfo(ReadOnlyTargetRules Rules)
 {
     this.Name          = Rules.Name;
     this.Platform      = Rules.Platform;
     this.Configuration = Rules.Configuration;
     this.Architecture  = Rules.Architecture;
     this.ProjectFile   = Rules.ProjectFile;
     this.Version       = Rules.Version;
 }
Ejemplo n.º 3
0
 /// <summary>
 /// Constructs a TargetInfo for passing to the ModuleRules constructor.
 /// </summary>
 /// <param name="Rules">The constructed target rules object. This is null when passed into a TargetRules constructor, but should be valid at all other times.</param>
 public TargetInfo(ReadOnlyTargetRules Rules)
 {
     this.Name          = Rules.Name;
     this.Platform      = Rules.Platform;
     this.Configuration = Rules.Configuration;
     this.Architecture  = Rules.Architecture;
     this.ProjectFile   = Rules.ProjectFile;
     this.Version       = Rules.Version;
     this.Type          = Rules.Type;
     this.bIsMonolithic = (Rules.LinkType == TargetLinkType.Monolithic);
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Determines a target name based on the type of target we're trying to build
        /// </summary>
        /// <param name="Type">The type of target to look for</param>
        /// <param name="Platform">The platform being built</param>
        /// <param name="Configuration">The configuration being built</param>
        /// <param name="Architecture">The architecture being built</param>
        /// <param name="ProjectFile">Project file for the target being built</param>
        /// <param name="Version">The current engine version information</param>
        /// <returns>Name of the target for the given type</returns>
        public string GetTargetNameByType(TargetType Type, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string Architecture, FileReference ProjectFile, ReadOnlyBuildVersion Version)
        {
            // Create all the targets in this assembly
            List <string> Matches = new List <string>();

            foreach (KeyValuePair <string, FileReference> TargetPair in TargetNameToTargetFile)
            {
                TargetRules Rules = CreateTargetRulesInstance(TargetPair.Key + "Target", new TargetInfo(TargetPair.Key, Platform, Configuration, Architecture, ProjectFile, Version));
                if (Rules.Type == Type)
                {
                    Matches.Add(TargetPair.Key);
                }
            }

            // If we got a result, return it. If there were multiple results, fail.
            if (Matches.Count == 0)
            {
                if (Parent == null)
                {
                    throw new BuildException("Unable to find target of type '{0}' for project '{1}'", Type, ProjectFile);
                }
                else
                {
                    return(Parent.GetTargetNameByType(Type, Platform, Configuration, Architecture, ProjectFile, Version));
                }
            }
            else
            {
                if (Matches.Count == 1)
                {
                    return(Matches[0]);
                }
                else
                {
                    throw new BuildException("Found multiple targets with TargetType={0}: {1}", Type, String.Join(", ", Matches));
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Creates a target rules object for the specified target name.
        /// </summary>
        /// <param name="TargetName">Name of the target</param>
        /// <param name="Platform">Platform being compiled</param>
        /// <param name="Configuration">Configuration being compiled</param>
        /// <param name="Architecture">Architecture being built</param>
        /// <param name="ProjectFile">Path to the project file for this target</param>
        /// <param name="Version">The current build version</param>
        /// <param name="TargetFileName">The original source file name of the Target.cs file for this target</param>
        /// <returns>The build target rules for the specified target</returns>
        public TargetRules CreateTargetRules(string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string Architecture, FileReference ProjectFile, ReadOnlyBuildVersion Version, out FileReference TargetFileName)
        {
            bool bFoundTargetName = TargetNameToTargetFile.ContainsKey(TargetName);

            if (bFoundTargetName == false)
            {
                if (Parent == null)
                {
                    //				throw new BuildException("Couldn't find target rules file for target '{0}' in rules assembly '{1}'.", TargetName, RulesAssembly.FullName);
                    string ExceptionMessage = "Couldn't find target rules file for target '";
                    ExceptionMessage += TargetName;
                    ExceptionMessage += "' in rules assembly '";
                    ExceptionMessage += CompiledAssembly.FullName;
                    ExceptionMessage += "'." + Environment.NewLine;

                    ExceptionMessage += "Location: " + CompiledAssembly.Location + Environment.NewLine;

                    ExceptionMessage += "Target rules found:" + Environment.NewLine;
                    foreach (KeyValuePair <string, FileReference> entry in TargetNameToTargetFile)
                    {
                        ExceptionMessage += "\t" + entry.Key + " - " + entry.Value + Environment.NewLine;
                    }

                    throw new BuildException(ExceptionMessage);
                }
                else
                {
                    return(Parent.CreateTargetRules(TargetName, Platform, Configuration, Architecture, ProjectFile, Version, out TargetFileName));
                }
            }

            // Return the target file name to the caller
            TargetFileName = TargetNameToTargetFile[TargetName];

            // Currently, we expect the user's rules object type name to be the same as the module name + 'Target'
            string TargetTypeName = TargetName + "Target";

            // The build module must define a type named '<TargetName>Target' that derives from our 'TargetRules' type.
            return(CreateTargetRulesInstance(TargetTypeName, new TargetInfo(TargetName, Platform, Configuration, Architecture, ProjectFile, Version)));
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Creates a target rules object for the specified target name.
        /// </summary>
        /// <param name="TargetName">Name of the target</param>
        /// <param name="Platform">The platform that the target is being built for</param>
        /// <param name="Configuration">The configuration the target is being built for</param>
        /// <param name="Architecture">The architecture the target is being built for</param>
        /// <param name="ProjectFile">The project containing the target being built</param>
        /// <param name="Version">The current build version</param>
        /// <returns>The build target rules for the specified target</returns>
        public TargetRules CreateTargetRules(string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string Architecture, FileReference ProjectFile, ReadOnlyBuildVersion Version)
        {
            FileReference TargetFileName;

            return(CreateTargetRules(TargetName, Platform, Configuration, Architecture, ProjectFile, Version, out TargetFileName));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Creates a rules assembly
        /// </summary>
        /// <param name="Scope">Scope for items created from this assembly</param>
        /// <param name="RootDirectories">The root directories to create rules for</param>
        /// <param name="AssemblyPrefix">A prefix for the assembly file name</param>
        /// <param name="Plugins">List of plugins to include in this assembly</param>
        /// <param name="bReadOnly">Whether the assembly should be marked as installed</param>
        /// <param name="bSkipCompile">Whether to skip compilation for this assembly</param>
        /// <param name="Parent">The parent rules assembly</param>
        /// <returns>New rules assembly</returns>
        private static RulesAssembly CreateEngineOrEnterpriseRulesAssembly(RulesScope Scope, List <DirectoryReference> RootDirectories, string AssemblyPrefix, IReadOnlyList <PluginInfo> Plugins, bool bReadOnly, bool bSkipCompile, RulesAssembly Parent)
        {
            // Scope hierarchy
            RulesScope PluginsScope  = new RulesScope(Scope.Name + " Plugins", Scope);
            RulesScope ProgramsScope = new RulesScope(Scope.Name + " Programs", PluginsScope);

            // Find the shared modules, excluding the programs directory. These are used to create an assembly with the bContainsEngineModules flag set to true.
            Dictionary <FileReference, ModuleRulesContext> ModuleFileToContext = new Dictionary <FileReference, ModuleRulesContext>();
            ModuleRulesContext DefaultModuleContext = new ModuleRulesContext(Scope, RootDirectories[0]);

            foreach (DirectoryReference RootDirectory in RootDirectories)
            {
                using (Timeline.ScopeEvent("Finding engine modules"))
                {
                    DirectoryReference SourceDirectory = DirectoryReference.Combine(RootDirectory, "Source");

                    AddEngineModuleRulesWithContext(SourceDirectory, "Runtime", DefaultModuleContext, UHTModuleType.EngineRuntime, ModuleFileToContext);
                    AddEngineModuleRulesWithContext(SourceDirectory, "Developer", DefaultModuleContext, UHTModuleType.EngineDeveloper, ModuleFileToContext);
                    AddEngineModuleRulesWithContext(SourceDirectory, "Editor", DefaultModuleContext, UHTModuleType.EngineEditor, ModuleFileToContext);
                    AddEngineModuleRulesWithContext(SourceDirectory, "ThirdParty", DefaultModuleContext, UHTModuleType.EngineThirdParty, ModuleFileToContext);
                }
            }

            // Add all the plugin modules too (don't need to loop over RootDirectories since the plugins come in already found
            using (Timeline.ScopeEvent("Finding plugin modules"))
            {
                ModuleRulesContext PluginsModuleContext = new ModuleRulesContext(PluginsScope, RootDirectories[0]);
                FindModuleRulesForPlugins(Plugins, PluginsModuleContext, ModuleFileToContext);
            }

            // Get the path to store any generated assemblies
            DirectoryReference AssemblyDir = RootDirectories[0];

            if (UnrealBuildTool.IsFileInstalled(FileReference.Combine(AssemblyDir, AssemblyPrefix)))
            {
                DirectoryReference UserDir = Utils.GetUserSettingDirectory();
                if (UserDir != null)
                {
                    ReadOnlyBuildVersion Version = ReadOnlyBuildVersion.Current;
                    AssemblyDir = DirectoryReference.Combine(UserDir, "UnrealEngine", String.Format("{0}.{1}", Version.MajorVersion, Version.MinorVersion));
                }
            }

            // Create the assembly
            FileReference EngineAssemblyFileName = FileReference.Combine(AssemblyDir, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "Rules" + FrameworkAssemblyExtension);
            RulesAssembly EngineAssembly         = new RulesAssembly(Scope, RootDirectories, Plugins, ModuleFileToContext, new List <FileReference>(), EngineAssemblyFileName, bContainsEngineModules: true, DefaultBuildSettings: BuildSettingsVersion.Latest, bReadOnly: bReadOnly, bSkipCompile: bSkipCompile, Parent: Parent);

            List <FileReference> ProgramTargetFiles = new List <FileReference>();
            Dictionary <FileReference, ModuleRulesContext> ProgramModuleFiles = new Dictionary <FileReference, ModuleRulesContext>();

            foreach (DirectoryReference RootDirectory in RootDirectories)
            {
                DirectoryReference SourceDirectory   = DirectoryReference.Combine(RootDirectory, "Source");
                DirectoryReference ProgramsDirectory = DirectoryReference.Combine(SourceDirectory, "Programs");

                // Also create a scope for them, and update the UHT module type
                ModuleRulesContext ProgramsModuleContext = new ModuleRulesContext(ProgramsScope, RootDirectory);
                ProgramsModuleContext.DefaultUHTModuleType = UHTModuleType.Program;

                using (Timeline.ScopeEvent("Finding program modules"))
                {
                    // Find all the rules files
                    AddModuleRulesWithContext(ProgramsDirectory, ProgramsModuleContext, ProgramModuleFiles);
                }

                using (Timeline.ScopeEvent("Finding program targets"))
                {
                    ProgramTargetFiles.AddRange(FindAllRulesFiles(SourceDirectory, RulesFileType.Target));
                }
            }

            // Create a path to the assembly that we'll either load or compile
            FileReference ProgramAssemblyFileName = FileReference.Combine(AssemblyDir, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "ProgramRules" + FrameworkAssemblyExtension);
            RulesAssembly ProgramAssembly         = new RulesAssembly(ProgramsScope, RootDirectories, new List <PluginInfo>().AsReadOnly(), ProgramModuleFiles, ProgramTargetFiles, ProgramAssemblyFileName, bContainsEngineModules: false, DefaultBuildSettings: BuildSettingsVersion.Latest, bReadOnly: bReadOnly, bSkipCompile: bSkipCompile, Parent: EngineAssembly);

            // Return the combined assembly
            return(ProgramAssembly);
        }
Ejemplo n.º 8
0
 private static string FormatVersionNumber(ReadOnlyBuildVersion Version)
 {
     return(string.Format("{0}.{1}.{2}", Version.MajorVersion, Version.MinorVersion, Version.PatchVersion));
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Dynamically compiles an assembly for the specified source file and loads that assembly into the application's
        /// current domain.  If an assembly has already been compiled and is not out of date, then it will be loaded and
        /// no compilation is necessary.
        /// </summary>
        /// <param name="OutputAssemblyPath">Full path to the assembly to be created</param>
        /// <param name="SourceFileNames">List of source file name</param>
        /// <param name="ReferencedAssembies"></param>
        /// <param name="PreprocessorDefines"></param>
        /// <param name="DoNotCompile"></param>
        /// <param name="TreatWarningsAsErrors"></param>
        /// <returns>The assembly that was loaded</returns>
        public static Assembly CompileAndLoadAssembly(FileReference OutputAssemblyPath, HashSet <FileReference> SourceFileNames, List <string> ReferencedAssembies = null, List <string> PreprocessorDefines = null, bool DoNotCompile = false, bool TreatWarningsAsErrors = false)
        {
            // Check to see if the resulting assembly is compiled and up to date
            FileReference AssemblyManifestFilePath = FileReference.Combine(OutputAssemblyPath.Directory, Path.GetFileNameWithoutExtension(OutputAssemblyPath.FullName) + "Manifest.json");

            bool bNeedsCompilation = false;

            if (!DoNotCompile)
            {
                bNeedsCompilation = RequiresCompilation(SourceFileNames, AssemblyManifestFilePath, OutputAssemblyPath);
            }

            // Load the assembly to ensure it is correct
            Assembly CompiledAssembly = null;

            if (!bNeedsCompilation)
            {
                try
                {
                    // Load the previously-compiled assembly from disk
                    CompiledAssembly = Assembly.LoadFile(OutputAssemblyPath.FullName);
                }
                catch (FileLoadException Ex)
                {
                    Log.TraceInformation(String.Format("Unable to load the previously-compiled assembly file '{0}'.  Unreal Build Tool will try to recompile this assembly now.  (Exception: {1})", OutputAssemblyPath, Ex.Message));
                    bNeedsCompilation = true;
                }
                catch (BadImageFormatException Ex)
                {
                    Log.TraceInformation(String.Format("Compiled assembly file '{0}' appears to be for a newer CLR version or is otherwise invalid.  Unreal Build Tool will try to recompile this assembly now.  (Exception: {1})", OutputAssemblyPath, Ex.Message));
                    bNeedsCompilation = true;
                }
                catch (FileNotFoundException)
                {
                    throw new BuildException("Precompiled rules assembly '{0}' does not exist.", OutputAssemblyPath);
                }
                catch (Exception Ex)
                {
                    throw new BuildException(Ex, "Error while loading previously-compiled assembly file '{0}'.  (Exception: {1})", OutputAssemblyPath, Ex.Message);
                }
            }

            // Compile the assembly if me
            if (bNeedsCompilation)
            {
                using (Timeline.ScopeEvent(String.Format("Compiling rules assembly ({0})", OutputAssemblyPath.GetFileName())))
                {
                    CompiledAssembly = CompileAssembly(OutputAssemblyPath, SourceFileNames, ReferencedAssembies, PreprocessorDefines, TreatWarningsAsErrors);
                }

                using (JsonWriter Writer = new JsonWriter(AssemblyManifestFilePath))
                {
                    ReadOnlyBuildVersion Version = ReadOnlyBuildVersion.Current;

                    Writer.WriteObjectStart();
                    // Save out a list of all the source files we compiled.  This is so that we can tell if whole files were added or removed
                    // since the previous time we compiled the assembly.  In that case, we'll always want to recompile it!
                    Writer.WriteStringArrayField("SourceFiles", SourceFileNames.Select(x => x.FullName));
                    Writer.WriteValue("EngineVersion", FormatVersionNumber(Version));
                    Writer.WriteObjectEnd();
                }
            }

#if !NET_CORE
            // Load the assembly into our app domain
            try
            {
                AppDomain.CurrentDomain.Load(CompiledAssembly.GetName());
            }
            catch (Exception Ex)
            {
                throw new BuildException(Ex, "Unable to load the compiled build assembly '{0}' into our application's domain.  (Exception: {1})", OutputAssemblyPath, Ex.Message);
            }
#endif

            return(CompiledAssembly);
        }
        /// <summary>
        /// Creates a target rules object for the specified target name.
        /// </summary>
        /// <param name="TargetName">Name of the target</param>
        /// <param name="Platform">Platform being compiled</param>
        /// <param name="Configuration">Configuration being compiled</param>
        /// <param name="Architecture">Architecture being built</param>
        /// <param name="ProjectFile">Path to the project file for this target</param>
        /// <param name="Version">The current build version</param>
        /// <param name="bInEditorRecompile">Whether this is an editor recompile, where we need to guess the name of the editor target</param>
        /// <param name="TargetFileName">The original source file name of the Target.cs file for this target</param>
        /// <returns>The build target rules for the specified target</returns>
        public TargetRules CreateTargetRules(string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string Architecture, FileReference ProjectFile, ReadOnlyBuildVersion Version, bool bInEditorRecompile, out FileReference TargetFileName)
        {
            // Make sure the target file is known to us
            bool bFoundTargetName = TargetNameToTargetFile.ContainsKey(TargetName);

            if (bFoundTargetName == false)
            {
                if (Parent == null)
                {
                    //				throw new BuildException("Couldn't find target rules file for target '{0}' in rules assembly '{1}'.", TargetName, RulesAssembly.FullName);
                    string ExceptionMessage = "Couldn't find target rules file for target '";
                    ExceptionMessage += TargetName;
                    ExceptionMessage += "' in rules assembly '";
                    ExceptionMessage += CompiledAssembly.FullName;
                    ExceptionMessage += "'." + Environment.NewLine;

                    ExceptionMessage += "Location: " + CompiledAssembly.Location + Environment.NewLine;

                    ExceptionMessage += "Target rules found:" + Environment.NewLine;
                    foreach (KeyValuePair <string, FileReference> entry in TargetNameToTargetFile)
                    {
                        ExceptionMessage += "\t" + entry.Key + " - " + entry.Value + Environment.NewLine;
                    }

                    throw new BuildException(ExceptionMessage);
                }
                else
                {
                    return(Parent.CreateTargetRules(TargetName, Platform, Configuration, Architecture, ProjectFile, Version, bInEditorRecompile, out TargetFileName));
                }
            }

            // Return the target file name to the caller
            TargetFileName = TargetNameToTargetFile[TargetName];

            // Currently, we expect the user's rules object type name to be the same as the module name + 'Target'
            string TargetTypeName = TargetName + "Target";

            // The build module must define a type named '<TargetName>Target' that derives from our 'TargetRules' type.
            TargetRules RulesObject = CreateTargetRulesInstance(TargetTypeName, new TargetInfo(TargetName, Platform, Configuration, Architecture, ProjectFile, Version));

            if (bInEditorRecompile)
            {
                // Make sure this is an editor module.
                if (RulesObject != null)
                {
                    if (RulesObject.Type != TargetType.Editor)
                    {
                        // Not the editor... determine the editor project
                        string TargetSourceFolderString = TargetFileName.FullName;
                        Int32  SourceFolderIndex        = -1;
                        if (Utils.IsRunningOnMono)
                        {
                            TargetSourceFolderString = TargetSourceFolderString.Replace("\\", "/");
                            SourceFolderIndex        = TargetSourceFolderString.LastIndexOf("/Source/", StringComparison.InvariantCultureIgnoreCase);
                        }
                        else
                        {
                            TargetSourceFolderString = TargetSourceFolderString.Replace("/", "\\");
                            SourceFolderIndex        = TargetSourceFolderString.LastIndexOf("\\Source\\", StringComparison.InvariantCultureIgnoreCase);
                        }
                        if (SourceFolderIndex != -1)
                        {
                            DirectoryReference TargetSourceFolder = new DirectoryReference(TargetSourceFolderString.Substring(0, SourceFolderIndex + 7));
                            foreach (KeyValuePair <string, FileReference> CheckEntry in TargetNameToTargetFile)
                            {
                                if (CheckEntry.Value.IsUnderDirectory(TargetSourceFolder))
                                {
                                    if (CheckEntry.Key.Equals(TargetName, StringComparison.InvariantCultureIgnoreCase) == false)
                                    {
                                        // We have found a target in the same source folder that is not the original target found.
                                        // See if it is the editor project
                                        string      CheckTargetTypeName = CheckEntry.Key + "Target";
                                        TargetRules CheckRulesObject    = CreateTargetRulesInstance(CheckTargetTypeName, new TargetInfo(CheckEntry.Key, Platform, Configuration, Architecture, ProjectFile, Version));
                                        if (CheckRulesObject != null)
                                        {
                                            if (CheckRulesObject.Type == TargetType.Editor)
                                            {
                                                // Found it
                                                // NOTE: This prevents multiple Editor targets from co-existing...
                                                RulesObject = CheckRulesObject;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(RulesObject);
        }
Ejemplo n.º 11
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ProjectFile"></param>
        /// <param name="Executable"></param>
        /// <param name="StageDirectory"></param>
        /// <param name="PlatformType"></param>
        public static void GenerateAssetCatalog(FileReference ProjectFile, string Executable, string StageDirectory, UnrealTargetPlatform PlatformType)
        {
            // Initialize the toolchain.
            IOSProjectSettings ProjectSettings = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(PlatformType)).ReadProjectSettings(null);
            IOSToolChain       ToolChain       = new IOSToolChain(ProjectFile, ProjectSettings);

            // Determine whether the user has modified icons that require a remote Mac to build.
            CppPlatform Platform         = PlatformType == UnrealTargetPlatform.IOS ? CppPlatform.IOS : CppPlatform.TVOS;
            bool        bUserImagesExist = false;

            ToolChain.GenerateAssetCatalog(Platform, ref bUserImagesExist);

            // Don't attempt to do anything remotely if the user is using the default UE4 images.
            if (!bUserImagesExist)
            {
                return;
            }

            // Also don't attempt to use a remote Mac if packaging for TVOS on PC.
            if (Platform == CppPlatform.TVOS && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
            {
                return;
            }

            // Save off the current bUseRPCUtil setting to restore at the end of this function.
            // At this time, iPhonePackager needs to be called with bUseRPCUtil == true.
            bool bSaveUseRPCUtil = RemoteToolChain.bUseRPCUtil;

            // Initialize the remote calling environment, taking into account the user's SSH setting.
            ToolChain.SetUpGlobalEnvironment(false);

            // Build the asset catalog ActionGraph.
            ActionGraph     ActionGraph = new ActionGraph();
            List <FileItem> OutputFiles = new List <FileItem>();

            ToolChain.CompileAssetCatalog(FileItem.GetItemByPath(Executable), Platform, ActionGraph, OutputFiles);

            ActionGraph.FinalizeActionGraph();

            // I'm not sure how to derive the UE4Game and Development arguments programmatically.
            string[] Arguments = new string[] { "UE4Game", (PlatformType == UnrealTargetPlatform.IOS ? "IOS" : "TVOS"), "Development", "-UniqueBuildEnvironment" };

            // Perform all of the setup necessary to actually execute the ActionGraph instance.
            ReadOnlyBuildVersion Version        = new ReadOnlyBuildVersion(BuildVersion.ReadDefault());
            List <string[]>      TargetSettings = new List <string[]>();

            TargetSettings.Add(Arguments);
            var Targets = new List <UEBuildTarget>();
            Dictionary <UEBuildTarget, CPPHeaders> TargetToHeaders = new Dictionary <UEBuildTarget, CPPHeaders>();
            List <TargetDescriptor> TargetDescs = new List <TargetDescriptor>();

            foreach (string[] TargetSetting in TargetSettings)
            {
                TargetDescs.AddRange(TargetDescriptor.ParseCommandLine(TargetSetting, ref ProjectFile));
            }
            foreach (TargetDescriptor TargetDesc in TargetDescs)
            {
                UEBuildTarget Target = UEBuildTarget.CreateTarget(TargetDesc, Arguments, false, Version);
                if (Target == null)
                {
                    continue;
                }
                Targets.Add(Target);
                TargetToHeaders.Add(Target, null);
            }

            bool bIsRemoteCompile = BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac;

            // Create the build configuration object, and read the settings
            BuildConfiguration BuildConfiguration = new BuildConfiguration();

            XmlConfig.ApplyTo(BuildConfiguration);
            CommandLine.ParseArguments(Arguments, BuildConfiguration);
            BuildConfiguration.bUseUBTMakefiles = false;

            Action[] PrerequisiteActions;
            {
                HashSet <Action> PrerequisiteActionsSet = new HashSet <Action>();
                foreach (FileItem OutputFile in OutputFiles)
                {
                    ActionGraph.GatherPrerequisiteActions(OutputFile, ref PrerequisiteActionsSet);
                }
                PrerequisiteActions = PrerequisiteActionsSet.ToArray();
            }

            // Copy any asset catalog files to the remote Mac, if necessary.
            foreach (UEBuildTarget Target in Targets)
            {
                UEBuildPlatform.GetBuildPlatform(Target.Platform).PreBuildSync();
            }

            // Begin execution of the ActionGraph.
            Dictionary <UEBuildTarget, List <FileItem> > TargetToOutdatedPrerequisitesMap;
            List <Action> ActionsToExecute = ActionGraph.GetActionsToExecute(BuildConfiguration, PrerequisiteActions, Targets, TargetToHeaders, true, true, out TargetToOutdatedPrerequisitesMap);
            string        ExecutorName     = "Unknown";
            bool          bSuccess         = ActionGraph.ExecuteActions(BuildConfiguration, ActionsToExecute, bIsRemoteCompile, out ExecutorName, "", EHotReload.Disabled);

            if (bSuccess)
            {
                if (bIsRemoteCompile)
                {
                    // Copy the remotely built AssetCatalog directory locally.
                    foreach (FileItem OutputFile in OutputFiles)
                    {
                        string   RemoteDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/");
                        FileItem LocalExecutable = ToolChain.RemoteToLocalFileItem(FileItem.GetItemByPath(Executable));
                        string   LocalDirectory  = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(LocalExecutable.AbsolutePath), "AssetCatalog");
                        LocalDirectory = StageDirectory;
                        RPCUtilHelper.CopyDirectory(RemoteDirectory, LocalDirectory, RPCUtilHelper.ECopyOptions.DoNotReplace);
                    }
                }
                else
                {
                    // Copy the built AssetCatalog directory to the StageDirectory.
                    foreach (FileItem OutputFile in OutputFiles)
                    {
                        string SourceDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/");
                        System.IO.DirectoryInfo SourceDirectoryInfo = new System.IO.DirectoryInfo(SourceDirectory);
                        if (!System.IO.Directory.Exists(StageDirectory))
                        {
                            System.IO.Directory.CreateDirectory(StageDirectory);
                        }
                        System.IO.FileInfo[] SourceFiles = SourceDirectoryInfo.GetFiles();
                        foreach (System.IO.FileInfo SourceFile in SourceFiles)
                        {
                            string DestinationPath = System.IO.Path.Combine(StageDirectory, SourceFile.Name);
                            SourceFile.CopyTo(DestinationPath, true);
                        }
                    }
                }
            }

            // Restore the former bUseRPCUtil setting.
            RemoteToolChain.bUseRPCUtil = bSaveUseRPCUtil;
        }