Merge pull request #2517 from Sridhar-MS/crossgen-cli

Enable crossgen for CLI SDK binaries.
This commit is contained in:
Piotr Puszkiewicz 2016-04-15 16:08:22 -07:00
commit 37f00f24e9
5 changed files with 123 additions and 66 deletions

View file

@ -5,16 +5,17 @@ namespace Microsoft.DotNet.Cli.Build.Framework
public static class BuildHelpers
{
public static int ExecInSilent(string workingDirectory, string command, params string[] args) => ExecInSilent(workingDirectory, command, (IEnumerable<string>)args);
public static int ExecInSilent(string workingDirectory, string command, IEnumerable<string> args) => ExecCore(command, args, workingDirectory, silent: true);
public static int ExecInSilent(string workingDirectory, string command, IEnumerable<string> args) => ExecCore(command, args, workingDirectory, silent: true, env: null);
public static int ExecIn(string workingDirectory, string command, params string[] args) => ExecIn(workingDirectory, command, (IEnumerable<string>)args);
public static int ExecIn(string workingDirectory, string command, IEnumerable<string> args) => ExecCore(command, args, workingDirectory, silent: false);
public static int ExecIn(string workingDirectory, string command, IEnumerable<string> args) => ExecCore(command, args, workingDirectory, silent: false, env: null);
public static int ExecSilent(string command, params string[] args) => ExecSilent(command, (IEnumerable<string>)args);
public static int ExecSilent(string command, IEnumerable<string> args) => ExecCore(command, args, workingDirectory: null, silent: true);
public static int ExecSilent(string command, IEnumerable<string> args) => ExecSilent(command, args, env: null);
public static int ExecSilent(string command, IEnumerable<string> args, IDictionary<string, string> env) => ExecCore(command, args, workingDirectory: null, silent: true, env: null);
public static int Exec(string command, params string[] args) => Exec(command, (IEnumerable<string>)args);
public static int Exec(string command, IEnumerable<string> args) => ExecCore(command, args, workingDirectory: null, silent: false);
public static int Exec(string command, IEnumerable<string> args) => ExecCore(command, args, workingDirectory: null, silent: false, env: null);
public static Command Cmd(string command, params string[] args) => Cmd(command, (IEnumerable<string>)args);
public static Command Cmd(string command, IEnumerable<string> args)
@ -22,21 +23,24 @@ namespace Microsoft.DotNet.Cli.Build.Framework
return Command.Create(command, args);
}
internal static int ExecCore(string command, IEnumerable<string> args, string workingDirectory, bool silent)
internal static int ExecCore(string command, IEnumerable<string> args, string workingDirectory, bool silent, IDictionary<string, string> env)
{
var cmd = Cmd(command, args);
if(!string.IsNullOrEmpty(workingDirectory))
if (!string.IsNullOrEmpty(workingDirectory))
{
cmd.WorkingDirectory(workingDirectory);
}
if(silent)
if (silent)
{
cmd.CaptureStdErr().CaptureStdOut();
}
var result = cmd.Execute();
var result = cmd.Environment(env).Execute();
result.EnsureSuccessful();
return result.ExitCode;
}
}
}

View file

