示例#1
0
        /// <summary>
        /// Checks if the makefile is valid for the current set of source files. This is done separately to the Load() method to allow pre-build steps to modify source files.
        /// </summary>
        /// <param name="Makefile">The makefile that has been loaded</param>
        /// <param name="ProjectFile">Path to the project file</param>
        /// <param name="WorkingSet">The current working set of source files</param>
        /// <param name="ReasonNotLoaded">If the makefile is not valid, is set to a message describing why</param>
        /// <returns>True if the makefile is valid, false otherwise</returns>
        public static bool IsValidForSourceFiles(TargetMakefile Makefile, FileReference ProjectFile, ISourceFileWorkingSet WorkingSet, out string ReasonNotLoaded)
        {
            using (Timeline.ScopeEvent("TargetMakefile.IsValidForSourceFiles()"))
            {
                // Check if any source files have been added or removed
                foreach (KeyValuePair <DirectoryItem, FileItem[]> Pair in Makefile.DirectoryToSourceFiles)
                {
                    DirectoryItem InputDirectory = Pair.Key;
                    if (!InputDirectory.Exists || InputDirectory.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        FileItem[] SourceFiles = UEBuildModuleCPP.GetSourceFiles(InputDirectory);
                        if (SourceFiles.Length < Pair.Value.Length)
                        {
                            ReasonNotLoaded = "source file removed";
                            return(false);
                        }
                        else if (SourceFiles.Length > Pair.Value.Length)
                        {
                            ReasonNotLoaded = "source file added";
                            return(false);
                        }
                        else if (SourceFiles.Intersect(Pair.Value).Count() != SourceFiles.Length)
                        {
                            ReasonNotLoaded = "source file modified";
                            return(false);
                        }
                    }
                }

                // Check if any of the additional dependencies has changed
                foreach (FileItem AdditionalDependency in Makefile.AdditionalDependencies)
                {
                    if (!AdditionalDependency.Exists)
                    {
                        Log.TraceLog("{0} has been deleted since makefile was built.", AdditionalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} deleted", AdditionalDependency.Location.GetFileName());
                        return(false);
                    }
                    if (AdditionalDependency.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} has been modified since makefile was built.", AdditionalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} modified", AdditionalDependency.Location.GetFileName());
                        return(false);
                    }
                }

                // Check that no new plugins have been added
                foreach (FileReference PluginFile in Plugins.EnumeratePlugins(ProjectFile))
                {
                    FileItem PluginFileItem = FileItem.GetItemByFileReference(PluginFile);
                    if (!Makefile.PluginFiles.Contains(PluginFileItem))
                    {
                        Log.TraceLog("{0} has been added", PluginFile.GetFileName());
                        ReasonNotLoaded = string.Format("{0} has been added", PluginFile.GetFileName());
                        return(false);
                    }
                }

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

                // Get all H files in processed modules newer than the makefile itself
                HashSet <FileItem> HFilesNewerThanMakefile = new HashSet <FileItem>();
                foreach (UHTModuleHeaderInfo ModuleHeaderInfo in Makefile.UObjectModuleHeaders)
                {
                    foreach (FileItem HeaderFile in ModuleHeaderInfo.SourceFolder.EnumerateFiles())
                    {
                        if (HeaderFile.HasExtension(".h") && HeaderFile.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                        {
                            HFilesNewerThanMakefile.Add(HeaderFile);
                        }
                    }
                }

                // Get all H files in all modules processed in the last makefile build
                HashSet <FileItem> AllUHTHeaders = new HashSet <FileItem>(Makefile.UObjectModuleHeaders.SelectMany(x => x.HeaderFiles));

                // 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 (FileItem HeaderFile in AllUHTHeaders)
                {
                    if (!HeaderFile.Exists)
                    {
                        Log.TraceLog("File processed by UHT was deleted ({0}); invalidating makefile", HeaderFile);
                        ReasonNotLoaded = string.Format("UHT file was deleted");
                        return(false);
                    }
                }

                // 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
                SourceFileMetadataCache MetadataCache = SourceFileMetadataCache.CreateHierarchy(ProjectFile);
                foreach (FileItem HeaderFile in HFilesNewerThanMakefile)
                {
                    bool bContainsUHTData = MetadataCache.ContainsReflectionMarkup(HeaderFile);
                    bool bWasProcessed    = AllUHTHeaders.Contains(HeaderFile);
                    if (bContainsUHTData != bWasProcessed)
                    {
                        Log.TraceLog("{0} {1} contain UHT types and now {2} , ignoring it", HeaderFile, bWasProcessed ? "used to" : "didn't", bWasProcessed ? "doesn't" : "does");
                        ReasonNotLoaded = string.Format("new files with reflected types");
                        return(false);
                    }
                }

                // 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.)

                // Check if any source files in the working set no longer belong in it
                foreach (FileItem SourceFile in Makefile.WorkingSet)
                {
                    if (!WorkingSet.Contains(SourceFile) && SourceFile.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} was part of source working set and now is not; invalidating makefile", SourceFile.AbsolutePath);
                        ReasonNotLoaded = string.Format("working set of source files changed");
                        return(false);
                    }
                }

                // Check if any source files that are eligible for being in the working set have been modified
                foreach (FileItem SourceFile in Makefile.CandidatesForWorkingSet)
                {
                    if (WorkingSet.Contains(SourceFile) && SourceFile.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} was part of source working set and now is not", SourceFile.AbsolutePath);
                        ReasonNotLoaded = string.Format("working set of source files changed");
                        return(false);
                    }
                }
            }

            ReasonNotLoaded = null;
            return(true);
        }
