Beispiel #1
0
        /// <summary>
        /// Builds a dictionary containing the actions from AllActions that are outdated by calling
        /// IsActionOutdated.
        /// </summary>
        static void GatherAllOutdatedActions(List <Action> Actions, ActionHistory ActionHistory, Dictionary <Action, bool> OutdatedActions, CppDependencyCache CppDependencies, bool bIgnoreOutdatedImportLibraries)
        {
            using (Timeline.ScopeEvent("Prefetching include dependencies"))
            {
                List <FileItem> Dependencies = new List <FileItem>();
                foreach (Action Action in Actions)
                {
                    if (Action.DependencyListFile != null)
                    {
                        Dependencies.Add(Action.DependencyListFile);
                    }
                }
                Parallel.ForEach(Dependencies, File => { List <FileItem> Temp; CppDependencies.TryGetDependencies(File, out Temp); });
            }

            using (Timeline.ScopeEvent("Cache outdated actions"))
            {
                Parallel.ForEach(Actions, Action => IsActionOutdated(Action, OutdatedActions, ActionHistory, CppDependencies, bIgnoreOutdatedImportLibraries));
            }
        }
        /// <summary>
        /// Attempts to read dependencies from the given file.
        /// </summary>
        /// <param name="InputFile">File to be read</param>
        /// <param name="OutDependencyItems">Receives a list of output items</param>
        /// <returns>True if the input file exists and the dependencies were read</returns>
        private bool TryGetDependenciesInternal(FileItem InputFile, out List <FileItem> OutDependencyItems)
        {
            if (Parent != null && !InputFile.Location.IsUnderDirectory(BaseDir))
            {
                return(Parent.TryGetDependencies(InputFile, out OutDependencyItems));
            }
            else
            {
                DependencyInfo Info;
                if (DependencyFileToInfo.TryGetValue(InputFile, out Info) && InputFile.LastWriteTimeUtc.Ticks <= Info.LastWriteTimeUtc)
                {
                    OutDependencyItems = Info.Files;
                    return(true);
                }

                List <FileItem> DependencyItems = ReadDependenciesFile(InputFile.Location);
                DependencyFileToInfo.TryAdd(InputFile, new DependencyInfo(InputFile.LastWriteTimeUtc.Ticks, DependencyItems));
                bModified = true;

                OutDependencyItems = DependencyItems;
                return(true);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Determines whether an action is outdated based on the modification times for its prerequisite
        /// and produced items.
        /// </summary>
        /// <param name="RootAction">- The action being considered.</param>
        /// <param name="OutdatedActionDictionary">-</param>
        /// <param name="ActionHistory"></param>
        /// <param name="CppDependencies"></param>
        /// <param name="bIgnoreOutdatedImportLibraries"></param>
        /// <returns>true if outdated</returns>
        public static bool IsActionOutdated(Action RootAction, Dictionary <Action, bool> OutdatedActionDictionary, ActionHistory ActionHistory, CppDependencyCache CppDependencies, bool bIgnoreOutdatedImportLibraries)
        {
            // Only compute the outdated-ness for actions that don't aren't cached in the outdated action dictionary.
            bool bIsOutdated = false;

            lock (OutdatedActionDictionary)
            {
                if (OutdatedActionDictionary.TryGetValue(RootAction, out bIsOutdated))
                {
                    return(bIsOutdated);
                }
            }

            // Determine the last time the action was run based on the write times of its produced files.
            string         LatestUpdatedProducedItemName = null;
            DateTimeOffset LastExecutionTimeUtc          = DateTimeOffset.MaxValue;

            foreach (FileItem ProducedItem in RootAction.ProducedItems)
            {
                // Check if the command-line of the action previously used to produce the item is outdated.
                string NewProducingCommandLine = RootAction.CommandPath.FullName + " " + RootAction.CommandArguments;
                if (ActionHistory.UpdateProducingCommandLine(ProducedItem, NewProducingCommandLine))
                {
                    if (ProducedItem.Exists)
                    {
                        Log.TraceLog(
                            "{0}: Produced item \"{1}\" was produced by outdated command-line.\n  New command-line: {2}",
                            RootAction.StatusDescription,
                            Path.GetFileName(ProducedItem.AbsolutePath),
                            NewProducingCommandLine
                            );
                    }

                    bIsOutdated = true;
                }

                // If the produced file doesn't exist or has zero size, consider it outdated.  The zero size check is to detect cases
                // where aborting an earlier compile produced invalid zero-sized obj files, but that may cause actions where that's
                // legitimate output to always be considered outdated.
                if (ProducedItem.Exists && (RootAction.ActionType != ActionType.Compile || ProducedItem.Length > 0 || (!ProducedItem.Location.HasExtension(".obj") && !ProducedItem.Location.HasExtension(".o"))))
                {
                    // Use the oldest produced item's time as the last execution time.
                    if (ProducedItem.LastWriteTimeUtc < LastExecutionTimeUtc)
                    {
                        LastExecutionTimeUtc          = ProducedItem.LastWriteTimeUtc;
                        LatestUpdatedProducedItemName = ProducedItem.AbsolutePath;
                    }
                }
                else
                {
                    // If any of the produced items doesn't exist, the action is outdated.
                    Log.TraceLog(
                        "{0}: Produced item \"{1}\" doesn't exist.",
                        RootAction.StatusDescription,
                        Path.GetFileName(ProducedItem.AbsolutePath)
                        );
                    bIsOutdated = true;
                }
            }

            // Check if any of the prerequisite actions are out of date
            if (!bIsOutdated)
            {
                foreach (Action PrerequisiteAction in RootAction.PrerequisiteActions)
                {
                    if (IsActionOutdated(PrerequisiteAction, OutdatedActionDictionary, ActionHistory, CppDependencies, bIgnoreOutdatedImportLibraries))
                    {
                        // Only check for outdated import libraries if we were configured to do so.  Often, a changed import library
                        // won't affect a dependency unless a public header file was also changed, in which case we would be forced
                        // to recompile anyway.  This just allows for faster iteration when working on a subsystem in a DLL, as we
                        // won't have to wait for dependent targets to be relinked after each change.
                        if (!bIgnoreOutdatedImportLibraries || !IsImportLibraryDependency(RootAction, PrerequisiteAction))
                        {
                            Log.TraceLog("{0}: Prerequisite {1} is produced by outdated action.", RootAction.StatusDescription, PrerequisiteAction.StatusDescription);
                            bIsOutdated = true;
                            break;
                        }
                    }
                }
            }

            // Check if any prerequisite item has a newer timestamp than the last execution time of this action
            if (!bIsOutdated)
            {
                foreach (FileItem PrerequisiteItem in RootAction.PrerequisiteItems)
                {
                    if (PrerequisiteItem.Exists)
                    {
                        // allow a 1 second slop for network copies
                        TimeSpan TimeDifference = PrerequisiteItem.LastWriteTimeUtc - LastExecutionTimeUtc;
                        bool     bPrerequisiteItemIsNewerThanLastExecution = TimeDifference.TotalSeconds > 1;
                        if (bPrerequisiteItemIsNewerThanLastExecution)
                        {
                            // Need to check for import libraries here too
                            if (!bIgnoreOutdatedImportLibraries || !IsImportLibraryDependency(RootAction, PrerequisiteItem))
                            {
                                Log.TraceLog("{0}: Prerequisite {1} is newer than the last execution of the action: {2} vs {3}", RootAction.StatusDescription, Path.GetFileName(PrerequisiteItem.AbsolutePath), PrerequisiteItem.LastWriteTimeUtc.ToLocalTime(), LastExecutionTimeUtc.LocalDateTime);
                                bIsOutdated = true;
                                break;
                            }
                        }
                    }
                }
            }

            // Check the dependency list
            if (!bIsOutdated && RootAction.DependencyListFile != null)
            {
                List <FileItem> DependencyFiles;
                if (!CppDependencies.TryGetDependencies(RootAction.DependencyListFile, out DependencyFiles))
                {
                    Log.TraceLog("{0}: Missing dependency list file \"{1}\"", RootAction.StatusDescription, RootAction.DependencyListFile);
                    bIsOutdated = true;
                }
                else
                {
                    foreach (FileItem DependencyFile in DependencyFiles)
                    {
                        if (!DependencyFile.Exists || DependencyFile.LastWriteTimeUtc > LastExecutionTimeUtc)
                        {
                            Log.TraceLog(
                                "{0}: Dependency {1} is newer than the last execution of the action: {2} vs {3}",
                                RootAction.StatusDescription,
                                Path.GetFileName(DependencyFile.AbsolutePath),
                                DependencyFile.LastWriteTimeUtc.ToLocalTime(),
                                LastExecutionTimeUtc.LocalDateTime
                                );
                            bIsOutdated = true;
                            break;
                        }
                    }
                }
            }

            // Cache the outdated-ness of this action.
            lock (OutdatedActionDictionary)
            {
                if (!OutdatedActionDictionary.ContainsKey(RootAction))
                {
                    OutdatedActionDictionary.Add(RootAction, bIsOutdated);
                }
            }

            return(bIsOutdated);
        }