blob: 0fe8cf1e28b93eb94c089b4777e195ea189f9860 [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.IO;
using System.Resources;
using System.Reflection;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.CPPTasks;
using Microsoft.Build.Utilities;
namespace NaCl.Build.CPPTasks
{
public class NaClLink : NaClToolTask
{
/// <summary>
/// Property set only in PNaCl builds to signal that the translator
/// should be run post-link.
/// </summary>
public bool TranslateARM { get; set; }
/// <summary>
/// Property set only in PNaCl builds to signal that the translator
/// should be run post-link.
/// </summary>
public bool TranslateX86 { get; set; }
/// <summary>
/// Property set only in PNaCl builds to signal that the translator
/// should be run post-link.
/// </summary>
public bool TranslateX64 { get; set; }
[Required]
public bool CreateNMF { get; set; }
[Required]
public string NaClLinkerPath { get; set; }
[Required]
public string ProjectName { get; set; }
[Required]
public string ToolchainName { get; set; }
[Required]
public string CreateNMFPath { get; set; }
[Required]
public string PropertiesFile { get; set; }
[Required]
public string ConfigurationType { get; set; }
public NaClLink()
: base(new ResourceManager("NaCl.Build.CPPTasks.Properties.Resources", Assembly.GetExecutingAssembly()))
{
this.EnvironmentVariables = new string[] { "CYGWIN=nodosfilewarning", "LC_CTYPE=C" };
}
protected override void LogEventsFromTextOutput(string singleLine, MessageImportance messageImportance)
{
base.LogEventsFromTextOutput(GCCUtilities.ConvertGCCOutput(singleLine), messageImportance);
}
protected override string GenerateResponseFileCommands()
{
StringBuilder responseFileCmds = new StringBuilder(GCCUtilities.s_CommandLineLength);
// We want GCC to behave more like visual studio in term of library dependencies
// so we wrap all the inputs (libraries and object) into one group so they are
// searched iteratively.
responseFileCmds.Append("-Wl,--start-group ");
foreach (ITaskItem sourceFile in Sources)
{
responseFileCmds.Append(GCCUtilities.ConvertPathWindowsToPosix(sourceFile.GetMetadata("Identity")));
responseFileCmds.Append(" ");
}
responseFileCmds.Append("-Wl,--end-group ");
responseFileCmds.Append(xamlParser.Parse(Sources[0], false));
return responseFileCmds.ToString();
}
private static string PexeToNexe(string pexe, string arch)
{
string basename = Path.GetFileNameWithoutExtension(pexe) + "_" + arch + ".nexe";
return Path.Combine(Path.GetDirectoryName(pexe), basename);
}
private bool Translate(string arch, string pnacl_arch=null)
{
if (pnacl_arch == null)
pnacl_arch = arch;
string outfile = PexeToNexe(OutputFile, arch);
string cmd = String.Format("-arch {0} \"{1}\" -o \"{2}\"",
pnacl_arch, OutputFile, outfile);
string dirname = Path.GetDirectoryName(GenerateFullPathToTool());
string translateTool = Path.Combine(dirname, "pnacl-translate.bat");
if (!OutputCommandLine)
Log.LogMessage("pnacl-translate -> {0}", Path.GetFileName(outfile));
if (ExecuteTool(translateTool, cmd, string.Empty) != 0)
{
return false;
}
return true;
}
public override bool Execute()
{
xamlParser = new XamlParser(PropertiesFile);
if (!Setup())
return false;
if (!OutputCommandLine)
Log.LogMessage("Linking: {0}", Path.GetFileName(OutputFile));
if (!base.Execute())
return false;
if (!PostLink())
return false;
return true;
}
protected bool PostLink()
{
if (IsPNaCl())
{
if (TranslateX64 && !Translate("64", "x86-64"))
return false;
if (TranslateX86 && !Translate("32", "i686"))
return false;
if (TranslateARM && !Translate("arm"))
return false;
}
if (CreateNMF)
{
if (!SDKUtilities.FindPython())
{
Log.LogError("Automatic NMF creation requires python in your executable path.");
return false;
}
string outputRoot = ToolchainName;
if (IsPNaCl())
outputRoot = "PNaCl";
if (!Directory.Exists(outputRoot))
Directory.CreateDirectory(outputRoot);
string nmfPath = Path.Combine(outputRoot, Path.ChangeExtension(ProjectName, ".nmf"));
string cmd = "\"" + CreateNMFPath + "\" -o \"" + nmfPath + "\"";
// The SDK root is one level up from create_nmf.py
// Starting with 25.170267 the -t options to create_nmf is deprecated.
string sdkroot = Path.GetDirectoryName(Path.GetDirectoryName(CreateNMFPath));
if (!SDKUtilities.CheckVersionAtLeast(sdkroot, 25, 170267))
cmd += " -t " + ToolchainName;
cmd += " -s " + ToolchainName;
if (IsPNaCl())
{
if (!TranslateARM && !TranslateX64 && !TranslateX86)
// Don't run create_nmf unless we actaully produced a nexe file.
return true;
foreach (var arch in new string []{ "arm", "32", "64" })
{
string nexe = PexeToNexe(OutputFile, arch);
if (File.Exists(nexe))
cmd += " \"" + nexe + "\"";
}
}
else
{
if (ToolchainName == "glibc")
{
string bindir = Path.GetDirectoryName(NaClLinkerPath);
string tcroot = Path.GetDirectoryName(bindir);
cmd += " -D \"" + Path.Combine(bindir, "x86_64-nacl-objdump.exe") + "\"";
cmd += " -L \"" + Path.Combine(tcroot, "x86_64-nacl", "lib") + "\"";
cmd += " -L \"" + Path.Combine(tcroot, "x86_64-nacl", "lib32") + "\"";
}
cmd += " \"" + OutputFile + "\"";
}
if (!OutputCommandLine)
Log.LogMessage("CreateNMF -> {0}", Path.GetFileName(nmfPath));
if (ExecuteTool("python", string.Empty, cmd) != 0)
{
return false;
}
}
return true;
}
protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
{
if (OutputCommandLine)
{
Log.LogMessage(MessageImportance.High, pathToTool + " " + responseFileCommands + " " + commandLineCommands);
}
return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
}
protected override Encoding ResponseFileEncoding
{
get
{
return Encoding.ASCII;
}
}
protected override string ToolName
{
get
{
return NaClLinkerPath;
}
}
protected override string CommandTLogFilename
{
get
{
return BaseTool() + ".link.command.1.tlog";
}
}
protected override string[] ReadTLogFilenames
{
get
{
return new string[] { BaseTool() + ".link.read.1.tlog" };
}
}
protected override string WriteTLogFilename
{
get
{
return BaseTool() + ".link.write.1.tlog";
}
}
}
}