@ -136,6 +136,11 @@ namespace Microsoft.DotNet.Cli.Build.Framework
public Command Environment(IDictionary<string, string> env)
{
if (env == null)
{
return this;
}
foreach (var item in env)
{
_process.StartInfo.Environment[item.Key] = item.Value;

View file

@ -37,6 +37,8 @@ namespace Microsoft.DotNet.Cli.Build
public const string SharedFrameworkName = "Microsoft.NETCore.App";
public static Crossgen CrossgenUtil = new Crossgen(CoreCLRVersion);
private static string CoreHostBaseName => $"corehost{Constants.ExeSuffix}";
private static string DotnetHostFxrBaseName => $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}";
private static string HostPolicyBaseName => $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}";
@ -427,7 +429,7 @@ namespace Microsoft.DotNet.Cli.Build
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll"));
}
CrossgenSharedFx(c, SharedFrameworkNameAndVersionRoot);
CrossgenUtil.CrossgenDirectory(c, SharedFrameworkNameAndVersionRoot);
// Generate .version file for sharedfx
var version = SharedFrameworkNugetVersion;
@ -527,6 +529,8 @@ namespace Microsoft.DotNet.Cli.Build
File.Delete(compilersDeps);
File.Delete(compilersRuntimeConfig);
CrossgenUtil.CrossgenDirectory(c, outputDir);
// Generate .version file
var version = buildVersion.NuGetVersion;
var content = $@"{c.BuildContext["CommitHash"]}{Environment.NewLine}{version}{Environment.NewLine}";
@ -535,41 +539,6 @@ namespace Microsoft.DotNet.Cli.Build
return c.Success();
}
public static BuildTargetResult CrossgenSharedFx(BuildTargetContext c, string pathToAssemblies)
{
// Check if we need to skip crossgen
if (string.Equals(Environment.GetEnvironmentVariable("DONT_CROSSGEN_SHAREDFRAMEWORK"), "1"))
{
c.Warn("Skipping crossgen for SharedFx because DONT_CROSSGEN_SHAREDFRAMEWORK is set to 1");
return c.Success();
}
foreach (var file in Directory.GetFiles(pathToAssemblies))
{
string fileName = Path.GetFileName(file);
if (fileName == "mscorlib.dll" || fileName == "mscorlib.ni.dll" || !HasMetadata(file))
{
continue;
}
string tempPathName = Path.ChangeExtension(file, "readytorun");
// 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.
ExecSilent(Crossgen.GetCrossgenPathForVersion(CoreCLRVersion),
"-readytorun", "-in", file, "-out", tempPathName, "-platform_assemblies_paths", pathToAssemblies);
File.Delete(file);
File.Move(tempPathName, file);
}
return c.Success();
}
private static void ChangeEntryPointLibraryName(string depsFile, string newName)
{
JToken deps;
@ -600,7 +569,7 @@ namespace Microsoft.DotNet.Cli.Build
library.Replace(new JProperty(newName + '/' + version, library.Value));
}
using (var file = File.CreateText(depsFile))
using (var writer = new JsonTextWriter(file) { Formatting = Formatting.Indented})
using (var writer = new JsonTextWriter(file) { Formatting = Formatting.Indented })
{
deps.WriteTo(writer);
}
@ -612,22 +581,5 @@ namespace Microsoft.DotNet.Cli.Build
File.Delete(Path.Combine(path, $"{name}.dll"));
File.Delete(Path.Combine(path, $"{name}.pdb"));
}
private static bool HasMetadata(string pathToFile)
{
try
{
using (var inStream = File.OpenRead(pathToFile))
{
using (var peReader = new PEReader(inStream))
{
return peReader.HasMetadata;
}
}
}
catch (BadImageFormatException) { }
return false;
}
}
}

View file

@ -1,15 +1,32 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;
using System.Runtime.InteropServices;
using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.Extensions.PlatformAbstractions;
using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers;
namespace Microsoft.DotNet.Cli.Build
{
internal static class Crossgen
public class Crossgen
{
public static string GetCrossgenPathForVersion(string coreClrVersion)
private string _coreClrVersion;
private string _crossGenPath;
// 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()
{
string arch = PlatformServices.Default.Runtime.RuntimeArchitecture;
string packageId;
@ -42,9 +59,61 @@ namespace Microsoft.DotNet.Cli.Build
return Path.Combine(
Dirs.NuGetPackages,
packageId,
coreClrVersion,
_coreClrVersion,
"tools",
$"crossgen{Constants.ExeSuffix}");
}
public void CrossgenDirectory(BuildTargetContext c, string pathToAssemblies)
{
// Check if we need to skip crossgen
if (string.Equals(Environment.GetEnvironmentVariable("DISABLE_CROSSGEN"), "1"))
{
c.Warn("Skipping crossgen for because DISABLE_CROSSGEN is set to 1");
return;
}
string sharedFxPath = c.BuildContext.Get<string>("SharedFrameworkPath");
// 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
{ "COMPLUS_ZapDisable", "0" }
};
foreach (var file in Directory.GetFiles(pathToAssemblies))
{
string fileName = Path.GetFileName(file);
if (fileName == "mscorlib.dll" || fileName == "mscorlib.ni.dll" || !PEUtils.HasMetadata(file))
{
continue;
}
string tempPathName = Path.ChangeExtension(file, "readytorun");
IList<string> crossgenArgs = new List<string> {
"-readytorun", "-in", file, "-out", tempPathName,
"-platform_assemblies_paths", platformAssembliesPaths
};
ExecSilent(_crossGenPath, crossgenArgs, env);
File.Delete(file);
File.Move(tempPathName, file);
}
}
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.PortableExecutable;
namespace Microsoft.DotNet.Cli.Build
{
public static class PEUtils
{
public static bool HasMetadata(string pathToFile)
{
try
{
using (var inStream = File.OpenRead(pathToFile))
{
using (var peReader = new PEReader(inStream))
{
return peReader.HasMetadata;
}
}
}
catch (BadImageFormatException) { }
return false;
}
}
}