public override void PostCodeGeneration(UHTManifest Manifest) { if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac) { // @todo UHT: Temporary workaround for UBT no longer being able to follow includes from generated headers unless // the headers already existed before the build started. We're working on a proper fix. // Make sure all generated headers are synced. If we had to generate code, we need to assume that not all of the // header files existed on disk at the time that UBT scanned include statements looking for prerequisite files. Those // files are created during code generation and must exist on disk by the time this function is called. We'll scan // for generated code files and make sure they are enqueued for copying to the remote machine. foreach (var UObjectModule in Manifest.Modules) { // @todo uht: Ideally would only copy exactly the files emitted by UnrealHeaderTool, rather than scanning directory (could copy stale files; not a big deal though) try { var GeneratedCodeDirectory = Path.GetDirectoryName(UObjectModule.GeneratedCPPFilenameBase); var GeneratedCodeFiles = Directory.GetFiles(GeneratedCodeDirectory, "*", SearchOption.AllDirectories); foreach (var GeneratedCodeFile in GeneratedCodeFiles) { // Skip copying "Timestamp" files (UBT temporary files) if (!Path.GetFileName(GeneratedCodeFile).Equals(@"Timestamp", StringComparison.InvariantCultureIgnoreCase)) { var GeneratedCodeFileItem = FileItem.GetExistingItemByPath(GeneratedCodeFile); QueueFileForBatchUpload(GeneratedCodeFileItem); } } } catch (System.IO.DirectoryNotFoundException) { // Ignore directory not found } // For source files in legacy "Classes" directories, we need to make sure they all get copied over too, since // they may not have been directly included in any C++ source files (only generated headers), and the initial // header scan wouldn't have picked them up if they hadn't been generated yet! try { var SourceFiles = Directory.GetFiles(UObjectModule.BaseDirectory, "*", SearchOption.AllDirectories); foreach (var SourceFile in SourceFiles) { var SourceFileItem = FileItem.GetExistingItemByPath(SourceFile); QueueFileForBatchUpload(SourceFileItem); } } catch (System.IO.DirectoryNotFoundException) { // Ignore directory not found } } } }
/// <summary> /// Called immediately after UnrealHeaderTool is executed to generated code for all UObjects modules. Only is called if UnrealHeaderTool was actually run in this session. /// </summary> /// <param name="Manifest">List of UObject modules we generated code for.</param> public virtual void PostCodeGeneration(UHTManifest Manifest) { }
public override void PostCodeGeneration(UHTManifest Manifest) { IOSToolChain.PostCodeGeneration(Manifest); }
/// <summary> /// 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 /// </summary> public static bool ExecuteHeaderToolIfNecessary(UEToolChain ToolChain, UEBuildTarget Target, CPPEnvironment GlobalCompileEnvironment, List <UHTModuleInfo> UObjectModules, FileReference ModuleInfoFileName, ref ECompilationResult UHTResult) { if (ProgressWriter.bWriteMarkup) { Log.WriteLine(LogEventType.Console, "@progress push 5%"); } using (ProgressWriter Progress = new ProgressWriter("Generating code...", false)) { // 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 RootLocalPath = Path.GetFullPath(ProjectFileGenerator.RootRelativePath); // check if UHT is out of date DateTime HeaderToolTimestamp = DateTime.MaxValue; bool bHaveHeaderTool = !bIsBuildingUHT && GetHeaderToolTimestamp(out HeaderToolTimestamp); // ensure the headers are up to date bool bUHTNeedsToRun = (UEBuildConfiguration.bForceHeaderGeneration == true || !bHaveHeaderTool || AreGeneratedCodeFilesOutOfDate(UObjectModules, HeaderToolTimestamp)); if (bUHTNeedsToRun || UnrealBuildTool.IsGatheringBuild) { // Since code files are definitely out of date, we'll now finish computing information about the UObject modules for UHT. We // want to save this work until we know that UHT actually needs to be run to speed up best-case iteration times. if (UnrealBuildTool.IsGatheringBuild) // In assembler-only mode, PCH info is loaded from our UBTMakefile! { foreach (var UHTModuleInfo in UObjectModules) { // Only cache the PCH name if we don't already have one. When running in 'gather only' mode, this will have already been cached if (string.IsNullOrEmpty(UHTModuleInfo.PCH)) { UHTModuleInfo.PCH = ""; // We need to figure out which PCH header this module is including, so that UHT can inject an include statement for it into any .cpp files it is synthesizing var DependencyModuleCPP = (UEBuildModuleCPP)Target.GetModuleByName(UHTModuleInfo.ModuleName); var ModuleCompileEnvironment = DependencyModuleCPP.CreateModuleCompileEnvironment(GlobalCompileEnvironment); DependencyModuleCPP.CachePCHUsageForModuleSourceFiles(ModuleCompileEnvironment); if (DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile != null) { UHTModuleInfo.PCH = DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile.AbsolutePath; } } } } } // @todo ubtmake: Optimization: Ideally we could avoid having to generate this data in the case where UHT doesn't even need to run! Can't we use the existing copy? (see below use of Manifest) UHTManifest Manifest = new UHTManifest(Target, RootLocalPath, ToolChain.ConvertPath(RootLocalPath + '\\'), UObjectModules); if (!bIsBuildingUHT && bUHTNeedsToRun) { // Always build UnrealHeaderTool if header regeneration is required, unless we're running within a Rocket ecosystem or hot-reloading if (UnrealBuildTool.RunningRocket() == false && UEBuildConfiguration.bDoNotBuildUHT == false && UEBuildConfiguration.bHotReloadFromIDE == false && !(bHaveHeaderTool && !UnrealBuildTool.IsGatheringBuild && UnrealBuildTool.IsAssemblingBuild)) // If running in "assembler only" mode, we assume UHT is already up to date for much faster iteration! { // 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(" " + BuildHostPlatform.Current.Platform.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"); } // Propagate command-line option if (UnrealBuildTool.CommandLineContains("-2015")) { UBTArguments.Append(" -2015"); } if (UnrealBuildTool.CommandLineContains("-2013")) { UBTArguments.Append(" -2013"); } // Add UHT plugins to UBT command line as external plugins if (Target.UnrealHeaderToolPlugins != null && Target.UnrealHeaderToolPlugins.Count > 0) { foreach (PluginInfo Plugin in Target.UnrealHeaderToolPlugins) { UBTArguments.Append(" -PLUGIN \"" + Plugin.File + "\""); } } if (RunExternalExecutable(UnrealBuildTool.GetUBTPath(), UBTArguments.ToString()) != 0) { return(false); } } Progress.Write(1, 3); 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(ModuleInfoFileName.Directory.FullName); System.IO.File.WriteAllText(ModuleInfoFileName.FullName, fastJSON.JSON.Instance.ToJSON(Manifest, new fastJSON.JSONParameters { UseExtensions = false })); string CmdLine = (Target.ProjectFile != null) ? "\"" + Target.ProjectFile.FullName + "\"" : Target.GetTargetName(); CmdLine += " \"" + ModuleInfoFileName + "\" -LogCmds=\"loginit warning, logexit warning, logdatabase error\" -Unattended -WarningsAsErrors"; if (UnrealBuildTool.IsEngineInstalled()) { CmdLine += " -installed"; } if (UEBuildConfiguration.bFailIfGeneratedCodeChanges) { CmdLine += " -FailIfGeneratedCodeChanges"; } if (!bInvalidateUHTMakefile && BuildConfiguration.bUseUHTMakefiles) { CmdLine += " -UseMakefiles"; } if (!UEBuildConfiguration.bCompileAgainstEngine) { CmdLine += " -NoEnginePlugins"; } Log.TraceInformation(" Running UnrealHeaderTool {0}", CmdLine); Stopwatch s = new Stopwatch(); s.Start(); UHTResult = (ECompilationResult)RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine); s.Stop(); if (UHTResult != ECompilationResult.Succeeded) { // On Linux and Mac, the shell will return 128+signal number exit codes if UHT gets a signal (e.g. crashes or is interrupted) if ((BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) && (int)(UHTResult) >= 128 ) { // SIGINT is 2, so 128 + SIGINT is 130 UHTResult = ((int)(UHTResult) == 130) ? ECompilationResult.Canceled : ECompilationResult.CrashOrAssert; } Log.TraceInformation("Error: Failed to generate code for {0} - error code: {2} ({1})", ActualTargetName, (int)UHTResult, UHTResult.ToString()); return(false); } Log.TraceInformation("Reflection code generated for {0} in {1} seconds", ActualTargetName, s.Elapsed.TotalSeconds); if (BuildConfiguration.bPrintPerformanceInfo) { Log.TraceInformation("UnrealHeaderTool 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."); } Progress.Write(2, 3); // 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. // @todo ubtmake: Need to figure out what this does in the assembler case, and whether we need to run it ToolChain.PostCodeGeneration(Manifest); } // touch the directories UpdateDirectoryTimestamps(UObjectModules); Progress.Write(3, 3); } if (ProgressWriter.bWriteMarkup) { Log.WriteLine(LogEventType.Console, "@progress pop"); } return(true); }
/** * 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, CPPEnvironment GlobalCompileEnvironment, List<UHTModuleInfo> UObjectModules, string ModuleInfoFileName, ref ECompilationResult UHTResult ) { if(ProgressWriter.bWriteMarkup) { Log.WriteLine(TraceEventType.Information, "@progress push 5%"); } using (ProgressWriter Progress = new ProgressWriter("Generating code...", false)) { // 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); // check if UHT is out of date DateTime HeaderToolTimestamp = DateTime.MaxValue; bool bHaveHeaderTool = !bIsBuildingUHT && GetHeaderToolTimestamp(out HeaderToolTimestamp); // ensure the headers are up to date bool bUHTNeedsToRun = (UEBuildConfiguration.bForceHeaderGeneration == true || !bHaveHeaderTool || AreGeneratedCodeFilesOutOfDate(UObjectModules, HeaderToolTimestamp)); if( bUHTNeedsToRun || UnrealBuildTool.IsGatheringBuild ) { // Since code files are definitely out of date, we'll now finish computing information about the UObject modules for UHT. We // want to save this work until we know that UHT actually needs to be run to speed up best-case iteration times. if( UnrealBuildTool.IsGatheringBuild ) // In assembler-only mode, PCH info is loaded from our UBTMakefile! { foreach( var UHTModuleInfo in UObjectModules ) { // Only cache the PCH name if we don't already have one. When running in 'gather only' mode, this will have already been cached if( string.IsNullOrEmpty( UHTModuleInfo.PCH ) ) { UHTModuleInfo.PCH = ""; // We need to figure out which PCH header this module is including, so that UHT can inject an include statement for it into any .cpp files it is synthesizing var DependencyModuleCPP = (UEBuildModuleCPP)Target.GetModuleByName( UHTModuleInfo.ModuleName ); var ModuleCompileEnvironment = DependencyModuleCPP.CreateModuleCompileEnvironment(GlobalCompileEnvironment); DependencyModuleCPP.CachePCHUsageForModuleSourceFiles(ModuleCompileEnvironment); if (DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile != null) { UHTModuleInfo.PCH = DependencyModuleCPP.ProcessedDependencies.UniquePCHHeaderFile.AbsolutePath; } } } } } // @todo ubtmake: Optimization: Ideally we could avoid having to generate this data in the case where UHT doesn't even need to run! Can't we use the existing copy? (see below use of Manifest) UHTManifest Manifest = new UHTManifest(Target, RootLocalPath, ToolChain.ConvertPath(RootLocalPath + '\\'), UObjectModules); if( !bIsBuildingUHT && bUHTNeedsToRun ) { // Always build UnrealHeaderTool if header regeneration is required, unless we're running within a Rocket ecosystem or hot-reloading if (UnrealBuildTool.RunningRocket() == false && UEBuildConfiguration.bDoNotBuildUHT == false && UEBuildConfiguration.bHotReloadFromIDE == false && !( bHaveHeaderTool && !UnrealBuildTool.IsGatheringBuild && UnrealBuildTool.IsAssemblingBuild ) ) // If running in "assembler only" mode, we assume UHT is already up to date for much faster iteration! { // 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(" " + BuildHostPlatform.Current.Platform.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; } } Progress.Write(1, 3); 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"; } Log.TraceInformation(" Running UnrealHeaderTool {0}", CmdLine); Stopwatch s = new Stopwatch(); s.Start(); UHTResult = (ECompilationResult) RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine); s.Stop(); if (UHTResult != ECompilationResult.Succeeded) { // On Linux and Mac, the shell will return 128+signal number exit codes if UHT gets a signal (e.g. crashes or is interrupted) if ((BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux || BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac) && (int)(UHTResult) >= 128 ) { // SIGINT is 2, so 128 + SIGINT is 130 UHTResult = ((int)(UHTResult) == 130) ? ECompilationResult.Canceled : ECompilationResult.CrashOrAssert; } Log.TraceInformation("Error: Failed to generate code for {0} - error code: {2} ({1})", ActualTargetName, (int) UHTResult, UHTResult.ToString()); return false; } Log.TraceInformation("Reflection code generated for {0} in {1} seconds", ActualTargetName, s.Elapsed.TotalSeconds); if( BuildConfiguration.bPrintPerformanceInfo ) { Log.TraceInformation( "UnrealHeaderTool 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." ); } Progress.Write(2, 3); // 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. // @todo ubtmake: Need to figure out what this does in the assembler case, and whether we need to run it ToolChain.PostCodeGeneration(Manifest); } // touch the directories UpdateDirectoryTimestamps(UObjectModules); Progress.Write(3, 3); } if(ProgressWriter.bWriteMarkup) { Log.WriteLine(TraceEventType.Information, "@progress pop"); } return true; }
public override void PostCodeGeneration(UHTManifest Manifest) { if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac) { // @todo UHT: Temporary workaround for UBT no longer being able to follow includes from generated headers unless // the headers already existed before the build started. We're working on a proper fix. // Make sure all generated headers are synced. If we had to generate code, we need to assume that not all of the // header files existed on disk at the time that UBT scanned include statements looking for prerequisite files. Those // files are created during code generation and must exist on disk by the time this function is called. We'll scan // for generated code files and make sure they are enqueued for copying to the remote machine. foreach( var UObjectModule in Manifest.Modules ) { // @todo uht: Ideally would only copy exactly the files emitted by UnrealHeaderTool, rather than scanning directory (could copy stale files; not a big deal though) try { var GeneratedCodeDirectory = Path.GetDirectoryName( UObjectModule.GeneratedCPPFilenameBase ); var GeneratedCodeFiles = Directory.GetFiles( GeneratedCodeDirectory, "*", SearchOption.AllDirectories ); foreach( var GeneratedCodeFile in GeneratedCodeFiles ) { // Skip copying "Timestamp" files (UBT temporary files) if( !Path.GetFileName( GeneratedCodeFile ).Equals( @"Timestamp", StringComparison.InvariantCultureIgnoreCase ) ) { var GeneratedCodeFileItem = FileItem.GetExistingItemByPath( GeneratedCodeFile ); QueueFileForBatchUpload( GeneratedCodeFileItem ); } } } catch (System.IO.DirectoryNotFoundException) { // Ignore directory not found } // For source files in legacy "Classes" directories, we need to make sure they all get copied over too, since // they may not have been directly included in any C++ source files (only generated headers), and the initial // header scan wouldn't have picked them up if they hadn't been generated yet! try { var SourceFiles = Directory.GetFiles( UObjectModule.BaseDirectory, "*", SearchOption.AllDirectories ); foreach( var SourceFile in SourceFiles ) { var SourceFileItem = FileItem.GetExistingItemByPath( SourceFile ); QueueFileForBatchUpload( SourceFileItem ); } } catch (System.IO.DirectoryNotFoundException) { // Ignore directory not found } } } }
/** * 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 ) { bool bSuccess = true; // 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? var UHTPlatform = UnrealTargetPlatform.Win64; if( Utils.IsRunningOnMono ) { UHTPlatform = UnrealTargetPlatform.Mac; } UBTArguments.Append( " " + UHTPlatform.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"); } bSuccess = RunExternalExecutable( UnrealBuildTool.GetUBTPath(), UBTArguments.ToString() ); } if( bSuccess ) { 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(); bSuccess = RunExternalExecutable(ExternalExecution.GetHeaderToolPath(), CmdLine); s.Stop(); if (bSuccess) { //if( BuildConfiguration.bPrintDebugInfo ) { 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.TraceInformation( "Error: Failed to generate code for {0}", ActualTargetName ); } } else { bSuccess = false; } } else { Log.TraceVerbose( "Generated code is up to date." ); } if (bSuccess) { // 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 bSuccess; }
/// <summary> /// Called immediately after UnrealHeaderTool is executed to generated code for all UObjects modules. Only is called if UnrealHeaderTool was actually run in this session. /// </summary> /// <param name="UObjectModules">List of UObject modules we generated code for.</param> public virtual void PostCodeGeneration(UEBuildTarget Target, UHTManifest Manifest) { }