Example #1
0
 /// <summary>
 /// Caches the subdirectories of this directories
 /// </summary>
 public void CacheDirectories()
 {
     if (Directories == null)
     {
         Dictionary <string, DirectoryItem> NewDirectories = new Dictionary <string, DirectoryItem>(DirectoryReference.Comparer);
         if (Info.Exists)
         {
             foreach (DirectoryInfo SubDirectoryInfo in Info.EnumerateDirectories())
             {
                 if (SubDirectoryInfo.Name.Length == 1 && SubDirectoryInfo.Name[0] == '.')
                 {
                     continue;
                 }
                 else if (SubDirectoryInfo.Name.Length == 2 && SubDirectoryInfo.Name[0] == '.' && SubDirectoryInfo.Name[1] == '.')
                 {
                     continue;
                 }
                 else
                 {
                     NewDirectories[SubDirectoryInfo.Name] = DirectoryItem.GetItemByDirectoryInfo(SubDirectoryInfo);
                 }
             }
         }
         Directories = NewDirectories;
     }
 }
Example #2
0
        /// <summary>
        /// Finds all the rules of the given type under a given directory
        /// </summary>
        /// <param name="Directory">Directory to search</param>
        /// <param name="Type">Type of rules to return</param>
        /// <returns>List of rules files of the given type</returns>
        private static IReadOnlyList <FileReference> FindAllRulesFiles(DirectoryReference Directory, RulesFileType Type)
        {
            // Check to see if we've already cached source files for this folder
            RulesFileCache Cache;

            if (!RootFolderToRulesFileCache.TryGetValue(Directory, out Cache))
            {
                Cache = new RulesFileCache();
                using (ThreadPoolWorkQueue Queue = new ThreadPoolWorkQueue())
                {
                    DirectoryItem BaseDirectory = DirectoryItem.GetItemByDirectoryReference(Directory);
                    Queue.Enqueue(() => FindAllRulesFilesRecursively(BaseDirectory, Cache, Queue));
                }
                RootFolderToRulesFileCache[Directory] = Cache;
            }

            // Get the list of files of the type we're looking for
            if (Type == RulesCompiler.RulesFileType.Module)
            {
                return(Cache.ModuleRules);
            }
            else if (Type == RulesCompiler.RulesFileType.Target)
            {
                return(Cache.TargetRules);
            }
            else if (Type == RulesCompiler.RulesFileType.AutomationModule)
            {
                return(Cache.AutomationModules);
            }
            else
            {
                throw new BuildException("Unhandled rules type: {0}", Type);
            }
        }
Example #3
0
        /// <summary>
        /// Prefetch multiple directories in parallel
        /// </summary>
        /// <param name="Directories">The directories to cache</param>
        private static void PrefetchRulesFiles(IEnumerable <DirectoryReference> Directories)
        {
            ThreadPoolWorkQueue Queue = null;

            try
            {
                foreach (DirectoryReference Directory in Directories)
                {
                    if (!RootFolderToRulesFileCache.ContainsKey(Directory))
                    {
                        RulesFileCache Cache = new RulesFileCache();
                        RootFolderToRulesFileCache[Directory] = Cache;

                        if (Queue == null)
                        {
                            Queue = new ThreadPoolWorkQueue();
                        }

                        DirectoryItem DirectoryItem = DirectoryItem.GetItemByDirectoryReference(Directory);
                        Queue.Enqueue(() => FindAllRulesFilesRecursively(DirectoryItem, Cache, Queue));
                    }
                }
            }
            finally
            {
                if (Queue != null)
                {
                    Queue.Dispose();
                    Queue = null;
                }
            }
        }
Example #4
0
 /// <summary>
 /// Scans an arbitrary directory tree
 /// </summary>
 /// <param name="Directory">Root of the directory tree</param>
 static void ScanDirectoryTree(DirectoryItem Directory)
 {
     foreach (DirectoryItem SubDirectory in Directory.EnumerateDirectories())
     {
         Enqueue(() => ScanDirectoryTree(SubDirectory));
     }
     Directory.CacheFiles();
 }
