/// <summary>
        /// Creates an action which copies a file from one location to another
        /// </summary>
        /// <param name="Graph">List of actions to be executed. Additional actions will be added to this list.</param>
        /// <param name="SourceFile">The source file location</param>
        /// <param name="TargetFile">The target file location</param>
        /// <returns>File item for the output file</returns>
        public static FileItem CreateCopyAction(this IActionGraphBuilder Graph, FileReference SourceFile, FileReference TargetFile)
        {
            FileItem SourceFileItem = FileItem.GetItemByFileReference(SourceFile);
            FileItem TargetFileItem = FileItem.GetItemByFileReference(TargetFile);

            Graph.CreateCopyAction(SourceFileItem, TargetFileItem);

            return(TargetFileItem);
        }
        /// <summary>
        /// Creates an action which calls UBT recursively
        /// </summary>
        /// <param name="Graph">The action graph</param>
        /// <param name="Type">Type of the action</param>
        /// <param name="Arguments">Arguments for the action</param>
        /// <returns>New action instance</returns>
        public static Action CreateRecursiveAction <T>(this IActionGraphBuilder Graph, ActionType Type, string Arguments) where T : ToolMode
        {
            ToolModeAttribute Attribute = typeof(T).GetCustomAttribute <ToolModeAttribute>();

            if (Attribute == null)
            {
                throw new BuildException("Missing ToolModeAttribute on {0}", typeof(T).Name);
            }

            Action NewAction = Graph.CreateAction(Type);

            NewAction.CommandPath      = UnrealBuildTool.GetUBTPath();
            NewAction.CommandArguments = String.Format("-Mode={0} {1}", Attribute.Name, Arguments);
            return(NewAction);
        }
        /// <summary>
        /// Creates an action which copies a file from one location to another
        /// </summary>
        /// <param name="Graph">The action graph</param>
        /// <param name="SourceFile">The source file location</param>
        /// <param name="TargetFile">The target file location</param>
        /// <returns>File item for the output file</returns>
        public static Action CreateCopyAction(this IActionGraphBuilder Graph, FileItem SourceFile, FileItem TargetFile)
        {
            Action CopyAction = Graph.CreateAction(ActionType.BuildProject);

            CopyAction.CommandDescription = "Copy";
            CopyAction.CommandPath        = BuildHostPlatform.Current.Shell;
            if (BuildHostPlatform.Current.ShellType == ShellType.Cmd)
            {
                CopyAction.CommandArguments = String.Format("/C \"copy /Y \"{0}\" \"{1}\" 1>nul\"", SourceFile.AbsolutePath, TargetFile.AbsolutePath);
            }
            else
            {
                CopyAction.CommandArguments = String.Format("-c 'cp -f \"{0}\" \"{1}\"'", SourceFile.AbsolutePath, TargetFile.AbsolutePath);
            }
            CopyAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory;
            CopyAction.PrerequisiteItems.Add(SourceFile);
            CopyAction.ProducedItems.Add(TargetFile);
            CopyAction.DeleteItems.Add(TargetFile);
            CopyAction.StatusDescription   = TargetFile.Location.GetFileName();
            CopyAction.bCanExecuteRemotely = false;
            return(CopyAction);
        }
Ejemplo n.º 4
0
 public virtual void GenerateTypeLibraryHeader(CppCompileEnvironment CompileEnvironment, ModuleRules.TypeLibrary TypeLibrary, FileReference OutputFile, IActionGraphBuilder Graph)
 {
     throw new NotSupportedException("This platform does not support type libraries.");
 }
Ejemplo n.º 5
0
        public virtual CPPOutput GenerateISPCHeaders(CppCompileEnvironment Environment, List <FileItem> InputFiles, DirectoryReference OutputDir, IActionGraphBuilder Graph)
        {
            CPPOutput Result = new CPPOutput();

            return(Result);
        }
