blob: ab5e413917a6124665859c483044c59feb6a2b67 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Windows.Forms;
using Microsoft.Build.Framework;
using Microsoft.Win32;
using Microsoft.Build.Utilities;
using System.Collections.Specialized;
using System.Diagnostics;
namespace NaCl.Build.CPPTasks
{
public abstract class NaClToolTask : ToolTask
{
protected NaClToolTask(ResourceManager taskResources) : base(taskResources) { }
public bool BuildingInIDE { get; set; }
protected ITaskItem[] excludedInputPaths;
private ITaskItem[] tlogReadFiles;
private ITaskItem tlogCommandFile;
private ITaskItem[] tlogWriteFiles;
private CanonicalTrackedInputFiles trackedInputFiles;
private bool skippedExecution;
private bool minimalRebuildFromTracking;
private bool trackFileAccess;
protected ITaskItem[] compileSourceList;
protected XamlParser xamlParser;
[Required]
public string TrackerLogDirectory { get; set; }
[Required]
public virtual ITaskItem[] Sources { get; set; }
[Required]
public bool OutputCommandLine { get; set; }
[Required]
public string Platform { get; set; }
public virtual string OutputFile { get; set; }
// Override default StandardOutputLoggingImportance so that we see the stdout from the
// toolchain from within visual studio.
protected override MessageImportance StandardOutputLoggingImportance
{
get { return MessageImportance.Normal; }
}
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;
}
}
protected override bool SkipTaskExecution()
{
return this.skippedExecution;
}
protected string BaseTool()
{
return Path.GetFileNameWithoutExtension(ToolName);
}
protected bool IsPNaCl()
{
return Platform.Equals("pnacl", StringComparison.OrdinalIgnoreCase);
}
protected bool Setup()
{
this.SkippedExecution = false;
if (!ValidateParameters())
{
return false;
}
if (IsPNaCl())
{
if (!SDKUtilities.FindPython())
{
Log.LogError("PNaCl linking requires python in your executable path.");
return false;
}
}
if (this.TrackFileAccess || this.MinimalRebuildFromTracking)
{
this.SetTrackerLogPaths();
}
if (this.ForcedRebuildRequired() || this.MinimalRebuildFromTracking == false)
{
if (this.Sources == null || this.Sources.Length == 0)
{
this.SkippedExecution = true;
}
}
return true;
}
protected virtual CanonicalTrackedOutputFiles OutputWriteTLog(ITaskItem[] inputs)
{
string path = Path.Combine(TlogDirectory, WriteTLogFilename);
TaskItem item = new TaskItem(path);
CanonicalTrackedOutputFiles trackedFiles =
new CanonicalTrackedOutputFiles(new TaskItem[] { item });
foreach (ITaskItem sourceItem in Sources)
{
//remove this entry associated with compiled source which is about to be recomputed
trackedFiles.RemoveEntriesForSource(sourceItem);
//add entry with updated information
string upper = Path.GetFullPath(sourceItem.ItemSpec).ToUpperInvariant();
trackedFiles.AddComputedOutputForSourceRoot(upper, OutputFile);
}
//output tlog
trackedFiles.SaveTlog();
return trackedFiles;
}
protected virtual void OutputReadTLog(ITaskItem[] compiledSources,
CanonicalTrackedOutputFiles outputs)
{
string trackerPath = Path.GetFullPath(TlogDirectory + ReadTLogFilenames[0]);
using (var writer = new StreamWriter(trackerPath, false, Encoding.Unicode))
{
string sourcePath = "";
foreach (ITaskItem source in Sources)
{
if (sourcePath != "")
sourcePath += "|";
sourcePath += Path.GetFullPath(source.ItemSpec).ToUpperInvariant();
}
writer.WriteLine("^" + sourcePath);
foreach (ITaskItem source in Sources)
{
writer.WriteLine(Path.GetFullPath(source.ItemSpec).ToUpperInvariant());
}
writer.WriteLine(Path.GetFullPath(OutputFile).ToUpperInvariant());
}
}
protected virtual void OutputCommandTLog(ITaskItem[] compiledSources)
{
string fullpath = TLogCommandFile.GetMetadata("FullPath");
using (var writer = new StreamWriter(fullpath, false, Encoding.Unicode))
{
string cmds = GenerateResponseFileCommands();
string sourcePath = "";
foreach (ITaskItem source in Sources)
{
if (sourcePath != "")
sourcePath += "|";
sourcePath += Path.GetFullPath(source.ItemSpec).ToUpperInvariant();
}
writer.WriteLine("^" + sourcePath);
writer.WriteLine(cmds);
}
}
public override bool Execute()
{
bool returnResult = base.Execute();
// Update tracker log files if execution occurred
//if (this.skippedExecution == false)
{
CanonicalTrackedOutputFiles outputs = OutputWriteTLog(compileSourceList);
OutputReadTLog(compileSourceList, outputs);
OutputCommandTLog(compileSourceList);
}
return returnResult;
}
protected override Encoding ResponseFileEncoding
{
get
{
return Encoding.ASCII;
}
}
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);
}
}
[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[] TLogWriteFiles
{
get
{
return this.tlogWriteFiles;
}
set
{
this.tlogWriteFiles = value;
}
}
public bool TrackFileAccess
{
get
{
return this.trackFileAccess;
}
set
{
this.trackFileAccess = value;
}
}
protected CanonicalTrackedInputFiles TrackedInputFiles
{
get
{
return this.trackedInputFiles;
}
set
{
this.trackedInputFiles = value;
}
}
public ITaskItem[] ExcludedInputPaths
{
get
{
return this.excludedInputPaths;
}
set
{
this.excludedInputPaths = value;
}
}
protected virtual string CommandTLogFilename
{
get
{
return BaseTool() + ".compile.command.1.tlog";
}
}
protected virtual string[] ReadTLogFilenames
{
get
{
return new string[] { BaseTool() + ".compile.read.1.tlog" };
}
}
protected virtual string WriteTLogFilename
{
get
{
return BaseTool() + ".compile.write.1.tlog";
}
}
public virtual string PlatformToolset
{
get
{
return "GCC";
}
}
protected override string GenerateFullPathToTool()
{
return this.ToolName;
}
}
}