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); }
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); }
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); }
/// <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); }
/// <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))); }
/// <inheritdoc/> public virtual FileItem CreateIntermediateTextFile(FileReference Location, string Contents) { return(Inner.CreateIntermediateTextFile(Location, Contents)); }