Ejemplo n.º 6
0
        public override CPPOutput CompileISPCFiles(CppCompileEnvironment CompileEnvironment, List <FileItem> InputFiles, DirectoryReference OutputDir, IActionGraphBuilder Graph)
        {
            CPPOutput Result = new CPPOutput();

            if (!CompileEnvironment.bCompileISPC)
            {
                return(Result);
            }

            List <string> CompileTargets = GetISPCCompileTargets(CompileEnvironment.Platform, null);

            foreach (FileItem ISPCFile in InputFiles)
            {
                Action CompileAction = Graph.CreateAction(ActionType.Compile);
                CompileAction.CommandDescription = "Compile";
                CompileAction.WorkingDirectory   = UnrealBuildTool.EngineSourceDirectory;
                CompileAction.CommandPath        = new FileReference(GetISPCHostCompilerPath(BuildHostPlatform.Current.Platform));
                CompileAction.StatusDescription  = Path.GetFileName(ISPCFile.AbsolutePath);

                // Disable remote execution to workaround mismatched case on XGE
                CompileAction.bCanExecuteRemotely = false;

                List <string> Arguments = new List <string>();

                // Add the ISPC file to be compiled.
                Arguments.Add(String.Format(" \"{0}\"", ISPCFile.AbsolutePath));

                List <FileItem> CompiledISPCObjFiles = new List <FileItem>();
                string          TargetString         = "";

                foreach (string Target in CompileTargets)
                {
                    string ObjTarget = Target;

                    if (Target.Contains("-"))
                    {
                        // Remove lane width and gang size from obj file name
                        ObjTarget = Target.Split('-')[0];
                    }

                    FileItem CompiledISPCObjFile;

                    if (CompileTargets.Count > 1)
                    {
                        CompiledISPCObjFile = FileItem.GetItemByFileReference(
                            FileReference.Combine(
                                OutputDir,
                                Path.GetFileName(ISPCFile.AbsolutePath) + "_" + ObjTarget + GetISPCObjectFileSuffix(CompileEnvironment.Platform)
                                )
                            );
                    }
                    else
                    {
                        CompiledISPCObjFile = FileItem.GetItemByFileReference(
                            FileReference.Combine(
                                OutputDir,
                                Path.GetFileName(ISPCFile.AbsolutePath) + GetISPCObjectFileSuffix(CompileEnvironment.Platform)
                                )
                            );
                    }

                    // Add the ISA specific ISPC obj files to the produced item list.
                    CompiledISPCObjFiles.Add(CompiledISPCObjFile);

                    // Build target string. No comma on last
                    if (Target == CompileTargets[CompileTargets.Count - 1])                   // .Last()
                    {
                        TargetString += Target;
                    }
                    else
                    {
                        TargetString += Target + ",";
                    }
                }

                // Add the common ISPC obj file to the produced item list.
                FileItem CompiledISPCObjFileNoISA = FileItem.GetItemByFileReference(
                    FileReference.Combine(
                        OutputDir,
                        Path.GetFileName(ISPCFile.AbsolutePath) + GetISPCObjectFileSuffix(CompileEnvironment.Platform)
                        )
                    );

                CompiledISPCObjFiles.Add(CompiledISPCObjFileNoISA);

                // Add the output ISPC obj file
                Arguments.Add(String.Format("-o \"{0}\"", CompiledISPCObjFileNoISA));

                // Build target triplet
                Arguments.Add(String.Format("--target-os=\"{0}\"", GetISPCOSTarget(CompileEnvironment.Platform)));
                Arguments.Add(String.Format("--arch=\"{0}\"", GetISPCArchTarget(CompileEnvironment.Platform, null)));
                Arguments.Add(String.Format("--target=\"{0}\"", TargetString));

                if (CompileEnvironment.Configuration == CppConfiguration.Debug)
                {
                    Arguments.Add("-g -O0");
                }
                else
                {
                    Arguments.Add("-O2");
                }

                // PIC is needed for modular builds except on Windows
                if ((CompileEnvironment.bIsBuildingDLL ||
                     CompileEnvironment.bIsBuildingLibrary) &&
                    !UEBuildPlatform.IsPlatformInGroup(CompileEnvironment.Platform, UnrealPlatformGroup.Windows))
                {
                    Arguments.Add("--pic");
                }

                // Include paths. Don't use AddIncludePath() here, since it uses the full path and exceeds the max command line length.
                foreach (DirectoryReference IncludePath in CompileEnvironment.UserIncludePaths)
                {
                    Arguments.Add(String.Format("-I\"{0}\"", IncludePath));
                }

                // System include paths.
                foreach (DirectoryReference SystemIncludePath in CompileEnvironment.SystemIncludePaths)
                {
                    Arguments.Add(String.Format("-I\"{0}\"", SystemIncludePath));
                }

                // Preprocessor definitions.
                foreach (string Definition in CompileEnvironment.Definitions)
                {
                    Arguments.Add(String.Format("-D\"{0}\"", Definition));
                }

                // Consume the included header dependency list
                if (CompileEnvironment.bGenerateDependenciesFile)
                {
                    FileItem DependencyListFile = FileItem.GetItemByFileReference(FileReference.Combine(OutputDir, Path.GetFileName(ISPCFile.AbsolutePath) + ".txt"));
                    CompileAction.DependencyListFile = DependencyListFile;
                    CompileAction.PrerequisiteItems.Add(DependencyListFile);
                }

                CompileAction.ProducedItems.AddRange(CompiledISPCObjFiles);
                Result.ObjectFiles.AddRange(CompiledISPCObjFiles);

                FileReference ResponseFileName = new FileReference(CompiledISPCObjFileNoISA.AbsolutePath + ".response");
                FileItem      ResponseFileItem = Graph.CreateIntermediateTextFile(ResponseFileName, Arguments.Select(x => Utils.ExpandVariables(x)));
                CompileAction.CommandArguments = " @\"" + ResponseFileName + "\"";
                CompileAction.PrerequisiteItems.Add(ResponseFileItem);

                // Add the source file and its included files to the prerequisite item list.
                CompileAction.PrerequisiteItems.Add(ISPCFile);

                Log.TraceVerbose("   ISPC Compiling " + CompileAction.StatusDescription + ": \"" + CompileAction.CommandPath + "\"" + CompileAction.CommandArguments);
            }

            return(Result);
        }