Example #5
0
        /// <summary>
        /// Read a file item as a DirectoryItem and name. This is slower than reading it directly, but results in a significantly smaller archive
        /// where most files are in the same directories.
        /// </summary>
        /// <param name="Reader">Archive to read from</param>
        /// <returns>FileItem read from the archive</returns>
        static FileItem ReadCompactFileItemData(this BinaryArchiveReader Reader)
        {
            DirectoryItem Directory = Reader.ReadDirectoryItem();
            string        Name      = Reader.ReadString();

            FileItem FileItem = FileItem.GetItemByFileReference(FileReference.Combine(Directory.Location, Name));

            FileItem.UpdateCachedDirectory(Directory);
            return(FileItem);
        }
Example #6
0
        /// <summary>
        /// Scans a project directory, adding tasks for subdirectories
        /// </summary>
        /// <param name="ProjectDirectory">The project directory to search</param>
        static void ScanProjectDirectory(DirectoryItem ProjectDirectory)
        {
            DirectoryItem ProjectPluginsDirectory = DirectoryItem.Combine(ProjectDirectory, "Plugins");

            Enqueue(() => ScanPluginFolder(ProjectPluginsDirectory));

            DirectoryItem ProjectSourceDirectory = DirectoryItem.Combine(ProjectDirectory, "Source");

            Enqueue(() => ScanDirectoryTree(ProjectSourceDirectory));
        }
Example #7
0
 /// <summary>
 /// Enqueue a project directory for prefetching
 /// </summary>
 /// <param name="ProjectDirectory">The project directory to prefetch</param>
 public static void QueueProjectDirectory(DirectoryReference ProjectDirectory)
 {
     lock (QueuedDirectories)
     {
         if (QueuedDirectories.Add(ProjectDirectory))
         {
             Enqueue(() => ScanProjectDirectory(DirectoryItem.GetItemByDirectoryReference(ProjectDirectory)));
         }
     }
 }
Example #8
0
 /// <summary>
 /// Enqueue a directory tree for prefetching
 /// </summary>
 /// <param name="Directory">Directory to start searching from</param>
 public static void QueueDirectoryTree(DirectoryReference Directory)
 {
     lock (QueuedDirectories)
     {
         if (QueuedDirectories.Add(Directory))
         {
             Enqueue(() => ScanDirectoryTree(DirectoryItem.GetItemByDirectoryReference(Directory)));
         }
     }
 }
Example #9
0
        /// <summary>
        /// Scans a project directory, adding tasks for subdirectories
        /// </summary>
        /// <param name="ProjectDirectory">The project directory to search</param>
        static void ScanProjectDirectory(DirectoryItem ProjectDirectory)
        {
            foreach (DirectoryReference ExtensionDir in UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory))
            {
                DirectoryItem BaseDirectory = DirectoryItem.GetItemByDirectoryReference(ExtensionDir);
                BaseDirectory.CacheDirectories();

                DirectoryItem BasePluginsDirectory = DirectoryItem.Combine(ProjectDirectory, "Plugins");
                Enqueue(() => ScanPluginFolder(BasePluginsDirectory));

                DirectoryItem BaseSourceDirectory = DirectoryItem.Combine(ProjectDirectory, "Source");
                Enqueue(() => ScanDirectoryTree(BaseSourceDirectory));
            }
        }
Example #10
0
 /// <summary>
 /// Scans a plugin parent directory, adding tasks for subdirectories
 /// </summary>
 /// <param name="Directory">The directory which may contain plugin directories</param>
 static void ScanPluginFolder(DirectoryItem Directory)
 {
     foreach (DirectoryItem SubDirectory in Directory.EnumerateDirectories())
     {
         if (SubDirectory.EnumerateFiles().Any(x => x.HasExtension(".uplugin")))
         {
             Enqueue(() => ScanDirectoryTree(DirectoryItem.Combine(SubDirectory, "Source")));
         }
         else
         {
             Enqueue(() => ScanPluginFolder(SubDirectory));
         }
     }
 }
