You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
========================== MAJOR FEATURES + CHANGES ========================== Change 2864843 on 2016/02/12 by Ben.Marsh Add individual 'status', 'outcome', and 'error_code' fields to parsed jobsteps. Should fix grid view not being able to display 'pending' icons. Change 2865161 on 2016/02/12 by Ben.Marsh Stop storing a reference to UEBuildTarget from UEBuildModule. It creates an awkward cyclic data dependency, and makes it easy for people to write lazy code that just reaches into the internal state of the build. Change 2865643 on 2016/02/12 by Ben.Marsh Rename UEBuildModuleType to UHTModuleType, and move implementation into ExternalExecution. Change 2874408 on 2016/02/19 by Ben.Marsh Automatically sort nodes in the dashboard grid view by a weight derived from the node's order in the build graph, summed across all the jobs in which it was present. Change 2879572 on 2016/02/24 by Ben.Marsh Allow spoofing a Git merge from a given commit, using a changelist description containing the tag "git merge <branch> <changelist>", where <branch> is the name of a branch on Git (eg. master, 4.11, etc..), and <changelist> is the changelist being merged in. Change 2883216 on 2016/02/26 by Ben.Marsh Prevent Jira tickets being incorrectly updated with 'Main CL' fields which are after the 'Fix CL' fields. Change 2883755 on 2016/02/26 by Ben.Marsh Fix solution files having a Shipping configuration, even when -NoShippingConfigs is passed on the command line. Change 2886223 on 2016/02/29 by Ben.Marsh Ignore SignTool errors - we can recover from them. Change 2887414 on 2016/03/01 by Ben.Marsh Dump all the *.crash files produced while running commandlets, to make it easier to diagnose build system crashes cooking on Mac. Change 2888235 on 2016/03/01 by Ben.Marsh Add overloads for methods in FileFilter which take FileReference and DirectoryReference objects. Change 2889602 on 2016/03/02 by Ben.Marsh Treat shaders as code in UGS. Don't sync them as part of content-only syncs, and don't allow syncing past them without updated binaries. Change2889610on 2016/03/02 by Ben.Marsh Fix setting for using incremental builds not being saved. Also hide command to do incremental builds if the 'use incremental builds' option is not checked. Change 2891866 on 2016/03/03 by Matthew.Griffin Removed Rocket specific batch files and made sure installed build won't try to include them Removed last use of RocketGenerateProjectFiles.sh by using UBT directly instead Change2893349on 2016/03/03 by Ben.Marsh Add derived ReplicatedBranch to support mirroring the VR editor branch to GitHub. Change 2894703 on 2016/03/04 by Ben.Marsh Include *.usf when looking for the last code changelist. Also update version to 1.68. Change 2897991 on 2016/03/07 by Ben.Marsh Copy the changelist number to the clipboard when the user presses Ctrl-C. Update version number to 1.69. Change 2898005 on 2016/03/07 by Ben.Marsh Minor changes to support BuildGraph: * UE4Build now has a static function that can update version files. * Adding FileReference/DirectoryReference methods to FileFilter and CommandUtils. * FileFilter treats any pattern containing a slash as implictly starting from the root directory, unless it begins with "...". Change 2898095 on 2016/03/07 by Ben.Marsh UAT - Don't retry builds if we're using local executor; we don't encounter failures due to timeouts. Change 2898248 on 2016/03/07 by Ben.Marsh UBT - Add the standard game include paths back in to plugin modules. Existing game code relies on this. Change 2898615 on 2016/03/08 by Matthew.Griffin Removed last uses of RunningRocket function All seemed to be overly cautious about people using an Installed build to do non standard things, don't see any ill effects in the most common circumstances. Change 2898681 on 2016/03/08 by Matthew.Griffin Removed Automation.RunningRocket function as there are no more uses Changed the majority of comments referencing Rocket mode that are now either about the engine being installed or from the Launcher etc. #lockdown Nick.Penwarden [CL 2898813 by Matthew Griffin in Main branch]
555 lines
15 KiB
C#
555 lines
15 KiB
C#
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using System.Runtime.Serialization;
|
|
|
|
namespace UnrealBuildTool
|
|
{
|
|
/// <summary>
|
|
/// Represents a file on disk that is used as an input or output of a build action.
|
|
/// FileItems are created by calling FileItem.GetItemByFileReference, which creates a single FileItem for each unique file path.
|
|
/// </summary>
|
|
[Serializable]
|
|
public class FileItem : ISerializable
|
|
{
|
|
///
|
|
/// Preparation and Assembly (serialized)
|
|
///
|
|
|
|
/// <summary>
|
|
/// The action that produces the file.
|
|
/// </summary>
|
|
public Action ProducingAction = null;
|
|
|
|
/// <summary>
|
|
/// The file reference
|
|
/// </summary>
|
|
public FileReference Reference;
|
|
|
|
/// <summary>
|
|
/// True if any DLLs produced by this
|
|
/// </summary>
|
|
public bool bNeedsHotReloadNumbersDLLCleanUp = false;
|
|
|
|
/// <summary>
|
|
/// Whether or not this is a remote file, in which case we can't access it directly
|
|
/// </summary>
|
|
public bool bIsRemoteFile = false;
|
|
|
|
/// <summary>
|
|
/// Accessor for the absolute path to the file
|
|
/// </summary>
|
|
public string AbsolutePath
|
|
{
|
|
get { return Reference.FullName; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// For C++ file items, this stores cached information about the include paths needed in order to include header files from these C++ files. This is part of UBT's dependency caching optimizations.
|
|
/// </summary>
|
|
public CPPIncludeInfo CachedCPPIncludeInfo
|
|
{
|
|
get
|
|
{
|
|
return _CachedCPPIncludeInfo;
|
|
}
|
|
set
|
|
{
|
|
if (value != null && _CachedCPPIncludeInfo != null && _CachedCPPIncludeInfo != value)
|
|
{
|
|
// Uh oh. We're clobbering our cached CompileEnvironment for this file with a different CompileEnvironment. This means
|
|
// that the same source file is being compiled into more than one module. (e.g. PCLaunch.rc)
|
|
|
|
// @todo ubtmake: The only expected offender here is PCLaunch.rc and friends, which are injected by UBT into every module when not compiling monolithic.
|
|
// PCLaunch.rc and ModuleVersionResource.rc.inl are "safe" because they do not include any headers that would be affected by include path order.
|
|
// ==> Ideally we would use a different "shared" CompileEnvironment for these injected .rc files, so their include paths would not change
|
|
// ==> OR, we can make an Intermediate copy of the .rc file for each module (easier)
|
|
if (!AbsolutePath.EndsWith("PCLaunch.rc", StringComparison.InvariantCultureIgnoreCase) &&
|
|
!AbsolutePath.EndsWith("ModuleVersionResource.rc.inl", StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
// Let's make sure the include paths are the same
|
|
// @todo ubtmake: We have not seen examples of this actually firing off, so we could probably remove the check for matching includes and simply always make this an error case
|
|
List<string> CachedIncludePathsToSearch = _CachedCPPIncludeInfo.GetIncludesPathsToSearch(this);
|
|
List<string> NewIncludePathsToSearch = value.GetIncludesPathsToSearch(this);
|
|
|
|
bool bIncludesAreDifferent = false;
|
|
if (CachedIncludePathsToSearch.Count != NewIncludePathsToSearch.Count)
|
|
{
|
|
bIncludesAreDifferent = true;
|
|
}
|
|
else
|
|
{
|
|
for (int IncludeIndex = 0; IncludeIndex < CachedIncludePathsToSearch.Count; ++IncludeIndex)
|
|
{
|
|
if (!CachedIncludePathsToSearch[IncludeIndex].Equals(NewIncludePathsToSearch[IncludeIndex], StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
bIncludesAreDifferent = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bIncludesAreDifferent)
|
|
{
|
|
throw new BuildException("File '{0}' was included by multiple modules, but with different include paths", this.Info.FullName);
|
|
}
|
|
}
|
|
}
|
|
_CachedCPPIncludeInfo = value;
|
|
}
|
|
}
|
|
public CPPIncludeInfo _CachedCPPIncludeInfo;
|
|
|
|
|
|
///
|
|
/// Preparation only (not serialized)
|
|
///
|
|
|
|
/// <summary>
|
|
/// PCH header file name as it appears in an #include statement in source code (might include partial, or no relative path.)
|
|
/// This is needed by some compilers to use PCH features.
|
|
/// </summary>
|
|
public string PCHHeaderNameInCode;
|
|
|
|
/// <summary>
|
|
/// The PCH file that this file will use
|
|
/// </summary>
|
|
public FileReference PrecompiledHeaderIncludeFilename;
|
|
|
|
|
|
///
|
|
/// Transients (not serialized)
|
|
///
|
|
|
|
/// <summary>
|
|
/// The information about the file.
|
|
/// </summary>
|
|
public FileInfo Info;
|
|
|
|
/// <summary>
|
|
/// This is true if this item is actually a directory. Consideration for Mac application bundles. Note that Info will be null if true!
|
|
/// </summary>
|
|
public bool IsDirectory;
|
|
|
|
/// <summary>
|
|
/// Relative cost of action associated with producing this file.
|
|
/// </summary>
|
|
public long RelativeCost = 0;
|
|
|
|
/// <summary>
|
|
/// The last write time of the file.
|
|
/// </summary>
|
|
public DateTimeOffset _LastWriteTime;
|
|
public DateTimeOffset LastWriteTime
|
|
{
|
|
get
|
|
{
|
|
if (bIsRemoteFile)
|
|
{
|
|
LookupOutstandingFiles();
|
|
}
|
|
return _LastWriteTime;
|
|
}
|
|
set { _LastWriteTime = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Whether the file exists.
|
|
/// </summary>
|
|
public bool _bExists = false;
|
|
public bool bExists
|
|
{
|
|
get
|
|
{
|
|
if (bIsRemoteFile)
|
|
{
|
|
LookupOutstandingFiles();
|
|
}
|
|
return _bExists;
|
|
}
|
|
set { _bExists = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Size of the file if it exists, otherwise -1
|
|
/// </summary>
|
|
public long _Length = -1;
|
|
public long Length
|
|
{
|
|
get
|
|
{
|
|
if (bIsRemoteFile)
|
|
{
|
|
LookupOutstandingFiles();
|
|
}
|
|
return _Length;
|
|
}
|
|
set { _Length = value; }
|
|
}
|
|
|
|
|
|
///
|
|
/// Statics
|
|
///
|
|
|
|
/// <summary>
|
|
/// Used for performance debugging
|
|
/// </summary>
|
|
public static long TotalFileItemCount = 0;
|
|
public static long MissingFileItemCount = 0;
|
|
|
|
/// <summary>
|
|
/// A case-insensitive dictionary that's used to map each unique file name to a single FileItem object.
|
|
/// </summary>
|
|
static Dictionary<FileReference, FileItem> UniqueSourceFileMap = new Dictionary<FileReference, FileItem>();
|
|
|
|
/// <summary>
|
|
/// A list of remote file items that have been created but haven't needed the remote info yet, so we can gang up many into one request
|
|
/// </summary>
|
|
static List<FileItem> DelayedRemoteLookupFiles = new List<FileItem>();
|
|
|
|
/// <summary>
|
|
/// Clears the FileItem caches.
|
|
/// </summary>
|
|
public static void ClearCaches()
|
|
{
|
|
UniqueSourceFileMap.Clear();
|
|
DelayedRemoteLookupFiles.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resolve any outstanding remote file info lookups
|
|
/// </summary>
|
|
private void LookupOutstandingFiles()
|
|
{
|
|
// for remote files, look up any outstanding files
|
|
if (bIsRemoteFile)
|
|
{
|
|
FileItem[] Files = null;
|
|
lock (DelayedRemoteLookupFiles)
|
|
{
|
|
if (DelayedRemoteLookupFiles.Count > 0)
|
|
{
|
|
// make an array so we can clear the original array, just in case BatchFileInfo does something that uses
|
|
// DelayedRemoteLookupFiles, so we don't deadlock
|
|
Files = DelayedRemoteLookupFiles.ToArray();
|
|
DelayedRemoteLookupFiles.Clear();
|
|
}
|
|
}
|
|
if (Files != null)
|
|
{
|
|
RPCUtilHelper.BatchFileInfo(Files);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <returns>The FileItem that represents the given file path.</returns>
|
|
public static FileItem GetItemByPath(string FilePath)
|
|
{
|
|
return GetItemByFileReference(new FileReference(FilePath));
|
|
}
|
|
|
|
/// <returns>The FileItem that represents the given a full file path.</returns>
|
|
public static FileItem GetItemByFileReference(FileReference Reference)
|
|
{
|
|
FileItem Result = null;
|
|
if (UniqueSourceFileMap.TryGetValue(Reference, out Result))
|
|
{
|
|
return Result;
|
|
}
|
|
else
|
|
{
|
|
return new FileItem(Reference);
|
|
}
|
|
}
|
|
|
|
/// <returns>The remote FileItem that represents the given file path.</returns>
|
|
public static FileItem GetRemoteItemByPath(string AbsoluteRemotePath, UnrealTargetPlatform Platform)
|
|
{
|
|
if (AbsoluteRemotePath.StartsWith("."))
|
|
{
|
|
throw new BuildException("GetRemoteItemByPath must be passed an absolute path, not a relative path '{0}'", AbsoluteRemotePath);
|
|
}
|
|
|
|
FileReference RemoteFileReference = FileReference.MakeRemote(AbsoluteRemotePath);
|
|
|
|
FileItem Result = null;
|
|
if (UniqueSourceFileMap.TryGetValue(RemoteFileReference, out Result))
|
|
{
|
|
return Result;
|
|
}
|
|
else
|
|
{
|
|
return new FileItem(RemoteFileReference, true, Platform);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// If the given file path identifies a file that already exists, returns the FileItem that represents it.
|
|
/// </summary>
|
|
public static FileItem GetExistingItemByPath(string FileName)
|
|
{
|
|
return GetExistingItemByFileReference(new FileReference(FileName));
|
|
}
|
|
|
|
/// <summary>
|
|
/// If the given file path identifies a file that already exists, returns the FileItem that represents it.
|
|
/// </summary>
|
|
public static FileItem GetExistingItemByFileReference(FileReference FileRef)
|
|
{
|
|
FileItem Result = GetItemByFileReference(FileRef);
|
|
if (Result.bExists)
|
|
{
|
|
return Result;
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the appropriate encoding for a string: either ASCII or UTF-8.
|
|
/// </summary>
|
|
/// <param name="Str">The string to test.</param>
|
|
/// <returns>Either System.Text.Encoding.ASCII or System.Text.Encoding.UTF8, depending on whether or not the string contains non-ASCII characters.</returns>
|
|
private static Encoding GetEncodingForString(string Str)
|
|
{
|
|
// If the string length is equivalent to the encoded length, then no non-ASCII characters were present in the string.
|
|
// Don't write BOM as it messes with clang when loading response files.
|
|
return (Encoding.UTF8.GetByteCount(Str) == Str.Length) ? Encoding.ASCII : new UTF8Encoding(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a text file with the given contents. If the contents of the text file aren't changed, it won't write the new contents to
|
|
/// the file to avoid causing an action to be considered outdated.
|
|
/// </summary>
|
|
public static FileItem CreateIntermediateTextFile(FileReference AbsolutePath, string Contents)
|
|
{
|
|
// Create the directory if it doesn't exist.
|
|
Directory.CreateDirectory(Path.GetDirectoryName(AbsolutePath.FullName));
|
|
|
|
// Only write the file if its contents have changed.
|
|
if (!AbsolutePath.Exists() || !String.Equals(Utils.ReadAllText(AbsolutePath.FullName), Contents, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
File.WriteAllText(AbsolutePath.FullName, Contents, GetEncodingForString(Contents));
|
|
}
|
|
|
|
return GetItemByFileReference(AbsolutePath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes the file.
|
|
/// </summary>
|
|
public void Delete()
|
|
{
|
|
Debug.Assert(_bExists);
|
|
Debug.Assert(!bIsRemoteFile);
|
|
|
|
int MaxRetryCount = 3;
|
|
int DeleteTryCount = 0;
|
|
bool bFileDeletedSuccessfully = false;
|
|
do
|
|
{
|
|
// If this isn't the first time through, sleep a little before trying again
|
|
if (DeleteTryCount > 0)
|
|
{
|
|
Thread.Sleep(1000);
|
|
}
|
|
DeleteTryCount++;
|
|
try
|
|
{
|
|
// Delete the destination file if it exists
|
|
FileInfo DeletedFileInfo = new FileInfo(AbsolutePath);
|
|
if (DeletedFileInfo.Exists)
|
|
{
|
|
DeletedFileInfo.IsReadOnly = false;
|
|
DeletedFileInfo.Delete();
|
|
}
|
|
// Success!
|
|
bFileDeletedSuccessfully = true;
|
|
}
|
|
catch (Exception Ex)
|
|
{
|
|
Log.TraceInformation("Failed to delete file '" + AbsolutePath + "'");
|
|
Log.TraceInformation(" Exception: " + Ex.Message);
|
|
if (DeleteTryCount < MaxRetryCount)
|
|
{
|
|
Log.TraceInformation("Attempting to retry...");
|
|
}
|
|
else
|
|
{
|
|
Log.TraceInformation("ERROR: Exhausted all retries!");
|
|
}
|
|
}
|
|
}
|
|
while (!bFileDeletedSuccessfully && (DeleteTryCount < MaxRetryCount));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialization constructor.
|
|
/// </summary>
|
|
protected FileItem(FileReference InFile)
|
|
{
|
|
Reference = InFile;
|
|
|
|
ResetFileInfo();
|
|
|
|
++TotalFileItemCount;
|
|
if (!_bExists)
|
|
{
|
|
++MissingFileItemCount;
|
|
// Log.TraceInformation( "Missing: " + FileAbsolutePath );
|
|
}
|
|
|
|
UniqueSourceFileMap[Reference] = this;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// ISerializable: Constructor called when this object is deserialized
|
|
/// </summary>
|
|
protected FileItem(SerializationInfo SerializationInfo, StreamingContext StreamingContext)
|
|
{
|
|
ProducingAction = (Action)SerializationInfo.GetValue("pa", typeof(Action));
|
|
Reference = (FileReference)SerializationInfo.GetValue("fi", typeof(FileReference));
|
|
bIsRemoteFile = SerializationInfo.GetBoolean("rf");
|
|
bNeedsHotReloadNumbersDLLCleanUp = SerializationInfo.GetBoolean("hr");
|
|
CachedCPPIncludeInfo = (CPPIncludeInfo)SerializationInfo.GetValue("ci", typeof(CPPIncludeInfo));
|
|
|
|
// Go ahead and init normally now
|
|
{
|
|
ResetFileInfo();
|
|
|
|
++TotalFileItemCount;
|
|
if (!_bExists)
|
|
{
|
|
++MissingFileItemCount;
|
|
// Log.TraceInformation( "Missing: " + FileAbsolutePath );
|
|
}
|
|
|
|
if (bIsRemoteFile)
|
|
{
|
|
lock (DelayedRemoteLookupFiles)
|
|
{
|
|
DelayedRemoteLookupFiles.Add(this);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UniqueSourceFileMap[Reference] = this;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// ISerializable: Called when serialized to report additional properties that should be saved
|
|
/// </summary>
|
|
public void GetObjectData(SerializationInfo SerializationInfo, StreamingContext StreamingContext)
|
|
{
|
|
SerializationInfo.AddValue("pa", ProducingAction);
|
|
SerializationInfo.AddValue("fi", Reference);
|
|
SerializationInfo.AddValue("rf", bIsRemoteFile);
|
|
SerializationInfo.AddValue("hr", bNeedsHotReloadNumbersDLLCleanUp);
|
|
SerializationInfo.AddValue("ci", CachedCPPIncludeInfo);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// (Re-)set file information for this FileItem
|
|
/// </summary>
|
|
public void ResetFileInfo()
|
|
{
|
|
if (Directory.Exists(AbsolutePath))
|
|
{
|
|
// path is actually a directory (such as a Mac app bundle)
|
|
_bExists = true;
|
|
LastWriteTime = Directory.GetLastWriteTimeUtc(AbsolutePath);
|
|
IsDirectory = true;
|
|
_Length = 0;
|
|
Info = null;
|
|
}
|
|
else
|
|
{
|
|
Info = new FileInfo(AbsolutePath);
|
|
|
|
_bExists = Info.Exists;
|
|
if (_bExists)
|
|
{
|
|
_LastWriteTime = Info.LastWriteTimeUtc;
|
|
_Length = Info.Length;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset file information on all cached FileItems.
|
|
/// </summary>
|
|
public static void ResetInfos()
|
|
{
|
|
foreach (KeyValuePair<FileReference, FileItem> Item in UniqueSourceFileMap)
|
|
{
|
|
Item.Value.ResetFileInfo();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialization constructor for optionally remote files.
|
|
/// </summary>
|
|
protected FileItem(FileReference InReference, bool InIsRemoteFile, UnrealTargetPlatform Platform)
|
|
{
|
|
bIsRemoteFile = InIsRemoteFile;
|
|
Reference = InReference;
|
|
|
|
// @todo iosmerge: This doesn't handle remote directories (may be needed for compiling Mac from Windows)
|
|
if (bIsRemoteFile)
|
|
{
|
|
if (Platform == UnrealTargetPlatform.IOS || Platform == UnrealTargetPlatform.Mac)
|
|
{
|
|
lock (DelayedRemoteLookupFiles)
|
|
{
|
|
DelayedRemoteLookupFiles.Add(this);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new BuildException("Only IPhone and Mac support remote FileItems");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FileInfo Info = new FileInfo(AbsolutePath);
|
|
|
|
_bExists = Info.Exists;
|
|
if (_bExists)
|
|
{
|
|
_LastWriteTime = Info.LastWriteTimeUtc;
|
|
_Length = Info.Length;
|
|
}
|
|
|
|
++TotalFileItemCount;
|
|
if (!_bExists)
|
|
{
|
|
++MissingFileItemCount;
|
|
// Log.TraceInformation( "Missing: " + FileAbsolutePath );
|
|
}
|
|
}
|
|
|
|
// @todo iosmerge: This was in UE3, why commented out now?
|
|
//UniqueSourceFileMap[AbsolutePathUpperInvariant] = this;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Path.GetFileName(AbsolutePath);
|
|
}
|
|
}
|
|
|
|
}
|