Exemplo n.º 1
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 NewProducingAttributes = string.Format("{0} {1} (ver {2})", RootAction.CommandPath.FullName, RootAction.CommandArguments, RootAction.CommandVersion);
                if (ActionHistory.UpdateProducingAttributes(ProducedItem, NewProducingAttributes))
                {
                    if (ProducedItem.Exists)
                    {
                        Log.TraceLog(
                            "{0}: Produced item \"{1}\" was produced by outdated attributes.\n  New attributes: {2}",
                            RootAction.StatusDescription,
                            Path.GetFileName(ProducedItem.AbsolutePath),
                            NewProducingAttributes
                            );
                    }

                    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);
        }