Пример #1
0
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    protected virtual void OutputReadTLog (Dictionary<string, List<ITaskItem>> commandDictionary, ITaskItem [] sources)
    {
      // 
      // Output a tracking file detailing which files were read (or are dependencies) for the source files built. Changes in these files will invoke recompilation.
      // 

      try
      {
        if (!TrackFileAccess)
        {
          throw new InvalidOperationException ("'TrackFileAccess' is not set. Should not be attempting to output read TLog.");
        }

        if (commandDictionary == null)
        {
          throw new ArgumentNullException ("commandDictionary");
        }

        if (sources == null)
        {
          throw new ArgumentNullException ("sources");
        }

        if ((TLogReadFiles == null) || (TLogReadFiles.Length != 1))
        {
          throw new InvalidOperationException ("TLogReadFiles is missing or does not have a length of 1");
        }

        TrackedFileManager trackedFileManager = new TrackedFileManager ();

        if (trackedFileManager != null)
        {
          // 
          // Clear any old entries to sources which have just been processed.
          // 

          trackedFileManager.ImportFromExistingTLog (TLogReadFiles [0]);

          trackedFileManager.RemoveSourcesFromTable (sources);

          trackedFileManager.AddSourcesToTable (sources);

          // 
          // Add any explicit inputs registered by parent task.
          // 

          AddTaskSpecificDependencies (ref trackedFileManager, sources);

          // 
          // Create dependency mappings for 'global' task outputs. Assume these relate to all processed sources.
          // 
          //   Dependency files are exported/collated in various different ways:
          // 
          //   - C/C++ uses <filename>.d (alongside .o/.obj output)
          //   - Java uses: <filename>.java.d
          //   - Unix uses: <filename>.<ext>.d
          // 

          // 
          // Check alongside the known output files for a dependency file.
          // 

          {
            Dictionary<string, string> outputDependencyFilePermutations = new Dictionary<string, string> (OutputFiles.Length * 2);

            foreach (ITaskItem outputFile in OutputFiles)
            {
              string outputFileFullPath = outputFile.GetMetadata ("FullPath");

              if (!string.IsNullOrWhiteSpace (outputFileFullPath))
              {
                string [] permutations = new string [] 
                {
                  Path.ChangeExtension (outputFileFullPath, ".d"),
                  outputFileFullPath + ".d"
                };

                for (int i = 0; i < permutations.Length; ++i)
                {
                  if (!outputDependencyFilePermutations.ContainsKey (permutations [i]))
                  {
                    outputDependencyFilePermutations.Add (permutations [i], outputFileFullPath);
                  }
                }
              }
            }

            foreach (KeyValuePair<string, string> dependencyKeyPair in outputDependencyFilePermutations)
            {
              // 
              // Validate this permutation is something we'd expect.
              // 

              string dependencyFile = dependencyKeyPair.Key;

              if (string.IsNullOrWhiteSpace (dependencyFile))
              {
                continue;
              }
              else if (string.IsNullOrWhiteSpace (Path.GetFileNameWithoutExtension (dependencyFile)))
              {
                continue;
              }
              else if (!File.Exists (dependencyFile))
              {
                continue;
              }

              // 
              // Probe the dependency file. Evaluate & find parent source item and add dependencies.
              // 

              GccUtilities.DependencyParser parser = new GccUtilities.DependencyParser ();

              parser.Parse (dependencyFile);

#if DEBUG
              Log.LogMessageFromText (string.Format ("[{0}] --> Dependencies (Read) : {1} (Entries: {2})", ToolName, dependencyFile, parser.Dependencies.Count), MessageImportance.Low);

              Log.LogMessageFromText (string.Format ("[{0}] --> Dependencies (Read) : [{1}] '{2}'", ToolName, "+", parser.OutputFile.GetMetadata ("FullPath")), MessageImportance.Low);

              int index = 0;

              foreach (var dependency in parser.Dependencies)
              {
                Log.LogMessageFromText (string.Format ("[{0}] --> Dependencies (Read) : [{1}] '{2}'", ToolName, ++index, dependency), MessageImportance.Low);
              }
#endif

              if (parser.Dependencies.Count > 0)
              {
                Dictionary<string, ITaskItem> collatedFullPathSources = new Dictionary<string, ITaskItem> (sources.Length);

                foreach (ITaskItem source in sources)
                {
                  collatedFullPathSources [source.GetMetadata ("FullPath")] = source;
                }

                ITaskItem parentSourceItem = null;

                if (collatedFullPathSources.TryGetValue (parser.OutputFile.GetMetadata ("FullPath"), out parentSourceItem))
                {
                  // 
                  // We managed to find a parent source file (the master file from which the output was generated),
                  // just add of the evaluated dependencies as they are all relevant in this case.
                  // 

                  ITaskItem [] dependenciesItemArray = new ITaskItem [parser.Dependencies.Count];

                  parser.Dependencies.CopyTo (dependenciesItemArray, 0);

                  trackedFileManager.AddDependencyForSources (dependenciesItemArray, new ITaskItem [] { parentSourceItem });
                }
                else
                {
                  // 
                  // If we can't determine a parent source file (the master file from which the output was generated),
                  // we'll want to add entries for all the dependencies which aren't already flagged as sources.
                  // NOTE: This isn't ideal, but should reduce likelyhood of required dependencies being missed.
                  // 

                  Dictionary<string, ITaskItem> nonSourceDependencies = new Dictionary<string, ITaskItem> (parser.Dependencies.Count);

                  foreach (ITaskItem dependency in parser.Dependencies)
                  {
                    string dependencyFullPath = dependency.GetMetadata ("FullPath");

                    if (collatedFullPathSources.ContainsKey (dependencyFullPath))
                    {
                      continue;
                    }

                    if (nonSourceDependencies.ContainsKey (dependencyFullPath))
                    {
                      continue;
                    }

                    nonSourceDependencies.Add (dependencyFullPath, dependency);
                  }

                  ITaskItem [] nonSourceDependenciesArray = new ITaskItem [nonSourceDependencies.Count];

                  nonSourceDependencies.Values.CopyTo (nonSourceDependenciesArray, 0);

                  trackedFileManager.AddDependencyForSources (nonSourceDependenciesArray, sources);
                }
              }
            }
          }

          // 
          // In some instances, we need to use metadata to search for dependency files in alternative locations.
          // 

          foreach (KeyValuePair<string, List<ITaskItem>> commandKeyPair in commandDictionary)
          {
            foreach (ITaskItem source in commandKeyPair.Value)
            {
              Dictionary<string, string> alternateDependencyFilePermutations = new Dictionary<string, string> (4);

              string dependentOutputFile = source.GetMetadata ("OutputFile");

              string dependentObjectFileName = source.GetMetadata ("ObjectFileName");

              if (!string.IsNullOrWhiteSpace (dependentOutputFile))
              {
                string [] permutations = new string [] 
                {
                  Path.ChangeExtension (dependentOutputFile, ".d"),
                  dependentOutputFile + ".d"
                };

                for (int i = 0; i < permutations.Length; ++i)
                {
                  if (!alternateDependencyFilePermutations.ContainsKey (permutations [i]))
                  {
                    alternateDependencyFilePermutations.Add (permutations [i], dependentOutputFile);
                  }
                }
              }

              if (!string.IsNullOrWhiteSpace (dependentObjectFileName))
              {
                string [] permutations = new string [] 
                {
                  Path.ChangeExtension (dependentObjectFileName, ".d"),
                  dependentObjectFileName + ".d"
                };

                for (int i = 0; i < permutations.Length; ++i)
                {
                  if (!alternateDependencyFilePermutations.ContainsKey (permutations [i]))
                  {
                    alternateDependencyFilePermutations.Add (permutations [i], dependentObjectFileName);
                  }
                }
              }

              // 
              // Iterate through each possible dependency file. Cache listings so that similar outputs aren't re-parsed (i.e. static/shared libraries from object files)
              // 

              foreach (KeyValuePair<string, string> dependencyKeyPair in alternateDependencyFilePermutations)
              {
                // 
                // Validate this permutation is something we'd expect.
                // 

                string dependencyFile = dependencyKeyPair.Key;

                if (string.IsNullOrWhiteSpace (dependencyFile))
                {
                  continue;
                }
                else if (string.IsNullOrWhiteSpace (Path.GetFileNameWithoutExtension (dependencyFile)))
                {
                  continue;
                }
                else if (!File.Exists (dependencyFile))
                {
                  continue;
                }

                // 
                // Probe and cache each dependency file. Saves re-parsing identical file references each time.
                // 

                GccUtilities.DependencyParser parser = new GccUtilities.DependencyParser ();

                parser.Parse (dependencyFile);

#if DEBUG
                Log.LogMessageFromText (string.Format ("[{0}] --> Dependencies (Read) : {1} (Entries: {2})", ToolName, dependencyFile, parser.Dependencies.Count), MessageImportance.Low);

                Log.LogMessageFromText (string.Format ("[{0}] --> Dependencies (Read) : [{1}] '{2}'", ToolName, "+", parser.OutputFile.GetMetadata ("FullPath")), MessageImportance.Low);

                int index = 0;

                foreach (var dependency in parser.Dependencies)
                {
                  Log.LogMessageFromText (string.Format ("[{0}] --> Dependencies (Read) : [{1}] '{2}'", ToolName, ++index, dependency), MessageImportance.Low);
                }
#endif

                ITaskItem [] dependenciesItemArray = new ITaskItem [parser.Dependencies.Count];

                parser.Dependencies.CopyTo (dependenciesItemArray, 0);

                trackedFileManager.AddDependencyForSources (dependenciesItemArray, new ITaskItem [] { source });
              }
            }
          }

          trackedFileManager.Save (TLogReadFiles [0]);
        }
      }
      catch (Exception e)
      {
        Log.LogErrorFromException (e, true, true, null);
      }
    }