Example #11
0
        /// <summary>
        /// Finds or creates a directory item from its location
        /// </summary>
        /// <param name="Location">Path to the directory</param>
        /// <returns>The directory item for this location</returns>
        public static DirectoryItem GetItemByDirectoryReference(DirectoryReference Location)
        {
            DirectoryItem Result;

            if (!LocationToItem.TryGetValue(Location, out Result))
            {
                DirectoryItem NewItem = new DirectoryItem(Location, new DirectoryInfo(Location.FullName));
                if (LocationToItem.TryAdd(Location, NewItem))
                {
                    Result = NewItem;
                }
                else
                {
                    Result = LocationToItem[Location];
                }
            }
            return(Result);
        }
Example #12
0
        /// <summary>
        /// Attempts to get a sub-directory by name
        /// </summary>
        /// <param name="Name">Name of the directory</param>
        /// <param name="OutDirectory">If successful receives the matching directory item with this name</param>
        /// <returns>True if the file exists, false otherwise</returns>
        public bool TryGetDirectory(string Name, out DirectoryItem OutDirectory)
        {
            if (Name.Length > 0 && Name[0] == '.')
            {
                if (Name.Length == 1)
                {
                    OutDirectory = this;
                    return(true);
                }
                else if (Name.Length == 2 && Name[1] == '.')
                {
                    OutDirectory = GetParentDirectoryItem();
                    return(OutDirectory != null);
                }
            }

            CacheDirectories();
            return(Directories.TryGetValue(Name, out OutDirectory));
        }
Example #13
0
        /// <summary>
        /// Finds all the source files under a directory that contain reflection markup
        /// </summary>
        /// <param name="Directory">The directory to search</param>
        /// <param name="MetadataCache">Cache of source file metadata</param>
        /// <param name="ExcludedFolderNames">Set of folder names to ignore when recursing the directory tree</param>
        /// <param name="FilesWithMarkup">Receives the set of files which contain reflection markup</param>
        /// <param name="Queue">Queue to add sub-tasks to</param>
        static void FindFilesWithMarkup(DirectoryItem Directory, SourceFileMetadataCache MetadataCache, ReadOnlyHashSet <string> ExcludedFolderNames, ConcurrentBag <FileItem> FilesWithMarkup, ThreadPoolWorkQueue Queue)
        {
            // Search through all the subfolders
            foreach (DirectoryItem SubDirectory in Directory.EnumerateDirectories())
            {
                if (!ExcludedFolderNames.Contains(SubDirectory.Name))
                {
                    Queue.Enqueue(() => FindFilesWithMarkup(SubDirectory, MetadataCache, ExcludedFolderNames, FilesWithMarkup, Queue));
                }
            }

            // Check for all the headers in this folder
            foreach (FileItem File in Directory.EnumerateFiles())
            {
                if (File.HasExtension(".h") && MetadataCache.ContainsReflectionMarkup(File))
                {
                    FilesWithMarkup.Add(File);
                }
            }
        }
