Exemplo n.º 1
0
 /// <summary>
 /// Gets the producing command line for the given file
 /// </summary>
 /// <param name="File">The output file to look for</param>
 /// <param name="CommandLine">Receives the command line used to produce this file</param>
 /// <returns>True if the output item exists</returns>
 public bool UpdateProducingCommandLine(FileItem File, string CommandLine)
 {
     if (File.Location.IsUnderDirectory(BaseDirectory) || Parent == null)
     {
         byte[] NewHash = ComputeHash(CommandLine);
         lock (LockObject)
         {
             byte[] CurrentHash;
             if (!OutputItemToCommandLineHash.TryGetValue(File, out CurrentHash) || !CompareHashes(CurrentHash, NewHash))
             {
                 OutputItemToCommandLineHash[File] = NewHash;
                 bModified = true;
                 return(true);
             }
             return(false);
         }
     }
     else
     {
         return(Parent.UpdateProducingCommandLine(File, CommandLine));
     }
 }
Exemplo n.º 2
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);
        }