public override void FinalizeOutput(ReadOnlyTargetRules Target, List <FileItem> OutputItems, ActionGraph ActionGraph)
        {
            FileReference OutputFile;

            if (Target.ProjectFile == null)
            {
                OutputFile = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Saved", "PVS-Studio", String.Format("{0}.pvslog", Target.Name));
            }
            else
            {
                OutputFile = FileReference.Combine(Target.ProjectFile.Directory, "Saved", "PVS-Studio", String.Format("{0}.pvslog", Target.Name));
            }

            List <FileReference> InputFiles = OutputItems.Select(x => x.Reference).ToList();

            Action AnalyzeAction = ActionGraph.Add(ActionType.Compile);

            AnalyzeAction.CommandPath        = "Dummy.exe";
            AnalyzeAction.CommandArguments   = "";
            AnalyzeAction.CommandDescription = "Combining output from PVS-Studio";
            AnalyzeAction.WorkingDirectory   = UnrealBuildTool.EngineSourceDirectory.FullName;
            AnalyzeAction.PrerequisiteItems.AddRange(OutputItems);
            AnalyzeAction.ProducedItems.Add(FileItem.GetItemByFileReference(OutputFile));
            AnalyzeAction.ActionHandler = (Action Action, out int ExitCode, out string Output) => WriteResults(OutputFile, InputFiles, out ExitCode, out Output);
            AnalyzeAction.bShouldDeleteProducedItems = true;

            OutputItems.AddRange(AnalyzeAction.ProducedItems);
        }
Example #2
0
 public abstract CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List <FileItem> InputFiles, DirectoryReference OutputDir, string ModuleName, ActionGraph ActionGraph);
Example #3
0
 public abstract FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, ActionGraph ActionGraph);
        public virtual CPPOutput CompileRCFiles(CppCompileEnvironment Environment, List <FileItem> RCFiles, ActionGraph ActionGraph)
        {
            CPPOutput Result = new CPPOutput();

            return(Result);
        }
 public virtual ICollection <FileItem> PostBuild(FileItem Executable, LinkEnvironment ExecutableLinkEnvironment, ActionGraph ActionGraph)
 {
     return(new List <FileItem>());
 }
 // UEBuildModule interface.
 public override List <FileItem> Compile(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ISourceFileWorkingSet WorkingSet, ActionGraph ActionGraph)
 {
     return(new List <FileItem>());
 }