Example #14
0
        /// <summary>
        /// Search through a directory tree for any rules files
        /// </summary>
        /// <param name="Directory">The root directory to search from</param>
        /// <param name="Cache">Receives all the discovered rules files</param>
        /// <param name="Queue">Queue for adding additional tasks to</param>
        private static void FindAllRulesFilesRecursively(DirectoryItem Directory, RulesFileCache Cache, ThreadPoolWorkQueue Queue)
        {
            // Scan all the files in this directory
            bool bSearchSubFolders = true;

            foreach (FileItem File in Directory.EnumerateFiles())
            {
                if (File.HasExtension(".build.cs"))
                {
                    lock (Cache.ModuleRules)
                    {
                        Cache.ModuleRules.Add(File.Location);
                    }
                    bSearchSubFolders = false;
                }
                else if (File.HasExtension(".target.cs"))
                {
                    lock (Cache.TargetRules)
                    {
                        Cache.TargetRules.Add(File.Location);
                    }
                }
                else if (File.HasExtension(".automation.csproj"))
                {
                    lock (Cache.AutomationModules)
                    {
                        Cache.AutomationModules.Add(File.Location);
                    }
                    bSearchSubFolders = false;
                }
            }

            // If we didn't find anything to stop the search, search all the subdirectories too
            if (bSearchSubFolders)
            {
                foreach (DirectoryItem SubDirectory in Directory.EnumerateDirectories())
                {
                    Queue.Enqueue(() => FindAllRulesFilesRecursively(SubDirectory, Cache, Queue));
                }
            }
        }
Example #15
0
        /// <summary>
        /// Scans the engine directory, adding tasks for subdirectories
        /// </summary>
        static void ScanEngineDirectory()
        {
            DirectoryItem EngineDirectory = DirectoryItem.GetItemByDirectoryReference(UnrealBuildTool.EngineDirectory);

            EngineDirectory.CacheDirectories();

            DirectoryItem EnginePluginsDirectory = DirectoryItem.Combine(EngineDirectory, "Plugins");

            Enqueue(() => ScanPluginFolder(EnginePluginsDirectory));

            DirectoryItem EngineRuntimeDirectory = DirectoryItem.GetItemByDirectoryReference(UnrealBuildTool.EngineSourceRuntimeDirectory);

            Enqueue(() => ScanDirectoryTree(EngineRuntimeDirectory));

            DirectoryItem EngineDeveloperDirectory = DirectoryItem.GetItemByDirectoryReference(UnrealBuildTool.EngineSourceDeveloperDirectory);

            Enqueue(() => ScanDirectoryTree(EngineDeveloperDirectory));

            DirectoryItem EngineEditorDirectory = DirectoryItem.GetItemByDirectoryReference(UnrealBuildTool.EngineSourceEditorDirectory);

            Enqueue(() => ScanDirectoryTree(EngineEditorDirectory));
        }
Example #16
0
        /// <summary>
        /// Scans the engine directory, adding tasks for subdirectories
        /// </summary>
        static void ScanEngineDirectory()
        {
            foreach (DirectoryReference ExtensionDir in UnrealBuildTool.GetExtensionDirs(UnrealBuildTool.EngineDirectory))
            {
                DirectoryItem BaseDirectory = DirectoryItem.GetItemByDirectoryReference(ExtensionDir);
                BaseDirectory.CacheDirectories();

                DirectoryItem BasePluginsDirectory = DirectoryItem.Combine(BaseDirectory, "Plugins");
                Enqueue(() => ScanPluginFolder(BasePluginsDirectory));

                DirectoryItem BaseSourceDirectory = DirectoryItem.Combine(BaseDirectory, "Source");
                BaseSourceDirectory.CacheDirectories();

                DirectoryItem BaseSourceRuntimeDirectory = DirectoryItem.Combine(BaseSourceDirectory, "Runtime");
                Enqueue(() => ScanDirectoryTree(BaseSourceRuntimeDirectory));

                DirectoryItem BaseSourceDeveloperDirectory = DirectoryItem.Combine(BaseSourceDirectory, "Developer");
                Enqueue(() => ScanDirectoryTree(BaseSourceDeveloperDirectory));

                DirectoryItem BaseSourceEditorDirectory = DirectoryItem.Combine(BaseSourceDirectory, "Editor");
                Enqueue(() => ScanDirectoryTree(BaseSourceEditorDirectory));
            }
        }
