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