/// <summary> /// Creates a rules assembly with the given parameters. /// </summary> /// <param name="PluginFileName">The plugin file to create rules for</param> /// <param name="bSkipCompile">Whether to skip compilation for this assembly</param> /// <param name="Parent">The parent rules assembly</param> /// <param name="bContainsEngineModules">Whether the plugin contains engine modules. Used to initialize the default value for ModuleRules.bTreatAsEngineModule.</param> /// <returns>The new rules assembly</returns> public static RulesAssembly CreatePluginRulesAssembly(FileReference PluginFileName, bool bSkipCompile, RulesAssembly Parent, bool bContainsEngineModules) { // Check if there's an existing assembly for this project RulesAssembly PluginRulesAssembly; if (!LoadedAssemblyMap.TryGetValue(PluginFileName, out PluginRulesAssembly)) { // Find all the rules source files Dictionary <FileReference, ModuleRulesContext> ModuleFiles = new Dictionary <FileReference, ModuleRulesContext>(); List <FileReference> TargetFiles = new List <FileReference>(); // Create a list of plugins for this assembly. If it already exists in the parent assembly, just create an empty assembly. List <PluginInfo> ForeignPlugins = new List <PluginInfo>(); if (Parent == null || !Parent.EnumeratePlugins().Any(x => x.File == PluginFileName)) { ForeignPlugins.Add(new PluginInfo(PluginFileName, PluginType.External)); } // Create a new scope for the plugin. It should not reference anything else. RulesScope Scope = new RulesScope("Plugin", Parent.Scope); // Find all the modules ModuleRulesContext PluginModuleContext = new ModuleRulesContext(Scope, PluginFileName.Directory); PluginModuleContext.bClassifyAsGameModuleForUHT = !bContainsEngineModules; FindModuleRulesForPlugins(ForeignPlugins, PluginModuleContext, ModuleFiles); // Compile the assembly FileReference AssemblyFileName = FileReference.Combine(PluginFileName.Directory, "Intermediate", "Build", "BuildRules", Path.GetFileNameWithoutExtension(PluginFileName.FullName) + "ModuleRules" + FrameworkAssemblyExtension); PluginRulesAssembly = new RulesAssembly(Scope, new List <DirectoryReference> { PluginFileName.Directory }, ForeignPlugins, ModuleFiles, TargetFiles, AssemblyFileName, bContainsEngineModules, DefaultBuildSettings: null, bReadOnly: false, bSkipCompile: bSkipCompile, Parent: Parent); LoadedAssemblyMap.Add(PluginFileName, PluginRulesAssembly); } return(PluginRulesAssembly); }
/// <summary> /// Find all the module rules files under a given directory /// </summary> /// <param name="BaseDirectory">The directory to search under</param> /// <param name="ModuleContext">The module context for each found rules instance</param> /// <param name="ModuleFileToContext">Map of module files to their context</param> private static void AddModuleRulesWithContext(DirectoryReference BaseDirectory, ModuleRulesContext ModuleContext, Dictionary <FileReference, ModuleRulesContext> ModuleFileToContext) { IReadOnlyList <FileReference> RulesFiles = FindAllRulesFiles(BaseDirectory, RulesFileType.Module); foreach (FileReference RulesFile in RulesFiles) { ModuleFileToContext[RulesFile] = ModuleContext; } }
/// <summary> /// Copy constructor /// </summary> /// <param name="Other">The context to copy from</param> public ModuleRulesContext(ModuleRulesContext Other) { this.Scope = Other.Scope; this.DefaultOutputBaseDir = Other.DefaultOutputBaseDir; this.Plugin = Other.Plugin; this.bCanHotReload = Other.bCanHotReload; this.bCanBuildDebugGame = Other.bCanBuildDebugGame; this.bCanUseForSharedPCH = Other.bCanUseForSharedPCH; this.bClassifyAsGameModuleForUHT = Other.bClassifyAsGameModuleForUHT; this.DefaultUHTModuleType = Other.DefaultUHTModuleType; }
/// <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> /// Finds all the module rules for plugins under the given directory. /// </summary> /// <param name="Plugins">The directory to search</param> /// <param name="DefaultContext">The default context for any files that are enumerated</param> /// <param name="ModuleFileToContext">Dictionary which is filled with mappings from the module file to its corresponding context</param> private static void FindModuleRulesForPlugins(IReadOnlyList <PluginInfo> Plugins, ModuleRulesContext DefaultContext, Dictionary <FileReference, ModuleRulesContext> ModuleFileToContext) { PrefetchRulesFiles(Plugins.Select(x => DirectoryReference.Combine(x.Directory, "Source"))); foreach (PluginInfo Plugin in Plugins) { IReadOnlyList <FileReference> PluginModuleFiles = FindAllRulesFiles(DirectoryReference.Combine(Plugin.Directory, "Source"), RulesFileType.Module); foreach (FileReference ModuleFile in PluginModuleFiles) { ModuleRulesContext PluginContext = new ModuleRulesContext(DefaultContext); PluginContext.DefaultOutputBaseDir = Plugin.Directory; PluginContext.Plugin = Plugin; ModuleFileToContext[ModuleFile] = PluginContext; } } }
/// <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 = new List <DirectoryReference>(UnrealBuildTool.GetAllProjectDirectories(ProjectFileName)); 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 a rules assembly /// </summary> /// <param name="Scope">Scope for items created from this assembly</param> /// <param name="RootDirectories">The root directories 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(RulesScope Scope, List <DirectoryReference> RootDirectories, string AssemblyPrefix, IReadOnlyList <PluginInfo> Plugins, bool bReadOnly, bool bSkipCompile, RulesAssembly Parent) { // Scope hierarchy RulesScope PluginsScope = new RulesScope(Scope.Name + " Plugins", Scope); RulesScope ProgramsScope = new RulesScope(Scope.Name + " Programs", PluginsScope); // Find the shared modules, excluding the programs directory. These are used to create an assembly with the bContainsEngineModules flag set to true. Dictionary <FileReference, ModuleRulesContext> ModuleFileToContext = new Dictionary <FileReference, ModuleRulesContext>(); ModuleRulesContext DefaultModuleContext = new ModuleRulesContext(Scope, RootDirectories[0]); foreach (DirectoryReference RootDirectory in RootDirectories) { using (Timeline.ScopeEvent("Finding engine modules")) { DirectoryReference SourceDirectory = DirectoryReference.Combine(RootDirectory, "Source"); AddEngineModuleRulesWithContext(SourceDirectory, "Runtime", DefaultModuleContext, UHTModuleType.EngineRuntime, ModuleFileToContext); AddEngineModuleRulesWithContext(SourceDirectory, "Developer", DefaultModuleContext, UHTModuleType.EngineDeveloper, ModuleFileToContext); AddEngineModuleRulesWithContext(SourceDirectory, "Editor", DefaultModuleContext, UHTModuleType.EngineEditor, ModuleFileToContext); AddEngineModuleRulesWithContext(SourceDirectory, "ThirdParty", DefaultModuleContext, UHTModuleType.EngineThirdParty, ModuleFileToContext); } } // Add all the plugin modules too (don't need to loop over RootDirectories since the plugins come in already found using (Timeline.ScopeEvent("Finding plugin modules")) { ModuleRulesContext PluginsModuleContext = new ModuleRulesContext(PluginsScope, RootDirectories[0]); FindModuleRulesForPlugins(Plugins, PluginsModuleContext, ModuleFileToContext); } // Get the path to store any generated assemblies DirectoryReference AssemblyDir = RootDirectories[0]; if (UnrealBuildTool.IsFileInstalled(FileReference.Combine(AssemblyDir, AssemblyPrefix))) { DirectoryReference UserDir = Utils.GetUserSettingDirectory(); if (UserDir != null) { ReadOnlyBuildVersion Version = ReadOnlyBuildVersion.Current; AssemblyDir = DirectoryReference.Combine(UserDir, "UnrealEngine", String.Format("{0}.{1}", Version.MajorVersion, Version.MinorVersion)); } } // Create the assembly FileReference EngineAssemblyFileName = FileReference.Combine(AssemblyDir, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "Rules" + FrameworkAssemblyExtension); RulesAssembly EngineAssembly = new RulesAssembly(Scope, RootDirectories, Plugins, ModuleFileToContext, new List <FileReference>(), EngineAssemblyFileName, bContainsEngineModules: true, DefaultBuildSettings: BuildSettingsVersion.Latest, bReadOnly: bReadOnly, bSkipCompile: bSkipCompile, Parent: Parent); List <FileReference> ProgramTargetFiles = new List <FileReference>(); Dictionary <FileReference, ModuleRulesContext> ProgramModuleFiles = new Dictionary <FileReference, ModuleRulesContext>(); foreach (DirectoryReference RootDirectory in RootDirectories) { DirectoryReference SourceDirectory = DirectoryReference.Combine(RootDirectory, "Source"); DirectoryReference ProgramsDirectory = DirectoryReference.Combine(SourceDirectory, "Programs"); // Also create a scope for them, and update the UHT module type ModuleRulesContext ProgramsModuleContext = new ModuleRulesContext(ProgramsScope, RootDirectory); ProgramsModuleContext.DefaultUHTModuleType = UHTModuleType.Program; using (Timeline.ScopeEvent("Finding program modules")) { // Find all the rules files AddModuleRulesWithContext(ProgramsDirectory, ProgramsModuleContext, ProgramModuleFiles); } using (Timeline.ScopeEvent("Finding program targets")) { ProgramTargetFiles.AddRange(FindAllRulesFiles(SourceDirectory, RulesFileType.Target)); } } // Create a path to the assembly that we'll either load or compile FileReference ProgramAssemblyFileName = FileReference.Combine(AssemblyDir, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "ProgramRules" + FrameworkAssemblyExtension); RulesAssembly ProgramAssembly = new RulesAssembly(ProgramsScope, RootDirectories, new List <PluginInfo>().AsReadOnly(), ProgramModuleFiles, ProgramTargetFiles, ProgramAssemblyFileName, bContainsEngineModules: false, DefaultBuildSettings: BuildSettingsVersion.Latest, bReadOnly: bReadOnly, bSkipCompile: bSkipCompile, Parent: EngineAssembly); // Return the combined assembly return(ProgramAssembly); }