Example #1
0
        /// <summary>
        /// Writes a XGE task file containing the specified actions to the specified file path.
        /// </summary>
        static void WriteTaskFile(List <Action> InActions, string TaskFilePath, bool bProgressMarkup, bool bXGEExport)
        {
            Dictionary <string, string> ExportEnv = new Dictionary <string, string>();

            List <Action> Actions = InActions;

            if (bXGEExport)
            {
                IDictionary CurrentEnvironment = Environment.GetEnvironmentVariables();
                foreach (System.Collections.DictionaryEntry Pair in CurrentEnvironment)
                {
                    if (!UnrealBuildTool.InitialEnvironment.Contains(Pair.Key) || (string)(UnrealBuildTool.InitialEnvironment[Pair.Key]) != (string)(Pair.Value))
                    {
                        ExportEnv.Add((string)(Pair.Key), (string)(Pair.Value));
                    }
                }

                int NumSortErrors = 0;
                for (int ActionIndex = 0; ActionIndex < InActions.Count; ActionIndex++)
                {
                    Action Action = InActions[ActionIndex];
                    foreach (FileItem Item in Action.PrerequisiteItems)
                    {
                        if (Item.ProducingAction != null && InActions.Contains(Item.ProducingAction))
                        {
                            int DepIndex = InActions.IndexOf(Item.ProducingAction);
                            if (DepIndex > ActionIndex)
                            {
                                //Console.WriteLine("Action is not topologically sorted.");
                                //Console.WriteLine("  {0} {1}", Action.CommandPath, Action.CommandArguments);
                                //Console.WriteLine("Dependency");
                                //Console.WriteLine("  {0} {1}", Item.ProducingAction.CommandPath, Item.ProducingAction.CommandArguments);
                                NumSortErrors++;
                            }
                        }
                    }
                }
                if (NumSortErrors > 0)
                {
                    //Console.WriteLine("The UBT action graph was not sorted. Sorting actions....");
                    Actions = new List <Action>();
                    HashSet <int> UsedActions = new HashSet <int>();
                    for (int ActionIndex = 0; ActionIndex < InActions.Count; ActionIndex++)
                    {
                        if (UsedActions.Contains(ActionIndex))
                        {
                            continue;
                        }
                        Action Action = InActions[ActionIndex];
                        foreach (FileItem Item in Action.PrerequisiteItems)
                        {
                            if (Item.ProducingAction != null && InActions.Contains(Item.ProducingAction))
                            {
                                int DepIndex = InActions.IndexOf(Item.ProducingAction);
                                if (UsedActions.Contains(DepIndex))
                                {
                                    continue;
                                }
                                Actions.Add(Item.ProducingAction);
                                UsedActions.Add(DepIndex);
                            }
                        }
                        Actions.Add(Action);
                        UsedActions.Add(ActionIndex);
                    }
                    for (int ActionIndex = 0; ActionIndex < Actions.Count; ActionIndex++)
                    {
                        Action Action = Actions[ActionIndex];
                        foreach (FileItem Item in Action.PrerequisiteItems)
                        {
                            if (Item.ProducingAction != null && Actions.Contains(Item.ProducingAction))
                            {
                                int DepIndex = Actions.IndexOf(Item.ProducingAction);
                                if (DepIndex > ActionIndex)
                                {
                                    Console.WriteLine("Action is not topologically sorted.");
                                    Console.WriteLine("  {0} {1}", Action.CommandPath, Action.CommandArguments);
                                    Console.WriteLine("Dependency");
                                    Console.WriteLine("  {0} {1}", Item.ProducingAction.CommandPath, Item.ProducingAction.CommandArguments);
                                    throw new BuildException("Cyclical Dependency in action graph.");
                                }
                            }
                        }
                    }
                }
            }


            XmlDocument XGETaskDocument = new XmlDocument();

            // <BuildSet FormatVersion="1">...</BuildSet>
            XmlElement BuildSetElement = XGETaskDocument.CreateElement("BuildSet");

            XGETaskDocument.AppendChild(BuildSetElement);
            BuildSetElement.SetAttribute("FormatVersion", "1");

            // <Environments>...</Environments>
            XmlElement EnvironmentsElement = XGETaskDocument.CreateElement("Environments");

            BuildSetElement.AppendChild(EnvironmentsElement);

            // <Environment Name="Default">...</CompileEnvironment>
            XmlElement EnvironmentElement = XGETaskDocument.CreateElement("Environment");

            EnvironmentsElement.AppendChild(EnvironmentElement);
            EnvironmentElement.SetAttribute("Name", "Default");

            // <Tools>...</Tools>
            XmlElement ToolsElement = XGETaskDocument.CreateElement("Tools");

            EnvironmentElement.AppendChild(ToolsElement);

            if (ExportEnv.Count > 0)
            {
                // <Variables>...</Variables>
                XmlElement VariablesElement = XGETaskDocument.CreateElement("Variables");
                EnvironmentElement.AppendChild(VariablesElement);

                foreach (KeyValuePair <string, string> Pair in ExportEnv)
                {
                    // <Variable>...</Variable>
                    XmlElement VariableElement = XGETaskDocument.CreateElement("Variable");
                    VariablesElement.AppendChild(VariableElement);
                    VariableElement.SetAttribute("Name", Pair.Key);
                    VariableElement.SetAttribute("Value", Pair.Value);
                }
            }

            for (int ActionIndex = 0; ActionIndex < Actions.Count; ActionIndex++)
            {
                Action Action = Actions[ActionIndex];

                // <Tool ... />
                XmlElement ToolElement = XGETaskDocument.CreateElement("Tool");
                ToolsElement.AppendChild(ToolElement);
                ToolElement.SetAttribute("Name", string.Format("Tool{0}", ActionIndex));
                ToolElement.SetAttribute("AllowRemote", Action.bCanExecuteRemotely.ToString());

                // The XGE documentation says that 'AllowIntercept' must be set to 'true' for all tools where 'AllowRemote' is enabled
                ToolElement.SetAttribute("AllowIntercept", Action.bCanExecuteRemotely.ToString());

                string OutputPrefix = "";
                if (bProgressMarkup)
                {
                    OutputPrefix += ProgressMarkupPrefix;
                }
                if (Action.bShouldOutputStatusDescription)
                {
                    OutputPrefix += Action.StatusDescription;
                }
                if (OutputPrefix.Length > 0)
                {
                    ToolElement.SetAttribute("OutputPrefix", OutputPrefix);
                }

                // When running on Windows, differentiate between .exe and batch files.
                // Those (.bat, .cmd) need to be run via cmd /c or shellexecute,
                // the latter which we can't use because we want to redirect input/output

                bool bLaunchViaCmdExe = (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64) && (!Path.GetExtension(Action.CommandPath).ToLower().EndsWith(".exe"));

                string CommandPath      = "";
                string CommandArguments = "";

                if (bLaunchViaCmdExe)
                {
                    CommandPath      = "cmd.exe";
                    CommandArguments = string.Format
                                       (
                        "/c \"\"{0}\" {1}\"",
                        (Action.CommandPath),
                        (Action.CommandArguments)
                                       );
                }
                else
                {
                    CommandPath      = Action.CommandPath;
                    CommandArguments = Action.CommandArguments;
                }

                ToolElement.SetAttribute("Params", CommandArguments);
                ToolElement.SetAttribute("Path", CommandPath);
                ToolElement.SetAttribute("SkipIfProjectFailed", "true");
                if (Action.bIsGCCCompiler)
                {
                    ToolElement.SetAttribute("AutoReserveMemory", "*.gch");
                }
                else
                {
                    ToolElement.SetAttribute("AutoReserveMemory", "*.pch");
                }
                ToolElement.SetAttribute(
                    "OutputFileMasks",
                    string.Join(
                        ",",
                        Action.ProducedItems.ConvertAll <string>(
                            delegate(FileItem ProducedItem) { return(ProducedItem.ToString()); }
                            ).ToArray()
                        )
                    );
            }

            // <Project Name="Default" Env="Default">...</Project>
            XmlElement ProjectElement = XGETaskDocument.CreateElement("Project");

            BuildSetElement.AppendChild(ProjectElement);
            ProjectElement.SetAttribute("Name", "Default");
            ProjectElement.SetAttribute("Env", "Default");

            for (int ActionIndex = 0; ActionIndex < Actions.Count; ActionIndex++)
            {
                Action Action = Actions[ActionIndex];

                // <Task ... />
                XmlElement TaskElement = XGETaskDocument.CreateElement("Task");
                ProjectElement.AppendChild(TaskElement);
                TaskElement.SetAttribute("SourceFile", "");
                if (!Action.bShouldOutputStatusDescription)
                {
                    // If we were configured to not output a status description, then we'll instead
                    // set 'caption' text for this task, so that the XGE coordinator has something
                    // to display within the progress bars.  For tasks that are outputting a
                    // description, XGE automatically displays that text in the progress bar, so we
                    // only need to do this for tasks that output their own progress.
                    TaskElement.SetAttribute("Caption", Action.StatusDescription);
                }
                TaskElement.SetAttribute("Name", string.Format("Action{0}", ActionIndex));
                TaskElement.SetAttribute("Tool", string.Format("Tool{0}", ActionIndex));
                TaskElement.SetAttribute("WorkingDir", Action.WorkingDirectory);
                TaskElement.SetAttribute("SkipIfProjectFailed", "true");

                // Create a semi-colon separated list of the other tasks this task depends on the results of.
                List <string> DependencyNames = new List <string>();
                foreach (FileItem Item in Action.PrerequisiteItems)
                {
                    if (Item.ProducingAction != null && Actions.Contains(Item.ProducingAction))
                    {
                        DependencyNames.Add(string.Format("Action{0}", Actions.IndexOf(Item.ProducingAction)));
                    }
                }

                if (DependencyNames.Count > 0)
                {
                    TaskElement.SetAttribute("DependsOn", string.Join(";", DependencyNames.ToArray()));
                }
            }

            // Write the XGE task XML to a temporary file.
            using (FileStream OutputFileStream = new FileStream(TaskFilePath, FileMode.Create, FileAccess.Write))
            {
                XGETaskDocument.Save(OutputFileStream);
            }
        }
