Example #1
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 public CppCompileEnvironment(CppPlatform Platform, CppConfiguration Configuration, string Architecture, CPPHeaders Headers)
 {
     this.Platform      = Platform;
     this.Configuration = Configuration;
     this.Architecture  = Architecture;
     this.Headers       = Headers;
 }
Example #2
0
        /// <summary>
        /// Copy constructor.
        /// </summary>
        protected CPPEnvironment(CPPEnvironment InCopyEnvironment)
        {
            PrecompiledHeaderFile = InCopyEnvironment.PrecompiledHeaderFile;
            Headers = InCopyEnvironment.Headers;
            bHackHeaderGenerator = InCopyEnvironment.bHackHeaderGenerator;

            Config = new CPPEnvironmentConfiguration(InCopyEnvironment.Config);
        }
Example #3
0
        public FileItem CachePCHUsageForCPPFile(FileItem CPPFile, CppIncludePaths IncludePaths, CppPlatform Platform)
        {
            // @todo ubtmake: We don't really need to scan every file looking for PCH headers, just need one.  The rest is just for error checking.
            // @todo ubtmake: We don't need all of the direct includes either.  We just need the first, unless we want to check for errors.
            List <DependencyInclude> DirectIncludeFilenames = GetDirectIncludeDependencies(CPPFile, bOnlyCachedDependencies: false);

            if (UnrealBuildTool.bPrintDebugInfo)
            {
                Log.TraceVerbose("Found direct includes for {0}: {1}", Path.GetFileName(CPPFile.AbsolutePath), string.Join(", ", DirectIncludeFilenames.Select(F => F.IncludeName)));
            }

            if (DirectIncludeFilenames.Count == 0)
            {
                return(null);
            }

            DependencyInclude FirstInclude = DirectIncludeFilenames[0];

            // 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 (FirstInclude.IncludeResolvedNameIfSuccessful != null &&
                // ignore any preexisting resolve cache if we are not configured to use it.
                bUseIncludeDependencyResolveCache &&
                // if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts
                !bTestIncludeDependencyResolveCache)
            {
                CPPFile.PrecompiledHeaderIncludeFilename = FirstInclude.IncludeResolvedNameIfSuccessful;
                return(FileItem.GetItemByFileReference(CPPFile.PrecompiledHeaderIncludeFilename));
            }

            // search the include paths to resolve the file.
            string          FirstIncludeName = FirstInclude.IncludeName;
            UEBuildPlatform BuildPlatform    = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(Platform);

            // convert back from relative to host path if needed
            if (!BuildPlatform.UseAbsolutePathsInUnityFiles())
            {
                FirstIncludeName = RemoteExports.UnconvertPath(FirstIncludeName);
            }

            FileItem PrecompiledHeaderIncludeFile = CPPHeaders.FindIncludedFile(CPPFile.Reference, FirstIncludeName, IncludePaths);

            if (PrecompiledHeaderIncludeFile == null)
            {
                FirstIncludeName = RemoteExports.UnconvertPath(FirstInclude.IncludeName);
                throw new BuildException("The first include statement in source file '{0}' is trying to include the file '{1}' as the precompiled header, but that file could not be located in any of the module's include search paths.", CPPFile.AbsolutePath, FirstIncludeName);
            }

            IncludeDependencyCache.CacheResolvedIncludeFullPath(CPPFile, 0, PrecompiledHeaderIncludeFile.Reference, bUseIncludeDependencyResolveCache, bTestIncludeDependencyResolveCache);
            CPPFile.PrecompiledHeaderIncludeFilename = PrecompiledHeaderIncludeFile.Reference;

            return(PrecompiledHeaderIncludeFile);
        }
 /// <summary>
 /// Copy constructor.
 /// </summary>
 /// <param name="Other">Environment to copy settings from</param>
 public CppCompileEnvironment(CppCompileEnvironment Other)
 {
     Platform                         = Other.Platform;
     Configuration                    = Other.Configuration;
     Architecture                     = Other.Architecture;
     OutputDirectory                  = Other.OutputDirectory;
     PCHOutputDirectory               = Other.PCHOutputDirectory;
     LocalShadowDirectory             = Other.LocalShadowDirectory;
     PrecompiledHeaderIncludeFilename = Other.PrecompiledHeaderIncludeFilename;
     PrecompiledHeaderAction          = Other.PrecompiledHeaderAction;
     bUseRTTI                         = Other.bUseRTTI;
     bUseInlining                     = Other.bUseInlining;
     bUseAVX             = Other.bUseAVX;
     bFasterWithoutUnity = Other.bFasterWithoutUnity;
     MinSourceFilesForUnityBuildOverride    = Other.MinSourceFilesForUnityBuildOverride;
     MinFilesUsingPrecompiledHeaderOverride = Other.MinFilesUsingPrecompiledHeaderOverride;
     bBuildLocallyWithSNDBS               = Other.bBuildLocallyWithSNDBS;
     bEnableExceptions                    = Other.bEnableExceptions;
     bEnableObjCExceptions                = Other.bEnableObjCExceptions;
     bShadowVariableWarningsAsErrors      = Other.bShadowVariableWarningsAsErrors;
     bEnableShadowVariableWarnings        = Other.bEnableShadowVariableWarnings;
     bUndefinedIdentifierWarningsAsErrors = Other.bUndefinedIdentifierWarningsAsErrors;
     bEnableUndefinedIdentifierWarnings   = Other.bEnableUndefinedIdentifierWarnings;
     bOptimizeCode           = Other.bOptimizeCode;
     bOptimizeForSize        = Other.bOptimizeForSize;
     bCreateDebugInfo        = Other.bCreateDebugInfo;
     bIsBuildingLibrary      = Other.bIsBuildingLibrary;
     bIsBuildingDLL          = Other.bIsBuildingDLL;
     bUseStaticCRT           = Other.bUseStaticCRT;
     bUseDebugCRT            = Other.bUseDebugCRT;
     bOmitFramePointers      = Other.bOmitFramePointers;
     bEnableOSX109Support    = Other.bEnableOSX109Support;
     bUsePDBFiles            = Other.bUsePDBFiles;
     bSupportEditAndContinue = Other.bSupportEditAndContinue;
     bUseIncrementalLinking  = Other.bUseIncrementalLinking;
     bAllowLTCG                 = Other.bAllowLTCG;
     bPGOOptimize               = Other.bPGOOptimize;
     bPGOProfile                = Other.bPGOProfile;
     PGOFilenamePrefix          = Other.PGOFilenamePrefix;
     PGODirectory               = Other.PGODirectory;
     bPrintTimingInfo           = Other.bPrintTimingInfo;
     bAllowRemotelyCompiledPCHs = Other.bAllowRemotelyCompiledPCHs;
     IncludePaths               = new CppIncludePaths(Other.IncludePaths);
     ForceIncludeFiles.AddRange(Other.ForceIncludeFiles);
     Definitions.AddRange(Other.Definitions);
     AdditionalArguments = Other.AdditionalArguments;
     AdditionalFrameworks.AddRange(Other.AdditionalFrameworks);
     PrecompiledHeaderFile = Other.PrecompiledHeaderFile;
     Headers = Other.Headers;
     bHackHeaderGenerator  = Other.bHackHeaderGenerator;
     bHideSymbolsByDefault = Other.bHideSymbolsByDefault;
 }
