private LinkEnvironment SetupBinaryLinkEnvironment(UEBuildTarget Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CPPEnvironment CompileEnvironment) { LinkEnvironment BinaryLinkEnvironment = LinkEnvironment.DeepCopy(); HashSet<UEBuildModule> LinkEnvironmentVisitedModules = new HashSet<UEBuildModule>(); List<UEBuildBinary> BinaryDependencies = new List<UEBuildBinary>(); CompileEnvironment.Config.bIsBuildingDLL = IsBuildingDll(Config.Type); CompileEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type); CPPEnvironment BinaryCompileEnvironment = CompileEnvironment.DeepCopy(); // @Hack: This to prevent UHT from listing CoreUObject.generated.cpp as its dependency. // We flag the compile environment when we build UHT so that we don't need to check // this for each file when generating their dependencies. BinaryCompileEnvironment.bHackHeaderGenerator = (Target.GetAppName() == "UnrealHeaderTool"); // @todo: This should be in some Windows code somewhere... // Set the original file name macro; used in PCLaunch.rc to set the binary metadata fields. string OriginalFilename = (Config.OriginalOutputFilePaths != null) ? Config.OriginalOutputFilePaths[0].GetFileName() : Config.OutputFilePaths[0].GetFileName(); BinaryCompileEnvironment.Config.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OriginalFilename + "\""); foreach (UEBuildModule Module in Modules) { List<FileItem> LinkInputFiles; if (Module.Binary == null || Module.Binary == this) { // Compile each module. Log.TraceVerbose("Compile module: " + Module.Name); LinkInputFiles = Module.Compile(Target, ToolChain, CompileEnvironment, BinaryCompileEnvironment); // NOTE: Because of 'Shared PCHs', in monolithic builds the same PCH file may appear as a link input // multiple times for a single binary. We'll check for that here, and only add it once. This avoids // a linker warning about redundant .obj files. foreach (FileItem LinkInputFile in LinkInputFiles) { if (!BinaryLinkEnvironment.InputFiles.Contains(LinkInputFile)) { BinaryLinkEnvironment.InputFiles.Add(LinkInputFile); } } } else { BinaryDependencies.Add(Module.Binary); } if (!BuildConfiguration.bRunUnrealCodeAnalyzer) { // Allow the module to modify the link environment for the binary. Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules); } } // Allow the binary dependencies to modify the link environment. foreach (UEBuildBinary BinaryDependency in BinaryDependencies) { BinaryDependency.SetupDependentLinkEnvironment(BinaryLinkEnvironment); } // Remove the default resource file on Windows (PCLaunch.rc) if the user has specified their own if (BinaryLinkEnvironment.InputFiles.Select(Item => Path.GetFileName(Item.AbsolutePath).ToLower()).Any(Name => Name.EndsWith(".res") && !Name.EndsWith(".inl.res") && Name != "pclaunch.rc.res")) { BinaryLinkEnvironment.InputFiles.RemoveAll(x => Path.GetFileName(x.AbsolutePath).ToLower() == "pclaunch.rc.res"); } // Set the link output file. BinaryLinkEnvironment.Config.OutputFilePaths = Config.OutputFilePaths.ToList(); // Set whether the link is allowed to have exports. BinaryLinkEnvironment.Config.bHasExports = Config.bAllowExports; // Set the output folder for intermediate files BinaryLinkEnvironment.Config.IntermediateDirectory = Config.IntermediateDirectory; // Put the non-executable output files (PDB, import library, etc) in the same directory as the production BinaryLinkEnvironment.Config.OutputDirectory = Config.OutputFilePaths[0].Directory; // Setup link output type BinaryLinkEnvironment.Config.bIsBuildingDLL = IsBuildingDll(Config.Type); BinaryLinkEnvironment.Config.bIsBuildingLibrary = IsBuildingLibrary(Config.Type); BinaryLinkEnvironment.Config.ProjectFile = Target.ProjectFile; return BinaryLinkEnvironment; }
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 ); }