Index: visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/NaClCompile.cs |
diff --git a/visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/NaClCompile.cs b/visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/NaClCompile.cs |
index 7c91a261a3a41ad247267ab2a2df97cfd43da397..5682575a61bfc693af45e0c539fba6932909481b 100644 |
--- a/visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/NaClCompile.cs |
+++ b/visual_studio/NativeClientVSAddIn/NaCl.Build.CPPTasks/NaClCompile.cs |
@@ -1,645 +1,645 @@ |
- |
-using System; |
-using System.Collections.Generic; |
-using System.Text; |
-using System.Collections; |
-using System.IO; |
-using System.Reflection; |
-using System.Resources; |
-using Microsoft.Build.Framework; |
-using Microsoft.Build.Utilities; |
- |
-using System.Diagnostics; |
- |
-namespace NaCl.Build.CPPTasks |
-{ |
- public class NaClCompile : ToolTask |
- { |
- private XamlParser m_XamlParser; |
- private ITaskItem[] excludedInputPaths; |
- private ITaskItem[] tlogReadFiles; |
- private ITaskItem tlogCommandFile; |
- private ITaskItem[] tlogWriteFiles; |
- private CanonicalTrackedInputFiles trackedInputFiles; |
- private bool skippedExecution; |
- private ITaskItem[] compileSourceList; |
- public bool BuildingInIDE { get; set; } |
- private string m_toolname; |
- private bool trackFileAccess; |
- private bool minimalRebuildFromTracking; |
- private string pathToLog; |
- |
- [Required] |
- public string PropertiesFile { get; set; } |
- |
- [Required] |
- public ITaskItem[] Sources { get; set; } |
- |
- [Required] |
- public string NaCLCompilerPath { get; set; } |
- |
- [Required] |
- public string OutputCommandLine { get; set; } |
- |
- [Required] |
- public string TrackerLogDirectory { get; set; } |
- |
- |
- protected override string GenerateFullPathToTool() { return ToolName; } |
- |
- public NaClCompile() |
- : base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly())) |
- { |
- this.pathToLog = string.Empty; |
- this.EnvironmentVariables = new string []{"CYGWIN=nodosfilewarning", "LC_CTYPE=C"}; |
- } |
- |
- protected IDictionary<string, string> GenerateCommandLinesFromTlog() |
- { |
- IDictionary<string, string> cmdLineDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); |
- string tlogFilename = this.TLogCommandFile.GetMetadata("FullPath"); |
- if (File.Exists(tlogFilename)) |
- { |
- using (StreamReader reader = File.OpenText(tlogFilename)) |
- { |
- string filename = string.Empty; |
- for (string lineStr = reader.ReadLine(); lineStr != null; lineStr = reader.ReadLine()) |
- { |
- if (lineStr.Length == 0 || |
- (lineStr[0] == '^' && lineStr.Length == 1)) |
- { |
- Log.LogMessage(MessageImportance.High, "Invalid line in command tlog"); |
- break; |
- } |
- else if (lineStr[0] == '^') |
- { |
- filename = lineStr.Substring(1); |
- } |
- else |
- { |
- cmdLineDictionary[filename] = lineStr; |
- } |
- } |
- } |
- } |
- return cmdLineDictionary; |
- } |
- |
- protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance) |
- { |
- base.LogEventsFromTextOutput(GCCUtilities.Convert_Output_GCC_to_VS(singleLine), messageImportance); |
- } |
- |
- private void ConstructReadTLog(ITaskItem[] compiledSources, CanonicalTrackedOutputFiles outputs) |
- { |
- string trackerPath = Path.GetFullPath(TlogDirectory + ReadTLogFilenames[0]); |
- |
- //save tlog for sources not compiled during this execution |
- TaskItem readTrackerItem = new TaskItem(trackerPath); |
- CanonicalTrackedInputFiles files = new CanonicalTrackedInputFiles(new TaskItem[] { readTrackerItem }, Sources, outputs, false, false); |
- files.RemoveEntriesForSource(compiledSources); |
- files.SaveTlog(); |
- |
- //add tlog information for compiled sources |
- using (StreamWriter writer = new StreamWriter(trackerPath, true, Encoding.Unicode)) |
- { |
- foreach (ITaskItem source in compiledSources) |
- { |
- string sourcePath = Path.GetFullPath(source.ItemSpec).ToUpperInvariant(); |
- |
- string objectFilePath = Path.GetFullPath(source.GetMetadata("ObjectFileName")); |
- string depFilePath = Path.ChangeExtension(objectFilePath, ".d"); |
- |
- try |
- { |
- if (File.Exists(depFilePath) == false) |
- { |
- Log.LogMessage(MessageImportance.High, depFilePath + " not found"); |
- } |
- else |
- { |
- writer.WriteLine("^" + sourcePath); |
- DependencyParser parser = new DependencyParser(depFilePath); |
- |
- foreach (string filename in parser.Dependencies) |
- { |
- //source itself not required |
- if (filename == sourcePath) |
- continue; |
- |
- if (File.Exists(filename) == false) |
- { |
- Log.LogMessage(MessageImportance.High, "File " + sourcePath + " is missing dependency " + filename); |
- } |
- |
- writer.WriteLine(filename); |
- } |
- |
- //remove d file |
- try |
- { |
- File.Delete(depFilePath); |
- } |
- finally |
- { |
- |
- } |
- } |
- |
- } |
- catch (Exception) |
- { |
- Log.LogError("Failed to update " + readTrackerItem + " for " + sourcePath); |
- } |
- } |
- } |
- } |
- |
- private CanonicalTrackedOutputFiles OutputWriteTrackerLog(ITaskItem[] compiledSources) |
- { |
- string path = Path.Combine(TlogDirectory, WriteTLogFilename); |
- TaskItem item = new TaskItem(path); |
- CanonicalTrackedOutputFiles trackedFiles = new CanonicalTrackedOutputFiles(new TaskItem[] { item }); |
- |
- foreach (ITaskItem sourceItem in compiledSources) |
- { |
- //remove this entry associated with compiled source which is about to be recomputed |
- trackedFiles.RemoveEntriesForSource(sourceItem); |
- |
- //add entry with updated information |
- trackedFiles.AddComputedOutputForSourceRoot( Path.GetFullPath(sourceItem.ItemSpec).ToUpperInvariant(), |
- Path.GetFullPath(sourceItem.GetMetadata("ObjectFileName")).ToUpperInvariant()); |
- } |
- |
- //output tlog |
- trackedFiles.SaveTlog(); |
- |
- return trackedFiles; |
- } |
- |
- private void OutputCommandTrackerLog(ITaskItem[] compiledSources) |
- { |
- IDictionary<string, string> commandLines = GenerateCommandLinesFromTlog(); |
- |
- // |
- if (compiledSources != null) |
- { |
- foreach (ITaskItem source in compiledSources) |
- { |
- string rmSource = FileTracker.FormatRootingMarker(source); |
- commandLines[rmSource] = GenerateCommandLineFromProps(source) + " " + source.GetMetadata("FullPath").ToUpperInvariant(); |
- } |
- } |
- |
- //write tlog |
- using (StreamWriter writer = new StreamWriter(this.TLogCommandFile.GetMetadata("FullPath"), false, Encoding.Unicode)) |
- { |
- foreach (KeyValuePair<string, string> p in commandLines) |
- { |
- string keyLine = "^" + p.Key; |
- writer.WriteLine(keyLine); |
- writer.WriteLine(p.Value); |
- } |
- } |
- } |
- |
- protected string GenerateCommandLineFromProps(ITaskItem sourceFile) |
- { |
- StringBuilder commandLine = new StringBuilder(GCCUtilities.s_CommandLineLength); |
- |
- if (sourceFile != null) |
- { |
- string sourcePath = GCCUtilities.Convert_Path_Windows_To_Posix(sourceFile.ToString()); |
- |
- // Remove rtti items as they are not relevant in C compilation and will produce warnings |
- if (SourceIsC(sourceFile.ToString())) |
- { |
- commandLine.Replace("-fno-rtti", ""); |
- commandLine.Replace("-frtti", ""); |
- } |
- |
- //build command line from components and add required switches |
- string props = m_XamlParser.Parse(sourceFile); |
- commandLine.Append(props); |
- commandLine.Append(" -MD -c "); |
- commandLine.Append(sourcePath); |
- |
- } |
- |
- return commandLine.ToString(); |
- } |
- |
- protected ITaskItem[] MergeOutOfDateSources(ITaskItem[] outOfDateSourcesFromTracking, List<ITaskItem> outOfDateSourcesFromCommandLineChanges) |
- { |
- List<ITaskItem> mergedSources = new List<ITaskItem>(outOfDateSourcesFromTracking); |
- |
- foreach (ITaskItem item in outOfDateSourcesFromCommandLineChanges) |
- { |
- if (!mergedSources.Contains(item)) |
- { |
- mergedSources.Add(item); |
- } |
- } |
- |
- return mergedSources.ToArray(); |
- } |
- |
- protected bool ForcedRebuildRequired() |
- { |
- string tlogCommandPath = null; |
- |
- try |
- { |
- tlogCommandPath = this.TLogCommandFile.GetMetadata("FullPath"); |
- } |
- catch (Exception exception) |
- { |
- if (exception is InvalidOperationException || exception is NullReferenceException) |
- return true; |
- else |
- throw; |
- } |
- |
- //if command tlog file does not exist then force rebuild is required |
- if (File.Exists(tlogCommandPath) == false) |
- { |
- return true; |
- } |
- else |
- { |
- return false; |
- } |
- } |
- |
- private int Compile(string pathToTool) |
- { |
- int returnCode = 0; |
- |
- foreach (ITaskItem sourceFileItem in CompileSourceList) |
- { |
- try |
- { |
- string commandLine = GenerateCommandLineFromProps(sourceFileItem); |
- |
- base.Log.LogMessageFromText(Path.GetFileName(sourceFileItem.ToString()), MessageImportance.High); |
- |
- if (OutputCommandLine == "true") |
- { |
- string logMessage = pathToTool + " " + commandLine; |
- Log.LogMessageFromText(logMessage, MessageImportance.High); |
- } |
- |
- |
- // compile |
- returnCode = base.ExecuteTool(pathToTool, commandLine, string.Empty); |
- } |
- catch (Exception) |
- { |
- returnCode = base.ExitCode; |
- } |
- |
- //abort if an error was encountered |
- if (returnCode != 0) |
- { |
- return returnCode; |
- } |
- } |
- return returnCode; |
- } |
- |
- protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands) |
- { |
- if (File.Exists(pathToTool) == false) |
- { |
- base.Log.LogMessageFromText("Unable to find NaCL compiler: " + pathToTool, MessageImportance.High); |
- return -1; |
- } |
- |
- int returnCode = -1; |
- |
- try |
- { |
- returnCode = Compile(pathToTool); |
- } |
- finally |
- { |
- |
- } |
- return returnCode; |
- } |
- |
- protected override bool SkipTaskExecution() |
- { |
- return this.skippedExecution; |
- } |
- |
- protected void CalcSourcesToCompile() |
- { |
- if (this.TrackFileAccess || this.MinimalRebuildFromTracking) |
- { |
- this.SetTrackerLogPaths(); |
- } |
- |
- //check if full recompile is required otherwise perform incremental |
- if (this.ForcedRebuildRequired() || this.MinimalRebuildFromTracking == false) |
- { |
- this.CompileSourceList = this.Sources; |
- if ((this.CompileSourceList == null) || (this.CompileSourceList.Length == 0)) |
- { |
- this.SkippedExecution = true; |
- } |
- } |
- else |
- { |
- //retrieve list of sources out of date due to command line changes |
- List<ITaskItem> outOfDateSourcesFromCommandLineChanges = this.GetOutOfDateSourcesFromCommandLineChanges(); |
- |
- //retrieve sources out of date due to tracking |
- CanonicalTrackedOutputFiles trackedOutputFiles = new CanonicalTrackedOutputFiles(this, this.TLogWriteFiles); |
- this.TrackedInputFiles = new CanonicalTrackedInputFiles(this, this.TLogReadFiles, this.Sources, this.ExcludedInputPaths, trackedOutputFiles, true, false); |
- ITaskItem[] outOfDateSourcesFromTracking = this.TrackedInputFiles.ComputeSourcesNeedingCompilation(); |
- |
- //merge out of date lists |
- this.CompileSourceList = this.MergeOutOfDateSources(outOfDateSourcesFromTracking, outOfDateSourcesFromCommandLineChanges); |
- |
- if (this.CompileSourceList.Length == 0) |
- { |
- this.SkippedExecution = true; |
- } |
- else |
- { |
- //remove sources to compile from tracked file list |
- this.TrackedInputFiles.RemoveEntriesForSource(this.CompileSourceList); |
- trackedOutputFiles.RemoveEntriesForSource(this.CompileSourceList); |
- this.TrackedInputFiles.SaveTlog(); |
- trackedOutputFiles.SaveTlog(); |
- |
- this.SkippedExecution = false; |
- } |
- } |
- } |
- |
- protected bool SourceIsC(string sourceFilename) |
- { |
- string fileExt = Path.GetExtension(sourceFilename.ToString()); |
- |
- if (fileExt == ".c") |
- return true; |
- else |
- return false; |
- } |
- |
- public override bool Execute() |
- { |
- bool returnResult = false; |
- |
- try |
- { |
- m_XamlParser = new XamlParser(PropertiesFile); |
- m_toolname = Path.GetFileNameWithoutExtension(ToolName); |
- ValidateParameters(); |
- CalcSourcesToCompile(); |
- |
- returnResult = base.Execute(); |
- |
- // Update tracker log files if execution occurred |
- //if (this.skippedExecution == false) |
- { |
- CanonicalTrackedOutputFiles outputs = OutputWriteTrackerLog(CompileSourceList); |
- ConstructReadTLog(CompileSourceList, outputs); |
- OutputCommandTrackerLog(CompileSourceList); |
- } |
- } |
- finally |
- { |
- |
- } |
- |
- return returnResult; |
- } |
- |
- protected List<ITaskItem> GetOutOfDateSourcesFromCommandLineChanges() |
- { |
- //get dictionary of source + command lines |
- IDictionary<string, string> dictionary = this.GenerateCommandLinesFromTlog(); |
- List<ITaskItem> outOfDateSources = new List<ITaskItem>(); |
- |
- //add sources to out of date list if the tlog dictionary string do not match the generated command line string |
- StringBuilder currentCommandLine = new StringBuilder(GCCUtilities.s_CommandLineLength); |
- foreach (ITaskItem sourceItem in Sources) |
- { |
- currentCommandLine.Length = 0; |
- |
- currentCommandLine.Append(GenerateCommandLineFromProps(sourceItem)); |
- currentCommandLine.Append(" "); |
- currentCommandLine.Append(sourceItem.GetMetadata("FullPath").ToUpperInvariant()); |
- |
- string tlogCommandLine = null; |
- if (dictionary.TryGetValue(FileTracker.FormatRootingMarker(sourceItem), out tlogCommandLine)) |
- { |
- if ((tlogCommandLine == null) || !currentCommandLine.ToString().Equals(tlogCommandLine, StringComparison.Ordinal)) |
- { |
- outOfDateSources.Add(sourceItem); |
- } |
- } |
- else |
- { |
- outOfDateSources.Add(sourceItem); |
- } |
- } |
- return outOfDateSources; |
- } |
- |
- protected virtual void SetTrackerLogPaths() |
- { |
- if (this.TLogCommandFile == null) |
- { |
- string commandFile = Path.Combine(this.TlogDirectory, this.CommandTLogFilename); |
- this.TLogCommandFile = new TaskItem(commandFile); |
- } |
- |
- if (this.TLogReadFiles == null) |
- { |
- this.TLogReadFiles = new ITaskItem[this.ReadTLogFilenames.Length]; |
- for (int n = 0; n < this.ReadTLogFilenames.Length; n++) |
- { |
- string readFile = Path.Combine(this.TlogDirectory, this.ReadTLogFilenames[n]); |
- this.TLogReadFiles[n] = new TaskItem(readFile); |
- } |
- } |
- |
- if (this.TLogWriteFiles == null) |
- { |
- this.TLogWriteFiles = new ITaskItem[1]; |
- string writeFile = Path.Combine(this.TlogDirectory, this.WriteTLogFilename); |
- this.TLogWriteFiles[0] = new TaskItem(writeFile); |
- } |
- } |
- |
- |
- //props |
- protected string CommandTLogFilename |
- { |
- get |
- { |
- return m_toolname + ".compile.command.1.tlog"; |
- } |
- } |
- |
- protected string[] ReadTLogFilenames |
- { |
- get |
- { |
- return new string[] { m_toolname + ".compile.read.1.tlog" }; |
- } |
- } |
- |
- [Output] |
- public bool SkippedExecution |
- { |
- get |
- { |
- return this.skippedExecution; |
- } |
- set |
- { |
- this.skippedExecution = value; |
- } |
- } |
- |
- public ITaskItem TLogCommandFile |
- { |
- get |
- { |
- return this.tlogCommandFile; |
- } |
- set |
- { |
- this.tlogCommandFile = value; |
- } |
- } |
- |
- protected string TlogDirectory |
- { |
- get |
- { |
- if (this.TrackerLogDirectory != null) |
- { |
- return this.TrackerLogDirectory; |
- } |
- return string.Empty; |
- } |
- } |
- |
- public bool MinimalRebuildFromTracking |
- { |
- get |
- { |
- return this.minimalRebuildFromTracking; |
- } |
- set |
- { |
- this.minimalRebuildFromTracking = value; |
- } |
- } |
- |
- |
- public ITaskItem[] TLogReadFiles |
- { |
- get |
- { |
- return this.tlogReadFiles; |
- } |
- set |
- { |
- this.tlogReadFiles = value; |
- } |
- } |
- |
- public ITaskItem[] ExcludedInputPaths |
- { |
- get |
- { |
- return this.excludedInputPaths; |
- } |
- set |
- { |
- this.excludedInputPaths = value; |
- } |
- } |
- |
- |
- public ITaskItem[] TLogWriteFiles |
- { |
- get |
- { |
- return this.tlogWriteFiles; |
- } |
- set |
- { |
- this.tlogWriteFiles = value; |
- } |
- } |
- |
- protected string WriteTLogFilename |
- { |
- get |
- { |
- return m_toolname + ".compile.write.1.tlog"; |
- } |
- } |
- |
- public bool TrackFileAccess |
- { |
- get |
- { |
- return this.trackFileAccess; |
- } |
- set |
- { |
- this.trackFileAccess = value; |
- } |
- } |
- |
- protected CanonicalTrackedInputFiles TrackedInputFiles |
- { |
- get |
- { |
- return this.trackedInputFiles; |
- } |
- set |
- { |
- this.trackedInputFiles = value; |
- } |
- } |
- |
- [Output] |
- public ITaskItem[] CompileSourceList |
- { |
- get |
- { |
- return this.compileSourceList; |
- } |
- set |
- { |
- this.compileSourceList = value; |
- } |
- } |
- |
- protected override string ToolName |
- { |
- get |
- { |
- return NaCLCompilerPath; |
- } |
- } |
- |
- protected override Encoding ResponseFileEncoding |
- { |
- get |
- { |
- return Encoding.ASCII; |
- } |
- } |
- } |
+ |
+using System; |
+using System.Collections.Generic; |
+using System.Text; |
+using System.Collections; |
+using System.IO; |
+using System.Reflection; |
+using System.Resources; |
+using Microsoft.Build.Framework; |
+using Microsoft.Build.Utilities; |
+ |
+using System.Diagnostics; |
+ |
+namespace NaCl.Build.CPPTasks |
+{ |
+ public class NaClCompile : ToolTask |
+ { |
+ private XamlParser m_XamlParser; |
+ private ITaskItem[] excludedInputPaths; |
+ private ITaskItem[] tlogReadFiles; |
+ private ITaskItem tlogCommandFile; |
+ private ITaskItem[] tlogWriteFiles; |
+ private CanonicalTrackedInputFiles trackedInputFiles; |
+ private bool skippedExecution; |
+ private ITaskItem[] compileSourceList; |
+ public bool BuildingInIDE { get; set; } |
+ private string m_toolname; |
+ private bool trackFileAccess; |
+ private bool minimalRebuildFromTracking; |
+ private string pathToLog; |
+ |
+ [Required] |
+ public string PropertiesFile { get; set; } |
+ |
+ [Required] |
+ public ITaskItem[] Sources { get; set; } |
+ |
+ [Required] |
+ public string NaCLCompilerPath { get; set; } |
+ |
+ [Required] |
+ public string OutputCommandLine { get; set; } |
+ |
+ [Required] |
+ public string TrackerLogDirectory { get; set; } |
+ |
+ |
+ protected override string GenerateFullPathToTool() { return ToolName; } |
+ |
+ public NaClCompile() |
+ : base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly())) |
+ { |
+ this.pathToLog = string.Empty; |
+ this.EnvironmentVariables = new string []{"CYGWIN=nodosfilewarning", "LC_CTYPE=C"}; |
+ } |
+ |
+ protected IDictionary<string, string> GenerateCommandLinesFromTlog() |
+ { |
+ IDictionary<string, string> cmdLineDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); |
+ string tlogFilename = this.TLogCommandFile.GetMetadata("FullPath"); |
+ if (File.Exists(tlogFilename)) |
+ { |
+ using (StreamReader reader = File.OpenText(tlogFilename)) |
+ { |
+ string filename = string.Empty; |
+ for (string lineStr = reader.ReadLine(); lineStr != null; lineStr = reader.ReadLine()) |
+ { |
+ if (lineStr.Length == 0 || |
+ (lineStr[0] == '^' && lineStr.Length == 1)) |
+ { |
+ Log.LogMessage(MessageImportance.High, "Invalid line in command tlog"); |
+ break; |
+ } |
+ else if (lineStr[0] == '^') |
+ { |
+ filename = lineStr.Substring(1); |
+ } |
+ else |
+ { |
+ cmdLineDictionary[filename] = lineStr; |
+ } |
+ } |
+ } |
+ } |
+ return cmdLineDictionary; |
+ } |
+ |
+ protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance) |
+ { |
+ base.LogEventsFromTextOutput(GCCUtilities.Convert_Output_GCC_to_VS(singleLine), messageImportance); |
+ } |
+ |
+ private void ConstructReadTLog(ITaskItem[] compiledSources, CanonicalTrackedOutputFiles outputs) |
+ { |
+ string trackerPath = Path.GetFullPath(TlogDirectory + ReadTLogFilenames[0]); |
+ |
+ //save tlog for sources not compiled during this execution |
+ TaskItem readTrackerItem = new TaskItem(trackerPath); |
+ CanonicalTrackedInputFiles files = new CanonicalTrackedInputFiles(new TaskItem[] { readTrackerItem }, Sources, outputs, false, false); |
+ files.RemoveEntriesForSource(compiledSources); |
+ files.SaveTlog(); |
+ |
+ //add tlog information for compiled sources |
+ using (StreamWriter writer = new StreamWriter(trackerPath, true, Encoding.Unicode)) |
+ { |
+ foreach (ITaskItem source in compiledSources) |
+ { |
+ string sourcePath = Path.GetFullPath(source.ItemSpec).ToUpperInvariant(); |
+ |
+ string objectFilePath = Path.GetFullPath(source.GetMetadata("ObjectFileName")); |
+ string depFilePath = Path.ChangeExtension(objectFilePath, ".d"); |
+ |
+ try |
+ { |
+ if (File.Exists(depFilePath) == false) |
+ { |
+ Log.LogMessage(MessageImportance.High, depFilePath + " not found"); |
+ } |
+ else |
+ { |
+ writer.WriteLine("^" + sourcePath); |
+ DependencyParser parser = new DependencyParser(depFilePath); |
+ |
+ foreach (string filename in parser.Dependencies) |
+ { |
+ //source itself not required |
+ if (filename == sourcePath) |
+ continue; |
+ |
+ if (File.Exists(filename) == false) |
+ { |
+ Log.LogMessage(MessageImportance.High, "File " + sourcePath + " is missing dependency " + filename); |
+ } |
+ |
+ writer.WriteLine(filename); |
+ } |
+ |
+ //remove d file |
+ try |
+ { |
+ File.Delete(depFilePath); |
+ } |
+ finally |
+ { |
+ |
+ } |
+ } |
+ |
+ } |
+ catch (Exception) |
+ { |
+ Log.LogError("Failed to update " + readTrackerItem + " for " + sourcePath); |
+ } |
+ } |
+ } |
+ } |
+ |
+ private CanonicalTrackedOutputFiles OutputWriteTrackerLog(ITaskItem[] compiledSources) |
+ { |
+ string path = Path.Combine(TlogDirectory, WriteTLogFilename); |
+ TaskItem item = new TaskItem(path); |
+ CanonicalTrackedOutputFiles trackedFiles = new CanonicalTrackedOutputFiles(new TaskItem[] { item }); |
+ |
+ foreach (ITaskItem sourceItem in compiledSources) |
+ { |
+ //remove this entry associated with compiled source which is about to be recomputed |
+ trackedFiles.RemoveEntriesForSource(sourceItem); |
+ |
+ //add entry with updated information |
+ trackedFiles.AddComputedOutputForSourceRoot( Path.GetFullPath(sourceItem.ItemSpec).ToUpperInvariant(), |
+ Path.GetFullPath(sourceItem.GetMetadata("ObjectFileName")).ToUpperInvariant()); |
+ } |
+ |
+ //output tlog |
+ trackedFiles.SaveTlog(); |
+ |
+ return trackedFiles; |
+ } |
+ |
+ private void OutputCommandTrackerLog(ITaskItem[] compiledSources) |
+ { |
+ IDictionary<string, string> commandLines = GenerateCommandLinesFromTlog(); |
+ |
+ // |
+ if (compiledSources != null) |
+ { |
+ foreach (ITaskItem source in compiledSources) |
+ { |
+ string rmSource = FileTracker.FormatRootingMarker(source); |
+ commandLines[rmSource] = GenerateCommandLineFromProps(source) + " " + source.GetMetadata("FullPath").ToUpperInvariant(); |
+ } |
+ } |
+ |
+ //write tlog |
+ using (StreamWriter writer = new StreamWriter(this.TLogCommandFile.GetMetadata("FullPath"), false, Encoding.Unicode)) |
+ { |
+ foreach (KeyValuePair<string, string> p in commandLines) |
+ { |
+ string keyLine = "^" + p.Key; |
+ writer.WriteLine(keyLine); |
+ writer.WriteLine(p.Value); |
+ } |
+ } |
+ } |
+ |
+ protected string GenerateCommandLineFromProps(ITaskItem sourceFile) |
+ { |
+ StringBuilder commandLine = new StringBuilder(GCCUtilities.s_CommandLineLength); |
+ |
+ if (sourceFile != null) |
+ { |
+ string sourcePath = GCCUtilities.Convert_Path_Windows_To_Posix(sourceFile.ToString()); |
+ |
+ // Remove rtti items as they are not relevant in C compilation and will produce warnings |
+ if (SourceIsC(sourceFile.ToString())) |
+ { |
+ commandLine.Replace("-fno-rtti", ""); |
+ commandLine.Replace("-frtti", ""); |
+ } |
+ |
+ //build command line from components and add required switches |
+ string props = m_XamlParser.Parse(sourceFile); |
+ commandLine.Append(props); |
+ commandLine.Append(" -MD -c "); |
+ commandLine.Append(sourcePath); |
+ |
+ } |
+ |
+ return commandLine.ToString(); |
+ } |
+ |
+ protected ITaskItem[] MergeOutOfDateSources(ITaskItem[] outOfDateSourcesFromTracking, List<ITaskItem> outOfDateSourcesFromCommandLineChanges) |
+ { |
+ List<ITaskItem> mergedSources = new List<ITaskItem>(outOfDateSourcesFromTracking); |
+ |
+ foreach (ITaskItem item in outOfDateSourcesFromCommandLineChanges) |
+ { |
+ if (!mergedSources.Contains(item)) |
+ { |
+ mergedSources.Add(item); |
+ } |
+ } |
+ |
+ return mergedSources.ToArray(); |
+ } |
+ |
+ protected bool ForcedRebuildRequired() |
+ { |
+ string tlogCommandPath = null; |
+ |
+ try |
+ { |
+ tlogCommandPath = this.TLogCommandFile.GetMetadata("FullPath"); |
+ } |
+ catch (Exception exception) |
+ { |
+ if (exception is InvalidOperationException || exception is NullReferenceException) |
+ return true; |
+ else |
+ throw; |
+ } |
+ |
+ //if command tlog file does not exist then force rebuild is required |
+ if (File.Exists(tlogCommandPath) == false) |
+ { |
+ return true; |
+ } |
+ else |
+ { |
+ return false; |
+ } |
+ } |
+ |
+ private int Compile(string pathToTool) |
+ { |
+ int returnCode = 0; |
+ |
+ foreach (ITaskItem sourceFileItem in CompileSourceList) |
+ { |
+ try |
+ { |
+ string commandLine = GenerateCommandLineFromProps(sourceFileItem); |
+ |
+ base.Log.LogMessageFromText(Path.GetFileName(sourceFileItem.ToString()), MessageImportance.High); |
+ |
+ if (OutputCommandLine == "true") |
+ { |
+ string logMessage = pathToTool + " " + commandLine; |
+ Log.LogMessageFromText(logMessage, MessageImportance.High); |
+ } |
+ |
+ |
+ // compile |
+ returnCode = base.ExecuteTool(pathToTool, commandLine, string.Empty); |
+ } |
+ catch (Exception) |
+ { |
+ returnCode = base.ExitCode; |
+ } |
+ |
+ //abort if an error was encountered |
+ if (returnCode != 0) |
+ { |
+ return returnCode; |
+ } |
+ } |
+ return returnCode; |
+ } |
+ |
+ protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands) |
+ { |
+ if (File.Exists(pathToTool) == false) |
+ { |
+ base.Log.LogMessageFromText("Unable to find NaCL compiler: " + pathToTool, MessageImportance.High); |
+ return -1; |
+ } |
+ |
+ int returnCode = -1; |
+ |
+ try |
+ { |
+ returnCode = Compile(pathToTool); |
+ } |
+ finally |
+ { |
+ |
+ } |
+ return returnCode; |
+ } |
+ |
+ protected override bool SkipTaskExecution() |
+ { |
+ return this.skippedExecution; |
+ } |
+ |
+ protected void CalcSourcesToCompile() |
+ { |
+ if (this.TrackFileAccess || this.MinimalRebuildFromTracking) |
+ { |
+ this.SetTrackerLogPaths(); |
+ } |
+ |
+ //check if full recompile is required otherwise perform incremental |
+ if (this.ForcedRebuildRequired() || this.MinimalRebuildFromTracking == false) |
+ { |
+ this.CompileSourceList = this.Sources; |
+ if ((this.CompileSourceList == null) || (this.CompileSourceList.Length == 0)) |
+ { |
+ this.SkippedExecution = true; |
+ } |
+ } |
+ else |
+ { |
+ //retrieve list of sources out of date due to command line changes |
+ List<ITaskItem> outOfDateSourcesFromCommandLineChanges = this.GetOutOfDateSourcesFromCommandLineChanges(); |
+ |
+ //retrieve sources out of date due to tracking |
+ CanonicalTrackedOutputFiles trackedOutputFiles = new CanonicalTrackedOutputFiles(this, this.TLogWriteFiles); |
+ this.TrackedInputFiles = new CanonicalTrackedInputFiles(this, this.TLogReadFiles, this.Sources, this.ExcludedInputPaths, trackedOutputFiles, true, false); |
+ ITaskItem[] outOfDateSourcesFromTracking = this.TrackedInputFiles.ComputeSourcesNeedingCompilation(); |
+ |
+ //merge out of date lists |
+ this.CompileSourceList = this.MergeOutOfDateSources(outOfDateSourcesFromTracking, outOfDateSourcesFromCommandLineChanges); |
+ |
+ if (this.CompileSourceList.Length == 0) |
+ { |
+ this.SkippedExecution = true; |
+ } |
+ else |
+ { |
+ //remove sources to compile from tracked file list |
+ this.TrackedInputFiles.RemoveEntriesForSource(this.CompileSourceList); |
+ trackedOutputFiles.RemoveEntriesForSource(this.CompileSourceList); |
+ this.TrackedInputFiles.SaveTlog(); |
+ trackedOutputFiles.SaveTlog(); |
+ |
+ this.SkippedExecution = false; |
+ } |
+ } |
+ } |
+ |
+ protected bool SourceIsC(string sourceFilename) |
+ { |
+ string fileExt = Path.GetExtension(sourceFilename.ToString()); |
+ |
+ if (fileExt == ".c") |
+ return true; |
+ else |
+ return false; |
+ } |
+ |
+ public override bool Execute() |
+ { |
+ bool returnResult = false; |
+ |
+ try |
+ { |
+ m_XamlParser = new XamlParser(PropertiesFile); |
+ m_toolname = Path.GetFileNameWithoutExtension(ToolName); |
+ ValidateParameters(); |
+ CalcSourcesToCompile(); |
+ |
+ returnResult = base.Execute(); |
+ |
+ // Update tracker log files if execution occurred |
+ //if (this.skippedExecution == false) |
+ { |
+ CanonicalTrackedOutputFiles outputs = OutputWriteTrackerLog(CompileSourceList); |
+ ConstructReadTLog(CompileSourceList, outputs); |
+ OutputCommandTrackerLog(CompileSourceList); |
+ } |
+ } |
+ finally |
+ { |
+ |
+ } |
+ |
+ return returnResult; |
+ } |
+ |
+ protected List<ITaskItem> GetOutOfDateSourcesFromCommandLineChanges() |
+ { |
+ //get dictionary of source + command lines |
+ IDictionary<string, string> dictionary = this.GenerateCommandLinesFromTlog(); |
+ List<ITaskItem> outOfDateSources = new List<ITaskItem>(); |
+ |
+ //add sources to out of date list if the tlog dictionary string do not match the generated command line string |
+ StringBuilder currentCommandLine = new StringBuilder(GCCUtilities.s_CommandLineLength); |
+ foreach (ITaskItem sourceItem in Sources) |
+ { |
+ currentCommandLine.Length = 0; |
+ |
+ currentCommandLine.Append(GenerateCommandLineFromProps(sourceItem)); |
+ currentCommandLine.Append(" "); |
+ currentCommandLine.Append(sourceItem.GetMetadata("FullPath").ToUpperInvariant()); |
+ |
+ string tlogCommandLine = null; |
+ if (dictionary.TryGetValue(FileTracker.FormatRootingMarker(sourceItem), out tlogCommandLine)) |
+ { |
+ if ((tlogCommandLine == null) || !currentCommandLine.ToString().Equals(tlogCommandLine, StringComparison.Ordinal)) |
+ { |
+ outOfDateSources.Add(sourceItem); |
+ } |
+ } |
+ else |
+ { |
+ outOfDateSources.Add(sourceItem); |
+ } |
+ } |
+ return outOfDateSources; |
+ } |
+ |
+ protected virtual void SetTrackerLogPaths() |
+ { |
+ if (this.TLogCommandFile == null) |
+ { |
+ string commandFile = Path.Combine(this.TlogDirectory, this.CommandTLogFilename); |
+ this.TLogCommandFile = new TaskItem(commandFile); |
+ } |
+ |
+ if (this.TLogReadFiles == null) |
+ { |
+ this.TLogReadFiles = new ITaskItem[this.ReadTLogFilenames.Length]; |
+ for (int n = 0; n < this.ReadTLogFilenames.Length; n++) |
+ { |
+ string readFile = Path.Combine(this.TlogDirectory, this.ReadTLogFilenames[n]); |
+ this.TLogReadFiles[n] = new TaskItem(readFile); |
+ } |
+ } |
+ |
+ if (this.TLogWriteFiles == null) |
+ { |
+ this.TLogWriteFiles = new ITaskItem[1]; |
+ string writeFile = Path.Combine(this.TlogDirectory, this.WriteTLogFilename); |
+ this.TLogWriteFiles[0] = new TaskItem(writeFile); |
+ } |
+ } |
+ |
+ |
+ //props |
+ protected string CommandTLogFilename |
+ { |
+ get |
+ { |
+ return m_toolname + ".compile.command.1.tlog"; |
+ } |
+ } |
+ |
+ protected string[] ReadTLogFilenames |
+ { |
+ get |
+ { |
+ return new string[] { m_toolname + ".compile.read.1.tlog" }; |
+ } |
+ } |
+ |
+ [Output] |
+ public bool SkippedExecution |
+ { |
+ get |
+ { |
+ return this.skippedExecution; |
+ } |
+ set |
+ { |
+ this.skippedExecution = value; |
+ } |
+ } |
+ |
+ public ITaskItem TLogCommandFile |
+ { |
+ get |
+ { |
+ return this.tlogCommandFile; |
+ } |
+ set |
+ { |
+ this.tlogCommandFile = value; |
+ } |
+ } |
+ |
+ protected string TlogDirectory |
+ { |
+ get |
+ { |
+ if (this.TrackerLogDirectory != null) |
+ { |
+ return this.TrackerLogDirectory; |
+ } |
+ return string.Empty; |
+ } |
+ } |
+ |
+ public bool MinimalRebuildFromTracking |
+ { |
+ get |
+ { |
+ return this.minimalRebuildFromTracking; |
+ } |
+ set |
+ { |
+ this.minimalRebuildFromTracking = value; |
+ } |
+ } |
+ |
+ |
+ public ITaskItem[] TLogReadFiles |
+ { |
+ get |
+ { |
+ return this.tlogReadFiles; |
+ } |
+ set |
+ { |
+ this.tlogReadFiles = value; |
+ } |
+ } |
+ |
+ public ITaskItem[] ExcludedInputPaths |
+ { |
+ get |
+ { |
+ return this.excludedInputPaths; |
+ } |
+ set |
+ { |
+ this.excludedInputPaths = value; |
+ } |
+ } |
+ |
+ |
+ public ITaskItem[] TLogWriteFiles |
+ { |
+ get |
+ { |
+ return this.tlogWriteFiles; |
+ } |
+ set |
+ { |
+ this.tlogWriteFiles = value; |
+ } |
+ } |
+ |
+ protected string WriteTLogFilename |
+ { |
+ get |
+ { |
+ return m_toolname + ".compile.write.1.tlog"; |
+ } |
+ } |
+ |
+ public bool TrackFileAccess |
+ { |
+ get |
+ { |
+ return this.trackFileAccess; |
+ } |
+ set |
+ { |
+ this.trackFileAccess = value; |
+ } |
+ } |
+ |
+ protected CanonicalTrackedInputFiles TrackedInputFiles |
+ { |
+ get |
+ { |
+ return this.trackedInputFiles; |
+ } |
+ set |
+ { |
+ this.trackedInputFiles = value; |
+ } |
+ } |
+ |
+ [Output] |
+ public ITaskItem[] CompileSourceList |
+ { |
+ get |
+ { |
+ return this.compileSourceList; |
+ } |
+ set |
+ { |
+ this.compileSourceList = value; |
+ } |
+ } |
+ |
+ protected override string ToolName |
+ { |
+ get |
+ { |
+ return NaCLCompilerPath; |
+ } |
+ } |
+ |
+ protected override Encoding ResponseFileEncoding |
+ { |
+ get |
+ { |
+ return Encoding.ASCII; |
+ } |
+ } |
+ } |
} |