Example #5
0
        /// <summary>
        /// Get a set of directly included files from the given source file, resolving their include paths to FileItem instances.
        /// </summary>
        /// <param name="SourceFile">The file to check.</param>
        /// <param name="IncludePaths">Include paths to search.</param>
        /// <param name="bOnlyCachedDependencies">Whether to just return cached dependencies, or update the cache with new results.</param>
        /// <returns>Set of files that are included</returns>
        private HashSet <FileItem> GetDirectlyIncludedFiles(FileItem SourceFile, CppIncludePaths IncludePaths, bool bOnlyCachedDependencies)
        {
            // Gather a list of names of files directly included by this C++ file.
            List <DependencyInclude> DirectIncludes = GetDirectIncludeDependencies(SourceFile, bOnlyCachedDependencies: bOnlyCachedDependencies);

            // Build a list of the unique set of files that are included by this file.
            HashSet <FileItem> DirectlyIncludedFiles = new HashSet <FileItem>();

            // require a for loop here because we need to keep track of the index in the list.
            for (int DirectlyIncludedFileNameIndex = 0; DirectlyIncludedFileNameIndex < DirectIncludes.Count; ++DirectlyIncludedFileNameIndex)
            {
                // Resolve the included file name to an actual file.
                DependencyInclude DirectInclude = DirectIncludes[DirectlyIncludedFileNameIndex];
                if (!DirectInclude.HasAttemptedResolve ||
                    // ignore any preexisting resolve cache if we are not configured to use it.
                    !bUseIncludeDependencyResolveCache ||
                    // if we are testing the resolve cache, we force UBT to resolve every time to look for conflicts
                    bTestIncludeDependencyResolveCache
                    )
                {
                    ++TotalDirectIncludeResolveCacheMisses;

                    // search the include paths to resolve the file
                    FileItem DirectIncludeResolvedFile = CPPHeaders.FindIncludedFile(SourceFile.Location, DirectInclude.IncludeName, IncludePaths);
                    if (DirectIncludeResolvedFile != null)
                    {
                        DirectlyIncludedFiles.Add(DirectIncludeResolvedFile);
                    }
                    IncludeDependencyCache.CacheResolvedIncludeFullPath(SourceFile, DirectlyIncludedFileNameIndex, DirectIncludeResolvedFile != null ? DirectIncludeResolvedFile.Location : null, bUseIncludeDependencyResolveCache, bTestIncludeDependencyResolveCache);
                }
                else
                {
                    // we might have cached an attempt to resolve the file, but couldn't actually find the file (system headers, etc).
                    if (DirectInclude.IncludeResolvedNameIfSuccessful != null)
                    {
                        DirectlyIncludedFiles.Add(FileItem.GetItemByFileReference(DirectInclude.IncludeResolvedNameIfSuccessful));
                    }
                }
            }
            TotalDirectIncludeResolves += DirectIncludes.Count;

            return(DirectlyIncludedFiles);
        }
