Exemplo n.º 1
0
 public ProgressWriterFacts()
 {
     _output = new StringWriter();
     _error = new StringWriter();
     _progressWriter = new ProgressWriter(_output, _error, _idlingStart, _idlingDelay);
     _done = new ManualResetEventSlim(false);
 }
Exemplo n.º 2
0
        /// <summary>
        /// Generates data for IntelliSense (compile definitions, include paths)
        /// </summary>
        /// <param name="Arguments">Incoming command-line arguments to UBT</param>
        /// <param name="TargetFiles">Target files</param>
        /// <return>Whether the process was successful or not</return>
        private bool GenerateIntelliSenseData( String[] Arguments, List<Tuple<ProjectFile, string>> TargetFiles )
        {
            var bSuccess = true;
            if( ShouldGenerateIntelliSenseData() && TargetFiles.Count > 0 )
            {
                string ProgressInfoText = Utils.IsRunningOnMono ? "Generating data for project indexing..." : "Binding IntelliSense data...";
                using(ProgressWriter Progress = new ProgressWriter(ProgressInfoText, true))
                {
                    for(int TargetIndex = 0; TargetIndex < TargetFiles.Count; ++TargetIndex)
                    {
                        var TargetProjectFile = TargetFiles[ TargetIndex ].Item1;
                        var CurTarget = TargetFiles[ TargetIndex ].Item2;

                        var TargetName = Utils.GetFilenameWithoutAnyExtensions( CurTarget );

                        Log.TraceVerbose( "Found target: " + TargetName );

                        var ArgumentsCopy = new string[ Arguments.Length + 1 ];
                        ArgumentsCopy[ 0 ] = TargetName;
                        Array.Copy(Arguments, 0, ArgumentsCopy, 1, Arguments.Length);

                        // CreateTarget mutates the current project setting file if it isn't already set, which prevents other
                        // projects from being able to do the same. Capture the state beforehand, and reset if after running UBT.
                        bool bHasProjectFile = UnrealBuildTool.HasUProjectFile();

                        // We only want to update definitions and include paths for modules that are part of this target's project file.
                        ProjectFileGenerator.OnlyGenerateIntelliSenseDataForProject = TargetProjectFile;

                        // Run UnrealBuildTool, pretending to build this target but instead only gathering data for IntelliSense (include paths and definitions).
                        // No actual compiling or linking will happen because we early out using the ProjectFileGenerator.bGenerateProjectFiles global
                        bSuccess = UnrealBuildTool.RunUBT( ArgumentsCopy ) == ECompilationResult.Succeeded;
                        ProjectFileGenerator.OnlyGenerateIntelliSenseDataForProject = null;

                        if( !bSuccess )
                        {
                            break;
                        }

                        if(!bHasProjectFile)
                        {
                            UnrealBuildTool.ResetProjectFile();
                        }

                        // Display progress
                        Progress.Write(TargetIndex + 1, TargetFiles.Count);
                    }
                }
            }

            return bSuccess;
        }
Exemplo n.º 3
0
        /// <summary>
        /// Writes the project files to disk
        /// </summary>
        /// <returns>True if successful</returns>
        protected virtual bool WriteProjectFiles()
        {
            using(ProgressWriter Progress = new ProgressWriter("Writing project files...", true))
            {
                var TotalProjectFileCount = GeneratedProjectFiles.Count + 1;	// +1 for the master project file, which we'll save next

                for(int ProjectFileIndex = 0 ; ProjectFileIndex < GeneratedProjectFiles.Count; ++ProjectFileIndex )
                {
                    var CurProject = GeneratedProjectFiles[ ProjectFileIndex ];
                    if( !CurProject.WriteProjectFile(
                                InPlatforms: SupportedPlatforms,
                                InConfigurations: SupportedConfigurations ) )
                    {
                        return false;
                    }

                    Progress.Write(ProjectFileIndex + 1, TotalProjectFileCount);
                }

                WriteMasterProjectFile( UBTProject: UBTProject );
                Progress.Write(TotalProjectFileCount, TotalProjectFileCount);
            }
            return true;
        }
