Exemplo n.º 1
0
        /// <summary>
        /// Build a list of targets with a given set of makefiles.
        /// </summary>
        /// <param name="Makefiles">Makefiles created with CreateMakefiles</param>
        /// <param name="TargetDescriptors">Target descriptors</param>
        /// <param name="BuildConfiguration">Current build configuration</param>
        /// <param name="WorkingSet">The source file working set</param>
        /// <param name="Options">Additional options for the build</param>
        /// <param name="WriteOutdatedActionsFile">Files to write the list of outdated actions to (rather than building them)</param>
        /// <returns>Result from the compilation</returns>
        static void Build(TargetMakefile[] Makefiles, List <TargetDescriptor> TargetDescriptors, BuildConfiguration BuildConfiguration, ISourceFileWorkingSet WorkingSet, BuildOptions Options, FileReference WriteOutdatedActionsFile)
        {
            // Export the actions for each target
            for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++)
            {
                TargetDescriptor TargetDescriptor = TargetDescriptors[TargetIdx];
                foreach (FileReference WriteActionFile in TargetDescriptor.WriteActionFiles)
                {
                    Log.TraceInformation("Writing actions to {0}", WriteActionFile);
                    ActionGraph.ExportJson(Makefiles[TargetIdx].Actions, WriteActionFile);
                }
            }

            // Execute the build
            if ((Options & BuildOptions.SkipBuild) == 0)
            {
                // Make sure that none of the actions conflict with any other (producing output files differently, etc...)
                ActionGraph.CheckForConflicts(Makefiles.SelectMany(x => x.Actions));

                // Check we don't exceed the nominal max path length
                using (Timeline.ScopeEvent("ActionGraph.CheckPathLengths"))
                {
                    ActionGraph.CheckPathLengths(BuildConfiguration, Makefiles.SelectMany(x => x.Actions));
                }

                // Clean up any previous hot reload runs, and reapply the current state if it's already active
                for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++)
                {
                    HotReload.Setup(TargetDescriptors[TargetIdx], Makefiles[TargetIdx], BuildConfiguration);
                }

                // Merge the action graphs together
                List <Action> MergedActions;
                if (TargetDescriptors.Count == 1)
                {
                    MergedActions = new List <Action>(Makefiles[0].Actions);
                }
                else
                {
                    MergedActions = MergeActionGraphs(TargetDescriptors, Makefiles);
                }

                // Gather all the prerequisite actions that are part of the targets
                HashSet <FileItem> MergedOutputItems = new HashSet <FileItem>();
                for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++)
                {
                    GatherOutputItems(TargetDescriptors[TargetIdx], Makefiles[TargetIdx], MergedOutputItems);
                }

                // Link all the actions together
                ActionGraph.Link(MergedActions);

                // Get all the actions that are prerequisites for these targets. This forms the list of actions that we want executed.
                List <Action> PrerequisiteActions = ActionGraph.GatherPrerequisiteActions(MergedActions, MergedOutputItems);

                // Create the action history
                ActionHistory History = new ActionHistory();
                for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++)
                {
                    using (Timeline.ScopeEvent("Reading action history"))
                    {
                        TargetDescriptor TargetDescriptor = TargetDescriptors[TargetIdx];
                        if (TargetDescriptor.ProjectFile != null)
                        {
                            History.Mount(TargetDescriptor.ProjectFile.Directory);
                        }
                    }
                }

                // Figure out which actions need to be built
                Dictionary <Action, bool> ActionToOutdatedFlag = new Dictionary <Action, bool>();
                for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++)
                {
                    TargetDescriptor TargetDescriptor = TargetDescriptors[TargetIdx];

                    // Create the dependencies cache
                    CppDependencyCache CppDependencies;
                    using (Timeline.ScopeEvent("Reading dependency cache"))
                    {
                        CppDependencies = CppDependencyCache.CreateHierarchy(TargetDescriptor.ProjectFile, TargetDescriptor.Name, TargetDescriptor.Platform, TargetDescriptor.Configuration, Makefiles[TargetIdx].TargetType, TargetDescriptor.Architecture);
                    }

                    // Plan the actions to execute for the build. For single file compiles, always rebuild the source file regardless of whether it's out of date.
                    if (TargetDescriptor.SpecificFilesToCompile.Count == 0)
                    {
                        ActionGraph.GatherAllOutdatedActions(PrerequisiteActions, History, ActionToOutdatedFlag, CppDependencies, BuildConfiguration.bIgnoreOutdatedImportLibraries);
                    }
                    else
                    {
                        foreach (FileReference SpecificFile in TargetDescriptor.SpecificFilesToCompile)
                        {
                            foreach (Action PrerequisiteAction in PrerequisiteActions.Where(x => x.PrerequisiteItems.Any(y => y.Location == SpecificFile)))
                            {
                                ActionToOutdatedFlag[PrerequisiteAction] = true;
                            }
                        }
                    }
                }

                // Link the action graph again to sort it
                List <Action> MergedActionsToExecute = ActionToOutdatedFlag.Where(x => x.Value).Select(x => x.Key).ToList();
                ActionGraph.Link(MergedActionsToExecute);

                // Allow hot reload to override the actions
                int HotReloadTargetIdx = -1;
                for (int Idx = 0; Idx < TargetDescriptors.Count; Idx++)
                {
                    if (TargetDescriptors[Idx].HotReloadMode != HotReloadMode.Disabled)
                    {
                        if (HotReloadTargetIdx != -1)
                        {
                            throw new BuildException("Unable to perform hot reload with multiple targets.");
                        }
                        else
                        {
                            MergedActionsToExecute = HotReload.PatchActionsForTarget(BuildConfiguration, TargetDescriptors[Idx], Makefiles[Idx], PrerequisiteActions, MergedActionsToExecute);
                        }
                        HotReloadTargetIdx = Idx;
                    }
                }

                // Make sure we're not modifying any engine files
                if ((Options & BuildOptions.NoEngineChanges) != 0)
                {
                    List <FileItem> EngineChanges = MergedActionsToExecute.SelectMany(x => x.ProducedItems).Where(x => x.Location.IsUnderDirectory(UnrealBuildTool.EngineDirectory)).Distinct().OrderBy(x => x.FullName).ToList();
                    if (EngineChanges.Count > 0)
                    {
                        StringBuilder Result = new StringBuilder("Building would modify the following engine files:\n");
                        foreach (FileItem EngineChange in EngineChanges)
                        {
                            Result.AppendFormat("\n{0}", EngineChange.FullName);
                        }
                        Result.Append("\n\nPlease rebuild from an IDE instead.");
                        Log.TraceError("{0}", Result.ToString());
                        throw new CompilationResultException(CompilationResult.FailedDueToEngineChange);
                    }
                }

                // Make sure the appropriate executor is selected
                foreach (TargetDescriptor TargetDescriptor in TargetDescriptors)
                {
                    UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(TargetDescriptor.Platform);
                    BuildConfiguration.bAllowXGE    &= BuildPlatform.CanUseXGE();
                    BuildConfiguration.bAllowDistcc &= BuildPlatform.CanUseDistcc();
                    BuildConfiguration.bAllowSNDBS  &= BuildPlatform.CanUseSNDBS();
                }

                // Delete produced items that are outdated.
                ActionGraph.DeleteOutdatedProducedItems(MergedActionsToExecute);

                // Save all the action histories now that files have been removed. We have to do this after deleting produced items to ensure that any
                // items created during the build don't have the wrong command line.
                History.Save();

                // Create directories for the outdated produced items.
                ActionGraph.CreateDirectoriesForProducedItems(MergedActionsToExecute);

                // Execute the actions
                if ((Options & BuildOptions.XGEExport) != 0)
                {
                    OutputToolchainInfo(TargetDescriptors, Makefiles);

                    // Just export to an XML file
                    using (Timeline.ScopeEvent("XGE.ExportActions()"))
                    {
                        XGE.ExportActions(MergedActionsToExecute);
                    }
                }
                else if (WriteOutdatedActionsFile != null)
                {
                    OutputToolchainInfo(TargetDescriptors, Makefiles);

                    // Write actions to an output file
                    using (Timeline.ScopeEvent("ActionGraph.WriteActions"))
                    {
                        ActionGraph.ExportJson(MergedActionsToExecute, WriteOutdatedActionsFile);
                    }
                }
                else
                {
                    // Execute the actions
                    if (MergedActionsToExecute.Count == 0)
                    {
                        if (TargetDescriptors.Any(x => !x.bQuiet))
                        {
                            Log.TraceInformation((TargetDescriptors.Count == 1)? "Target is up to date" : "Targets are up to date");
                        }
                    }
                    else
                    {
                        if (TargetDescriptors.Any(x => !x.bQuiet))
                        {
                            Log.TraceInformation("Building {0}...", StringUtils.FormatList(TargetDescriptors.Select(x => x.Name).Distinct()));
                        }

                        OutputToolchainInfo(TargetDescriptors, Makefiles);

                        using (Timeline.ScopeEvent("ActionGraph.ExecuteActions()"))
                        {
                            ActionGraph.ExecuteActions(BuildConfiguration, MergedActionsToExecute);
                        }
                    }

                    // Run the deployment steps
                    foreach (TargetMakefile Makefile in Makefiles)
                    {
                        if (Makefile.bDeployAfterCompile)
                        {
                            TargetReceipt Receipt = TargetReceipt.Read(Makefile.ReceiptFile);
                            Log.TraceInformation("Deploying {0} {1} {2}...", Receipt.TargetName, Receipt.Platform, Receipt.Configuration);

                            UEBuildPlatform.GetBuildPlatform(Receipt.Platform).Deploy(Receipt);
                        }
                    }
                }
            }
        }