Files
UnrealEngineUWP/Engine/Source/Programs/UnrealBuildTool/System/ExternalExecution.cs
Robert Manuszewski aa11e3bbbf Merging UE4-Pretest @ 2042161 to UE4
Change 1996384 by Andrew Brown:
	322252 - EDITOR: Asset picker displays incorrect text when there are no filter results.
Change 1996385 by Andrew Brown:
	321858 - CRASH: Assertion failed: (Index >= 0) Function: STransformViewportToolBar::GetLocationGridLabel() STextBlock::CacheDesiredSize()
Change 1996977 by Andrew Brown:
	309685 - UE4: Adding an event/renaming an event on an event track in Matinee does not update the MatineeActor node in blueprint
Change 2034873 by Jaroslaw Palczynski:
	More robust VS installation detection.
Change 2039693 by Jaroslaw Palczynski:
	327268 - RocketGDC: POSTLAUNCH: DEV: Make engine more robust against bad Visual Studio environment variables
Change 1978978 by Jaroslaw Surowiec:
	- Removed obsolete AllowEliminatingReferences from the FArchive
Change 2020326 by Maciej Mroz:
	pretest BP K2Node: RemovePinsFromOldPins function moved from K2Node to RemovePinsFromOldPins
Change 2017608 by Maciej Mroz:
	pretest Some changes in SFortMissionEventSelector caused by FPinTypeTreeInfo
Change 2017463 by Maciej Mroz:
	PinTypeSelector can lins unloaded UDStructs
Change 2019979 by Maciej Mroz:
	pretest BP: Crash when performing Diff against Depot with blueprints containing Format Text nodes
Change 2024469 by Maciej Mroz:
	MemberReference variable added to PinType. It's necessary for delegate's signature.
Change 2024049 by Maciej Mroz:
	HasExternalBlueprintDependencies added to UK2Node_DynamicCast
Change 2024586 by Maciej Mroz:
	FillSimpleMemberReference fix
Change 2024472 by Maciej Mroz:
	workaround for delegates signature in pintype removed.
Change 2023997 by Maciej Mroz:
	BP, UDStruc: Class UserDefinedStructEditorData added. It fixes many problems with undo/redo.
Change 2021934 by Maciej Mroz:
	typo in a comment
Change 2020355 by Maciej Mroz:
	Back out changelist 2020342
Change 2022178 by Maciej Mroz:
	CRASH: PRETEST: EDITOR: UDS: Crash when undo then redo new variable in struct that is used by blueprint
Change 2021958 by Maciej Mroz:
	CRASH: PRETEST: EDITOR: UDS: Crash using variable of a type of copied struct in blueprint
Change 1986247 by Maciej Mroz:
	User Defined Structures: circle dependency fixed. Early version.
Change 1985107 by Maciej Mroz:
	UserDefinedStruct cannot have a field of a non-native type
Change 1986278 by Maciej Mroz:
	pretest ensureMsgf in Struct::link
Change 1986250 by Maciej Mroz:
	User Defined Struct: Non native classes are accepted types od values in structures.
Change 1980955 by Maciej Mroz:
	Using AssetPtr and LazyPtr as UFunction parameter (intput or return) is explicitly disallowed.
Change 2041215 by Maciej Mroz:
	ttp331249 BLOCKER: PRETEST: UI: Survive the Storm is missing the Mission HUD.
Change 1984316 by Maciej Mroz:
	New User Defined Structure. WIP - there are still problems with circular dependencies.
Change 2011616 by Maciej Mroz:
	UserDefinedStructures - various problems fixed.
Change 2011609 by Maciej Mroz:
	more robust HasExternalBlueprintDependencies implementation
Change 2016697 by Maciej Mroz:
	pretest BP: UDStruct - default value propagation in cooked build
Change 2016288 by Maciej Mroz:
	pretest BP: UDStruct: Renaming variables wont break links from make/break nodes
