// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using AutomationTool; using UnrealBuildTool; namespace Rocket { public class RocketBuild : GUBP.GUBPNodeAdder { static readonly string[] CurrentTemplates = { "TP_FirstPerson", "TP_FirstPersonBP", "TP_Flying", "TP_FlyingBP", "TP_Rolling", "TP_RollingBP", "TP_SideScroller", "TP_SideScrollerBP", "TP_ThirdPerson", "TP_ThirdPersonBP", "TP_TopDown", "TP_TopDownBP", "TP_TwinStick", "TP_TwinStickBP", "TP_Vehicle", "TP_VehicleBP", "TP_Puzzle", "TP_PuzzleBP", "TP_2DSideScroller", "TP_2DSideScrollerBP", "TP_VehicleAdv", "TP_VehicleAdvBP", }; static readonly string[] CurrentFeaturePacks = { "FP_FirstPerson", "FP_FirstPersonBP", "TP_Flying", "TP_FlyingBP", "TP_Rolling", "TP_RollingBP", "TP_SideScroller", "TP_SideScrollerBP", "TP_ThirdPerson", "TP_ThirdPersonBP", "TP_TopDown", "TP_TopDownBP", "TP_TwinStick", "TP_TwinStickBP", "TP_Vehicle", "TP_VehicleBP", "TP_Puzzle", "TP_PuzzleBP", "TP_2DSideScroller", "TP_2DSideScrollerBP", "TP_VehicleAdv", "TP_VehicleAdvBP", "StarterContent", "MobileStarterContent" }; public RocketBuild() { } public override void AddNodes(GUBP bp, UnrealTargetPlatform HostPlatform) { if(!bp.BranchOptions.bNoInstalledEngine) { // Get the promotable node, so we can add additional dependencies to it // GUBP.GUBPNode PromotableNode = bp.FindNode(GUBP.SharedAggregatePromotableNode.StaticGetFullName()); // Get the output paths for the installed engine string InstallDir = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "LocalBuilds", "Engine", CommandUtils.GetGenericPlatformName(HostPlatform)); string SymbolsDir = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "LocalBuilds", "Engine", CommandUtils.GetGenericPlatformName(HostPlatform) + "Symbols"); // Find all the target platforms for this host platform List TargetPlatforms = GetTargetPlatforms(bp, HostPlatform); // Get a list of all the code target platforms List CodeTargetPlatforms = new List(); foreach(UnrealTargetPlatform TargetPlatform in TargetPlatforms) { if(IsCodeTargetPlatform(HostPlatform, TargetPlatform)) { CodeTargetPlatforms.Add(TargetPlatform); } } // Add the aggregate node for the whole install, if there isn't one already if(!bp.HasNode(RocketAggregateNode.StaticGetFullName())) { bp.AddNode(new RocketAggregateNode()); } // Add a dependency on this platform finishing RocketAggregateNode AggNode = (RocketAggregateNode)bp.FindNode(RocketAggregateNode.StaticGetFullName()); // Copy to output folders AggNode.AddDependency(bp.AddNode(new CopyInstalledEditorNode(bp, HostPlatform, InstallDir))); AggNode.AddDependency(bp.AddNode(new CopyInstalledPlatformsNode(bp, HostPlatform, TargetPlatforms, CodeTargetPlatforms, InstallDir, CurrentFeaturePacks, CurrentTemplates))); AggNode.AddDependency(bp.AddNode(new CopyInstalledDerivedDataNode(HostPlatform, GetCookPlatforms(HostPlatform, TargetPlatforms), CurrentFeaturePacks, InstallDir))); AggNode.AddDependency(bp.AddNode(new CopyInstalledSymbolsNode(bp, HostPlatform, CodeTargetPlatforms, SymbolsDir))); // Add the aggregate node for the entire install AggNode.AddDependency(bp.AddNode(new BuildInstalledEngineNode(HostPlatform, InstallDir, SymbolsDir))); // PromotableNode.AddDependency(BuildInstalledEngineNode.StaticGetFullName(HostPlatform)); // Add a node for GitHub promotions if(HostPlatform == UnrealTargetPlatform.Win64) { string GitConfigRelativePath = "Engine/Build/Git/UnrealBot.ini"; if(CommandUtils.FileExists(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, GitConfigRelativePath))) { bp.AddNode(new BuildGitPromotable(bp, HostPlatform, GitConfigRelativePath)); // PromotableNode.AddDependency(BuildGitPromotable.StaticGetFullName(HostPlatform)); } } } } public static List GetTargetPlatforms(GUBP bp, UnrealTargetPlatform HostPlatform) { List TargetPlatforms = new List(); if(!bp.ParseParam("NoPlatforms")) { TargetPlatforms.Add(HostPlatform); if(HostPlatform == UnrealTargetPlatform.Win64) { TargetPlatforms.Add(UnrealTargetPlatform.Win32); } if(!bp.ParseParam("NoAndroid")) { TargetPlatforms.Add(UnrealTargetPlatform.Android); } if(!bp.ParseParam("NoIOS")) { TargetPlatforms.Add(UnrealTargetPlatform.IOS); } if(!bp.ParseParam("NoLinux") && HostPlatform == UnrealTargetPlatform.Win64) { TargetPlatforms.Add(UnrealTargetPlatform.Linux); } if(!bp.ParseParam("NoHTML5") && HostPlatform == UnrealTargetPlatform.Win64) { TargetPlatforms.Add(UnrealTargetPlatform.HTML5); } TargetPlatforms.RemoveAll(x => !bp.ActivePlatforms.Contains(x)); } return TargetPlatforms; } public static string GetCookPlatforms(UnrealTargetPlatform HostPlatform, IEnumerable TargetPlatforms) { // Always include the editor platform for cooking List CookPlatforms = new List(); CookPlatforms.Add(Platform.Platforms[HostPlatform].GetEditorCookPlatform()); // Add all the target platforms foreach(UnrealTargetPlatform TargetPlatform in TargetPlatforms) { if(TargetPlatform == UnrealTargetPlatform.Android) { CookPlatforms.Add(Platform.Platforms[TargetPlatform].GetCookPlatform(false, false, "ATC")); } else { CookPlatforms.Add(Platform.Platforms[TargetPlatform].GetCookPlatform(false, false, "")); } } return CommandUtils.CombineCommandletParams(CookPlatforms.Distinct().ToArray()); } public static bool ShouldDoSeriousThingsLikeP4CheckinAndPostToMCP() { return CommandUtils.P4Enabled && CommandUtils.AllowSubmit && !GUBP.bPreflightBuild; // we don't do serious things in a preflight } public static UnrealTargetPlatform GetSourceHostPlatform(GUBP bp, UnrealTargetPlatform HostPlatform, UnrealTargetPlatform TargetPlatform) { if (TargetPlatform == UnrealTargetPlatform.Android && HostPlatform == UnrealTargetPlatform.Mac && bp.HostPlatforms.Contains(UnrealTargetPlatform.Win64)) { return UnrealTargetPlatform.Win64; } if(TargetPlatform == UnrealTargetPlatform.IOS && HostPlatform == UnrealTargetPlatform.Win64 && bp.HostPlatforms.Contains(UnrealTargetPlatform.Mac)) { return UnrealTargetPlatform.Mac; } return HostPlatform; } public static bool IsCodeTargetPlatform(UnrealTargetPlatform HostPlatform, UnrealTargetPlatform TargetPlatform) { if(TargetPlatform == UnrealTargetPlatform.Linux) { return false; } if(HostPlatform == UnrealTargetPlatform.Win64 && TargetPlatform == UnrealTargetPlatform.IOS) { return false; } return true; } } public class BuildGitPromotable : GUBP.HostPlatformNode { string ConfigRelativePath; public BuildGitPromotable(GUBP bp, UnrealTargetPlatform HostPlatform, string InConfigRelativePath) : base(HostPlatform) { ConfigRelativePath = InConfigRelativePath; foreach(UnrealTargetPlatform OtherHostPlatform in bp.HostPlatforms) { AddDependency(GUBP.RootEditorNode.StaticGetFullName(OtherHostPlatform)); AddDependency(GUBP.ToolsNode.StaticGetFullName(OtherHostPlatform)); AddDependency(GUBP.InternalToolsNode.StaticGetFullName(OtherHostPlatform)); } SingleTargetProperties VersionSelector = bp.Branch.FindProgram("UnrealVersionSelector"); if (VersionSelector.Rules != null) { AddDependency(GUBP.SingleInternalToolsNode.StaticGetFullName(UnrealTargetPlatform.Win64, VersionSelector)); } } public static string StaticGetFullName(UnrealTargetPlatform HostPlatform) { return "BuildGitPromotable" + StaticGetHostPlatformSuffix(HostPlatform); } public override string GetFullName() { return StaticGetFullName(HostPlatform); } public override void DoBuild(GUBP bp) { // Create a filter for all the promoted binaries FileFilter PromotableFilter = new FileFilter(); CopyNode.AddFilesToFilter(PromotableFilter, AllDependencyBuildProducts, CommandUtils.CmdEnv.LocalRoot, FileFilterType.Include); PromotableFilter.AddRulesFromFile(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, ConfigRelativePath), "promotable"); CopyNode.ExcludeConfidentialFolders(PromotableFilter); // Copy everything that matches the filter to the promotion folder string PromotableFolder = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Saved", "GitPromotable"); CommandUtils.DeleteDirectoryContents(PromotableFolder); string[] PromotableFiles = CopyNode.CopyFolder(CommandUtils.CmdEnv.LocalRoot, PromotableFolder, PromotableFilter); BuildProducts = new List(PromotableFiles); } } public class CopySymbolsNode : GUBP.HostPlatformNode { public string OutputDirectory; public bool bAddToBuildProducts; public CopySymbolsNode(UnrealTargetPlatform HostPlatform, string InOutputDirectory, bool bInAddToBuildProducts) : base(HostPlatform) { OutputDirectory = InOutputDirectory; bAddToBuildProducts = bInAddToBuildProducts; AgentSharingGroup = "BuildMinimalInstall" + StaticGetHostPlatformSuffix(HostPlatform); } public override void DoBuild(GUBP bp) { BuildProducts = new List(); // Make a lookup for all the known debug extensions, and filter all the dependency build products against that HashSet DebugExtensions = new HashSet(Platform.Platforms.Values.SelectMany(x => x.GetDebugFileExtentions()).Distinct().ToArray(), StringComparer.InvariantCultureIgnoreCase); foreach(string InputFileName in AllDependencyBuildProducts) { string Extension = Path.GetExtension(InputFileName); if(DebugExtensions.Contains(Extension)) { string OutputFileName = CommandUtils.MakeRerootedFilePath(InputFileName, CommandUtils.CmdEnv.LocalRoot, OutputDirectory); CommandUtils.CopyFile(InputFileName, OutputFileName); if(bAddToBuildProducts) { BuildProducts.Add(OutputFileName); } } } // Add a dummy build product if we're not adding all the files we copied if(!bAddToBuildProducts) { SaveRecordOfSuccessAndAddToBuildProducts(); } } } public class CopyInstalledSymbolsNode : CopySymbolsNode { public CopyInstalledSymbolsNode(GUBP bp, UnrealTargetPlatform HostPlatform, IEnumerable TargetPlatforms, string OutputDirectory) : base(HostPlatform, OutputDirectory, false) { AddDependency(GUBP.ToolsForCompileNode.StaticGetFullName(HostPlatform)); AddDependency(GUBP.RootEditorNode.StaticGetFullName(HostPlatform)); AddDependency(GUBP.ToolsNode.StaticGetFullName(HostPlatform)); foreach(UnrealTargetPlatform TargetPlatform in TargetPlatforms) { UnrealTargetPlatform SourceHostPlatform = CopyInstalledPlatformsNode.GetSourceHostPlatform(bp, HostPlatform, TargetPlatform); AddDependency(GUBP.GamePlatformMonolithicsNode.StaticGetFullName(SourceHostPlatform, bp.Branch.BaseEngineProject, TargetPlatform, Precompiled: true)); } } public static string StaticGetFullName(UnrealTargetPlatform HostPlatform) { return "CopyEngineSymbols" + StaticGetHostPlatformSuffix(HostPlatform); } public override string GetFullName() { return StaticGetFullName(HostPlatform); } } public class CopyNode : GUBP.HostPlatformNode { public CopyNode(UnrealTargetPlatform InHostPlatform) : base(InHostPlatform) { } static IEnumerable FindBuildProducts(GUBP bp, string NodeName) { GUBP.GUBPNode Node = bp.FindNode(NodeName); if (Node == null) { throw new AutomationException("Couldn't find node '{0}'", NodeName); } return Node.BuildProducts; } static IEnumerable MakeRerootedFilePaths(IEnumerable FileNames, string SourceDir, string TargetDir) { foreach(string FileName in FileNames) { yield return CommandUtils.MakeRerootedFilePath(Path.GetFullPath(FileName), SourceDir, TargetDir); } } public static void AddFileToFilter(FileFilter Filter, string FileName, FileFilterType Type) { AddFileToFilter(Filter, FileName, CommandUtils.CmdEnv.LocalRoot, Type); } public static void AddFileToFilter(FileFilter Filter, string FileName, string BaseDirectoryName, FileFilterType Type) { Filter.AddRule("/" + CommandUtils.StripBaseDirectory(Path.GetFullPath(FileName), BaseDirectoryName), Type); } public static void AddFilesToFilter(FileFilter Filter, IEnumerable FileNames, FileFilterType Type) { AddFilesToFilter(Filter, FileNames, CommandUtils.CmdEnv.LocalRoot, Type); } public static void AddFilesToFilter(FileFilter Filter, IEnumerable FileNames, string BaseDirectoryName, FileFilterType Type) { foreach (string FileName in FileNames) { AddFileToFilter(Filter, FileName, BaseDirectoryName, Type); } } public static void AddNodeToFilter(FileFilter Filter, GUBP bp, string NodeName, FileFilterType Type) { AddNodeToFilter(Filter, bp, NodeName, CommandUtils.CmdEnv.LocalRoot, Type); } public static void AddNodeToFilter(FileFilter Filter, GUBP bp, string NodeName, string BaseDirectoryName, FileFilterType Type) { GUBP.GUBPNode Node = bp.FindNode(NodeName); if(Node == null) { throw new AutomationException("Couldn't find node '{0}'", NodeName); } AddFilesToFilter(Filter, Node.BuildProducts, BaseDirectoryName, Type); } public static void ExcludeConfidentialPlatforms(FileFilter Filter) { // Exclude platforms that can't be redistributed without an NDA Filter.Exclude(".../PS4/..."); Filter.Exclude(".../XboxOne/..."); } public static void ExcludeConfidentialFolders(FileFilter Filter) { // Exclude standard folders Filter.Exclude(".../EpicInternal/..."); Filter.Exclude(".../CarefullyRedist/..."); Filter.Exclude(".../NotForLicensees/..."); Filter.Exclude(".../NoRedist/..."); } public static string[] CopyFolder(string SourceDir, string TargetDir, FileFilter Filter) { // Filter all the relative paths CommandUtils.Log("Applying filter to {0}...", SourceDir); string[] RelativePaths = Filter.ApplyToDirectory(SourceDir).ToArray(); return CopyFolder(SourceDir, TargetDir, RelativePaths); } public static string[] CopyFolder(string SourceDir, string TargetDir, IEnumerable RelativePaths) { // Find all the source and target filenames, removing any symlinks. List SourceFileNames = new List(); List TargetFileNames = new List(); foreach(string RelativePath in RelativePaths) { string SourceFileName = CommandUtils.CombinePaths(SourceDir, RelativePath); if(!File.GetAttributes(SourceFileName).HasFlag(FileAttributes.ReparsePoint)) { SourceFileNames.Add(SourceFileName); TargetFileNames.Add(CommandUtils.CombinePaths(TargetDir, RelativePath)); } } // Copy them all over string[] TargetFileNamesArray = TargetFileNames.ToArray(); CommandUtils.Log("Copying {0} files to {1}...", SourceFileNames.Count, TargetDir); CommandUtils.ThreadedCopyFiles(SourceFileNames.ToArray(), TargetFileNamesArray); return TargetFileNamesArray; } public static void StripSymbols(UnrealTargetPlatform TargetPlatform, IEnumerable FileNames) { if(TargetPlatform == UnrealTargetPlatform.Win32 || TargetPlatform == UnrealTargetPlatform.Win64) { string PDBCopyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "MSBuild", "Microsoft", "VisualStudio", "v12.0", "AppxPackage", "PDBCopy.exe"); foreach(string FileName in FileNames) { string TempFileName = FileName + ".stripped"; CommandUtils.Run(PDBCopyPath, String.Format("{0} {1} -p", CommandUtils.MakePathSafeToUseWithCommandLine(FileName), CommandUtils.MakePathSafeToUseWithCommandLine(TempFileName))); CommandUtils.DeleteFile(FileName); CommandUtils.RenameFile(TempFileName, FileName); } } else if(TargetPlatform == UnrealTargetPlatform.Android) { CommandUtils.LogWarning("Stripping has not yet been implemented for Android. Skipping files:"); foreach (string FileName in FileNames) { CommandUtils.LogWarning(" {0}", FileName); } } else if(TargetPlatform == UnrealTargetPlatform.Linux) { CommandUtils.LogWarning("Stripping has not yet been implemented for Linux. Skipping files:"); foreach (string FileName in FileNames) { CommandUtils.LogWarning(" {0}", FileName); } } else { if(FileNames.Any()) { throw new AutomationException("Symbol stripping has not been implemented for {0}", TargetPlatform.ToString()); } } } } public class CopyInstalledEditorNode : CopyNode { string TargetDir; public CopyInstalledEditorNode(GUBP bp, UnrealTargetPlatform InHostPlatform, string InTargetDir) : base(InHostPlatform) { TargetDir = InTargetDir; AddDependency(GUBP.VersionFilesNode.StaticGetFullName()); AddDependency(GUBP.ToolsForCompileNode.StaticGetFullName(HostPlatform)); AddDependency(GUBP.RootEditorNode.StaticGetFullName(HostPlatform)); AddDependency(GUBP.ToolsNode.StaticGetFullName(HostPlatform)); // Add win64 tools on Mac, to get the win64 build of UBT and UAT if (HostPlatform == UnrealTargetPlatform.Mac && bp.HostPlatforms.Contains(UnrealTargetPlatform.Win64)) { AddDependency(GUBP.ToolsForCompileNode.StaticGetFullName(UnrealTargetPlatform.Win64)); } AgentSharingGroup = "BuildMinimalInstall" + StaticGetHostPlatformSuffix(HostPlatform); } public override int CISFrequencyQuantumShift(GUBP bp) { return base.CISFrequencyQuantumShift(bp) + 2; } public static string StaticGetFullName(UnrealTargetPlatform InHostPlatform) { return "CopyEditor" + StaticGetHostPlatformSuffix(InHostPlatform); } public override string GetFullName() { return StaticGetFullName(HostPlatform); } public override void DoBuild(GUBP bp) { FileFilter Filter = new FileFilter(); // Include all the editor products AddNodeToFilter(Filter, bp, GUBP.ToolsForCompileNode.StaticGetFullName(HostPlatform), FileFilterType.Include); AddNodeToFilter(Filter, bp, GUBP.RootEditorNode.StaticGetFullName(HostPlatform), FileFilterType.Include); AddNodeToFilter(Filter, bp, GUBP.ToolsNode.StaticGetFullName(HostPlatform), FileFilterType.Include); // Include all the standard rules string RulesFileName = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Build", "InstalledEngineFilters.ini"); Filter.AddRulesFromFile(RulesFileName, "CopyEditor", HostPlatform.ToString()); // Add the final exclusions for legal reasons. ExcludeConfidentialPlatforms(Filter); ExcludeConfidentialFolders(Filter); // Wipe the target directory and copy all the files over CommandUtils.DeleteDirectoryContents(TargetDir); // Copy everything over and add the result as build products string[] TargetFileNames = CopyFolder(CommandUtils.CmdEnv.LocalRoot, TargetDir, Filter); BuildProducts = new List(TargetFileNames); // Strip symbols from all the debug files FileFilter StripFilter = new FileFilter(); StripFilter.AddRulesFromFile(RulesFileName, "StripEditor", HostPlatform.ToString()); StripSymbols(HostPlatform, StripFilter.ApplyTo(TargetDir, TargetFileNames)); // Write the default command line to the root of the output directory string CommandLinePath = Path.Combine(TargetDir, "UE4CommandLine.txt"); File.WriteAllText(CommandLinePath, "-installedengine -rocket"); AddBuildProduct(CommandLinePath); } } public class CopyInstalledPlatformsNode : CopyNode { List TargetPlatforms; List CodeTargetPlatforms; string InstallDir; string[] CurrentFeaturePacks; string[] CurrentTemplates; public CopyInstalledPlatformsNode(GUBP bp, UnrealTargetPlatform InHostPlatform, List InTargetPlatforms, List InCodeTargetPlatforms, string InInstallDir, string[] InCurrentFeaturePacks, string[] InCurrentTemplates) : base(InHostPlatform) { TargetPlatforms = new List(InTargetPlatforms); CodeTargetPlatforms = new List(InCodeTargetPlatforms); InstallDir = InInstallDir; CurrentFeaturePacks = InCurrentFeaturePacks; CurrentTemplates = InCurrentTemplates; // copy the editor AddDependency(CopyInstalledEditorNode.StaticGetFullName(HostPlatform)); // add all the feature packs AddDependency(GUBP.MakeFeaturePacksNode.StaticGetFullName(GUBP.MakeFeaturePacksNode.GetDefaultBuildPlatform(bp))); // Get all the external file lists. Android on Mac uses the same files as Win64. foreach(UnrealTargetPlatform CodeTargetPlatform in CodeTargetPlatforms) { UnrealTargetPlatform SourceHostPlatform = GetSourceHostPlatform(bp, HostPlatform, CodeTargetPlatform); AddDependency(GUBP.GamePlatformMonolithicsNode.StaticGetFullName(SourceHostPlatform, bp.Branch.BaseEngineProject, CodeTargetPlatform, Precompiled: true)); } // Add win64 tools on Mac, to get the win64 build of IPP if (HostPlatform == UnrealTargetPlatform.Mac && bp.HostPlatforms.Contains(UnrealTargetPlatform.Win64)) { AddDependency(GUBP.ToolsNode.StaticGetFullName(UnrealTargetPlatform.Win64)); AddDependency(GUBP.ToolsForCompileNode.StaticGetFullName(UnrealTargetPlatform.Win64)); } } public static UnrealTargetPlatform GetSourceHostPlatform(GUBP bp, UnrealTargetPlatform HostPlatform, UnrealTargetPlatform TargetPlatform) { if(HostPlatform == UnrealTargetPlatform.Mac && TargetPlatform == UnrealTargetPlatform.Android && bp.HostPlatforms.Contains(UnrealTargetPlatform.Win64)) { return UnrealTargetPlatform.Win64; } else { return HostPlatform; } } public override int CISFrequencyQuantumShift(GUBP bp) { return base.CISFrequencyQuantumShift(bp) + 2; } public override float Priority() { return base.Priority() + 5.0f; } public override void DoBuild(GUBP bp) { FileFilter Filter = new FileFilter(); // Include the build dependencies for every code platform foreach(UnrealTargetPlatform CodeTargetPlatform in CodeTargetPlatforms) { UnrealTargetPlatform SourceHostPlatform = GetSourceHostPlatform(bp, HostPlatform, CodeTargetPlatform); string FileListPath = GUBP.GamePlatformMonolithicsNode.StaticGetBuildDependenciesPath(SourceHostPlatform, CodeTargetPlatform); AddFilesToFilter(Filter, UnrealBuildTool.Utils.ReadClass(FileListPath).FileNames, FileFilterType.Include); } // Add the monolithic binaries foreach(UnrealTargetPlatform CodeTargetPlatform in CodeTargetPlatforms) { UnrealTargetPlatform SourceHostPlatform = GetSourceHostPlatform(bp, HostPlatform, CodeTargetPlatform); AddNodeToFilter(Filter, bp, GUBP.GamePlatformMonolithicsNode.StaticGetFullName(SourceHostPlatform, bp.Branch.BaseEngineProject, CodeTargetPlatform, Precompiled: true), FileFilterType.Include); } // Include the feature packs foreach(string CurrentFeaturePack in CurrentFeaturePacks) { BranchInfo.BranchUProject Project = bp.Branch.FindGameChecked(CurrentFeaturePack); AddFileToFilter(Filter, GUBP.MakeFeaturePacksNode.GetOutputFile(Project), FileFilterType.Include); } // Include all the templates foreach (string Template in CurrentTemplates) { BranchInfo.BranchUProject Project = bp.Branch.FindGameChecked(Template); string TemplateRelativeDirectory = "/" + Utils.StripBaseDirectory(Path.GetDirectoryName(Project.FilePath), CommandUtils.CmdEnv.LocalRoot) + "/"; Filter.Include(TemplateRelativeDirectory + "/..."); Filter.Exclude(TemplateRelativeDirectory + "/.../Binaries/..."); Filter.Exclude(TemplateRelativeDirectory + "/.../Intermediate/..."); } // Custom rules for all platforms string RulesFileName = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine", "Build", "InstalledEngineFilters.ini"); Filter.AddRulesFromFile(RulesFileName, "CopyTargetPlatforms", HostPlatform.ToString()); // Custom rules for each target platform foreach(UnrealTargetPlatform TargetPlaform in TargetPlatforms) { string SectionName = String.Format("CopyTargetPlatform.{0}", TargetPlaform.ToString()); Filter.AddRulesFromFile(RulesFileName, SectionName, HostPlatform.ToString()); } // Exclude any the files which have already been added by the CopyInstalledEditor node AddNodeToFilter(Filter, bp, CopyInstalledEditorNode.StaticGetFullName(HostPlatform), FileFilterType.Exclude); // Add the final exclusions for legal reasons. ExcludeConfidentialPlatforms(Filter); ExcludeConfidentialFolders(Filter); // Copy all the files over string[] TargetFileNames = CopyFolder(CommandUtils.CmdEnv.LocalRoot, InstallDir, Filter); BuildProducts = new List(TargetFileNames); // Strip symbols from any of the build products foreach(UnrealTargetPlatform TargetPlatform in TargetPlatforms) { FileFilter StripFilter = new FileFilter(); StripFilter.AddRulesFromFile(RulesFileName, String.Format("StripTargetPlatform.{0}", TargetPlatform.ToString()), HostPlatform.ToString()); StripSymbols(TargetPlatform, StripFilter.ApplyTo(InstallDir, TargetFileNames)); } } public override string RootIfAnyForTempStorage() // this saves a bit of path space for temp storage { return InstallDir; } public static string StaticGetFullName(UnrealTargetPlatform InHostPlatform) { return "CopyPlatforms" + StaticGetHostPlatformSuffix(InHostPlatform); } public override string GetFullName() { return StaticGetFullName(HostPlatform); } } public class CopyInstalledDerivedDataNode : GUBP.HostPlatformNode { string TargetPlatforms; string InstallDir; string[] ProjectNames; public CopyInstalledDerivedDataNode(UnrealTargetPlatform InHostPlatform, string InTargetPlatforms, string[] InProjectNames, string InInstallDir) : base(InHostPlatform) { TargetPlatforms = InTargetPlatforms; ProjectNames = InProjectNames; InstallDir = InInstallDir; AddDependency(CopyInstalledEditorNode.StaticGetFullName(HostPlatform)); AgentSharingGroup = "BuildMinimalInstall" + StaticGetHostPlatformSuffix(InHostPlatform); } public static string StaticGetFullName(UnrealTargetPlatform InHostPlatform) { return "CopyDerivedData" + StaticGetHostPlatformSuffix(InHostPlatform); } public override int CISFrequencyQuantumShift(GUBP bp) { return base.CISFrequencyQuantumShift(bp) + 2; } public override string GetFullName() { return StaticGetFullName(HostPlatform); } public override void DoBuild(GUBP bp) { // Remove any existing DDP file string OutputFileName = CommandUtils.CombinePaths(InstallDir, "Engine/DerivedDataCache/Compressed.ddp"); if(CommandUtils.FileExists(OutputFileName)) { CommandUtils.DeleteFile(OutputFileName); } // Enumerate all the files in the install directory. We'll remove everything in this list that's not a build product once we're done. string[] InitialFiles = Directory.EnumerateFiles(InstallDir, "*", SearchOption.AllDirectories).ToArray(); // Generate DDC for all the non-code projects. We don't necessarily have editor DLLs for the code projects, but they should be the same as their blueprint counterparts. foreach(string ProjectName in ProjectNames) { BranchInfo.BranchUProject Project = bp.Branch.FindGameChecked(ProjectName); if(!Project.Properties.bIsCodeBasedProject) { string InstalledProjectPath = CommandUtils.MakeRerootedFilePath(Project.FilePath, CommandUtils.CmdEnv.LocalRoot, InstallDir); if(!CommandUtils.FileExists(InstalledProjectPath)) { CommandUtils.CopyFile(Project.FilePath, InstalledProjectPath); } CommandUtils.Log("Running RocketEditor to generate engine DDC data for {0} on {1}", InstalledProjectPath, TargetPlatforms); CommandUtils.DDCCommandlet(InstalledProjectPath, CommandUtils.GetEditorCommandletExe(InstallDir, HostPlatform), null, TargetPlatforms, "-fill -DDC=CreateInstalledEnginePak -MergePaks"); } } // Create the list of DDC build products BuildProducts = new List(); BuildProducts.Add(OutputFileName); // Remove all the files all the temporary files that can be removed SortedSet TemporaryFiles = new SortedSet(Directory.EnumerateFiles(InstallDir, "*", SearchOption.AllDirectories)); TemporaryFiles.ExceptWith(InitialFiles); TemporaryFiles.ExceptWith(BuildProducts.Select(x => Path.GetFullPath(x))); foreach(string TemporaryFile in TemporaryFiles) { CommandUtils.DeleteFile(TemporaryFile); } // Remove any empty directories left over foreach(string DirectoryName in Directory.EnumerateDirectories(InstallDir, "*", SearchOption.AllDirectories).OrderByDescending(x => x.Length)) { if(!Directory.EnumerateFileSystemEntries(DirectoryName).GetEnumerator().MoveNext()) { try { Directory.Delete(DirectoryName); } catch(Exception){ } } } } public override float Priority() { return base.Priority() + 55.0f; } } public class BuildInstalledEngineNode : GUBP.HostPlatformAggregateNode { public readonly string InstallDir; public readonly string SymbolsDir; public BuildInstalledEngineNode(UnrealTargetPlatform InHostPlatform, string InInstallDir, string InSymbolsDir) : base(InHostPlatform) { InstallDir = InInstallDir; SymbolsDir = InSymbolsDir; AddDependency(CopyInstalledEditorNode.StaticGetFullName(InHostPlatform)); AddDependency(CopyInstalledPlatformsNode.StaticGetFullName(InHostPlatform)); AddDependency(CopyInstalledDerivedDataNode.StaticGetFullName(InHostPlatform)); AddDependency(CopyInstalledSymbolsNode.StaticGetFullName(InHostPlatform)); } public static string StaticGetFullName(UnrealTargetPlatform InHostPlatform) { return "BuildInstalledEngine" + StaticGetHostPlatformSuffix(InHostPlatform); } public override string GetFullName() { return StaticGetFullName(HostPlatform); } } public class RocketAggregateNode : GUBP.AggregateNode { public RocketAggregateNode() { } public static string StaticGetFullName() { return "Rocket_Aggregate"; } public override string GetFullName() { return StaticGetFullName(); } } }