Example #6
0
        /// <summary>
        /// Finds the files directly or indirectly included by the given C++ file.
        /// </summary>
        /// <param name="CPPFile">C++ file to get the dependencies for.</param>
        /// <param name="Result">List of CPPFile dependencies.</param>
        /// <returns>false if CPPFile is still being processed further down the callstack, true otherwise.</returns>
        public bool FindAndCacheAllIncludedFiles(FileItem CPPFile, UEBuildPlatform BuildPlatform, CPPIncludeInfo CPPIncludeInfo, ref IncludedFilesSet Result, bool bOnlyCachedDependencies)
        {
            IncludedFilesSet IncludedFileList;
            Dictionary <FileItem, IncludedFilesSet> IncludedFilesMap = bOnlyCachedDependencies ? OnlyCachedIncludedFilesMap : ExhaustiveIncludedFilesMap;

            if (!IncludedFilesMap.TryGetValue(CPPFile, out IncludedFileList))
            {
                DateTime TimerStartTime = DateTime.UtcNow;

                IncludedFileList = new IncludedFilesSet();

                // Add an uninitialized entry for the include file to avoid infinitely recursing on include file loops.
                IncludedFilesMap.Add(CPPFile, IncludedFileList);

                // Gather a list of names of files directly included by this C++ file.
                List <DependencyInclude> DirectIncludes = GetDirectIncludeDependencies(CPPFile, BuildPlatform, bOnlyCachedDependencies: bOnlyCachedDependencies);

                // Build a list of the unique set of files that are included by this file.
                HashSet <FileItem> DirectlyIncludedFiles = new HashSet <FileItem>();
                // require a for loop here because we need to keep track of the index in the list.
                for (int DirectlyIncludedFileNameIndex = 0; DirectlyIncludedFileNameIndex < DirectIncludes.Count; ++DirectlyIncludedFileNameIndex)
                {
                    // Resolve the included file name to an actual file.
                    DependencyInclude DirectInclude = DirectIncludes[DirectlyIncludedFileNameIndex];
                    if (!DirectInclude.HasAttemptedResolve ||
                        // 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
                        )
                    {
                        ++TotalDirectIncludeResolveCacheMisses;

                        // search the include paths to resolve the file
                        FileItem DirectIncludeResolvedFile = CPPHeaders.FindIncludedFile(DirectInclude.IncludeName, !BuildConfiguration.bCheckExternalHeadersForModification, CPPIncludeInfo.GetIncludesPathsToSearch(CPPFile), CPPIncludeInfo.IncludeFileSearchDictionary);
                        if (DirectIncludeResolvedFile != null)
                        {
                            DirectlyIncludedFiles.Add(DirectIncludeResolvedFile);
                        }
                        IncludeDependencyCache.CacheResolvedIncludeFullPath(CPPFile, DirectlyIncludedFileNameIndex, DirectIncludeResolvedFile != null ? DirectIncludeResolvedFile.Reference : null);
                    }
                    else
                    {
                        // we might have cached an attempt to resolve the file, but couldn't actually find the file (system headers, etc).
                        if (DirectInclude.IncludeResolvedNameIfSuccessful != null)
                        {
                            DirectlyIncludedFiles.Add(FileItem.GetItemByFileReference(DirectInclude.IncludeResolvedNameIfSuccessful));
                        }
                    }
                }
                TotalDirectIncludeResolves += DirectIncludes.Count;

                // Convert the dictionary of files included by this file into a list.
                foreach (FileItem DirectlyIncludedFile in DirectlyIncludedFiles)
                {
                    // Add the file we're directly including
                    IncludedFileList.Add(DirectlyIncludedFile);

                    // Also add all of the indirectly included files!
                    if (FindAndCacheAllIncludedFiles(DirectlyIncludedFile, BuildPlatform, CPPIncludeInfo, ref IncludedFileList, bOnlyCachedDependencies: bOnlyCachedDependencies) == false)
                    {
                        // DirectlyIncludedFile is a circular dependency which is still being processed
                        // further down the callstack. Add this file to its circular dependencies list
                        // so that it can update its dependencies later.
                        IncludedFilesSet DirectlyIncludedFileIncludedFileList;
                        if (IncludedFilesMap.TryGetValue(DirectlyIncludedFile, out DirectlyIncludedFileIncludedFileList))
                        {
                            DirectlyIncludedFileIncludedFileList.CircularDependencies.Add(CPPFile);
                        }
                    }
                }

                // All dependencies have been processed by now so update all circular dependencies
                // with the full list.
                foreach (FileItem CircularDependency in IncludedFileList.CircularDependencies)
                {
                    IncludedFilesSet CircularDependencyIncludedFiles = IncludedFilesMap[CircularDependency];
                    foreach (FileItem IncludedFile in IncludedFileList)
                    {
                        CircularDependencyIncludedFiles.Add(IncludedFile);
                    }
                }
                // No need to keep this around anymore.
                IncludedFileList.CircularDependencies.Clear();

                // Done collecting files.
                IncludedFileList.bIsInitialized = true;

                TimeSpan TimerDuration = DateTime.UtcNow - TimerStartTime;
                TotalTimeSpentGettingIncludes += TimerDuration.TotalSeconds;
            }

            if (IncludedFileList.bIsInitialized)
            {
                // Copy the list of files included by this file into the result list.
                foreach (FileItem IncludedFile in IncludedFileList)
                {
                    // If the result list doesn't contain this file yet, add the file and the files it includes.
                    // NOTE: For some reason in .NET 4, Add() is over twice as fast as calling UnionWith() on the set
                    Result.Add(IncludedFile);
                }

                return(true);
            }
            else
            {
                // The IncludedFileList.bIsInitialized was false because we added a dummy entry further down the call stack.  We're already processing
                // the include list for this header elsewhere in the stack frame, so we don't need to add anything here.
                return(false);
            }
        }
        /// <summary>
        /// Loads a UBTMakefile from disk
        /// </summary>
        /// <param name="MakefilePath">Path to the makefile to load</param>
        /// <param name="ProjectFile">Path to the project file</param>
        /// <param name="ReasonNotLoaded">If the function returns null, this string will contain the reason why</param>
        /// <param name="WorkingSet">Interface to query which source files are in the working set</param>
        /// <returns>The loaded makefile, or null if it failed for some reason.  On failure, the 'ReasonNotLoaded' variable will contain information about why</returns>
        public static UBTMakefile LoadUBTMakefile(FileReference MakefilePath, FileReference ProjectFile, ISourceFileWorkingSet WorkingSet, out string ReasonNotLoaded)
        {
            // Check the directory timestamp on the project files directory.  If the user has generated project files more
            // recently than the UBTMakefile, then we need to consider the file to be out of date
            FileInfo UBTMakefileInfo = new FileInfo(MakefilePath.FullName);

            if (!UBTMakefileInfo.Exists)
            {
                // UBTMakefile doesn't even exist, so we won't bother loading it
                ReasonNotLoaded = "no existing makefile";
                return(null);
            }

            // Check the build version
            FileInfo BuildVersionFileInfo = new FileInfo(BuildVersion.GetDefaultFileName().FullName);

            if (BuildVersionFileInfo.Exists && UBTMakefileInfo.LastWriteTime.CompareTo(BuildVersionFileInfo.LastWriteTime) < 0)
            {
                Log.TraceVerbose("Existing makefile is older than Build.version, ignoring it");
                ReasonNotLoaded = "Build.version is newer";
                return(null);
            }

            // @todo ubtmake: This will only work if the directory timestamp actually changes with every single GPF.  Force delete existing files before creating new ones?  Eh... really we probably just want to delete + create a file in that folder
            //			-> UPDATE: Seems to work OK right now though on Windows platform, maybe due to GUID changes
            // @todo ubtmake: Some platforms may not save any files into this folder.  We should delete + generate a "touch" file to force the directory timestamp to be updated (or just check the timestamp file itself.  We could put it ANYWHERE, actually)

            // Installed Build doesn't need to check engine projects for outdatedness
            if (!UnrealBuildTool.IsEngineInstalled())
            {
                if (DirectoryReference.Exists(ProjectFileGenerator.IntermediateProjectFilesPath))
                {
                    DateTime EngineProjectFilesLastUpdateTime = new FileInfo(ProjectFileGenerator.ProjectTimestampFile).LastWriteTime;
                    if (UBTMakefileInfo.LastWriteTime.CompareTo(EngineProjectFilesLastUpdateTime) < 0)
                    {
                        // Engine project files are newer than UBTMakefile
                        Log.TraceVerbose("Existing makefile is older than generated engine project files, ignoring it");
                        ReasonNotLoaded = "project files are newer";
                        return(null);
                    }
                }
            }

            // Check the game project directory too
            if (ProjectFile != null)
            {
                string   ProjectFilename = ProjectFile.FullName;
                FileInfo ProjectFileInfo = new FileInfo(ProjectFilename);
                if (!ProjectFileInfo.Exists || UBTMakefileInfo.LastWriteTime.CompareTo(ProjectFileInfo.LastWriteTime) < 0)
                {
                    // .uproject file is newer than UBTMakefile
                    Log.TraceVerbose("Makefile is older than .uproject file, ignoring it");
                    ReasonNotLoaded = ".uproject file is newer";
                    return(null);
                }

                DirectoryReference MasterProjectRelativePath        = ProjectFile.Directory;
                string             GameIntermediateProjectFilesPath = Path.Combine(MasterProjectRelativePath.FullName, "Intermediate", "ProjectFiles");
                if (Directory.Exists(GameIntermediateProjectFilesPath))
                {
                    DateTime GameProjectFilesLastUpdateTime = new DirectoryInfo(GameIntermediateProjectFilesPath).LastWriteTime;
                    if (UBTMakefileInfo.LastWriteTime.CompareTo(GameProjectFilesLastUpdateTime) < 0)
                    {
                        // Game project files are newer than UBTMakefile
                        Log.TraceVerbose("Makefile is older than generated game project files, ignoring it");
                        ReasonNotLoaded = "game project files are newer";
                        return(null);
                    }
                }
            }

            // Check to see if UnrealBuildTool.exe was compiled more recently than the UBTMakefile
            DateTime UnrealBuildToolTimestamp = new FileInfo(Assembly.GetExecutingAssembly().Location).LastWriteTime;

            if (UBTMakefileInfo.LastWriteTime.CompareTo(UnrealBuildToolTimestamp) < 0)
            {
                // UnrealBuildTool.exe was compiled more recently than the UBTMakefile
                Log.TraceVerbose("Makefile is older than UnrealBuildTool.exe, ignoring it");
                ReasonNotLoaded = "UnrealBuildTool.exe is newer";
                return(null);
            }

            // Check to see if any BuildConfiguration files have changed since the last build
            List <XmlConfig.InputFile> InputFiles = XmlConfig.FindInputFiles();

            foreach (XmlConfig.InputFile InputFile in InputFiles)
            {
                FileInfo InputFileInfo = new FileInfo(InputFile.Location.FullName);
                if (InputFileInfo.LastWriteTime > UBTMakefileInfo.LastWriteTime)
                {
                    Log.TraceVerbose("Makefile is older than BuildConfiguration.xml, ignoring it");
                    ReasonNotLoaded = "BuildConfiguration.xml is newer";
                    return(null);
                }
            }

            UBTMakefile LoadedUBTMakefile = null;

            try
            {
                DateTime LoadUBTMakefileStartTime = DateTime.UtcNow;

                using (FileStream Stream = new FileStream(UBTMakefileInfo.FullName, FileMode.Open, FileAccess.Read))
                {
                    BinaryFormatter Formatter = new BinaryFormatter();
                    LoadedUBTMakefile = Formatter.Deserialize(Stream) as UBTMakefile;
                }

                if (UnrealBuildTool.bPrintPerformanceInfo)
                {
                    double LoadUBTMakefileTime = (DateTime.UtcNow - LoadUBTMakefileStartTime).TotalSeconds;
                    Log.TraceInformation("LoadUBTMakefile took " + LoadUBTMakefileTime + "s");
                }
            }
            catch (Exception Ex)
            {
                Log.TraceWarning("Failed to read makefile: {0}", Ex.Message);
                ReasonNotLoaded = "couldn't read existing makefile";
                return(null);
            }

            if (!LoadedUBTMakefile.IsValidMakefile())
            {
                Log.TraceWarning("Loaded makefile appears to have invalid contents, ignoring it ({0})", UBTMakefileInfo.FullName);
                ReasonNotLoaded = "existing makefile appears to be invalid";
                return(null);
            }

            // Check if any of the target's Build.cs files are newer than the makefile
            foreach (UEBuildTarget Target in LoadedUBTMakefile.Targets)
            {
                string TargetCsFilename = Target.TargetRulesFile.FullName;
                if (TargetCsFilename != null)
                {
                    FileInfo TargetCsFile        = new FileInfo(TargetCsFilename);
                    bool     bTargetCsFileExists = TargetCsFile.Exists;
                    if (!bTargetCsFileExists || TargetCsFile.LastWriteTime > UBTMakefileInfo.LastWriteTime)
                    {
                        Log.TraceVerbose("{0} has been {1} since makefile was built, ignoring it ({2})", TargetCsFilename, bTargetCsFileExists ? "changed" : "deleted", UBTMakefileInfo.FullName);
                        ReasonNotLoaded = string.Format("changes to target files");
                        return(null);
                    }
                }

                IEnumerable <string> BuildCsFilenames = Target.GetAllModuleBuildCsFilenames();
                foreach (string BuildCsFilename in BuildCsFilenames)
                {
                    if (BuildCsFilename != null)
                    {
                        FileInfo BuildCsFile        = new FileInfo(BuildCsFilename);
                        bool     bBuildCsFileExists = BuildCsFile.Exists;
                        if (!bBuildCsFileExists || BuildCsFile.LastWriteTime > UBTMakefileInfo.LastWriteTime)
                        {
                            Log.TraceVerbose("{0} has been {1} since makefile was built, ignoring it ({2})", BuildCsFilename, bBuildCsFileExists ? "changed" : "deleted", UBTMakefileInfo.FullName);
                            ReasonNotLoaded = string.Format("changes to module files");
                            return(null);
                        }
                    }
                }

                foreach (FlatModuleCsDataType FlatCsModuleData in Target.FlatModuleCsData.Values)
                {
                    if (FlatCsModuleData.BuildCsFilename != null && FlatCsModuleData.ExternalDependencies.Count > 0)
                    {
                        string BaseDir = Path.GetDirectoryName(FlatCsModuleData.BuildCsFilename);
                        foreach (string ExternalDependency in FlatCsModuleData.ExternalDependencies)
                        {
                            FileInfo DependencyFile        = new FileInfo(Path.Combine(BaseDir, ExternalDependency));
                            bool     bDependencyFileExists = DependencyFile.Exists;
                            if (!bDependencyFileExists || DependencyFile.LastWriteTime > UBTMakefileInfo.LastWriteTime)
                            {
                                Log.TraceVerbose("{0} has been {1} since makefile was built, ignoring it ({2})", DependencyFile.FullName, bDependencyFileExists ? "changed" : "deleted", UBTMakefileInfo.FullName);
                                ReasonNotLoaded = string.Format("changes to external dependency");
                                return(null);
                            }
                        }
                    }
                }
            }

            // We do a check to see if any modules' headers have changed which have
            // acquired or lost UHT types.  If so, which should be rare,
            // we'll just invalidate the entire makefile and force it to be rebuilt.
            foreach (UEBuildTarget Target in LoadedUBTMakefile.Targets)
            {
                // Get all H files in processed modules newer than the makefile itself
                HashSet <string> HFilesNewerThanMakefile =
                    new HashSet <string>(
                        Target.FlatModuleCsData
                        .SelectMany(x => x.Value.ModuleSourceFolder != null ? Directory.EnumerateFiles(x.Value.ModuleSourceFolder.FullName, "*.h", SearchOption.AllDirectories) : Enumerable.Empty <string>())
                        .Where(y => Directory.GetLastWriteTimeUtc(y) > UBTMakefileInfo.LastWriteTimeUtc)
                        .OrderBy(z => z).Distinct()
                        );

                // Get all H files in all modules processed in the last makefile build
                HashSet <string> AllUHTHeaders = new HashSet <string>(Target.FlatModuleCsData.Select(x => x.Value).SelectMany(x => x.UHTHeaderNames));

                // Check whether any headers have been deleted. If they have, we need to regenerate the makefile since the module might now be empty. If we don't,
                // and the file has been moved to a different module, we may include stale generated headers.
                foreach (string FileName in AllUHTHeaders)
                {
                    if (!File.Exists(FileName))
                    {
                        Log.TraceVerbose("File processed by UHT was deleted ({0}); invalidating makefile", FileName);
                        ReasonNotLoaded = string.Format("UHT file was deleted");
                        return(null);
                    }
                }

                // Makefile is invalid if:
                // * There are any newer files which contain no UHT data, but were previously in the makefile
                // * There are any newer files contain data which needs processing by UHT, but weren't not previously in the makefile
                foreach (string Filename in HFilesNewerThanMakefile)
                {
                    bool bContainsUHTData = CPPHeaders.DoesFileContainUObjects(Filename);
                    bool bWasProcessed    = AllUHTHeaders.Contains(Filename);
                    if (bContainsUHTData != bWasProcessed)
                    {
                        Log.TraceVerbose("{0} {1} contain UHT types and now {2} , ignoring it ({3})", Filename, bWasProcessed ? "used to" : "didn't", bWasProcessed ? "doesn't" : "does", UBTMakefileInfo.FullName);
                        ReasonNotLoaded = string.Format("new files with reflected types");
                        return(null);
                    }
                }
            }

            // If adaptive unity build is enabled, do a check to see if there are any source files that became part of the
            // working set since the Makefile was created (or, source files were removed from the working set.)  If anything
            // changed, then we'll force a new Makefile to be created so that we have fresh unity build blobs.  We always
            // want to make sure that source files in the working set are excluded from those unity blobs (for fastest possible
            // iteration times.)
            if (LoadedUBTMakefile.bUseAdaptiveUnityBuild)
            {
                // Check if any source files in the working set no longer belong in it
                foreach (FileItem SourceFile in LoadedUBTMakefile.SourceFileWorkingSet)
                {
                    if (!WorkingSet.Contains(SourceFile.Location) && File.GetLastWriteTimeUtc(SourceFile.AbsolutePath) > UBTMakefileInfo.LastWriteTimeUtc)
                    {
                        Log.TraceVerbose("{0} was part of source working set and now is not; invalidating makefile ({1})", SourceFile.AbsolutePath, UBTMakefileInfo.FullName);
                        ReasonNotLoaded = string.Format("working set of source files changed");
                        return(null);
                    }
                }

                // Check if any source files that are eligible for being in the working set have been modified
                foreach (FileItem SourceFile in LoadedUBTMakefile.CandidateSourceFilesForWorkingSet)
                {
                    if (WorkingSet.Contains(SourceFile.Location) && File.GetLastWriteTimeUtc(SourceFile.AbsolutePath) > UBTMakefileInfo.LastWriteTimeUtc)
                    {
                        Log.TraceVerbose("{0} was part of source working set and now is not; invalidating makefile ({1})", SourceFile.AbsolutePath, UBTMakefileInfo.FullName);
                        ReasonNotLoaded = string.Format("working set of source files changed");
                        return(null);
                    }
                }
            }

            ReasonNotLoaded = null;
            return(LoadedUBTMakefile);
        }
Example #8
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 public CPPEnvironment(CPPHeaders Headers)
 {
     this.Headers = Headers;
 }