/// <summary> /// Invalidate the cache for the givcen directory /// </summary> /// <param name="DirectoryPath">Directory to invalidate</param> public static void InvalidateRulesFileCache(string DirectoryPath) { DirectoryReference Directory = new DirectoryReference(DirectoryPath); RootFolderToRulesFileCache.Remove(Directory); DirectoryLookupCache.InvalidateCachedDirectory(Directory); }
private static void FindAllRulesFilesRecursively(DirectoryReference Directory, RulesFileCache Cache) { // Scan all the files in this directory bool bSearchSubFolders = true; foreach (FileReference File in DirectoryLookupCache.EnumerateFiles(Directory)) { if (File.HasExtension(".build.cs")) { Cache.ModuleRules.Add(File); bSearchSubFolders = false; } else if (File.HasExtension(".target.cs")) { Cache.TargetRules.Add(File); } else if (File.HasExtension(".automation.csproj")) { Cache.AutomationModules.Add(File); bSearchSubFolders = false; } } // If we didn't find anything to stop the search, search all the subdirectories too if (bSearchSubFolders) { foreach (DirectoryReference SubDirectory in DirectoryLookupCache.EnumerateDirectories(Directory)) { FindAllRulesFilesRecursively(SubDirectory, Cache); } } }
/// <summary> /// Get the project folder for the given target name /// </summary> /// <param name="InTargetName">Name of the target of interest</param> /// <param name="OutProjectFileName">The project filename</param> /// <returns>True if the target was found</returns> public static bool TryGetProjectForTarget(string InTargetName, out FileReference OutProjectFileName) { if (CachedTargetNameToProjectFile == null) { lock (LockObject) { if (CachedTargetNameToProjectFile == null) { Dictionary <string, FileReference> TargetNameToProjectFile = new Dictionary <string, FileReference>(); foreach (FileReference ProjectFile in EnumerateProjectFiles()) { DirectoryReference SourceDirectory = DirectoryReference.Combine(ProjectFile.Directory, "Source"); if (DirectoryLookupCache.DirectoryExists(SourceDirectory)) { FindTargetFiles(SourceDirectory, TargetNameToProjectFile, ProjectFile); } DirectoryReference IntermediateSourceDirectory = DirectoryReference.Combine(ProjectFile.Directory, "Intermediate", "Source"); if (DirectoryLookupCache.DirectoryExists(IntermediateSourceDirectory)) { FindTargetFiles(IntermediateSourceDirectory, TargetNameToProjectFile, ProjectFile); } } CachedTargetNameToProjectFile = TargetNameToProjectFile; } } } return(CachedTargetNameToProjectFile.TryGetValue(InTargetName, out OutProjectFileName)); }
/// <summary> /// Returns a list of all the projects /// </summary> /// <returns>List of projects</returns> public static IEnumerable <FileReference> EnumerateProjectFiles() { if (CachedProjectFiles == null) { lock (LockObject) { if (CachedProjectFiles == null) { HashSet <FileReference> ProjectFiles = new HashSet <FileReference>(); foreach (DirectoryReference BaseDirectory in EnumerateBaseDirectories()) { if (DirectoryLookupCache.DirectoryExists(BaseDirectory)) { foreach (DirectoryReference SubDirectory in DirectoryLookupCache.EnumerateDirectories(BaseDirectory)) { foreach (FileReference File in DirectoryLookupCache.EnumerateFiles(SubDirectory)) { if (File.HasExtension(".uproject")) { ProjectFiles.Add(File); } } } } } CachedProjectFiles = ProjectFiles; } } } return(CachedProjectFiles); }
/// <summary> /// Creates a rules assembly /// </summary> /// <param name="RootDirectory">The root directory to create rules for</param> /// <param name="AssemblyPrefix">A prefix for the assembly file name</param> /// <param name="Plugins">List of plugins to include in this assembly</param> /// <param name="bReadOnly">Whether the assembly should be marked as installed</param> /// <param name="bSkipCompile">Whether to skip compilation for this assembly</param> /// <param name="Parent">The parent rules assembly</param> /// <returns>New rules assembly</returns> private static RulesAssembly CreateEngineOrEnterpriseRulesAssembly(DirectoryReference RootDirectory, string AssemblyPrefix, IReadOnlyList <PluginInfo> Plugins, bool bReadOnly, bool bSkipCompile, RulesAssembly Parent) { DirectoryReference SourceDirectory = DirectoryReference.Combine(RootDirectory, "Source"); DirectoryReference ProgramsDirectory = DirectoryReference.Combine(SourceDirectory, "Programs"); // Find the shared modules, excluding the programs directory. These are used to create an assembly with the bContainsEngineModules flag set to true. List <FileReference> EngineModuleFiles = new List <FileReference>(); using (Timeline.ScopeEvent("Finding engine modules")) { foreach (DirectoryReference SubDirectory in DirectoryLookupCache.EnumerateDirectories(SourceDirectory)) { if (SubDirectory != ProgramsDirectory) { EngineModuleFiles.AddRange(FindAllRulesFiles(SubDirectory, RulesFileType.Module)); } } } // Add all the plugin modules too Dictionary <FileReference, PluginInfo> ModuleFileToPluginInfo = new Dictionary <FileReference, PluginInfo>(); using (Timeline.ScopeEvent("Finding plugin modules")) { FindModuleRulesForPlugins(Plugins, EngineModuleFiles, ModuleFileToPluginInfo); } // Create the assembly FileReference EngineAssemblyFileName = FileReference.Combine(RootDirectory, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "Rules" + FrameworkAssemblyExtension); RulesAssembly EngineAssembly = new RulesAssembly(RootDirectory, Plugins, EngineModuleFiles, new List <FileReference>(), ModuleFileToPluginInfo, EngineAssemblyFileName, bContainsEngineModules: true, bUseBackwardsCompatibleDefaults: false, bReadOnly: bReadOnly, bSkipCompile: bSkipCompile, Parent: Parent); // Find all the rules files List <FileReference> ProgramModuleFiles; using (Timeline.ScopeEvent("Finding program modules")) { ProgramModuleFiles = new List <FileReference>(FindAllRulesFiles(ProgramsDirectory, RulesFileType.Module)); } List <FileReference> ProgramTargetFiles; using (Timeline.ScopeEvent("Finding program targets")) { ProgramTargetFiles = new List <FileReference>(FindAllRulesFiles(SourceDirectory, RulesFileType.Target)); } // Create a path to the assembly that we'll either load or compile FileReference ProgramAssemblyFileName = FileReference.Combine(RootDirectory, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "ProgramRules" + FrameworkAssemblyExtension); RulesAssembly ProgramAssembly = new RulesAssembly(RootDirectory, new List <PluginInfo>().AsReadOnly(), ProgramModuleFiles, ProgramTargetFiles, new Dictionary <FileReference, PluginInfo>(), ProgramAssemblyFileName, bContainsEngineModules: false, bUseBackwardsCompatibleDefaults: false, bReadOnly: bReadOnly, bSkipCompile: bSkipCompile, Parent: EngineAssembly); // Return the combined assembly return(ProgramAssembly); }
/// <summary> /// Find all the module rules files under a given directory /// </summary> /// <param name="BaseDirectory">The directory to search under</param> /// <param name="SubDirectoryName">Name of the subdirectory to look under</param> /// <param name="BaseModuleContext">The module context for each found rules instance</param> /// <param name="DefaultUHTModuleType">The UHT module type</param> /// <param name="ModuleFileToContext">Map of module files to their context</param> private static void AddEngineModuleRulesWithContext(DirectoryReference BaseDirectory, string SubDirectoryName, ModuleRulesContext BaseModuleContext, UHTModuleType?DefaultUHTModuleType, Dictionary <FileReference, ModuleRulesContext> ModuleFileToContext) { DirectoryReference Directory = DirectoryReference.Combine(BaseDirectory, SubDirectoryName); if (DirectoryLookupCache.DirectoryExists(Directory)) { ModuleRulesContext ModuleContext = new ModuleRulesContext(BaseModuleContext) { DefaultUHTModuleType = DefaultUHTModuleType }; AddModuleRulesWithContext(Directory, ModuleContext, ModuleFileToContext); } }
/// <summary> /// Converts an optional string list parameter to a well-defined hash set. /// </summary> protected HashSet <DirectoryReference> CreateDirectoryHashSet(IEnumerable <string> InEnumerableStrings) { HashSet <DirectoryReference> Directories = new HashSet <DirectoryReference>(); if (InEnumerableStrings != null) { foreach (string InputString in InEnumerableStrings) { DirectoryReference Dir = new DirectoryReference(ExpandPathVariables(InputString, null, null)); if (DirectoryLookupCache.DirectoryExists(Dir)) { Directories.Add(Dir); } else { Log.WriteLineOnce(LogEventType.Warning, LogFormatOptions.NoSeverityPrefix, "{0}: warning: Referenced directory '{1}' does not exist.", RulesFile, Dir); } } } return(Directories); }
/// <summary> /// Retrieve the list of base directories for native projects /// </summary> public static IEnumerable <DirectoryReference> EnumerateBaseDirectories() { if (CachedBaseDirectories == null) { lock (LockObject) { if (CachedBaseDirectories == null) { HashSet <DirectoryReference> BaseDirs = new HashSet <DirectoryReference>(); foreach (FileReference RootFile in DirectoryLookupCache.EnumerateFiles(UnrealBuildTool.RootDirectory)) { if (RootFile.HasExtension(".uprojectdirs")) { foreach (string Line in File.ReadAllLines(RootFile.FullName)) { string TrimLine = Line.Trim(); if (!TrimLine.StartsWith(";")) { DirectoryReference BaseProjectDir = DirectoryReference.Combine(UnrealBuildTool.RootDirectory, TrimLine); if (BaseProjectDir.IsUnderDirectory(UnrealBuildTool.RootDirectory)) { BaseDirs.Add(BaseProjectDir); } else { Log.TraceWarning("Project search path '{0}' referenced by '{1}' is not under '{2}', ignoring.", TrimLine, RootFile, UnrealBuildTool.RootDirectory); } } } } } CachedBaseDirectories = BaseDirs; } } } return(CachedBaseDirectories); }
/// <summary> /// Finds all target files under a given folder, and add them to the target name to project file map /// </summary> /// <param name="Directory">Directory to search</param> /// <param name="TargetNameToProjectFile">Map from target name to project file</param> /// <param name="ProjectFile">The project file for this directory</param> private static void FindTargetFiles(DirectoryReference Directory, Dictionary <string, FileReference> TargetNameToProjectFile, FileReference ProjectFile) { // Search for all target files within this directory bool bSearchSubFolders = true; foreach (FileReference File in DirectoryLookupCache.EnumerateFiles(Directory)) { if (File.HasExtension(".target.cs")) { string TargetName = Path.GetFileNameWithoutExtension(File.GetFileNameWithoutExtension()); TargetNameToProjectFile[TargetName] = ProjectFile; bSearchSubFolders = false; } } // If we didn't find anything, recurse through the subfolders if (bSearchSubFolders) { foreach (DirectoryReference SubDirectory in DirectoryLookupCache.EnumerateDirectories(Directory)) { FindTargetFiles(SubDirectory, TargetNameToProjectFile, ProjectFile); } } }
/// <summary> /// Finds the header file that is referred to by a partial include filename. /// </summary> /// <param name="RelativeIncludePath">path relative to the project</param> /// <param name="bSkipExternalHeader">true to skip processing of headers in external path</param> /// <param name="SourceFilesDirectory">- The folder containing the source files we're generating a PCH for</param> public static FileItem FindIncludedFile(string RelativeIncludePath, bool bSkipExternalHeader, List <string> IncludePathsToSearch, Dictionary <string, FileItem> IncludeFileSearchDictionary) { FileItem Result = null; if (IncludePathsToSearch == null) { throw new BuildException("Was not expecting IncludePathsToSearch to be empty for file '{0}'!", RelativeIncludePath); } ++TotalFindIncludedFileCalls; // Only search for the include file if the result hasn't been cached. string InvariantPath = RelativeIncludePath.ToLowerInvariant(); if (!IncludeFileSearchDictionary.TryGetValue(InvariantPath, out Result)) { int SearchAttempts = 0; if (Path.IsPathRooted(RelativeIncludePath)) { FileReference Reference = new FileReference(RelativeIncludePath); if (DirectoryLookupCache.FileExists(Reference)) { Result = FileItem.GetItemByFileReference(Reference); } ++SearchAttempts; } else { // Find the first include path that the included file exists in. foreach (string IncludePath in IncludePathsToSearch) { ++SearchAttempts; string RelativeFilePath = ""; try { RelativeFilePath = Path.Combine(IncludePath, RelativeIncludePath); } catch (ArgumentException Exception) { throw new BuildException(Exception, "Failed to combine null or invalid include paths."); } FileReference FullFilePath = null; try { FullFilePath = new FileReference(RelativeFilePath); } catch (Exception) { } if (FullFilePath != null && DirectoryLookupCache.FileExists(FullFilePath)) { Result = FileItem.GetItemByFileReference(FullFilePath); break; } } } IncludePathSearchAttempts += SearchAttempts; if (BuildConfiguration.bPrintPerformanceInfo) { // More than two search attempts indicates: // - Include path was not relative to the directory that the including file was in // - Include path was not relative to the project's base if (SearchAttempts > 2) { Trace.TraceInformation(" Cache miss: " + RelativeIncludePath + " found after " + SearchAttempts.ToString() + " attempts: " + (Result != null ? Result.AbsolutePath : "NOT FOUND!")); } } // Cache the result of the include path search. IncludeFileSearchDictionary.Add(InvariantPath, Result); } // @todo ubtmake: The old UBT tried to skip 'external' (STABLE) headers here. But it didn't work. We might want to do this though! Skip system headers and source/thirdparty headers! if (Result != null) { Log.TraceVerbose("Resolved included file \"{0}\" to: {1}", RelativeIncludePath, Result.AbsolutePath); } else { Log.TraceVerbose("Couldn't resolve included file \"{0}\"", RelativeIncludePath); } return(Result); }