Example #7
0
        /// <summary>
        /// Determine what needs to be built for a target
        /// </summary>
        /// <param name="BuildConfiguration">The build configuration</param>
        /// <param name="TargetDescriptor">Target being built</param>
        /// <param name="Makefile">Makefile generated for this target</param>
        /// <returns>Set of actions to execute</returns>
        static HashSet <Action> GetActionsForTarget(BuildConfiguration BuildConfiguration, TargetDescriptor TargetDescriptor, TargetMakefile Makefile)
        {
            // Create the action graph
            ActionGraph.Link(Makefile.Actions);

            // Get the hot-reload mode
            HotReloadMode HotReloadMode = TargetDescriptor.HotReloadMode;

            if (HotReloadMode == HotReloadMode.Default)
            {
                if (TargetDescriptor.HotReloadModuleNameToSuffix.Count > 0 && TargetDescriptor.ForeignPlugin == null)
                {
                    HotReloadMode = HotReloadMode.FromEditor;
                }
                else if (BuildConfiguration.bAllowHotReloadFromIDE && HotReload.ShouldDoHotReloadFromIDE(BuildConfiguration, TargetDescriptor))
                {
                    HotReloadMode = HotReloadMode.FromIDE;
                }
                else
                {
                    HotReloadMode = HotReloadMode.Disabled;
                }
            }

            // Guard against a live coding session for this target being active
            if (HotReloadMode != HotReloadMode.LiveCoding && TargetDescriptor.ForeignPlugin == null && HotReload.IsLiveCodingSessionActive(Makefile))
            {
                throw new BuildException("Unable to start regular build while Live Coding is active. Press Ctrl+Alt+F11 to trigger a Live Coding compile.");
            }

            // Get the root prerequisite actions
            List <Action> PrerequisiteActions = GatherPrerequisiteActions(TargetDescriptor, Makefile);

            // Get the path to the hot reload state file for this target
            FileReference HotReloadStateFile = global::UnrealBuildTool.HotReloadState.GetLocation(TargetDescriptor.ProjectFile, TargetDescriptor.Name, TargetDescriptor.Platform, TargetDescriptor.Configuration, TargetDescriptor.Architecture);

            // Apply the previous hot reload state
            HotReloadState HotReloadState = null;

            if (HotReloadMode == HotReloadMode.Disabled)
            {
                // Make sure we're not doing a partial build from the editor (eg. compiling a new plugin)
                if (TargetDescriptor.ForeignPlugin == null && TargetDescriptor.SingleFileToCompile == null)
                {
                    // Delete the previous state file
                    HotReload.DeleteTemporaryFiles(HotReloadStateFile);
                }
            }
            else
            {
                // Read the previous state file and apply it to the action graph
                if (FileReference.Exists(HotReloadStateFile))
                {
                    HotReloadState = HotReloadState.Load(HotReloadStateFile);
                }
                else
                {
                    HotReloadState = new HotReloadState();
                }

                // Apply the old state to the makefile
                HotReload.ApplyState(HotReloadState, Makefile);

                // If we want a specific suffix on any modules, apply that now. We'll track the outputs later, but the suffix has to be forced (and is always out of date if it doesn't exist).
                HotReload.PatchActionGraphWithNames(PrerequisiteActions, TargetDescriptor.HotReloadModuleNameToSuffix, Makefile);

                // Re-link the action graph
                ActionGraph.Link(PrerequisiteActions);
            }

            // Create the dependencies cache
            CppDependencyCache CppDependencies;

            using (Timeline.ScopeEvent("Reading dependency cache"))
            {
                CppDependencies = CppDependencyCache.CreateHierarchy(TargetDescriptor.ProjectFile, TargetDescriptor.Name, TargetDescriptor.Platform, TargetDescriptor.Configuration, Makefile.TargetType, TargetDescriptor.Architecture);
            }

            // Create the action history
            ActionHistory History;

            using (Timeline.ScopeEvent("Reading action history"))
            {
                History = ActionHistory.CreateHierarchy(TargetDescriptor.ProjectFile, TargetDescriptor.Name, TargetDescriptor.Platform, Makefile.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.
            HashSet <Action> TargetActionsToExecute;

            if (TargetDescriptor.SingleFileToCompile == null)
            {
                TargetActionsToExecute = ActionGraph.GetActionsToExecute(Makefile.Actions, PrerequisiteActions, CppDependencies, History, BuildConfiguration.bIgnoreOutdatedImportLibraries);
            }
            else
            {
                TargetActionsToExecute = new HashSet <Action>(PrerequisiteActions);
            }

            // Additional processing for hot reload
            if (HotReloadMode == HotReloadMode.LiveCoding)
            {
                // Make sure we're not overwriting any lazy-loaded modules
                if (TargetDescriptor.LiveCodingModules != null)
                {
                    // Read the list of modules that we're allowed to build
                    string[] Lines = FileReference.ReadAllLines(TargetDescriptor.LiveCodingModules);

                    // Parse it out into a set of filenames
                    HashSet <string> AllowedOutputFileNames = new HashSet <string>(FileReference.Comparer);
                    foreach (string Line in Lines)
                    {
                        string TrimLine = Line.Trim();
                        if (TrimLine.Length > 0)
                        {
                            AllowedOutputFileNames.Add(Path.GetFileName(TrimLine));
                        }
                    }

                    // Find all the binaries that we're actually going to build
                    HashSet <FileReference> OutputFiles = new HashSet <FileReference>();
                    foreach (Action Action in TargetActionsToExecute)
                    {
                        if (Action.ActionType == ActionType.Link)
                        {
                            OutputFiles.UnionWith(Action.ProducedItems.Where(x => x.HasExtension(".exe") || x.HasExtension(".dll")).Select(x => x.Location));
                        }
                    }

                    // Find all the files that will be built that aren't allowed
                    List <FileReference> ProtectedOutputFiles = OutputFiles.Where(x => !AllowedOutputFileNames.Contains(x.GetFileName())).ToList();
                    if (ProtectedOutputFiles.Count > 0)
                    {
                        FileReference.WriteAllLines(new FileReference(TargetDescriptor.LiveCodingModules.FullName + ".out"), ProtectedOutputFiles.Select(x => x.ToString()));
                        foreach (FileReference ProtectedOutputFile in ProtectedOutputFiles)
                        {
                            Log.TraceInformation("Module {0} is not currently enabled for Live Coding", ProtectedOutputFile);
                        }
                        throw new CompilationResultException(CompilationResult.Canceled);
                    }
                }

                // Filter the prerequisite actions down to just the compile actions, then recompute all the actions to execute
                PrerequisiteActions    = new List <Action>(TargetActionsToExecute.Where(x => x.ActionType == ActionType.Compile));
                TargetActionsToExecute = ActionGraph.GetActionsToExecute(Makefile.Actions, PrerequisiteActions, CppDependencies, History, BuildConfiguration.bIgnoreOutdatedImportLibraries);

                // Update the action graph with these new paths
                Dictionary <FileReference, FileReference> OriginalFileToPatchedFile = new Dictionary <FileReference, FileReference>();
                HotReload.PatchActionGraphForLiveCoding(PrerequisiteActions, OriginalFileToPatchedFile);

                // Get a new list of actions to execute now that the graph has been modified
                TargetActionsToExecute = ActionGraph.GetActionsToExecute(Makefile.Actions, PrerequisiteActions, CppDependencies, History, BuildConfiguration.bIgnoreOutdatedImportLibraries);

                // Output the Live Coding manifest
                if (TargetDescriptor.LiveCodingManifest != null)
                {
                    HotReload.WriteLiveCodingManifest(TargetDescriptor.LiveCodingManifest, Makefile.Actions, OriginalFileToPatchedFile);
                }
            }
            else if (HotReloadMode == HotReloadMode.FromEditor || HotReloadMode == HotReloadMode.FromIDE)
            {
                // Patch action history for hot reload when running in assembler mode.  In assembler mode, the suffix on the output file will be
                // the same for every invocation on that makefile, but we need a new suffix each time.

                // For all the hot-reloadable modules that may need a unique suffix appended, build a mapping from output item to all the output items in that module. We can't
                // apply a suffix to one without applying a suffix to all of them.
                Dictionary <FileItem, FileItem[]> HotReloadItemToDependentItems = new Dictionary <FileItem, FileItem[]>();
                foreach (string HotReloadModuleName in Makefile.HotReloadModuleNames)
                {
                    int ModuleSuffix;
                    if (!TargetDescriptor.HotReloadModuleNameToSuffix.TryGetValue(HotReloadModuleName, out ModuleSuffix) || ModuleSuffix == -1)
                    {
                        FileItem[] ModuleOutputItems;
                        if (Makefile.ModuleNameToOutputItems.TryGetValue(HotReloadModuleName, out ModuleOutputItems))
                        {
                            foreach (FileItem ModuleOutputItem in ModuleOutputItems)
                            {
                                HotReloadItemToDependentItems[ModuleOutputItem] = ModuleOutputItems;
                            }
                        }
                    }
                }

                // Expand the list of actions to execute to include everything that references any files with a new suffix. Unlike a regular build, we can't ignore
                // dependencies on import libraries under the assumption that a header would change if the API changes, because the dependency will be on a different DLL.
                HashSet <FileItem> FilesRequiringSuffix = new HashSet <FileItem>(TargetActionsToExecute.SelectMany(x => x.ProducedItems).Where(x => HotReloadItemToDependentItems.ContainsKey(x)));
                for (int LastNumFilesWithNewSuffix = 0; FilesRequiringSuffix.Count > LastNumFilesWithNewSuffix;)
                {
                    LastNumFilesWithNewSuffix = FilesRequiringSuffix.Count;
                    foreach (Action PrerequisiteAction in PrerequisiteActions)
                    {
                        if (!TargetActionsToExecute.Contains(PrerequisiteAction))
                        {
                            foreach (FileItem ProducedItem in PrerequisiteAction.ProducedItems)
                            {
                                FileItem[] DependentItems;
                                if (HotReloadItemToDependentItems.TryGetValue(ProducedItem, out DependentItems))
                                {
                                    TargetActionsToExecute.Add(PrerequisiteAction);
                                    FilesRequiringSuffix.UnionWith(DependentItems);
                                }
                            }
                        }
                    }
                }

                // Build a list of file mappings
                Dictionary <FileReference, FileReference> OldLocationToNewLocation = new Dictionary <FileReference, FileReference>();
                foreach (FileItem FileRequiringSuffix in FilesRequiringSuffix)
                {
                    FileReference OldLocation = FileRequiringSuffix.Location;
                    FileReference NewLocation = HotReload.ReplaceSuffix(OldLocation, HotReloadState.NextSuffix);
                    OldLocationToNewLocation[OldLocation] = NewLocation;
                }

                // Update the action graph with these new paths
                HotReload.PatchActionGraph(PrerequisiteActions, OldLocationToNewLocation);

                // Get a new list of actions to execute now that the graph has been modified
                TargetActionsToExecute = ActionGraph.GetActionsToExecute(Makefile.Actions, PrerequisiteActions, CppDependencies, History, BuildConfiguration.bIgnoreOutdatedImportLibraries);

                // Build a mapping of all file items to their original
                Dictionary <FileReference, FileReference> HotReloadFileToOriginalFile = new Dictionary <FileReference, FileReference>();
                foreach (KeyValuePair <FileReference, FileReference> Pair in HotReloadState.OriginalFileToHotReloadFile)
                {
                    HotReloadFileToOriginalFile[Pair.Value] = Pair.Key;
                }
                foreach (KeyValuePair <FileReference, FileReference> Pair in OldLocationToNewLocation)
                {
                    FileReference OriginalLocation;
                    if (!HotReloadFileToOriginalFile.TryGetValue(Pair.Key, out OriginalLocation))
                    {
                        OriginalLocation = Pair.Key;
                    }
                    HotReloadFileToOriginalFile[Pair.Value] = OriginalLocation;
                }

                // Now filter out all the hot reload files and update the state
                foreach (Action Action in TargetActionsToExecute)
                {
                    foreach (FileItem ProducedItem in Action.ProducedItems)
                    {
                        FileReference OriginalLocation;
                        if (HotReloadFileToOriginalFile.TryGetValue(ProducedItem.Location, out OriginalLocation))
                        {
                            HotReloadState.OriginalFileToHotReloadFile[OriginalLocation] = ProducedItem.Location;
                            HotReloadState.TemporaryFiles.Add(ProducedItem.Location);
                        }
                    }
                }

                // Increment the suffix for the next iteration
                if (TargetActionsToExecute.Count > 0)
                {
                    HotReloadState.NextSuffix++;
                }

                // Save the new state
                HotReloadState.Save(HotReloadStateFile);

                // Prevent this target from deploying
                Makefile.bDeployAfterCompile = false;
            }

            return(TargetActionsToExecute);
        }
Example #8
0
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, ActionGraph ActionGraph)
        {
            FileItem OutputFile;

            // Make the final javascript file
            Action LinkAction = ActionGraph.Add(ActionType.Link);

            LinkAction.CommandDescription = "Link";
//			LinkAction.bPrintDebugInfo = true;

            // ResponseFile lines.
            List <string> ReponseLines = new List <string>();

            LinkAction.bCanExecuteRemotely = false;
            LinkAction.WorkingDirectory    = UnrealBuildTool.EngineSourceDirectory.FullName;
            LinkAction.CommandPath         = HTML5SDKInfo.Python();
            LinkAction.CommandArguments    = HTML5SDKInfo.EmscriptenCompiler();
//			bool bIsBuildingLibrary = LinkEnvironment.bIsBuildingLibrary || bBuildImportLibraryOnly;
//			ReponseLines.Add(
//					bIsBuildingLibrary ?
//					GetLibArguments(LinkEnvironment) :
//					GetLinkArguments(LinkEnvironment)
//				);
            ReponseLines.Add(GetLinkArguments(LinkEnvironment));

            // Add the input files to a response file, and pass the response file on the command-line.
            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                //System.Console.WriteLine("File  {0} ", InputFile.AbsolutePath);
                ReponseLines.Add(string.Format(" \"{0}\"", InputFile.AbsolutePath));
                LinkAction.PrerequisiteItems.Add(InputFile);
            }

            if (!LinkEnvironment.bIsBuildingLibrary)
            {
                // Make sure ThirdParty libs are at the end.
                List <string> ThirdParty = (from Lib in LinkEnvironment.AdditionalLibraries
                                            where Lib.Contains("ThirdParty")
                                            select Lib).ToList();

                LinkEnvironment.AdditionalLibraries.RemoveAll(Element => Element.Contains("ThirdParty"));
                LinkEnvironment.AdditionalLibraries.AddRange(ThirdParty);

                foreach (string InputFile in LinkEnvironment.AdditionalLibraries)
                {
                    FileItem Item = FileItem.GetItemByPath(InputFile);

                    if (Item.AbsolutePath.Contains(".lib"))
                    {
                        continue;
                    }

                    if (Item.ToString().EndsWith(".js"))
                    {
                        ReponseLines.Add(string.Format(" --js-library \"{0}\"", Item.AbsolutePath));
                    }


                    // WARNING: With --pre-js and --post-js, the order in which these directives are passed to
                    // the compiler is very critical, because that dictates the order in which they are appended.
                    //
                    // Set environment variable [ EMCC_DEBUG=1 ] to see the linker order used in packaging.
                    //     See GetSharedArguments_Global() above to set this environment variable

                    else if (Item.ToString().EndsWith(".jspre"))
                    {
                        ReponseLines.Add(string.Format(" --pre-js \"{0}\"", Item.AbsolutePath));
                    }

                    else if (Item.ToString().EndsWith(".jspost"))
                    {
                        ReponseLines.Add(string.Format(" --post-js \"{0}\"", Item.AbsolutePath));
                    }


                    else
                    {
                        ReponseLines.Add(string.Format(" \"{0}\"", Item.AbsolutePath));
                    }

                    LinkAction.PrerequisiteItems.Add(Item);
                }
            }
            // make the file we will create


            OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.OutputFilePath);
            LinkAction.ProducedItems.Add(OutputFile);
            ReponseLines.Add(string.Format(" -o \"{0}\"", OutputFile.AbsolutePath));

            FileItem OutputBC = FileItem.GetItemByPath(LinkEnvironment.OutputFilePath.FullName.Replace(".js", ".bc").Replace(".html", ".bc"));

            LinkAction.ProducedItems.Add(OutputBC);
            ReponseLines.Add(string.Format(" --save-bc \"{0}\"", OutputBC.AbsolutePath));

            LinkAction.StatusDescription = Path.GetFileName(OutputFile.AbsolutePath);

            FileReference ResponseFileName = GetResponseFileName(LinkEnvironment, OutputFile);

            FileItem ResponseFileItem = FileItem.CreateIntermediateTextFile(ResponseFileName, ReponseLines);

            LinkAction.CommandArguments += string.Format(" @\"{0}\"", ResponseFileName);
            LinkAction.PrerequisiteItems.Add(ResponseFileItem);

            return(OutputFile);
        }
