// Copyright 1998-2018 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
{
///
/// Describes all of the information needed to initialize a UEBuildTarget object
///
class TargetDescriptor
{
public FileReference ProjectFile;
public string Name;
public UnrealTargetPlatform Platform;
public UnrealTargetConfiguration Configuration;
public string Architecture;
public List OnlyModules;
public FileReference ForeignPlugin;
public string ForceReceiptFileName;
public string[] AdditionalArguments;
///
/// Constructor
///
/// Path to the project file
/// Name of the target to build
/// Platform to build for
/// Configuration to build
/// Architecture to build for
/// Additional arguments for the target
public TargetDescriptor(FileReference ProjectFile, string TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, string Architecture, string[] Arguments)
{
this.ProjectFile = ProjectFile;
this.Name = TargetName;
this.Platform = Platform;
this.Configuration = Configuration;
this.Architecture = Architecture;
this.AdditionalArguments = Arguments;
}
///
/// Parse a list of target descriptors from the command line
///
/// Command-line arguments
/// Whether to use a precompiled engine distribution
/// Whether to skip compiling rules assemblies
/// The project file, if already set. May be updated if not.
/// List of target descriptors
public static List ParseCommandLine(string[] Arguments, bool bUsePrecompiled, bool bSkipRulesCompile, ref FileReference ProjectFile)
{
UnrealTargetPlatform Platform = UnrealTargetPlatform.Unknown;
UnrealTargetConfiguration Configuration = UnrealTargetConfiguration.Unknown;
List TargetNames = new List();
List TargetTypes = new List();
string Architecture = null;
List OnlyModules = new List();
FileReference ForeignPlugin = null;
string ForceReceiptFileName = null;
List AdditionalArguments = new List();
// Settings for creating/using static libraries for the engine
for (int ArgumentIndex = 0; ArgumentIndex < Arguments.Length; ArgumentIndex++)
{
string Argument = Arguments[ArgumentIndex];
if(!Argument.StartsWith("-"))
{
UnrealTargetPlatform ParsedPlatform;
if(Enum.TryParse(Argument, true, out ParsedPlatform) && ParsedPlatform != UnrealTargetPlatform.Unknown)
{
if(Platform != UnrealTargetPlatform.Unknown)
{
throw new BuildException("Multiple platforms specified on command line (first {0}, then {1})", Platform, ParsedPlatform);
}
Platform = ParsedPlatform;
continue;
}
UnrealTargetConfiguration ParsedConfiguration;
if(Enum.TryParse(Argument, true, out ParsedConfiguration) && ParsedConfiguration != UnrealTargetConfiguration.Unknown)
{
if(Configuration != UnrealTargetConfiguration.Unknown)
{
throw new BuildException("Multiple configurations specified on command line (first {0}, then {1})", Configuration, ParsedConfiguration);
}
Configuration = ParsedConfiguration;
continue;
}
// Make sure the target name is valid. It may be the path to a project file.
if(Argument.IndexOfAny(new char[]{ Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, '.' }) == -1)
{
TargetNames.Add(Argument);
}
}
else
{
string Value;
if(ParseArgumentValue(Argument, "-TargetType=", out Value))
{
TargetType Type;
if(!Enum.TryParse(Value, true, out Type))
{
throw new BuildException("Invalid target type: '{0}'", Value);
}
TargetTypes.Add(Type);
}
else if(ParseArgumentValue(Argument, "-Module=", out Value))
{
OnlyModules.Add(new OnlyModule(Value));
}
else if(ParseArgumentValue(Argument, "-ModuleWithSuffix=", out Value))
{
int SuffixIdx = Value.LastIndexOf(',');
if(SuffixIdx == -1)
{
throw new BuildException("Missing suffix argument from -ModuleWithSuffix=Name,Suffix");
}
OnlyModules.Add(new OnlyModule(Value.Substring(0, SuffixIdx), Value.Substring(SuffixIdx + 1)));
}
else if(ParseArgumentValue(Argument, "-Plugin=", out Value))
{
if(ForeignPlugin != null)
{
throw new BuildException("Only one foreign plugin to compile may be specified per invocation");
}
ForeignPlugin = new FileReference(Value);
}
else if(ParseArgumentValue(Argument, "-Receipt=", out Value))
{
ForceReceiptFileName = Value;
}
else
{
switch (Arguments[ArgumentIndex].ToUpperInvariant())
{
case "-MODULE":
throw new BuildException("'-Module ' syntax is no longer supported on the command line. Use '-Module=' instead.");
case "-MODULEWITHSUFFIX":
throw new BuildException("'-ModuleWithSuffix ' syntax is no longer supported on the command line. Use '-Module=,' instead.");
case "-PLUGIN":
throw new BuildException("'-Plugin ' syntax is no longer supported on the command line. Use '-Plugin=' instead.");
case "-RECEIPT":
throw new BuildException("'-Receipt ' syntax is no longer supported on the command line. Use '-Receipt=' instead.");
default:
AdditionalArguments.Add(Arguments[ArgumentIndex]);
break;
}
}
}
}
if (Platform == UnrealTargetPlatform.Unknown)
{
throw new BuildException("Couldn't find platform name.");
}
if (Configuration == UnrealTargetConfiguration.Unknown)
{
throw new BuildException("Couldn't determine configuration name.");
}
if(Architecture == null)
{
Architecture = UEBuildPlatform.GetBuildPlatform(Platform).GetDefaultArchitecture(ProjectFile);
}
// Create all the target descriptors for targets specified by type
foreach(TargetType Type in TargetTypes)
{
if (ProjectFile == null)
{
throw new BuildException("-TargetType=... requires a project file to be specified");
}
else
{
TargetNames.Add(RulesCompiler.CreateProjectRulesAssembly(ProjectFile, bUsePrecompiled, bSkipRulesCompile).GetTargetNameByType(Type, Platform, Configuration, Architecture, ProjectFile, new ReadOnlyBuildVersion(BuildVersion.ReadDefault())));
}
}
// Create all the target descriptor
List Targets = new List();
foreach(string TargetName in TargetNames)
{
// If a project file was not specified see if we can find one
if (ProjectFile == null && UProjectInfo.TryGetProjectForTarget(TargetName, out ProjectFile))
{
Log.TraceVerbose("Found project file for {0} - {1}", TargetName, ProjectFile);
}
// Create the target descriptor
TargetDescriptor Target = new TargetDescriptor(ProjectFile, TargetName, Platform, Configuration, Architecture, AdditionalArguments.ToArray());
Target.OnlyModules = OnlyModules;
Target.ForeignPlugin = ForeignPlugin;
Target.ForceReceiptFileName = ForceReceiptFileName;
Targets.Add(Target);
}
// Make sure we could parse something
if (Targets.Count == 0)
{
throw new BuildException("No target name was specified on the command-line.");
}
return Targets;
}
///
/// Parse a single argument value, of the form -Foo=Bar
///
/// The argument to parse
/// The argument prefix, eg. "-Foo="
/// Receives the value of the argument
/// True if the argument could be parsed, false otherwise
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;
}
}
}
}