Exemplo n.º 4
0
        /**
         * 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;
        }
Exemplo n.º 5
0
		/**
		 * Executes the tasks in the specified file, parsing progress markup as part of the output.
		 */
		public static ExecutionResult ExecuteTaskFileWithProgressMarkup(string TaskFilePath, int NumActions, DataReceivedEventHandler OutputEventHandler)
		{
			using (ProgressWriter Writer = new ProgressWriter("Compiling C++ source files...", false))
			{
				int NumCompletedActions = 0;

				// Create a wrapper delegate that will parse the output actions
				DataReceivedEventHandler EventHandlerWrapper = (Sender, Args) =>
				{
					if (Args.Data != null && Args.Data.StartsWith(ProgressMarkupPrefix))
					{
						Writer.Write(++NumCompletedActions, NumActions);
						Args = ConstructDataReceivedEventArgs(Args.Data.Substring(ProgressMarkupPrefix.Length));
					}
					if(OutputEventHandler != null)
					{
						OutputEventHandler(Sender, Args);
					}
				};

				// Run through the standard XGE executor
				return ExecuteTaskFile(TaskFilePath, EventHandlerWrapper);
			}
		}
Exemplo n.º 6
0
		/**
		 * Executes the specified actions locally.
		 * @return True if all the tasks successfully executed, or false if any of them failed.
		 */
		public static bool ExecuteActions(List<Action> Actions)
		{
			// Time to sleep after each iteration of the loop in order to not busy wait.
			const float LoopSleepTime = 0.1f;

			// Use WMI to figure out physical cores, excluding hyper threading.
			int NumCores = 0;
			if (!Utils.IsRunningOnMono)
			{
				try
				{
					using (var Mos = new System.Management.ManagementObjectSearcher("Select * from Win32_Processor"))
					{
						var MosCollection = Mos.Get();
						foreach (var Item in MosCollection)
						{
							NumCores += int.Parse(Item["NumberOfCores"].ToString());
						}
					}
				}
				catch (Exception Ex)
				{
					Log.TraceWarning("Unable to get the number of Cores: {0}", Ex.ToString());
					Log.TraceWarning("Falling back to processor count.");
				}
			}
			// On some systems this requires a hot fix to work so we fall back to using the (logical) processor count.
			if( NumCores == 0 )
			{
				NumCores = System.Environment.ProcessorCount;
			}
			// The number of actions to execute in parallel is trying to keep the CPU busy enough in presence of I/O stalls.
			int MaxActionsToExecuteInParallel = 0;
			if (NumCores < System.Environment.ProcessorCount && BuildConfiguration.ProcessorCountMultiplier != 1.0)
			{
				// The CPU has more logical cores than physical ones, aka uses hyper-threading. 
				// Use multiplier if provided
				MaxActionsToExecuteInParallel = (int)(NumCores * BuildConfiguration.ProcessorCountMultiplier);
			}
			else if (NumCores < System.Environment.ProcessorCount && NumCores > 4)
			{
				// The CPU has more logical cores than physical ones, aka uses hyper-threading. 
				// Use average of logical and physical if we have "lots of cores"
				MaxActionsToExecuteInParallel = (int)(NumCores + System.Environment.ProcessorCount) / 2;
			}
			// No hyper-threading. Only kicking off a task per CPU to keep machine responsive.
			else
			{
				MaxActionsToExecuteInParallel = NumCores;
			}

            if (Utils.IsRunningOnMono)
            {
				// heuristic: give each action at least 1.5GB of RAM (some clang instances will need more, actually)
				long MinMemoryPerActionMB = 3 * 1024 / 2;
				long PhysicalRAMAvailableMB = (new PerformanceCounter ("Mono Memory", "Total Physical Memory").RawValue) / (1024 * 1024);
				int MaxActionsAffordedByMemory = (int)(Math.Max(1, (PhysicalRAMAvailableMB) / MinMemoryPerActionMB));

				MaxActionsToExecuteInParallel = Math.Min(MaxActionsToExecuteInParallel, MaxActionsAffordedByMemory);
            }

			MaxActionsToExecuteInParallel = Math.Max( 1, Math.Min(MaxActionsToExecuteInParallel, BuildConfiguration.MaxProcessorCount) );

            Log.TraceInformation("Performing {0} actions ({1} in parallel)", Actions.Count, MaxActionsToExecuteInParallel);

			Dictionary<Action, ActionThread> ActionThreadDictionary = new Dictionary<Action, ActionThread>();
            int JobNumber = 1;
			using(ProgressWriter ProgressWriter = new ProgressWriter("Compiling C++ 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)
								{
									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, LogEventType.Console, "-------- Begin Detailed Action Stats ----------------------------------------------------------");
			Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats, LogEventType.Console, "^Action Type^Duration (seconds)^Tool^Task^Using PCH");

			double TotalThreadSeconds = 0;

			// Check whether any of the tasks failed and log action stats if wanted.
			bool bSuccess = true;
			foreach (KeyValuePair<Action, ActionThread> ActionProcess in ActionThreadDictionary)
			{
				Action Action = ActionProcess.Key;
				ActionThread ActionThread = ActionProcess.Value;

				// Check for pending actions, preemptive failure
				if (ActionThread == null)
				{
                    bSuccess = false;
					continue;
				}
				// Check for executed action but general failure
				if (ActionThread.ExitCode != 0)
				{
					bSuccess = false;
				}
                // Log CPU time, tool and task.
				double ThreadSeconds = Action.Duration.TotalSeconds;

				Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats,
					LogEventType.Console,
					"^{0}^{1:0.00}^{2}^{3}^{4}", 
					Action.ActionType.ToString(),
					ThreadSeconds,
					Path.GetFileName(Action.CommandPath), 
                      Action.StatusDescription,
					Action.bIsUsingPCH);

				// 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;
			}

			Log.TraceInformation("-------- End Detailed Actions Stats -----------------------------------------------------------");

			// Log total CPU seconds and numbers of processors involved in tasks.
			Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats || BuildConfiguration.bPrintDebugInfo,
				LogEventType.Console, "Cumulative thread seconds ({0} processors): {1:0.00}", System.Environment.ProcessorCount, TotalThreadSeconds);

			return bSuccess;
		}