Example #9
0
        /// <summary>
        /// Builds the binary.
        /// </summary>
        /// <param name="Target">Rules for the target being built</param>
        /// <param name="ToolChain">The toolchain which to use for building</param>
        /// <param name="CompileEnvironment">The environment to compile the binary in</param>
        /// <param name="LinkEnvironment">The environment to link the binary in</param>
        /// <param name="SharedPCHs">List of templates for shared PCHs</param>
        /// <param name="WorkingSet">The working set of source files</param>
        /// <param name="ExeDir">Directory containing the output executable</param>
        /// <param name="ActionGraph">Graph to add build actions to</param>
        /// <returns>Set of built products</returns>
        public IEnumerable <FileItem> Build(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ISourceFileWorkingSet WorkingSet, DirectoryReference ExeDir, ActionGraph ActionGraph)
        {
            // Return nothing if we're using precompiled binaries. If we're not linking, we might want just one module to be compiled (eg. a foreign plugin), so allow any actions to run.
            if (bUsePrecompiled && !Target.bDisableLinking)
            {
                return(new List <FileItem>());
            }

            // Setup linking environment.
            LinkEnvironment BinaryLinkEnvironment = SetupBinaryLinkEnvironment(Target, ToolChain, LinkEnvironment, CompileEnvironment, SharedPCHs, WorkingSet, ExeDir, ActionGraph);

            // If we're generating projects, we only need include paths and definitions, there is no need to run the linking logic.
            if (ProjectFileGenerator.bGenerateProjectFiles)
            {
                return(BinaryLinkEnvironment.InputFiles);
            }

            // If linking is disabled, our build products are just the compiled object files
            if (Target.bDisableLinking)
            {
                return(BinaryLinkEnvironment.InputFiles);
            }

            // Generate import libraries as a separate step
            List <FileItem> OutputFiles = new List <FileItem>();

            if (bCreateImportLibrarySeparately)
            {
                // Mark the link environment as cross-referenced.
                BinaryLinkEnvironment.bIsCrossReferenced = true;

                if (BinaryLinkEnvironment.Platform != CppPlatform.Mac && BinaryLinkEnvironment.Platform != CppPlatform.Linux)
                {
                    // Create the import library.
                    OutputFiles.AddRange(ToolChain.LinkAllFiles(BinaryLinkEnvironment, true, ActionGraph));
                }
            }

            // Link the binary.
            FileItem[] Executables = ToolChain.LinkAllFiles(BinaryLinkEnvironment, false, ActionGraph);
            OutputFiles.AddRange(Executables);

            // Produce additional console app if requested
            if (bBuildAdditionalConsoleApp)
            {
                // Produce additional binary but link it as a console app
                LinkEnvironment ConsoleAppLinkEvironment = new LinkEnvironment(BinaryLinkEnvironment);
                ConsoleAppLinkEvironment.bIsBuildingConsoleApplication = true;
                ConsoleAppLinkEvironment.WindowsEntryPointOverride     = "WinMainCRTStartup";                           // For WinMain() instead of "main()" for Launch module
                ConsoleAppLinkEvironment.OutputFilePaths = ConsoleAppLinkEvironment.OutputFilePaths.Select(Path => GetAdditionalConsoleAppPath(Path)).ToList();

                // Link the console app executable
                OutputFiles.AddRange(ToolChain.LinkAllFiles(ConsoleAppLinkEvironment, false, ActionGraph));
            }

            foreach (FileItem Executable in Executables)
            {
                OutputFiles.AddRange(ToolChain.PostBuild(Executable, BinaryLinkEnvironment, ActionGraph));
            }

            return(OutputFiles);
        }
Example #10
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);
                        }
                    }
                }
            }
        }
