You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
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 Change2030016by 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 Change2034181by 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]
484 lines
19 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|