Exemplo n.º 7
0
		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";
				string NumUBTBuildTasks = Environment.GetEnvironmentVariable("NumUBTBuildTasks");
				Int32 MaxUBTBuildTasks = MaxActionsToExecuteInParallel;
				if(Int32.TryParse(NumUBTBuildTasks, out MaxUBTBuildTasks))
				{
					MaxActionsToExecuteInParallel = MaxUBTBuildTasks;
				}
				else if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
				{
					using (System.Diagnostics.Process DefaultsProcess = new System.Diagnostics.Process())
					{
						try
						{
							DefaultsProcess.StartInfo.FileName = "/usr/bin/defaults";
							DefaultsProcess.StartInfo.CreateNoWindow = true;
							DefaultsProcess.StartInfo.UseShellExecute = false;
							DefaultsProcess.StartInfo.RedirectStandardOutput = true;
							DefaultsProcess.StartInfo.Arguments = "com.apple.dt.Xcode IDEBuildOperationMaxNumberOfConcurrentCompileTasks";
							DefaultsProcess.Start();
							string Output = DefaultsProcess.StandardOutput.ReadToEnd();
							DefaultsProcess.WaitForExit();
							if(DefaultsProcess.ExitCode == 0 && Int32.TryParse(Output, out MaxUBTBuildTasks))
							{
								MaxActionsToExecuteInParallel = MaxUBTBuildTasks;
							}
						}
						catch (Exception)
						{
						}
					}
				}
				else if (System.IO.File.Exists (HostsInfo))
				{
					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();
				}
				else
				{
					MaxActionsToExecuteInParallel = System.Environment.ProcessorCount;
				}

				if (BuildConfiguration.bAllowDistccLocalFallback == false)
				{
					Environment.SetEnvironmentVariable("DISTCC_FALLBACK", "0");
				}

				if (BuildConfiguration.bVerboseDistccOutput == true)
				{
					Environment.SetEnvironmentVariable("DISTCC_VERBOSE", "1");
				}

				string DistccExecutable = BuildConfiguration.DistccExecutablesPath + "/distcc";
				string GetHostExecutable = BuildConfiguration.DistccExecutablesPath + "/gethost";

				Log.TraceInformation("Performing {0} actions ({1} in parallel)", Actions.Count, MaxActionsToExecuteInParallel, DistccExecutable, GetHostExecutable);

				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 TypeCommand = String.IsNullOrEmpty(BuildConfiguration.DMUCSDistProp) ? "" : (" --type " + BuildConfiguration.DMUCSDistProp);
											string NewCommandArguments = "--server " + BuildConfiguration.DMUCSCoordinator + TypeCommand + " --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, LogEventType.Console, "-------- Begin Detailed Action Stats ----------------------------------------------------------");
				Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats, LogEventType.Console, "^Action Type^Duration (seconds)^Tool^Task^Using PCH");

				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,
						LogEventType.Console,
						"^{0}^{1:0.00}^{2}^{3}^{4}", 
						Action.ActionType.ToString(),
						ThreadSeconds,
						Path.GetFileName(Action.CommandPath), 
						Action.StatusDescription,
						Action.bIsUsingPCH);

					// 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;
				}

				Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats || BuildConfiguration.bPrintDebugInfo,
					LogEventType.Console, 
					"-------- End Detailed Actions Stats -----------------------------------------------------------");

				// Log total CPU seconds and numbers of processors involved in tasks.
				Log.WriteLineIf(BuildConfiguration.bLogDetailedActionStats || BuildConfiguration.bPrintDebugInfo,
					LogEventType.Console, "Cumulative thread seconds ({0} processors): {1:0.00}", System.Environment.ProcessorCount, TotalThreadSeconds);
			}
			return bDistccResult;
		}
		/// <summary>
		/// Writes the project files to disk
		/// </summary>
		/// <returns>True if successful</returns>
		protected virtual bool WriteProjectFiles()
		{
            using(ProgressWriter Progress = new ProgressWriter("Writing project files...", true))
			{
				int TotalProjectFileCount = GeneratedProjectFiles.Count + 1;	// +1 for the master project file, which we'll save next

				for(int ProjectFileIndex = 0 ; ProjectFileIndex < GeneratedProjectFiles.Count; ++ProjectFileIndex )
				{
					ProjectFile CurProject = GeneratedProjectFiles[ ProjectFileIndex ];
					if( !CurProject.WriteProjectFile(
								InPlatforms: SupportedPlatforms,
								InConfigurations: SupportedConfigurations ) )
					{
						return false;
					}

					Progress.Write(ProjectFileIndex + 1, TotalProjectFileCount);
				}

				WriteMasterProjectFile( UBTProject: UBTProject );
				Progress.Write(TotalProjectFileCount, TotalProjectFileCount);
			}

            // Write AutomationReferences file
            if (AutomationProjectFiles.Any())
            {
                XNamespace NS = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");

                DirectoryReference AutomationToolDir = DirectoryReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Programs", "AutomationTool");
                new XDocument(
                    new XElement(NS + "Project",
                        new XAttribute("ToolsVersion", VCProjectFileGenerator.ProjectFileToolVersionString),
                        new XAttribute("DefaultTargets", "Build"),
                        new XElement(NS + "ItemGroup",
                            from AutomationProject in AutomationProjectFiles
                            select new XElement(NS + "ProjectReference",
                                new XAttribute("Include", AutomationProject.ProjectFilePath.MakeRelativeTo(AutomationToolDir)),
                                new XElement(NS + "Project", (AutomationProject as VCSharpProjectFile).ProjectGUID.ToString("B")),
                                new XElement(NS + "Name", AutomationProject.ProjectFilePath.GetFileNameWithoutExtension()),
                                new XElement(NS + "Private", "false")
                            )
                        )
                    )
                ).Save(FileReference.Combine( AutomationToolDir, "AutomationTool.csproj.References" ).FullName);
            }

			return true;
		}
		/// <summary>
		/// Generates data for IntelliSense (compile definitions, include paths)
		/// </summary>
		/// <param name="Arguments">Incoming command-line arguments to UBT</param>
		/// <param name="TargetFiles">Target files</param>
		/// <return>Whether the process was successful or not</return>
		private bool GenerateIntelliSenseData( String[] Arguments, List<Tuple<ProjectFile, FileReference>> TargetFiles )
		{
			bool bSuccess = true;
			if( ShouldGenerateIntelliSenseData() && TargetFiles.Count > 0 )
			{
				string ProgressInfoText = Utils.IsRunningOnMono ? "Generating data for project indexing..." : "Binding IntelliSense data...";
				using(ProgressWriter Progress = new ProgressWriter(ProgressInfoText, true))
				{
					for(int TargetIndex = 0; TargetIndex < TargetFiles.Count; ++TargetIndex)
					{
						ProjectFile TargetProjectFile = TargetFiles[ TargetIndex ].Item1;
						FileReference CurTarget = TargetFiles[ TargetIndex ].Item2;

						string TargetName = CurTarget.GetFileNameWithoutAnyExtensions();

						Log.TraceVerbose( "Found target: " + TargetName );

						string[] ArgumentsCopy = new string[ Arguments.Length + 2 ];
						ArgumentsCopy[ 0 ] = TargetName;
						ArgumentsCopy[ 1 ] = "-precompile";
						Array.Copy(Arguments, 0, ArgumentsCopy, 2, Arguments.Length);

						// We only want to update definitions and include paths for modules that are part of this target's project file.
						ProjectFileGenerator.OnlyGenerateIntelliSenseDataForProject = TargetProjectFile;

						FileReference ProjectFile;
						if(!UProjectInfo.TryGetProjectForTarget(TargetName, out ProjectFile))
						{
							ProjectFile = null;
						}

						// Run UnrealBuildTool, pretending to build this target but instead only gathering data for IntelliSense (include paths and definitions).
						// No actual compiling or linking will happen because we early out using the ProjectFileGenerator.bGenerateProjectFiles global
						bSuccess = UnrealBuildTool.RunUBT( ArgumentsCopy, ProjectFile ) == ECompilationResult.Succeeded;
						ProjectFileGenerator.OnlyGenerateIntelliSenseDataForProject = null;

						if( !bSuccess )
						{
							break;
						}

						// Display progress
						Progress.Write(TargetIndex + 1, TargetFiles.Count);
					}
				}
			}

			return bSuccess;
		}
        /// <summary>
        /// Generates data for IntelliSense (compile definitions, include paths)
        /// </summary>
        /// <param name="Arguments">Incoming command-line arguments to UBT</param>
        /// <param name="TargetFiles">Target files</param>
        /// <return>Whether the process was successful or not</return>
        private bool GenerateIntelliSenseData( String[] Arguments, List<string> TargetFiles )
        {
            var bSuccess = true;
            if( ShouldGenerateIntelliSenseData() && TargetFiles.Count > 0 )
            {
                using(ProgressWriter Progress = new ProgressWriter("Binding IntelliSense data...", true))
                {
                    for(int TargetIndex = 0; TargetIndex < TargetFiles.Count; ++TargetIndex)
                    {
                        var CurTarget = TargetFiles[ TargetIndex ];
                        var TargetName = Utils.GetFilenameWithoutAnyExtensions( CurTarget );	// Twice, to remove both extensions from *.Target.cs file

                        Log.TraceVerbose( "Found target: " + TargetName );

                        var ArgumentsCopy = new string[ Arguments.Length + 1 ];
                        ArgumentsCopy[ 0 ] = TargetName;
                        Array.Copy(Arguments, 0, ArgumentsCopy, 1, Arguments.Length);

                        // CreateTarget mutates the current project setting file if it isn't already set, which prevents other
                        // projects from being able to do the same. Capture the state beforehand, and reset if after running UBT.
                        bool bHasProjectFile = UnrealBuildTool.HasUProjectFile();

                        bSuccess = UnrealBuildTool.RunUBT( ArgumentsCopy ) == ECompilationResult.Succeeded;
                        if( !bSuccess )
                        {
                            break;
                        }

                        if(!bHasProjectFile)
                        {
                            UnrealBuildTool.ResetProjectFile();
                        }

                        // Display progress
                        Progress.Write(TargetIndex + 1, TargetFiles.Count);
                    }
                }
            }

            return bSuccess;
        }