Example #11
0
        public override CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List <FileItem> InputFiles, DirectoryReference OutputDir, string ModuleName, ActionGraph ActionGraph)
        {
            string Arguments = GetCLArguments_Global(CompileEnvironment);

            CPPOutput Result = new CPPOutput();

            // Add include paths to the argument list.
            foreach (DirectoryReference IncludePath in CompileEnvironment.IncludePaths.UserIncludePaths)
            {
                AddIncludePath(ref Arguments, IncludePath);
            }
            foreach (DirectoryReference IncludePath in CompileEnvironment.IncludePaths.SystemIncludePaths)
            {
                AddIncludePath(ref Arguments, IncludePath);
            }


            // Add preprocessor definitions to the argument list.
            foreach (string Definition in CompileEnvironment.Definitions)
            {
                Arguments += string.Format(" -D{0}", Definition);
            }

            if (bEnableTracing)
            {
                Arguments += string.Format(" -D__EMSCRIPTEN_TRACING__");
            }

            // Force include all the requested headers
            foreach (FileItem ForceIncludeFile in CompileEnvironment.ForceIncludeFiles)
            {
                Arguments += String.Format(" -include \"{0}\"", ForceIncludeFile.Location);
            }

            foreach (FileItem SourceFile in InputFiles)
            {
                Action CompileAction = ActionGraph.Add(ActionType.Compile);
                CompileAction.CommandDescription = "Compile";
                CompileAction.PrerequisiteItems.AddRange(CompileEnvironment.ForceIncludeFiles);
//				CompileAction.bPrintDebugInfo = true;

                bool bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C";

                // Add the C++ source file and its included files to the prerequisite item list.
                AddPrerequisiteSourceFile(CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems);

                // Add the source file path to the command-line.
                string FileArguments = string.Format(" \"{0}\"", SourceFile.AbsolutePath);
                // Add the object file to the produced item list.
                FileItem ObjectFile = FileItem.GetItemByFileReference(FileReference.Combine(OutputDir, Path.GetFileName(SourceFile.AbsolutePath) + ".bc"));
                CompileAction.ProducedItems.Add(ObjectFile);
                FileArguments += string.Format(" -o \"{0}\"", ObjectFile.AbsolutePath);

                // Add C or C++ specific compiler arguments.
                if (bIsPlainCFile)
                {
                    FileArguments += GetCLArguments_C(CompileEnvironment.Architecture);
                }
                else
                {
                    FileArguments += GetCLArguments_CPP(CompileEnvironment);
                }

                CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName;
                CompileAction.CommandPath      = HTML5SDKInfo.Python();

                CompileAction.CommandArguments = HTML5SDKInfo.EmscriptenCompiler() + " " + Arguments + FileArguments + CompileEnvironment.AdditionalArguments;

                //System.Console.WriteLine(CompileAction.CommandArguments);
                CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath);

                // Don't farm out creation of precomputed headers as it is the critical path task.
                CompileAction.bCanExecuteRemotely = CompileEnvironment.PrecompiledHeaderAction != PrecompiledHeaderAction.Create;

                // this is the final output of the compile step (a .abc file)
                Result.ObjectFiles.Add(ObjectFile);

                // VC++ always outputs the source file name being compiled, so we don't need to emit this ourselves
                CompileAction.bShouldOutputStatusDescription = true;

                // Don't farm out creation of precompiled headers as it is the critical path task.
                CompileAction.bCanExecuteRemotely =
                    CompileEnvironment.PrecompiledHeaderAction != PrecompiledHeaderAction.Create ||
                    CompileEnvironment.bAllowRemotelyCompiledPCHs;
            }

            return(Result);
        }
        private List <FileItem> SetupOutputFiles(UEToolChain ToolChain, CppCompileEnvironment BinaryCompileEnvironment, LinkEnvironment BinaryLinkEnvironment, ActionGraph ActionGraph)
        {
            //
            // Regular linking action.
            //
            List <FileItem> OutputFiles = new List <FileItem>();

            if (bCreateImportLibrarySeparately)
            {
                // Mark the link environment as cross-referenced.
                BinaryLinkEnvironment.bIsCrossReferenced = true;

                if (BinaryLinkEnvironment.Platform != CppPlatform.Mac && BinaryLinkEnvironment.Platform != CppPlatform.Linux)
                {
                    // Create the import library.
                    OutputFiles.AddRange(ToolChain.LinkAllFiles(BinaryLinkEnvironment, true, ActionGraph));
                }
            }

            BinaryLinkEnvironment.bIncludeDependentLibrariesInLibrary = bIncludeDependentLibrariesInLibrary;

            // Link the binary.
            FileItem[] Executables = ToolChain.LinkAllFiles(BinaryLinkEnvironment, false, ActionGraph);
            OutputFiles.AddRange(Executables);

            // Produce additional console app if requested
            if (Config.bBuildAdditionalConsoleApp)
            {
                // Produce additional binary but link it as a console app
                LinkEnvironment ConsoleAppLinkEvironment = new LinkEnvironment(BinaryLinkEnvironment);
                ConsoleAppLinkEvironment.bIsBuildingConsoleApplication = true;
                ConsoleAppLinkEvironment.WindowsEntryPointOverride     = "WinMainCRTStartup";                           // For WinMain() instead of "main()" for Launch module
                ConsoleAppLinkEvironment.OutputFilePaths = ConsoleAppLinkEvironment.OutputFilePaths.Select(Path => GetAdditionalConsoleAppPath(Path)).ToList();

                // Link the console app executable
                OutputFiles.AddRange(ToolChain.LinkAllFiles(ConsoleAppLinkEvironment, false, ActionGraph));
            }

            foreach (FileItem Executable in Executables)
            {
                OutputFiles.AddRange(ToolChain.PostBuild(Executable, BinaryLinkEnvironment, ActionGraph));
            }

            return(OutputFiles);
        }
        /// <summary>
        /// Builds the binary.
        /// </summary>
        /// <param name="Target">The target rules</param>
        /// <param name="ToolChain">The toolchain to use for building</param>
        /// <param name="CompileEnvironment">The environment to compile the binary in</param>
        /// <param name="LinkEnvironment">The environment to link the binary in</param>
        /// <param name="SharedPCHs">List of available shared PCHs</param>
        /// <param name="ActionGraph">The graph to add build actions to</param>
        /// <returns>Set of build products</returns>
        public override IEnumerable <FileItem> Build(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ActionGraph ActionGraph)
        {
            // Setup linking environment.
            LinkEnvironment BinaryLinkEnvironment = SetupBinaryLinkEnvironment(Target, ToolChain, LinkEnvironment, CompileEnvironment, SharedPCHs, ActionGraph);

            // If we're generating projects, we only need include paths and definitions, there is no need to run the linking logic.
            if (ProjectFileGenerator.bGenerateProjectFiles)
            {
                return(BinaryLinkEnvironment.InputFiles);
            }

            // If linking is disabled, our build products are just the compiled object files
            if (Target.bDisableLinking)
            {
                return(BinaryLinkEnvironment.InputFiles);
            }

            // Return linked files.
            return(SetupOutputFiles(ToolChain, CompileEnvironment, BinaryLinkEnvironment, ActionGraph));
        }
        public override CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName, ActionGraph ActionGraph)
        {
            VCEnvironment EnvVars = VCEnvironment.SetEnvironment(CppPlatform, Compiler);

            // Get the MSVC arguments required to compile all files in this batch
            List <string> SharedArguments = new List <string>();

            SharedArguments.Add("/nologo");
            SharedArguments.Add("/P");             // Preprocess
            SharedArguments.Add("/C");             // Preserve comments when preprocessing
            SharedArguments.Add("/D PVS_STUDIO");
            SharedArguments.Add("/wd4005");
            foreach (string IncludePath in CompileEnvironment.IncludePaths.UserIncludePaths)
            {
                SharedArguments.Add(String.Format("/I \"{0}\"", GetFullIncludePath(IncludePath)));
            }
            foreach (string IncludePath in CompileEnvironment.IncludePaths.SystemIncludePaths)
            {
                SharedArguments.Add(String.Format("/I \"{0}\"", GetFullIncludePath(IncludePath)));
            }
            foreach (string Definition in CompileEnvironment.Definitions)
            {
                SharedArguments.Add(String.Format("/D \"{0}\"", Definition));
            }

            // Get the path to PVS studio
            FileReference AnalyzerFile = new FileReference(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "PVS-Studio", "x64", "PVS-Studio.exe"));

            if (!FileReference.Exists(AnalyzerFile))
            {
                throw new BuildException("Unable to find PVS-Studio at {0}", AnalyzerFile);
            }

            CPPOutput Result = new CPPOutput();

            foreach (FileItem SourceFile in SourceFiles)
            {
                // Get the file names for everything we need
                string BaseFileName = SourceFile.Reference.GetFileName();

                // Write the response file
                FileReference PreprocessedFileLocation = FileReference.Combine(CompileEnvironment.OutputDirectory, BaseFileName + ".i");

                List <string> Arguments = new List <string>(SharedArguments);
                Arguments.Add(String.Format("/Fi\"{0}\"", PreprocessedFileLocation));                 // Preprocess to a file
                Arguments.Add(String.Format("\"{0}\"", SourceFile.AbsolutePath));

                FileReference ResponseFileLocation = FileReference.Combine(CompileEnvironment.OutputDirectory, BaseFileName + ".i.response");
                FileItem      ResponseFileItem     = FileItem.CreateIntermediateTextFile(ResponseFileLocation, String.Join("\n", Arguments));

                // Preprocess the source file
                FileItem PreprocessedFileItem = FileItem.GetItemByFileReference(PreprocessedFileLocation);

                Action PreprocessAction = ActionGraph.Add(ActionType.Compile);
                PreprocessAction.CommandPath      = EnvVars.CompilerPath.FullName;
                PreprocessAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName;
                PreprocessAction.CommandArguments = " @\"" + ResponseFileItem.AbsolutePath + "\"";
                PreprocessAction.PrerequisiteItems.Add(SourceFile);
                PreprocessAction.PrerequisiteItems.Add(ResponseFileItem);
                PreprocessAction.ProducedItems.Add(PreprocessedFileItem);
                PreprocessAction.bShouldOutputStatusDescription = false;

                // Write the PVS studio config file
                StringBuilder ConfigFileContents = new StringBuilder();
                ConfigFileContents.AppendFormat("exclude-path={0}\n", EnvVars.VCInstallDir.FullName);
                if (CppPlatform == CppPlatform.Win64)
                {
                    ConfigFileContents.Append("platform=x64\n");
                }
                else if (CppPlatform == CppPlatform.Win32)
                {
                    ConfigFileContents.Append("platform=Win32\n");
                }
                else
                {
                    throw new BuildException("PVS studio does not support this platform");
                }
                ConfigFileContents.Append("preprocessor=visualcpp\n");
                ConfigFileContents.Append("language=C++\n");
                ConfigFileContents.Append("skip-cl-exe=yes\n");
                ConfigFileContents.AppendFormat("i-file={0}\n", PreprocessedFileItem.Reference.FullName);

                FileReference ConfigFileLocation = FileReference.Combine(CompileEnvironment.OutputDirectory, BaseFileName + ".cfg");
                FileItem      ConfigFileItem     = FileItem.CreateIntermediateTextFile(ConfigFileLocation, ConfigFileContents.ToString());

                // Run the analzyer on the preprocessed source file
                FileReference OutputFileLocation = FileReference.Combine(CompileEnvironment.OutputDirectory, BaseFileName + ".pvslog");
                FileItem      OutputFileItem     = FileItem.GetItemByFileReference(OutputFileLocation);

                Action AnalyzeAction = ActionGraph.Add(ActionType.Compile);
                AnalyzeAction.CommandDescription = "Analyzing";
                AnalyzeAction.StatusDescription  = BaseFileName;
                AnalyzeAction.WorkingDirectory   = UnrealBuildTool.EngineSourceDirectory.FullName;
                AnalyzeAction.CommandPath        = AnalyzerFile.FullName;
                AnalyzeAction.CommandArguments   = String.Format("--cl-params \"{0}\" --source-file \"{1}\" --output-file \"{2}\" --cfg \"{3}\" --analysis-mode 4", PreprocessAction.CommandArguments, SourceFile.AbsolutePath, OutputFileLocation, ConfigFileItem.AbsolutePath);
                AnalyzeAction.PrerequisiteItems.Add(ConfigFileItem);
                AnalyzeAction.PrerequisiteItems.Add(PreprocessedFileItem);
                AnalyzeAction.ProducedItems.Add(OutputFileItem);
                AnalyzeAction.bShouldDeleteProducedItems = true;                 // PVS Studio will append by default, so need to delete produced items

                Result.ObjectFiles.AddRange(AnalyzeAction.ProducedItems);
            }
            return(Result);
        }