Example #17
0
        /// <summary>
        /// Find paths to all the plugins under a given parent directory (recursively)
        /// </summary>
        /// <param name="ParentDirectory">Parent directory to look in. Plugins will be found in any *subfolders* of this directory.</param>
        /// <param name="FileNames">List of filenames. Will have all the discovered .uplugin files appended to it.</param>
        /// <param name="Queue">Queue for tasks to be executed</param>
        static void EnumeratePluginsInternal(DirectoryItem ParentDirectory, List <FileReference> FileNames, ThreadPoolWorkQueue Queue)
        {
            foreach (DirectoryItem ChildDirectory in ParentDirectory.EnumerateDirectories())
            {
                bool bSearchSubDirectories = true;
                foreach (FileItem PluginFile in ChildDirectory.EnumerateFiles())
                {
                    if (PluginFile.HasExtension(".uplugin"))
                    {
                        lock (FileNames)
                        {
                            FileNames.Add(PluginFile.Location);
                        }
                        bSearchSubDirectories = false;
                    }
                }

                if (bSearchSubDirectories)
                {
                    Queue.Enqueue(() => EnumeratePluginsInternal(ChildDirectory, FileNames, Queue));
                }
            }
        }
Example #18
0
        /// <summary>
        /// Determines if a directory, or any subdirectory of it, contains new source files
        /// </summary>
        /// <param name="Directory">Directory to search through</param>
        /// <param name="ExcludedFolderNames">Set of directory names to exclude</param>
        /// <returns>True if the directory contains any source files</returns>
        static bool ContainsSourceFiles(DirectoryItem Directory, ReadOnlyHashSet <string> ExcludedFolderNames)
        {
            // Check this directory isn't ignored
            if (!ExcludedFolderNames.Contains(Directory.Name))
            {
                // Check for any source files in this actual directory
                FileItem[] SourceFiles = UEBuildModuleCPP.GetSourceFiles(Directory);
                if (SourceFiles.Length > 0)
                {
                    return(true);
                }

                // Check for any source files in a subdirectory
                foreach (DirectoryItem SubDirectory in Directory.EnumerateDirectories())
                {
                    if (ContainsSourceFiles(SubDirectory, ExcludedFolderNames))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Example #19
0
        /// <summary>
        /// Find paths to all the plugins under a given parent directory (recursively)
        /// </summary>
        /// <param name="ParentDirectory">Parent directory to look in. Plugins will be found in any *subfolders* of this directory.</param>
        public static IEnumerable <FileReference> EnumeratePlugins(DirectoryReference ParentDirectory)
        {
            List <FileReference> FileNames;

            if (!PluginFileCache.TryGetValue(ParentDirectory, out FileNames))
            {
                FileNames = new List <FileReference>();

                DirectoryItem ParentDirectoryItem = DirectoryItem.GetItemByDirectoryReference(ParentDirectory);
                if (ParentDirectoryItem.Exists)
                {
                    using (ThreadPoolWorkQueue Queue = new ThreadPoolWorkQueue())
                    {
                        EnumeratePluginsInternal(ParentDirectoryItem, FileNames, Queue);
                    }
                }

                // Sort the filenames to ensure that the plugin order is deterministic; otherwise response files will change with each build.
                FileNames = FileNames.OrderBy(x => x.FullName, StringComparer.OrdinalIgnoreCase).ToList();

                PluginFileCache.Add(ParentDirectory, FileNames);
            }
            return(FileNames);
        }
Example #20
0
 static public bool DirectoryExists(DirectoryReference Directory)
 {
     return(DirectoryItem.GetItemByDirectoryReference(Directory).Exists);
 }
Example #21
0
 static public IEnumerable <DirectoryReference> EnumerateDirectories(DirectoryReference Directory)
 {
     return(DirectoryItem.GetItemByDirectoryReference(Directory).EnumerateDirectories().Select(x => x.Location));
 }
Example #22
0
 static public void InvalidateCachedDirectory(DirectoryReference Directory)
 {
     DirectoryItem.GetItemByDirectoryReference(Directory).ResetCachedInfo();
 }
Example #23
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);
        }
Example #24
0
 /// <inheritdoc/>
 public void AddSourceDir(DirectoryItem SourceDir)
 {
     SourceDirectories.Add(SourceDir);
 }
Example #25
0
 /// <inheritdoc/>
 public void AddSourceFiles(DirectoryItem SourceDir, FileItem[] SourceFiles)
 {
     DirectoryToSourceFiles[SourceDir] = SourceFiles;
 }
Example #26
0
 /// <summary>
 /// Write a directory item to a binary archive
 /// </summary>
 /// <param name="Writer">Writer to serialize data to</param>
 /// <param name="DirectoryItem">Directory item to write</param>
 public static void WriteDirectoryItem(this BinaryArchiveWriter Writer, DirectoryItem DirectoryItem)
 {
     Writer.WriteObjectReference <DirectoryItem>(DirectoryItem, () => Writer.WriteDirectoryReference(DirectoryItem.Location));
 }
Example #27
0
 /// <summary>
 /// Read a directory item from a binary archive
 /// </summary>
 /// <param name="Reader">Reader to serialize data from</param>
 /// <returns>Instance of the serialized directory item</returns>
 public static DirectoryItem ReadDirectoryItem(this BinaryArchiveReader Reader)
 {
     return(Reader.ReadObjectReference <DirectoryItem>(() => DirectoryItem.GetItemByDirectoryReference(Reader.ReadDirectoryReference())));
 }
Example #28
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);
        }
