Files
UnrealEngine/Engine/Source/Programs/UnrealBuildTool/Configuration/UEBuildPlatform.cs
2025-05-18 13:04:45 +08:00

1399 lines
59 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using EpicGames.Core;
using Microsoft.Extensions.Logging;
using OpenTracing.Util;
using static UnrealBuildTool.DataDrivenPlatformInfo;
namespace UnrealBuildTool
{
/// <summary>
/// Enum for the different ways a platform can support multiple architectures within UnrealBuildTool
/// </summary>
public enum UnrealArchitectureMode
{
/// <summary>
/// This platform only supports a single architecture (consoles, etc)
/// </summary>
SingleArchitecture,
/// <summary>
/// This platform needs separate targets per architecture (compiling for multiple will compile two entirely separate set of source/exectuable/intermediates)
/// </summary>
OneTargetPerArchitecture,
/// <summary>
/// This will create a single target, but compile each source file separately
/// </summary>
SingleTargetCompileSeparately,
/// <summary>
/// This will create a single target, but compile each source file and link the executable separately - but then packaged together into one final output
/// </summary>
SingleTargetLinkSeparately,
}
/// <summary>
/// Full architecture configuation information for a platform. Can be found by platform with UnrealArchitectureConfig.ForPlatform(), or UEBuildPlatform.ArchitectureConfig
/// </summary>
public class UnrealArchitectureConfig
{
/// <summary>
/// Get the architecture configuration object for a given platform
/// </summary>
/// <param name="Platform"></param>
/// <returns></returns>
public static UnrealArchitectureConfig ForPlatform(UnrealTargetPlatform Platform)
{
return UEBuildPlatform.GetBuildPlatform(Platform).ArchitectureConfig;
}
/// <summary>
/// Get all known ArchitectureConfig objects
/// </summary>
/// <returns></returns>
public static IEnumerable<UnrealArchitectureConfig> AllConfigs()
{
// return ArchConfigs for platforms that have a BuildPlatform (which is where the Configs are stored)
return UnrealTargetPlatform.GetValidPlatforms().Where(x => UEBuildPlatform.TryGetBuildPlatform(x, out _)).Select(x => UEBuildPlatform.GetBuildPlatform(x).ArchitectureConfig);
}
/// <summary>
/// The multi-architecture mode for this platform (potentially single-architecture)
/// </summary>
public UnrealArchitectureMode Mode { get; }
/// <summary>
/// The set of all architecture this platform supports. Any platform specified on the UBT commandline not in this list will be an error
/// </summary>
public UnrealArchitectures AllSupportedArchitectures { get; }
/// <summary>
/// This determines what architecture(s) to compile/package when no architeecture is specified on the commandline
/// </summary>
/// <param name="ProjectFile"></param>
/// <param name="TargetName"></param>
/// <returns></returns>
public virtual UnrealArchitectures ActiveArchitectures(FileReference? ProjectFile, string? TargetName)
{
if (Mode != UnrealArchitectureMode.SingleArchitecture || AllSupportedArchitectures.bIsMultiArch)
{
throw new BuildException("Platforms that support multiple platforms are expected to override ActiveArchitectures in a platform-specifiec UnraelArchitectureConfig subclass");
}
return AllSupportedArchitectures;
}
/// <summary>
/// Like ProjectSupportedArchitectures, except when building in distribution mode. Defaults to ActiveArchitectures
/// </summary>
/// <param name="ProjectFile"></param>
/// <param name="TargetName"></param>
/// <returns></returns>
public virtual UnrealArchitectures DistributionArchitectures(FileReference? ProjectFile, string? TargetName)
{
return ActiveArchitectures(ProjectFile, TargetName);
}
/// <summary>
/// Returns the set all architectures potentially supported by this project. Can be used by project file gnenerators to restrict IDE architecture options
/// Defaults to AllSupportedArchitectures
/// </summary>
/// <param name="ProjectFile"></param>
/// <param name="TargetName"></param>
/// <returns></returns>
public virtual UnrealArchitectures ProjectSupportedArchitectures(FileReference? ProjectFile, string? TargetName)
{
return AllSupportedArchitectures;
}
/// <summary>
/// Returns if architecture name should be used when making intermediate directories, per-architecture filenames, etc
/// It is virtual, so a platform can choose to skip architecture name for one platform, but not another
/// </summary>
/// <returns></returns>
public virtual bool RequiresArchitectureFilenames(UnrealArchitectures Architectures)
{
// @todo: this needs to also have directory vs file (we may need directory names but not filenames in the case of Single-target multi-arch)
return Mode == UnrealArchitectureMode.OneTargetPerArchitecture;
}
/// <summary>
/// Convert user specified architecture strings to what the platform wants
/// </summary>
/// <param name="Architecture"></param>
/// <returns></returns>
public virtual string ConvertToReadableArchitecture(UnrealArch Architecture)
{
return Architecture.ToString();
}
/// <summary>
/// Get name for architecture-specific directories (can be shorter than architecture name itself)
/// </summary>
public virtual string GetFolderNameForArchitecture(UnrealArch Architecture)
{
// by default, use the architecture name
return Architecture.ToString();
}
/// <summary>
/// Get name for architecture-specific directories (can be shorter than architecture name itself)
/// </summary>
public virtual string GetFolderNameForArchitectures(UnrealArchitectures Architectures)
{
// by default, use the architecture names combined with +
return Architectures.GetFolderNameForPlatform(this);
}
/// <summary>
/// Returns the architecture of the currently running OS (only used for desktop platforms, so will throw an exception in the general case)
/// </summary>
/// <returns></returns>
public virtual UnrealArch GetHostArchitecture()
{
if (AllSupportedArchitectures.bIsMultiArch)
{
throw new BuildException($"Asking for Host architecture from {GetType()} which supports multiple architectures, but did not override GetHostArchitecture()");
}
return AllSupportedArchitectures.SingleArchitecture;
}
/// <summary>
/// Simple constructor for platforms with a single architecture
/// </summary>
/// <param name="SingleArchitecture"></param>
public UnrealArchitectureConfig(UnrealArch SingleArchitecture)
{
Mode = UnrealArchitectureMode.SingleArchitecture;
AllSupportedArchitectures = new UnrealArchitectures(SingleArchitecture);
}
/// <summary>
/// Full constructor for platforms that support multiple architectures
/// </summary>
/// <param name="Mode"></param>
/// <param name="SupportedArchitectures"></param>
protected UnrealArchitectureConfig(UnrealArchitectureMode Mode, IEnumerable<UnrealArch> SupportedArchitectures)
{
this.Mode = Mode;
AllSupportedArchitectures = new UnrealArchitectures(SupportedArchitectures);
}
}
abstract class UEBuildPlatform
{
private static Dictionary<UnrealTargetPlatform, UEBuildPlatform> BuildPlatformDictionary = new Dictionary<UnrealTargetPlatform, UEBuildPlatform>();
// a mapping of a group to the platforms in the group (ie, Microsoft contains Win32 and Win64)
static Dictionary<UnrealPlatformGroup, List<UnrealTargetPlatform>> PlatformGroupDictionary = new Dictionary<UnrealPlatformGroup, List<UnrealTargetPlatform>>();
/// <summary>
/// The corresponding target platform enum
/// </summary>
public readonly UnrealTargetPlatform Platform;
/// <summary>
/// The configuration about the architecture(s) this platform supports
/// </summary>
public readonly UnrealArchitectureConfig ArchitectureConfig;
/// <summary>
/// Logger for this platform
/// </summary>
protected readonly ILogger Logger;
/// <summary>
/// All the platform folder names
/// </summary>
private static string[]? CachedPlatformFolderNames;
/// <summary>
/// Cached copy of the list of folders to include for this platform
/// </summary>
private IReadOnlySet<string>? CachedIncludedFolderNames;
/// <summary>
/// Cached copy of the list of folders to exclude for this platform
/// </summary>
private IReadOnlySet<string>? CachedExcludedFolderNames;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="InPlatform">The enum value for this platform</param>
/// <param name="SDK">The SDK management object for this platform</param>
/// <param name="ArchitectureConfig">THe architecture configuraton for this platform. This is returned by UnrealArchitectureConfig.ForPlatform()</param>
/// <param name="InLogger">Logger for output</param>
public UEBuildPlatform(UnrealTargetPlatform InPlatform, UEBuildPlatformSDK SDK, UnrealArchitectureConfig ArchitectureConfig, ILogger InLogger)
{
Platform = InPlatform;
Logger = InLogger;
this.ArchitectureConfig = ArchitectureConfig;
// check DDPI to see if the platform is enabled on this host platform
string IniPlatformName = ConfigHierarchy.GetIniPlatformName(Platform);
bool bIsEnabled = false;
ConfigDataDrivenPlatformInfo? DDPI = DataDrivenPlatformInfo.GetDataDrivenInfoForPlatform(IniPlatformName);
if (DDPI != null)
{
bIsEnabled = DDPI.bIsEnabled;
}
// set up the SDK if the platform is enabled
UEBuildPlatformSDK.RegisterSDKForPlatform(SDK, Platform.ToString(), bIsEnabled);
if (bIsEnabled)
{
SDK.ManageAndValidateSDK();
}
}
private static string[] UATProjectParams = { "-project=", "-scriptsforproject=" };
private static void InitializePerPlatformSDKs(string[] Args, bool bArgumentsAreForUBT, ILogger Logger)
{
// Before we setup AutoSDK, we check to see if any projects need to override the Main version so that AutoSDK
// will set up an alternate SDK
Dictionary<string, string> PlatformToVersionMap = new();
IEnumerable<FileReference?> ProjectFiles;
if (bArgumentsAreForUBT == false)
{
ProjectFiles = Args
// find arguments that start with one of the hard-coded parameters
.Where(x => UATProjectParams.Any(y => x.StartsWith(y, StringComparison.OrdinalIgnoreCase)))
// treat the part after the = as a path to a uproject, and ask the NativeProjects class to find a .uproject
.Select(x => NativeProjects.FindProjectFile(x.Substring(x.IndexOf('=') + 1), Logger))
// only use existant projects
.Where(x => x != null && FileReference.Exists(x));
}
else
{
CommandLineArguments CommandLine = new(Args);
BuildConfiguration BuildConfiguration = new();
XmlConfig.ApplyTo(BuildConfiguration);
CommandLine.ApplyTo(BuildConfiguration);
// get the project files for all targets - we allow null uproject files which means to use the defaults
// (same as a uproject that has no override SDK versions set)
ProjectFiles = TargetDescriptor.ParseCommandLineForProjects(CommandLine, Logger);
}
UEBuildPlatformSDK.InitializePerProjectSDKVersions(ProjectFiles.OfType<FileReference>());
// clear the cache used for auto-switching to the best manually-installed SDK
UEBuildPlatformSDK.ClearManualSDKEnvVarCache();
}
/// <summary>
/// Finds all the UEBuildPlatformFactory types in this assembly and uses them to register all the available platforms, and uses a UBT commandline to check for per-project SDKs
/// </summary>
/// <param name="bIncludeNonInstalledPlatforms">Whether to register platforms that are not installed</param>
/// <param name="bHostPlatformOnly">Only register the host platform</param>
/// <param name="ArgumentsForPerPlatform">Commandline args to look through for finding uprojects, to look up per-project SDK versions</param>
/// <param name="UBTModeType">The UBT mode (usually Build, but </param>
/// <param name="Logger">Logger for output</param>
internal static void RegisterPlatforms(bool bIncludeNonInstalledPlatforms, bool bHostPlatformOnly, Type UBTModeType, string[] ArgumentsForPerPlatform, ILogger Logger)
{
bool bUseTargetTripleParams = false;
// @todo : add a ToolModeOptions.UseTargetTripleCommandLine or something
if (UBTModeType.Name == "BuildMode")
{
bUseTargetTripleParams = true;
}
RegisterPlatforms(bIncludeNonInstalledPlatforms, bHostPlatformOnly, ArgumentsForPerPlatform, bArgumentsAreForUBT: bUseTargetTripleParams, Logger);
}
/// <summary>
/// Finds all the UEBuildPlatformFactory types in this assembly and uses them to register all the available platforms, and uses a UAT commandline to check for per-project SDKs
/// </summary>
/// <param name="bIncludeNonInstalledPlatforms">Whether to register platforms that are not installed</param>
/// <param name="bHostPlatformOnly">Only register the host platform</param>
/// <param name="ArgumentsForPerPlatform">Commandline args to look through for finding uprojects, to look up per-project SDK versions</param>
/// <param name="Logger">Logger for output</param>
internal static void RegisterPlatforms(bool bIncludeNonInstalledPlatforms, bool bHostPlatformOnly, string[] ArgumentsForPerPlatform, ILogger Logger)
{
RegisterPlatforms(bIncludeNonInstalledPlatforms, bHostPlatformOnly, ArgumentsForPerPlatform, bArgumentsAreForUBT: false, Logger);
}
private static void RegisterPlatforms(bool bIncludeNonInstalledPlatforms, bool bHostPlatformOnly, string[] ArgumentsForPerPlatform, bool bArgumentsAreForUBT, ILogger Logger)
{
// Initialize the installed platform info
using (GlobalTracer.Instance.BuildSpan("Initializing InstalledPlatformInfo").StartActive())
{
InstalledPlatformInfo.Initialize();
}
using (GlobalTracer.Instance.BuildSpan("Initializing PerPlatformSDKs").StartActive())
{
InitializePerPlatformSDKs(ArgumentsForPerPlatform, bArgumentsAreForUBT, Logger);
}
// Find and register all tool chains and build platforms that are present
Type[] AllTypes;
using (GlobalTracer.Instance.BuildSpan("Querying types").StartActive())
{
AllTypes = Assembly.GetExecutingAssembly().GetTypes();
}
// register all build platforms first, since they implement SDK-switching logic that can set environment variables
foreach (Type CheckType in AllTypes)
{
if (CheckType.IsClass && !CheckType.IsAbstract)
{
if (CheckType.IsSubclassOf(typeof(UEBuildPlatformFactory)))
{
Logger.LogDebug(" Registering build platform: {Platform}", CheckType.ToString());
using (GlobalTracer.Instance.BuildSpan(CheckType.Name).StartActive())
{
UEBuildPlatformFactory TempInst = (UEBuildPlatformFactory)Activator.CreateInstance(CheckType)!;
if (bHostPlatformOnly && TempInst.TargetPlatform != BuildHostPlatform.Current.Platform)
{
continue;
}
// We need all platforms to be registered when we run -validateplatform command to check SDK status of each
if (bIncludeNonInstalledPlatforms || InstalledPlatformInfo.IsValidPlatform(TempInst.TargetPlatform))
{
TempInst.RegisterBuildPlatforms(Logger);
}
}
}
}
}
}
/// <summary>
/// Gets an array of all platform folder names
/// </summary>
/// <returns>Array of platform folders</returns>
public static string[] GetPlatformFolderNames()
{
if (CachedPlatformFolderNames == null)
{
List<string> PlatformFolderNames = new List<string>();
// Find all the platform folders to exclude from the list of precompiled modules
PlatformFolderNames.AddRange(UnrealTargetPlatform.GetValidPlatformNames());
// Also exclude all the platform groups that this platform is not a part of
PlatformFolderNames.AddRange(UnrealPlatformGroup.GetValidGroupNames());
// Save off the list as an array
CachedPlatformFolderNames = PlatformFolderNames.ToArray();
}
return CachedPlatformFolderNames;
}
/// <summary>
/// Finds a list of folder names to include when building for this platform
/// </summary>
public IReadOnlySet<string> GetIncludedFolderNames()
{
if (CachedIncludedFolderNames == null)
{
HashSet<string> Names = new HashSet<string>(DirectoryReference.Comparer);
Names.Add(Platform.ToString());
foreach (UnrealPlatformGroup Group in UEBuildPlatform.GetPlatformGroups(Platform))
{
Names.Add(Group.ToString());
}
CachedIncludedFolderNames = Names;
}
return CachedIncludedFolderNames;
}
/// <summary>
/// Finds a list of folder names to exclude when building for this platform
/// </summary>
public IReadOnlySet<string> GetExcludedFolderNames()
{
CachedExcludedFolderNames ??= new HashSet<string>(GetPlatformFolderNames().Except(GetIncludedFolderNames()), DirectoryReference.Comparer);
return CachedExcludedFolderNames;
}
/// <summary>
/// Whether the required external SDKs are installed for this platform. Could be either a manual install or an AutoSDK.
/// </summary>
public SDKStatus HasRequiredSDKsInstalled()
{
UEBuildPlatformSDK? SDK = UEBuildPlatform.GetSDK(Platform);
if (SDK == null || !SDK.bIsSdkAllowedOnHost)
{
return SDKStatus.Invalid;
}
return SDK.HasRequiredSDKsInstalled();
}
/// <summary>
/// Whether this platform requires specific Visual Studio version.
/// </summary>
public virtual VCProjectFileFormat GetRequiredVisualStudioVersion()
{
return VCProjectFileFormat.Default;
}
/// <summary>
/// The version required to support Visual Studio
/// </summary>
public virtual Version GetVersionRequiredForVisualStudio(VCProjectFileFormat Format)
{
return new Version();
}
/// <summary>
/// Gets all the registered platforms
/// </summary>
/// <returns>Sequence of registered platforms</returns>
public static IEnumerable<UnrealTargetPlatform> GetRegisteredPlatforms()
{
return BuildPlatformDictionary.Keys;
}
/// <summary>
/// Searches a directory tree for build products to be cleaned.
/// </summary>
/// <param name="BaseDir">The directory to search</param>
/// <param name="NamePrefixes">Target or application names that may appear at the start of the build product name (eg. "UnrealEditor", "ShooterGameEditor")</param>
/// <param name="NameSuffixes">Suffixes which may appear at the end of the build product name</param>
/// <param name="FilesToClean">List to receive a list of files to be cleaned</param>
/// <param name="DirectoriesToClean">List to receive a list of directories to be cleaned</param>
public void FindBuildProductsToClean(DirectoryReference BaseDir, string[] NamePrefixes, string[] NameSuffixes, List<FileReference> FilesToClean, List<DirectoryReference> DirectoriesToClean)
{
foreach (FileReference File in DirectoryReference.EnumerateFiles(BaseDir))
{
string FileName = File.GetFileName();
if (IsDefaultBuildProduct(FileName, NamePrefixes, NameSuffixes) || IsBuildProduct(FileName, NamePrefixes, NameSuffixes))
{
FilesToClean.Add(File);
}
}
foreach (DirectoryReference SubDir in DirectoryReference.EnumerateDirectories(BaseDir))
{
string SubDirName = SubDir.GetDirectoryName();
if (IsBuildProduct(SubDirName, NamePrefixes, NameSuffixes))
{
DirectoriesToClean.Add(SubDir);
}
else
{
FindBuildProductsToClean(SubDir, NamePrefixes, NameSuffixes, FilesToClean, DirectoriesToClean);
}
}
}
/// <summary>
/// Enumerates any additional directories needed to clean this target
/// </summary>
/// <param name="Target">The target to clean</param>
/// <param name="FilesToDelete">Receives a list of files to be removed</param>
/// <param name="DirectoriesToDelete">Receives a list of directories to be removed</param>
public virtual void FindAdditionalBuildProductsToClean(ReadOnlyTargetRules Target, List<FileReference> FilesToDelete, List<DirectoryReference> DirectoriesToDelete)
{
}
/// <summary>
/// Determines if a filename is a default UBT build product
/// </summary>
/// <param name="FileName">The name to check</param>
/// <param name="NamePrefixes">Target or application names that may appear at the start of the build product name (eg. "UnrealEditor", "ShooterGameEditor")</param>
/// <param name="NameSuffixes">Suffixes which may appear at the end of the build product name</param>
/// <returns>True if the substring matches the name of a build product, false otherwise</returns>
public static bool IsDefaultBuildProduct(string FileName, string[] NamePrefixes, string[] NameSuffixes)
{
return UEBuildPlatform.IsBuildProductName(FileName, NamePrefixes, NameSuffixes, ".target")
|| UEBuildPlatform.IsBuildProductName(FileName, NamePrefixes, NameSuffixes, ".modules")
|| UEBuildPlatform.IsBuildProductName(FileName, NamePrefixes, NameSuffixes, ".version");
}
/// <summary>
/// Determines if the given name is a build product for a target.
/// </summary>
/// <param name="FileName">The name to check</param>
/// <param name="NamePrefixes">Target or application names that may appear at the start of the build product name (eg. "UnrealEditor", "ShooterGameEditor")</param>
/// <param name="NameSuffixes">Suffixes which may appear at the end of the build product name</param>
/// <returns>True if the string matches the name of a build product, false otherwise</returns>
public abstract bool IsBuildProduct(string FileName, string[] NamePrefixes, string[] NameSuffixes);
/// <summary>
/// Determines if a string is in the canonical name of a UE build product, with a specific extension (eg. "UnrealEditor-Win64-Debug.exe" or "UnrealEditor-ModuleName-Win64-Debug.dll").
/// </summary>
/// <param name="FileName">The file name to check</param>
/// <param name="NamePrefixes">Target or application names that may appear at the start of the build product name (eg. "UnrealEditor", "ShooterGameEditor")</param>
/// <param name="NameSuffixes">Suffixes which may appear at the end of the build product name</param>
/// <param name="Extension">The extension to check for</param>
/// <returns>True if the string matches the name of a build product, false otherwise</returns>
public static bool IsBuildProductName(string FileName, string[] NamePrefixes, string[] NameSuffixes, string Extension)
{
return IsBuildProductName(FileName, 0, FileName.Length, NamePrefixes, NameSuffixes, Extension);
}
/// <summary>
/// Determines if a substring is in the canonical name of a UE build product, with a specific extension (eg. "UnrealEditor-Win64-Debug.exe" or "UnrealEditor-ModuleName-Win64-Debug.dll").
/// </summary>
/// <param name="FileName">The name to check</param>
/// <param name="Index">Index of the first character to be checked</param>
/// <param name="Count">Number of characters of the substring to check</param>
/// <param name="NamePrefixes">Target or application names that may appear at the start of the build product name (eg. "UnrealEditor", "ShooterGameEditor")</param>
/// <param name="NameSuffixes">Suffixes which may appear at the end of the build product name</param>
/// <param name="Extension">The extension to check for</param>
/// <returns>True if the substring matches the name of a build product, false otherwise</returns>
public static bool IsBuildProductName(string FileName, int Index, int Count, string[] NamePrefixes, string[] NameSuffixes, string Extension)
{
// Check if the extension matches, and forward on to the next IsBuildProductName() overload without it if it does.
if (Count > Extension.Length && String.Compare(FileName, Index + Count - Extension.Length, Extension, 0, Extension.Length, StringComparison.InvariantCultureIgnoreCase) == 0)
{
return IsBuildProductName(FileName, Index, Count - Extension.Length, NamePrefixes, NameSuffixes);
}
return false;
}
/// <summary>
/// Determines if a substring is in the canonical name of a UE build product, excluding extension or other decoration (eg. "UnrealEditor-Win64-Debug" or "UnrealEditor-ModuleName-Win64-Debug").
/// </summary>
/// <param name="FileName">The name to check</param>
/// <param name="Index">Index of the first character to be checked</param>
/// <param name="Count">Number of characters of the substring to check</param>
/// <param name="NamePrefixes">Target or application names that may appear at the start of the build product name (eg. "UnrealEditor", "ShooterGameEditor")</param>
/// <param name="NameSuffixes">Suffixes which may appear at the end of the build product name</param>
/// <returns>True if the substring matches the name of a build product, false otherwise</returns>
public static bool IsBuildProductName(string FileName, int Index, int Count, string[] NamePrefixes, string[] NameSuffixes)
{
foreach (string NamePrefix in NamePrefixes)
{
if (Count >= NamePrefix.Length && String.Compare(FileName, Index, NamePrefix, 0, NamePrefix.Length, StringComparison.InvariantCultureIgnoreCase) == 0)
{
int MinIdx = Index + NamePrefix.Length;
foreach (string NameSuffix in NameSuffixes)
{
int MaxIdx = Index + Count - NameSuffix.Length;
if (MaxIdx >= MinIdx && String.Compare(FileName, MaxIdx, NameSuffix, 0, NameSuffix.Length, StringComparison.InvariantCultureIgnoreCase) == 0)
{
if (MinIdx < MaxIdx && FileName[MinIdx] == '-')
{
MinIdx++;
while (MinIdx < MaxIdx && FileName[MinIdx] != '-' && FileName[MinIdx] != '.')
{
MinIdx++;
}
}
if (MinIdx == MaxIdx)
{
return true;
}
}
}
}
}
return false;
}
public virtual void PostBuildSync(UEBuildTarget Target)
{
}
/// <summary>
/// Get the bundle directory for the shared link environment
/// </summary>
/// <param name="Rules">The target rules</param>
/// <param name="OutputFiles">List of executable output files</param>
/// <returns>Path to the bundle directory</returns>
public virtual DirectoryReference? GetBundleDirectory(ReadOnlyTargetRules Rules, List<FileReference> OutputFiles)
{
return null;
}
/// <summary>
/// Determines whether a given platform is available
/// </summary>
/// <param name="Platform">The platform to check for</param>
/// <param name="bIgnoreSDKCheck">Ignore the sdks presence when checking for platform availablity (many platforms can be cooked as a target platform without requiring sdk)</param>
/// <returns>True if it's available, false otherwise</returns>
public static bool IsPlatformAvailable(UnrealTargetPlatform Platform, bool bIgnoreSDKCheck = false)
{
return BuildPlatformDictionary.ContainsKey(Platform) && (bIgnoreSDKCheck || BuildPlatformDictionary[Platform].HasRequiredSDKsInstalled() == SDKStatus.Valid);
}
/// <summary>
/// Determines whether a given platform is available in the context of a particular Taget
/// </summary>
/// <param name="Platform">The platform to check for</param>
/// <param name="Target">A Target object that may further restrict available platforms</param>
/// <param name="bIgnoreSDKCheck">Ignore the sdks presence when checking for platform availablity (many platforms can be cooked as a target platform without requiring sdk)</param>
/// <returns>True if it's available, false otherwise</returns>
public static bool IsPlatformAvailableForTarget(UnrealTargetPlatform Platform, ReadOnlyTargetRules Target, bool bIgnoreSDKCheck = false)
{
return IsPlatformAvailable(Platform, bIgnoreSDKCheck) && Target.IsPlatformOptedIn(Platform);
}
/// <summary>
/// Register the given platforms UEBuildPlatform instance
/// </summary>
/// <param name="InBuildPlatform"> The UEBuildPlatform instance to use for the InPlatform</param>
/// <param name="Logger">Logger for output</param>
public static void RegisterBuildPlatform(UEBuildPlatform InBuildPlatform, ILogger Logger)
{
Logger.LogDebug(" Registering build platform: {Platform} - buildable: {Buildable}", InBuildPlatform.Platform, InBuildPlatform.HasRequiredSDKsInstalled() == SDKStatus.Valid);
if (BuildPlatformDictionary.ContainsKey(InBuildPlatform.Platform) == true)
{
Logger.LogWarning("RegisterBuildPlatform Warning: Registering build platform {Platform} for {ForPlatform} when it is already set to {CurPlatform}",
InBuildPlatform.ToString(), InBuildPlatform.Platform.ToString(), BuildPlatformDictionary[InBuildPlatform.Platform].ToString());
BuildPlatformDictionary[InBuildPlatform.Platform] = InBuildPlatform;
}
else
{
BuildPlatformDictionary.Add(InBuildPlatform.Platform, InBuildPlatform);
}
}
/// <summary>
/// Assign a platform as a member of the given group
/// </summary>
public static void RegisterPlatformWithGroup(UnrealTargetPlatform InPlatform, UnrealPlatformGroup InGroup)
{
// find or add the list of groups for this platform
List<UnrealTargetPlatform>? Platforms;
if (!PlatformGroupDictionary.TryGetValue(InGroup, out Platforms))
{
Platforms = new List<UnrealTargetPlatform>();
PlatformGroupDictionary.Add(InGroup, Platforms);
}
Platforms.Add(InPlatform);
}
/// <summary>
/// Retrieve the list of platforms in this group (if any)
/// </summary>
public static List<UnrealTargetPlatform> GetPlatformsInGroup(UnrealPlatformGroup InGroup)
{
List<UnrealTargetPlatform>? PlatformList;
if (!PlatformGroupDictionary.TryGetValue(InGroup, out PlatformList))
{
PlatformList = new List<UnrealTargetPlatform>();
}
return PlatformList;
}
/// <summary>
/// Enumerates all the platform groups for a given platform
/// </summary>
/// <param name="Platform">The platform to look for</param>
/// <returns>List of platform groups that this platform is a member of</returns>
public static IEnumerable<UnrealPlatformGroup> GetPlatformGroups(UnrealTargetPlatform Platform)
{
return PlatformGroupDictionary.Where(x => x.Value.Contains(Platform)).Select(x => x.Key);
}
/// <summary>
/// Retrieve the IUEBuildPlatform instance for the given TargetPlatform
/// </summary>
/// <param name="InPlatform"> The UnrealTargetPlatform being built</param>
/// <returns>UEBuildPlatform The instance of the build platform</returns>
public static UEBuildPlatform GetBuildPlatform(UnrealTargetPlatform InPlatform)
{
UEBuildPlatform? Platform;
if (!TryGetBuildPlatform(InPlatform, out Platform))
{
throw new BuildException("GetBuildPlatform: No BuildPlatform found for {0}", InPlatform.ToString());
}
return Platform;
}
/// <summary>
/// Retrieve the IUEBuildPlatform instance for the given TargetPlatform
/// </summary>
/// <param name="InPlatform"> The UnrealTargetPlatform being built</param>
/// <param name="Platform"></param>
/// <returns>UEBuildPlatform The instance of the build platform</returns>
public static bool TryGetBuildPlatform(UnrealTargetPlatform InPlatform, [NotNullWhen(true)] out UEBuildPlatform? Platform)
{
return BuildPlatformDictionary.TryGetValue(InPlatform, out Platform);
}
/// <summary>
/// Allow all registered build platforms to modify the newly created module
/// passed in for the given platform.
/// This is not required - but allows for hiding details of a particular platform.
/// </summary>
/// <param name="ModuleName">The name of the module</param>
/// <param name="Rules">The module rules</param>
/// <param name="Target">The target being build</param>
public static void PlatformModifyHostModuleRules(string ModuleName, ModuleRules Rules, ReadOnlyTargetRules Target)
{
foreach (KeyValuePair<UnrealTargetPlatform, UEBuildPlatform> PlatformEntry in BuildPlatformDictionary)
{
PlatformEntry.Value.ModifyModuleRulesForOtherPlatform(ModuleName, Rules, Target);
}
}
/// <summary>
/// Returns the delimiter used to separate paths in the PATH environment variable for the platform we are executing on.
/// </summary>
[Obsolete("Replace with System.IO.Path.PathSeparator")]
public static string GetPathVarDelimiter()
{
return Path.PathSeparator.ToString();
}
/// <summary>
/// Gets the platform name that should be used.
/// </summary>
public virtual string GetPlatformName()
{
return Platform.ToString();
}
/// <summary>
/// If this platform can be compiled with XGE
/// </summary>
public virtual bool CanUseXGE()
{
return true;
}
/// <summary>
/// If this platform can be compiled with FASTBuild
/// </summary>
public virtual bool CanUseFASTBuild()
{
return false;
}
/// <summary>
/// If this platform can be compiled with SN-DBS
/// </summary>
public virtual bool CanUseSNDBS()
{
return false;
}
/// <summary>
/// Set all the platform-specific defaults for a new target
/// </summary>
public virtual void ResetTarget(TargetRules Target)
{
}
/// <summary>
/// Validate a target's settings
/// </summary>
public virtual void ValidateTarget(TargetRules Target)
{
if (Target.bMergeModules)
{
ValidateMergedTarget(Target);
}
}
/// <summary>
/// Validate a target's settings for merged modules
/// </summary>
public virtual void ValidateMergedTarget(TargetRules Target)
{
}
/// <summary>
/// Validate a plugin's settings
/// </summary>
public virtual void ValidatePlugin(UEBuildPlugin Plugin, ReadOnlyTargetRules Target)
{
}
/// <summary>
/// Validate a UEBuildModule before it's processed
/// <param name="Module">The UEBuildModule that needs to be validated</param>
/// <param name="Target">Options for the target being built</param>
/// <param name="Logger">The logger for output</param>
/// </summary>
public virtual void ValidateModule(UEBuildModule Module, ReadOnlyTargetRules Target, ILogger Logger)
{
}
/// <summary>
/// Validate a UEBuildModule's include paths before it's processed
/// </summary>
/// <param name="Module">The UEBuildModule that needs to be validated</param>
/// <param name="Target">Options for the target being built</param>
/// <param name="AllModules">Other modules to validate against, if needed</param>
/// <param name="Logger">The logger for output</param>
public virtual bool ValidateModuleIncludePaths(UEBuildModule Module, ReadOnlyTargetRules Target, IEnumerable<UEBuildModule> AllModules, ILogger Logger)
{
CppCompileWarnings ModuleWarningSettings = Module.Rules.CppCompileWarningSettings;
if (ModuleWarningSettings.ModuleIncludePathWarningLevel <= WarningLevel.Off
&& ModuleWarningSettings.ModuleIncludePrivateWarningLevel <= WarningLevel.Off
&& ModuleWarningSettings.ModuleIncludeSubdirectoryWarningLevel <= WarningLevel.Off)
{
return false;
}
bool AnyErrors = false;
void LoggerFunc(string? message, params object?[] args)
{
if (ModuleWarningSettings.ModuleIncludePathWarningLevel == WarningLevel.Warning)
{
Logger.LogWarning($"Warning: {message}", args);
}
else if (ModuleWarningSettings.ModuleIncludePathWarningLevel == WarningLevel.Error)
{
Logger.LogError($"Error: {message}", args);
AnyErrors = true;
}
}
void LoggerFuncPrivate(string? message, params object?[] args)
{
if (ModuleWarningSettings.ModuleIncludePrivateWarningLevel == WarningLevel.Warning)
{
Logger.LogWarning($"Warning: {message}", args);
}
else if (ModuleWarningSettings.ModuleIncludePrivateWarningLevel == WarningLevel.Error)
{
Logger.LogError($"Error: {message}", args);
AnyErrors = true;
}
}
void LoggerFuncSubDir(string? message, params object?[] args)
{
if (ModuleWarningSettings.ModuleIncludeSubdirectoryWarningLevel == WarningLevel.Warning)
{
Logger.LogWarning($"Warning: {message}", args);
}
else if (ModuleWarningSettings.ModuleIncludeSubdirectoryWarningLevel == WarningLevel.Error)
{
Logger.LogError($"Error: {message}", args);
AnyErrors = true;
}
}
IOrderedEnumerable<DirectoryReference> PublicIncludePaths = Module.Rules.PublicIncludePaths.Select(x => DirectoryReference.FromString(x)!).OrderBy(x => x.FullName);
IOrderedEnumerable<DirectoryReference> PrivateIncludePaths = Module.Rules.PrivateIncludePaths.Select(x => DirectoryReference.FromString(x)!).OrderBy(x => x.FullName);
IOrderedEnumerable<DirectoryReference> InternalIncludePaths = Module.Rules.InternalIncludePaths.Select(x => DirectoryReference.FromString(x)!).OrderBy(x => x.FullName);
IOrderedEnumerable<DirectoryReference> PublicSystemIncludePaths = Module.Rules.PublicSystemIncludePaths.Select(x => DirectoryReference.FromString(x)!).OrderBy(x => x.FullName);
IOrderedEnumerable<UEBuildModule> OtherModules = AllModules.Where(x => x != Module).OrderBy(x => x.Name);
if (Module is UEBuildModuleExternal)
{
foreach (DirectoryReference Path in PublicIncludePaths)
{
LoggerFunc("External module '{Name}' is adding '{Path}' to PublicIncludePaths. This path should be added to PublicSystemIncludePaths.", Module.Name, Path.MakeRelativeTo(Module.ModuleDirectory));
}
foreach (DirectoryReference Path in PublicSystemIncludePaths.Where(x => !x.IsUnderDirectory(Module.ModuleDirectory)))
{
UEBuildModule? OtherModule = OtherModules.FirstOrDefault(x => Path.IsUnderDirectory(x.ModuleDirectory));
if (OtherModule is UEBuildModuleExternal)
{
LoggerFunc("External module '{Name}' is adding '{Path}' from external module '{OtherModule}' to PublicSystemIncludePaths. Did you intend to add a public reference?", Module.Name, Path, OtherModule.Name);
}
else if (OtherModule is UEBuildModuleCPP)
{
LoggerFunc("External module '{Name}' is adding '{Path}' from module '{OtherModule}' to PublicSystemIncludePaths. This is not allowed.", Module.Name, Path, OtherModule.Name);
}
}
foreach (DirectoryReference Path in PrivateIncludePaths)
{
LoggerFunc("External module '{Name}' is adding '{Path}' to PrivateIncludePaths. This path is unused.", Module.Name, Path);
}
foreach (DirectoryReference Path in InternalIncludePaths)
{
LoggerFunc("External module '{Name}' is adding '{Path}' to InternalIncludePaths. This path is unused.", Module.Name, Path);
}
}
else if (Module is UEBuildModuleCPP)
{
foreach (DirectoryReference Path in PublicIncludePaths)
{
if (Path.IsUnderDirectory(Module.ModuleDirectory))
{
if (Path == Module.ModuleDirectory)
{
LoggerFunc("Module '{Name}' is adding root directory to PublicIncludePaths. This is not allowed.", Module.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Private"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Internal")))
{
LoggerFuncPrivate("Module '{Name}' is adding subdirectory '{Path}' to PublicIncludePaths. This is not allowed.", Module.Name, Path.MakeRelativeTo(Module.ModuleDirectory));
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Public"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Classes")))
{
LoggerFuncSubDir("Module '{Name}' is adding subdirectory '{Path}' to PublicIncludePaths. This is not necessary.", Module.Name, Path.MakeRelativeTo(Module.ModuleDirectory));
}
}
UEBuildModule? OtherModule = OtherModules.FirstOrDefault(x => Path.IsUnderDirectory(x.ModuleDirectory));
if (OtherModule is UEBuildModuleExternal)
{
LoggerFunc("Module '{Name}' is adding '{Path}' from external module '{OtherModule}' to PublicIncludePaths. Did you intend to add a public reference?", Module.Name, Path, OtherModule.Name);
}
else if (OtherModule is UEBuildModuleCPP)
{
if (Path == OtherModule.ModuleDirectory)
{
LoggerFuncPrivate("Module '{Name}' is adding root directory from '{OtherModule}' to PublicIncludePaths. This is not allowed.", Module.Name, OtherModule.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Private"))
| Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Internal")))
{
LoggerFuncPrivate("Module '{Name}' is adding '{Path}' from module '{OtherModule}' to PublicIncludePaths. This is not allowed.", Module.Name, Path, OtherModule.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Public"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Classes")))
{
LoggerFunc("Module '{Name}' is adding '{Path}' from module '{OtherModule}' to PublicIncludePaths. Did you intend to add a public reference?", Module.Name, Path, OtherModule.Name);
}
}
}
foreach (DirectoryReference Path in PrivateIncludePaths)
{
if (Path.IsUnderDirectory(Module.ModuleDirectory))
{
if (Path == Module.ModuleDirectory)
{
LoggerFunc("Module '{Name}' is adding root directory to PrivateIncludePaths. This is not recommended.", Module.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Private"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Internal"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Public"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Classes")))
{
LoggerFuncSubDir("Module '{Name}' is adding subdirectory '{Path}' to PrivateIncludePaths. This is not necessary.", Module.Name, Path.MakeRelativeTo(Module.ModuleDirectory));
}
}
UEBuildModule? OtherModule = OtherModules.FirstOrDefault(x => Path.IsUnderDirectory(x.ModuleDirectory));
if (OtherModule is UEBuildModuleExternal)
{
LoggerFunc("Module '{Name}' is adding '{Path}' from external module '{OtherModule}' to PrivateIncludePaths. Did you intend to add a private reference?", Module.Name, Path, OtherModule.Name);
}
else if (OtherModule is UEBuildModuleCPP)
{
if (Path == OtherModule.ModuleDirectory)
{
LoggerFuncPrivate("Module '{Name}' is adding root directory from '{OtherModule}' to PrivateIncludePaths. This is not allowed.", Module.Name, OtherModule.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Private"))
| Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Internal")))
{
LoggerFuncPrivate("Module '{Name}' is adding '{Path}' from module '{OtherModule}' to PrivateIncludePaths. This is not allowed.", Module.Name, Path, OtherModule.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Public"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Classes")))
{
LoggerFunc("Module '{Name}' is adding '{Path}' from module '{OtherModule}' to PrivateIncludePaths. Did you intend to add a private reference?", Module.Name, Path, OtherModule.Name);
}
}
}
foreach (DirectoryReference Path in InternalIncludePaths)
{
if (Path.IsUnderDirectory(Module.ModuleDirectory))
{
if (Path == Module.ModuleDirectory)
{
LoggerFunc("Module '{Name}' is adding root directory to InternalIncludePaths. This is not allowed.", Module.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Private"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Internal")))
{
LoggerFunc("Module '{Name}' is adding subdirectory '{Path}' to InternalIncludePaths. This is not allowed.", Module.Name, Path.MakeRelativeTo(Module.ModuleDirectory));
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Public"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(Module.ModuleDirectory, "Classes")))
{
LoggerFuncSubDir("Module '{Name}' is adding subdirectory '{Path}' to InternalIncludePaths. This is not necessary.", Module.Name, Path.MakeRelativeTo(Module.ModuleDirectory));
}
}
UEBuildModule? OtherModule = OtherModules.FirstOrDefault(x => Path.IsUnderDirectory(x.ModuleDirectory));
if (OtherModule is UEBuildModuleExternal)
{
LoggerFunc("Module '{Name}' is adding '{Path}' from external module '{OtherModule}' to InternalIncludePaths. Did you intend to add a public reference?", Module.Name, Path, OtherModule.Name);
}
else if (OtherModule is UEBuildModuleCPP)
{
if (Path == OtherModule.ModuleDirectory)
{
LoggerFunc("Module '{Name}' is adding root directory from '{OtherModule}' to InternalIncludePaths. This is not allowed.", Module.Name, OtherModule.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Private"))
| Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Internal")))
{
LoggerFunc("Module '{Name}' is adding '{Path}' from module '{OtherModule}' to InternalIncludePaths. This is not allowed.", Module.Name, Path, OtherModule.Name);
}
else if (Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Public"))
|| Path.IsUnderDirectory(DirectoryReference.Combine(OtherModule.ModuleDirectory, "Classes")))
{
LoggerFunc("Module '{Name}' is adding '{Path}' from module '{OtherModule}' to InternalIncludePaths. Did you intend to add a public reference?", Module.Name, Path, OtherModule.Name);
}
}
}
}
return AnyErrors;
}
/// <summary>
/// Return whether the given platform requires a monolithic build
/// </summary>
/// <param name="InPlatform">The platform of interest</param>
/// <param name="InConfiguration">The configuration of interest</param>
/// <returns></returns>
public static bool PlatformRequiresMonolithicBuilds(UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration)
{
// Some platforms require monolithic builds...
UEBuildPlatform? BuildPlatform;
if (TryGetBuildPlatform(InPlatform, out BuildPlatform))
{
return BuildPlatform.ShouldCompileMonolithicBinary(InPlatform);
}
// We assume it does not
return false;
}
/// <summary>
/// Get the extension to use for the given binary type
/// </summary>
/// <param name="InBinaryType"> The binary type being built</param>
/// <returns>string The binary extension (i.e. 'exe' or 'dll')</returns>
public virtual string GetBinaryExtension(UEBuildBinaryType InBinaryType)
{
throw new BuildException("GetBinaryExtensiton for {0} not handled in {1}", InBinaryType.ToString(), ToString());
}
/// <summary>
/// Get the extensions to use for debug info for the given binary type
/// </summary>
/// <param name="InTarget">Options for the target being built</param>
/// <param name="InBinaryType"> The binary type being built</param>
/// <returns>string[] The debug info extensions (i.e. 'pdb')</returns>
public virtual string[] GetDebugInfoExtensions(ReadOnlyTargetRules InTarget, UEBuildBinaryType InBinaryType)
{
throw new BuildException("GetDebugInfoExtensions for {0} not handled in {1}", InBinaryType.ToString(), ToString());
}
/// <summary>
/// Whether this platform should build a monolithic binary
/// </summary>
public virtual bool ShouldCompileMonolithicBinary(UnrealTargetPlatform InPlatform)
{
return false;
}
/// <summary>
/// Modify the rules for a newly created module, where the target is a different host platform.
/// This is not required - but allows for hiding details of a particular platform.
/// </summary>
/// <param name="ModuleName">The name of the module</param>
/// <param name="Rules">The module rules</param>
/// <param name="Target">The target being build</param>
public virtual void ModifyModuleRulesForOtherPlatform(string ModuleName, ModuleRules Rules, ReadOnlyTargetRules Target)
{
}
/// <summary>
/// For platforms that need to output multiple files per binary (ie Android "fat" binaries)
/// this will emit multiple paths. By default, it simply makes an array from the input
/// </summary>
public virtual List<FileReference> FinalizeBinaryPaths(FileReference BinaryName, FileReference? ProjectFile, ReadOnlyTargetRules Target)
{
List<FileReference> TempList = new List<FileReference>() { BinaryName };
return TempList;
}
/// <summary>
/// Return all valid configurations for this platform
/// Typically, this is always Debug, Development, and Shipping - but Test is a likely future addition for some platforms
/// </summary>
public virtual List<UnrealTargetConfiguration> GetConfigurations(UnrealTargetPlatform InUnrealTargetPlatform, bool bIncludeDebug)
{
List<UnrealTargetConfiguration> Configurations = new List<UnrealTargetConfiguration>()
{
UnrealTargetConfiguration.Development,
};
if (bIncludeDebug)
{
Configurations.Insert(0, UnrealTargetConfiguration.Debug);
}
return Configurations;
}
protected static bool DoProjectSettingsMatchDefault(UnrealTargetPlatform Platform, DirectoryReference ProjectDirectoryName, string Section, string[]? BoolKeys, string[]? IntKeys, string[]? StringKeys, ILogger Logger)
{
ConfigHierarchy ProjIni = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, ProjectDirectoryName, Platform);
ConfigHierarchy DefaultIni = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, (DirectoryReference?)null, Platform);
// look at all bool values
if (BoolKeys != null)
{
foreach (string Key in BoolKeys)
{
bool Default = false, Project = false;
DefaultIni.GetBool(Section, Key, out Default);
ProjIni.GetBool(Section, Key, out Project);
if (Default != Project)
{
Log.TraceInformationOnce("{0} is not set to default. (Base: {1} vs. {2}: {3})", Key, Default, Path.GetFileName(ProjectDirectoryName.FullName), Project);
return false;
}
}
}
// look at all int values
if (IntKeys != null)
{
foreach (string Key in IntKeys)
{
int Default = 0, Project = 0;
DefaultIni.GetInt32(Section, Key, out Default);
ProjIni.GetInt32(Section, Key, out Project);
if (Default != Project)
{
Log.TraceInformationOnce("{0} is not set to default. (Base: {1} vs. {2}: {3})", Key, Default, Path.GetFileName(ProjectDirectoryName.FullName), Project);
return false;
}
}
}
// look for all string values
if (StringKeys != null)
{
foreach (string Key in StringKeys)
{
string? Default = "", Project = "";
DefaultIni.GetString(Section, Key, out Default);
ProjIni.GetString(Section, Key, out Project);
if (Default != Project)
{
Log.TraceInformationOnce("{0} is not set to default. (Base: {1} vs. {2}: {3})", Key, Default, Path.GetFileName(ProjectDirectoryName.FullName), Project);
return false;
}
}
}
// if we get here, we match all important settings
return true;
}
/// <summary>
/// Check for the default configuration
/// return true if the project uses the default build config
/// </summary>
public virtual bool HasDefaultBuildConfig(UnrealTargetPlatform Platform, DirectoryReference ProjectDirectoryName)
{
string[] BoolKeys = new string[] {
"bCompileApex", "bCompileICU",
"bCompileRecast", "bCompileSpeedTree",
"bCompileWithPluginSupport", "bCompilePhysXVehicle", "bCompileFreeType",
"bCompileForSize", "bCompileCEF3", "bCompileCustomSQLitePlatform"
};
return DoProjectSettingsMatchDefault(Platform, ProjectDirectoryName, "/Script/BuildSettings.BuildSettings",
BoolKeys, null, null, Logger);
}
/// <summary>
/// Check for whether we require a build for platform reasons
/// return true if the project requires a build
/// </summary>
public virtual bool RequiresBuild(UnrealTargetPlatform Platform, DirectoryReference ProjectDirectoryName)
{
return false;
}
/// <summary>
/// Get a list of extra modules the platform requires.
/// This is to allow undisclosed platforms to add modules they need without exposing information about the platform.
/// </summary>
/// <param name="Target">The target being build</param>
/// <param name="ExtraModuleNames">List of extra modules the platform needs to add to the target</param>
public virtual void AddExtraModules(ReadOnlyTargetRules Target, List<string> ExtraModuleNames)
{
}
/// <summary>
/// Modify the rules for a newly created module, in a target that's being built for this platform.
/// This is not required - but allows for hiding details of a particular platform.
/// </summary>
/// <param name="ModuleName">The name of the module</param>
/// <param name="Rules">The module rules</param>
/// <param name="Target">The target being build</param>
public virtual void ModifyModuleRulesForActivePlatform(string ModuleName, ModuleRules Rules, ReadOnlyTargetRules Target)
{
}
/// <summary>
/// Setup the target environment for building
/// </summary>
/// <param name="Target">Settings for the target being compiled</param>
/// <param name="CompileEnvironment">The compile environment for this target</param>
/// <param name="LinkEnvironment">The link environment for this target</param>
public abstract void SetUpEnvironment(ReadOnlyTargetRules Target, CppCompileEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment);
/// <summary>
/// Setup the configuration environment for building
/// </summary>
/// <param name="Target">The target being built</param>
/// <param name="GlobalCompileEnvironment">The global compile environment</param>
/// <param name="GlobalLinkEnvironment">The global link environment</param>
public virtual void SetUpConfigurationEnvironment(ReadOnlyTargetRules Target, CppCompileEnvironment GlobalCompileEnvironment, LinkEnvironment GlobalLinkEnvironment)
{
if (GlobalCompileEnvironment.bUseDebugCRT)
{
GlobalCompileEnvironment.Definitions.Add("_DEBUG=1"); // the engine doesn't use this, but lots of 3rd party stuff does
}
else
{
GlobalCompileEnvironment.Definitions.Add("NDEBUG=1"); // the engine doesn't use this, but lots of 3rd party stuff does
}
switch (Target.Configuration)
{
default:
case UnrealTargetConfiguration.Debug:
GlobalCompileEnvironment.Definitions.Add("UE_BUILD_DEBUG=1");
break;
case UnrealTargetConfiguration.DebugGame:
// Individual game modules can be switched to be compiled in debug as necessary. By default, everything is compiled in development.
case UnrealTargetConfiguration.Development:
GlobalCompileEnvironment.Definitions.Add("UE_BUILD_DEVELOPMENT=1");
break;
case UnrealTargetConfiguration.Shipping:
GlobalCompileEnvironment.Definitions.Add("UE_BUILD_SHIPPING=1");
break;
case UnrealTargetConfiguration.Test:
GlobalCompileEnvironment.Definitions.Add("UE_BUILD_TEST=1");
break;
}
// Create debug info based on the heuristics specified by the user.
GlobalCompileEnvironment.bCreateDebugInfo =
Target.DebugInfo != DebugInfoMode.None && ShouldCreateDebugInfo(Target);
GlobalLinkEnvironment.bCreateDebugInfo = GlobalCompileEnvironment.bCreateDebugInfo;
}
/// <summary>
/// Allows the platform to return various build metadata that is not tracked by other means. If the returned string changes, the makefile will be invalidated.
/// </summary>
/// <param name="ProjectFile">The project file being built</param>
/// <returns>String describing the current build metadata</returns>
public string GetExternalBuildMetadata(FileReference? ProjectFile)
{
StringBuilder Result = new StringBuilder();
GetExternalBuildMetadata(ProjectFile, Result);
return Result.ToString();
}
/// <summary>
/// Allows the platform to return various build metadata that is not tracked by other means. If the returned string changes, the makefile will be invalidated.
/// </summary>
/// <param name="ProjectFile">The project file being built</param>
/// <param name="Metadata">String builder to contain build metadata</param>
public virtual void GetExternalBuildMetadata(FileReference? ProjectFile, StringBuilder Metadata)
{
}
/// <summary>
/// Allows the platform to modify the binary link environment before the binary is built
/// </summary>
/// <param name="BinaryLinkEnvironment">The binary link environment being created</param>
/// <param name="BinaryCompileEnvironment">The binary compile environment being used</param>
/// <param name="Target">The target rules in use</param>
/// <param name="ToolChain">The toolchain being used</param>
/// <param name="Graph">Action graph that is used to build the binary</param>
public virtual void ModifyBinaryLinkEnvironment(LinkEnvironment BinaryLinkEnvironment, CppCompileEnvironment BinaryCompileEnvironment, ReadOnlyTargetRules Target, UEToolChain ToolChain, IActionGraphBuilder Graph)
{
}
/// <summary>
/// Indicates whether this platform requires a .loadorder file to be generated for the build.
/// .loadorder files contain a list of dynamic modules and the exact order in which they should be loaded
/// to ensure that all dependencies are satisfied i.e. we don't attempt to load a module without loading
/// all its dependencies first.
/// As such, this file is only needed in modular builds on some platforms (depending on the way they implement dynamic modules such as DLLs).
/// </summary>
/// <param name="Target">The target rules in use</param>
/// <returns>True if .loadorder file should be generated</returns>
public virtual bool RequiresLoadOrderManifest(ReadOnlyTargetRules Target)
{
return false;
}
/// <summary>
/// Checks if platform is part of a given platform group
/// </summary>
/// <param name="Platform">The platform to check</param>
/// <param name="PlatformGroup">The platform group to check</param>
/// <returns>True if platform is part of a platform group</returns>
internal static bool IsPlatformInGroup(UnrealTargetPlatform Platform, UnrealPlatformGroup PlatformGroup)
{
List<UnrealTargetPlatform>? Platforms = UEBuildPlatform.GetPlatformsInGroup(PlatformGroup);
if (Platforms != null)
{
return Platforms.Contains(Platform);
}
else
{
return false;
}
}
/// <summary>
/// Gets the SDK object that was passed in to the constructor
/// </summary>
/// <returns>The SDK object</returns>
public UEBuildPlatformSDK? GetSDK()
{
return UEBuildPlatformSDK.GetSDKForPlatform(Platform.ToString());
}
/// <summary>
/// Gets the SDK object that was passed in to the constructor to the UEBuildPlatform constructor for this platform
/// </summary>
/// <returns>The SDK object</returns>
public static UEBuildPlatformSDK? GetSDK(UnrealTargetPlatform Platform)
{
return UEBuildPlatformSDK.GetSDKForPlatform(Platform.ToString());
}
/// <summary>
/// Whether this platform should create debug information or not
/// </summary>
/// <param name="Target">The target being built</param>
/// <returns>bool true if debug info should be generated, false if not</returns>
public abstract bool ShouldCreateDebugInfo(ReadOnlyTargetRules Target);
/// <summary>
/// Creates a toolchain instance for this platform. There should be a single toolchain instance per-target, as their may be
/// state data and configuration cached between calls.
/// </summary>
/// <param name="Target">The target being built</param>
/// <returns>New toolchain instance.</returns>
public abstract UEToolChain CreateToolChain(ReadOnlyTargetRules Target);
/// <summary>
/// Deploys the given target
/// </summary>
/// <param name="Receipt">Receipt for the target being deployed</param>
public abstract void Deploy(TargetReceipt Receipt);
}
}