Пример #2
0
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    protected virtual void OutputWriteTLog (Dictionary<string, List<ITaskItem>> commandDictionary, ITaskItem [] sources)
    {
      try
      {
        if (!TrackFileAccess)
        {
          throw new InvalidOperationException ("'TrackFileAccess' is not set. Should not be attempting to output write TLog.");
        }

        if (commandDictionary == null)
        {
          throw new ArgumentNullException ("commandDictionary");
        }

        if (sources == null)
        {
          throw new ArgumentNullException ("sources");
        }

        if ((TLogWriteFiles == null) || (TLogWriteFiles.Length != 1))
        {
          throw new InvalidOperationException ("TLogWriteFiles is missing or does not have a length of 1");
        }

        TrackedFileManager trackedFileManager = new TrackedFileManager ();

        if (trackedFileManager != null)
        {
          // 
          // Clear any old entries to sources which have just been processed.
          // 

          trackedFileManager.ImportFromExistingTLog (TLogWriteFiles [0]);

          trackedFileManager.RemoveSourcesFromTable (sources);

          trackedFileManager.AddSourcesToTable (sources);

          // 
          // Add any explicit outputs registered by parent task.
          // 

          AddTaskSpecificOutputFiles (ref trackedFileManager, sources);

          // 
          // Create dependency mappings between source and explicit output file (object-file type relationship).
          // 

          Dictionary<string, ITaskItem> dependantFiles = new Dictionary<string, ITaskItem> (5);

          foreach (KeyValuePair<string, List<ITaskItem>> keyPair in commandDictionary)
          {
            foreach (ITaskItem source in keyPair.Value)
            {
              dependantFiles.Clear ();

              string outputFile = source.GetMetadata ("OutputFile");

              string objectFileName = source.GetMetadata ("ObjectFileName");

              if (!string.IsNullOrWhiteSpace (outputFile))
              {
                string key = Path.GetFullPath (outputFile);

                if (!dependantFiles.ContainsKey (key))
                {
                  dependantFiles.Add (key, new TaskItem (key));
                }
              }

              if (!string.IsNullOrWhiteSpace (objectFileName))
              {
                string key = Path.GetFullPath (objectFileName);

                if (!dependantFiles.ContainsKey (key))
                {
                  dependantFiles.Add (key, new TaskItem (key));
                }
              }

              if (!string.IsNullOrWhiteSpace (source.GetMetadata ("OutputFiles")))
              {
                string [] files = source.GetMetadata ("OutputFiles").Split (new char [] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                foreach (string file in files)
                {
                  string key = Path.GetFullPath (objectFileName);

                  if (!dependantFiles.ContainsKey (key))
                  {
                    dependantFiles.Add (key, new TaskItem (key));
                  }
                }
              }

              ITaskItem [] dependencies = new ITaskItem [dependantFiles.Count];

              dependantFiles.Values.CopyTo (dependencies, 0);

              trackedFileManager.AddDependencyForSources (dependencies, new ITaskItem [] { source });
            }
          }

          trackedFileManager.Save (TLogWriteFiles [0]);
        }
      }
      catch (Exception e)
      {
        Log.LogErrorFromException (e, true, true, null);
      }
    }