Example #15
0
        /// <summary>
        /// Builds the binary.
        /// </summary>
        /// <param name="ToolChain">The toolchain to use for building</param>
        /// <param name="CompileEnvironment">The environment to compile the binary in</param>
        /// <param name="LinkEnvironment">The environment to link the binary in</param>
        /// <returns></returns>
        public override IEnumerable <FileItem> Build(UEBuildTarget Target, UEToolChain ToolChain, CPPEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ActionGraph ActionGraph)
        {
            CSharpEnvironment ProjectCSharpEnviroment = new CSharpEnvironment();

            if (LinkEnvironment.Config.Configuration == CPPTargetConfiguration.Debug)
            {
                ProjectCSharpEnviroment.TargetConfiguration = CSharpTargetConfiguration.Debug;
            }
            else
            {
                ProjectCSharpEnviroment.TargetConfiguration = CSharpTargetConfiguration.Development;
            }
            ProjectCSharpEnviroment.EnvironmentTargetPlatform = LinkEnvironment.Config.Platform;

            ToolChain.CompileCSharpProject(ProjectCSharpEnviroment, Config.ProjectFilePath, Config.OutputFilePath, ActionGraph);

            return(new FileItem[] { FileItem.GetItemByFileReference(Config.OutputFilePath) });
        }
