Пример #1
0
        // UEBuildModule interface.
        public override List<FileItem> Compile(CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment)
        {
            var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);

            var LinkInputFiles = new List<FileItem>();
            if( ProjectFileGenerator.bGenerateProjectFiles && IntelliSenseGatherer == null)
            {
                // Nothing to do for IntelliSense, bail out early
                return LinkInputFiles;
            }

            var ModuleCompileEnvironment = CreateModuleCompileEnvironment(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)
                {
                    string DefRC = Utils.CleanDirectorySeparators( Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "Runtime/Launch/Resources/Windows/PCLaunch.rc")) );
                    FileItem Item = FileItem.GetItemByFullPath(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.
                string ModuleVersionRC = Utils.CleanDirectorySeparators( Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "Runtime/Core/Resources/Windows/ModuleVersionResource.rc.inl")) );
                FileItem ModuleVersionItem = FileItem.GetItemByFullPath(ModuleVersionRC);
                if( !SourceFilesToBuild.RCFiles.Contains(ModuleVersionItem) )
                {
                    SourceFilesToBuild.RCFiles.Add(ModuleVersionItem);
                }
            }

            {
                // Process all of the header file dependencies for this module
                this.CachePCHUsageForModuleSourceFiles( ModuleCompileEnvironment );

                // Make sure our RC files have cached includes.
                foreach( var 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
            var IsGameModule = !Utils.IsFileUnderDirectory( this.ModuleDirectory, Path.Combine( ProjectFileGenerator.EngineRelativePath ) );

            // 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( MinFilesUsingPrecompiledHeaderOverride != 0 )
            {
                MinFilesUsingPrecompiledHeader = 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;
            }

            // Should we use unity build mode for this module?
            bool bModuleUsesUnityBuild = BuildConfiguration.bUseUnityBuild || BuildConfiguration.bForceUnityBuild;
            if (!BuildConfiguration.bForceUnityBuild)
            {
                if (bFasterWithoutUnity)
                {
                    bModuleUsesUnityBuild = false;
                }
                else if (IsGameModule && SourceFilesToBuild.CPPFiles.Count < BuildConfiguration.MinGameModuleSourceFilesForUnityBuild)
                {
                    // 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
                    bModuleUsesUnityBuild = false;
                }
            }

            // The environment with which to compile the CPP files
            var CPPCompileEnvironment = ModuleCompileEnvironment;

            // Precompiled header support.
            bool bWasModuleCodeCompiled = false;
            if (BuildPlatform.ShouldUsePCHFiles(CompileEnvironment.Config.Target.Platform, CompileEnvironment.Config.Target.Configuration))
            {
                var 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 )
                {
                    string SharingPCHHeaderFilePath = null;
                    bool bIsASharedPCHModule = bUseSharedPCHFiles && GlobalCompileEnvironment.SharedPCHHeaderFiles.Any( PCH => PCH.Module == this );
                    if( bIsASharedPCHModule )
                    {
                        SharingPCHHeaderFilePath = Path.GetFullPath( Path.Combine( ProjectFileGenerator.RootRelativePath, "Engine", "Source", this.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 bCanModuleUseOwnSharedPCH = bAllowSharedPCH && bIsASharedPCHModule && !Binary.Config.bAllowExports && ProcessedDependencies.UniquePCHHeaderFile.AbsolutePath.Equals( SharingPCHHeaderFilePath, StringComparison.InvariantCultureIgnoreCase );
                    if( bAllowSharedPCH && ( !bIsASharedPCHModule || bCanModuleUseOwnSharedPCH ) )
                    {
                        // Figure out which shared PCH tier we're in
                        var ReferencedModules = new CaselessDictionary<ModuleIndexPair>();
                        {
                            this.GetAllDependencyModules( ReferencedModules, bIncludeDynamicallyLoaded:false, bForceCircular:false, bOnlyDirectDependencies:true );
                        }

                        int LargestSharedPCHHeaderFileIndex = -1;
                        foreach( var DependencyModule in ReferencedModules.Values.OrderBy(P => P.Index).Select(P => P.Module) )
                        {
                            // These Shared PCHs are ordered from least complex to most complex.  We'll start at the last one and search backwards.
                            for( var SharedPCHHeaderFileIndex = GlobalCompileEnvironment.SharedPCHHeaderFiles.Count - 1; SharedPCHHeaderFileIndex > LargestSharedPCHHeaderFileIndex; --SharedPCHHeaderFileIndex )
                            {
                                var 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
                        var LargestSharedPCHHeader = GlobalCompileEnvironment.SharedPCHHeaderFiles[ LargestSharedPCHHeaderFileIndex ];
                        ++LargestSharedPCHHeader.NumModulesUsingThisPCH;

                    }
                    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 (var CPPFile in SourceFilesToBuild.CPPFiles)
                        {
                            CPPFile.PCHHeaderNameInCode              = PCHToUse.AbsolutePath;
                            CPPFile.PrecompiledHeaderIncludeFilename = PCHToUse.AbsolutePath;
                        }
                    }

                    // A shared PCH was not already set up for us, so set one up.
                    if( ModulePCHEnvironment == null )
                    {
                        var PCHHeaderFile = ProcessedDependencies.UniquePCHHeaderFile;
                        var PCHModuleName = this.Name;
                        if( SharedPCHHeaderFile != null )
                        {
                            PCHHeaderFile = SharedPCHHeaderFile;
                            PCHModuleName = SharedPCHModuleName;
                        }
                        var 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.

                    var ModulePCHCompileEnvironment = ModuleCompileEnvironment.DeepCopy();
                    ModulePCHCompileEnvironment.Config.PrecompiledHeaderAction          = PrecompiledHeaderAction.Include;
                    ModulePCHCompileEnvironment.Config.PrecompiledHeaderIncludeFilename = ModulePCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath;
                    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;
                    }

                    var CPPFilesToBuild = SourceFilesToBuild.CPPFiles;
                    if (bModuleUsesUnityBuild)
                    {
                        // unity files generated for only the set of files which share the same PCH environment
                        CPPFilesToBuild = Unity.GenerateUnityCPPs( 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(
                                    Target,
                                    CPPFilesToBuild[0].PCHHeaderNameInCode,
                                    ModulePCHEnvironment.PrecompiledHeaderIncludeFilename,
                                    ModuleCompileEnvironment,
                                    ModuleCompileEnvironment.Config.OutputDirectory,
                                    Name,
                                    true );
                            }
                            else
                            {
                                UEBuildModuleCPP SharedPCHModule = (UEBuildModuleCPP)Target.FindOrCreateModuleByName(SharedPCHModuleName);

                                CPPEnvironment SharedPCHCompileEnvironment = GlobalCompileEnvironment.DeepCopy();
                                SharedPCHCompileEnvironment.Config.bEnableShadowVariableWarning = SharedPCHModule.bEnableShadowVariableWarnings;

                                SharedPCHModule.SetupPublicCompileEnvironment(
                                    Binary,
                                    false,
                                    SharedPCHCompileEnvironment.Config.CPPIncludeInfo.IncludePaths,
                                    SharedPCHCompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths,
                                    SharedPCHCompileEnvironment.Config.Definitions,
                                    SharedPCHCompileEnvironment.Config.AdditionalFrameworks,
                                    new Dictionary<UEBuildModule,bool>());

                                PCHOutput = PrecompileHeaderEnvironment.GeneratePCHCreationAction(
                                    Target,
                                    CPPFilesToBuild[0].PCHHeaderNameInCode,
                                    ModulePCHEnvironment.PrecompiledHeaderIncludeFilename,
                                    SharedPCHCompileEnvironment,
                                    Path.Combine( CompileEnvironment.Config.OutputDirectory, "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( CPPCompileEnvironment.CompileFiles( Target, CPPFilesToBuild, Name ).ObjectFiles );
                    bWasModuleCodeCompiled = true;
                }

                if( BuildConfiguration.bPrintPerformanceInfo )
                {
                    var PCHGenTime = ( DateTime.UtcNow - PCHGenTimerStart ).TotalSeconds;
                    TotalPCHGenTime += PCHGenTime;
                }
            }

            if( !bWasModuleCodeCompiled && SourceFilesToBuild.CPPFiles.Count > 0 )
            {
                var CPPFilesToCompile = SourceFilesToBuild.CPPFiles;
                if (bModuleUsesUnityBuild)
                {
                    CPPFilesToCompile = Unity.GenerateUnityCPPs( Target, CPPFilesToCompile, CPPCompileEnvironment, Name );
                }
                LinkInputFiles.AddRange( CPPCompileEnvironment.CompileFiles( Target, 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)
                {
                    var GeneratedCppFileItem = FileItem.GetItemByPath(GeneratedFilename);

                    CachePCHUsageForModuleSourceFile(this.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(CPPCompileEnvironment.CompileFiles(Target, new List<FileItem> { GeneratedCppFileItem }, Name).ObjectFiles);
                }
            }

            // Compile C files directly.
            LinkInputFiles.AddRange(CPPCompileEnvironment.CompileFiles( Target, SourceFilesToBuild.CFiles, Name).ObjectFiles);

            // Compile CC files directly.
            LinkInputFiles.AddRange(CPPCompileEnvironment.CompileFiles( Target, SourceFilesToBuild.CCFiles, Name).ObjectFiles);

            // Compile MM files directly.
            LinkInputFiles.AddRange(CPPCompileEnvironment.CompileFiles( Target, SourceFilesToBuild.MMFiles, Name).ObjectFiles);

            // Compile RC files.
            LinkInputFiles.AddRange(CPPCompileEnvironment.CompileRCFiles(Target, SourceFilesToBuild.RCFiles).ObjectFiles);

            return LinkInputFiles;
        }
Пример #2
0
        // UEBuildModule interface.
        public override List<FileItem> Compile(CPPEnvironment GlobalCompileEnvironment, CPPEnvironment CompileEnvironment, bool bCompileMonolithic)
        {
            UEBuildPlatform BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.TargetPlatform);

            var LinkInputFiles = new List<FileItem>();
            if( ProjectFileGenerator.bGenerateProjectFiles && IntelliSenseGatherer == null)
            {
                // Nothing to do for IntelliSense, bail out early
                return LinkInputFiles;
            }

            if(RedistStaticLibraryPath != null && !bBuildingRedistStaticLibrary)
            {
                // The redist static library will be added in SetupPrivateLinkEnvironment
                return LinkInputFiles;
            }

            var ModuleCompileEnvironment = new CPPEnvironment(CompileEnvironment);

            // Override compile environment
            ModuleCompileEnvironment.Config.OptimizeCode = OptimizeCode;
            ModuleCompileEnvironment.Config.bUseRTTI = bUseRTTI;
            ModuleCompileEnvironment.Config.bFasterWithoutUnity = bFasterWithoutUnity;
            ModuleCompileEnvironment.Config.OptimizeCode                           = OptimizeCode;
            ModuleCompileEnvironment.Config.bUseRTTI                               = bUseRTTI;
            ModuleCompileEnvironment.Config.bFasterWithoutUnity                    = bFasterWithoutUnity;
            ModuleCompileEnvironment.Config.OptimizeCode = OptimizeCode;
            ModuleCompileEnvironment.Config.bUseRTTI = bUseRTTI;
            ModuleCompileEnvironment.Config.bEnableBufferSecurityChecks = bEnableBufferSecurityChecks;
            ModuleCompileEnvironment.Config.bFasterWithoutUnity = bFasterWithoutUnity;
            ModuleCompileEnvironment.Config.MinFilesUsingPrecompiledHeaderOverride = MinFilesUsingPrecompiledHeaderOverride;
            ModuleCompileEnvironment.Config.bEnableExceptions                      = bEnableExceptions;
            ModuleCompileEnvironment.Config.bEnableInlining                        = bEnableInlining;
            ModuleCompileEnvironment.Config.OutputDirectory                        = Path.Combine(Binary.Config.IntermediateDirectory, Name);

            // Switch the optimization flag if we're building a game module
            if(Target.Configuration == UnrealTargetConfiguration.DebugGame && Type == UEBuildModuleType.GameModule)
            {
                ModuleCompileEnvironment.Config.TargetConfiguration = CPPTargetConfiguration.Debug;
            }

            // Add the module's private definitions.
            ModuleCompileEnvironment.Config.Definitions.AddRange(Definitions);

            // Setup the compile environment for the module.
            SetupPrivateCompileEnvironment(
                ref ModuleCompileEnvironment.Config.IncludePaths,
                ref ModuleCompileEnvironment.Config.SystemIncludePaths,
                ref ModuleCompileEnvironment.Config.Definitions
                );

            if( IntelliSenseGatherer != null )
            {
                // Update project file's set of preprocessor definitions and include paths
                IntelliSenseGatherer.AddIntelliSensePreprocessorDefinitions( ModuleCompileEnvironment.Config.Definitions );
                IntelliSenseGatherer.AddInteliiSenseIncludePaths( ModuleCompileEnvironment.Config.SystemIncludePaths );
                IntelliSenseGatherer.AddInteliiSenseIncludePaths( ModuleCompileEnvironment.Config.IncludePaths );

                // Bail out.  We don't need to actually compile anything while generating project files.
                return LinkInputFiles;
            }

            // Gather a list of CPP files in the project.
            var CPPFiles = new List<FileItem>();
            var CFiles = new List<FileItem>();
            var CCFiles = new List<FileItem>();
            var MMFiles = new List<FileItem>();
            var RCFiles = new List<FileItem>();
            var MissingFiles = new List<FileItem>();
            foreach (var SourceFile in SourceFiles)
            {
                string Extension = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant();
                if (SourceFile.bExists)
                {
                    if (Extension == ".CPP")
                    {
                        CPPFiles.Add(SourceFile);
                    }
                    else if (Extension == ".C")
                    {
                        CFiles.Add(SourceFile);
                    }
                    else if (Extension == ".CC")
                    {
                        CCFiles.Add(SourceFile);
                    }
                    else if (Extension == ".MM" || Extension == ".M")
                    {
                        MMFiles.Add(SourceFile);
                    }
                    else if (Extension == ".RC")
                    {
                        RCFiles.Add(SourceFile);
                    }
                }
                else
                {
                    MissingFiles.Add(SourceFile);
                }
            }

            // 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 (RCFiles.Count <= 0)
                {
                    string DefRC = Path.Combine(Directory.GetCurrentDirectory(), "Runtime/Launch/Resources/Windows/PCLaunch.rc");
                    FileItem Item = FileItem.GetItemByFullPath(DefRC);
                    RCFiles.Add(Item);
                }
            }

            // Throw an error if the module's source file list referenced any non-existent files.
            if (MissingFiles.Count > 0)
            {
                string FileList = "";
                foreach (var MissingFile in MissingFiles)
                {
                    FileList += "\n";
                    FileList += MissingFile.AbsolutePath;
                }
                throw new BuildException(
                    "UBT ERROR: Module \"{0}\" references non-existent files:{1} (perhaps a file was added to the project but not checked in)",
                    Name,
                    FileList
                    );
            }

            // Clear out any references to precompiled header usage for source files..
            foreach (var CPPFile in CPPFiles)
            {
                CPPFile.PCHHeaderNameInCode = null;
                CPPFile.PrecompiledHeaderIncludeFilename = null;
            }

            // Check to see if this is an Engine module (including program or plugin modules).  That is, the module is located under the "Engine" folder
            var IsGameModule = !Utils.IsFileUnderDirectory( this.ModuleDirectory, Path.Combine( ProjectFileGenerator.EngineRelativePath ) );

            // 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( MinFilesUsingPrecompiledHeaderOverride != 0 )
            {
                MinFilesUsingPrecompiledHeader = 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;
            }

            // Should we use unity build mode for this module?
            bool bModuleUsesUnityBuild = BuildConfiguration.bUseUnityBuild;
            if( bFasterWithoutUnity )
            {
                bModuleUsesUnityBuild = false;
            }
            else if( !BuildConfiguration.bForceUnityBuild && IsGameModule && CPPFiles != null && CPPFiles.Count < BuildConfiguration.MinGameModuleSourceFilesForUnityBuild )
            {
                // 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
                bModuleUsesUnityBuild = false;
            }

            // Precompiled header support.
            bool bWasModuleCodeCompiled = false;
            if (BuildPlatform.ShouldUsePCHFiles(CompileEnvironment.Config.TargetPlatform, CompileEnvironment.Config.TargetConfiguration))
            {
                var PCHTimerStart = 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 UniquePCHHeaderFile = null;
                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;

                // The precompiled header environment for all source files in this module that use a precompiled header, if we even need one
                PrecompileHeaderEnvironment ModulePCHEnvironment = null;

                bool bDisableSharedPCHFiles = (Binary.Config.bCompileMonolithic && CompileEnvironment.Config.bIsBuildingLibrary);
                if( BuildConfiguration.bUseSharedPCHs && bDisableSharedPCHFiles )
                {
                    Log.TraceVerbose("Module '{0}' was not allowed to use SharedPCHs, because we're compiling to a library in monolithic mode", this.Name );
                }

                bool bUseSharedPCHFiles = BuildConfiguration.bUseSharedPCHs && (bDisableSharedPCHFiles == false);
                bool bIsASharedPCHModule = false;
                if (bUseSharedPCHFiles)
                {
                    foreach( var CurSharedPCHHeaderFile in GlobalCompileEnvironment.SharedPCHHeaderFiles )
                    {
                        if( this == CurSharedPCHHeaderFile.Module )
                        {
                            bIsASharedPCHModule = true;
                            break;
                        }
                    }
                }

                // Map from pch header string to the source files that use that PCH
                var UsageMapPCH = new Dictionary<string, List<FileItem>>( StringComparer.InvariantCultureIgnoreCase );

                // Determine what potential precompiled header is used by each source file.
                double SharedPCHTotalTime = 0.0;
                foreach( var CPPFile in CPPFiles )
                {
                    if (bUseSharedPCHFiles)
                    {
                        var SharedPCHStartTime = DateTime.UtcNow;

                        // When compiling in modular mode, 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.
                        // @todo SharedPCH: If we ever have SharedPCH headers that themselves belong to modules which never use DLL Exports, we can avoid
                        // generating TWO PCH files by checking for that here.  For now, we always assume that SharedPCH headers have exports when
                        // compiling in modular mode.
                        if( bAllowSharedPCH && ( !bIsASharedPCHModule || bCompileMonolithic ) )
                        {
                            // Figure out which shared PCH tier we're in
                            int LargestSharedPCHHeaderFileIndex = -1;
                            {
                                var AllIncludedFiles = ModuleCompileEnvironment.GetIncludeDependencies( CPPFile );
                                foreach( var IncludedFile in AllIncludedFiles )
                                {
                                    // These PCHs are ordered from least complex to most complex.  We'll start at the last one and search backwards.
                                    for( var SharedPCHHeaderFileIndex = GlobalCompileEnvironment.SharedPCHHeaderFiles.Count - 1; SharedPCHHeaderFileIndex > LargestSharedPCHHeaderFileIndex; --SharedPCHHeaderFileIndex )
                                    {
                                        var CurSharedPCHHeaderFile = GlobalCompileEnvironment.SharedPCHHeaderFiles[ SharedPCHHeaderFileIndex ];
                                        if( IncludedFile == 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;
                                    }
                                }
                            }

                            if( LargestSharedPCHHeaderFileIndex > -1 )
                            {
                                var LargestIncludedSharedPCHHeaderFile = GlobalCompileEnvironment.SharedPCHHeaderFiles[LargestSharedPCHHeaderFileIndex];
                                if( SharedPCHHeaderFile == null )
                                {
                                    SharedPCHModuleName = LargestIncludedSharedPCHHeaderFile.Module.Name;
                                    SharedPCHHeaderFile = LargestIncludedSharedPCHHeaderFile.PCHHeaderFile;
                                }
                                else
                                {
                                    if( SharedPCHHeaderFile != LargestIncludedSharedPCHHeaderFile.PCHHeaderFile )
                                    {
                                        // @todo UBT perf: It is fairly costly to perform this test, as we could easily early-out after we have SharedPCHHeaderFile and not bother testing the rest of the files in the module.  But this can be useful to find abusive modules that include a shared PCH header in the bowels of a non-PCH private source file.
                                        Console.WriteLine( "WARNING: File '{0}' doesn't use same 'shared' precompiled header as other files in this module: '{1}' vs '{2}'.  This can greatly impact compile times.  Make sure that your module's private PCH header includes the 'largest' shared PCH header that your module uses",
                                            CPPFile.AbsolutePath, SharedPCHHeaderFile, LargestIncludedSharedPCHHeaderFile.PCHHeaderFile );
                                    }
                                }
                            }
                            else
                            {
                                Log.TraceVerbose("File {0} doesn't use a SharedPCH!", CPPFile.AbsolutePath);
                            }

                            SharedPCHTotalTime += ( DateTime.UtcNow - SharedPCHStartTime ).TotalSeconds;
                        }
                        else
                        {
                            Log.TraceVerbose("File '{0}' cannot create or use SharedPCHs, because its module '{1}' needs its own private PCH", CPPFile.AbsolutePath, this.Name);
                        }
                    }

                    {
                        // Find headers used by the source file.
                        List<DependencyInclude> DirectIncludeFilenames = CPPEnvironment.GetDirectIncludeDependencies( CPPFile, ModuleCompileEnvironment.Config.TargetPlatform, ModuleCompileEnvironment.bHackHeaderGenerator );
                        if( BuildConfiguration.bPrintDebugInfo )
                        {
                            var IncludedFileNames = new StringBuilder();
                            foreach( var CurInclude in DirectIncludeFilenames )
                            {
                                if( IncludedFileNames.Length > 0 )
                                {
                                    IncludedFileNames.Append( ", " );
                                }
                                IncludedFileNames.Append( Path.GetFileName( CurInclude.IncludeName ) );
                            }

                            Log.TraceVerbose( "Found direct includes for {0}: {1}", Path.GetFileName( CPPFile.AbsolutePath ), IncludedFileNames );
                        }

                        if( DirectIncludeFilenames.Count > 0 )
                        {
                            // The pch header should always be the first include in the source file.
                            // NOTE: This is not an absolute path.  This is just the literal include string from the source file!
                            CPPFile.PCHHeaderNameInCode = DirectIncludeFilenames[ 0 ].IncludeName;

                            // Resolve the PCH header to an absolute path.
                            // Check NullOrEmpty here because if the file could not be resolved we need to throw an exception
                            if (string.IsNullOrEmpty(DirectIncludeFilenames[0].IncludeResolvedName) ||
                                // ignore any preexisting resolve cache if we are not configured to use it.
                                !BuildConfiguration.bUseIncludeDependencyResolveCache ||
                                // if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts
                                BuildConfiguration.bTestIncludeDependencyResolveCache)
                            {
                                string SourceFilesDirectory = Path.GetDirectoryName(CPPFile.AbsolutePath);
                                // search the include paths to resolve the file.
                                FileItem PrecompiledHeaderIncludeFile = ModuleCompileEnvironment.FindIncludedFile(CPPFile.PCHHeaderNameInCode, !BuildConfiguration.bCheckExternalHeadersForModification, SourceFilesDirectory);
                                if (PrecompiledHeaderIncludeFile != null)
                                {
                                    CPPEnvironment.IncludeDependencyCache.CacheResolvedIncludeFullPath(CPPFile, 0, PrecompiledHeaderIncludeFile.AbsolutePath);
                                    CPPFile.PrecompiledHeaderIncludeFilename = PrecompiledHeaderIncludeFile.AbsolutePath;

                                    if (UniquePCHHeaderFile == null)
                                    {
                                        UniquePCHHeaderFile = PrecompiledHeaderIncludeFile;
                                    }
                                }
                                else
                                {
                                    throw new BuildException("The first include statement in source file '{0}' is trying to include the file '{1}' as the precompiled header for module '{2}', but that file could not be located in any of the module's include search paths.", CPPFile.AbsolutePath, CPPFile.PCHHeaderNameInCode, this.Name);
                                }
                            }
                            else
                            {
                                CPPFile.PrecompiledHeaderIncludeFilename = DirectIncludeFilenames[0].IncludeResolvedName;
                                if (UniquePCHHeaderFile == null)
                                {
                                    UniquePCHHeaderFile = FileItem.GetItemByFullPath(CPPFile.PrecompiledHeaderIncludeFilename);
                                }
                            }
                        }
                    }

                    if( CPPFile.PrecompiledHeaderIncludeFilename == null )
                    {
                        throw new BuildException( "No PCH usage for file \"{0}\" . Missing #include header?", CPPFile.AbsolutePath );
                    }

                    // Create a new entry if not in the pch usage map
                    List<FileItem> PCHSourceFiles = null;
                    if( !UsageMapPCH.TryGetValue( CPPFile.PrecompiledHeaderIncludeFilename, out PCHSourceFiles ) )
                    {
                        PCHSourceFiles = new List<FileItem>();
                        UsageMapPCH.Add( CPPFile.PrecompiledHeaderIncludeFilename, PCHSourceFiles );
                    }
                    PCHSourceFiles.Add( CPPFile );
                }

                if( BuildConfiguration.bPrintDebugInfo )
                {
                    Log.TraceVerbose( "{0} PCH files for module {1}:", UsageMapPCH.Count, Name );
                    int MostFilesIncluded = 0;
                    foreach( var CurPCH in UsageMapPCH )
                    {
                        if( CurPCH.Value.Count > MostFilesIncluded )
                        {
                            MostFilesIncluded = CurPCH.Value.Count;
                        }

                        Log.TraceVerbose("   {0}  ({1} files including it: {2}, ...)", CurPCH.Key, CurPCH.Value.Count, CurPCH.Value[0].AbsolutePath);
                    }
                }

                if( UsageMapPCH.Count > 1 )
                {
                    // Keep track of the PCH file that is most used within this module
                    string MostFilesAreIncludingPCH = string.Empty;
                    int MostFilesIncluded = 0;
                    foreach( var CurPCH in UsageMapPCH )
                    {
                        if( CurPCH.Value.Count > MostFilesIncluded )
                        {
                            MostFilesAreIncludingPCH = CurPCH.Key;
                            MostFilesIncluded = CurPCH.Value.Count;
                        }
                    }

                    // Find all of the files that are not including our "best" PCH header
                    var FilesNotIncludingBestPCH = new StringBuilder();
                    foreach( var CurPCH in UsageMapPCH )
                    {
                        if( CurPCH.Key != MostFilesAreIncludingPCH )
                        {
                            foreach( var SourceFile in CurPCH.Value )
                            {
                                FilesNotIncludingBestPCH.AppendFormat( "{0} (including {1})\n", SourceFile.AbsolutePath, CurPCH.Key );
                            }
                        }
                    }

                    // Bail out and let the user know which source files may need to be fixed up
                    throw new BuildException(
                        "All source files in module \"{0}\" must include the same precompiled header first.  Currently \"{1}\" is included by most of the source files.  The following source files are not including \"{1}\" as their first include:\n\n{2}",
                        Name,
                        MostFilesAreIncludingPCH,
                        FilesNotIncludingBestPCH );
                }

                // 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( CPPFiles != null &&
                    ( SharedPCHHeaderFile != null || CPPFiles.Count >= MinFilesUsingPrecompiledHeader ) )
                {
                    if( SharedPCHHeaderFile != null )
                    {
                        // Check to see if we have a PCH header already setup that we can use
                        foreach( var SharedPCHEnvironment in GlobalCompileEnvironment.SharedPCHEnvironments )
                        {
                            if( SharedPCHEnvironment.PrecompiledHeaderIncludeFilename == SharedPCHHeaderFile )
                            {
                                // Don't mix CLR modes
                                if( SharedPCHEnvironment.CLRMode == ModuleCompileEnvironment.Config.CLRMode )
                                {
                                    // Don't mix non-optimized code with optimized code (PCHs won't be compatible)
                                    bool bIsDebugBuild = CompileEnvironment.Config.TargetConfiguration == CPPTargetConfiguration.Debug;
                                    var SharedPCHCodeOptimization = SharedPCHEnvironment.OptimizeCode;
                                    if( SharedPCHCodeOptimization == ModuleRules.CodeOptimization.InNonDebugBuilds && !bIsDebugBuild )
                                    {
                                        SharedPCHCodeOptimization = ModuleRules.CodeOptimization.Always;
                                    }
                                    var ModuleCodeOptimization = ModuleCompileEnvironment.Config.OptimizeCode;
                                    if( ModuleCodeOptimization == ModuleRules.CodeOptimization.InNonDebugBuilds && !bIsDebugBuild )
                                    {
                                        ModuleCodeOptimization = ModuleRules.CodeOptimization.Always;
                                    }

                                    if( SharedPCHCodeOptimization.Equals( ModuleCodeOptimization ) )
                                    {
                                        // Found a valid shared PCH header to use!

                                        // @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 determinstic builds, or turn up compile
                                        //    errors unexpectedly due to compile environment differences.
                                        ModulePCHEnvironment = SharedPCHEnvironment;
                                        Log.TraceVerbose( "Module " + Name + " uses existing SharedPCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "' (from module " + ModulePCHEnvironment.ModuleName + ")" );

                                        // Update all CPPFiles to point to the shared PCH
                                        foreach( var CPPFile in CPPFiles )
                                        {
                                            CPPFile.PCHHeaderNameInCode = SharedPCHHeaderFile.AbsolutePath;
                                            CPPFile.PrecompiledHeaderIncludeFilename = SharedPCHHeaderFile.AbsolutePath;
                                        }
                                    }
                                    else
                                    {
                                        Log.TraceVerbose( "Module {0} cannot use existing SharedPCH '{1}' (from module '{2}') because optimization levels don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName );
                                        SharedPCHHeaderFile = null;
                                    }
                                }
                                else
                                {
                                    Log.TraceVerbose( "Module {0} cannot use existing SharedPCH '{1}' (from module '{2}') because CLR modes don't match", Name, SharedPCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath, SharedPCHEnvironment.ModuleName );
                                    SharedPCHHeaderFile = null;
                                }
                                break;
                            }
                        }
                    }

                    // A shared PCH was not already set up for us, so set one up.
                    if( ModulePCHEnvironment == null )
                    {
                        var PCHHeaderFile = UniquePCHHeaderFile;
                        var PCHModuleName = this.Name;
                        if( SharedPCHHeaderFile != null )
                        {
                            PCHHeaderFile = SharedPCHHeaderFile;
                            PCHModuleName = SharedPCHModuleName;
                        }
                        var PCHHeaderNameInCode = CPPFiles[ 0 ].PCHHeaderNameInCode;

                        ModulePCHEnvironment = new PrecompileHeaderEnvironment( PCHModuleName, PCHHeaderNameInCode, PCHHeaderFile, ModuleCompileEnvironment.Config.CLRMode, ModuleCompileEnvironment.Config.OptimizeCode );

                        Log.TraceVerbose( "PCH file \"{0}\" generated for module \"{1}\" .", PCHHeaderFile.AbsolutePath, Name );

                        if( SharedPCHHeaderFile != null )
                        {
                            // Add to list of shared PCH environments
                            GlobalCompileEnvironment.SharedPCHEnvironments.Add( ModulePCHEnvironment );
                            Log.TraceVerbose( "Module " + Name + " uses new SharedPCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "'" );
                        }
                        else
                        {
                            Log.TraceVerbose( "Module " + Name + " uses a unique PCH '" + ModulePCHEnvironment.PrecompiledHeaderIncludeFilename + "'" );
                        }
                    }
                }

                // 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.
                    var ModulePCHCompileEnvironment = new CPPEnvironment( ModuleCompileEnvironment );
                    {
                        ModulePCHCompileEnvironment.Config.PrecompiledHeaderAction = PrecompiledHeaderAction.Include;
                        ModulePCHCompileEnvironment.Config.PrecompiledHeaderIncludeFilename = ModulePCHEnvironment.PrecompiledHeaderIncludeFilename.AbsolutePath;
                        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;
                        }
                    }

                    var CPPFilesToBuild = CPPFiles;
                    if (bModuleUsesUnityBuild)
                    {
                        // unity files generated for only the set of files which share the same PCH environment
                        CPPFilesToBuild = Unity.GenerateUnityCPPs( 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 &&
                        ( SharedPCHHeaderFile != null || CPPFilesToBuild.Count >= MinFilesUsingPrecompiledHeader ) )
                    {
                        bool bAllowDLLExports = true;
                        var PCHOutputDirectory = ModuleCompileEnvironment.Config.OutputDirectory;
                        var PCHModuleName = this.Name;

                        if( SharedPCHHeaderFile != null )
                        {
                            // Disallow DLLExports when generating shared PCHs.  These headers aren't able to export anything, because they're potentially shared between many modules.
                            bAllowDLLExports = false;

                            // Save shared PCHs to a specific folder
                            PCHOutputDirectory = Path.Combine( CompileEnvironment.Config.OutputDirectory, "SharedPCHs" );

                            // Use a fake module name for "shared" PCHs.  It may be used by many modules, so we don't want to use this module's name.
                            PCHModuleName = "Shared";
                        }

                        var PCHOutput = PrecompileHeaderEnvironment.GeneratePCHCreationAction(
                            CPPFilesToBuild[0].PCHHeaderNameInCode,
                            ModulePCHEnvironment.PrecompiledHeaderIncludeFilename,
                            ModuleCompileEnvironment,
                            PCHOutputDirectory,
                            PCHModuleName,
                            bAllowDLLExports );
                        ModulePCHEnvironment.PrecompiledHeaderFile = PCHOutput.PrecompiledHeaderFile;

                        ModulePCHEnvironment.OutputObjectFiles.Clear();
                        ModulePCHEnvironment.OutputObjectFiles.AddRange( PCHOutput.ObjectFiles );
                    }

                    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;
                        LinkInputFiles.AddRange( ModulePCHCompileEnvironment.CompileFiles( CPPFilesToBuild, Name ).ObjectFiles );
                    }
                    else
                    {
                        // otherwise, compile non-pch
                        LinkInputFiles.AddRange( ModuleCompileEnvironment.CompileFiles( CPPFilesToBuild, Name ).ObjectFiles );
                    }

                    bWasModuleCodeCompiled = true;
                }

                if( BuildConfiguration.bPrintPerformanceInfo )
                {
                var TotalPCHTime = DateTime.UtcNow - PCHTimerStart;
                    Trace.TraceInformation( "PCH time for " + Name + " is " + TotalPCHTime.TotalSeconds + "s (shared PCHs: " + SharedPCHTotalTime + "s)" );
                }
            }

            if( !bWasModuleCodeCompiled )
            {
                if( CPPFiles.Count > 0 )
                {
                    var CPPFilesToCompile = CPPFiles;
                    if (bModuleUsesUnityBuild)
                    {
                        CPPFilesToCompile = Unity.GenerateUnityCPPs( CPPFilesToCompile, ModuleCompileEnvironment, Name );
                    }
                    LinkInputFiles.AddRange( ModuleCompileEnvironment.CompileFiles( CPPFilesToCompile, Name ).ObjectFiles );
                }
            }

            // Compile C files directly.
            LinkInputFiles.AddRange(ModuleCompileEnvironment.CompileFiles(CFiles, Name).ObjectFiles);

            // Compile CC files directly.
            LinkInputFiles.AddRange(ModuleCompileEnvironment.CompileFiles(CCFiles, Name).ObjectFiles);

            // Compile MM files directly.
            LinkInputFiles.AddRange(ModuleCompileEnvironment.CompileFiles(MMFiles, Name).ObjectFiles);

            // If we're building Rocket, generate a static library for this module
            if(RedistStaticLibraryPath != null)
            {
                // Create a link environment for it
                LinkEnvironment RedistLinkEnvironment = new LinkEnvironment();
                RedistLinkEnvironment.InputFiles.AddRange(LinkInputFiles);
                RedistLinkEnvironment.Config.TargetArchitecture = CompileEnvironment.Config.TargetArchitecture;
                RedistLinkEnvironment.Config.TargetConfiguration = CompileEnvironment.Config.TargetConfiguration;
                RedistLinkEnvironment.Config.TargetPlatform = CompileEnvironment.Config.TargetPlatform;
                RedistLinkEnvironment.Config.bIsBuildingDLL = false;
                RedistLinkEnvironment.Config.bIsBuildingLibrary = true;
                RedistLinkEnvironment.Config.IntermediateDirectory = Binary.Config.IntermediateDirectory;
                RedistLinkEnvironment.Config.OutputFilePath = RedistStaticLibraryPath;

                // Replace the items built so far with the library
                FileItem RedistLibrary = RedistLinkEnvironment.LinkExecutable(false);
                LinkInputFiles.Clear();
            }

            // Compile RC files.
            LinkInputFiles.AddRange(ModuleCompileEnvironment.CompileRCFiles(RCFiles).ObjectFiles);

            // Keep track of this module's public and private UObject source files, so that we can pass those off to UHT if needed
            {
                string ModuleSourceFolder = Path.GetFullPath( this.ModuleDirectory );
                var ModuleClassesSourceFolder = Path.Combine( ModuleSourceFolder, "Classes" );	// @todo uht: Want to deprecate this eventually
                foreach( var SourceFile in SourceFiles )
                {
                    // Will always be a cache hit (we did this earlier during Compile())
                    var IncludedFiles = ModuleCompileEnvironment.GetIncludeDependencies( SourceFile );

                    // Also check for intrinsic classes like "Object.h", which are special cases because they are never included in compiled code and exist only for UHT to parse
                    {
                        // Runtime/CoreUObject/Classes/Object.h
                        {
                            var IntrinsicFileItem = FileItem.GetExistingItemByPath( Path.Combine( ProjectFileGenerator.EngineRelativePath, "Source", "Runtime", Path.Combine( "CoreUObject", "Classes", "Object.h" ) ) );	// @todo uht: In Classes folder right now
                            if( !IntrinsicFileItem.bExists )
                            {
                                throw new BuildException( "Expecting " + IntrinsicFileItem.AbsolutePath + " to exist" );
                            }
                            IntrinsicFileItem.HasUObjects = true;
                            IncludedFiles.Add( IntrinsicFileItem );
                        }

                        // Runtime/Engine/Classes/Model.h
                        {
                            var IntrinsicFileItem = FileItem.GetExistingItemByPath( Path.Combine( ProjectFileGenerator.EngineRelativePath, "Source", "Runtime", Path.Combine( "Engine", "Classes", "Intrinsic", "Model.h" ) ) );	// @todo uht: In Classes folder right now
                            if( !IntrinsicFileItem.bExists )
                            {
                                throw new BuildException( "Expecting " + IntrinsicFileItem.AbsolutePath + " to exist" );
                            }
                            IntrinsicFileItem.HasUObjects = true;
                            IncludedFiles.Add( IntrinsicFileItem );
                        }
                    }

                    // @todo uht: Could check SourceFile.HasUObjects if we want to include .cpps with USTRUCT/UCLASSES here
                    foreach( var IncludedFile in IncludedFiles )
                    {
                        if( IncludedFile.HasUObjects )
                        {
                            if( IncludedFile.AbsolutePath.StartsWith( ModuleSourceFolder + Path.DirectorySeparatorChar ) )
                            {
                                // Is it private or public?
                                bool bIsPublic = false;
                                {
                                    // Get the part of the path that is relative to the module source folder
                                    var RelativeSourceFilePath = IncludedFile.AbsolutePath.Substring( ModuleSourceFolder.Length + 1 );
                                    if( RelativeSourceFilePath.StartsWith( "Classes" + Path.DirectorySeparatorChar, StringComparison.InvariantCultureIgnoreCase ) )
                                    {
                                        // Code files under the legacy 'Classes' directory are always considered public
                                        bIsPublic = true;
                                    }
                                    else if( RelativeSourceFilePath.StartsWith( "Public" + Path.DirectorySeparatorChar, StringComparison.InvariantCultureIgnoreCase ) ||
                                             ( RelativeSourceFilePath.IndexOf( Path.DirectorySeparatorChar + "Public" + Path.DirectorySeparatorChar, StringComparison.InvariantCultureIgnoreCase ) != -1 ) )
                                    {
                                        // Code is under a 'Public' subdirectory somewhere in the hierarchy
                                        bIsPublic = true;
                                    }
                                }

                                if( bIsPublic )
                                {
                                    PublicUObjectHeaders.Add( IncludedFile );
                                }
                                else
                                {
                                    PrivateUObjectHeaders.Add( IncludedFile );
                                }
                            }
                            else
                            {
                                // Not from this module, so we don't need to worry about UObjects
                            }
                        }
                    }

                }
            }

            return LinkInputFiles;
        }