Exemplo n.º 11
0
        public async Task DeployAsync(IRepository repository, ChangeSet changeSet, string deployer, bool clean, bool needFileUpdate)
        {
            using (var deploymentAnalytics = new DeploymentAnalytics(_analytics, _settings))
            {
                Exception   exception    = null;
                ITracer     tracer       = _traceFactory.GetTracer();
                IDisposable deployStep   = null;
                ILogger     innerLogger  = null;
                string      targetBranch = null;

                // If we don't get a changeset, find out what branch we should be deploying and get the commit ID from it
                if (changeSet == null)
                {
                    targetBranch = _settings.GetBranch();

                    changeSet = repository.GetChangeSet(targetBranch);

                    if (changeSet == null)
                    {
                        throw new InvalidOperationException(String.Format("The current deployment branch is '{0}', but nothing has been pushed to it", targetBranch));
                    }
                }

                string id = changeSet.Id;
                IDeploymentStatusFile statusFile = null;
                try
                {
                    deployStep = tracer.Step("DeploymentManager.Deploy(id)");

                    // Remove the old log file for this deployment id
                    string logPath = GetLogPath(id);
                    FileSystemHelpers.DeleteFileSafe(logPath);

                    statusFile = GetOrCreateStatusFile(changeSet, tracer, deployer);
                    statusFile.MarkPending();

                    ILogger logger = GetLogger(changeSet.Id);

                    if (needFileUpdate)
                    {
                        using (tracer.Step("Updating to specific changeset"))
                        {
                            innerLogger = logger.Log(Resources.Log_UpdatingBranch, targetBranch ?? id);

                            using (var writer = new ProgressWriter())
                            {
                                // Update to the specific changeset or branch
                                repository.Update(targetBranch ?? id);
                            }
                        }
                    }

                    if (_settings.ShouldUpdateSubmodules())
                    {
                        using (tracer.Step("Updating submodules"))
                        {
                            innerLogger = logger.Log(Resources.Log_UpdatingSubmodules);

                            repository.UpdateSubmodules();
                        }
                    }

                    if (clean)
                    {
                        tracer.Trace("Cleaning {0} repository", repository.RepositoryType);

                        innerLogger = logger.Log(Resources.Log_CleaningRepository, repository.RepositoryType);

                        repository.Clean();
                    }

                    // set to null as Build() below takes over logging
                    innerLogger = null;

                    // Perform the build deployment of this changeset
                    await Build(changeSet, tracer, deployStep, repository, deploymentAnalytics);
                }
                catch (Exception ex)
                {
                    exception = ex;

                    if (innerLogger != null)
                    {
                        innerLogger.Log(ex);
                    }

                    if (statusFile != null)
                    {
                        MarkStatusComplete(statusFile, success: false);
                    }

                    tracer.TraceError(ex);

                    deploymentAnalytics.Error = ex.ToString();

                    if (deployStep != null)
                    {
                        deployStep.Dispose();
                    }
                }

                // Reload status file with latest updates
                statusFile = _status.Open(id);
                if (statusFile != null)
                {
                    await _hooksManager.PublishEventAsync(HookEventTypes.PostDeployment, statusFile);
                }

                if (exception != null)
                {
                    throw new DeploymentFailedException(exception);
                }
            }
        }