Ejemplo n.º 7
0
        public override CPPOutput GenerateISPCHeaders(CppCompileEnvironment CompileEnvironment, List <FileItem> InputFiles, DirectoryReference OutputDir, IActionGraphBuilder Graph)
        {
            CPPOutput Result = new CPPOutput();

            if (!CompileEnvironment.bCompileISPC)
            {
                return(Result);
            }

            List <string> CompileTargets = GetISPCCompileTargets(CompileEnvironment.Platform, null);

            foreach (FileItem ISPCFile in InputFiles)
            {
                Action CompileAction = Graph.CreateAction(ActionType.Compile);
                CompileAction.CommandDescription = "Compile";
                CompileAction.WorkingDirectory   = UnrealBuildTool.EngineSourceDirectory;
                CompileAction.CommandPath        = new FileReference(GetISPCHostCompilerPath(BuildHostPlatform.Current.Platform));
                CompileAction.StatusDescription  = Path.GetFileName(ISPCFile.AbsolutePath);

                // Disable remote execution to workaround mismatched case on XGE
                CompileAction.bCanExecuteRemotely = false;

                List <string> Arguments = new List <string>();

                // Add the ISPC obj file as a prerequisite of the action.
                CompileAction.CommandArguments = String.Format("\"{0}\" ", ISPCFile.AbsolutePath);

                // Add the ISPC h file to the produced item list.
                FileItem ISPCIncludeHeaderFile = FileItem.GetItemByFileReference(
                    FileReference.Combine(
                        OutputDir,
                        Path.GetFileName(ISPCFile.AbsolutePath) + ".generated.dummy.h"
                        )
                    );

                // Add the ISPC file to be compiled.
                Arguments.Add(String.Format("-h \"{0}\"", ISPCIncludeHeaderFile));

                // Build target string. No comma on last
                string TargetString = "";
                foreach (string Target in CompileTargets)
                {
                    if (Target == CompileTargets[CompileTargets.Count - 1])                   // .Last()
                    {
                        TargetString += Target;
                    }
                    else
                    {
                        TargetString += Target + ",";
                    }
                }

                // Build target triplet
                Arguments.Add(String.Format("--target-os={0}", GetISPCOSTarget(CompileEnvironment.Platform)));
                Arguments.Add(String.Format("--arch={0}", GetISPCArchTarget(CompileEnvironment.Platform, null)));
                Arguments.Add(String.Format("--target={0}", TargetString));

                // PIC is needed for modular builds except on Windows
                if ((CompileEnvironment.bIsBuildingDLL ||
                     CompileEnvironment.bIsBuildingLibrary) &&
                    !UEBuildPlatform.IsPlatformInGroup(CompileEnvironment.Platform, UnrealPlatformGroup.Windows))
                {
                    Arguments.Add("--pic");
                }

                // Include paths. Don't use AddIncludePath() here, since it uses the full path and exceeds the max command line length.
                // Because ISPC response files don't support white space in arguments, paths with white space need to be passed to the command line directly.
                foreach (DirectoryReference IncludePath in CompileEnvironment.UserIncludePaths)
                {
                    Arguments.Add(String.Format("-I\"{0}\"", IncludePath));
                }

                // System include paths.
                foreach (DirectoryReference SystemIncludePath in CompileEnvironment.SystemIncludePaths)
                {
                    Arguments.Add(String.Format("-I\"{0}\"", SystemIncludePath));
                }

                // Generate the included header dependency list
                if (CompileEnvironment.bGenerateDependenciesFile)
                {
                    FileItem DependencyListFile = FileItem.GetItemByFileReference(FileReference.Combine(OutputDir, Path.GetFileName(ISPCFile.AbsolutePath) + ".txt"));
                    Arguments.Add(String.Format("-MMM \"{0}\"", DependencyListFile.AbsolutePath.Replace('\\', '/')));
                    CompileAction.DependencyListFile = DependencyListFile;
                    CompileAction.ProducedItems.Add(DependencyListFile);
                }

                CompileAction.ProducedItems.Add(ISPCIncludeHeaderFile);

                FileReference ResponseFileName = new FileReference(ISPCIncludeHeaderFile.AbsolutePath + ".response");
                FileItem      ResponseFileItem = Graph.CreateIntermediateTextFile(ResponseFileName, Arguments.Select(x => Utils.ExpandVariables(x)));
                CompileAction.CommandArguments += String.Format("@\"{0}\"", ResponseFileName);
                CompileAction.PrerequisiteItems.Add(ResponseFileItem);

                // Add the source file and its included files to the prerequisite item list.
                CompileAction.PrerequisiteItems.Add(ISPCFile);

                FileItem ISPCFinalHeaderFile = FileItem.GetItemByFileReference(
                    FileReference.Combine(
                        OutputDir,
                        Path.GetFileName(ISPCFile.AbsolutePath) + ".generated.h"
                        )
                    );

                // Fix interrupted build issue by copying header after generation completes
                FileReference SourceFile = ISPCIncludeHeaderFile.Location;
                FileReference TargetFile = ISPCFinalHeaderFile.Location;

                FileItem SourceFileItem = FileItem.GetItemByFileReference(SourceFile);
                FileItem TargetFileItem = FileItem.GetItemByFileReference(TargetFile);

                Action CopyAction = Graph.CreateAction(ActionType.BuildProject);
                CopyAction.CommandDescription = "Copy";
                CopyAction.CommandPath        = BuildHostPlatform.Current.Shell;
                if (BuildHostPlatform.Current.ShellType == ShellType.Cmd)
                {
                    CopyAction.CommandArguments = String.Format("/C \"copy /Y \"{0}\" \"{1}\" 1>nul\"", SourceFile, TargetFile);
                }
                else
                {
                    CopyAction.CommandArguments = String.Format("-c 'cp -f \"{0}\" \"{1}\"'", SourceFile.FullName, TargetFile.FullName);
                }
                CopyAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory;
                CopyAction.PrerequisiteItems.Add(SourceFileItem);
                CopyAction.ProducedItems.Add(TargetFileItem);
                CopyAction.StatusDescription              = TargetFileItem.Location.GetFileName();
                CopyAction.bCanExecuteRemotely            = false;
                CopyAction.bShouldOutputStatusDescription = false;

                Result.GeneratedHeaderFiles.Add(TargetFileItem);

                Log.TraceVerbose("   ISPC Generating Header " + CompileAction.StatusDescription + ": \"" + CompileAction.CommandPath + "\"" + CompileAction.CommandArguments);
            }

            return(Result);
        }