示例#2
0
        /// <summary>
        /// Checks if the makefile is valid for the current set of source files. This is done separately to the Load() method to allow pre-build steps to modify source files.
        /// </summary>
        /// <param name="Makefile">The makefile that has been loaded</param>
        /// <param name="ProjectFile">Path to the project file</param>
        /// <param name="Platform">The platform being built</param>
        /// <param name="WorkingSet">The current working set of source files</param>
        /// <param name="ReasonNotLoaded">If the makefile is not valid, is set to a message describing why</param>
        /// <returns>True if the makefile is valid, false otherwise</returns>
        public static bool IsValidForSourceFiles(TargetMakefile Makefile, FileReference ProjectFile, UnrealTargetPlatform Platform, ISourceFileWorkingSet WorkingSet, out string ReasonNotLoaded)
        {
            using (Timeline.ScopeEvent("TargetMakefile.IsValidForSourceFiles()"))
            {
                // Get the list of excluded folder names for this platform
                ReadOnlyHashSet <string> ExcludedFolderNames = UEBuildPlatform.GetBuildPlatform(Platform).GetExcludedFolderNames();

                // Check if any source files have been added or removed
                foreach (KeyValuePair <DirectoryItem, FileItem[]> Pair in Makefile.DirectoryToSourceFiles)
                {
                    DirectoryItem InputDirectory = Pair.Key;
                    if (!InputDirectory.Exists || InputDirectory.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        FileItem[] SourceFiles = UEBuildModuleCPP.GetSourceFiles(InputDirectory);
                        if (SourceFiles.Length < Pair.Value.Length)
                        {
                            ReasonNotLoaded = "source file removed";
                            return(false);
                        }
                        else if (SourceFiles.Length > Pair.Value.Length)
                        {
                            ReasonNotLoaded = "source file added";
                            return(false);
                        }
                        else if (SourceFiles.Intersect(Pair.Value).Count() != SourceFiles.Length)
                        {
                            ReasonNotLoaded = "source file modified";
                            return(false);
                        }

                        foreach (DirectoryItem Directory in InputDirectory.EnumerateDirectories())
                        {
                            if (!Makefile.DirectoryToSourceFiles.ContainsKey(Directory) && ContainsSourceFiles(Directory, ExcludedFolderNames))
                            {
                                ReasonNotLoaded = "directory added";
                                return(false);
                            }
                        }
                    }
                }

                // Check if any external dependencies have changed. These comparisons are done against the makefile creation time.
                foreach (FileItem ExternalDependency in Makefile.ExternalDependencies)
                {
                    if (!ExternalDependency.Exists)
                    {
                        Log.TraceLog("{0} has been deleted since makefile was built.", ExternalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} deleted", ExternalDependency.Location.GetFileName());
                        return(false);
                    }
                    if (ExternalDependency.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} has been modified since makefile was built.", ExternalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} modified", ExternalDependency.Location.GetFileName());
                        return(false);
                    }
                }

                // Check if any internal dependencies has changed. These comparisons are done against the makefile modified time.
                foreach (FileItem InternalDependency in Makefile.InternalDependencies)
                {
                    if (!InternalDependency.Exists)
                    {
                        Log.TraceLog("{0} has been deleted since makefile was written.", InternalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} deleted", InternalDependency.Location.GetFileName());
                        return(false);
                    }
                    if (InternalDependency.LastWriteTimeUtc > Makefile.ModifiedTimeUtc)
                    {
                        Log.TraceLog("{0} has been modified since makefile was written.", InternalDependency.Location);
                        ReasonNotLoaded = string.Format("{0} modified", InternalDependency.Location.GetFileName());
                        return(false);
                    }
                }

                // Check that no new plugins have been added
                foreach (FileReference PluginFile in Plugins.EnumeratePlugins(ProjectFile))
                {
                    FileItem PluginFileItem = FileItem.GetItemByFileReference(PluginFile);
                    if (!Makefile.PluginFiles.Contains(PluginFileItem))
                    {
                        Log.TraceLog("{0} has been added", PluginFile.GetFileName());
                        ReasonNotLoaded = string.Format("{0} has been added", PluginFile.GetFileName());
                        return(false);
                    }
                }

                // Load the metadata cache
                SourceFileMetadataCache MetadataCache = SourceFileMetadataCache.CreateHierarchy(ProjectFile);

                // Find the set of files that contain reflection markup
                ConcurrentBag <FileItem> NewFilesWithMarkupBag = new ConcurrentBag <FileItem>();
                using (ThreadPoolWorkQueue Queue = new ThreadPoolWorkQueue())
                {
                    foreach (DirectoryItem SourceDirectory in Makefile.SourceDirectories)
                    {
                        Queue.Enqueue(() => FindFilesWithMarkup(SourceDirectory, MetadataCache, ExcludedFolderNames, NewFilesWithMarkupBag, Queue));
                    }
                }

                // Check whether the list has changed
                List <FileItem> PrevFilesWithMarkup = Makefile.UObjectModuleHeaders.Where(x => !x.bUsePrecompiled).SelectMany(x => x.HeaderFiles).ToList();
                List <FileItem> NextFilesWithMarkup = NewFilesWithMarkupBag.ToList();
                if (NextFilesWithMarkup.Count != PrevFilesWithMarkup.Count || NextFilesWithMarkup.Intersect(PrevFilesWithMarkup).Count() != PrevFilesWithMarkup.Count)
                {
                    ReasonNotLoaded = "UHT files changed";
                    return(false);
                }

                // 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.)

                // Check if any source files in the working set no longer belong in it
                foreach (FileItem SourceFile in Makefile.WorkingSet)
                {
                    if (!WorkingSet.Contains(SourceFile) && SourceFile.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} was part of source working set and now is not; invalidating makefile", SourceFile.AbsolutePath);
                        ReasonNotLoaded = string.Format("working set of source files changed");
                        return(false);
                    }
                }

                // Check if any source files that are eligible for being in the working set have been modified
                foreach (FileItem SourceFile in Makefile.CandidatesForWorkingSet)
                {
                    if (WorkingSet.Contains(SourceFile) && SourceFile.LastWriteTimeUtc > Makefile.CreateTimeUtc)
                    {
                        Log.TraceLog("{0} was part of source working set and now is not", SourceFile.AbsolutePath);
                        ReasonNotLoaded = string.Format("working set of source files changed");
                        return(false);
                    }
                }
            }

            ReasonNotLoaded = null;
            return(true);
        }