Exemplo n.º 12
0
        public void Deploy(IRepository repository, ChangeSet changeSet, string deployer, bool clean, bool needFileUpdate)
        {
            ITracer     tracer       = _traceFactory.GetTracer();
            IDisposable deployStep   = null;
            ILogger     innerLogger  = null;
            string      targetBranch = null;

            // If we don't get a changeset, find out what branch we should be deploying and get the commit ID from it
            if (changeSet == null)
            {
                targetBranch = _settings.GetBranch();

                changeSet = repository.GetChangeSet(targetBranch);
            }

            string id = changeSet.Id;
            IDeploymentStatusFile statusFile = null;

            try
            {
                deployStep = tracer.Step("DeploymentManager.Deploy(id)");

                // Remove the old log file for this deployment id
                string logPath = GetLogPath(id);
                FileSystemHelpers.DeleteFileSafe(logPath);

                statusFile = GetOrCreateStatusFile(changeSet, tracer, deployer);
                statusFile.MarkPending();

                ILogger logger = GetLogger(changeSet.Id);

                if (needFileUpdate)
                {
                    using (tracer.Step("Updating to specific changeset"))
                    {
                        innerLogger = logger.Log(Resources.Log_UpdatingBranch, targetBranch ?? id);

                        using (var writer = new ProgressWriter())
                        {
                            // Update to the the specific changeset
                            repository.ClearLock();
                            repository.Update(id);
                        }
                    }
                }

                using (tracer.Step("Updating submodules"))
                {
                    innerLogger = logger.Log(Resources.Log_UpdatingSubmodules);

                    repository.UpdateSubmodules();
                }

                if (clean)
                {
                    tracer.Trace("Cleaning {0} repository", repository.RepositoryType);

                    innerLogger = logger.Log(Resources.Log_CleaningRepository, repository.RepositoryType);

                    repository.Clean();
                }

                // set to null as Build() below takes over logging
                innerLogger = null;

                // Perform the build deployment of this changeset
                Build(id, tracer, deployStep);
            }
            catch (Exception ex)
            {
                if (innerLogger != null)
                {
                    innerLogger.Log(ex);
                }

                if (statusFile != null)
                {
                    statusFile.MarkFailed();
                }

                tracer.TraceError(ex);

                if (deployStep != null)
                {
                    deployStep.Dispose();
                }

                throw;
            }
        }