Ejemplo n.º 8
0
        public override CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List <FileItem> InputFiles, DirectoryReference OutputDir, string ModuleName, IActionGraphBuilder Graph)
        {
            // Use a subdirectory for PVS output, to avoid clobbering regular build artifacts
            OutputDir = DirectoryReference.Combine(OutputDir, "PVS");

            // Preprocess the source files with the regular toolchain
            CppCompileEnvironment PreprocessCompileEnvironment = new CppCompileEnvironment(CompileEnvironment);

            PreprocessCompileEnvironment.bPreprocessOnly = true;
            PreprocessCompileEnvironment.bEnableUndefinedIdentifierWarnings = false;             // Not sure why THIRD_PARTY_INCLUDES_START doesn't pick this up; the _Pragma appears in the preprocessed output. Perhaps in preprocess-only mode the compiler doesn't respect these?
            PreprocessCompileEnvironment.Definitions.Add("PVS_STUDIO");

            List <Action> PreprocessActions = new List <Action>();
            CPPOutput     Result            = InnerToolChain.CompileCPPFiles(PreprocessCompileEnvironment, InputFiles, OutputDir, ModuleName, new ActionGraphCapture(Graph, PreprocessActions));

            // Run the source files through PVS-Studio
            foreach (Action PreprocessAction in PreprocessActions)
            {
                if (PreprocessAction.ActionType != ActionType.Compile)
                {
                    continue;
                }

                FileItem SourceFileItem = PreprocessAction.PrerequisiteItems.FirstOrDefault(x => x.HasExtension(".c") || x.HasExtension(".cc") || x.HasExtension(".cpp"));
                if (SourceFileItem == null)
                {
                    Log.TraceWarning("Unable to find source file from command: {0} {1}", PreprocessAction.CommandArguments);
                    continue;
                }

                FileItem PreprocessedFileItem = PreprocessAction.ProducedItems.FirstOrDefault(x => x.HasExtension(".i"));
                if (PreprocessedFileItem == null)
                {
                    Log.TraceWarning("Unable to find preprocessed output file from command: {0} {1}", PreprocessAction.CommandArguments);
                    continue;
                }

                // Disable a few warnings that seem to come from the preprocessor not respecting _Pragma
                PreprocessAction.CommandArguments += " /wd4005";                 // macro redefinition
                PreprocessAction.CommandArguments += " /wd4828";                 // file contains a character starting at offset xxxx that is illegal in the current source character set

                // Write the PVS studio config file
                StringBuilder ConfigFileContents = new StringBuilder();
                foreach (DirectoryReference IncludePath in Target.WindowsPlatform.Environment.IncludePaths)
                {
                    ConfigFileContents.AppendFormat("exclude-path={0}\n", IncludePath.FullName);
                }
                if (ApplicationSettings != null && ApplicationSettings.PathMasks != null)
                {
                    foreach (string PathMask in ApplicationSettings.PathMasks)
                    {
                        if (PathMask.Contains(":") || PathMask.Contains("\\") || PathMask.Contains("/"))
                        {
                            if (Path.IsPathRooted(PathMask) && !PathMask.Contains(":"))
                            {
                                ConfigFileContents.AppendFormat("exclude-path=*{0}*\n", PathMask);
                            }
                            else
                            {
                                ConfigFileContents.AppendFormat("exclude-path={0}\n", PathMask);
                            }
                        }
                    }
                }
                if (Platform == UnrealTargetPlatform.Win64)
                {
                    ConfigFileContents.Append("platform=x64\n");
                }
                else if (Platform == UnrealTargetPlatform.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.Location.FullName);

                string BaseFileName = PreprocessedFileItem.Location.GetFileNameWithoutExtension();

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

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

                Action AnalyzeAction = Graph.CreateAction(ActionType.Compile);
                AnalyzeAction.CommandDescription = "Analyzing";
                AnalyzeAction.StatusDescription  = BaseFileName;
                AnalyzeAction.WorkingDirectory   = UnrealBuildTool.EngineSourceDirectory;
                AnalyzeAction.CommandPath        = AnalyzerFile;
                AnalyzeAction.CommandArguments   = String.Format("--cl-params \"{0}\" --source-file \"{1}\" --output-file \"{2}\" --cfg \"{3}\" --analysis-mode {4}", PreprocessAction.CommandArguments, SourceFileItem.AbsolutePath, OutputFileLocation, ConfigFileItem.AbsolutePath, (uint)Settings.ModeFlags);
                if (LicenseFile != null)
                {
                    AnalyzeAction.CommandArguments += String.Format(" --lic-file \"{0}\"", LicenseFile);
                    AnalyzeAction.PrerequisiteItems.Add(FileItem.GetItemByFileReference(LicenseFile));
                }
                AnalyzeAction.PrerequisiteItems.Add(ConfigFileItem);
                AnalyzeAction.PrerequisiteItems.Add(PreprocessedFileItem);
                AnalyzeAction.PrerequisiteItems.AddRange(InputFiles);          // Add the InputFiles as PrerequisiteItems so that in SingleFileCompile mode the PVSAnalyze step is not filtered out
                AnalyzeAction.ProducedItems.Add(OutputFileItem);
                AnalyzeAction.DeleteItems.Add(OutputFileItem);                 // PVS Studio will append by default, so need to delete produced items

                Result.ObjectFiles.AddRange(AnalyzeAction.ProducedItems);
            }
            return(Result);
        }
