2016-04-14 18:02:26 -07:00
using System ;
using System.Collections.Generic ;
2016-03-10 03:19:00 -08:00
using System.IO ;
using System.Linq ;
using Microsoft.DotNet.Cli.Build.Framework ;
2016-04-28 16:30:32 -07:00
using Microsoft.DotNet.InternalAbstractions ;
2016-04-14 18:02:26 -07:00
using static Microsoft . DotNet . Cli . Build . Framework . BuildHelpers ;
2016-03-10 03:19:00 -08:00
namespace Microsoft.DotNet.Cli.Build
{
2016-04-14 18:02:26 -07:00
public class Crossgen
2016-03-10 03:19:00 -08:00
{
2016-04-14 18:02:26 -07:00
private string _coreClrVersion ;
private string _crossGenPath ;
2016-05-16 23:12:48 -07:00
private static readonly string [ ] s_excludedLibraries =
2016-05-16 12:01:13 -07:00
{
"mscorlib.dll" ,
2016-05-23 18:06:34 -07:00
"mscorlib.ni.dll" ,
"System.Private.CoreLib" ,
"System.Private.CoreLib.ni.dll"
2016-05-16 12:01:13 -07:00
} ;
2016-04-14 18:02:26 -07:00
// This is not always correct. The version of crossgen we need to pick up is whatever one was restored as part
// of the Microsoft.NETCore.Runtime.CoreCLR package that is part of the shared library. For now, the version hardcoded
// in CompileTargets and the one in the shared library project.json match and are updated in lock step, but long term
// we need to be able to look at the project.lock.json file and figure out what version of Microsoft.NETCore.Runtime.CoreCLR
// was used, and then select that version.
public Crossgen ( string coreClrVersion )
{
_coreClrVersion = coreClrVersion ;
_crossGenPath = GetCrossgenPathForVersion ( ) ;
}
private string GetCrossgenPathForVersion ( )
2016-03-10 03:19:00 -08:00
{
2016-05-23 17:52:56 -07:00
var crossgenPackagePath = GetCrossGenPackagePathForVersion ( ) ;
if ( crossgenPackagePath = = null )
{
return null ;
}
return Path . Combine (
crossgenPackagePath ,
"tools" ,
$"crossgen{Constants.ExeSuffix}" ) ;
}
private string GetLibCLRJitPathForVersion ( )
{
var coreclrRid = GetCoreCLRRid ( ) ;
var crossgenPackagePath = GetCrossGenPackagePathForVersion ( ) ;
if ( crossgenPackagePath = = null )
{
return null ;
}
return Path . Combine (
crossgenPackagePath ,
"runtimes" ,
coreclrRid ,
"native" ,
$"{Constants.DynamicLibPrefix}clrjit{Constants.DynamicLibSuffix}" ) ;
}
private string GetCrossGenPackagePathForVersion ( )
{
string coreclrRid = GetCoreCLRRid ( ) ;
if ( coreclrRid = = null )
{
return null ;
}
string packageId = $"runtime.{coreclrRid}.Microsoft.NETCore.Runtime.CoreCLR" ;
return Path . Combine (
Dirs . NuGetPackages ,
packageId ,
_coreClrVersion ) ;
}
private string GetCoreCLRRid ( )
{
string rid = null ;
2016-03-10 03:19:00 -08:00
if ( CurrentPlatform . IsWindows )
{
2016-05-23 17:52:56 -07:00
var arch = RuntimeEnvironment . RuntimeArchitecture ;
rid = $"win7-{arch}" ;
2016-03-10 03:19:00 -08:00
}
else if ( CurrentPlatform . IsUbuntu )
{
2016-05-23 17:52:56 -07:00
rid = "ubuntu.14.04-x64" ;
2016-03-10 03:19:00 -08:00
}
else if ( CurrentPlatform . IsCentOS | | CurrentPlatform . IsRHEL )
{
// CentOS runtime is in the runtime.rhel.7-x64... package.
2016-05-23 17:52:56 -07:00
rid = "rhel.7-x64" ;
2016-03-10 03:19:00 -08:00
}
else if ( CurrentPlatform . IsOSX )
{
2016-05-23 17:52:56 -07:00
rid = "osx.10.10-x64" ;
2016-03-10 03:19:00 -08:00
}
else if ( CurrentPlatform . IsDebian )
{
2016-05-23 17:52:56 -07:00
rid = "debian.8-x64" ;
2016-03-10 03:19:00 -08:00
}
2016-05-23 17:52:56 -07:00
return rid ;
}
2016-04-14 18:02:26 -07:00
2016-05-16 15:30:53 -07:00
public void CrossgenDirectory ( string sharedFxPath , string pathToAssemblies )
2016-04-14 18:02:26 -07:00
{
// Check if we need to skip crossgen
if ( string . Equals ( Environment . GetEnvironmentVariable ( "DISABLE_CROSSGEN" ) , "1" ) )
{
2016-05-16 15:30:53 -07:00
var originalColor = Console . ForegroundColor ;
Console . ForegroundColor = ConsoleColor . Yellow ;
Console . WriteLine ( "Skipping crossgen for because DISABLE_CROSSGEN is set to 1" ) ;
Console . ForegroundColor = originalColor ;
2016-04-14 18:02:26 -07:00
return ;
}
2016-04-15 10:31:17 -07:00
// HACK
// The input directory can be a portable FAT app (example the CLI itself).
// In that case there can be RID specific managed dependencies which are not right next to the app binary (example System.Diagnostics.TraceSource).
// We need those dependencies during crossgen. For now we just pass all subdirectories of the input directory as input to crossgen.
// The right fix -
// If the assembly has deps.json then parse the json file to get all the dependencies, pass these dependencies as input to crossgen.
// else pass the current directory of assembly as input to crossgen.
var addtionalPaths = Directory . GetDirectories ( pathToAssemblies , "*" , SearchOption . AllDirectories ) . ToList ( ) ;
var paths = new List < string > ( ) { sharedFxPath , pathToAssemblies } ;
paths . AddRange ( addtionalPaths ) ;
var platformAssembliesPaths = string . Join ( Path . PathSeparator . ToString ( ) , paths . Distinct ( ) ) ;
var env = new Dictionary < string , string > ( )
{
// disable partial ngen
2016-05-18 13:03:49 -07:00
{ "COMPlus_PartialNGen" , "0" }
2016-04-15 10:31:17 -07:00
} ;
2016-04-14 18:02:26 -07:00
foreach ( var file in Directory . GetFiles ( pathToAssemblies ) )
{
string fileName = Path . GetFileName ( file ) ;
2016-05-16 23:12:48 -07:00
if ( s_excludedLibraries . Any ( lib = > String . Equals ( lib , fileName , StringComparison . OrdinalIgnoreCase ) )
2016-05-16 12:01:13 -07:00
| | ! PEUtils . HasMetadata ( file ) )
2016-04-14 18:02:26 -07:00
{
continue ;
}
string tempPathName = Path . ChangeExtension ( file , "readytorun" ) ;
IList < string > crossgenArgs = new List < string > {
"-readytorun" , "-in" , file , "-out" , tempPathName ,
2016-05-23 17:52:56 -07:00
"-JITPath" , GetLibCLRJitPathForVersion ( ) ,
2016-04-14 18:54:25 -07:00
"-platform_assemblies_paths" , platformAssembliesPaths
2016-04-14 18:02:26 -07:00
} ;
2016-04-14 18:36:33 -07:00
ExecSilent ( _crossGenPath , crossgenArgs , env ) ;
2016-04-14 18:02:26 -07:00
2016-05-02 19:51:12 -07:00
File . Copy ( tempPathName , file , overwrite : true ) ;
File . Delete ( tempPathName ) ;
2016-04-14 18:02:26 -07:00
}
}
2016-03-10 03:19:00 -08:00
}
}