Example #16
0
        private LinkEnvironment SetupBinaryLinkEnvironment(ReadOnlyTargetRules Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CppCompileEnvironment CompileEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ISourceFileWorkingSet WorkingSet, DirectoryReference ExeDir, ActionGraph ActionGraph)
        {
            LinkEnvironment         BinaryLinkEnvironment         = new LinkEnvironment(LinkEnvironment);
            HashSet <UEBuildModule> LinkEnvironmentVisitedModules = new HashSet <UEBuildModule>();
            List <UEBuildBinary>    BinaryDependencies            = new List <UEBuildBinary>();

            CppCompileEnvironment BinaryCompileEnvironment = CreateBinaryCompileEnvironment(CompileEnvironment);

            foreach (UEBuildModule Module in Modules)
            {
                List <FileItem> LinkInputFiles;
                if (Module.Binary == null || Module.Binary == this)
                {
                    // Compile each module.
                    Log.TraceVerbose("Compile module: " + Module.Name);
                    LinkInputFiles = Module.Compile(Target, ToolChain, BinaryCompileEnvironment, SharedPCHs, WorkingSet, ActionGraph);

                    // NOTE: Because of 'Shared PCHs', in monolithic builds the same PCH file may appear as a link input
                    // multiple times for a single binary.  We'll check for that here, and only add it once.  This avoids
                    // a linker warning about redundant .obj files.
                    foreach (FileItem LinkInputFile in LinkInputFiles)
                    {
                        if (!BinaryLinkEnvironment.InputFiles.Contains(LinkInputFile))
                        {
                            BinaryLinkEnvironment.InputFiles.Add(LinkInputFile);
                        }
                    }
                }
                else
                {
                    BinaryDependencies.Add(Module.Binary);
                }

                // Allow the module to modify the link environment for the binary.
                Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules, ExeDir);
            }


            // Allow the binary dependencies to modify the link environment.
            foreach (UEBuildBinary BinaryDependency in BinaryDependencies)
            {
                BinaryDependency.SetupDependentLinkEnvironment(BinaryLinkEnvironment);
            }

            // Remove the default resource file on Windows (PCLaunch.rc) if the user has specified their own
            if (BinaryLinkEnvironment.InputFiles.Select(Item => Path.GetFileName(Item.AbsolutePath).ToLower()).Any(Name => Name.EndsWith(".res") && !Name.EndsWith(".inl.res") && Name != "pclaunch.rc.res"))
            {
                BinaryLinkEnvironment.InputFiles.RemoveAll(x => Path.GetFileName(x.AbsolutePath).ToLower() == "pclaunch.rc.res");
            }

            // Set the link output file.
            BinaryLinkEnvironment.OutputFilePaths = OutputFilePaths.ToList();

            // Set whether the link is allowed to have exports.
            BinaryLinkEnvironment.bHasExports = bAllowExports;

            // Set the output folder for intermediate files
            BinaryLinkEnvironment.IntermediateDirectory = IntermediateDirectory;

            // Put the non-executable output files (PDB, import library, etc) in the same directory as the production
            BinaryLinkEnvironment.OutputDirectory = OutputFilePaths[0].Directory;

            // Setup link output type
            BinaryLinkEnvironment.bIsBuildingDLL     = IsBuildingDll(Type);
            BinaryLinkEnvironment.bIsBuildingLibrary = IsBuildingLibrary(Type);

            // If we don't have any resource file, use the default or compile a custom one for this module
            if (BinaryLinkEnvironment.Platform == CppPlatform.Win32 || BinaryLinkEnvironment.Platform == CppPlatform.Win64)
            {
                if (!BinaryLinkEnvironment.InputFiles.Any(x => x.Location.HasExtension(".res")))
                {
                    if (BinaryLinkEnvironment.DefaultResourceFiles.Count > 0)
                    {
                        // Use the default resource file if possible
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                    else
                    {
                        // Get the intermediate directory
                        DirectoryReference ResourceIntermediateDirectory = ((UEBuildModuleCPP)Modules.First()).IntermediateDirectory;

                        // Create a compile environment for resource files
                        CppCompileEnvironment ResourceCompileEnvironment = new CppCompileEnvironment(BinaryCompileEnvironment);
                        WindowsPlatform.SetupResourceCompileEnvironment(ResourceCompileEnvironment, ResourceIntermediateDirectory, Target);

                        // @todo: This should be in some Windows code somewhere...
                        // Set the original file name macro; used in PCLaunch.rc to set the binary metadata fields.
                        string OriginalFilename = (OriginalOutputFilePaths != null) ? OriginalOutputFilePaths[0].GetFileName() : OutputFilePaths[0].GetFileName();
                        ResourceCompileEnvironment.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OriginalFilename + "\"");

                        // Set the other version fields
                        ResourceCompileEnvironment.Definitions.Add(String.Format("BUILT_FROM_CHANGELIST={0}", Target.Version.Changelist));
                        ResourceCompileEnvironment.Definitions.Add(String.Format("BUILD_VERSION={0}", Target.BuildVersion));

                        // Otherwise compile the default resource file per-binary, so that it gets the correct ORIGINAL_FILE_NAME macro.
                        FileItem  DefaultResourceFile   = FileItem.GetItemByFileReference(FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Runtime", "Launch", "Resources", "Windows", "PCLaunch.rc"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(ResourceCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ResourceIntermediateDirectory, ActionGraph);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                }
            }

            // Add all the common resource files
            BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.CommonResourceFiles);

            return(BinaryLinkEnvironment);
        }
Example #17
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ProjectFile"></param>
        /// <param name="Executable"></param>
        /// <param name="StageDirectory"></param>
        /// <param name="PlatformType"></param>
        public static void GenerateAssetCatalog(FileReference ProjectFile, string Executable, string StageDirectory, UnrealTargetPlatform PlatformType)
        {
            // Initialize the toolchain.
            IOSProjectSettings ProjectSettings = ((IOSPlatform)UEBuildPlatform.GetBuildPlatform(PlatformType)).ReadProjectSettings(null);
            IOSToolChain       ToolChain       = new IOSToolChain(ProjectFile, ProjectSettings);

            // Determine whether the user has modified icons that require a remote Mac to build.
            CppPlatform Platform         = PlatformType == UnrealTargetPlatform.IOS ? CppPlatform.IOS : CppPlatform.TVOS;
            bool        bUserImagesExist = false;

            ToolChain.GenerateAssetCatalog(Platform, ref bUserImagesExist);

            // Don't attempt to do anything remotely if the user is using the default UE4 images.
            if (!bUserImagesExist)
            {
                return;
            }

            // Also don't attempt to use a remote Mac if packaging for TVOS on PC.
            if (Platform == CppPlatform.TVOS && BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
            {
                return;
            }

            // Save off the current bUseRPCUtil setting to restore at the end of this function.
            // At this time, iPhonePackager needs to be called with bUseRPCUtil == true.
            bool bSaveUseRPCUtil = RemoteToolChain.bUseRPCUtil;

            // Initialize the remote calling environment, taking into account the user's SSH setting.
            ToolChain.SetUpGlobalEnvironment(false);

            // Build the asset catalog ActionGraph.
            ActionGraph     ActionGraph = new ActionGraph();
            List <FileItem> OutputFiles = new List <FileItem>();

            ToolChain.CompileAssetCatalog(FileItem.GetItemByPath(Executable), Platform, ActionGraph, OutputFiles);

            ActionGraph.FinalizeActionGraph();

            // I'm not sure how to derive the UE4Game and Development arguments programmatically.
            string[] Arguments = new string[] { "UE4Game", (PlatformType == UnrealTargetPlatform.IOS ? "IOS" : "TVOS"), "Development", "-UniqueBuildEnvironment" };

            // Perform all of the setup necessary to actually execute the ActionGraph instance.
            ReadOnlyBuildVersion Version        = new ReadOnlyBuildVersion(BuildVersion.ReadDefault());
            List <string[]>      TargetSettings = new List <string[]>();

            TargetSettings.Add(Arguments);
            var Targets = new List <UEBuildTarget>();
            Dictionary <UEBuildTarget, CPPHeaders> TargetToHeaders = new Dictionary <UEBuildTarget, CPPHeaders>();
            List <TargetDescriptor> TargetDescs = new List <TargetDescriptor>();

            foreach (string[] TargetSetting in TargetSettings)
            {
                TargetDescs.AddRange(TargetDescriptor.ParseCommandLine(TargetSetting, ref ProjectFile));
            }
            foreach (TargetDescriptor TargetDesc in TargetDescs)
            {
                UEBuildTarget Target = UEBuildTarget.CreateTarget(TargetDesc, Arguments, false, Version);
                if (Target == null)
                {
                    continue;
                }
                Targets.Add(Target);
                TargetToHeaders.Add(Target, null);
            }

            bool bIsRemoteCompile = BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac;

            // Create the build configuration object, and read the settings
            BuildConfiguration BuildConfiguration = new BuildConfiguration();

            XmlConfig.ApplyTo(BuildConfiguration);
            CommandLine.ParseArguments(Arguments, BuildConfiguration);
            BuildConfiguration.bUseUBTMakefiles = false;

            Action[] PrerequisiteActions;
            {
                HashSet <Action> PrerequisiteActionsSet = new HashSet <Action>();
                foreach (FileItem OutputFile in OutputFiles)
                {
                    ActionGraph.GatherPrerequisiteActions(OutputFile, ref PrerequisiteActionsSet);
                }
                PrerequisiteActions = PrerequisiteActionsSet.ToArray();
            }

            // Copy any asset catalog files to the remote Mac, if necessary.
            foreach (UEBuildTarget Target in Targets)
            {
                UEBuildPlatform.GetBuildPlatform(Target.Platform).PreBuildSync();
            }

            // Begin execution of the ActionGraph.
            Dictionary <UEBuildTarget, List <FileItem> > TargetToOutdatedPrerequisitesMap;
            List <Action> ActionsToExecute = ActionGraph.GetActionsToExecute(BuildConfiguration, PrerequisiteActions, Targets, TargetToHeaders, true, true, out TargetToOutdatedPrerequisitesMap);
            string        ExecutorName     = "Unknown";
            bool          bSuccess         = ActionGraph.ExecuteActions(BuildConfiguration, ActionsToExecute, bIsRemoteCompile, out ExecutorName, "", EHotReload.Disabled);

            if (bSuccess)
            {
                if (bIsRemoteCompile)
                {
                    // Copy the remotely built AssetCatalog directory locally.
                    foreach (FileItem OutputFile in OutputFiles)
                    {
                        string   RemoteDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/");
                        FileItem LocalExecutable = ToolChain.RemoteToLocalFileItem(FileItem.GetItemByPath(Executable));
                        string   LocalDirectory  = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(LocalExecutable.AbsolutePath), "AssetCatalog");
                        LocalDirectory = StageDirectory;
                        RPCUtilHelper.CopyDirectory(RemoteDirectory, LocalDirectory, RPCUtilHelper.ECopyOptions.DoNotReplace);
                    }
                }
                else
                {
                    // Copy the built AssetCatalog directory to the StageDirectory.
                    foreach (FileItem OutputFile in OutputFiles)
                    {
                        string SourceDirectory = System.IO.Path.GetDirectoryName(OutputFile.AbsolutePath).Replace("\\", "/");
                        System.IO.DirectoryInfo SourceDirectoryInfo = new System.IO.DirectoryInfo(SourceDirectory);
                        if (!System.IO.Directory.Exists(StageDirectory))
                        {
                            System.IO.Directory.CreateDirectory(StageDirectory);
                        }
                        System.IO.FileInfo[] SourceFiles = SourceDirectoryInfo.GetFiles();
                        foreach (System.IO.FileInfo SourceFile in SourceFiles)
                        {
                            string DestinationPath = System.IO.Path.Combine(StageDirectory, SourceFile.Name);
                            SourceFile.CopyTo(DestinationPath, true);
                        }
                    }
                }
            }

            // Restore the former bUseRPCUtil setting.
            RemoteToolChain.bUseRPCUtil = bSaveUseRPCUtil;
        }
Example #18
0
 /// <summary>
 /// Compiles the module, and returns a list of files output by the compiler.
 /// </summary>
 public abstract List <FileItem> Compile(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, List <PrecompiledHeaderTemplate> SharedPCHModules, ActionGraph ActionGraph);
Example #19
0
        /// <summary>
        /// Build a list of targets
        /// </summary>
        /// <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>
        public static void Build(List <TargetDescriptor> TargetDescriptors, BuildConfiguration BuildConfiguration, ISourceFileWorkingSet WorkingSet, BuildOptions Options, FileReference WriteOutdatedActionsFile)
        {
            // Create a makefile for each target
            TargetMakefile[] Makefiles = new TargetMakefile[TargetDescriptors.Count];
            for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++)
            {
                Makefiles[TargetIdx] = CreateMakefile(BuildConfiguration, TargetDescriptors[TargetIdx], WorkingSet);
            }

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

                // Find all the actions to be executed
                HashSet <Action>[] ActionsToExecute = new HashSet <Action> [TargetDescriptors.Count];
                for (int TargetIdx = 0; TargetIdx < TargetDescriptors.Count; TargetIdx++)
                {
                    ActionsToExecute[TargetIdx] = GetActionsForTarget(BuildConfiguration, TargetDescriptors[TargetIdx], Makefiles[TargetIdx]);
                }

                // If there are multiple targets being built, merge the actions together
                List <Action> MergedActionsToExecute;
                if (TargetDescriptors.Count == 1)
                {
                    MergedActionsToExecute = new List <Action>(ActionsToExecute[0]);
                }
                else
                {
                    MergedActionsToExecute = MergeActionGraphs(TargetDescriptors, ActionsToExecute);
                }

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

                // 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.
                ActionHistory.SaveAll();

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

                // Execute the actions
                if ((Options & BuildOptions.XGEExport) != 0)
                {
                    // Just export to an XML file
                    using (Timeline.ScopeEvent("XGE.ExportActions()"))
                    {
                        XGE.ExportActions(MergedActionsToExecute);
                    }
                }
                else if (WriteOutdatedActionsFile != null)
                {
                    // Write actions to an output file
                    using (Timeline.ScopeEvent("ActionGraph.WriteActions"))
                    {
                        ActionGraph.ExportJson(MergedActionsToExecute, WriteOutdatedActionsFile);
                    }
                }
                else
                {
                    // Execute the actions
                    if (MergedActionsToExecute.Count == 0)
                    {
                        if ((Options & BuildOptions.Quiet) == 0)
                        {
                            Log.TraceInformation((TargetDescriptors.Count == 1)? "Target is up to date" : "Targets are up to date");
                        }
                    }
                    else
                    {
                        if ((Options & BuildOptions.Quiet) != 0)
                        {
                            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);
                        }
                    }
                }
            }
        }
