You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
429 lines
15 KiB
C#
429 lines
15 KiB
C#
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Tools.DotNETCommon;
|
|
|
|
namespace UnrealBuildTool
|
|
{
|
|
/// <summary>
|
|
/// Describes all of the information needed to initialize a UEBuildTarget object
|
|
/// </summary>
|
|
class TargetDescriptor
|
|
{
|
|
public FileReference ProjectFile;
|
|
public string Name;
|
|
public UnrealTargetPlatform Platform;
|
|
public UnrealTargetConfiguration Configuration;
|
|
public string Architecture;
|
|
public CommandLineArguments AdditionalArguments;
|
|
|
|
/// <summary>
|
|
/// Foreign plugin to compile against this target
|
|
/// </summary>
|
|
[CommandLine("-Plugin=")]
|
|
public FileReference ForeignPlugin = null;
|
|
|
|
/// <summary>
|
|
/// Set of module names to compile.
|
|
/// </summary>
|
|
[CommandLine("-Module=")]
|
|
public HashSet<string> OnlyModuleNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
/// <summary>
|
|
/// Single file to compile
|
|
/// </summary>
|
|
[CommandLine("-SingleFile=")]
|
|
public FileReference SingleFileToCompile = null;
|
|
|
|
/// <summary>
|
|
/// Whether to perform hot reload for this target
|
|
/// </summary>
|
|
[CommandLine("-NoHotReload", Value = nameof(HotReloadMode.Disabled))]
|
|
[CommandLine("-ForceHotReload", Value = nameof(HotReloadMode.FromIDE))]
|
|
[CommandLine("-LiveCoding", Value = nameof(HotReloadMode.LiveCoding))]
|
|
public HotReloadMode HotReloadMode = HotReloadMode.Default;
|
|
|
|
/// <summary>
|
|
/// Map of module name to suffix for hot reloading from the editor
|
|
/// </summary>
|
|
public Dictionary<string, int> HotReloadModuleNameToSuffix = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
/// <summary>
|
|
/// Export the actions for the target to a file
|
|
/// </summary>
|
|
[CommandLine("-WriteActions=")]
|
|
public List<FileReference> WriteActionFiles = new List<FileReference>();
|
|
|
|
/// <summary>
|
|
/// Path to a file containing a list of modules that may be modified for live coding.
|
|
/// </summary>
|
|
[CommandLine("-LiveCodingModules=")]
|
|
public FileReference LiveCodingModules = null;
|
|
|
|
/// <summary>
|
|
/// Path to the manifest for passing info about the output to live coding
|
|
/// </summary>
|
|
[CommandLine("-LiveCodingManifest=")]
|
|
public FileReference LiveCodingManifest = null;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="ProjectFile">Path to the project file</param>
|
|
/// <param name="TargetName">Name of the target to build</param>
|
|
/// <param name="Platform">Platform to build for</param>
|
|
/// <param name="Configuration">Configuration to build</param>
|
|
/// <param name="Architecture">Architecture to build for</param>
|
|
/// <param name="Arguments">Other command-line arguments for the target</param>
|
|
public TargetDescriptor(FileReference ProjectFile, string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string Architecture, CommandLineArguments Arguments)
|
|
{
|
|
this.ProjectFile = ProjectFile;
|
|
this.Name = TargetName;
|
|
this.Platform = Platform;
|
|
this.Configuration = Configuration;
|
|
this.Architecture = Architecture;
|
|
|
|
// If there are any additional command line arguments
|
|
List<string> AdditionalArguments = new List<string>();
|
|
if(Arguments != null)
|
|
{
|
|
// Apply the arguments to this object
|
|
Arguments.ApplyTo(this);
|
|
|
|
// Parse all the hot-reload module names
|
|
foreach(string ModuleWithSuffix in Arguments.GetValues("-ModuleWithSuffix="))
|
|
{
|
|
int SuffixIdx = ModuleWithSuffix.LastIndexOf(',');
|
|
if(SuffixIdx == -1)
|
|
{
|
|
throw new BuildException("Missing suffix argument from -ModuleWithSuffix=Name,Suffix");
|
|
}
|
|
|
|
string ModuleName = ModuleWithSuffix.Substring(0, SuffixIdx);
|
|
|
|
int Suffix;
|
|
if(!Int32.TryParse(ModuleWithSuffix.Substring(SuffixIdx + 1), out Suffix))
|
|
{
|
|
throw new BuildException("Suffix for modules must be an integer");
|
|
}
|
|
|
|
HotReloadModuleNameToSuffix[ModuleName] = Suffix;
|
|
}
|
|
|
|
// Pull out all the arguments that haven't been used so far
|
|
for(int Idx = 0; Idx < Arguments.Count; Idx++)
|
|
{
|
|
if(!Arguments.HasBeenUsed(Idx))
|
|
{
|
|
AdditionalArguments.Add(Arguments[Idx]);
|
|
}
|
|
}
|
|
}
|
|
this.AdditionalArguments = new CommandLineArguments(AdditionalArguments.ToArray());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse a list of target descriptors from the command line
|
|
/// </summary>
|
|
/// <param name="Arguments">Command-line arguments</param>
|
|
/// <param name="bUsePrecompiled">Whether to use a precompiled engine distribution</param>
|
|
/// <param name="bSkipRulesCompile">Whether to skip compiling rules assemblies</param>
|
|
/// <returns>List of target descriptors</returns>
|
|
public static List<TargetDescriptor> ParseCommandLine(CommandLineArguments Arguments, bool bUsePrecompiled, bool bSkipRulesCompile)
|
|
{
|
|
List<TargetDescriptor> TargetDescriptors = new List<TargetDescriptor>();
|
|
ParseCommandLine(Arguments, bUsePrecompiled, bSkipRulesCompile, TargetDescriptors);
|
|
return TargetDescriptors;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse a list of target descriptors from the command line
|
|
/// </summary>
|
|
/// <param name="Arguments">Command-line arguments</param>
|
|
/// <param name="bUsePrecompiled">Whether to use a precompiled engine distribution</param>
|
|
/// <param name="bSkipRulesCompile">Whether to skip compiling rules assemblies</param>
|
|
/// <param name="TargetDescriptors">Receives the list of parsed target descriptors</param>
|
|
public static void ParseCommandLine(CommandLineArguments Arguments, bool bUsePrecompiled, bool bSkipRulesCompile, List<TargetDescriptor> TargetDescriptors)
|
|
{
|
|
List<string> TargetLists;
|
|
Arguments = Arguments.Remove("-TargetList=", out TargetLists);
|
|
|
|
List<string> Targets;
|
|
Arguments = Arguments.Remove("-Target=", out Targets);
|
|
|
|
if(TargetLists.Count > 0 || Targets.Count > 0)
|
|
{
|
|
// Try to parse multiple arguments from a single command line
|
|
foreach(string TargetList in TargetLists)
|
|
{
|
|
string[] Lines = File.ReadAllLines(TargetList);
|
|
foreach(string Line in Lines)
|
|
{
|
|
string TrimLine = Line.Trim();
|
|
if(TrimLine.Length > 0 && TrimLine[0] != ';')
|
|
{
|
|
CommandLineArguments NewArguments = Arguments.Append(CommandLineArguments.Split(TrimLine));
|
|
ParseCommandLine(NewArguments, bUsePrecompiled, bSkipRulesCompile, TargetDescriptors);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach(string Target in Targets)
|
|
{
|
|
CommandLineArguments NewArguments = Arguments.Append(CommandLineArguments.Split(Target));
|
|
ParseCommandLine(NewArguments, bUsePrecompiled, bSkipRulesCompile, TargetDescriptors);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Otherwise just process the whole command line together
|
|
ParseSingleCommandLine(Arguments, bUsePrecompiled, bSkipRulesCompile, TargetDescriptors);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse a list of target descriptors from the command line
|
|
/// </summary>
|
|
/// <param name="Arguments">Command-line arguments</param>
|
|
/// <param name="bUsePrecompiled">Whether to use a precompiled engine distribution</param>
|
|
/// <param name="bSkipRulesCompile">Whether to skip compiling rules assemblies</param>
|
|
/// <param name="TargetDescriptors">List of target descriptors</param>
|
|
public static void ParseSingleCommandLine(CommandLineArguments Arguments, bool bUsePrecompiled, bool bSkipRulesCompile, List<TargetDescriptor> TargetDescriptors)
|
|
{
|
|
List<UnrealTargetPlatform> Platforms = new List<UnrealTargetPlatform>();
|
|
List<UnrealTargetConfiguration> Configurations = new List<UnrealTargetConfiguration>();
|
|
List<string> TargetNames = new List<string>();
|
|
FileReference ProjectFile = Arguments.GetFileReferenceOrDefault("-Project=", null);
|
|
|
|
// Settings for creating/using static libraries for the engine
|
|
for (int ArgumentIndex = 0; ArgumentIndex < Arguments.Count; ArgumentIndex++)
|
|
{
|
|
string Argument = Arguments[ArgumentIndex];
|
|
if(Argument.Length > 0 && Argument[0] != '-')
|
|
{
|
|
// Mark this argument as used. We'll interpret it as one thing or another.
|
|
Arguments.MarkAsUsed(ArgumentIndex);
|
|
|
|
// Check if it's a project file argument
|
|
if(Argument.EndsWith(".uproject", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
FileReference NewProjectFile = new FileReference(Argument);
|
|
if(ProjectFile != null && ProjectFile != NewProjectFile)
|
|
{
|
|
throw new BuildException("Multiple project files specified on command line (first {0}, then {1})", ProjectFile, NewProjectFile);
|
|
}
|
|
ProjectFile = new FileReference(Argument);
|
|
continue;
|
|
}
|
|
|
|
// Split it into separate arguments
|
|
string[] InlineArguments = Argument.Split('+');
|
|
|
|
// Try to parse them as platforms
|
|
UnrealTargetPlatform ParsedPlatform;
|
|
if(UnrealTargetPlatform.TryParse(InlineArguments[0], out ParsedPlatform))
|
|
{
|
|
Platforms.Add(ParsedPlatform);
|
|
for(int InlineArgumentIdx = 1; InlineArgumentIdx < InlineArguments.Length; InlineArgumentIdx++)
|
|
{
|
|
Platforms.Add(UnrealTargetPlatform.Parse(InlineArguments[InlineArgumentIdx]));
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Try to parse them as configurations
|
|
UnrealTargetConfiguration ParsedConfiguration;
|
|
if(Enum.TryParse(InlineArguments[0], true, out ParsedConfiguration))
|
|
{
|
|
Configurations.Add(ParsedConfiguration);
|
|
for(int InlineArgumentIdx = 1; InlineArgumentIdx < InlineArguments.Length; InlineArgumentIdx++)
|
|
{
|
|
string InlineArgument = InlineArguments[InlineArgumentIdx];
|
|
if(!Enum.TryParse(InlineArgument, true, out ParsedConfiguration))
|
|
{
|
|
throw new BuildException("Invalid configuration '{0}'", InlineArgument);
|
|
}
|
|
Configurations.Add(ParsedConfiguration);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Otherwise assume they are target names
|
|
TargetNames.AddRange(InlineArguments);
|
|
}
|
|
}
|
|
|
|
if (Platforms.Count == 0)
|
|
{
|
|
throw new BuildException("No platforms specified for target");
|
|
}
|
|
if (Configurations.Count == 0)
|
|
{
|
|
throw new BuildException("No configurations specified for target");
|
|
}
|
|
|
|
// Make sure the project file exists, and make sure we're using the correct case.
|
|
if(ProjectFile != null)
|
|
{
|
|
FileInfo ProjectFileInfo = FileUtils.FindCorrectCase(ProjectFile.ToFileInfo());
|
|
if(!ProjectFileInfo.Exists)
|
|
{
|
|
throw new BuildException("Unable to find project '{0}'.", ProjectFile);
|
|
}
|
|
ProjectFile = new FileReference(ProjectFileInfo);
|
|
}
|
|
|
|
// Expand all the platforms, architectures and configurations
|
|
foreach(UnrealTargetPlatform Platform in Platforms)
|
|
{
|
|
// Make sure the platform is valid
|
|
if (!InstalledPlatformInfo.IsValid(null, Platform, null, EProjectType.Code, InstalledPlatformState.Downloaded))
|
|
{
|
|
if (!InstalledPlatformInfo.IsValid(null, Platform, null, EProjectType.Code, InstalledPlatformState.Supported))
|
|
{
|
|
throw new BuildException("The {0} platform is not supported from this engine distribution.", Platform);
|
|
}
|
|
else
|
|
{
|
|
throw new BuildException("Missing files required to build {0} targets. Enable {0} as an optional download component in the Epic Games Launcher.", Platform);
|
|
}
|
|
}
|
|
|
|
// Parse the architecture parameter, or get the default for the platform
|
|
List<string> Architectures = new List<string>(Arguments.GetValues("-Architecture=", '+'));
|
|
if(Architectures.Count == 0)
|
|
{
|
|
Architectures.Add(UEBuildPlatform.GetBuildPlatform(Platform).GetDefaultArchitecture(ProjectFile));
|
|
}
|
|
|
|
foreach(string Architecture in Architectures)
|
|
{
|
|
foreach(UnrealTargetConfiguration Configuration in Configurations)
|
|
{
|
|
// Create all the target descriptors for targets specified by type
|
|
foreach(string TargetTypeString in Arguments.GetValues("-TargetType="))
|
|
{
|
|
TargetType TargetType;
|
|
if(!Enum.TryParse(TargetTypeString, out TargetType))
|
|
{
|
|
throw new BuildException("Invalid target type '{0}'", TargetTypeString);
|
|
}
|
|
|
|
if (ProjectFile == null)
|
|
{
|
|
throw new BuildException("-TargetType=... requires a project file to be specified");
|
|
}
|
|
else
|
|
{
|
|
TargetNames.Add(RulesCompiler.CreateProjectRulesAssembly(ProjectFile, bUsePrecompiled, bSkipRulesCompile).GetTargetNameByType(TargetType, Platform, Configuration, Architecture, ProjectFile));
|
|
}
|
|
}
|
|
|
|
// Make sure we could parse something
|
|
if (TargetNames.Count == 0)
|
|
{
|
|
throw new BuildException("No target name was specified on the command-line.");
|
|
}
|
|
|
|
// Create all the target descriptors
|
|
foreach(string TargetName in TargetNames)
|
|
{
|
|
// If a project file was not specified see if we can find one
|
|
if (ProjectFile == null && NativeProjects.TryGetProjectForTarget(TargetName, out ProjectFile))
|
|
{
|
|
Log.TraceVerbose("Found project file for {0} - {1}", TargetName, ProjectFile);
|
|
}
|
|
|
|
// Create the target descriptor
|
|
TargetDescriptors.Add(new TargetDescriptor(ProjectFile, TargetName, Platform, Configuration, Architecture, Arguments));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Try to parse the project file from the command line
|
|
/// </summary>
|
|
/// <param name="Arguments">The command line arguments</param>
|
|
/// <param name="ProjectFile">The project file that was parsed</param>
|
|
/// <returns>True if the project file was parsed, false otherwise</returns>
|
|
public static bool TryParseProjectFileArgument(CommandLineArguments Arguments, out FileReference ProjectFile)
|
|
{
|
|
FileReference ExplicitProjectFile;
|
|
if(Arguments.TryGetValue("-Project=", out ExplicitProjectFile))
|
|
{
|
|
ProjectFile = ExplicitProjectFile;
|
|
return true;
|
|
}
|
|
|
|
for(int Idx = 0; Idx < Arguments.Count; Idx++)
|
|
{
|
|
if(Arguments[Idx][0] != '-' && Arguments[Idx].EndsWith(".uproject", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
Arguments.MarkAsUsed(Idx);
|
|
ProjectFile = new FileReference(Arguments[Idx]);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if(UnrealBuildTool.IsProjectInstalled())
|
|
{
|
|
ProjectFile = UnrealBuildTool.GetInstalledProjectFile();
|
|
return true;
|
|
}
|
|
|
|
ProjectFile = null;
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parse a single argument value, of the form -Foo=Bar
|
|
/// </summary>
|
|
/// <param name="Argument">The argument to parse</param>
|
|
/// <param name="Prefix">The argument prefix, eg. "-Foo="</param>
|
|
/// <param name="Value">Receives the value of the argument</param>
|
|
/// <returns>True if the argument could be parsed, false otherwise</returns>
|
|
private static bool ParseArgumentValue(string Argument, string Prefix, out string Value)
|
|
{
|
|
if(Argument.StartsWith(Prefix, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
Value = Argument.Substring(Prefix.Length);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Value = null;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Format this object for the debugger
|
|
/// </summary>
|
|
/// <returns>String representation of this target descriptor</returns>
|
|
public override string ToString()
|
|
{
|
|
StringBuilder Result = new StringBuilder();
|
|
Result.AppendFormat("{0} {1} {2}", Name, Platform, Configuration);
|
|
if(!String.IsNullOrEmpty(Architecture))
|
|
{
|
|
Result.AppendFormat(" -Architecture={0}", Architecture);
|
|
}
|
|
if(ProjectFile != null)
|
|
{
|
|
Result.AppendFormat(" -Project={0}", Utils.MakePathSafeToUseWithCommandLine(ProjectFile));
|
|
}
|
|
if(AdditionalArguments != null && AdditionalArguments.Count > 0)
|
|
{
|
|
Result.AppendFormat(" {0}", AdditionalArguments);
|
|
}
|
|
return Result.ToString();
|
|
}
|
|
}
|
|
}
|