Ejemplo n.º 9
0
 public virtual ICollection <FileItem> PostBuild(FileItem Executable, LinkEnvironment ExecutableLinkEnvironment, IActionGraphBuilder Graph)
 {
     return(new List <FileItem>());
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Given a set of C++ files, generates another set of C++ files that #include all the original
        /// files, the goal being to compile the same code in fewer translation units.
        /// The "unity" files are written to the CompileEnvironment's OutputDirectory.
        /// </summary>
        /// <param name="Target">The target we're building</param>
        /// <param name="CPPFiles">The C++ files to #include.</param>
        /// <param name="CompileEnvironment">The environment that is used to compile the C++ files.</param>
        /// <param name="WorkingSet">Interface to query files which belong to the working set</param>
        /// <param name="BaseName">Base name to use for the Unity files</param>
        /// <param name="IntermediateDirectory">Intermediate directory for unity cpp files</param>
        /// <param name="Graph">The makefile being built</param>
        /// <param name="SourceFileToUnityFile">Receives a mapping of source file to unity file</param>
        /// <returns>The "unity" C++ files.</returns>
        public static List <FileItem> GenerateUnityCPPs(
            ReadOnlyTargetRules Target,
            List <FileItem> CPPFiles,
            CppCompileEnvironment CompileEnvironment,
            ISourceFileWorkingSet WorkingSet,
            string BaseName,
            DirectoryReference IntermediateDirectory,
            IActionGraphBuilder Graph,
            Dictionary <FileItem, FileItem> SourceFileToUnityFile
            )
        {
            List <FileItem> NewCPPFiles = new List <FileItem>();

            //UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatform(CompileEnvironment.Platform);

            // Figure out size of all input files combined. We use this to determine whether to use larger unity threshold or not.
            long TotalBytesInCPPFiles = CPPFiles.Sum(F => F.Length);

            // We have an increased threshold for unity file size if, and only if, all files fit into the same unity file. This
            // is beneficial when dealing with PCH files. The default PCH creation limit is X unity files so if we generate < X
            // this could be fairly slow and we'd rather bump the limit a bit to group them all into the same unity file.


            // When enabled, UnrealBuildTool will try to determine source files that you are actively iteratively changing, and break those files
            // out of their unity blobs so that you can compile them as individual translation units, much faster than recompiling the entire
            // unity blob each time.
            bool bUseAdaptiveUnityBuild = Target.bUseAdaptiveUnityBuild && !Target.bStressTestUnity;

            // Optimization only makes sense if PCH files are enabled.
            bool bForceIntoSingleUnityFile = Target.bStressTestUnity || (TotalBytesInCPPFiles < Target.NumIncludedBytesPerUnityCPP * 2 && Target.bUsePCHFiles);

            // Build the list of unity files.
            List <FileCollection> AllUnityFiles;
            {
                // Sort the incoming file paths alphabetically, so there will be consistency in unity blobs across multiple machines.
                // Note that we're relying on this not only sorting files within each directory, but also the directories
                // themselves, so the whole list of file paths is the same across computers.
                List <FileItem> SortedCPPFiles = CPPFiles.GetRange(0, CPPFiles.Count);
                {
                    // Case-insensitive file path compare, because you never know what is going on with local file systems
                    Comparison <FileItem> FileItemComparer = (FileA, FileB) => { return(FileA.AbsolutePath.ToLowerInvariant().CompareTo(FileB.AbsolutePath.ToLowerInvariant())); };
                    SortedCPPFiles.Sort(FileItemComparer);
                }


                // Figure out whether we REALLY want to use adaptive unity for this module.  If nearly every file in the module appears in the working
                // set, we'll just go ahead and let unity build do its thing.
                HashSet <FileItem> FilesInWorkingSet = new HashSet <FileItem>();
                if (bUseAdaptiveUnityBuild)
                {
                    int CandidateWorkingSetSourceFileCount = 0;
                    int WorkingSetSourceFileCount          = 0;
                    foreach (FileItem CPPFile in SortedCPPFiles)
                    {
                        ++CandidateWorkingSetSourceFileCount;

                        // Don't include writable source files into unity blobs
                        if (WorkingSet.Contains(CPPFile))
                        {
                            ++WorkingSetSourceFileCount;

                            // Mark this file as part of the working set.  This will be saved into the UBT Makefile so that
                            // the assembler can automatically invalidate the Makefile when the working set changes (allowing this
                            // code to run again, to build up new unity blobs.)
                            FilesInWorkingSet.Add(CPPFile);
                            Graph.AddFileToWorkingSet(CPPFile);
                        }
                    }

                    if (WorkingSetSourceFileCount >= CandidateWorkingSetSourceFileCount)
                    {
                        // Every single file in the module appears in the working set, so don't bother using adaptive unity for this
                        // module.  Otherwise it would make full builds really slow.
                        bUseAdaptiveUnityBuild = false;
                    }
                }

                UnityFileBuilder CPPUnityFileBuilder          = new UnityFileBuilder(bForceIntoSingleUnityFile ? -1 : Target.NumIncludedBytesPerUnityCPP);
                StringBuilder    AdaptiveUnityBuildInfoString = new StringBuilder();
                foreach (FileItem CPPFile in SortedCPPFiles)
                {
                    if (!bForceIntoSingleUnityFile && CPPFile.AbsolutePath.IndexOf(".GeneratedWrapper.", StringComparison.InvariantCultureIgnoreCase) != -1)
                    {
                        NewCPPFiles.Add(CPPFile);
                    }

                    // When adaptive unity is enabled, go ahead and exclude any source files that we're actively working with
                    if (bUseAdaptiveUnityBuild && FilesInWorkingSet.Contains(CPPFile))
                    {
                        // Just compile this file normally, not as part of the unity blob
                        NewCPPFiles.Add(CPPFile);

                        // Let the unity file builder know about the file, so that we can retain the existing size of the unity blobs.
                        // This won't actually make the source file part of the unity blob, but it will keep track of how big the
                        // file is so that other existing unity blobs from the same module won't be invalidated.  This prevents much
                        // longer compile times the first time you build after your working file set changes.
                        CPPUnityFileBuilder.AddVirtualFile(CPPFile);

                        string CPPFileName = Path.GetFileName(CPPFile.AbsolutePath);
                        if (AdaptiveUnityBuildInfoString.Length == 0)
                        {
                            AdaptiveUnityBuildInfoString.Append(String.Format("[Adaptive unity build] Excluded from {0} unity file: {1}", BaseName, CPPFileName));
                        }
                        else
                        {
                            AdaptiveUnityBuildInfoString.Append(", " + CPPFileName);
                        }
                    }
                    else
                    {
                        // If adaptive unity build is enabled for this module, add this source file to the set that will invalidate the makefile
                        if (bUseAdaptiveUnityBuild)
                        {
                            Graph.AddCandidateForWorkingSet(CPPFile);
                        }

                        // Compile this file as part of the unity blob
                        CPPUnityFileBuilder.AddFile(CPPFile);
                    }
                }

                if (AdaptiveUnityBuildInfoString.Length > 0)
                {
                    if (Target.bAdaptiveUnityCreatesDedicatedPCH)
                    {
                        Graph.AddDiagnostic("[Adaptive unity build] Creating dedicated PCH for each excluded file. Set bAdaptiveUnityCreatesDedicatedPCH to false in BuildConfiguration.xml to change this behavior.");
                    }
                    else if (Target.bAdaptiveUnityDisablesPCH)
                    {
                        Graph.AddDiagnostic("[Adaptive unity build] Disabling PCH for excluded files. Set bAdaptiveUnityDisablesPCH to false in BuildConfiguration.xml to change this behavior.");
                    }

                    if (Target.bAdaptiveUnityDisablesOptimizations)
                    {
                        Graph.AddDiagnostic("[Adaptive unity build] Disabling optimizations for excluded files. Set bAdaptiveUnityDisablesOptimizations to false in BuildConfiguration.xml to change this behavior.");
                    }
                    if (Target.bAdaptiveUnityEnablesEditAndContinue)
                    {
                        Graph.AddDiagnostic("[Adaptive unity build] Enabling Edit & Continue for excluded files. Set bAdaptiveUnityEnablesEditAndContinue to false in BuildConfiguration.xml to change this behavior.");
                    }

                    Graph.AddDiagnostic(AdaptiveUnityBuildInfoString.ToString());
                }

                AllUnityFiles = CPPUnityFileBuilder.GetUnityFiles();
            }

            // Create a set of CPP files that combine smaller CPP files into larger compilation units, along with the corresponding
            // actions to compile them.
            int CurrentUnityFileCount = 0;

            foreach (FileCollection UnityFile in AllUnityFiles)
            {
                ++CurrentUnityFileCount;

                StringWriter OutputUnityCPPWriter = new StringWriter();

                OutputUnityCPPWriter.WriteLine("// This file is automatically generated at compile-time to include some subset of the user-created cpp files.");

                // Add source files to the unity file
                foreach (FileItem CPPFile in UnityFile.Files)
                {
                    OutputUnityCPPWriter.WriteLine("#include \"{0}\"", CPPFile.AbsolutePath.Replace('\\', '/'));
                }

                // Determine unity file path name
                string UnityCPPFileName;
                if (AllUnityFiles.Count > 1)
                {
                    UnityCPPFileName = string.Format("{0}{1}.{2}_of_{3}.cpp", ModulePrefix, BaseName, CurrentUnityFileCount, AllUnityFiles.Count);
                }
                else
                {
                    UnityCPPFileName = string.Format("{0}{1}.cpp", ModulePrefix, BaseName);
                }
                FileReference UnityCPPFilePath = FileReference.Combine(IntermediateDirectory, UnityCPPFileName);

                // Write the unity file to the intermediate folder.
                FileItem UnityCPPFile = Graph.CreateIntermediateTextFile(UnityCPPFilePath, OutputUnityCPPWriter.ToString());
                NewCPPFiles.Add(UnityCPPFile);

                // Store the mapping of source files to unity files in the makefile
                foreach (FileItem SourceFile in UnityFile.Files)
                {
                    SourceFileToUnityFile[SourceFile] = UnityCPPFile;
                }
                foreach (FileItem SourceFile in UnityFile.VirtualFiles)
                {
                    SourceFileToUnityFile[SourceFile] = UnityCPPFile;
                }
            }

            return(NewCPPFiles);
        }
Ejemplo n.º 11
0
        private LinkEnvironment SetupBinaryLinkEnvironment(ReadOnlyTargetRules Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CppCompileEnvironment CompileEnvironment, List <FileReference> SpecificFilesToCompile, ISourceFileWorkingSet WorkingSet, DirectoryReference ExeDir, IActionGraphBuilder Graph)
        {
            LinkEnvironment         BinaryLinkEnvironment         = new LinkEnvironment(LinkEnvironment);
            HashSet <UEBuildModule> LinkEnvironmentVisitedModules = new HashSet <UEBuildModule>();
            List <UEBuildBinary>    BinaryDependencies            = new List <UEBuildBinary>();

            CppCompileEnvironment BinaryCompileEnvironment = CreateBinaryCompileEnvironment(CompileEnvironment);

            if (BinaryCompileEnvironment.bUseSharedBuildEnvironment && Target.ProjectFile != null && IntermediateDirectory.IsUnderDirectory(Target.ProjectFile.Directory))
            {
                BinaryCompileEnvironment.bUseSharedBuildEnvironment = false;
            }

            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, SpecificFilesToCompile, WorkingSet, Graph);

                    // Save the module outputs. In monolithic builds, this is just the object files.
                    if (Target.LinkType == TargetLinkType.Monolithic)
                    {
                        Graph.SetOutputItemsForModule(Module.Name, LinkInputFiles.ToArray());
                    }

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

                    // Force a reference to initialize module for this binary
                    if (Module.Rules.bRequiresImplementModule.Value)
                    {
                        BinaryLinkEnvironment.IncludeFunctions.Add(String.Format("IMPLEMENT_MODULE_{0}", Module.Name));
                    }
                }
                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);
            }

            // 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.IsInGroup(UnrealPlatformGroup.Windows))
            {
                // Figure out if this binary has any custom resource files. Hacky check to ignore the resource file in the Launch module, since it contains dialogs that the engine needs and always needs to be included.
                FileItem[] CustomResourceFiles = BinaryLinkEnvironment.InputFiles.Where(x => x.Location.HasExtension(".res") && !x.Location.FullName.EndsWith("\\Launch\\PCLaunch.rc.res", StringComparison.OrdinalIgnoreCase)).ToArray();
                if (CustomResourceFiles.Length == 0)
                {
                    if (BinaryLinkEnvironment.DefaultResourceFiles.Count > 0)
                    {
                        // Use the default resource file if possible
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                    else
                    {
                        // Get the intermediate directory
                        DirectoryReference ResourceIntermediateDirectory = BinaryLinkEnvironment.IntermediateDirectory;

                        // Create a compile environment for resource files
                        CppCompileEnvironment ResourceCompileEnvironment = new CppCompileEnvironment(BinaryCompileEnvironment);

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

                        // 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.EngineDirectory, "Build", "Windows", "Resources", "Default.rc2"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(ResourceCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ResourceIntermediateDirectory, Graph);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                }
            }

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

            return(BinaryLinkEnvironment);
        }
Ejemplo n.º 12
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="SpecificFilesToCompile">If non-empty, specifies individual cpp files to be compiled</param>
        /// <param name="WorkingSet">The working set of source files</param>
        /// <param name="ExeDir">Directory containing the output executable</param>
        /// <param name="Graph">The graph being built</param>
        /// <returns>Set of built products</returns>
        public List <FileItem> Build(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, LinkEnvironment LinkEnvironment, List <FileReference> SpecificFilesToCompile, ISourceFileWorkingSet WorkingSet, DirectoryReference ExeDir, IActionGraphBuilder Graph)
        {
            // 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.LinkType == TargetLinkType.Monolithic && Target.bDisableLinking))
            {
                return(new List <FileItem>());
            }

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

            // 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 != UnrealTargetPlatform.Mac &&
                    BinaryLinkEnvironment.Platform != UnrealTargetPlatform.Linux &&
                    BinaryLinkEnvironment.Platform != UnrealTargetPlatform.LinuxAArch64)
                {
                    // Create the import library.
                    OutputFiles.AddRange(ToolChain.LinkAllFiles(BinaryLinkEnvironment, true, Graph));
                }
            }

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

            // Save all the output items for this binary. This is used for hot-reload, and excludes any items added in PostBuild (such as additional files copied into the app).
            if (Target.LinkType == TargetLinkType.Modular)
            {
                Graph.SetOutputItemsForModule(PrimaryModule.Name, OutputFiles.ToArray());
            }

            // 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
                FileItem[] ConsoleAppOutputFiles = ToolChain.LinkAllFiles(ConsoleAppLinkEvironment, false, Graph);
                OutputFiles.AddRange(ConsoleAppOutputFiles);

                foreach (FileItem Executable in ConsoleAppOutputFiles)
                {
                    OutputFiles.AddRange(ToolChain.PostBuild(Executable, ConsoleAppLinkEvironment, Graph));
                }
            }

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

            return(OutputFiles);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Compiles the module, and returns a list of files output by the compiler.
        /// </summary>
        public virtual List <FileItem> Compile(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, FileReference SingleFileToCompile, ISourceFileWorkingSet WorkingSet, IActionGraphBuilder Graph)
        {
            // Generate type libraries for Windows
            foreach (ModuleRules.TypeLibrary TypeLibrary in Rules.TypeLibraries)
            {
                FileReference OutputFile = FileReference.Combine(IntermediateDirectory, TypeLibrary.Header);
                ToolChain.GenerateTypeLibraryHeader(CompileEnvironment, TypeLibrary, OutputFile, Graph);
            }

            return(new List <FileItem>());
        }
 /// <summary>
 /// Creates a text file with the given contents.  If the contents of the text file aren't changed, it won't write the new contents to
 /// the file to avoid causing an action to be considered outdated.
 /// </summary>
 /// <param name="Graph">The action graph</param>
 /// <param name="AbsolutePath">Path to the intermediate file to create</param>
 /// <param name="Contents">Contents of the new file</param>
 /// <returns>File item for the newly created file</returns>
 public static FileItem CreateIntermediateTextFile(this IActionGraphBuilder Graph, FileReference AbsolutePath, IEnumerable <string> Contents)
 {
     return(Graph.CreateIntermediateTextFile(AbsolutePath, string.Join(Environment.NewLine, Contents)));
 }