Example #2
0
        /// <summary>
        /// Executes a list of actions.
        /// </summary>
        public static void ExecuteActions(BuildConfiguration BuildConfiguration, List <Action> ActionsToExecute, List <TargetDescriptor> TargetDescriptors = null)
        {
            Log.TraceInformation("Execute actions num:" + ActionsToExecute.Count + " target descriptors num:" + TargetDescriptors.Count);

            if (ActionsToExecute.Count == 0)
            {
                Log.TraceInformation("Target is up to date");
            }
            else
            {
                // Figure out which executor to use
                ActionExecutor Executor;
                if (BuildConfiguration.bAllowHybridExecutor && HybridExecutor.IsAvailable())
                {
                    Executor = new HybridExecutor();
                }
                else if (BuildConfiguration.bAllowXGE && XGE.IsAvailable())
                {
                    Executor = new XGE();
                }
                else if (BuildConfiguration.bAllowDistcc)
                {
                    Executor = new Distcc();
                }
                else if (BuildConfiguration.bAllowSNDBS && SNDBS.IsAvailable())
                {
                    Executor = new SNDBS();
                }
                else if (BuildConfiguration.bAllowParallelExecutor && ParallelExecutor.IsAvailable())
                {
                    Executor = new ParallelExecutor();
                }
                else
                {
                    Executor = new LocalExecutor();
                }


                //if (BuildConfiguration.bAllowFastBuild && FastBuild_v1.IsAvailable())
                //{
                //	Executor = new FastBuild_v1(Executor, TargetDescriptors);
                //}
                if (BuildConfiguration.bAllowFastBuild && FastBuild_v2.IsAvailable())
                {
                    Executor = new FastBuild_v2(Executor, TargetDescriptors);
                }

                // Execute the build
                Stopwatch Timer = Stopwatch.StartNew();
                if (!Executor.ExecuteActions(ActionsToExecute, BuildConfiguration.bLogDetailedActionStats))
                {
                    throw new CompilationResultException(CompilationResult.OtherCompilationError);
                }
                Log.TraceInformation("Total time in {0} executor: {1:0.00} seconds", Executor.Name, Timer.Elapsed.TotalSeconds);

                // Reset the file info for all the produced items
                foreach (Action BuildAction in ActionsToExecute)
                {
                    foreach (FileItem ProducedItem in BuildAction.ProducedItems)
                    {
                        ProducedItem.ResetCachedInfo();
                    }
                }

                // Verify the link outputs were created (seems to happen with Win64 compiles)
                foreach (Action BuildAction in ActionsToExecute)
                {
                    if (BuildAction.ActionType == ActionType.Link)
                    {
                        foreach (FileItem Item in BuildAction.ProducedItems)
                        {
                            if (!Item.Exists)
                            {
                                throw new BuildException("Failed to produce item: {0}", Item.AbsolutePath);
                            }
                        }
                    }
                }
            }
        }