2016-07-26 00:29:59 -04:00
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System ;
2017-11-01 17:17:22 -07:00
using System.Diagnostics ;
2016-07-26 00:29:59 -04:00
using System.IO ;
2017-11-01 17:17:22 -07:00
using System.Runtime.InteropServices ;
2016-07-26 00:29:59 -04:00
using Microsoft.Build.Framework ;
using Microsoft.Build.Utilities ;
namespace Microsoft.DotNet.Build.Tasks
{
public sealed class Crossgen : ToolTask
{
[Required]
public string SourceAssembly { get ; set ; }
[Required]
public string DestinationPath { get ; set ; }
[Required]
public string JITPath { get ; set ; }
public string CrossgenPath { get ; set ; }
2017-11-01 17:17:22 -07:00
public bool CreateSymbols { get ; set ; }
public string DiasymReaderPath { get ; set ; }
2016-07-26 00:29:59 -04:00
public bool ReadyToRun { get ; set ; }
public ITaskItem [ ] PlatformAssemblyPaths { get ; set ; }
private string TempOutputPath { get ; set ; }
2017-11-01 17:17:22 -07:00
private bool _secondInvocationToCreateSymbols ;
2016-07-26 00:29:59 -04:00
protected override bool ValidateParameters ( )
{
base . ValidateParameters ( ) ;
if ( ! File . Exists ( SourceAssembly ) )
{
Log . LogError ( $"SourceAssembly '{SourceAssembly}' does not exist." ) ;
return false ;
}
return true ;
}
public override bool Execute ( )
{
2018-10-15 13:27:42 -07:00
string tempDirPath = Path . Combine ( Path . GetTempPath ( ) , Path . GetRandomFileName ( ) ) ;
Directory . CreateDirectory ( tempDirPath ) ;
TempOutputPath = Path . Combine ( tempDirPath , Path . GetFileName ( DestinationPath ) ) ;
2016-07-26 00:29:59 -04:00
var toolResult = base . Execute ( ) ;
if ( toolResult )
{
File . Copy ( TempOutputPath , DestinationPath , overwrite : true ) ;
}
if ( File . Exists ( TempOutputPath ) )
{
File . Delete ( TempOutputPath ) ;
}
2018-10-15 13:27:42 -07:00
Directory . Delete ( tempDirPath ) ;
2016-07-26 00:29:59 -04:00
2017-11-01 17:17:22 -07:00
if ( toolResult & & CreateSymbols )
{
_secondInvocationToCreateSymbols = true ;
toolResult = base . Execute ( ) ;
}
2016-07-26 00:29:59 -04:00
return toolResult ;
}
protected override string ToolName
{
get { return "crossgen" ; }
}
protected override MessageImportance StandardOutputLoggingImportance
{
2018-08-06 11:16:45 -07:00
// Default is low, but we want to see output at normal verbosity.
get { return MessageImportance . Normal ; }
}
protected override MessageImportance StandardErrorLoggingImportance
{
// This turns stderr messages into msbuild errors below.
get { return MessageImportance . High ; }
}
protected override void LogEventsFromTextOutput ( string singleLine , MessageImportance messageImportance )
{
// Crossgen's error/warning formatting is inconsistent and so we do
// not use the "canonical error format" handling of base.
//
// Furthermore, we don't want to log crossgen warnings as msbuild
// warnings because we cannot prevent them and they are only
// occasionally formatted as something that base would recognize as
// a canonically formatted warning anyway.
//
// One thing that is consistent is that crossgne errors go to stderr
// and everything else goes to stdout. Above, we set stderr to high
// importance above, and stdout to normal. So we can use that here
// to distinguish between errors and messages.
if ( messageImportance = = MessageImportance . High )
{
Log . LogError ( singleLine ) ;
}
else
{
Log . LogMessage ( messageImportance , singleLine ) ;
}
2016-07-26 00:29:59 -04:00
}
protected override string GenerateFullPathToTool ( )
{
if ( CrossgenPath ! = null )
{
return CrossgenPath ;
}
return "crossgen" ;
}
protected override string GenerateCommandLineCommands ( )
{
2017-11-01 17:17:22 -07:00
if ( _secondInvocationToCreateSymbols )
{
return $"{GetReadyToRun()} {GetPlatformAssemblyPaths()} {GetDiasymReaderPath()} {GetCreateSymbols()}" ;
}
2016-07-26 00:29:59 -04:00
return $"{GetReadyToRun()} {GetInPath()} {GetOutPath()} {GetPlatformAssemblyPaths()} {GetJitPath()}" ;
}
2017-11-01 17:17:22 -07:00
private string GetCreateSymbols ( )
{
var option = RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) ? "-createpdb" : "-createperfmap" ;
return $"{option} \" { Path . GetDirectoryName ( DestinationPath ) } \ " \"{DestinationPath}\"" ;
}
private string GetDiasymReaderPath ( )
{
if ( string . IsNullOrEmpty ( DiasymReaderPath ) )
{
return null ;
}
return $"-diasymreaderpath \" { DiasymReaderPath } \ "" ;
}
2016-07-26 00:29:59 -04:00
private string GetReadyToRun ( )
{
if ( ReadyToRun )
{
return "-readytorun" ;
}
return null ;
}
private string GetInPath ( )
{
2016-12-20 11:36:48 -08:00
return $"-in \" { SourceAssembly } \ "" ;
2016-07-26 00:29:59 -04:00
}
private string GetOutPath ( )
{
2016-12-20 11:36:48 -08:00
return $"-out \" { TempOutputPath } \ "" ;
2016-07-26 00:29:59 -04:00
}
private string GetPlatformAssemblyPaths ( )
{
var platformAssemblyPaths = String . Empty ;
if ( PlatformAssemblyPaths ! = null )
{
foreach ( var excludeTaskItem in PlatformAssemblyPaths )
{
platformAssemblyPaths + = $"{excludeTaskItem.ItemSpec}{Path.PathSeparator}" ;
}
}
return $" -platform_assemblies_paths {platformAssemblyPaths.Trim(':')}" ;
}
private string GetJitPath ( )
{
return $"-JITPath {JITPath}" ;
}
protected override void LogToolCommand ( string message )
{
base . LogToolCommand ( $"{base.GetWorkingDirectory()}> {message}" ) ;
}
}
}