/// <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()) { foreach (DirectoryReference ExtensionDir in UnrealBuildTool.GetExtensionDirs(ProjectFile.Directory)) { DirectoryReference SourceDirectory = DirectoryReference.Combine(ExtensionDir, "Source"); if (DirectoryLookupCache.DirectoryExists(SourceDirectory)) { FindTargetFiles(SourceDirectory, TargetNameToProjectFile, ProjectFile); } DirectoryReference IntermediateSourceDirectory = DirectoryReference.Combine(ExtensionDir, "Intermediate", "Source"); if (DirectoryLookupCache.DirectoryExists(IntermediateSourceDirectory)) { FindTargetFiles(IntermediateSourceDirectory, TargetNameToProjectFile, ProjectFile); } } } CachedTargetNameToProjectFile = TargetNameToProjectFile; } } } return(CachedTargetNameToProjectFile.TryGetValue(InTargetName, out OutProjectFileName)); }
/// <summary> /// Enumerates all the plugin files available to the given project /// </summary> /// <param name="ProjectFile">Path to the project file</param> /// <returns>List of project files</returns> public static IEnumerable <FileReference> EnumeratePlugins(FileReference ProjectFile) { List <DirectoryReference> BaseDirs = new List <DirectoryReference>(); BaseDirs.AddRange(UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory, "Plugins")); BaseDirs.AddRange(UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EnterpriseDirectory, "Plugins")); if (ProjectFile != null) { BaseDirs.AddRange(UnrealBuildTool.GetExtensionDirs(ProjectFile.Directory, "Plugins")); BaseDirs.AddRange(UnrealBuildTool.GetExtensionDirs(ProjectFile.Directory, "Mods")); } return(BaseDirs.SelectMany(x => EnumeratePlugins(x)).ToList()); }
/// <summary> /// Scans a project directory, adding tasks for subdirectories /// </summary> /// <param name="ProjectDirectory">The project directory to search</param> static void ScanProjectDirectory(DirectoryItem ProjectDirectory) { foreach (DirectoryReference ExtensionDir in UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory)) { DirectoryItem BaseDirectory = DirectoryItem.GetItemByDirectoryReference(ExtensionDir); BaseDirectory.CacheDirectories(); DirectoryItem BasePluginsDirectory = DirectoryItem.Combine(ProjectDirectory, "Plugins"); Enqueue(() => ScanPluginFolder(BasePluginsDirectory)); DirectoryItem BaseSourceDirectory = DirectoryItem.Combine(ProjectDirectory, "Source"); Enqueue(() => ScanDirectoryTree(BaseSourceDirectory)); } }
/// <summary> /// Read all the plugin descriptors under the given directory /// </summary> /// <param name="RootDirectory">The directory to look in.</param> /// <param name="Subdirectory">A subdirectory to look in in RootDirectory and any other Platform directories under Root</param> /// <param name="Type">The plugin type</param> /// <returns>Sequence of the found PluginInfo object.</returns> public static IReadOnlyList <PluginInfo> ReadPluginsFromDirectory(DirectoryReference RootDirectory, string Subdirectory, PluginType Type) { // look for directories in RootDirectory and and extension directories under RootDirectory List <DirectoryReference> RootDirectories = UnrealBuildTool.GetExtensionDirs(RootDirectory, Subdirectory); Dictionary <PluginInfo, FileReference> ChildPlugins = new Dictionary <PluginInfo, FileReference>(); List <PluginInfo> AllParentPlugins = new List <PluginInfo>(); foreach (DirectoryReference Dir in RootDirectories) { if (!DirectoryReference.Exists(Dir)) { continue; } List <PluginInfo> Plugins; if (!PluginInfoCache.TryGetValue(Dir, out Plugins)) { Plugins = new List <PluginInfo>(); foreach (FileReference PluginFileName in EnumeratePlugins(Dir)) { PluginInfo Plugin = new PluginInfo(PluginFileName, Type); // is there a parent to merge up into? if (Plugin.Descriptor.bIsPluginExtension) { ChildPlugins.Add(Plugin, PluginFileName); } else { Plugins.Add(Plugin); } } PluginInfoCache.Add(Dir, Plugins); } // gather all of the plugins into one list AllParentPlugins.AddRange(Plugins); } // now that all parent plugins are read in, we can let the children look up the parents foreach (KeyValuePair <PluginInfo, FileReference> Pair in ChildPlugins) { TryMergeWithParent(Pair.Key, Pair.Value); } return(AllParentPlugins); }
/// <summary> /// Scans the engine directory, adding tasks for subdirectories /// </summary> static void ScanEngineDirectory() { foreach (DirectoryReference ExtensionDir in UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory)) { DirectoryItem BaseDirectory = DirectoryItem.GetItemByDirectoryReference(ExtensionDir); BaseDirectory.CacheDirectories(); DirectoryItem BasePluginsDirectory = DirectoryItem.Combine(BaseDirectory, "Plugins"); Enqueue(() => ScanPluginFolder(BasePluginsDirectory)); DirectoryItem BaseSourceDirectory = DirectoryItem.Combine(BaseDirectory, "Source"); BaseSourceDirectory.CacheDirectories(); DirectoryItem BaseSourceRuntimeDirectory = DirectoryItem.Combine(BaseSourceDirectory, "Runtime"); Enqueue(() => ScanDirectoryTree(BaseSourceRuntimeDirectory)); DirectoryItem BaseSourceDeveloperDirectory = DirectoryItem.Combine(BaseSourceDirectory, "Developer"); Enqueue(() => ScanDirectoryTree(BaseSourceDeveloperDirectory)); DirectoryItem BaseSourceEditorDirectory = DirectoryItem.Combine(BaseSourceDirectory, "Editor"); Enqueue(() => ScanDirectoryTree(BaseSourceEditorDirectory)); } }
/// <summary> /// Return all data driven infos found /// </summary> /// <returns></returns> public static Dictionary <string, ConfigDataDrivenPlatformInfo> GetAllPlatformInfos() { // need to init? if (PlatformInfos == null) { PlatformInfos = new Dictionary <string, ConfigDataDrivenPlatformInfo>(); Dictionary <string, string> IniParents = new Dictionary <string, string>(); // find all platform directories (skipping NFL/NoRedist) foreach (DirectoryReference EngineConfigDir in UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory, "Config", bIncludeRestrictedDirectories:false)) { // look through all config dirs looking for the data driven ini file foreach (string FilePath in Directory.EnumerateFiles(EngineConfigDir.FullName, "DataDrivenPlatformInfo.ini", SearchOption.AllDirectories)) { FileReference FileRef = new FileReference(FilePath); // get the platform name from the path string IniPlatformName; if (FileRef.IsUnderDirectory(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Config"))) { // Foo/Engine/Config/<Platform>/DataDrivenPlatformInfo.ini IniPlatformName = Path.GetFileName(Path.GetDirectoryName(FilePath)); } else { // Foo/Engine/Platforms/<Platform>/Config/DataDrivenPlatformInfo.ini IniPlatformName = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(FilePath))); } // load the DataDrivenPlatformInfo from the path (with Add support in a file that doesn't use +'s in the arrays for C++ usage) ConfigFile Config = new ConfigFile(FileRef, ConfigLineAction.Add); ConfigDataDrivenPlatformInfo NewInfo = new ConfigDataDrivenPlatformInfo(); // we must have the key section ConfigFileSection Section = null; if (Config.TryGetSection("DataDrivenPlatformInfo", out Section)) { ConfigHierarchySection ParsedSection = new ConfigHierarchySection(new List <ConfigFileSection>() { Section }); // get string values string IniParent; if (ParsedSection.TryGetValue("IniParent", out IniParent)) { IniParents[IniPlatformName] = IniParent; } // slightly nasty bool parsing for bool values string Temp; if (ParsedSection.TryGetValue("bIsConfidential", out Temp) == false || ConfigHierarchy.TryParse(Temp, out NewInfo.bIsConfidential) == false) { NewInfo.bIsConfidential = false; } // get a list of additional restricted folders IReadOnlyList <string> AdditionalRestrictedFolders; if (ParsedSection.TryGetValues("AdditionalRestrictedFolders", out AdditionalRestrictedFolders) && AdditionalRestrictedFolders.Count > 0) { NewInfo.AdditionalRestrictedFolders = AdditionalRestrictedFolders.Select(x => x.Trim()).Where(x => x.Length > 0).ToArray(); } // create cache it PlatformInfos[IniPlatformName] = NewInfo; } } } // now that all are read in, calculate the ini parent chain, starting with parent-most foreach (KeyValuePair <string, ConfigDataDrivenPlatformInfo> Pair in PlatformInfos) { string CurrentPlatform; // walk up the chain and build up the ini chain List <string> Chain = new List <string>(); if (IniParents.TryGetValue(Pair.Key, out CurrentPlatform)) { while (!string.IsNullOrEmpty(CurrentPlatform)) { // insert at 0 to reverse the order Chain.Insert(0, CurrentPlatform); if (IniParents.TryGetValue(CurrentPlatform, out CurrentPlatform) == false) { break; } } } // bake it into the info if (Chain.Count > 0) { Pair.Value.IniParentChain = Chain.ToArray(); } } } return(PlatformInfos); }
/// <summary> /// /// </summary> /// <param name="RulesFileType"></param> /// <param name="GameFolders"></param> /// <param name="ForeignPlugins"></param> /// <param name="AdditionalSearchPaths"></param> /// <param name="bIncludeEngine"></param> /// <param name="bIncludeEnterprise"></param> /// <param name="bIncludeTempTargets">Whether to include targets generated by UAT to accomodate content-only projects that need to be compiled to include plugins</param> /// <returns></returns> public static List <FileReference> FindAllRulesSourceFiles(RulesFileType RulesFileType, List <DirectoryReference> GameFolders, List <FileReference> ForeignPlugins, List <DirectoryReference> AdditionalSearchPaths, bool bIncludeEngine = true, bool bIncludeEnterprise = true, bool bIncludeTempTargets = true) { List <DirectoryReference> Folders = new List <DirectoryReference>(); // Add all engine source (including third party source) if (bIncludeEngine) { Folders.AddRange(UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory, "Source")); } if (bIncludeEnterprise) { Folders.Add(UnrealBuildTool.EnterpriseSourceDirectory); } // @todo plugin: Disallow modules from including plugin modules as dependency modules? (except when the module is part of that plugin) // Get all the root folders for plugins List <DirectoryReference> RootFolders = new List <DirectoryReference>(); if (bIncludeEngine) { RootFolders.AddRange(UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory)); } if (bIncludeEnterprise) { RootFolders.Add(UnrealBuildTool.EnterpriseDirectory); } if (GameFolders != null) { RootFolders.AddRange(GameFolders.SelectMany(x => UnrealBuildTool.GetExtensionDirs(x))); } // Find all the plugin source directories foreach (DirectoryReference RootFolder in RootFolders) { DirectoryReference PluginsFolder = DirectoryReference.Combine(RootFolder, "Plugins"); foreach (FileReference PluginFile in Plugins.EnumeratePlugins(PluginsFolder)) { Folders.Add(DirectoryReference.Combine(PluginFile.Directory, "Source")); } } // Add all the extra plugin folders if (ForeignPlugins != null) { foreach (FileReference ForeignPlugin in ForeignPlugins) { Folders.Add(DirectoryReference.Combine(ForeignPlugin.Directory, "Source")); } } // Add in the game folders to search if (GameFolders != null) { foreach (DirectoryReference GameFolder in GameFolders) { Folders.AddRange(UnrealBuildTool.GetExtensionDirs(GameFolder, "Source")); if (bIncludeTempTargets) { DirectoryReference GameIntermediateSourceFolder = DirectoryReference.Combine(GameFolder, "Intermediate", "Source"); Folders.Add(GameIntermediateSourceFolder); } } } // Process the additional search path, if sent in if (AdditionalSearchPaths != null) { foreach (DirectoryReference AdditionalSearchPath in AdditionalSearchPaths) { if (AdditionalSearchPath != null) { if (DirectoryReference.Exists(AdditionalSearchPath)) { Folders.Add(AdditionalSearchPath); } else { throw new BuildException("Couldn't find AdditionalSearchPath for rules source files '{0}'", AdditionalSearchPath); } } } } // Iterate over all the folders to check List <FileReference> SourceFiles = new List <FileReference>(); HashSet <FileReference> UniqueSourceFiles = new HashSet <FileReference>(); foreach (DirectoryReference Folder in Folders) { IReadOnlyList <FileReference> SourceFilesForFolder = FindAllRulesFiles(Folder, RulesFileType); foreach (FileReference SourceFile in SourceFilesForFolder) { if (UniqueSourceFiles.Add(SourceFile)) { SourceFiles.Add(SourceFile); } } } return(SourceFiles); }
/// <summary> /// Creates a rules assembly with the given parameters. /// </summary> /// <param name="ProjectFileName">The project file to create rules for. Null for the engine.</param> /// <param name="bUsePrecompiled">Whether to use a precompiled engine</param> /// <param name="bSkipCompile">Whether to skip compilation for this assembly</param> /// <returns>New rules assembly</returns> public static RulesAssembly CreateProjectRulesAssembly(FileReference ProjectFileName, bool bUsePrecompiled, bool bSkipCompile) { // Check if there's an existing assembly for this project RulesAssembly ProjectRulesAssembly; if (!LoadedAssemblyMap.TryGetValue(ProjectFileName, out ProjectRulesAssembly)) { ProjectDescriptor Project = ProjectDescriptor.FromFile(ProjectFileName); // Create the parent assembly RulesAssembly Parent; if (Project.IsEnterpriseProject) { Parent = CreateEnterpriseRulesAssembly(bUsePrecompiled, bSkipCompile); } else { Parent = CreateEngineRulesAssembly(bUsePrecompiled, bSkipCompile); } DirectoryReference MainProjectDirectory = ProjectFileName.Directory; //DirectoryReference MainProjectSourceDirectory = DirectoryReference.Combine(MainProjectDirectory, "Source"); // Create a scope for things in this assembly RulesScope Scope = new RulesScope("Project", Parent.Scope); // Create a new context for modules created by this assembly ModuleRulesContext DefaultModuleContext = new ModuleRulesContext(Scope, MainProjectDirectory); DefaultModuleContext.bCanBuildDebugGame = true; DefaultModuleContext.bCanHotReload = true; DefaultModuleContext.bClassifyAsGameModuleForUHT = true; DefaultModuleContext.bCanUseForSharedPCH = false; // gather modules from project and platforms Dictionary <FileReference, ModuleRulesContext> ModuleFiles = new Dictionary <FileReference, ModuleRulesContext>(); List <FileReference> TargetFiles = new List <FileReference>(); // Find all the project directories List <DirectoryReference> ProjectDirectories = UnrealBuildTool.GetExtensionDirs(ProjectFileName.Directory); if (Project.AdditionalRootDirectories != null) { ProjectDirectories.AddRange(Project.AdditionalRootDirectories); } // Find all the rules/plugins under the project source directories foreach (DirectoryReference ProjectDirectory in ProjectDirectories) { DirectoryReference ProjectSourceDirectory = DirectoryReference.Combine(ProjectDirectory, "Source"); AddModuleRulesWithContext(ProjectSourceDirectory, DefaultModuleContext, ModuleFiles); TargetFiles.AddRange(FindAllRulesFiles(ProjectSourceDirectory, RulesFileType.Target)); } // Find all the project plugins List <PluginInfo> ProjectPlugins = new List <PluginInfo>(); ProjectPlugins.AddRange(Plugins.ReadProjectPlugins(MainProjectDirectory)); // Add the project's additional plugin directories plugins too if (Project.AdditionalPluginDirectories != null) { foreach (DirectoryReference AdditionalPluginDirectory in Project.AdditionalPluginDirectories) { ProjectPlugins.AddRange(Plugins.ReadAdditionalPlugins(AdditionalPluginDirectory)); } } // Find all the plugin module rules FindModuleRulesForPlugins(ProjectPlugins, DefaultModuleContext, ModuleFiles); // Add the games project's intermediate source folder DirectoryReference ProjectIntermediateSourceDirectory = DirectoryReference.Combine(MainProjectDirectory, "Intermediate", "Source"); if (DirectoryReference.Exists(ProjectIntermediateSourceDirectory)) { AddModuleRulesWithContext(ProjectIntermediateSourceDirectory, DefaultModuleContext, ModuleFiles); TargetFiles.AddRange(FindAllRulesFiles(ProjectIntermediateSourceDirectory, RulesFileType.Target)); } // Compile the assembly. If there are no module or target files, just use the parent assembly. FileReference AssemblyFileName = FileReference.Combine(MainProjectDirectory, "Intermediate", "Build", "BuildRules", ProjectFileName.GetFileNameWithoutExtension() + "ModuleRules" + FrameworkAssemblyExtension); if (ModuleFiles.Count == 0 && TargetFiles.Count == 0) { ProjectRulesAssembly = Parent; } else { ProjectRulesAssembly = new RulesAssembly(Scope, new List <DirectoryReference> { MainProjectDirectory }, ProjectPlugins, ModuleFiles, TargetFiles, AssemblyFileName, bContainsEngineModules: false, DefaultBuildSettings: null, bReadOnly: UnrealBuildTool.IsProjectInstalled(), bSkipCompile: bSkipCompile, Parent: Parent); } LoadedAssemblyMap.Add(ProjectFileName, ProjectRulesAssembly); } return(ProjectRulesAssembly); }
/// <summary> /// Creates the engine rules assembly /// </summary> /// <param name="bUsePrecompiled">Whether to use a precompiled engine</param> /// <param name="bSkipCompile">Whether to skip compilation for this assembly</param> /// <returns>New rules assembly</returns> public static RulesAssembly CreateEngineRulesAssembly(bool bUsePrecompiled, bool bSkipCompile) { if (EngineRulesAssembly == null) { List <PluginInfo> IncludedPlugins = new List <PluginInfo>(); // search for all engine plugins IncludedPlugins.AddRange(Plugins.ReadEnginePlugins(UnrealBuildTool.EngineDirectory)); RulesScope EngineScope = new RulesScope("Engine", null); EngineRulesAssembly = CreateEngineOrEnterpriseRulesAssembly(EngineScope, UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory), ProjectFileGenerator.EngineProjectFileNameBase, IncludedPlugins, UnrealBuildTool.IsEngineInstalled() || bUsePrecompiled, bSkipCompile, null); } return(EngineRulesAssembly); }