2014-12-07 19:09:38 -05:00
|
|
|
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
2014-07-31 07:33:17 -04:00
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Xml;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
namespace UnrealBuildTool
|
|
|
|
|
{
|
|
|
|
|
public class Distcc
|
|
|
|
|
{
|
|
|
|
|
public static bool ExecuteActions(List<Action> Actions)
|
|
|
|
|
{
|
|
|
|
|
bool bDistccResult = true;
|
|
|
|
|
if (Actions.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
// Time to sleep after each iteration of the loop in order to not busy wait.
|
|
|
|
|
const float LoopSleepTime = 0.1f;
|
|
|
|
|
|
|
|
|
|
int MaxActionsToExecuteInParallel = 0;
|
|
|
|
|
string UserDir = Environment.GetEnvironmentVariable("HOME");
|
|
|
|
|
string HostsInfo = UserDir + "/.dmucs/hosts-info";
|
|
|
|
|
System.IO.StreamReader File = new System.IO.StreamReader(HostsInfo);
|
|
|
|
|
string Line = null;
|
|
|
|
|
while((Line = File.ReadLine()) != null)
|
|
|
|
|
{
|
|
|
|
|
var HostInfo = Line.Split(' ');
|
|
|
|
|
if (HostInfo.Count () == 3)
|
|
|
|
|
{
|
|
|
|
|
int NumCPUs = 0;
|
|
|
|
|
if (System.Int32.TryParse (HostInfo [1], out NumCPUs))
|
|
|
|
|
{
|
|
|
|
|
MaxActionsToExecuteInParallel += NumCPUs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
File.Close();
|
|
|
|
|
|
|
|
|
|
if (BuildConfiguration.bAllowDistccLocalFallback == false)
|
|
|
|
|
{
|
|
|
|
|
Environment.SetEnvironmentVariable("DISTCC_FALLBACK", "0");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string DistccExecutable = BuildConfiguration.DistccExecutablesPath + "/distcc";
|
|
|
|
|
string GetHostExecutable = BuildConfiguration.DistccExecutablesPath + "/gethost";
|
|
|
|
|
|
2014-08-20 11:47:58 -04:00
|
|
|
Log.TraceInformation("Performing {0} actions ({1} in parallel)", Actions.Count, MaxActionsToExecuteInParallel, DistccExecutable, GetHostExecutable);
|
2014-07-31 07:33:17 -04:00
|
|
|
|
|
|
|
|
Dictionary<Action, ActionThread> ActionThreadDictionary = new Dictionary<Action, ActionThread>();
|
|
|
|
|
int JobNumber = 1;
|
|
|
|
|
using(ProgressWriter ProgressWriter = new ProgressWriter("Compiling source code...", false))
|
|
|
|
|
{
|
|
|
|
|
int ProgressValue = 0;
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
// Count the number of pending and still executing actions.
|
|
|
|
|
int NumUnexecutedActions = 0;
|
|
|
|
|
int NumExecutingActions = 0;
|
|
|
|
|
foreach (Action Action in Actions)
|
|
|
|
|
{
|
|
|
|
|
ActionThread ActionThread = null;
|
|
|
|
|
bool bFoundActionProcess = ActionThreadDictionary.TryGetValue(Action, out ActionThread);
|
|
|
|
|
if (bFoundActionProcess == false)
|
|
|
|
|
{
|
|
|
|
|
NumUnexecutedActions++;
|
|
|
|
|
}
|
|
|
|
|
else if (ActionThread != null)
|
|
|
|
|
{
|
|
|
|
|
if (ActionThread.bComplete == false)
|
|
|
|
|
{
|
|
|
|
|
NumUnexecutedActions++;
|
|
|
|
|
NumExecutingActions++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update the current progress
|
|
|
|
|
int NewProgressValue = Actions.Count + 1 - NumUnexecutedActions;
|
|
|
|
|
if (ProgressValue != NewProgressValue)
|
|
|
|
|
{
|
|
|
|
|
ProgressWriter.Write(ProgressValue, Actions.Count + 1);
|
|
|
|
|
ProgressValue = NewProgressValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If there aren't any pending actions left, we're done executing.
|
|
|
|
|
if (NumUnexecutedActions == 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If there are fewer actions executing than the maximum, look for pending actions that don't have any outdated
|
|
|
|
|
// prerequisites.
|
|
|
|
|
foreach (Action Action in Actions)
|
|
|
|
|
{
|
|
|
|
|
ActionThread ActionProcess = null;
|
|
|
|
|
bool bFoundActionProcess = ActionThreadDictionary.TryGetValue(Action, out ActionProcess);
|
|
|
|
|
if (bFoundActionProcess == false)
|
|
|
|
|
{
|
|
|
|
|
if (NumExecutingActions < Math.Max(1,MaxActionsToExecuteInParallel))
|
|
|
|
|
{
|
|
|
|
|
// Determine whether there are any prerequisites of the action that are outdated.
|
|
|
|
|
bool bHasOutdatedPrerequisites = false;
|
|
|
|
|
bool bHasFailedPrerequisites = false;
|
|
|
|
|
foreach (FileItem PrerequisiteItem in Action.PrerequisiteItems)
|
|
|
|
|
{
|
|
|
|
|
if (PrerequisiteItem.ProducingAction != null && Actions.Contains(PrerequisiteItem.ProducingAction))
|
|
|
|
|
{
|
|
|
|
|
ActionThread PrerequisiteProcess = null;
|
|
|
|
|
bool bFoundPrerequisiteProcess = ActionThreadDictionary.TryGetValue( PrerequisiteItem.ProducingAction, out PrerequisiteProcess );
|
|
|
|
|
if (bFoundPrerequisiteProcess == true)
|
|
|
|
|
{
|
|
|
|
|
if (PrerequisiteProcess == null)
|
|
|
|
|
{
|
|
|
|
|
bHasFailedPrerequisites = true;
|
|
|
|
|
}
|
|
|
|
|
else if (PrerequisiteProcess.bComplete == false)
|
|
|
|
|
{
|
|
|
|
|
bHasOutdatedPrerequisites = true;
|
|
|
|
|
}
|
|
|
|
|
else if (PrerequisiteProcess.ExitCode != 0)
|
|
|
|
|
{
|
|
|
|
|
bHasFailedPrerequisites = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bHasOutdatedPrerequisites = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If there are any failed prerequisites of this action, don't execute it.
|
|
|
|
|
if (bHasFailedPrerequisites)
|
|
|
|
|
{
|
|
|
|
|
// Add a null entry in the dictionary for this action.
|
|
|
|
|
ActionThreadDictionary.Add( Action, null );
|
|
|
|
|
}
|
|
|
|
|
// If there aren't any outdated prerequisites of this action, execute it.
|
|
|
|
|
else if (!bHasOutdatedPrerequisites)
|
|
|
|
|
{
|
|
|
|
|
if ((Action.ActionType == ActionType.Compile || Action.ActionType == ActionType.Link) && DistccExecutable != null && GetHostExecutable != null)
|
|
|
|
|
{
|
|
|
|
|
string NewCommandArguments = "--wait -1 \"" + DistccExecutable + "\" " + Action.CommandPath + " " + Action.CommandArguments;
|
|
|
|
|
Action.CommandPath = GetHostExecutable;
|
|
|
|
|
Action.CommandArguments = NewCommandArguments;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ActionThread ActionThread = new ActionThread(Action, JobNumber, Actions.Count);
|
|
|
|
|
JobNumber++;
|
|
|
|
|
ActionThread.Run();
|
|
|
|
|
|
|
|
|
|
ActionThreadDictionary.Add(Action, ActionThread);
|
|
|
|
|
|
|
|
|
|
NumExecutingActions++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(LoopSleepTime));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats, TraceEventType.Information, "-------- Begin Detailed Action Stats ----------------------------------------------------------");
|
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
|
|
|
Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats, TraceEventType.Information, "^Action Type^Duration (seconds)^Tool^Task^Using PCH");
|
2014-07-31 07:33:17 -04:00
|
|
|
|
|
|
|
|
double TotalThreadSeconds = 0;
|
|
|
|
|
|
|
|
|
|
// Check whether any of the tasks failed and log action stats if wanted.
|
|
|
|
|
foreach (KeyValuePair<Action, ActionThread> ActionProcess in ActionThreadDictionary)
|
|
|
|
|
{
|
|
|
|
|
Action Action = ActionProcess.Key;
|
|
|
|
|
ActionThread ActionThread = ActionProcess.Value;
|
|
|
|
|
|
|
|
|
|
// Check for pending actions, preemptive failure
|
|
|
|
|
if (ActionThread == null)
|
|
|
|
|
{
|
|
|
|
|
bDistccResult = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// Check for executed action but general failure
|
|
|
|
|
if (ActionThread.ExitCode != 0)
|
|
|
|
|
{
|
|
|
|
|
bDistccResult = false;
|
|
|
|
|
}
|
|
|
|
|
// Log CPU time, tool and task.
|
|
|
|
|
double ThreadSeconds = Action.Duration.TotalSeconds;
|
|
|
|
|
|
|
|
|
|
Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats,
|
|
|
|
|
TraceEventType.Information,
|
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
|
|
|
"^{0}^{1:0.00}^{2}^{3}^{4}",
|
2014-07-31 07:33:17 -04:00
|
|
|
Action.ActionType.ToString(),
|
|
|
|
|
ThreadSeconds,
|
|
|
|
|
Path.GetFileName(Action.CommandPath),
|
|
|
|
|
Action.StatusDescription,
|
Experimental UnrealBuildTool makefile support
UnrealBuildTool 'Makefiles' allow for very fast iterative builds.
- New BuildConfiguration.xml setting added: "bUseExperimentalFastBuildIteration" (disabled by default)
- Turning this on causes Unreal Build Tool to emit 'UBT Makefiles' for targets when they're built the first time.
- Subsequent builds will load these Makefiles and begin outdatedness checking and build invocation very quickly.
- The caveat is that if source files are added or removed to the project, UBT will need to gather information about those in order for your build to complete successfully.
- Currently, you must run the project file generator after adding/removing source files to tell UBT to re-gather this information.
- Events that can invalidate the 'UBT Makefile':
- Adding/removing .cpp files
- Adding/removing .h files with UObjects
- Adding new UObject types to a file that didn't previously have any
- Changing global build settings (most settings in this file qualify.)
- Changed code that affects how Unreal Header Tool works
- You can force regeneration of the 'UBT Makefile' by passing the '-Gather' argument, or simply regenerating project files
- New command-line parameters added:
- "-Gather": Tells UBT to always perform the gather step (slower but will catch project structural changes)
- "-NoGather": Disables the gather step, unless UBT detects that it must be done. This is the default when bUseExperimentalFastBuildIteration is enabled
- "-GatherOnly": Runs the gather step and saves a UBTMakefile, but doesn't build anything
- "-Assemble": Tells UBT to also assemble build products. This always defaults to enabled
- "-NoAssemble": Tells UBT to skip the assemble step, whether we gathered build products or not
- "-AssembleOnly": Tells UBT to only assemble build products and not to gather, unless UBT determines it must
Other changes:
- UBT now keeps track of which targets it was building in an intermediate file, to help it invalidate cached includes in subsequent runs when the targets are different
- C++ includes are now stored in a class separate from the C++ compile enviroment (for easier serialization)
- The method that UBT uses to find the CoreUObject module timestamp was rewritten
- Various '@todo ubtmake' comments added to tag possible remaining Makefile tasks
- The 'FileItem' class had some member variable comments and code cleaned up, while making it serializable
- Cleaned up the comments and member variables in the "Action" class, while making it serializable
- Some UBT classes are now "serializable". This is because we need to store the data in UBTMakefiles.
- Removed support for Actions to tinker with Stdout and Stderror (was not used for anything)
- Moved PrecompileHeaderEnvironment class to the UEBuildModule.cs source file
- Plugin intermediate include directories are now selected on demand rather than cached early
- Toolchain code for gathering prerequisite headers is now shared in a single function (AddPrerequisiteSourceFile)
- Removed Action.StatusDetailedDescription, was not used for anything
- Removed UEBuildConfiguration.bExcludePlugins, was not used for anything
- Removed ECompilationResult.FailedDueToHeaderChange, was not used for anything
[CL 2254472 by Mike Fricker in Main branch]
2014-08-13 08:17:43 -04:00
|
|
|
Action.bIsUsingPCH);
|
2014-07-31 07:33:17 -04:00
|
|
|
|
|
|
|
|
// Update statistics
|
|
|
|
|
switch (Action.ActionType)
|
|
|
|
|
{
|
|
|
|
|
case ActionType.BuildProject:
|
|
|
|
|
UnrealBuildTool.TotalBuildProjectTime += ThreadSeconds;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ActionType.Compile:
|
|
|
|
|
UnrealBuildTool.TotalCompileTime += ThreadSeconds;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ActionType.CreateAppBundle:
|
|
|
|
|
UnrealBuildTool.TotalCreateAppBundleTime += ThreadSeconds;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ActionType.GenerateDebugInfo:
|
|
|
|
|
UnrealBuildTool.TotalGenerateDebugInfoTime += ThreadSeconds;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ActionType.Link:
|
|
|
|
|
UnrealBuildTool.TotalLinkTime += ThreadSeconds;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
UnrealBuildTool.TotalOtherActionsTime += ThreadSeconds;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keep track of total thread seconds spent on tasks.
|
|
|
|
|
TotalThreadSeconds += ThreadSeconds;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-18 16:52:27 -05:00
|
|
|
Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats || BuildConfiguration.bPrintDebugInfo,
|
|
|
|
|
TraceEventType.Information,
|
|
|
|
|
"-------- End Detailed Actions Stats -----------------------------------------------------------");
|
2014-07-31 07:33:17 -04:00
|
|
|
|
|
|
|
|
// Log total CPU seconds and numbers of processors involved in tasks.
|
|
|
|
|
Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats || BuildConfiguration.bPrintDebugInfo,
|
|
|
|
|
TraceEventType.Information, "Cumulative thread seconds ({0} processors): {1:0.00}", System.Environment.ProcessorCount, TotalThreadSeconds);
|
|
|
|
|
}
|
|
|
|
|
return bDistccResult;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|