示例#1
0
        private LinkEnvironment SetupBinaryLinkEnvironment(ReadOnlyTargetRules Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CppCompileEnvironment CompileEnvironment, FileReference SingleFileToCompile, ISourceFileWorkingSet WorkingSet, DirectoryReference ExeDir, TargetMakefile Makefile)
        {
            LinkEnvironment         BinaryLinkEnvironment         = new LinkEnvironment(LinkEnvironment);
            HashSet <UEBuildModule> LinkEnvironmentVisitedModules = new HashSet <UEBuildModule>();
            List <UEBuildBinary>    BinaryDependencies            = new List <UEBuildBinary>();

            CppCompileEnvironment BinaryCompileEnvironment = CreateBinaryCompileEnvironment(CompileEnvironment);

            if (BinaryCompileEnvironment.bUseSharedBuildEnvironment && Target.ProjectFile != null && IntermediateDirectory.IsUnderDirectory(Target.ProjectFile.Directory))
            {
                BinaryCompileEnvironment.bUseSharedBuildEnvironment = false;
            }

            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, BinaryCompileEnvironment, SingleFileToCompile, WorkingSet, Makefile);

                    // Save the module outputs. In monolithic builds, this is just the object files.
                    if (Target.LinkType == TargetLinkType.Monolithic)
                    {
                        Makefile.ModuleNameToOutputItems[Module.Name] = LinkInputFiles.ToArray();
                    }

                    // 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);
                        }
                    }

                    // Force a reference to initialize module for this binary
                    if (Module.Rules.bRequiresImplementModule.Value)
                    {
                        BinaryLinkEnvironment.IncludeFunctions.Add(String.Format("IMPLEMENT_MODULE_{0}", Module.Name));
                    }
                }
                else
                {
                    BinaryDependencies.Add(Module.Binary);
                }

                // Allow the module to modify the link environment for the binary.
                Module.SetupPrivateLinkEnvironment(this, BinaryLinkEnvironment, BinaryDependencies, LinkEnvironmentVisitedModules, ExeDir);
            }


            // Allow the binary dependencies to modify the link environment.
            foreach (UEBuildBinary BinaryDependency in BinaryDependencies)
            {
                BinaryDependency.SetupDependentLinkEnvironment(BinaryLinkEnvironment);
            }

            // Set the link output file.
            BinaryLinkEnvironment.OutputFilePaths = OutputFilePaths.ToList();

            // Set whether the link is allowed to have exports.
            BinaryLinkEnvironment.bHasExports = bAllowExports;

            // Set the output folder for intermediate files
            BinaryLinkEnvironment.IntermediateDirectory = IntermediateDirectory;

            // Put the non-executable output files (PDB, import library, etc) in the same directory as the production
            BinaryLinkEnvironment.OutputDirectory = OutputFilePaths[0].Directory;

            // Setup link output type
            BinaryLinkEnvironment.bIsBuildingDLL     = IsBuildingDll(Type);
            BinaryLinkEnvironment.bIsBuildingLibrary = IsBuildingLibrary(Type);

            // If we don't have any resource file, use the default or compile a custom one for this module
            if (BinaryLinkEnvironment.Platform == UnrealTargetPlatform.Win32 || BinaryLinkEnvironment.Platform == UnrealTargetPlatform.Win64)
            {
                // Figure out if this binary has any custom resource files. Hacky check to ignore the resource file in the Launch module, since it contains dialogs that the engine needs and always needs to be included.
                FileItem[] CustomResourceFiles = BinaryLinkEnvironment.InputFiles.Where(x => x.Location.HasExtension(".res") && !x.Location.FullName.EndsWith("\\Launch\\PCLaunch.rc.res", StringComparison.OrdinalIgnoreCase)).ToArray();
                if (CustomResourceFiles.Length == 0)
                {
                    if (BinaryLinkEnvironment.DefaultResourceFiles.Count > 0)
                    {
                        // Use the default resource file if possible
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                    else
                    {
                        // Get the intermediate directory
                        DirectoryReference ResourceIntermediateDirectory = BinaryLinkEnvironment.IntermediateDirectory;

                        // Create a compile environment for resource files
                        CppCompileEnvironment ResourceCompileEnvironment = new CppCompileEnvironment(BinaryCompileEnvironment);

                        // @todo: This should be in some Windows code somewhere...
                        // Set the original file name macro; used in Default.rc2 to set the binary metadata fields.
                        ResourceCompileEnvironment.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OutputFilePaths[0].GetFileName() + "\"");

                        // Set the other version fields
                        ResourceCompileEnvironment.Definitions.Add(String.Format("BUILT_FROM_CHANGELIST={0}", Target.Version.Changelist));
                        ResourceCompileEnvironment.Definitions.Add(String.Format("BUILD_VERSION={0}", Target.BuildVersion));

                        // Otherwise compile the default resource file per-binary, so that it gets the correct ORIGINAL_FILE_NAME macro.
                        FileItem  DefaultResourceFile   = FileItem.GetItemByFileReference(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Build", "Windows", "Resources", "Default.rc2"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(ResourceCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ResourceIntermediateDirectory, Makefile.Actions);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                }
            }

            // Add all the common resource files
            BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.CommonResourceFiles);

            return(BinaryLinkEnvironment);
        }
示例#2
0
        private LinkEnvironment SetupBinaryLinkEnvironment(UEBuildTarget Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CPPEnvironment CompileEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ActionGraph ActionGraph)
        {
            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, BinaryCompileEnvironment, SharedPCHs, ActionGraph);

                    // 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;

            // Add the default resources for dlls
            if (Config.Type == UEBuildBinaryType.DynamicLinkLibrary)
            {
                // Check if there's already a custom resource file
                if (!BinaryLinkEnvironment.InputFiles.Any(x => x.Reference.HasExtension(".res")))
                {
                    if (UEBuildConfiguration.bFormalBuild)
                    {
                        // For formal builds, compile the default resource file per-binary, so that it gets the correct ORIGINAL_FILE_NAME macro.
                        CPPEnvironment BinaryResourceCompileEnvironment = BinaryCompileEnvironment.DeepCopy();
                        BinaryResourceCompileEnvironment.Config.OutputDirectory = DirectoryReference.Combine(BinaryResourceCompileEnvironment.Config.OutputDirectory, Modules.First().Name);
                        FileItem  DefaultResourceFile   = FileItem.GetItemByFileReference(FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Runtime", "Launch", "Resources", "Windows", "PCLaunch.rc"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(BinaryResourceCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ActionGraph);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                    else
                    {
                        // For non-formal builds, we just want to share the default resource file between modules
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                }

                // Add all the common resource files
                BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.CommonResourceFiles);
            }

            return(BinaryLinkEnvironment);
        }
示例#3
0
        private LinkEnvironment SetupBinaryLinkEnvironment(ReadOnlyTargetRules Target, UEToolChain ToolChain, LinkEnvironment LinkEnvironment, CppCompileEnvironment CompileEnvironment, List <PrecompiledHeaderTemplate> SharedPCHs, ISourceFileWorkingSet WorkingSet, ActionGraph ActionGraph)
        {
            LinkEnvironment         BinaryLinkEnvironment         = new LinkEnvironment(LinkEnvironment);
            HashSet <UEBuildModule> LinkEnvironmentVisitedModules = new HashSet <UEBuildModule>();
            List <UEBuildBinary>    BinaryDependencies            = new List <UEBuildBinary>();

            CppCompileEnvironment BinaryCompileEnvironment = CreateBinaryCompileEnvironment(CompileEnvironment);

            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, BinaryCompileEnvironment, SharedPCHs, WorkingSet, ActionGraph);

                    // 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);
                }

                // 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.OutputFilePaths = OutputFilePaths.ToList();

            // Set whether the link is allowed to have exports.
            BinaryLinkEnvironment.bHasExports = bAllowExports;

            // Set the output folder for intermediate files
            BinaryLinkEnvironment.IntermediateDirectory = IntermediateDirectory;

            // Put the non-executable output files (PDB, import library, etc) in the same directory as the production
            BinaryLinkEnvironment.OutputDirectory = OutputFilePaths[0].Directory;

            // Setup link output type
            BinaryLinkEnvironment.bIsBuildingDLL     = IsBuildingDll(Type);
            BinaryLinkEnvironment.bIsBuildingLibrary = IsBuildingLibrary(Type);

            // If we don't have any resource file, use the default or compile a custom one for this module
            if (BinaryLinkEnvironment.Platform == CppPlatform.Win32 || BinaryLinkEnvironment.Platform == CppPlatform.Win64)
            {
                if (!BinaryLinkEnvironment.InputFiles.Any(x => x.Location.HasExtension(".res")))
                {
                    if (BinaryLinkEnvironment.DefaultResourceFiles.Count > 0)
                    {
                        // Use the default resource file if possible
                        BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.DefaultResourceFiles);
                    }
                    else
                    {
                        // Create a compile environment for resource files
                        CppCompileEnvironment ResourceCompileEnvironment = new CppCompileEnvironment(BinaryCompileEnvironment);

                        // @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 = (OriginalOutputFilePaths != null) ? OriginalOutputFilePaths[0].GetFileName() : OutputFilePaths[0].GetFileName();
                        ResourceCompileEnvironment.Definitions.Add("ORIGINAL_FILE_NAME=\"" + OriginalFilename + "\"");

                        // Set the other version fields
                        ResourceCompileEnvironment.Definitions.Add(String.Format("BUILT_FROM_CHANGELIST={0}", Target.Version.Changelist));
                        ResourceCompileEnvironment.Definitions.Add(String.Format("BUILD_VERSION={0}", Target.BuildVersion));

                        // Otherwise compile the default resource file per-binary, so that it gets the correct ORIGINAL_FILE_NAME macro.
                        FileItem  DefaultResourceFile   = FileItem.GetItemByFileReference(FileReference.Combine(UnrealBuildTool.EngineSourceDirectory, "Runtime", "Launch", "Resources", "Windows", "PCLaunch.rc"));
                        CPPOutput DefaultResourceOutput = ToolChain.CompileRCFiles(BinaryCompileEnvironment, new List <FileItem> {
                            DefaultResourceFile
                        }, ((UEBuildModuleCPP)Modules.First()).IntermediateDirectory, ActionGraph);
                        BinaryLinkEnvironment.InputFiles.AddRange(DefaultResourceOutput.ObjectFiles);
                    }
                }
            }

            // Add all the common resource files
            BinaryLinkEnvironment.InputFiles.AddRange(BinaryLinkEnvironment.CommonResourceFiles);

            return(BinaryLinkEnvironment);
        }
		// 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;
		}