// Copyright 1998-2017 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.CaselessDictionary; namespace UnrealBuildTool { /// /// A unit of code compilation and linking. /// abstract class UEBuildModule { /// /// The name that uniquely identifies the module. /// public readonly string Name; /// /// The type of module being built. Used to switch between debug/development and precompiled/source configurations. /// public UHTModuleType Type; /// /// The rules for this module /// public ModuleRules Rules; /// /// Path to the module directory /// public readonly DirectoryReference ModuleDirectory; /// /// Is this module allowed to be redistributed. /// private readonly bool? IsRedistributableOverride; /// /// The name of the .Build.cs file this module was created from, if any /// public FileReference RulesFile; /// /// The binary the module will be linked into for the current target. Only set after UEBuildBinary.BindModules is called. /// public UEBuildBinary Binary = null; /// /// Include path for this module's base directory, relative to the Engine/Source directory /// protected string NormalizedModuleIncludePath; /// /// 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; /// /// 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 PublicAdditionalShadowFiles; /// /// /// protected readonly HashSet PublicAdditionalBundleResources; /// /// 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; /// /// Extra modules this module may require at run time, that are on behalf of another platform (i.e. shader formats and the like) /// protected List PlatformSpecificDynamicallyLoadedModules; /// /// Files which this module depends on at runtime. /// public RuntimeDependencyList RuntimeDependencies; /// /// Set of all whitelisted restricted folder references /// private readonly HashSet WhitelistRestrictedFolders; /// /// Constructor /// /// Name of the module /// Type of the module, for UHT /// Base directory for the module /// Rules for this module /// Path to the rules file public UEBuildModule(string InName, UHTModuleType InType, DirectoryReference InModuleDirectory, ModuleRules InRules, FileReference InRulesFile) { Name = InName; Type = InType; ModuleDirectory = InModuleDirectory; Rules = InRules; RulesFile = InRulesFile; NormalizedModuleIncludePath = Utils.CleanDirectorySeparators(ModuleDirectory.MakeRelativeTo(UnrealBuildTool.EngineSourceDirectory), '/'); ModuleApiDefine = Name.ToUpperInvariant() + "_API"; PublicDefinitions = HashSetFromOptionalEnumerableStringParameter(InRules.Definitions); PublicIncludePaths = HashSetFromOptionalEnumerableStringParameter(InRules.PublicIncludePaths); PublicSystemIncludePaths = HashSetFromOptionalEnumerableStringParameter(InRules.PublicSystemIncludePaths); PublicLibraryPaths = HashSetFromOptionalEnumerableStringParameter(InRules.PublicLibraryPaths); PublicAdditionalLibraries = HashSetFromOptionalEnumerableStringParameter(InRules.PublicAdditionalLibraries); PublicFrameworks = HashSetFromOptionalEnumerableStringParameter(InRules.PublicFrameworks); PublicWeakFrameworks = HashSetFromOptionalEnumerableStringParameter(InRules.PublicWeakFrameworks); PublicAdditionalFrameworks = InRules.PublicAdditionalFrameworks == null ? new HashSet() : new HashSet(InRules.PublicAdditionalFrameworks); PublicAdditionalShadowFiles = HashSetFromOptionalEnumerableStringParameter(InRules.PublicAdditionalShadowFiles); PublicAdditionalBundleResources = InRules.AdditionalBundleResources == null ? new HashSet() : new HashSet(InRules.AdditionalBundleResources); PublicDelayLoadDLLs = HashSetFromOptionalEnumerableStringParameter(InRules.PublicDelayLoadDLLs); PrivateIncludePaths = HashSetFromOptionalEnumerableStringParameter(InRules.PrivateIncludePaths); RuntimeDependencies = (InRules.RuntimeDependencies == null) ? new RuntimeDependencyList() : new RuntimeDependencyList(InRules.RuntimeDependencies); IsRedistributableOverride = InRules.IsRedistributableOverride; WhitelistRestrictedFolders = new HashSet(InRules.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); Modules.UnionWith(PlatformSpecificDynamicallyLoadedModules); } return Modules; } /// /// 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).Concat(PlatformSpecificDynamicallyLoadedModules); } /// /// Converts an optional string list parameter to a well-defined hash set. /// protected static HashSet HashSetFromOptionalEnumerableStringParameter(IEnumerable InEnumerableStrings) { return InEnumerableStrings == null ? new HashSet() : new HashSet(InEnumerableStrings); } /// /// 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(string PublicIncludePath in PublicIncludePaths) { Directories.Add(new DirectoryReference(PublicIncludePath)); } foreach(string PrivateIncludePath in PrivateIncludePaths) { Directories.Add(new DirectoryReference(PrivateIncludePath)); } foreach(string PublicSystemIncludePath in PublicSystemIncludePaths) { Directories.Add(new DirectoryReference(PublicSystemIncludePath)); } foreach(string PublicLibraryPath in PublicLibraryPaths) { Directories.Add(new DirectoryReference(PublicLibraryPath)); } } /// /// Find all the modules which affect the public compile environment. Searches through /// /// /// protected void FindModulesInPublicCompileEnvironment(List Modules, Dictionary ModuleToIncludePathsOnlyFlag) { // bool bModuleIncludePathsOnly; if (!ModuleToIncludePathsOnlyFlag.TryGetValue(this, out bModuleIncludePathsOnly)) { Modules.Add(this); } else if (!bModuleIncludePathsOnly) { return; } ModuleToIncludePathsOnlyFlag[this] = false; foreach (UEBuildModule DependencyModule in PublicDependencyModules) { DependencyModule.FindModulesInPublicCompileEnvironment(Modules, 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(Modules, ModuleToIncludePathsOnlyFlag); } } /// /// Find all the modules which affect the public compile environment. Searches through /// /// /// protected void FindIncludePathModulesInPublicCompileEnvironment(List Modules, Dictionary ModuleToIncludePathsOnlyFlag) { if (!ModuleToIncludePathsOnlyFlag.ContainsKey(this)) { // Add this module to the list Modules.Add(this); ModuleToIncludePathsOnlyFlag.Add(this, true); // Include any of its public include path modules in the compile environment too foreach (UEBuildModule IncludePathModule in PublicIncludePathModules) { IncludePathModule.FindIncludePathModulesInPublicCompileEnvironment(Modules, ModuleToIncludePathsOnlyFlag); } } } /// /// Sets up the environment for compiling any module that includes the public interface of this module. /// public void AddModuleToCompileEnvironment( UEBuildBinary SourceBinary, bool bIncludePathsOnly, HashSet IncludePaths, HashSet SystemIncludePaths, List Definitions, List AdditionalFrameworks ) { // Add this module's public include paths and definitions. AddIncludePathsWithChecks(IncludePaths, PublicIncludePaths); AddIncludePathsWithChecks(SystemIncludePaths, PublicSystemIncludePaths); Definitions.AddRange(PublicDefinitions); // If this module is being built into a DLL or EXE, set up an IMPORTS or EXPORTS definition for it. if(SourceBinary == null) { // No source binary means a shared PCH, so always import all symbols. It's possible that an include path module now may be a imported module for the shared PCH consumer. if(!bIncludePathsOnly) { if(Binary == null || !Binary.Config.bAllowExports) { Definitions.Add(ModuleApiDefine + "="); } else { Definitions.Add(ModuleApiDefine + "=DLLIMPORT"); } } } else if (Binary == null) { // If we're referencing include paths for a module that's not being built, we don't actually need to import anything from it, but we need to avoid barfing when // the compiler encounters an _API define. We also want to avoid changing the compile environment in cases where the module happens to be compiled because it's a dependency // of something else, which cause a fall-through to the code below and set up an empty _API define. if (bIncludePathsOnly) { Log.TraceVerbose("{0}: Include paths only for {1} (no binary)", SourceBinary.Config.OutputFilePaths[0].GetFileNameWithoutExtension(), Name); Definitions.Add(ModuleApiDefine + "="); } } else { FileReference BinaryPath = Binary.Config.OutputFilePaths[0]; FileReference SourceBinaryPath = SourceBinary.Config.OutputFilePaths[0]; if (ProjectFileGenerator.bGenerateProjectFiles || (Binary.Config.Type == UEBuildBinaryType.StaticLibrary)) { // When generating IntelliSense files, never add dllimport/dllexport specifiers as it // simply confuses the compiler Definitions.Add(ModuleApiDefine + "="); } else if (Binary == SourceBinary) { if (Binary.Config.bAllowExports) { Log.TraceVerbose("{0}: Exporting {1} from {2}", SourceBinaryPath.GetFileNameWithoutExtension(), Name, BinaryPath.GetFileNameWithoutExtension()); Definitions.Add(ModuleApiDefine + "=DLLEXPORT"); } else { Log.TraceVerbose("{0}: Not importing/exporting {1} (binary: {2})", SourceBinaryPath.GetFileNameWithoutExtension(), Name, BinaryPath.GetFileNameWithoutExtension()); Definitions.Add(ModuleApiDefine + "="); } } else { // @todo SharedPCH: Public headers included from modules that are not importing the module of that public header, seems invalid. // Those public headers have no business having APIs in them. OnlineSubsystem has some public headers like this. Without changing // this, we need to suppress warnings at compile time. if (bIncludePathsOnly) { Log.TraceVerbose("{0}: Include paths only for {1} (binary: {2})", SourceBinaryPath.GetFileNameWithoutExtension(), Name, BinaryPath.GetFileNameWithoutExtension()); Definitions.Add(ModuleApiDefine + "="); } else if (Binary.Config.bAllowExports) { Log.TraceVerbose("{0}: Importing {1} from {2}", SourceBinaryPath.GetFileNameWithoutExtension(), Name, BinaryPath.GetFileNameWithoutExtension()); Definitions.Add(ModuleApiDefine + "=DLLIMPORT"); } else { Log.TraceVerbose("{0}: Not importing/exporting {1} (binary: {2})", SourceBinaryPath.GetFileNameWithoutExtension(), Name, BinaryPath.GetFileNameWithoutExtension()); Definitions.Add(ModuleApiDefine + "="); } } } // Add the module's directory to the include path, so we can root #includes to it IncludePaths.Add(NormalizedModuleIncludePath); // Add the additional frameworks so that the compiler can know about their #include paths AdditionalFrameworks.AddRange(PublicAdditionalFrameworks); // Remember the module so we can refer to it when needed foreach (UEBuildFramework Framework in PublicAdditionalFrameworks) { Framework.OwningModule = this; } } static Regex VCMacroRegex = new Regex(@"\$\([A-Za-z0-9_]+\)"); /// /// Checks if path contains a VC macro /// protected bool DoesPathContainVCMacro(string Path) { return VCMacroRegex.IsMatch(Path); } /// /// Adds PathsToAdd to IncludePaths, performing path normalization and ignoring duplicates. /// protected void AddIncludePathsWithChecks(HashSet IncludePaths, HashSet PathsToAdd) { if (ProjectFileGenerator.bGenerateProjectFiles) { // Extra checks are switched off for IntelliSense generation as they provide // no additional value and cause performance impact. IncludePaths.UnionWith(PathsToAdd); } else { foreach (string Path in PathsToAdd) { string NormalizedPath = Path.TrimEnd('/'); // If path doesn't exist, it may contain VC macro (which is passed directly to and expanded by compiler). if (Directory.Exists(NormalizedPath) || DoesPathContainVCMacro(NormalizedPath)) { IncludePaths.Add(NormalizedPath); } } } } /// /// Sets up the environment for compiling this module. /// protected virtual void SetupPrivateCompileEnvironment( HashSet IncludePaths, HashSet SystemIncludePaths, List Definitions, List AdditionalFrameworks ) { HashSet VisitedModules = new HashSet(); if (this.Type.IsGameModule()) { Definitions.Add("DEPRECATED_FORGAME=DEPRECATED"); } // Add this module's private include paths and definitions. AddIncludePathsWithChecks(IncludePaths, PrivateIncludePaths); // Find all the modules that are part of the public compile environment for this module. List Modules = new List(); Dictionary ModuleToIncludePathsOnlyFlag = new Dictionary(); FindModulesInPublicCompileEnvironment(Modules, ModuleToIncludePathsOnlyFlag); // Add in all the modules that are private dependencies foreach (UEBuildModule DependencyModule in PrivateDependencyModules) { DependencyModule.FindModulesInPublicCompileEnvironment(Modules, ModuleToIncludePathsOnlyFlag); } // And finally add in all the modules that are include path only dependencies foreach (UEBuildModule IncludePathModule in PrivateIncludePathModules) { IncludePathModule.FindIncludePathModulesInPublicCompileEnvironment(Modules, ModuleToIncludePathsOnlyFlag); } // Now set up the compile environment for the modules in the original order that we encountered them foreach (UEBuildModule Module in Modules) { Module.AddModuleToCompileEnvironment(Binary, ModuleToIncludePathsOnlyFlag[Module], IncludePaths, SystemIncludePaths, Definitions, AdditionalFrameworks); } } /// /// 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 Frameworks, List WeakFrameworks, List AdditionalFrameworks, List AdditionalShadowFiles, List AdditionalBundleResources, List DelayLoadDLLs, List BinaryDependencies, HashSet VisitedModules ) { // 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.Config.Type == UEBuildBinaryType.StaticLibrary); bool bIsModuleBinaryAStaticLibrary = (Binary != null && Binary.Config.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.Config.Type == UEBuildBinaryType.StaticLibrary); if (bIsExternalModule || bIsInStaticLibrary) { DependencyModule.SetupPublicLinkEnvironment(SourceBinary, LibraryPaths, AdditionalLibraries, Frameworks, WeakFrameworks, AdditionalFrameworks, AdditionalShadowFiles, AdditionalBundleResources, DelayLoadDLLs, BinaryDependencies, VisitedModules); } } } // Add this module's public include library paths and additional libraries. LibraryPaths.AddRange(PublicLibraryPaths); AdditionalLibraries.AddRange(PublicAdditionalLibraries); Frameworks.AddRange(PublicFrameworks); WeakFrameworks.AddRange(PublicWeakFrameworks); AdditionalBundleResources.AddRange(PublicAdditionalBundleResources); // Remember the module so we can refer to it when needed foreach (UEBuildFramework Framework in PublicAdditionalFrameworks) { Framework.OwningModule = this; } AdditionalFrameworks.AddRange(PublicAdditionalFrameworks); AdditionalShadowFiles.AddRange(PublicAdditionalShadowFiles); DelayLoadDLLs.AddRange(PublicDelayLoadDLLs); } } /// /// Sets up the environment for linking this module. /// public virtual void SetupPrivateLinkEnvironment( UEBuildBinary SourceBinary, LinkEnvironment LinkEnvironment, List BinaryDependencies, HashSet VisitedModules ) { // Allow the module's public dependencies to add library paths and additional libraries to the link environment. SetupPublicLinkEnvironment(SourceBinary, LinkEnvironment.LibraryPaths, LinkEnvironment.AdditionalLibraries, LinkEnvironment.Frameworks, LinkEnvironment.WeakFrameworks, LinkEnvironment.AdditionalFrameworks, LinkEnvironment.AdditionalShadowFiles, LinkEnvironment.AdditionalBundleResources, LinkEnvironment.DelayLoadDLLs, BinaryDependencies, VisitedModules); // 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.Frameworks, LinkEnvironment.WeakFrameworks, LinkEnvironment.AdditionalFrameworks, LinkEnvironment.AdditionalShadowFiles, LinkEnvironment.AdditionalBundleResources, LinkEnvironment.DelayLoadDLLs, BinaryDependencies, VisitedModules); } } /// /// Compiles the module, and returns a list of files output by the compiler. /// public abstract List Compile(ReadOnlyTargetRules Target, UEToolChain ToolChain, CppCompileEnvironment CompileEnvironment, List SharedPCHModules, ActionGraph ActionGraph); // 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) { } /// /// Gets all of the modules precompiled along with this module /// /// Set of all the precompiled modules public virtual void RecursivelyAddPrecompiledModules(List Modules) { } public delegate UEBuildModule CreateModuleDelegate(string Name); /// /// Creates all the modules required for this target /// public void RecursivelyCreateModules(CreateModuleDelegate CreateModule) { // Create all the include path modules. These modules may not be added to the target (and we don't process their dependencies), but they need // to be created to set up their compile environment. RecursivelyCreateIncludePathModulesByName(Rules.PublicIncludePathModuleNames, ref PublicIncludePathModules, CreateModule); RecursivelyCreateIncludePathModulesByName(Rules.PrivateIncludePathModuleNames, ref PrivateIncludePathModules, CreateModule); // Create all the dependency modules RecursivelyCreateModulesByName(Rules.PublicDependencyModuleNames, ref PublicDependencyModules, CreateModule); RecursivelyCreateModulesByName(Rules.PrivateDependencyModuleNames, ref PrivateDependencyModules, CreateModule); RecursivelyCreateModulesByName(Rules.DynamicallyLoadedModuleNames, ref DynamicallyLoadedModules, CreateModule); RecursivelyCreateModulesByName(Rules.PlatformSpecificDynamicallyLoadedModuleNames, ref PlatformSpecificDynamicallyLoadedModules, CreateModule); } private static void RecursivelyCreateModulesByName(List ModuleNames, ref List Modules, CreateModuleDelegate CreateModule) { // 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); if (!Modules.Contains(Module)) { Module.RecursivelyCreateModules(CreateModule); Modules.Add(Module); } } } } private static void RecursivelyCreateIncludePathModulesByName(List ModuleNames, ref List Modules, CreateModuleDelegate CreateModule) { // 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); RecursivelyCreateIncludePathModulesByName(Module.Rules.PublicIncludePathModuleNames, ref Module.PublicIncludePathModules, CreateModule); Modules.Add(Module); } } } /// /// Write information about this binary to a JSON file /// /// Writer for this binary's data public virtual void ExportJson(JsonWriter Writer) { Writer.WriteValue("Name", Name); Writer.WriteValue("Type", Type.ToString()); 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); Writer.WriteArrayStart("CircularlyReferencedModules"); foreach(string ModuleName in Rules.CircularlyReferencedDependentModules) { Writer.WriteValue(ModuleName); } Writer.WriteArrayEnd(); Writer.WriteArrayStart("RuntimeDependencies"); foreach(RuntimeDependency RuntimeDependency in Rules.RuntimeDependencies) { Writer.WriteObjectStart(); Writer.WriteValue("Path", RuntimeDependency.Path); 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(); } }; }