Exemplo n.º 13
0
        private void WalkEverythingAndSymbolCache(string rootPath, MutableSymbol parent)
        {
            List <string> binariesToIndex = new List <string>();
            List <string> indicesToMerge  = new List <string>();

            using (new TraceWatch("Finding Binaries to Index..."))
            {
                foreach (string filePath in Directory.GetFiles(rootPath))
                {
                    // Skip VsHost.exe binary
                    if (filePath.Contains(".vshost."))
                    {
                        continue;
                    }

                    if (FileIO.IsManagedBinary(filePath))
                    {
                        // If the binary has symbols next to it, index it
                        string pdbPath = Path.ChangeExtension(filePath, ".pdb");
                        if (File.Exists(pdbPath))
                        {
                            binariesToIndex.Add(filePath);
                        }

                        // If the binary has symbols and an IDX in the SymbolCache, merge it
                        string pdbPathInSymbolCache = Assembly.GetSymbolCachePdbPath(filePath);
                        if (!String.IsNullOrEmpty(pdbPathInSymbolCache) && File.Exists(pdbPathInSymbolCache))
                        {
                            string indexInSymbolCache = Path.ChangeExtension(pdbPathInSymbolCache, ".dll.idx");

                            if (File.Exists(indexInSymbolCache))
                            {
                                indicesToMerge.Add(indexInSymbolCache);
                            }
                        }
                    }
                }
            }

            // Index each binary
            ProgressWriter p = new ProgressWriter(binariesToIndex.Count);

            using (new TraceWatch("Indexing {0:n0} binaries...", binariesToIndex.Count))
            {
                foreach (string binaryPath in binariesToIndex)
                {
                    WalkIncremental(binaryPath, parent);
                    p.IncrementProgress();
                }
            }

            p = new ProgressWriter(indicesToMerge.Count);
            using (new TraceWatch("Merging {0:n0} dependency indices...", indicesToMerge.Count))
            {
                foreach (string indexPath in indicesToMerge)
                {
                    PackageDatabase dependency = new PackageDatabase();
                    dependency.FileRead(indexPath);
                    parent.AddTree(dependency.QueryRoot.FirstChild());
                    p.IncrementProgress();
                }
            }
        }
Exemplo n.º 14
0
 internal string Rebuild(ITracer tracer, ProgressWriter writer)
 {
     return(RunCommandWithProgress(tracer, writer, "rebuild"));
 }
Exemplo n.º 15
0
 public string Install(ITracer tracer, ProgressWriter writer)
 {
     return(RunCommandWithProgress(tracer, writer, "install --production"));
 }