using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnrealBuildTool; using AutomationTool; using System.Xml; namespace AutomationTool { /// /// Parameters for a compile task /// public class CompileTaskParameters { /// /// The target to compile /// [TaskParameter] public string Target; /// /// The configuration to compile /// [TaskParameter] public UnrealTargetConfiguration Configuration; /// /// The platform to compile for /// [TaskParameter] public UnrealTargetPlatform Platform; /// /// Additional arguments for UnrealBuildTool /// [TaskParameter(Optional = true)] public string Arguments; /// /// Tag to be applied to build products of this task /// [TaskParameter(Optional = true, ValidationType = TaskParameterValidationType.TagList)] public string Tag; } /// /// Task which compiles a target with UnrealBuildTool /// [TaskElement("Compile", typeof(CompileTaskParameters))] public class CompileTask : CustomTask { /// /// List of targets to compile. As well as the target specifically added for this task, additional compile tasks may be merged with it. /// List Targets = new List(); /// /// Mapping of receipt filename to its corresponding tag name /// Dictionary TargetToTagName = new Dictionary(); /// /// Construct a compile task /// /// Parameters for this task public CompileTask(CompileTaskParameters Parameters) { UE4Build.BuildTarget Target = new UE4Build.BuildTarget { TargetName = Parameters.Target, Platform = Parameters.Platform, Config = Parameters.Configuration, UBTArgs = "-nobuilduht " + (Parameters.Arguments ?? "") }; if(!String.IsNullOrEmpty(Parameters.Tag)) { TargetToTagName.Add(Target, Parameters.Tag); } Targets.Add(Target); } /// /// Allow this task to merge with other tasks within the same node. This can be useful to allow tasks to execute in parallel and reduce overheads. /// /// Other tasks that this task can merge with. If a merge takes place, the other tasks should be removed from the list. public override void Merge(List OtherTasks) { for (int Idx = 0; Idx < OtherTasks.Count; Idx++) { CompileTask OtherCompileTask = OtherTasks[Idx] as CompileTask; if (OtherCompileTask != null) { Targets.AddRange(OtherCompileTask.Targets); foreach(KeyValuePair TargetTagName in OtherCompileTask.TargetToTagName) { TargetToTagName.Add(TargetTagName.Key, TargetTagName.Value); } OtherTasks.RemoveAt(Idx); } } } /// /// Execute the task. /// /// Information about the current job /// Set of build products produced by this node. /// Mapping from tag names to the set of files they include /// True if the task succeeded public override bool Execute(JobContext Job, HashSet BuildProducts, Dictionary> TagNameToFileSet) { // Create the agenda UE4Build.BuildAgenda Agenda = new UE4Build.BuildAgenda(); Agenda.Targets.AddRange(Targets); // Build everything Dictionary TargetToManifest = new Dictionary(); UE4Build Builder = new UE4Build(Job.OwnerCommand); try { Builder.Build(Agenda, InDeleteBuildProducts: null, InUpdateVersionFiles: false, InForceNoXGE: false, InUseParallelExecutor: true, InTargetToManifest: TargetToManifest); } catch (CommandUtils.CommandFailedException) { return false; } UE4Build.CheckBuildProducts(Builder.BuildProductFiles); // Tag all the outputs foreach(KeyValuePair TargetTagName in TargetToTagName) { BuildManifest Manifest; if(!TargetToManifest.TryGetValue(TargetTagName.Key, out Manifest)) { throw new AutomationException("Missing manifest for target {0} {1} {2}", TargetTagName.Key.TargetName, TargetTagName.Key.Platform, TargetTagName.Key.Config); } foreach(string TagName in SplitDelimitedList(TargetTagName.Value)) { HashSet FileSet = FindOrAddTagSet(TagNameToFileSet, TagName); FileSet.UnionWith(Manifest.BuildProducts.Select(x => new FileReference(x))); FileSet.UnionWith(Manifest.LibraryBuildProducts.Select(x => new FileReference(x))); } } // Add everything to the list of build products BuildProducts.UnionWith(Builder.BuildProductFiles.Select(x => new FileReference(x))); BuildProducts.UnionWith(Builder.LibraryBuildProductFiles.Select(x => new FileReference(x))); return true; } /// /// Output this task out to an XML writer. /// public override void Write(XmlWriter Writer) { foreach (UE4Build.BuildTarget Target in Targets) { CompileTaskParameters Parameters = new CompileTaskParameters(); Parameters.Target = Target.TargetName; Parameters.Platform = Target.Platform; Parameters.Configuration = Target.Config; Parameters.Arguments = Target.UBTArgs; string TagName; if (TargetToTagName.TryGetValue(Target, out TagName)) { Parameters.Tag = TagName; } Write(Writer, Parameters); } } /// /// Find all the tags which are used as inputs to this task /// /// The tag names which are read by this task public override IEnumerable FindConsumedTagNames() { yield break; } /// /// Find all the tags which are modified by this task /// /// The tag names which are modified by this task public override IEnumerable FindProducedTagNames() { return TargetToTagName.Values.SelectMany(x => SplitDelimitedList(x)); } } }