Change 1987637 by Maciej Mroz:
	CustomStruct icons placeholders
Change 1987422 by Maciej Mroz:
	Better tooltips for variables in MyBlueprint
Change 1991387 by Maciej Mroz:
	UDStructures fixes:
Change 2029165 by Maciej Mroz:
	BP: better comment for incomatible pins
Change 2030016 by Maciej Mroz:
	8PRETEST: EDITOR: UDS: Defaults values aren't updated in struct type variables in blueprints
Change 2030017 by Maciej Mroz:
	Unused UDStructure code removed (PPF_UseDefaultsForUDStructures)
Change 2028856 by Maciej Mroz:
	BP: Pins with PC_Struct type are compatible only with exactly the same structure. (No derived structures are not handled as compatible).
Change 2026701 by Maciej Mroz:
	k2: odd error on an add item node within a function (see attached image in details)
Change 2028160 by Maciej Mroz:
	PRETEST: EDITOR: UDS: When deleting structures just after creating there is always some references in the memory
Change 2028165 by Maciej Mroz:
	BP: BreakHitResult function has proper icon.
Change 2033340 by Maciej Mroz:
	ttp330786 PRETEST: EDITOR: UDS: Changes of default values aren't apllied to breeak nodes for text type of variables
Change 2034255 by Maciej Mroz:
	EDITOR: UDS: Changes of default values aren't apllied to make nodes for text type of variables ttp#330620
Change 2037682 by Maciej Mroz:
	ttp331309 BLOCKER: PRETEST: CRASH: EDITOR: Crash occurs when performing Diff Against Depot on any Blueprint
Change 2033142 by Maciej Mroz:
	CreateDelegate Node uses internally FMemberReference. Refactor.
Change 2032329 by Maciej Mroz:
	ttp330608 CRASH: PRETEST: EDITOR: UDS: Crash when trying to use struct named 'Color' in blueprint
Change 2032420 by Maciej Mroz:
	ttp330620 PRETEST: EDITOR: UDS: Changes of default values aren't apllied to make nodes for text type of variables
Change 2033139 by Maciej Mroz:
	Functions generated from CustomEvents can be also identified by GUID
Change 2026631 by Maciej Mroz:
	BP. UDStruct: Invalid structs are handled better.
Change 2025344 by Maciej Mroz:
	UDStruct enabled by default
Change 2026672 by Maciej Mroz:
	EDITOR: BP: Can't easily remove 'pass-by-reference' pins on ReturnNodes
Change 2026411 by Maciej Mroz:
	ExposeOnSpawn updated, it supports UDStructs, custom native Structs, and it throws compiler error.
Change 2025342 by Maciej Mroz:
	GenerateBlueprintSkeleton moved from BLueprint::Serialize to RegenerateBlueprintClass, because SkeletonClass compilation requires all external dependencies to be loaded and linked.
Change 2025570 by Steve Robb:
	Moved dependency processing to its own function.
Change 2033235 by Steve Robb:
	String improvements
Change 2035830 by Steve Robb:
	Workaround for FriendsAndChat crash in Fortnite.
Change 2035115 by Steve Robb:
	UBT build time regression fixes.
Change 2034162 by Steve Robb:
	312775: UObject improvement: Ensure that *.generated.inl is included somewhere
Change 2034181 by Steve Robb:
	Removal of any references to .generated.inl
Change 2020165 by Steve Robb:
	BuildPublicAndPrivateUObjectHeaders factored out into its own function.
Change 2020187 by Steve Robb:
	CreateModuleCompileEnvironment function factored out.
Change 2020055 by Steve Robb:
	Refactoring of Unity.cs to remove complex and duplicate iteration.
Change 2020083 by Steve Robb:
	Another use of dictionary utilities.
Change 2031049 by Steve Robb:
	312775: UObject improvement: Ensure that *.generated.inl is included somewhere
