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