Ejemplo n.º 15
0
 public abstract FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, IActionGraphBuilder Graph);
        public override CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List <FileItem> InputFiles, DirectoryReference OutputDir, string ModuleName, IActionGraphBuilder Graph)
        {
            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();

            foreach (FileItem SourceFile in InputFiles)
            {
                FileItem ObjectFile = FileItem.GetItemByFileReference(FileReference.Combine(OutputDir, Path.GetFileName(SourceFile.AbsolutePath) + ".xo"));

                Action CompileAction = Graph.CreateAction(ActionType.Compile);
                CompileAction.CommandDescription = "FakeCompile";
                CompileAction.CommandPath        = BuildHostPlatform.Current.Shell;
                // we use type/cat instead of copy so that timestamp gets updated
                if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64)
                {
                    CompileAction.CommandArguments = String.Format("/C \"type \"{0}\" > \"{1}\"\"", SourceFile, ObjectFile);
                }
                else
                {
                    CompileAction.CommandArguments = String.Format("cat {0} > {1}", Utils.EscapeShellArgument(SourceFile.AbsolutePath), Utils.EscapeShellArgument(ObjectFile.AbsolutePath));
                }
                CompileAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory;
                CompileAction.PrerequisiteItems.Add(SourceFile);
                CompileAction.ProducedItems.Add(ObjectFile);
                CompileAction.StatusDescription   = ObjectFile.Location.GetFileName();
                CompileAction.bCanExecuteRemotely = false;
                Result.ObjectFiles.Add(ObjectFile);

                foreach (FileItem ForceIncludeFile in CompileEnvironment.ForceIncludeFiles)
                {
                    CompileAction.PrerequisiteItems.Add(ForceIncludeFile);
                }
            }

            return(Result);
        }