Change 2025728 by Steve Robb:
	Refactored the application of a shared PCH file to multiple file into a single ApplySharedPCH function.
Change 2020068 by Steve Robb:
	A couple of helpful utility functions for populating dictionaries.
Change 2032307 by Steve Robb:
	312775: UObject improvement: Ensure that *.generated.inl is included somewhere

[CL 2054495 by Robert Manuszewski in Main branch]
2014-04-23 20:18:55 -04:00

484 lines
19 KiB
C#

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Reflection;
namespace UnrealBuildTool
{
// This enum has to be compatible with the one defined in the
// UE4\Engine\Source\Runtime\Core\Public\Modules\ModuleManager.h
// to keep communication between UHT, UBT and Editor compiling
// processes valid.
public enum ECompilationResult
{
Succeeded = 0,
FailedDueToHeaderChange = 1,
OtherCompilationError = 2
}
/** Information about a module that needs to be passed to UnrealHeaderTool for code generation */
public struct UHTModuleInfo
{
/** Module name */
public string ModuleName;
/** Module base directory */
public string ModuleDirectory;
/** Public UObject headers found in the Classes directory (legacy) */
public List<FileItem> PublicUObjectClassesHeaders;
/** Public headers with UObjects */
public List<FileItem> PublicUObjectHeaders;
/** Private headers with UObjects */
public List<FileItem> PrivateUObjectHeaders;
/** Module PCH absolute path */
public string PCH;
/** Base (i.e. extensionless) path+filename of the .generated files */
public string GeneratedCPPFilenameBase;
public override string ToString()
{
return ModuleName;
}
}
public struct UHTManifest
{
public struct Module
{
public string Name;
public string BaseDirectory;
public string OutputDirectory;
public List<string> ClassesHeaders;
public List<string> PublicHeaders;
public List<string> PrivateHeaders;
public string PCH;
public string GeneratedCPPFilenameBase;
public bool SaveExportedHeaders;
public override string ToString()
{
return Name;
}
}
public UHTManifest(bool InUseRelativePaths, UEBuildTarget Target, string InRootLocalPath, string InRootBuildPath, IEnumerable<UHTModuleInfo> ModuleInfo)
{
UseRelativePaths = InUseRelativePaths;
RootLocalPath = InRootLocalPath;
RootBuildPath = InRootBuildPath;
Modules = ModuleInfo.Select(Info => new Module{
Name = Info.ModuleName,
BaseDirectory = Info.ModuleDirectory,
OutputDirectory = UEBuildModuleCPP.GetGeneratedCodeDirectoryForModule(Target, Info.ModuleDirectory, Info.ModuleName),
ClassesHeaders = Info.PublicUObjectClassesHeaders.Select((Header) => Header.AbsolutePath).ToList(),
PublicHeaders = Info.PublicUObjectHeaders .Select((Header) => Header.AbsolutePath).ToList(),
PrivateHeaders = Info.PrivateUObjectHeaders .Select((Header) => Header.AbsolutePath).ToList(),
PCH = Info.PCH,
GeneratedCPPFilenameBase = Info.GeneratedCPPFilenameBase,
//@todo.Rocket: This assumes Engine/Source is a 'safe' folder name to check for
SaveExportedHeaders = !UnrealBuildTool.RunningRocket() || !Info.ModuleDirectory.Contains("Engine\\Source\\")
}).ToList();
}
public bool UseRelativePaths; // Generate relative paths or absolute paths
public string RootLocalPath; // The engine path on the local machine
public string RootBuildPath; // The engine path on the build machine, if different (e.g. Mac/iOS builds)
public List<Module> Modules;
}
/**
* This handles all running of the UnrealHeaderTool
*/
public class ExternalExecution
{
static ExternalExecution()
{
}
static string GetHeaderToolPath()
{
UnrealTargetPlatform Platform = GetRuntimePlatform();
string ExeExtension = UEBuildPlatform.GetBuildPlatform(Platform).GetBinaryExtension(UEBuildBinaryType.Executable);
string HeaderToolExeName = "UnrealHeaderTool";
string HeaderToolPath = Path.Combine("..", "Binaries", Platform.ToString(), HeaderToolExeName + ExeExtension);
return HeaderToolPath;
}
/** Returns the name of platform UBT is running on */
public static UnrealTargetPlatform GetRuntimePlatform()
{
PlatformID Platform = Environment.OSVersion.Platform;
switch (Platform)
{
case PlatformID.Win32NT:
return UnrealTargetPlatform.Win64;
case PlatformID.Unix:
// Mono returns Unix when running on Mac OSX, so we need some kind of addtional
// check check to detect when we are running on Linux vs MacOSX.
// TODO(sbc): Find a better way to do this. Shelling out to uname would seem
// to make the most sense but I'm not sure there is an elegant way to do that from
// C#.
if (File.Exists("/etc/lsb-release") || File.Exists("/etc/debian_version"))
{
return UnrealTargetPlatform.Linux;
}
return UnrealTargetPlatform.Mac;
default:
throw new BuildException("Unhandled runtime platform " + Platform);
}
}
/// <summary>
/// Gets the timestamp of CoreUObject.generated.cpp file.
/// </summary>
/// <returns>Last write time of CoreUObject.generated.cpp or DateTime.MaxValue if it doesn't exist.</returns>
private static DateTime GetCoreGeneratedTimestamp(UEBuildTarget Target)
{
DateTime Timestamp;
if( UnrealBuildTool.RunningRocket() )
{
// In Rocket, we don't check the timestamps on engine headers. Default to a very old date.
Timestamp = DateTime.MinValue;
}
else
{
var CoreUObjectModule = (UEBuildModuleCPP)Target.GetModuleByName( "CoreUObject" );
string CoreGeneratedFilename = Path.Combine(UEBuildModuleCPP.GetGeneratedCodeDirectoryForModule(Target, CoreUObjectModule.ModuleDirectory, CoreUObjectModule.Name), CoreUObjectModule.Name + ".generated.cpp");
if (File.Exists(CoreGeneratedFilename))
{
Timestamp = new FileInfo(CoreGeneratedFilename).LastWriteTime;
}
else
{
// Doesn't exist, so use a 'newer that everything' date to force rebuild headers.
Timestamp = DateTime.MaxValue;
}
}
return Timestamp;
}
/**
* Checks the class header files and determines if generated UObject code files are out of date in comparison.
* @param UObjectModules Modules that we generate headers for
*
* @return True if the code files are out of date
* */
private static bool AreGeneratedCodeFilesOutOfDate(UEBuildTarget Target, List<UHTModuleInfo> UObjectModules)
{
bool bIsOutOfDate = false;
// Get UnrealHeaderTool timestamp. If it's newer than generated headers, they need to be rebuilt too.
string HeaderToolPath = GetHeaderToolPath();
var HeaderToolTimestamp = DateTime.MaxValue; // If UHT doesn't exist, force regenerate.
if( File.Exists( HeaderToolPath ) )
{
HeaderToolTimestamp = new FileInfo(HeaderToolPath).LastWriteTime;
}
// Get CoreUObject.generated.cpp timestamp. If the source files are older than the CoreUObject generated code, we'll
// need to regenerate code for the module
var CoreGeneratedTimestamp = GetCoreGeneratedTimestamp(Target);
foreach( var Module in UObjectModules )
{
// In Rocket, we skip checking timestamps for modules that don't exist within the project's directory
if (UnrealBuildTool.RunningRocket())
{
// @todo Rocket: This could be done in a better way I'm sure
if (!Utils.IsFileUnderDirectory( Module.ModuleDirectory, UnrealBuildTool.GetUProjectPath() ))
{
// Engine or engine plugin module - Rocket does not regenerate them so don't compare their timestamps
continue;
}
}
// Make sure we have an existing folder for generated code. If not, then we definitely need to generate code!
var GeneratedCodeDirectory = UEBuildModuleCPP.GetGeneratedCodeDirectoryForModule(Target, Module.ModuleDirectory, Module.ModuleName);
var TestDirectory = (FileSystemInfo)new DirectoryInfo(GeneratedCodeDirectory);
if( TestDirectory.Exists )
{
// Grab our special "Timestamp" file that we saved after the last set of headers were generated
string TimestampFile = Path.Combine( GeneratedCodeDirectory, @"Timestamp" );
var SavedTimestampFileInfo = (FileSystemInfo)new FileInfo(TimestampFile);
if (SavedTimestampFileInfo.Exists)
{
// Make sure the last UHT run completed after UnrealHeaderTool.exe was compiled last, and after the CoreUObject headers were touched last.
var SavedTimestamp = SavedTimestampFileInfo.LastWriteTime;
if( SavedTimestamp.CompareTo(HeaderToolTimestamp) > 0 &&
SavedTimestamp.CompareTo(CoreGeneratedTimestamp) > 0 )
{
// Iterate over our UObjects headers and figure out if any of them have changed
var AllUObjectHeaders = new List<FileItem>();
AllUObjectHeaders.AddRange( Module.PublicUObjectClassesHeaders );
AllUObjectHeaders.AddRange( Module.PublicUObjectHeaders );
AllUObjectHeaders.AddRange( Module.PrivateUObjectHeaders );
foreach( var HeaderFile in AllUObjectHeaders )
{
var HeaderFileTimestamp = HeaderFile.Info.LastWriteTime;
// Has the source header changed since we last generated headers successfully?
if( SavedTimestamp.CompareTo( HeaderFileTimestamp ) < 0 )
{
bIsOutOfDate = true;
break;
}
// Also check the timestamp on the directory the source file is in. If the directory timestamp has
// changed, new source files may have been added or deleted. We don't know whether the new/deleted
// files were actually UObject headers, but because we don't know all of the files we processed
// in the previous run, we need to assume our generated code is out of date if the directory timestamp
// is newer.
var HeaderDirectoryTimestamp = new DirectoryInfo( Path.GetDirectoryName( HeaderFile.AbsolutePath ) ).LastWriteTime;
if( SavedTimestamp.CompareTo( HeaderDirectoryTimestamp) < 0 )
{
bIsOutOfDate = true;
break;
}
}
}
else
{
// Generated code is older UnrealHeaderTool.exe or CoreUObject headers. Out of date!
bIsOutOfDate = true;
}
}
else
{
// Timestamp file was missing (possibly deleted/cleaned), so headers are out of date
bIsOutOfDate = true;
}
}
else
{
// Generated code directory is missing entirely!
bIsOutOfDate = true;
}
// If even one module is out of date, we're done! UHT does them all in one fell swoop.;
if( bIsOutOfDate )
{
break;
}
}
return bIsOutOfDate;
}
/** Updates the intermediate include directory timestamps of all the passed in UObject modules */
private static void UpdateDirectoryTimestamps(UEBuildTarget Target, List<UHTModuleInfo> UObjectModules)
{
foreach( var Module in UObjectModules )
{
string GeneratedCodeDirectory = UEBuildModuleCPP.GetGeneratedCodeDirectoryForModule(Target, Module.ModuleDirectory, Module.ModuleName);
var GeneratedCodeDirectoryInfo = new DirectoryInfo( GeneratedCodeDirectory );
try
{
if (GeneratedCodeDirectoryInfo.Exists)
{
if (UnrealBuildTool.RunningRocket())
{
// If it is an Engine folder and we are building a rocket project do NOT update the timestamp!
// @todo Rocket: This contains check is hacky/fragile
string FullGeneratedCodeDirectory = GeneratedCodeDirectoryInfo.FullName;
FullGeneratedCodeDirectory = FullGeneratedCodeDirectory.Replace("\\", "/");
if (FullGeneratedCodeDirectory.Contains("Engine/Intermediate/Build"))
{
continue;
}
// Skip checking timestamps for engine plugin intermediate headers in Rocket
PluginInfo Info = Plugins.GetPluginInfoForModule( Module.ModuleName );
if( Info != null )
{
if( Info.LoadedFrom == PluginInfo.LoadedFromType.Engine )
{
continue;
}
}
}
// Touch the include directory since we have technically 'generated' the headers
// However, the headers might not be touched at all since that would cause the compiler to recompile everything
// We can't alter the directory timestamp directly, because this may throw exceptions when the directory is
// open in visual studio or windows explorer, so instead we create a blank file that will change the timestamp for us
string TimestampFile = GeneratedCodeDirectoryInfo.FullName + Path.DirectorySeparatorChar + @"Timestamp";
if( !GeneratedCodeDirectoryInfo.Exists )
{
GeneratedCodeDirectoryInfo.Create();
}
if(File.Exists(TimestampFile))
{
File.Delete(TimestampFile);
}
using (File.Create(TimestampFile))
{
}
}
}
catch (Exception Exception)
{
throw new BuildException(Exception, "Couldn't touch header directories: " + Exception.Message);
}
}
}
/** Run an external exe (and capture the output), given the exe path and the commandline. */
public static int RunExternalExecutable(string ExePath, string Commandline)
{
var ExeInfo = new ProcessStartInfo(ExePath, Commandline);
ExeInfo.UseShellExecute = false;
ExeInfo.RedirectStandardOutput = true;
using (var GameProcess = Process.Start(ExeInfo))
{
GameProcess.BeginOutputReadLine();
GameProcess.OutputDataReceived += PrintProcessOutputAsync;
GameProcess.WaitForExit();
return GameProcess.ExitCode;
}
}
/** Simple function to pipe output asynchronously */
private static void PrintProcessOutputAsync(object Sender, DataReceivedEventArgs Event)
{
// DataReceivedEventHandler is fired with a null string when the output stream is closed. We don't want to
// print anything for that event.
if( !String.IsNullOrEmpty( Event.Data ) )
{
Log.TraceInformation( Event.Data );
}
}
/**
* Builds and runs the header tool and touches the header directories.
* Performs any early outs if headers need no changes, given the UObject modules, tool path, game name, and configuration
*/
public static bool ExecuteHeaderToolIfNecessary( UEBuildTarget Target, List<UHTModuleInfo> UObjectModules, string ModuleInfoFileName, ref ECompilationResult UHTResult )
{
// We never want to try to execute the header tool when we're already trying to build it!
var bIsBuildingUHT = Target.GetTargetName().Equals( "UnrealHeaderTool", StringComparison.InvariantCultureIgnoreCase );
var BuildPlatform = UEBuildPlatform.GetBuildPlatform(Target.Platform);
var CppPlatform = BuildPlatform.GetCPPTargetPlatform(Target.Platform);
var ToolChain = UEToolChain.GetPlatformToolChain(CppPlatform);
var RootLocalPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath);
var Manifest = new UHTManifest(UnrealBuildTool.BuildingRocket() || UnrealBuildTool.RunningRocket(), Target, RootLocalPath, ToolChain.ConvertPath(RootLocalPath + '\\'), UObjectModules);
// ensure the headers are up to date
if (!bIsBuildingUHT &&
(UEBuildConfiguration.bForceHeaderGeneration == true || AreGeneratedCodeFilesOutOfDate(Target, UObjectModules)))
{
// Always build UnrealHeaderTool if header regeneration is required, unless we're running within a Rocket ecosystem
if (UnrealBuildTool.RunningRocket() == false && UEBuildConfiguration.bDoNotBuildUHT == false)
{
// If it is out of date or not there it will be built.
// If it is there and up to date, it will add 0.8 seconds to the build time.
Log.TraceInformation("Building UnrealHeaderTool...");
var UBTArguments = new StringBuilder();
UBTArguments.Append( "UnrealHeaderTool" );
// Which desktop platform do we need to compile UHT for?
UBTArguments.Append( " " + GetRuntimePlatform().ToString() );
// NOTE: We force Development configuration for UHT so that it runs quickly, even when compiling debug
UBTArguments.Append( " " + UnrealTargetConfiguration.Development.ToString() );
// NOTE: We disable mutex when launching UBT from within UBT to compile UHT
UBTArguments.Append( " -NoMutex" );
if (UnrealBuildTool.CommandLineContains("-noxge"))
{
UBTArguments.Append(" -noxge");
}
if ( RunExternalExecutable( UnrealBuildTool.GetUBTPath(), UBTArguments.ToString() ) != 0 )
return false;
}
var ActualTargetName = String.IsNullOrEmpty( Target.GetTargetName() ) ? "UE4" : Target.GetTargetName();
Log.TraceInformation( "Parsing headers for {0}", ActualTargetName );
string HeaderToolPath = GetHeaderToolPath();
if (!File.Exists(HeaderToolPath))
{
throw new BuildException( "Unable to generate headers because UnrealHeaderTool binary was not found ({0}).", Path.GetFullPath( HeaderToolPath ) );
}
// Disable extensions when serializing to remove the $type fields
Directory.CreateDirectory(Path.GetDirectoryName(ModuleInfoFileName));
System.IO.File.WriteAllText(ModuleInfoFileName, fastJSON.JSON.Instance.ToJSON(Manifest, new fastJSON.JSONParameters{ UseExtensions = false }));
string CmdLine = (UnrealBuildTool.HasUProjectFile()) ? "\"" + UnrealBuildTool.GetUProjectFile() + "\"" : Target.GetTargetName();
CmdLine += " \"" + ModuleInfoFileName + "\" -LogCmds=\"loginit warning, logexit warning, logdatabase error\"";
if (UnrealBuildTool.RunningRocket())
{
CmdLine += " -rocket -installed";
}
if (UEBuildConfiguration.bFailIfGeneratedCodeChanges)
{
CmdLine += " -FailIfGeneratedCodeChanges";
}
Stopwatch s = new Stopwatch();
s.Start();
UHTResult = (ECompilationResult) RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine);
s.Stop();
if (UHTResult != ECompilationResult.Succeeded)
{
Log.TraceInformation("Error: Failed to generate code for {0} - error code: {1}", ActualTargetName, (int) UHTResult);
return false;
}
Log.TraceInformation( "Code generation finished for {0} and took {1}", ActualTargetName, (double)s.ElapsedMilliseconds/1000.0 );
// Now that UHT has successfully finished generating code, we need to update all cached FileItems in case their last write time has changed.
// Otherwise UBT might not detect changes UHT made.
DateTime StartTime = DateTime.UtcNow;
FileItem.ResetInfos();
double ResetDuration = (DateTime.UtcNow - StartTime).TotalSeconds;
Log.TraceVerbose("FileItem.ResetInfos() duration: {0}s", ResetDuration);
}
else
{
Log.TraceVerbose( "Generated code is up to date." );
}
// There will never be generated code if we're building UHT, so this should never be called.
if (!bIsBuildingUHT)
{
// Allow generated code to be sync'd to remote machines if needed. This needs to be done even if UHT did not run because
// generated headers include other generated headers using absolute paths which in case of building remotely are already
// the remote machine absolute paths. Because of that parsing headers will not result in finding all includes properly.
ToolChain.PostCodeGeneration(Target, Manifest);
}
// touch the directories
UpdateDirectoryTimestamps(Target, UObjectModules);
return true;
}
}
}