Example #20
0
 /// <summary>
 /// Builds the binary.
 /// </summary>
 /// <param name="ToolChain">The toolchain which to use for building</param>
 /// <param name="CompileEnvironment">The environment to compile the binary in</param>
 /// <param name="LinkEnvironment">The environment to link the binary in</param>
 /// <returns></returns>
 public abstract IEnumerable <FileItem> Build(UEBuildTarget Target, UEToolChain ToolChain, CPPEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ActionGraph ActionGraph);
 public abstract CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName, ActionGraph ActionGraph);
Example #22
0
        /// <summary>
        /// Builds the binary.
        /// </summary>
        /// <param name="CompileEnvironment">The environment to compile the binary in</param>
        /// <param name="LinkEnvironment">The environment to link the binary in</param>
        /// <returns></returns>
        public override IEnumerable <FileItem> Build(UEBuildTarget Target, UEToolChain ToolChain, CPPEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ActionGraph ActionGraph)
        {
            // UnrealCodeAnalyzer produces output files only for a specific module.
            if (BuildConfiguration.bRunUnrealCodeAnalyzer && !(Modules.Any(x => x.Name == BuildConfiguration.UCAModuleToAnalyze)))
            {
                return(new List <FileItem>());
            }

            // Setup linking environment.
            LinkEnvironment BinaryLinkEnvironment = SetupBinaryLinkEnvironment(Target, ToolChain, LinkEnvironment, CompileEnvironment, SharedPCHs, ActionGraph);

            // Return linked files.
            return(SetupOutputFiles(ToolChain, ref BinaryLinkEnvironment, ActionGraph));
        }
 public virtual void CompileCSharpProject(CSharpEnvironment CompileEnvironment, FileReference ProjectFileName, FileReference DestinationFile, ActionGraph ActionGraph)
 {
 }
