// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Xml; using Tools.DotNETCommon; namespace UnrealBuildTool { /// /// A unit of code compilation and linking. /// abstract class UEBuildModule { /// /// The rules for this module /// public readonly ModuleRules Rules; /// /// The name that uniquely identifies the module. /// public string Name { get { return Rules.Name; } } /// /// Path to the module directory /// public DirectoryReference ModuleDirectory { get { return Rules.Directory; } } /// /// The name of the .Build.cs file this module was created from, if any /// public FileReference RulesFile { get { return Rules.File; } } /// /// Is this module allowed to be redistributed. /// private readonly bool? IsRedistributableOverride; /// /// The binary the module will be linked into for the current target. Only set after UEBuildBinary.BindModules is called. /// public UEBuildBinary Binary = null; /// /// The name of the _API define for this module /// protected readonly string ModuleApiDefine; /// /// Set of all the public definitions /// protected readonly HashSet PublicDefinitions; /// /// Set of all public include paths /// protected readonly HashSet PublicIncludePaths; /// /// Nested public include paths which used to be added automatically, but are now only added for modules with bNestedPublicIncludePaths set. /// protected readonly HashSet LegacyPublicIncludePaths = new HashSet(); /// /// Set of all private include paths /// protected readonly HashSet PrivateIncludePaths; /// /// Set of all system include paths /// protected readonly HashSet PublicSystemIncludePaths; /// /// Set of all public library paths /// protected readonly HashSet PublicLibraryPaths; /// /// Set of all additional libraries /// protected readonly HashSet PublicAdditionalLibraries; /// /// Set of additional frameworks /// protected readonly HashSet PublicFrameworks; /// /// /// protected readonly HashSet PublicWeakFrameworks; /// /// /// protected readonly HashSet PublicAdditionalFrameworks; /// /// /// protected readonly HashSet PublicAdditionalBundleResources; // @ATG_CHANGE : BEGIN - winmd support protected readonly HashSet PublicWinMDReferences; protected readonly HashSet PrivateWinMDReferences; // @ATG_CHANGE : END /// /// Names of modules with header files that this module's public interface needs access to. /// protected List PublicIncludePathModules; /// /// Names of modules that this module's public interface depends on. /// protected List PublicDependencyModules; /// /// Names of DLLs that this module should delay load /// protected HashSet PublicDelayLoadDLLs; /// /// Names of modules with header files that this module's private implementation needs access to. /// protected List PrivateIncludePathModules; /// /// Names of modules that this module's private implementation depends on. /// protected List PrivateDependencyModules; /// /// Extra modules this module may require at run time /// protected List DynamicallyLoadedModules; /// /// Set of all whitelisted restricted folder references /// private readonly HashSet WhitelistRestrictedFolders; /// /// Constructor /// /// Rules for this module public UEBuildModule(ModuleRules Rules) { this.Rules = Rules; ModuleApiDefine = Name.ToUpperInvariant() + "_API"; PublicDefinitions = HashSetFromOptionalEnumerableStringParameter(Rules.PublicDefinitions); PublicIncludePaths = CreateDirectoryHashSet(Rules.PublicIncludePaths); PublicSystemIncludePaths = CreateDirectoryHashSet(Rules.PublicSystemIncludePaths); PublicLibraryPaths = CreateDirectoryHashSet(Rules.PublicLibraryPaths); PublicAdditionalLibraries = HashSetFromOptionalEnumerableStringParameter(Rules.PublicAdditionalLibraries); PublicFrameworks = HashSetFromOptionalEnumerableStringParameter(Rules.PublicFrameworks); PublicWeakFrameworks = HashSetFromOptionalEnumerableStringParameter(Rules.PublicWeakFrameworks); PublicAdditionalFrameworks = new HashSet(); if(Rules.PublicAdditionalFrameworks != null) { foreach(ModuleRules.Framework FrameworkRules in Rules.PublicAdditionalFrameworks) { UEBuildFramework Framework; if(String.IsNullOrEmpty(FrameworkRules.ZipPath)) { Framework = new UEBuildFramework(FrameworkRules.Name, FrameworkRules.CopyBundledAssets); } else { Framework = new UEBuildFramework(FrameworkRules.Name, FileReference.Combine(ModuleDirectory, FrameworkRules.ZipPath), DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "UnzippedFrameworks", Name, Path.GetFileNameWithoutExtension(FrameworkRules.ZipPath)), FrameworkRules.CopyBundledAssets); } PublicAdditionalFrameworks.Add(Framework); } } PublicAdditionalBundleResources = Rules.AdditionalBundleResources == null ? new HashSet() : new HashSet(Rules.AdditionalBundleResources.Select(x => new UEBuildBundleResource(x))); PublicDelayLoadDLLs = HashSetFromOptionalEnumerableStringParameter(Rules.PublicDelayLoadDLLs); if(Rules.bUsePrecompiled) { PrivateIncludePaths = new HashSet(); } else { PrivateIncludePaths = CreateDirectoryHashSet(Rules.PrivateIncludePaths); } // @ATG_CHANGE : BEGIN - winmd support PublicWinMDReferences = HashSetFromOptionalEnumerableStringParameter(Rules.PublicWinMDReferences); PrivateWinMDReferences = HashSetFromOptionalEnumerableStringParameter(Rules.PrivateWinMDReferences); // @ATG_CHANGE : END - winmd support IsRedistributableOverride = Rules.IsRedistributableOverride; WhitelistRestrictedFolders = new HashSet(Rules.WhitelistRestrictedFolders.Select(x => DirectoryReference.Combine(ModuleDirectory, x))); } /// /// Returns a list of this module's dependencies. /// /// An enumerable containing the dependencies of the module. public HashSet GetDependencies(bool bWithIncludePathModules, bool bWithDynamicallyLoadedModules) { HashSet Modules = new HashSet(); Modules.UnionWith(PublicDependencyModules); Modules.UnionWith(PrivateDependencyModules); if(bWithIncludePathModules) { Modules.UnionWith(PublicIncludePathModules); Modules.UnionWith(PrivateIncludePathModules); } if(bWithDynamicallyLoadedModules) { Modules.UnionWith(DynamicallyLoadedModules); } return Modules; } /// /// Returns a list of this module's frameworks. /// /// A List containing the frameworks this module requires. public List GetPublicFrameworks() { return new List(PublicFrameworks); } /// /// Returns a list of this module's immediate dependencies. /// /// An enumerable containing the dependencies of the module. public IEnumerable GetDirectDependencyModules() { return PublicDependencyModules.Concat(PrivateDependencyModules).Concat(DynamicallyLoadedModules); } /// /// Converts an optional string list parameter to a well-defined hash set. /// protected HashSet CreateDirectoryHashSet(IEnumerable InEnumerableStrings) { HashSet Directories = new HashSet(); if(InEnumerableStrings != null) { foreach(string InputString in InEnumerableStrings) { DirectoryReference Dir = new DirectoryReference(ExpandPathVariables(InputString, null, null)); if(DirectoryReference.Exists(Dir)) { Directories.Add(Dir); } else { Log.WriteLineOnce(LogEventType.Warning, LogFormatOptions.NoSeverityPrefix, "{0}: warning: Referenced directory '{1}' does not exist.", RulesFile, Dir); } } } return Directories; } /// /// Converts an optional string list parameter to a well-defined hash set. /// protected HashSet HashSetFromOptionalEnumerableStringParameter(IEnumerable InEnumerableStrings) { return InEnumerableStrings == null ? new HashSet() : new HashSet(InEnumerableStrings.Select(x => ExpandPathVariables(x, null, null))); } /// /// Determines whether this module has a circular dependency on the given module /// public bool HasCircularDependencyOn(string ModuleName) { return Rules.CircularlyReferencedDependentModules.Contains(ModuleName); } /// /// Enumerates additional build products which may be produced by this module. Some platforms (eg. Mac, Linux) can link directly against .so/.dylibs, but they /// are also copied to the output folder by the toolchain. /// /// List to which libraries required by this module are added /// List of bundle resources required by this module public void GatherAdditionalResources(List Libraries, List BundleResources) { Libraries.AddRange(PublicAdditionalLibraries); BundleResources.AddRange(PublicAdditionalBundleResources); } /// /// Determines the distribution level of a module based on its directory and includes. /// /// The project directory, if available /// Map of the restricted folder types to the first found instance public Dictionary FindRestrictedFolderReferences(DirectoryReference ProjectDir) { Dictionary References = new Dictionary(); if (!Rules.bOutputPubliclyDistributable) { // Find all the directories that this module references HashSet ReferencedDirs = new HashSet(); GetReferencedDirectories(ReferencedDirs); // Remove all the whitelisted folders ReferencedDirs.ExceptWith(WhitelistRestrictedFolders); ReferencedDirs.ExceptWith(PublicDependencyModules.SelectMany(x => x.WhitelistRestrictedFolders)); ReferencedDirs.ExceptWith(PrivateDependencyModules.SelectMany(x => x.WhitelistRestrictedFolders)); // Add flags for each of them foreach(DirectoryReference ReferencedDir in ReferencedDirs) { // Find the base directory containing this reference DirectoryReference BaseDir; if(ReferencedDir.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) { BaseDir = UnrealBuildTool.EngineDirectory; } else if(ProjectDir != null && ReferencedDir.IsUnderDirectory(ProjectDir)) { BaseDir = ProjectDir; } else { continue; } // Add references to each of the restricted folders List Folders = RestrictedFolders.FindRestrictedFolders(BaseDir, ReferencedDir); foreach(RestrictedFolder Folder in Folders) { if(!References.ContainsKey(Folder)) { References.Add(Folder, ReferencedDir); } } } } return References; } /// /// Finds all the directories that this folder references when building /// /// Set of directories to add to protected virtual void GetReferencedDirectories(HashSet Directories) { Directories.Add(ModuleDirectory); foreach(DirectoryReference PublicIncludePath in PublicIncludePaths) { Directories.Add(PublicIncludePath); } foreach(DirectoryReference PrivateIncludePath in PrivateIncludePaths) { Directories.Add(PrivateIncludePath); } foreach(DirectoryReference PublicSystemIncludePath in PublicSystemIncludePaths) { Directories.Add(PublicSystemIncludePath); } foreach(DirectoryReference PublicLibraryPath in PublicLibraryPaths) { Directories.Add(PublicLibraryPath); } } /// /// Find all the modules which affect the private compile environment. /// /// protected void FindModulesInPrivateCompileEnvironment(Dictionary ModuleToIncludePathsOnlyFlag) { // Add in all the modules that are only in the private compile environment foreach (UEBuildModule PrivateDependencyModule in PrivateDependencyModules) { PrivateDependencyModule.FindModulesInPublicCompileEnvironment(ModuleToIncludePathsOnlyFlag); } foreach (UEBuildModule PrivateIncludePathModule in PrivateIncludePathModules) { PrivateIncludePathModule.FindIncludePathModulesInPublicCompileEnvironment(ModuleToIncludePathsOnlyFlag); } // Add the modules in the public compile environment FindModulesInPublicCompileEnvironment(ModuleToIncludePathsOnlyFlag); } /// /// Find all the modules which affect the public compile environment. /// /// protected void FindModulesInPublicCompileEnvironment(Dictionary ModuleToIncludePathsOnlyFlag) { // bool bModuleIncludePathsOnly; if (ModuleToIncludePathsOnlyFlag.TryGetValue(this, out bModuleIncludePathsOnly) && !bModuleIncludePathsOnly) { return; } ModuleToIncludePathsOnlyFlag[this] = false; foreach (UEBuildModule DependencyModule in PublicDependencyModules) { DependencyModule.FindModulesInPublicCompileEnvironment(ModuleToIncludePathsOnlyFlag); } // Now add an include paths from modules with header files that we need access to, but won't necessarily be importing foreach (UEBuildModule IncludePathModule in PublicIncludePathModules) { IncludePathModule.FindIncludePathModulesInPublicCompileEnvironment(ModuleToIncludePathsOnlyFlag); } } /// /// Find all the modules which affect the public compile environment. Searches through /// /// protected void FindIncludePathModulesInPublicCompileEnvironment(Dictionary ModuleToIncludePathsOnlyFlag) { if (!ModuleToIncludePathsOnlyFlag.ContainsKey(this)) { // Add this module to the list ModuleToIncludePathsOnlyFlag.Add(this, true); // Include any of its public include path modules in the compile environment too foreach (UEBuildModule IncludePathModule in PublicIncludePathModules) { IncludePathModule.FindIncludePathModulesInPublicCompileEnvironment(ModuleToIncludePathsOnlyFlag); } } } private void AddIncludePaths(HashSet IncludePaths, HashSet IncludePathsToAdd) { // Need to check whether directories exist to avoid bloating compiler command line with generated code directories foreach(DirectoryReference IncludePathToAdd in IncludePathsToAdd) { IncludePaths.Add(IncludePathToAdd); } } /// /// Sets up the environment for compiling any module that includes the public interface of this module. /// public virtual void AddModuleToCompileEnvironment( UEBuildBinary SourceBinary, HashSet IncludePaths, HashSet SystemIncludePaths, List Definitions, List AdditionalFrameworks, bool bLegacyPublicIncludePaths, // @ATG_CHANGE : BEGIN - winmd support List WinMDFiles // @ATG_CHANGE : END - winmd support ) { // Add the module's parent directory to the include path, so we can root #includes from generated source files to it IncludePaths.Add(ModuleDirectory.ParentDirectory); // @ATG_CHANGE : BEGIN - winmd support WinMDFiles.AddRange(PublicWinMDReferences); // @ATG_CHANGE : END - winmd support AddIncludePaths(IncludePaths, PublicIncludePaths); if(bLegacyPublicIncludePaths) { AddIncludePaths(IncludePaths, LegacyPublicIncludePaths); } SystemIncludePaths.UnionWith(PublicSystemIncludePaths); Definitions.AddRange(PublicDefinitions); // Add the import or export declaration for the module if(Rules.Type == ModuleRules.ModuleType.CPlusPlus) { if(Rules.Target.LinkType == TargetLinkType.Monolithic) { if (Rules.Target.bShouldCompileAsDLL && Rules.Target.bHasExports) { Definitions.Add(ModuleApiDefine + "=DLLEXPORT"); } else { Definitions.Add(ModuleApiDefine + "="); } } else if(Binary == null || SourceBinary != Binary) { Definitions.Add(ModuleApiDefine + "=DLLIMPORT"); } else if(!Binary.bAllowExports) { Definitions.Add(ModuleApiDefine + "="); } else { Definitions.Add(ModuleApiDefine + "=DLLEXPORT"); } } // Add the additional frameworks so that the compiler can know about their #include paths AdditionalFrameworks.AddRange(PublicAdditionalFrameworks); } /// /// Sets up the environment for compiling this module. /// protected virtual void SetupPrivateCompileEnvironment( HashSet IncludePaths, HashSet SystemIncludePaths, List Definitions, List AdditionalFrameworks, bool bWithLegacyPublicIncludePaths, // @ATG_CHANGE : BEGIN - winmd support List WinMDFiles // @ATG_CHANGE : END - winmd support ) { if (!Rules.bTreatAsEngineModule) { Definitions.Add("DEPRECATED_FORGAME=DEPRECATED"); Definitions.Add("UE_DEPRECATED_FORGAME=UE_DEPRECATED"); } // Add this module's private include paths and definitions. IncludePaths.UnionWith(PrivateIncludePaths); // @ATG_CHANGE : BEGIN - winmd support WinMDFiles.AddRange(PrivateWinMDReferences); // @ATG_CHANGE : END - winmd support // Find all the modules that are part of the public compile environment for this module. Dictionary ModuleToIncludePathsOnlyFlag = new Dictionary(); FindModulesInPrivateCompileEnvironment(ModuleToIncludePathsOnlyFlag); // Now set up the compile environment for the modules in the original order that we encountered them foreach (UEBuildModule Module in ModuleToIncludePathsOnlyFlag.Keys) { Module.AddModuleToCompileEnvironment(Binary, IncludePaths, SystemIncludePaths, Definitions, AdditionalFrameworks, bWithLegacyPublicIncludePaths, WinMDFiles); } } /// /// Expand path variables within the context of this module /// /// Path to expand variables within /// Directory containing the binary that links this module. May be mull. /// Directory containing the output executable. May be null. /// The path with variables expanded public string ExpandPathVariables(string Path, DirectoryReference BinaryOutputDir, DirectoryReference TargetOutputDir) { if(Path.StartsWith("$(", StringComparison.Ordinal)) { int StartIdx = 2; for(int EndIdx = StartIdx; EndIdx < Path.Length; EndIdx++) { if(Path[EndIdx] == ')') { if(MatchVariableName(Path, StartIdx, EndIdx, "EngineDir")) { Path = UnrealBuildTool.EngineDirectory + Path.Substring(EndIdx + 1); } else if(MatchVariableName(Path, StartIdx, EndIdx, "ProjectDir")) { if(Rules.Target.ProjectFile == null) { Path = UnrealBuildTool.EngineDirectory + Path.Substring(EndIdx + 1); } else { Path = Rules.Target.ProjectFile.Directory + Path.Substring(EndIdx + 1); } } else if(MatchVariableName(Path, StartIdx, EndIdx, "ModuleDir")) { Path = Rules.ModuleDirectory + Path.Substring(EndIdx + 1); } else if(MatchVariableName(Path, StartIdx, EndIdx, "PluginDir")) { Path = Rules.PluginDirectory + Path.Substring(EndIdx + 1); } else if(BinaryOutputDir != null && MatchVariableName(Path, StartIdx, EndIdx, "BinaryOutputDir")) { Path = BinaryOutputDir.FullName + Path.Substring(EndIdx + 1); } else if(TargetOutputDir != null && MatchVariableName(Path, StartIdx, EndIdx, "TargetOutputDir")) { Path = TargetOutputDir.FullName + Path.Substring(EndIdx + 1); } else { string Name = Path.Substring(StartIdx, EndIdx - StartIdx); string Value = Environment.GetEnvironmentVariable(Name); if(String.IsNullOrEmpty(Value)) { throw new BuildException("Environment variable '{0}' is not defined (referenced by {1})", Name, Rules.File); } Path = Value + Path.Substring(EndIdx + 1); } break; } } } return Path; } /// /// Match a variable name within a path /// /// The path variable /// Start index of the substring to match /// End index of the substring to match /// Variable name to compare against /// True if the variable name matches private bool MatchVariableName(string Path, int StartIdx, int EndIdx, string Name) { return Name.Length == EndIdx - StartIdx && String.Compare(Path, StartIdx, Name, 0, EndIdx - StartIdx) == 0; } /// /// Expand path variables within the context of this module /// /// Path to expand variables within /// Directory containing the binary that links this module. May be mull. /// Directory containing the output executable. May be null. /// The path with variables expanded private IEnumerable ExpandPathVariables(IEnumerable Paths, DirectoryReference BinaryDir, DirectoryReference ExeDir) { foreach(string Path in Paths) { yield return ExpandPathVariables(Path, BinaryDir, ExeDir); } } /// /// Sets up the environment for linking any module that includes the public interface of this module. /// protected virtual void SetupPublicLinkEnvironment( UEBuildBinary SourceBinary, List LibraryPaths, List AdditionalLibraries, List RuntimeLibraryPaths, List Frameworks, List WeakFrameworks, List AdditionalFrameworks, List AdditionalBundleResources, List DelayLoadDLLs, List BinaryDependencies, HashSet VisitedModules, DirectoryReference ExeDir ) { // There may be circular dependencies in compile dependencies, so we need to avoid reentrance. if (VisitedModules.Add(this)) { // Add this module's binary to the binary dependencies. if (Binary != null && Binary != SourceBinary && !BinaryDependencies.Contains(Binary)) { BinaryDependencies.Add(Binary); } // If this module belongs to a static library that we are not currently building, recursively add the link environment settings for all of its dependencies too. // Keep doing this until we reach a module that is not part of a static library (or external module, since they have no associated binary). // Static libraries do not contain the symbols for their dependencies, so we need to recursively gather them to be linked into other binary types. bool bIsBuildingAStaticLibrary = (SourceBinary != null && SourceBinary.Type == UEBuildBinaryType.StaticLibrary); bool bIsModuleBinaryAStaticLibrary = (Binary != null && Binary.Type == UEBuildBinaryType.StaticLibrary); if (!bIsBuildingAStaticLibrary && bIsModuleBinaryAStaticLibrary) { // Gather all dependencies and recursively call SetupPublicLinkEnvironmnet List AllDependencyModules = new List(); AllDependencyModules.AddRange(PrivateDependencyModules); AllDependencyModules.AddRange(PublicDependencyModules); foreach (UEBuildModule DependencyModule in AllDependencyModules) { bool bIsExternalModule = (DependencyModule as UEBuildModuleExternal != null); bool bIsInStaticLibrary = (DependencyModule.Binary != null && DependencyModule.Binary.Type == UEBuildBinaryType.StaticLibrary); if (bIsExternalModule || bIsInStaticLibrary) { DependencyModule.SetupPublicLinkEnvironment(SourceBinary, LibraryPaths, AdditionalLibraries, RuntimeLibraryPaths, Frameworks, WeakFrameworks, AdditionalFrameworks, AdditionalBundleResources, DelayLoadDLLs, BinaryDependencies, VisitedModules, ExeDir); } } } // Add this module's public include library paths and additional libraries. LibraryPaths.AddRange(PublicLibraryPaths); AdditionalLibraries.AddRange(PublicAdditionalLibraries); RuntimeLibraryPaths.AddRange(ExpandPathVariables(Rules.PublicRuntimeLibraryPaths, SourceBinary.OutputDir, ExeDir)); Frameworks.AddRange(PublicFrameworks); WeakFrameworks.AddRange(PublicWeakFrameworks); AdditionalBundleResources.AddRange(PublicAdditionalBundleResources); AdditionalFrameworks.AddRange(PublicAdditionalFrameworks); DelayLoadDLLs.AddRange(PublicDelayLoadDLLs); } } /// /// Sets up the environment for linking this module. /// public virtual void SetupPrivateLinkEnvironment( UEBuildBinary SourceBinary, LinkEnvironment LinkEnvironment, List BinaryDependencies, HashSet VisitedModules, DirectoryReference ExeDir ) { // Add the private rpaths LinkEnvironment.RuntimeLibraryPaths.AddRange(ExpandPathVariables(Rules.PrivateRuntimeLibraryPaths, SourceBinary.OutputDir, ExeDir)); // Allow the module's public dependencies to add library paths and additional libraries to the link environment. SetupPublicLinkEnvironment(SourceBinary, LinkEnvironment.LibraryPaths, LinkEnvironment.AdditionalLibraries, LinkEnvironment.RuntimeLibraryPaths, LinkEnvironment.Frameworks, LinkEnvironment.WeakFrameworks, LinkEnvironment.AdditionalFrameworks, LinkEnvironment.AdditionalBundleResources, LinkEnvironment.DelayLoadDLLs, BinaryDependencies, VisitedModules, ExeDir); // Also allow the module's public and private dependencies to modify the link environment. List AllDependencyModules = new List(); AllDependencyModules.AddRange(PrivateDependencyModules); AllDependencyModules.AddRange(PublicDependencyModules); foreach (UEBuildModule DependencyModule in AllDependencyModules) { DependencyModule.SetupPublicLinkEnvironment(SourceBinary, LinkEnvironment.LibraryPaths, LinkEnvironment.AdditionalLibraries, LinkEnvironment.RuntimeLibraryPaths, LinkEnvironment.Frameworks, LinkEnvironment.WeakFrameworks, LinkEnvironment.AdditionalFrameworks, LinkEnvironment.AdditionalBundleResources, LinkEnvironment.DelayLoadDLLs, BinaryDependencies, VisitedModules, ExeDir); } // Add all the additional properties LinkEnvironment.AdditionalProperties.AddRange(Rules.AdditionalPropertiesForReceipt.Inner); } /// /// Compiles the module, and returns a list of files output by the compiler. /// public abstract List Compile(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, ISourceFileWorkingSet WorkingSet, TargetMakefile Makefile); // Object interface. public override string ToString() { return Name; } /// /// Finds the modules referenced by this module which have not yet been bound to a binary /// /// List of unbound modules public List GetUnboundReferences() { List Modules = new List(); Modules.AddRange(PrivateDependencyModules.Where(x => x.Binary == null)); Modules.AddRange(PublicDependencyModules.Where(x => x.Binary == null)); return Modules; } /// /// Gets all of the modules referenced by this module /// /// Hash of all referenced modules with their addition index. /// Hashset used to ignore modules which are already added to the list /// True if dynamically loaded modules (and all of their dependent modules) should be included. /// True if circular dependencies should be processed /// True to return only this module's direct dependencies public virtual void GetAllDependencyModules(List ReferencedModules, HashSet IgnoreReferencedModules, bool bIncludeDynamicallyLoaded, bool bForceCircular, bool bOnlyDirectDependencies) { } public delegate UEBuildModule CreateModuleDelegate(string Name, string ReferenceChain); /// /// Creates all the modules required for this target /// /// Delegate to create a module with a given name /// Chain of references before reaching this module public void RecursivelyCreateModules(CreateModuleDelegate CreateModule, string ReferenceChain) { // Get the reference chain for anything referenced by this module string NextReferenceChain = String.Format("{0} -> {1}", ReferenceChain, (RulesFile == null)? Name : RulesFile.GetFileName()); // Recursively create all the public include path modules. These modules may not be added to the target (and we don't process their referenced // dependencies), but they need to be created to set up their include paths. RecursivelyCreateIncludePathModulesByName(Rules.PublicIncludePathModuleNames, ref PublicIncludePathModules, CreateModule, NextReferenceChain); // Create all the referenced modules. This path can be recursive, so we check against PrivateIncludePathModules to ensure we don't recurse through the // same module twice (it produces better errors if something fails). if(PrivateIncludePathModules == null) { // Create the private include path modules RecursivelyCreateIncludePathModulesByName(Rules.PrivateIncludePathModuleNames, ref PrivateIncludePathModules, CreateModule, NextReferenceChain); // Create all the dependency modules RecursivelyCreateModulesByName(Rules.PublicDependencyModuleNames, ref PublicDependencyModules, CreateModule, NextReferenceChain); RecursivelyCreateModulesByName(Rules.PrivateDependencyModuleNames, ref PrivateDependencyModules, CreateModule, NextReferenceChain); RecursivelyCreateModulesByName(Rules.DynamicallyLoadedModuleNames, ref DynamicallyLoadedModules, CreateModule, NextReferenceChain); } } private static void RecursivelyCreateModulesByName(List ModuleNames, ref List Modules, CreateModuleDelegate CreateModule, string ReferenceChain) { // Check whether the module list is already set. We set this immediately (via the ref) to avoid infinite recursion. if (Modules == null) { Modules = new List(); foreach (string ModuleName in ModuleNames) { UEBuildModule Module = CreateModule(ModuleName, ReferenceChain); if (!Modules.Contains(Module)) { Module.RecursivelyCreateModules(CreateModule, ReferenceChain); Modules.Add(Module); } } } } private static void RecursivelyCreateIncludePathModulesByName(List ModuleNames, ref List Modules, CreateModuleDelegate CreateModule, string ReferenceChain) { // Check whether the module list is already set. We set this immediately (via the ref) to avoid infinite recursion. if (Modules == null) { Modules = new List(); foreach (string ModuleName in ModuleNames) { UEBuildModule Module = CreateModule(ModuleName, ReferenceChain); RecursivelyCreateIncludePathModulesByName(Module.Rules.PublicIncludePathModuleNames, ref Module.PublicIncludePathModules, CreateModule, ReferenceChain); Modules.Add(Module); } } } /// /// Write information about this binary to a JSON file /// /// The output directory for the binary containing this module /// The output directory for the target executable /// Writer for this binary's data public virtual void ExportJson(DirectoryReference BinaryOutputDir, DirectoryReference TargetOutputDir, JsonWriter Writer) { Writer.WriteValue("Name", Name); Writer.WriteValue("Directory", ModuleDirectory.FullName); Writer.WriteValue("Rules", RulesFile.FullName); Writer.WriteValue("PCHUsage", Rules.PCHUsage.ToString()); if (Rules.PrivatePCHHeaderFile != null) { Writer.WriteValue("PrivatePCH", FileReference.Combine(ModuleDirectory, Rules.PrivatePCHHeaderFile).FullName); } if (Rules.SharedPCHHeaderFile != null) { Writer.WriteValue("SharedPCH", FileReference.Combine(ModuleDirectory, Rules.SharedPCHHeaderFile).FullName); } ExportJsonModuleArray(Writer, "PublicDependencyModules", PublicDependencyModules); ExportJsonModuleArray(Writer, "PublicIncludePathModules", PublicIncludePathModules); ExportJsonModuleArray(Writer, "PrivateDependencyModules", PrivateDependencyModules); ExportJsonModuleArray(Writer, "PrivateIncludePathModules", PrivateIncludePathModules); ExportJsonModuleArray(Writer, "DynamicallyLoadedModules", DynamicallyLoadedModules); ExportJsonStringArray(Writer, "PublicSystemIncludePaths", PublicSystemIncludePaths.Select(x => x.FullName)); ExportJsonStringArray(Writer, "PublicIncludePaths", PublicIncludePaths.Select(x => x.FullName)); ExportJsonStringArray(Writer, "PrivateIncludePaths", PrivateIncludePaths.Select(x => x.FullName)); ExportJsonStringArray(Writer, "PublicLibraryPaths", PublicLibraryPaths.Select(x => x.FullName)); ExportJsonStringArray(Writer, "PublicAdditionalLibraries", PublicAdditionalLibraries); ExportJsonStringArray(Writer, "PublicFrameworks", PublicFrameworks); ExportJsonStringArray(Writer, "PublicWeakFrameworks", PublicWeakFrameworks); ExportJsonStringArray(Writer, "PublicDelayLoadDLLs", PublicDelayLoadDLLs); ExportJsonStringArray(Writer, "PublicDefinitions", PublicDefinitions); Writer.WriteArrayStart("CircularlyReferencedModules"); foreach(string ModuleName in Rules.CircularlyReferencedDependentModules) { Writer.WriteValue(ModuleName); } Writer.WriteArrayEnd(); Writer.WriteArrayStart("RuntimeDependencies"); foreach(ModuleRules.RuntimeDependency RuntimeDependency in Rules.RuntimeDependencies.Inner) { Writer.WriteObjectStart(); Writer.WriteValue("Path", ExpandPathVariables(RuntimeDependency.Path, BinaryOutputDir, TargetOutputDir)); if(RuntimeDependency.SourcePath != null) { Writer.WriteValue("SourcePath", ExpandPathVariables(RuntimeDependency.SourcePath, BinaryOutputDir, TargetOutputDir)); } Writer.WriteValue("Type", RuntimeDependency.Type.ToString()); Writer.WriteObjectEnd(); } Writer.WriteArrayEnd(); } /// /// Write an array of module names to a JSON writer /// /// Writer for the array data /// Name of the array property /// Sequence of modules to write. May be null. void ExportJsonModuleArray(JsonWriter Writer, string ArrayName, IEnumerable Modules) { Writer.WriteArrayStart(ArrayName); if (Modules != null) { foreach (UEBuildModule Module in Modules) { Writer.WriteValue(Module.Name); } } Writer.WriteArrayEnd(); } /// /// Write an array of strings to a JSON writer /// /// Writer for the array data /// Name of the array property /// Sequence of strings to write. May be null. void ExportJsonStringArray(JsonWriter Writer, string ArrayName, IEnumerable Strings) { Writer.WriteArrayStart(ArrayName); if (Strings != null) { foreach(string String in Strings) { Writer.WriteValue(String); } } Writer.WriteArrayEnd(); } }; }