public override void RecursivelyAddIncludePathModules( UEBuildTarget Target, bool bPublicIncludesOnly ) { var AllIncludePathModuleNames = new List<string>(); AllIncludePathModuleNames.AddRange( PublicIncludePathModuleNames ); if( !bPublicIncludesOnly ) { AllIncludePathModuleNames.AddRange( PrivateIncludePathModuleNames ); } foreach( var IncludePathModuleName in AllIncludePathModuleNames ) { var IncludePathModule = Target.FindOrCreateModuleByName( IncludePathModuleName ); // No need to do anything here. We just want to make sure that we've instantiated our representation of the // module so that we can find it later when processing include path module names. Unlike actual dependency // modules, these include path modules may never be "bound" (have Binary or bIncludedInTarget member variables set) // We'll also need to make sure we know about all dependent public include path modules, too! IncludePathModule.RecursivelyAddIncludePathModules( Target, bPublicIncludesOnly:true ); } }
private static void RecursivelyCreateIncludePathModulesByName(UEBuildTarget Target, List<string> ModuleNames, ref List<UEBuildModule> Modules) { // 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<UEBuildModule>(); foreach (string ModuleName in ModuleNames) { UEBuildModule Module = Target.FindOrCreateModuleByName(ModuleName); RecursivelyCreateIncludePathModulesByName(Target, Module.Rules.PublicIncludePathModuleNames, ref Module.PublicIncludePathModules); Modules.Add(Module); } } }
// UEBuildModule interface. public override List<FileItem> Compile(UEBuildTarget Target, UEToolChain ToolChain, CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment) { UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform); List<FileItem> LinkInputFiles = new List<FileItem>(); if (ProjectFileGenerator.bGenerateProjectFiles && IntelliSenseGatherer == null) { // Nothing to do for IntelliSense, bail out early return LinkInputFiles; } CPPEnvironment ModuleCompileEnvironment = CreateModuleCompileEnvironment(Target, CompileEnvironment); IncludeSearchPaths = ModuleCompileEnvironment.Config.CPPIncludeInfo.IncludePaths.ToList(); IncludeSearchPaths.AddRange(ModuleCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths.ToList()); if (IntelliSenseGatherer != null) { // Update project file's set of preprocessor definitions and include paths IntelliSenseGatherer.AddIntelliSensePreprocessorDefinitions(ModuleCompileEnvironment.Config.Definitions); IntelliSenseGatherer.AddInteliiSenseIncludePaths(ModuleCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths, bAddingSystemIncludes: true); IntelliSenseGatherer.AddInteliiSenseIncludePaths(ModuleCompileEnvironment.Config.CPPIncludeInfo.IncludePaths, bAddingSystemIncludes: false); // Bail out. We don't need to actually compile anything while generating project files. return LinkInputFiles; } // Throw an error if the module's source file list referenced any non-existent files. if (SourceFilesToBuild.MissingFiles.Count > 0) { throw new BuildException( "UBT ERROR: Module \"{0}\" references non-existent files:\n{1} (perhaps a file was added to the project but not checked in)", Name, string.Join("\n", SourceFilesToBuild.MissingFiles.Select(M => M.AbsolutePath)) ); } // For an executable or a static library do not use the default RC file - // If the executable wants it, it will be in their source list anyway. // The issue here is that when making a monolithic game, the processing // of the other game modules will stomp the game-specific rc file. if (Binary.Config.Type == UEBuildBinaryType.DynamicLinkLibrary) { // Add default PCLaunch.rc file if this module has no own resource file specified if (SourceFilesToBuild.RCFiles.Count <= 0) { FileReference DefRC = FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Runtime", "Launch", "Resources", "Windows", "PCLaunch.rc"); FileItem Item = FileItem.GetItemByFileReference(DefRC); SourceFilesToBuild.RCFiles.Add(Item); } // Always compile in the API version resource separately. This is required for the module manager to detect compatible API versions. FileReference ModuleVersionRC = FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Runtime", "Core", "Resources", "Windows", "ModuleVersionResource.rc.inl"); FileItem ModuleVersionItem = FileItem.GetItemByFileReference(ModuleVersionRC); if (!SourceFilesToBuild.RCFiles.Contains(ModuleVersionItem)) { SourceFilesToBuild.RCFiles.Add(ModuleVersionItem); } } { // Process all of the header file dependencies for this module this.CachePCHUsageForModuleSourceFiles(Target, ModuleCompileEnvironment); // Make sure our RC files have cached includes. foreach (FileItem RCFile in SourceFilesToBuild.RCFiles) { RCFile.CachedCPPIncludeInfo = ModuleCompileEnvironment.Config.CPPIncludeInfo; } } // Check to see if this is an Engine module (including program or plugin modules). That is, the module is located under the "Engine" folder bool IsPluginModule = ModuleDirectory.IsUnderDirectory(DirectoryReference.Combine(Target.ProjectDirectory, "Plugins")); bool IsGameModule = !IsPluginModule && !ModuleDirectory.IsUnderDirectory(UnrealBuildTool.EngineDirectory); // Should we force a precompiled header to be generated for this module? Usually, we only bother with a // precompiled header if there are at least several source files in the module (after combining them for unity // builds.) But for game modules, it can be convenient to always have a precompiled header to single-file // changes to code is really quick to compile. int MinFilesUsingPrecompiledHeader = BuildConfiguration.MinFilesUsingPrecompiledHeader; if (Rules.MinFilesUsingPrecompiledHeaderOverride != 0) { MinFilesUsingPrecompiledHeader = Rules.MinFilesUsingPrecompiledHeaderOverride; } else if (IsGameModule && BuildConfiguration.bForcePrecompiledHeaderForGameModules) { // This is a game module with only a small number of source files, so go ahead and force a precompiled header // to be generated to make incremental changes to source files as fast as possible for small projects. MinFilesUsingPrecompiledHeader = 1; } // Engine modules will always use unity build mode unless MinSourceFilesForUnityBuildOverride is specified in // the module rules file. By default, game modules only use unity of they have enough source files for that // to be worthwhile. If you have a lot of small game modules, consider specifying MinSourceFilesForUnityBuildOverride=0 // in the modules that you don't typically iterate on source files in very frequently. int MinSourceFilesForUnityBuild = 0; if (Rules.MinSourceFilesForUnityBuildOverride != 0) { MinSourceFilesForUnityBuild = Rules.MinSourceFilesForUnityBuildOverride; } else if (IsGameModule) { // Game modules with only a small number of source files are usually better off having faster iteration times // on single source file changes, so we forcibly disable unity build for those modules MinSourceFilesForUnityBuild = BuildConfiguration.MinGameModuleSourceFilesForUnityBuild; } // Should we use unity build mode for this module? bool bModuleUsesUnityBuild = false; if (BuildConfiguration.bUseUnityBuild || BuildConfiguration.bForceUnityBuild) { if (BuildConfiguration.bForceUnityBuild) { Log.TraceVerbose("Module '{0}' using unity build mode (bForceUnityBuild enabled for this module)", this.Name); bModuleUsesUnityBuild = true; } else if (Rules.bFasterWithoutUnity) { Log.TraceVerbose("Module '{0}' not using unity build mode (bFasterWithoutUnity enabled for this module)", this.Name); bModuleUsesUnityBuild = false; } else if (SourceFilesToBuild.CPPFiles.Count < MinSourceFilesForUnityBuild) { Log.TraceVerbose("Module '{0}' not using unity build mode (module with fewer than {1} source files)", this.Name, MinSourceFilesForUnityBuild); bModuleUsesUnityBuild = false; } else { Log.TraceVerbose("Module '{0}' using unity build mode (enabled in BuildConfiguration)", this.Name); bModuleUsesUnityBuild = true; } } else { Log.TraceVerbose("Module '{0}' not using unity build mode (disabled in BuildConfiguration)", this.Name); } // The environment with which to compile the CPP files CPPEnvironment CPPCompileEnvironment = ModuleCompileEnvironment; // Precompiled header support. bool bWasModuleCodeCompiled = false; if (BuildPlatform.ShouldUsePCHFiles(CompileEnvironment.Config.Target.Platform, CompileEnvironment.Config.Target.Configuration)) { DateTime PCHGenTimerStart = DateTime.UtcNow; // The code below will figure out whether this module will either use a "unique PCH" (private PCH that will only be included by // this module's code files), or a "shared PCH" (potentially included by many code files in many modules.) Only one or the other // will be used. FileItem SharedPCHHeaderFile = null; // In the case of a shared PCH, we also need to keep track of which module that PCH's header file is a member of string SharedPCHModuleName = String.Empty; if (BuildConfiguration.bUseSharedPCHs && CompileEnvironment.Config.bIsBuildingLibrary) { Log.TraceVerbose("Module '{0}' was not allowed to use Shared PCHs, because we're compiling to a library", this.Name); } bool bUseSharedPCHFiles = BuildConfiguration.bUseSharedPCHs && !CompileEnvironment.Config.bIsBuildingLibrary && GlobalCompileEnvironment.SharedPCHHeaderFiles.Count > 0; if (bUseSharedPCHFiles) { FileReference SharingPCHHeaderFilePath = null; bool bIsASharedPCHModule = bUseSharedPCHFiles && GlobalCompileEnvironment.SharedPCHHeaderFiles.Any(PCH => PCH.Module == this); if (bIsASharedPCHModule) { SharingPCHHeaderFilePath = FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, Rules.SharedPCHHeaderFile); } // We can't use a shared PCH file when compiling a module // with exports, because the shared PCH can only have imports in it to work correctly. bool bAllowSharedPCH = (Rules.PCHUsage == ModuleRules.PCHUsageMode.NoSharedPCHs) ? false : true; bool bCanModuleUseOwnSharedPCH = bAllowSharedPCH && bIsASharedPCHModule && !Binary.Config.bAllowExports && ProcessedDependencies.UniquePCHHeaderFile.Reference == SharingPCHHeaderFilePath; if (bAllowSharedPCH && (!bIsASharedPCHModule || bCanModuleUseOwnSharedPCH)) { // Figure out which shared PCH tier we're in List<UEBuildModule> ReferencedModules = new List<UEBuildModule>(); { this.GetAllDependencyModules(ReferencedModules, new HashSet<UEBuildModule>(), bIncludeDynamicallyLoaded: false, bForceCircular: false, bOnlyDirectDependencies: true); } int LargestSharedPCHHeaderFileIndex = -1; foreach (UEBuildModule DependencyModule in ReferencedModules) { // These Shared PCHs are ordered from least complex to most complex. We'll start at the last one and search backwards. for (int SharedPCHHeaderFileIndex = GlobalCompileEnvironment.SharedPCHHeaderFiles.Count - 1; SharedPCHHeaderFileIndex > LargestSharedPCHHeaderFileIndex; --SharedPCHHeaderFileIndex) { SharedPCHHeaderInfo CurSharedPCHHeaderFile = GlobalCompileEnvironment.SharedPCHHeaderFiles[SharedPCHHeaderFileIndex]; if (DependencyModule == CurSharedPCHHeaderFile.Module || (bIsASharedPCHModule && CurSharedPCHHeaderFile.Module == this)) // If we ourselves are a shared PCH module, always at least use our own module as our shared PCH header if we can't find anything better { SharedPCHModuleName = CurSharedPCHHeaderFile.Module.Name; SharedPCHHeaderFile = CurSharedPCHHeaderFile.PCHHeaderFile; LargestSharedPCHHeaderFileIndex = SharedPCHHeaderFileIndex; break; } } if (LargestSharedPCHHeaderFileIndex == GlobalCompileEnvironment.SharedPCHHeaderFiles.Count - 1) { // We've determined that the module is using our most complex PCH header, so we can early-out break; } } // Did we not find a shared PCH header that is being included by this module? This could happen if the module is not including Core.h, even indirectly. if (String.IsNullOrEmpty(SharedPCHModuleName)) { throw new BuildException("Module {0} doesn't use a Shared PCH! Please add a dependency on a Shared PCH module to this module's dependency list", this.Name); } // Keep track of how many modules make use of this PCH for performance diagnostics SharedPCHHeaderInfo LargestSharedPCHHeader = GlobalCompileEnvironment.SharedPCHHeaderFiles[LargestSharedPCHHeaderFileIndex]; ++LargestSharedPCHHeader.NumModulesUsingThisPCH; // Don't allow game modules to use engine PCHs in DebugGame - the optimization settings aren't correct. // @todo: we should be creating shared PCHs ahead of time, and only using them if our settings match. as it is, the first modules compiled // (which are currently plugins) get to call the shots for how the shared PCH gets built, and that might be a game plugin built in debug... if(Target.Configuration == UnrealTargetConfiguration.DebugGame && SharedPCHHeaderFile.Reference.IsUnderDirectory(UnrealBuildTool.EngineDirectory) && !RulesFile.IsUnderDirectory(UnrealBuildTool.EngineDirectory)) { SharedPCHModuleName = null; SharedPCHHeaderFile = null; } } else { Log.TraceVerbose("Module '{0}' cannot create or use Shared PCHs, because it needs its own private PCH", this.Name); } } // The precompiled header environment for all source files in this module that use a precompiled header, if we even need one PrecompileHeaderEnvironment ModulePCHEnvironment = null; // If there was one header that was included first by enough C++ files, use it as the precompiled header. // Only use precompiled headers for projects with enough files to make the PCH creation worthwhile. if (SharedPCHHeaderFile != null || SourceFilesToBuild.CPPFiles.Count >= MinFilesUsingPrecompiledHeader) { FileItem PCHToUse; if (SharedPCHHeaderFile != null) { ModulePCHEnvironment = ApplySharedPCH(GlobalCompileEnvironment, CompileEnvironment, ModuleCompileEnvironment, SourceFilesToBuild.CPPFiles, ref SharedPCHHeaderFile); if (ModulePCHEnvironment != null) { // @todo SharedPCH: Ideally we would exhaustively check for a compatible compile environment (definitions, imports/exports, etc) // Currently, it's possible for the shared PCH to be compiled differently depending on which module UBT happened to have // include it first during the build phase. This could create problems with deterministic builds, or turn up compile // errors unexpectedly due to compile environment differences. Log.TraceVerbose("Module " + Name + " uses existing Shared PCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "' (from module " + ModulePCHEnvironment.ModuleName + ")"); } PCHToUse = SharedPCHHeaderFile; } else { PCHToUse = ProcessedDependencies.UniquePCHHeaderFile; } if (PCHToUse != null) { // Update all CPPFiles to point to the PCH foreach (FileItem CPPFile in SourceFilesToBuild.CPPFiles) { CPPFile.PCHHeaderNameInCode = PCHToUse.AbsolutePath; CPPFile.PrecompiledHeaderIncludeFilename = PCHToUse.Reference; } } // A shared PCH was not already set up for us, so set one up. if (ModulePCHEnvironment == null && SourceFilesToBuild.CPPFiles.Count > 0) { FileItem PCHHeaderFile = ProcessedDependencies.UniquePCHHeaderFile; string PCHModuleName = this.Name; if (SharedPCHHeaderFile != null) { PCHHeaderFile = SharedPCHHeaderFile; PCHModuleName = SharedPCHModuleName; } string PCHHeaderNameInCode = SourceFilesToBuild.CPPFiles[0].PCHHeaderNameInCode; ModulePCHEnvironment = new PrecompileHeaderEnvironment(PCHModuleName, PCHHeaderNameInCode, PCHHeaderFile, ModuleCompileEnvironment.Config.CLRMode, ModuleCompileEnvironment.Config.OptimizeCode); if (SharedPCHHeaderFile != null) { // Add to list of shared PCH environments GlobalCompileEnvironment.SharedPCHEnvironments.Add(ModulePCHEnvironment); Log.TraceVerbose("Module " + Name + " uses new Shared PCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "'"); } else { Log.TraceVerbose("Module " + Name + " uses a Unique PCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "'"); } } } else { Log.TraceVerbose("Module " + Name + " doesn't use a Shared PCH, and only has " + SourceFilesToBuild.CPPFiles.Count.ToString() + " source file(s). No Unique PCH will be generated."); } // Compile the C++ source or the unity C++ files that use a PCH environment. if (ModulePCHEnvironment != null) { // Setup a new compile environment for this module's source files. It's pretty much the exact same as the // module's compile environment, except that it will include a PCH file. CPPEnvironment ModulePCHCompileEnvironment = ModuleCompileEnvironment.DeepCopy(); ModulePCHCompileEnvironment.Config.PrecompiledHeaderAction = PrecompiledHeaderAction.Include; ModulePCHCompileEnvironment.Config.PrecompiledHeaderIncludeFilename = ModulePCHEnvironment.PrecompiledHeaderIncludeFilename.Reference; ModulePCHCompileEnvironment.Config.PCHHeaderNameInCode = ModulePCHEnvironment.PCHHeaderNameInCode; if (SharedPCHHeaderFile != null) { // Shared PCH headers need to be force included, because we're basically forcing the module to use // the precompiled header that we want, instead of the "first include" in each respective .cpp file ModulePCHCompileEnvironment.Config.bForceIncludePrecompiledHeader = true; } List<FileItem> CPPFilesToBuild = SourceFilesToBuild.CPPFiles; if (bModuleUsesUnityBuild) { // unity files generated for only the set of files which share the same PCH environment CPPFilesToBuild = Unity.GenerateUnityCPPs(ToolChain, Target, CPPFilesToBuild, ModulePCHCompileEnvironment, Name); } // Check if there are enough unity files to warrant pch generation (and we haven't already generated the shared one) if (ModulePCHEnvironment.PrecompiledHeaderFile == null) { if (SharedPCHHeaderFile != null || CPPFilesToBuild.Count >= MinFilesUsingPrecompiledHeader) { CPPOutput PCHOutput; if (SharedPCHHeaderFile == null) { PCHOutput = PrecompileHeaderEnvironment.GeneratePCHCreationAction( ToolChain, Target, CPPFilesToBuild[0].PCHHeaderNameInCode, ModulePCHEnvironment.PrecompiledHeaderIncludeFilename, ModuleCompileEnvironment, ModuleCompileEnvironment.Config.OutputDirectory, ModuleCompileEnvironment.Config.PCHOutputDirectory, Name, true); } else { UEBuildModuleCPP SharedPCHModule = (UEBuildModuleCPP)Target.FindOrCreateModuleByName(SharedPCHModuleName); CPPEnvironment SharedPCHCompileEnvironment = GlobalCompileEnvironment.DeepCopy(); SharedPCHCompileEnvironment.Config.bEnableShadowVariableWarning = SharedPCHModule.Rules.bEnableShadowVariableWarnings; List<UEBuildModule> Modules = new List<UEBuildModule>(); Dictionary<UEBuildModule, bool> ModuleToIncludePathsOnlyFlag = new Dictionary<UEBuildModule, bool>(); SharedPCHModule.FindModulesInPublicCompileEnvironment(Modules, ModuleToIncludePathsOnlyFlag); foreach (UEBuildModule Module in Modules) { Module.AddModuleToCompileEnvironment( Binary, ModuleToIncludePathsOnlyFlag[Module], SharedPCHCompileEnvironment.Config.CPPIncludeInfo.IncludePaths, SharedPCHCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths, SharedPCHCompileEnvironment.Config.Definitions, SharedPCHCompileEnvironment.Config.AdditionalFrameworks); } PCHOutput = PrecompileHeaderEnvironment.GeneratePCHCreationAction( ToolChain, Target, CPPFilesToBuild[0].PCHHeaderNameInCode, ModulePCHEnvironment.PrecompiledHeaderIncludeFilename, SharedPCHCompileEnvironment, DirectoryReference.Combine(CompileEnvironment.Config.OutputDirectory, "SharedPCHs"), (CompileEnvironment.Config.PCHOutputDirectory == null)? null : DirectoryReference.Combine(CompileEnvironment.Config.PCHOutputDirectory, "SharedPCHs"), "Shared", false); } ModulePCHEnvironment.PrecompiledHeaderFile = PCHOutput.PrecompiledHeaderFile; ModulePCHEnvironment.OutputObjectFiles.Clear(); ModulePCHEnvironment.OutputObjectFiles.AddRange(PCHOutput.ObjectFiles); } else if (CPPFilesToBuild.Count < MinFilesUsingPrecompiledHeader) { Log.TraceVerbose("Module " + Name + " doesn't use a Shared PCH, and only has " + CPPFilesToBuild.Count.ToString() + " unity source file(s). No Unique PCH will be generated."); } } if (ModulePCHEnvironment.PrecompiledHeaderFile != null) { // Link in the object files produced by creating the precompiled header. LinkInputFiles.AddRange(ModulePCHEnvironment.OutputObjectFiles); // if pch action was generated for the environment then use pch ModulePCHCompileEnvironment.PrecompiledHeaderFile = ModulePCHEnvironment.PrecompiledHeaderFile; // Use this compile environment from now on CPPCompileEnvironment = ModulePCHCompileEnvironment; } LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(Target, CPPCompileEnvironment, CPPFilesToBuild, Name).ObjectFiles); bWasModuleCodeCompiled = true; } if (BuildConfiguration.bPrintPerformanceInfo) { double PCHGenTime = (DateTime.UtcNow - PCHGenTimerStart).TotalSeconds; TotalPCHGenTime += PCHGenTime; } } if (!bWasModuleCodeCompiled && SourceFilesToBuild.CPPFiles.Count > 0) { List<FileItem> CPPFilesToCompile = SourceFilesToBuild.CPPFiles; if (bModuleUsesUnityBuild) { CPPFilesToCompile = Unity.GenerateUnityCPPs(ToolChain, Target, CPPFilesToCompile, CPPCompileEnvironment, Name); } LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(Target, CPPCompileEnvironment, CPPFilesToCompile, Name).ObjectFiles); } if (AutoGenerateCppInfo != null && AutoGenerateCppInfo.BuildInfo != null && !CPPCompileEnvironment.bHackHeaderGenerator) { string[] GeneratedFiles = Directory.GetFiles(Path.GetDirectoryName(AutoGenerateCppInfo.BuildInfo.FileWildcard), Path.GetFileName(AutoGenerateCppInfo.BuildInfo.FileWildcard)); foreach (string GeneratedFilename in GeneratedFiles) { FileItem GeneratedCppFileItem = FileItem.GetItemByPath(GeneratedFilename); CachePCHUsageForModuleSourceFile(Target, CPPCompileEnvironment, GeneratedCppFileItem); // @todo ubtmake: Check for ALL other places where we might be injecting .cpp or .rc files for compiling without caching CachedCPPIncludeInfo first (anything platform specific?) LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(Target, CPPCompileEnvironment, new List<FileItem> { GeneratedCppFileItem }, Name).ObjectFiles); } } // Compile C files directly. LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(Target, CPPCompileEnvironment, SourceFilesToBuild.CFiles, Name).ObjectFiles); // Compile CC files directly. LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(Target, CPPCompileEnvironment, SourceFilesToBuild.CCFiles, Name).ObjectFiles); // Compile MM files directly. LinkInputFiles.AddRange(ToolChain.CompileCPPFiles(Target, CPPCompileEnvironment, SourceFilesToBuild.MMFiles, Name).ObjectFiles); // Compile RC files. LinkInputFiles.AddRange(ToolChain.CompileRCFiles(Target, CPPCompileEnvironment, SourceFilesToBuild.RCFiles).ObjectFiles); return LinkInputFiles; }
public override void RecursivelyProcessUnboundModules(UEBuildTarget Target, ref Dictionary<string, UEBuildBinary> Binaries, UEBuildBinary ExecutableBinary) { // Make sure this module is bound to a binary if( !bIncludedInTarget ) { throw new BuildException( "Module '{0}' should already have been bound to a binary!", Name ); } var AllModuleNames = new List<string>(); AllModuleNames.AddRange( PrivateDependencyModuleNames ); AllModuleNames.AddRange( PublicDependencyModuleNames ); AllModuleNames.AddRange( DynamicallyLoadedModuleNames ); AllModuleNames.AddRange( PlatformSpecificDynamicallyLoadedModuleNames ); foreach( var DependencyName in AllModuleNames ) { var DependencyModule = Target.FindOrCreateModuleByName(DependencyName); // Skip modules that are included with the target (externals) if( !DependencyModule.bIncludedInTarget ) { if( !Binaries.ContainsKey( DependencyModule.Name ) ) { UEBuildBinary BinaryToBindTo; if (Target.ShouldCompileMonolithic()) { // When linking monolithically, any unbound modules will be linked into the main executable BinaryToBindTo = ExecutableBinary; } else { // Is this a Rocket module? bool bIsRocketModule = RulesCompiler.IsRocketProjectModule(DependencyName); // Is this a plugin module? var PluginInfo = Plugins.GetPluginInfoForModule( DependencyName ); string OutputFilePath = Target.MakeBinaryPath(DependencyModule.Name, Target.GetAppName() + "-" + DependencyModule.Name, UEBuildBinaryType.DynamicLinkLibrary, Target.Rules.Type, bIsRocketModule, PluginInfo, ""); // If it's an engine module, output intermediates to the engine intermediates directory. string IntermediateDirectory = Binary.Config.IntermediateDirectory; if (PluginInfo == null && IntermediateDirectory != Target.EngineIntermediateDirectory && Path.GetFullPath(DependencyModule.ModuleDirectory).StartsWith(Path.GetFullPath(BuildConfiguration.RelativeEnginePath))) { IntermediateDirectory = Target.EngineIntermediateDirectory; } // When using modular linkage, unbound modules will be linked into their own DLL files UEBuildBinaryConfiguration Config = new UEBuildBinaryConfiguration( InType: UEBuildBinaryType.DynamicLinkLibrary, InOutputFilePath: OutputFilePath, InIntermediateDirectory: IntermediateDirectory, bInAllowExports: true, InModuleNames: new List<string> { DependencyModule.Name }, InTargetName: Target.GetAppName(), bInIsCrossTarget: PlatformSpecificDynamicallyLoadedModuleNames.Contains(DependencyName) && !DynamicallyLoadedModuleNames.Contains(DependencyName), InTargetConfiguration: Target.Configuration, bInCompileMonolithic: Target.ShouldCompileMonolithic() ); // Fix up the binary path if this is module specifies an alternate output directory Config.OutputFilePath = DependencyModule.FixupOutputPath(Config.OutputFilePath); BinaryToBindTo = new UEBuildBinaryCPP( Target, Config ); } Binaries[ DependencyModule.Name ] = BinaryToBindTo; // Bind this module DependencyModule.Binary = BinaryToBindTo; DependencyModule.bIncludedInTarget = true; // Also add binaries for this module's dependencies DependencyModule.RecursivelyProcessUnboundModules( Target, ref Binaries, ExecutableBinary ); } } if (Target.ShouldCompileMonolithic() == false) { // Check to see if there is a circular relationship between the module and it's referencer if( DependencyModule.Binary != null ) { if( CircularlyReferencedDependentModules.Contains( DependencyName ) ) { DependencyModule.Binary.SetCreateImportLibrarySeparately( true ); } } } } // Also make sure module entries are created for any module that is pulled in as an "include path" module. // These modules are never linked in unless they were referenced as an actual dependency of a different module, // but we still need to keep track of them so that we can find their include paths when setting up our // module's include paths. RecursivelyAddIncludePathModules( Target, bPublicIncludesOnly:false ); }