// 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; }
}
///
/// Paths to all potential module source directories (with platform extension directories added in)
///
protected DirectoryReference[] ModuleDirectories;
///
/// 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;
///
/// The name of the _VTABLE define for this module
///
protected readonly string ModuleVTableDefine;
///
/// 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";
ModuleVTableDefine = Name.ToUpperInvariant() + "_VTABLE";
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", FrameworkRules.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)));
// merge the main directory and any others set in the Rules
List MergedDirectories = new List { ModuleDirectory };
DirectoryReference[] ExtraModuleDirectories = Rules.GetModuleDirectoriesForAllSubClasses();
if (ExtraModuleDirectories != null)
{
MergedDirectories.AddRange(ExtraModuleDirectories);
}
// cache the results (it will always at least have the ModuleDirectory)
ModuleDirectories = MergedDirectories.ToArray();
}
///
/// 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(DirectoryLookupCache.DirectoryExists(Dir))
{
Directories.Add(Dir);
}
else
{
Log.WriteLineOnce(LogEventType.Warning, LogFormatOptions.NoSeverityPrefix, "{0}: warning: Referenced directory '{1}' does not exist.", RulesFile, Dir);
}
}
}
return Directories;
}
///
/// 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;
// @todo platplug does this need to check platform extension engine directories? what are ReferencedDir's here?
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 || Rules.ModuleSymbolVisibility == ModuleRules.SymbolVisibility.VisibileForDll))
{
Definitions.Add(ModuleVTableDefine + "=DLLEXPORT_VTABLE");
Definitions.Add(ModuleApiDefine + "=DLLEXPORT");
}
else
{
Definitions.Add(ModuleVTableDefine + "=");
Definitions.Add(ModuleApiDefine + "=");
}
}
else if(Binary == null || SourceBinary != Binary)
{
Definitions.Add(ModuleVTableDefine + "=DLLIMPORT_VTABLE");
Definitions.Add(ModuleApiDefine + "=DLLIMPORT");
}
else if(!Binary.bAllowExports)
{
Definitions.Add(ModuleVTableDefine + "=");
Definitions.Add(ModuleApiDefine + "=");
}
else
{
Definitions.Add(ModuleVTableDefine + "=DLLEXPORT_VTABLE");
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);
// this is a link-time property that needs to be accumulated (if any modules contributing to this module is ignoring, all are ignoring)
LinkEnvironment.bIgnoreUnresolvedSymbols |= Rules.bIgnoreUnresolvedSymbols;
}
///
/// 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();
}
};
}