Example #24
0
        private LinkEnvironment SetupBinaryLinkEnvironment(UEBuildTarget Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CPPEnvironment CompileEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ActionGraph ActionGraph)
        {
            LinkEnvironment         BinaryLinkEnvironment         = LinkEnvironment.DeepCopy();
            HashSet <UEBuildModule> LinkEnvironmentVisitedModules = new HashSet <UEBuildModule>();
            List <UEBuildBinary>    BinaryDependencies            = new List <UEBuildBinary>();

            CompileEnvironment.Config.bIsBuildingDLL     = IsBuildingDll(Config.Type);
            CompileEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            CPPEnvironment BinaryCompileEnvironment = CompileEnvironment.DeepCopy();

            // @Hack: This to prevent UHT from listing CoreUObject.generated.cpp as its dependency.
            // We flag the compile environment when we build UHT so that we don't need to check
            // this for each file when generating their dependencies.
            BinaryCompileEnvironment.bHackHeaderGenerator = (Target.GetAppName() == "UnrealHeaderTool");

            // @todo: This should be in some Windows code somewhere...
            // Set the original file name macro; used in PCLaunch.rc to set the binary metadata fields.
            string OriginalFilename = (Config.OriginalOutputFilePaths != null) ?
                                      Config.OriginalOutputFilePaths[0].GetFileName() :
                                      Config.OutputFilePaths[0].GetFileName();

            BinaryCompileEnvironment.Config.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OriginalFilename + "\"");

            foreach (UEBuildModule Module in Modules)
            {
                List <FileItem> LinkInputFiles;
                if (Module.Binary == null || Module.Binary == this)
                {
                    // Compile each module.
                    Log.TraceVerbose("Compile module: " + Module.Name);
                    LinkInputFiles = Module.Compile(Target, ToolChain, BinaryCompileEnvironment, SharedPCHs, ActionGraph);

                    // NOTE: Because of 'Shared PCHs', in monolithic builds the same PCH file may appear as a link input
                    // multiple times for a single binary.  We'll check for that here, and only add it once.  This avoids
                    // a linker warning about redundant .obj files.
                    foreach (FileItem LinkInputFile in LinkInputFiles)
                    {
                        if (!BinaryLinkEnvironment.InputFiles.Contains(LinkInputFile))
                        {
                            BinaryLinkEnvironment.InputFiles.Add(LinkInputFile);
                        }
                    }
                }
                else
                {
                    BinaryDependencies.Add(Module.Binary);
                }

                if (!BuildConfiguration.bRunUnrealCodeAnalyzer)
                {
                    // Allow the module to modify the link environment for the binary.
                    Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules);
                }
            }


            // Allow the binary dependencies to modify the link environment.
            foreach (UEBuildBinary BinaryDependency in BinaryDependencies)
            {
                BinaryDependency.SetupDependentLinkEnvironment(BinaryLinkEnvironment);
            }

            // Remove the default resource file on Windows (PCLaunch.rc) if the user has specified their own
            if (BinaryLinkEnvironment.InputFiles.Select(Item => Path.GetFileName(Item.AbsolutePath).ToLower()).Any(Name => Name.EndsWith(".res") && !Name.EndsWith(".inl.res") && Name != "pclaunch.rc.res"))
            {
                BinaryLinkEnvironment.InputFiles.RemoveAll(x => Path.GetFileName(x.AbsolutePath).ToLower() == "pclaunch.rc.res");
            }

            // Set the link output file.
            BinaryLinkEnvironment.Config.OutputFilePaths = Config.OutputFilePaths.ToList();

            // Set whether the link is allowed to have exports.
            BinaryLinkEnvironment.Config.bHasExports = Config.bAllowExports;

            // Set the output folder for intermediate files
            BinaryLinkEnvironment.Config.IntermediateDirectory = Config.IntermediateDirectory;

            // Put the non-executable output files (PDB, import library, etc) in the same directory as the production
            BinaryLinkEnvironment.Config.OutputDirectory = Config.OutputFilePaths[0].Directory;

            // Setup link output type
            BinaryLinkEnvironment.Config.bIsBuildingDLL     = IsBuildingDll(Config.Type);
            BinaryLinkEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type);

            BinaryLinkEnvironment.Config.ProjectFile = Target.ProjectFile;

            // Add the default resources for dlls
            if (Config.Type == UEBuildBinaryType.DynamicLinkLibrary)
            {
                // Check if there's already a custom resource file
                if (!BinaryLinkEnvironment.InputFiles.Any(x => x.Reference.HasExtension(".res")))
                {
                    if (UEBuildConfiguration.bFormalBuild)
                    {
                        // For formal builds, compile the default resource file per-binary, so that it gets the correct ORIGINAL_FILE_NAME macro.
                        CPPEnvironment BinaryResourceCompileEnvironment = BinaryCompileEnvironment.DeepCopy();
                        BinaryResourceCompileEnvironment.Config.OutputDirectory = DirectoryReference.Combine(BinaryResourceCompileEnvironment.Config.OutputDirectory, Modules.First().Name);
                        FileItem  DefaultResourceFile   = FileItem.GetItemByFileReference(FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Runtime", "Launch", "Resources", "Windows", "PCLaunch.rc"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(BinaryResourceCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ActionGraph);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                    else
                    {
                        // For non-formal builds, we just want to share the default resource file between modules
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                }

                // Add all the common resource files
                BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.CommonResourceFiles);
            }

            return(BinaryLinkEnvironment);
        }
 public virtual void FinalizeOutput(ReadOnlyTargetRules Target, List <FileItem> OutputItems, ActionGraph ActionGraph)
 {
 }
Example #26
0
        private List <FileItem> SetupOutputFiles(UEToolChain ToolChain, ref LinkEnvironment BinaryLinkEnvironment, ActionGraph ActionGraph)
        {
            // Early exits first
            if (ProjectFileGenerator.bGenerateProjectFiles)
            {
                // We're generating projects.  Since we only need include paths and definitions, there is no need
                // to go ahead and run through the linking logic.
                return(BinaryLinkEnvironment.InputFiles);
            }

            if (BuildConfiguration.bDisableLinking)
            {
                // We don't need linked binaries
                return(BinaryLinkEnvironment.InputFiles);
            }

            if (BuildConfiguration.bEnableCodeAnalysis)
            {
                // We're only analyzing code, so we won't actually link any executables.  Instead, our output
                // files will simply be the .obj files that were compiled during static analysis.
                return(BinaryLinkEnvironment.InputFiles);
            }

            if (BuildConfiguration.bRunUnrealCodeAnalyzer)
            {
                //
                // Create actions to analyze *.includes files and provide suggestions on how to modify PCH.
                //
                return(CreateOutputFilesForUCA(BinaryLinkEnvironment, ActionGraph));
            }

            if (!string.IsNullOrEmpty(BuildConfiguration.SingleFileToCompile))
            {
                return(BinaryLinkEnvironment.InputFiles);
            }

            //
            // Regular linking action.
            //
            List <FileItem> OutputFiles = new List <FileItem>();

            if (bCreateImportLibrarySeparately)
            {
                // Mark the link environment as cross-referenced.
                BinaryLinkEnvironment.Config.bIsCrossReferenced = true;

                if (BinaryLinkEnvironment.Config.Platform != CPPTargetPlatform.Mac && BinaryLinkEnvironment.Config.Platform != CPPTargetPlatform.Linux)
                {
                    // Create the import library.
                    OutputFiles.AddRange(ToolChain.LinkAllFiles(BinaryLinkEnvironment, true, ActionGraph));
                }
            }

            BinaryLinkEnvironment.Config.bIncludeDependentLibrariesInLibrary = bIncludeDependentLibrariesInLibrary;

            // Link the binary.
            FileItem[] Executables = ToolChain.LinkAllFiles(BinaryLinkEnvironment, false, ActionGraph);
            OutputFiles.AddRange(Executables);

            // Produce additional console app if requested
            if (Config.bBuildAdditionalConsoleApp)
            {
                // Produce additional binary but link it as a console app
                LinkEnvironment ConsoleAppLinkEvironment = BinaryLinkEnvironment.DeepCopy();
                ConsoleAppLinkEvironment.Config.bIsBuildingConsoleApplication = true;
                ConsoleAppLinkEvironment.Config.WindowsEntryPointOverride     = "WinMainCRTStartup";                            // For WinMain() instead of "main()" for Launch module
                ConsoleAppLinkEvironment.Config.OutputFilePaths = ConsoleAppLinkEvironment.Config.OutputFilePaths.Select(Path => GetAdditionalConsoleAppPath(Path)).ToList();

                // Link the console app executable
                OutputFiles.AddRange(ToolChain.LinkAllFiles(ConsoleAppLinkEvironment, false, ActionGraph));
            }

            foreach (FileItem Executable in Executables)
            {
                OutputFiles.AddRange(ToolChain.PostBuild(Executable, BinaryLinkEnvironment, ActionGraph));
            }

            return(OutputFiles);
        }
Example #27
0
        public virtual CPPOutput CompileRCFiles(CppCompileEnvironment Environment, List <FileItem> InputFiles, DirectoryReference OutputDir, ActionGraph ActionGraph)
        {
            CPPOutput Result = new CPPOutput();

            return(Result);
        }
Example #28
0
        private List <FileItem> CreateOutputFilesForUCA(LinkEnvironment BinaryLinkEnvironment, ActionGraph ActionGraph)
        {
            List <FileItem>  OutputFiles      = new List <FileItem>();
            string           ModuleName       = Modules.Select(Module => Module.Name).First(Name => Name.CompareTo(BuildConfiguration.UCAModuleToAnalyze) == 0);
            UEBuildModuleCPP ModuleCPP        = (UEBuildModuleCPP)Target.GetModuleByName(ModuleName);
            FileItem         ModulePrivatePCH = ModuleCPP.ProcessedDependencies.UniquePCHHeaderFile;
            string           IntermediatePath = Path.Combine(Target.ProjectIntermediateDirectory.FullName, ModuleName);
            FileReference    OutputFileName   = Target.OutputPath;
            FileItem         OutputFile       = FileItem.GetItemByFileReference(OutputFileName);

            Action LinkAction = ActionGraph.Add(ActionType.Compile);

            LinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory.FullName;
            LinkAction.CommandPath      = System.IO.Path.Combine(LinkAction.WorkingDirectory, @"..", @"Binaries", @"Win32", @"UnrealCodeAnalyzer.exe");
            LinkAction.ProducedItems.Add(OutputFile);
            LinkAction.PrerequisiteItems.AddRange(BinaryLinkEnvironment.InputFiles);
            LinkAction.CommandArguments = @"-AnalyzePCHFile -PCHFile=""" + ModulePrivatePCH.AbsolutePath + @""" -OutputFile=""" + OutputFileName + @""" -HeaderDataPath=""" + IntermediatePath + @""" -UsageThreshold " + BuildConfiguration.UCAUsageThreshold.ToString(CultureInfo.InvariantCulture);

            foreach (string IncludeSearchPath in ModuleCPP.IncludeSearchPaths)
            {
                LinkAction.CommandArguments += @" /I""" + LinkAction.WorkingDirectory + @"\" + IncludeSearchPath + @"""";
            }

            OutputFiles.Add(OutputFile);

            return(OutputFiles);
        }
Example #29
0
 public virtual FileItem[] LinkAllFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, ActionGraph ActionGraph)
 {
     return(new FileItem[] { LinkFiles(LinkEnvironment, bBuildImportLibraryOnly, ActionGraph) });
 }
 public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, ActionGraph ActionGraph)
 {
     throw new BuildException("Unable to link with PVS toolchain.");
 }