Example #29
0
 /// <summary>
 /// Gets a new directory item by combining the existing directory item with the given path fragments
 /// </summary>
 /// <param name="BaseDirectory">Base directory to append path fragments to</param>
 /// <param name="Fragments">The path fragments to append</param>
 /// <returns>Directory item corresponding to the combined path</returns>
 public static DirectoryItem Combine(DirectoryItem BaseDirectory, params string[] Fragments)
 {
     return(DirectoryItem.GetItemByDirectoryReference(DirectoryReference.Combine(BaseDirectory.Location, Fragments)));
 }
Example #30
0
        /// <summary>
        /// Creates the makefile for a target. If an existing, valid makefile already exists on disk, loads that instead.
        /// </summary>
        /// <param name="BuildConfiguration">The build configuration</param>
        /// <param name="TargetDescriptor">Target being built</param>
        /// <param name="WorkingSet">Set of source files which are part of the working set</param>
        /// <returns>Makefile for the given target</returns>
        static TargetMakefile CreateMakefile(BuildConfiguration BuildConfiguration, TargetDescriptor TargetDescriptor, ISourceFileWorkingSet WorkingSet)
        {
            // Get the path to the makefile for this target
            FileReference MakefileLocation = null;

            if (BuildConfiguration.bUseUBTMakefiles && TargetDescriptor.SpecificFilesToCompile.Count == 0)
            {
                MakefileLocation = TargetMakefile.GetLocation(TargetDescriptor.ProjectFile, TargetDescriptor.Name, TargetDescriptor.Platform, TargetDescriptor.Architecture, TargetDescriptor.Configuration);
            }

            // Try to load an existing makefile
            TargetMakefile Makefile = null;

            if (MakefileLocation != null)
            {
                using (Timeline.ScopeEvent("TargetMakefile.Load()"))
                {
                    string ReasonNotLoaded;
                    Makefile = TargetMakefile.Load(MakefileLocation, TargetDescriptor.ProjectFile, TargetDescriptor.Platform, TargetDescriptor.AdditionalArguments.GetRawArray(), out ReasonNotLoaded);
                    if (Makefile == null)
                    {
                        Log.TraceInformation("Creating makefile for {0} ({1})", TargetDescriptor.Name, ReasonNotLoaded);
                    }
                }
            }

            // If we have a makefile, execute the pre-build steps and check it's still valid
            bool bHasRunPreBuildScripts = false;

            if (Makefile != null)
            {
                // Execute the scripts. We have to invalidate all cached file info after doing so, because we don't know what may have changed.
                if (Makefile.PreBuildScripts.Length > 0)
                {
                    Utils.ExecuteCustomBuildSteps(Makefile.PreBuildScripts);
                    DirectoryItem.ResetAllCachedInfo_SLOW();
                }

                // Don't run the pre-build steps again, even if we invalidate the makefile.
                bHasRunPreBuildScripts = true;

                // Check that the makefile is still valid
                string Reason;
                if (!TargetMakefile.IsValidForSourceFiles(Makefile, TargetDescriptor.ProjectFile, TargetDescriptor.Platform, WorkingSet, out Reason))
                {
                    Log.TraceInformation("Invalidating makefile for {0} ({1})", TargetDescriptor.Name, Reason);
                    Makefile = null;
                }
            }

            // If we couldn't load a makefile, create a new one
            if (Makefile == null)
            {
                // Create the target
                UEBuildTarget Target;
                using (Timeline.ScopeEvent("UEBuildTarget.Create()"))
                {
                    Target = UEBuildTarget.Create(TargetDescriptor, BuildConfiguration.bSkipRulesCompile, BuildConfiguration.bUsePrecompiled);
                }

                // Create the pre-build scripts
                FileReference[] PreBuildScripts = Target.CreatePreBuildScripts();

                // Execute the pre-build scripts
                if (!bHasRunPreBuildScripts)
                {
                    Utils.ExecuteCustomBuildSteps(PreBuildScripts);
                    bHasRunPreBuildScripts = true;
                }

                // Build the target
                using (Timeline.ScopeEvent("UEBuildTarget.Build()"))
                {
                    const bool bIsAssemblingBuild = true;
                    Makefile = Target.Build(BuildConfiguration, WorkingSet, bIsAssemblingBuild, TargetDescriptor.SpecificFilesToCompile);
                }

                // Save the pre-build scripts onto the makefile
                Makefile.PreBuildScripts = PreBuildScripts;

                // Save the additional command line arguments
                Makefile.AdditionalArguments = TargetDescriptor.AdditionalArguments.GetRawArray();

                // Save the environment variables
                foreach (System.Collections.DictionaryEntry EnvironmentVariable in Environment.GetEnvironmentVariables())
                {
                    Makefile.EnvironmentVariables.Add(Tuple.Create((string)EnvironmentVariable.Key, (string)EnvironmentVariable.Value));
                }

                // Save the makefile for next time
                if (MakefileLocation != null)
                {
                    using (Timeline.ScopeEvent("TargetMakefile.Save()"))
                    {
                        Makefile.Save(MakefileLocation);
                    }
                }
            }
            else
            {
                // Restore the environment variables
                foreach (Tuple <string, string> EnvironmentVariable in Makefile.EnvironmentVariables)
                {
                    Environment.SetEnvironmentVariable(EnvironmentVariable.Item1, EnvironmentVariable.Item2);
                }

                // If the target needs UHT to be run, we'll go ahead and do that now
                if (Makefile.UObjectModules.Count > 0)
                {
                    const bool bIsGatheringBuild  = false;
                    const bool bIsAssemblingBuild = true;

                    FileReference ModuleInfoFileName = FileReference.Combine(Makefile.ProjectIntermediateDirectory, TargetDescriptor.Name + ".uhtmanifest");
                    ExternalExecution.ExecuteHeaderToolIfNecessary(BuildConfiguration, TargetDescriptor.ProjectFile, TargetDescriptor.Name, Makefile.TargetType, Makefile.bHasProjectScriptPlugin, UObjectModules: Makefile.UObjectModules, ModuleInfoFileName: ModuleInfoFileName, bIsGatheringBuild: bIsGatheringBuild, bIsAssemblingBuild: bIsAssemblingBuild, WorkingSet: WorkingSet);
                }
            }
            return(Makefile);
        }