Files
2025-05-18 13:04:45 +08:00

759 lines
25 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Diagnostics;
using UnrealBuildTool;
using EpicGames.Core;
using System.Linq;
using System.Reflection;
using OpenTracing;
using OpenTracing.Util;
using UnrealBuildBase;
using CommandLine = UnrealBuildBase.CommandLine;
using Microsoft.Extensions.Logging;
using static AutomationTool.CommandUtils;
namespace AutomationTool
{
class UnrealBuildException : AutomationException
{
public UnrealBuildException(string Message)
: base(ExitCode.Error_UBTFailure, "BUILD FAILED: " + Message)
{
OutputFormat = AutomationExceptionOutputFormat.MinimalError;
}
public UnrealBuildException(string Format, params object[] Args)
: this(String.Format(Format, Args))
{
}
}
[Help("ForceMonolithic", "Toggle to combined the result into one executable")]
[Help("ForceDebugInfo", "Forces debug info even in development builds")]
[Help("NoXGE", "Toggle to disable the distributed build process")]
[Help("ForceNonUnity", "Toggle to disable the unity build system")]
[Help("ForceUnity", "Toggle to force enable the unity build system")]
[Help("Licensee", "If set, this build is being compiled by a licensee")]
public class UnrealBuild
{
private BuildCommand OwnerCommand;
/// <summary>
/// If true we will let UBT build UHT
/// </summary>
[Obsolete]
public bool AlwaysBuildUHT { get; set; }
public void AddBuildProduct(string InFile)
{
string File = CommandUtils.CombinePaths(InFile);
if (!CommandUtils.FileExists(File) && !CommandUtils.DirectoryExists(File))
{
throw new UnrealBuildException("Specified file to AddBuildProduct {0} does not exist.", File);
}
BuildProductFiles.Add(File);
}
static bool IsBuildReceipt(string FileName)
{
return FileName.EndsWith(".version", StringComparison.InvariantCultureIgnoreCase)
|| FileName.EndsWith(".target", StringComparison.InvariantCultureIgnoreCase)
|| FileName.EndsWith(".modules", StringComparison.InvariantCultureIgnoreCase)
|| FileName.EndsWith("buildid.txt", StringComparison.InvariantCultureIgnoreCase);
}
BuildManifest AddBuildProductsFromManifest(FileReference ManifestFile)
{
if (!FileReference.Exists(ManifestFile))
{
throw new UnrealBuildException("UBT Manifest {0} does not exist.", ManifestFile);
}
BuildManifest Manifest = CommandUtils.ReadManifest(ManifestFile);
foreach (string Item in Manifest.BuildProducts)
{
if (!CommandUtils.FileExists_NoExceptions(Item) && !CommandUtils.DirectoryExists_NoExceptions(Item))
{
throw new UnrealBuildException($"AddBuildProductsFromManifest: {Item} was in manifest \"{ManifestFile}\" but could not be found.");
}
AddBuildProduct(Item);
}
return Manifest;
}
private void PrepareUBT()
{
if (!FileReference.Exists(UnrealBuildToolDll))
{
throw new UnrealBuildException($"UnrealBuildTool.dll does not exist at {UnrealBuildToolDll}");
}
if (!FileReference.Exists(Unreal.DotnetPath))
{
throw new UnrealBuildException($"dotnet executable does not exist at {Unreal.DotnetPath}");
}
}
public void CleanWithUBT(string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Config, FileReference UprojectPath, string InAddArgs = "")
{
string AddArgs = "";
if (UprojectPath != null)
{
AddArgs += " " + CommandUtils.MakePathSafeToUseWithCommandLine(UprojectPath.FullName);
}
AddArgs += " -NoUBTMakefiles";
AddArgs += " " + InAddArgs;
PrepareUBT();
using (IScope Scope = GlobalTracer.Instance.BuildSpan("Compile").StartActive())
{
Scope.Span.SetTag("target", TargetName);
Scope.Span.SetTag("platform", Platform.ToString());
Scope.Span.SetTag("config", Config.ToString());
CommandUtils.RunUBT(CommandUtils.CmdEnv, UnrealBuildToolDll: UnrealBuildToolDll, Project: UprojectPath, Target: TargetName, Platform: Platform, Config: Config, AdditionalArgs: "-Clean -NoHotReload" + AddArgs);
}
}
List<FileReference> GetManifestFiles(List<BuildTarget> Targets)
{
List<FileReference> ManifestFiles = new List<FileReference>();
for (int Idx = 0; Idx < Targets.Count; Idx++)
{
BuildTarget Target = Targets[Idx];
DirectoryReference ManifestDir = GetManifestDir(Target.UprojectPath);
ManifestFiles.Add(FileReference.Combine(ManifestDir, $"Manifest-{Idx + 1}-{Target.TargetName}-{Target.Platform}-{Target.Config}.xml"));
}
return ManifestFiles;
}
FileReference GetManifestFile(BuildTarget Target, int Index)
{
DirectoryReference ManifestDir = GetManifestDir(Target.UprojectPath);
if (Index == -1)
{
return FileReference.Combine(ManifestDir, "Manifest.xml");
}
else
{
return FileReference.Combine(ManifestDir, $"Manifest-{Index + 1}-{Target.TargetName}-{Target.Platform}-{Target.Config}.xml");
}
}
void BuildWithUBT(List<BuildTarget> Targets, Dictionary<BuildTarget, BuildManifest> TargetToManifest, bool DisableXGE, bool AllCores, bool SkipBuild)
{
List<FileReference> ManifestFiles = new List<FileReference>(Targets.Count);
StringBuilder FullCommandLine = new StringBuilder();
if (Targets.Count == 1)
{
ManifestFiles.Add(GetManifestFile(Targets[0], -1));
FullCommandLine.Append(GetTargetArguments(Targets[0], ManifestFiles[0]));
}
else
{
List<string> Arguments = new List<string>();
for (int Idx = 0; Idx < Targets.Count; Idx++)
{
ManifestFiles.Add(GetManifestFile(Targets[Idx], Idx));
Arguments.Add("-Target=" + GetTargetArguments(Targets[Idx], ManifestFiles[Idx]));
}
FullCommandLine.Append(CommandLine.FormatCommandLine(Arguments));
}
if (DisableXGE)
{
FullCommandLine.Append(" -NoXGE");
}
if (AllCores)
{
FullCommandLine.Append(" -AllCores");
}
if (SkipBuild)
{
FullCommandLine.Append(" -SkipBuild");
}
PrepareUBT();
for (int Idx = 0; Idx < ManifestFiles.Count; Idx++)
{
CommandUtils.DeleteFile(ManifestFiles[Idx]);
}
CommandUtils.RunUBT(CommandUtils.CmdEnv, UnrealBuildToolDll, FullCommandLine.ToString());
for (int Idx = 0; Idx < Targets.Count; Idx++)
{
FileReference ManifestFile = ManifestFiles[Idx];
BuildManifest Manifest = AddBuildProductsFromManifest(ManifestFile);
CommandUtils.DeleteFile(ManifestFile);
TargetToManifest?.Add(Targets[Idx], Manifest);
}
}
string GetTargetArguments(BuildTarget Target, FileReference ManifestFile)
{
List<string> Arguments = new List<string> { Target.TargetName, Target.Platform.ToString(), Target.Config.ToString() };
if (Target.UprojectPath != null)
{
Arguments.Add($"-Project={Target.UprojectPath}");
}
if (ManifestFile != null)
{
Arguments.Add($"-Manifest={ManifestFile}");
}
string CmdLine = CommandLine.FormatCommandLine(Arguments);
if (!String.IsNullOrEmpty(Target.UBTArgs))
{
CmdLine = $"{CmdLine} {Target.UBTArgs}";
}
return CmdLine;
}
string[] DotNetProductExtenstions()
{
return new string[]
{
".dll",
".pdb",
".exe.config",
".exe",
"exe.mdb"
};
}
string[] SwarmBuildProducts()
{
return new string[]
{
"AgentInterface",
"SwarmAgent",
"SwarmCoordinator",
"SwarmCoordinatorInterface",
"SwarmInterface",
"SwarmCommonUtils"
};
}
void AddBuildProductsForCSharpProj(string CsProj)
{
string BaseOutput = CommandUtils.CmdEnv.LocalRoot + @"/Engine/Binaries/DotNET/" + Path.GetFileNameWithoutExtension(CsProj);
foreach (var Ext in DotNetProductExtenstions())
{
if (CommandUtils.FileExists(BaseOutput + Ext))
{
AddBuildProduct(BaseOutput + Ext);
}
}
}
void AddIOSBuildProductsForCSharpProj(string CsProj)
{
string BaseOutput = CommandUtils.CmdEnv.LocalRoot + @"/Engine/Binaries/DotNET/IOS/" + Path.GetFileNameWithoutExtension(CsProj);
foreach (var Ext in DotNetProductExtenstions())
{
if (CommandUtils.FileExists(BaseOutput + Ext))
{
AddBuildProduct(BaseOutput + Ext);
}
}
}
void AddSwarmBuildProducts()
{
foreach (var SwarmProduct in SwarmBuildProducts())
{
string DotNETOutput = CommandUtils.CmdEnv.LocalRoot + @"/Engine/Binaries/DotNET/" + SwarmProduct;
string Win64Output = CommandUtils.CmdEnv.LocalRoot + @"/Engine/Binaries/Win64/" + SwarmProduct;
foreach (var Ext in DotNetProductExtenstions())
{
if (CommandUtils.FileExists(DotNETOutput + Ext))
{
AddBuildProduct(DotNETOutput + Ext);
}
}
foreach (var Ext in DotNetProductExtenstions())
{
if (CommandUtils.FileExists(Win64Output + Ext))
{
AddBuildProduct(Win64Output + Ext);
}
}
}
}
/// <summary>
/// Updates the engine version files
/// </summary>
public List<FileReference> UpdateVersionFiles(bool ActuallyUpdateVersionFiles = true, int? ChangelistNumberOverride = null, int? CompatibleChangelistNumberOverride = null, string Build = null, string BuildURL = null, bool? IsPromotedOverride = null)
{
bool bIsLicenseeVersion = ParseParam("Licensee") || !FileReference.Exists(FileReference.Combine(Unreal.EngineDirectory, "Restricted", "NotForLicensees", "Build", "EpicInternal.txt"));
bool bIsPromotedBuild = IsPromotedOverride.HasValue? IsPromotedOverride.Value : (ParseParamInt("Promoted", 1) != 0);
bool bDoUpdateVersionFiles = CommandUtils.P4Enabled && ActuallyUpdateVersionFiles;
int ChangelistNumber = 0;
if (bDoUpdateVersionFiles)
{
ChangelistNumber = ChangelistNumberOverride.HasValue? ChangelistNumberOverride.Value : CommandUtils.P4Env.Changelist;
}
int CompatibleChangelistNumber = 0;
if(bDoUpdateVersionFiles && CompatibleChangelistNumberOverride.HasValue)
{
CompatibleChangelistNumber = CompatibleChangelistNumberOverride.Value;
}
string Branch = OwnerCommand.ParseParamValue("Branch");
if (String.IsNullOrEmpty(Branch))
{
Branch = CommandUtils.P4Enabled ? CommandUtils.EscapePath(CommandUtils.P4Env.Branch) : "";
}
return StaticUpdateVersionFiles(ChangelistNumber, CompatibleChangelistNumber, Branch, Build, BuildURL, bIsLicenseeVersion, bIsPromotedBuild, bDoUpdateVersionFiles);
}
public static List<FileReference> StaticUpdateVersionFiles(int ChangelistNumber, int CompatibleChangelistNumber, string Branch, string Build, string BuildURL, bool bIsLicenseeVersion, bool bIsPromotedBuild, bool bDoUpdateVersionFiles)
{
FileReference BuildVersionFile = BuildVersion.GetDefaultFileName();
// Get the revision to sync files to before
if(CommandUtils.P4Enabled && ChangelistNumber > 0 && !CommandUtils.IsBuildMachine)
{
CommandUtils.P4.Sync(String.Format("-f \"{0}@{1}\"", BuildVersionFile, ChangelistNumber), false, false);
}
BuildVersion Version;
if(!BuildVersion.TryRead(BuildVersionFile, out Version))
{
Version = new BuildVersion();
}
List<FileReference> Result = new List<FileReference>(1);
{
if (bDoUpdateVersionFiles)
{
Logger.LogDebug("Updating {BuildVersionFile} with:", BuildVersionFile);
Logger.LogDebug(" Changelist={ChangelistNumber}", ChangelistNumber);
Logger.LogDebug(" CompatibleChangelist={CompatibleChangelistNumber}", CompatibleChangelistNumber);
Logger.LogDebug(" IsLicenseeVersion={Arg0}", bIsLicenseeVersion? 1 : 0);
Logger.LogDebug(" IsPromotedBuild={Arg0}", bIsPromotedBuild? 1 : 0);
Logger.LogDebug(" BranchName={Branch}", Branch);
Logger.LogDebug(" BuildVersion={Build}", Build);
Logger.LogDebug(" BuildURL={BuildURL}", BuildURL);
Version.Changelist = ChangelistNumber;
if(CompatibleChangelistNumber > 0)
{
Version.CompatibleChangelist = CompatibleChangelistNumber;
}
else if(bIsLicenseeVersion != Version.IsLicenseeVersion)
{
Version.CompatibleChangelist = 0; // Clear out the compatible changelist number; it corresponds to a different P4 server.
}
Version.IsLicenseeVersion = bIsLicenseeVersion;
Version.IsPromotedBuild = bIsPromotedBuild;
Version.BranchName = Branch;
Version.BuildVersionString = Build;
Version.BuildURL = BuildURL;
if (File.Exists(BuildVersionFile.FullName))
{
VersionFileUpdater.MakeFileWriteable(BuildVersionFile.FullName, true);
}
Version.Write(BuildVersionFile);
}
else
{
Logger.LogDebug("{BuildVersionFile} will not be updated because P4 is not enabled.", BuildVersionFile);
}
Result.Add(BuildVersionFile);
}
return Result;
}
[DebuggerDisplay("{TargetName} {Platform} {Config}")]
public class BuildTarget
{
/// <summary>
/// Name of the target
/// </summary>
public string TargetName;
/// <summary>
/// For code-based projects with a .uproject, the TargetName isn't enough for UBT to find the target, this will point UBT to the target
/// </summary>
public FileReference UprojectPath;
/// <summary>
/// Platform to build
/// </summary>
public UnrealTargetPlatform Platform;
/// <summary>
/// Configuration to build
/// </summary>
public UnrealTargetConfiguration Config;
/// <summary>
/// Extra UBT args
/// </summary>
public string UBTArgs;
/// <summary>
/// Whether to clean this target. If not specified, the target will be cleaned if -Clean is on the command line.
/// </summary>
public bool? Clean;
/// <summary>
/// Format as string
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format("{0} {1} {2}", TargetName, Platform, Config);
}
}
public class BuildAgenda
{
/// <summary>
/// .NET .csproj files that will be compiled and included in the build. Currently we assume the output
/// binary file names match the solution file base name, but with various different binary file extensions.
/// </summary>
public List<string> DotNetProjects = new List<string>();
public string SwarmAgentProject = "";
public string SwarmCoordinatorProject = "";
/// <summary>
/// List of targets to build. These can be various Unreal projects, programs or libraries in various configurations
/// </summary>
public List<BuildTarget> Targets = new List<BuildTarget>();
/// <summary>
/// Adds a target with the specified configuration.
/// </summary>
/// <param name="TargetName">Name of the target</param>
/// <param name="InPlatform">Platform</param>
/// <param name="InConfiguration">Configuration</param>
/// <param name="InUprojectPath">Path to optional uproject file</param>
/// <param name="InAddArgs">Specifies additional arguments for UBT</param>
public void AddTarget(string TargetName, UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration, FileReference InUprojectPath = null, string InAddArgs = "")
{
// Is this platform a compilable target?
if (!Platform.GetPlatform(InPlatform).CanBeCompiled())
{
return;
}
Targets.Add(new BuildTarget()
{
TargetName = TargetName,
Platform = InPlatform,
Config = InConfiguration,
UprojectPath = InUprojectPath,
UBTArgs = InAddArgs,
});
}
/// <summary>
/// Adds multiple targets with the specified configuration.
/// </summary>
/// <param name="TargetNames">List of targets.</param>
/// <param name="InPlatform">Platform</param>
/// <param name="InConfiguration">Configuration</param>
/// <param name="InUprojectPath">Path to optional uproject file</param>
/// <param name="InAddArgs">Specifies additional arguments for UBT</param>
public void AddTargets(string[] TargetNames, UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration, FileReference InUprojectPath = null, string InAddArgs = "")
{
// Is this platform a compilable target?
if (!Platform.GetPlatform(InPlatform).CanBeCompiled())
{
return;
}
foreach (var Target in TargetNames)
{
Targets.Add(new BuildTarget()
{
TargetName = Target,
Platform = InPlatform,
Config = InConfiguration,
UprojectPath = InUprojectPath,
UBTArgs = InAddArgs,
});
}
}
}
public UnrealBuild(BuildCommand Command)
{
OwnerCommand = Command;
BuildProductFiles.Clear();
}
private bool ParseParam(string Name)
{
return OwnerCommand != null && OwnerCommand.ParseParam(Name);
}
private string ParseParamValue(string Name)
{
return (OwnerCommand != null)? OwnerCommand.ParseParamValue(Name) : null;
}
private int ParseParamInt(string Name, int Default = 0)
{
return (OwnerCommand != null)? OwnerCommand.ParseParamInt(Name, Default) : Default;
}
/// <summary>
/// Executes a build.
/// </summary>
/// <param name="InAgenda">Build agenda.</param>
/// <param name="InDeleteBuildProducts">if specified, determines if the build products will be deleted before building. If not specified -clean parameter will be used,</param>
/// <param name="InUpdateVersionFiles">True if the version files are to be updated </param>
/// <param name="InForceNoXGE">If true will force XGE off</param>
/// <param name="InAllCores">If true AND XGE not present or not being used then ensure UBT uses all available cores</param>
/// <param name="InChangelistNumberOverride"></param>
/// <param name="InTargetToManifest"></param>
/// <param name="InSkipBuild"></param>
public void Build(BuildAgenda InAgenda, bool? InDeleteBuildProducts = null, bool InUpdateVersionFiles = true, bool InForceNoXGE = false, bool InAllCores = false, int? InChangelistNumberOverride = null, Dictionary<BuildTarget, BuildManifest> InTargetToManifest = null, bool InSkipBuild = false)
{
if (!CommandUtils.CmdEnv.HasCapabilityToCompile)
{
throw new UnrealBuildException("You are attempting to compile on a machine that does not have a supported compiler!");
}
bool DeleteBuildProducts = InDeleteBuildProducts.HasValue ? InDeleteBuildProducts.Value : ParseParam("Clean");
if (InUpdateVersionFiles)
{
UpdateVersionFiles(ActuallyUpdateVersionFiles: true, ChangelistNumberOverride: InChangelistNumberOverride);
}
//////////////////////////////////////
// make a set of unique platforms involved
var UniquePlatforms = new List<UnrealTargetPlatform>();
foreach (var Target in InAgenda.Targets)
{
if (!UniquePlatforms.Contains(Target.Platform))
{
UniquePlatforms.Add(Target.Platform);
}
}
if (InAgenda.SwarmAgentProject != "")
{
string SwarmAgentSolution = Path.Combine(CommandUtils.CmdEnv.LocalRoot, InAgenda.SwarmAgentProject);
CommandUtils.BuildSolution(CommandUtils.CmdEnv, SwarmAgentSolution, "Development", "Mixed Platforms");
AddSwarmBuildProducts();
}
if (InAgenda.SwarmCoordinatorProject != "")
{
string SwarmCoordinatorSolution = Path.Combine(CommandUtils.CmdEnv.LocalRoot, InAgenda.SwarmCoordinatorProject);
CommandUtils.BuildSolution(CommandUtils.CmdEnv, SwarmCoordinatorSolution, "Development", "Mixed Platforms");
AddSwarmBuildProducts();
}
foreach (var DotNetProject in InAgenda.DotNetProjects)
{
string CsProj = Path.Combine(CommandUtils.CmdEnv.LocalRoot, DotNetProject);
CommandUtils.BuildCSharpProject(CommandUtils.CmdEnv, CsProj);
AddBuildProductsForCSharpProj(CsProj);
}
string XGEConsole = null;
bool bDisableXGE = ParseParam("NoXGE") || InForceNoXGE;
bool bCanUseXGE = !bDisableXGE && PlatformExports.TryGetXgConsoleExecutable(out XGEConsole);
Logger.LogDebug("************************* UnrealBuild:");
Logger.LogDebug("************************* UseXGE: {bCanUseXGE}", bCanUseXGE);
// Clean all the targets
foreach (BuildTarget Target in InAgenda.Targets)
{
bool bClean = Target.Clean ?? DeleteBuildProducts;
if (bClean)
{
CleanWithUBT(Target.TargetName, Target.Platform, Target.Config, Target.UprojectPath, Target.UBTArgs);
}
}
if (InAgenda.Targets.Count == 0)
{
return;
}
// Build all the targets
BuildWithUBT(InAgenda.Targets, InTargetToManifest, bDisableXGE, InAllCores, InSkipBuild);
}
/// <summary>
/// Checks to make sure there was at least one build product, and that all files exist. Also, logs them all out.
/// </summary>
/// <param name="BuildProductFiles">List of files</param>
public static void CheckBuildProducts(HashSet<string> BuildProductFiles)
{
// Check build products
{
Logger.LogDebug("Build products *******");
if (BuildProductFiles.Count < 1)
{
Logger.LogInformation("No build products were made");
}
else
{
foreach (var Product in BuildProductFiles)
{
if (!CommandUtils.FileExists(Product) && !CommandUtils.DirectoryExists(Product))
{
throw new UnrealBuildException("{0} was a build product but no longer exists", Product);
}
Logger.LogDebug("{Text}", Product);
}
}
Logger.LogDebug("End Build products *******");
}
}
/// <summary>
/// Adds or edits existing files at head revision, expecting an exclusive lock, resolving by clobbering any existing version
/// </summary>
/// <param name="WorkingCL"></param>
/// <param name="Files">List of files to check out</param>
public static void AddBuildProductsToChangelist(int WorkingCL, IEnumerable<string> Files)
{
Logger.LogInformation("Adding {Arg0} build products to changelist {WorkingCL}...", Files.Count(), WorkingCL);
foreach (var File in Files)
{
CommandUtils.P4.Sync("-f -k " + CommandUtils.MakePathSafeToUseWithCommandLine(File) + "#head"); // sync the file without overwriting local one
if (!CommandUtils.FileExists(File))
{
throw new UnrealBuildException("{0} was a build product but no longer exists", File);
}
CommandUtils.P4.ReconcileNoDeletes(WorkingCL, CommandUtils.MakePathSafeToUseWithCommandLine(File));
// Change file type on binary files to be always writeable.
var FileStats = CommandUtils.P4.FStat(File);
if (CommandUtils.IsProbablyAMacOrIOSExe(File))
{
if (FileStats.Type == P4FileType.Binary && (FileStats.Attributes & (P4FileAttributes.Executable | P4FileAttributes.Writeable)) != (P4FileAttributes.Executable | P4FileAttributes.Writeable))
{
CommandUtils.P4.ChangeFileType(File, (P4FileAttributes.Executable | P4FileAttributes.Writeable));
}
}
else
{
if (IsBuildProduct(File, FileStats) && (FileStats.Attributes & P4FileAttributes.Writeable) != P4FileAttributes.Writeable)
{
CommandUtils.P4.ChangeFileType(File, P4FileAttributes.Writeable);
}
}
}
}
/// <summary>
/// Determines if this file is a build product.
/// </summary>
/// <param name="File">File path</param>
/// <param name="FileStats">P4 file stats.</param>
/// <returns>True if this is a Windows build product. False otherwise.</returns>
private static bool IsBuildProduct(string File, P4FileStat FileStats)
{
if(FileStats.Type == P4FileType.Binary || IsBuildReceipt(File))
{
return true;
}
return FileStats.Type == P4FileType.Text && File.EndsWith(".exe.config", StringComparison.InvariantCultureIgnoreCase);
}
/// <summary>
/// Add UBT files to build products
/// </summary>
public void AddUBTFilesToBuildProducts()
{
string UBTLocation = UnrealBuildToolDll.Directory.FullName;
// copy all the files from the UBT output directory
string[] UBTFiles = CommandUtils.FindFiles_NoExceptions("*.*", true, UBTLocation);
foreach (string UBTFile in UBTFiles)
{
AddBuildProduct(UBTFile);
}
}
/// <summary>
/// Copy the UAT files to their precompiled location, and add them as build products
/// </summary>
public void AddUATFilesToBuildProducts()
{
// All scripts are expected to exist in DotNET/AutomationScripts subfolder.
foreach (FileReference BuildProduct in ScriptManager.BuildProducts)
{
string UATScriptFilePath = BuildProduct.FullName;
if (!CommandUtils.FileExists_NoExceptions(UATScriptFilePath))
{
throw new UnrealBuildException("Cannot add UAT to the build products because {0} does not exist.", UATScriptFilePath);
}
AddBuildProduct(UATScriptFilePath);
}
}
DirectoryReference GetManifestDir(FileReference ProjectFile)
{
// Can't write to Engine directory on installed builds
if (Unreal.IsEngineInstalled() && ProjectFile != null)
{
return DirectoryReference.Combine(ProjectFile.Directory, "Intermediate", "Build");
}
else
{
return DirectoryReference.Combine(Unreal.EngineDirectory, "Intermediate", "Build");
}
}
FileReference GetManifestFile(FileReference ProjectFile)
{
return FileReference.Combine(GetManifestDir(ProjectFile), "Manifest.xml");
}
[Obsolete("Deprecated in UE5.1; use UnrealBuildToolDll")]
public static string GetUBTExecutable()
{
return CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, @"Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool" + (OperatingSystem.IsWindows() ? ".exe" : ""));
}
[Obsolete("Deprecated in UE5.1; use UnrealBuildToolDll")]
public string UBTExecutable
{
get
{
return GetUBTExecutable();
}
}
public static FileReference UnrealBuildToolDll =>
FileReference.FromString(CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.dll"));
// List of everything we built so far
public readonly HashSet<string> BuildProductFiles = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
}
}