Ejemplo n.º 17
0
 public virtual FileItem[] LinkAllFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, IActionGraphBuilder Graph)
 {
     return(new FileItem[] { LinkFiles(LinkEnvironment, bBuildImportLibraryOnly, Graph) });
 }
        public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, IActionGraphBuilder Graph)
        {
            FileItem OutputFile = FileItem.GetItemByFileReference(LinkEnvironment.OutputFilePath);

            Action LinkAction = Graph.CreateAction(ActionType.Link);

            LinkAction.CommandDescription = "FakeCompile";
            LinkAction.CommandPath        = BuildHostPlatform.Current.Shell;
            if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Win64)
            {
                LinkAction.CommandArguments = String.Format("/C echo Linked > {0}", LinkEnvironment.OutputFilePath.FullName);
            }
            else
            {
                LinkAction.CommandArguments = String.Format("echo Linked > {0}", Utils.EscapeShellArgument(LinkEnvironment.OutputFilePath.FullName));
            }
            LinkAction.WorkingDirectory = UnrealBuildTool.EngineSourceDirectory;
            foreach (FileItem InputFile in LinkEnvironment.InputFiles)
            {
                LinkAction.PrerequisiteItems.Add(InputFile);
            }
            LinkAction.ProducedItems.Add(OutputFile);
            LinkAction.DeleteItems.Add(OutputFile);
            LinkAction.StatusDescription   = OutputFile.Location.GetFileName();
            LinkAction.bCanExecuteRemotely = false;

            return(OutputFile);
        }
Ejemplo n.º 19
0
 public ActionGraphCapture(IActionGraphBuilder Inner, List <Action> Actions)
     : base(Inner)
 {
     this.Actions = Actions;
 }
Ejemplo n.º 20
0
 public abstract CPPOutput CompileCPPFiles(CppCompileEnvironment CompileEnvironment, List <FileItem> InputFiles, DirectoryReference OutputDir, string ModuleName, IActionGraphBuilder Graph);
Ejemplo n.º 21
0
 public override FileItem LinkFiles(LinkEnvironment LinkEnvironment, bool bBuildImportLibraryOnly, IActionGraphBuilder Graph)
 {
     throw new BuildException("Unable to link with PVS toolchain.");
 }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="Inner">Builder to pass all calls to</param>
 public ForwardingActionGraphBuilder(IActionGraphBuilder Inner)
 {
     this.Inner = Inner;
 }