Enable crossgen for CLI SDK binaries.
TODO: Write tests to make sure aseemblies are crossgened.
This commit is contained in:
parent
880dcf2fc8
commit
d6fe71d4dd
3 changed files with 97 additions and 59 deletions
|
@ -37,6 +37,8 @@ namespace Microsoft.DotNet.Cli.Build
|
||||||
|
|
||||||
public const string SharedFrameworkName = "Microsoft.NETCore.App";
|
public const string SharedFrameworkName = "Microsoft.NETCore.App";
|
||||||
|
|
||||||
|
public static Crossgen CrossgenUtil = new Crossgen(CoreCLRVersion);
|
||||||
|
|
||||||
private static string CoreHostBaseName => $"corehost{Constants.ExeSuffix}";
|
private static string CoreHostBaseName => $"corehost{Constants.ExeSuffix}";
|
||||||
private static string DotnetHostFxrBaseName => $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}";
|
private static string DotnetHostFxrBaseName => $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}";
|
||||||
private static string HostPolicyBaseName => $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}";
|
private static string HostPolicyBaseName => $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}";
|
||||||
|
@ -343,7 +345,7 @@ namespace Microsoft.DotNet.Cli.Build
|
||||||
}
|
}
|
||||||
|
|
||||||
string SharedFrameworkSourceRoot = GenerateSharedFrameworkProject(c, SharedFrameworkTemplateSourceRoot, sharedFrameworkRid);
|
string SharedFrameworkSourceRoot = GenerateSharedFrameworkProject(c, SharedFrameworkTemplateSourceRoot, sharedFrameworkRid);
|
||||||
|
|
||||||
dotnetCli.Restore("--verbosity", "verbose", "--disable-parallel", "--infer-runtimes", "--fallbacksource", Dirs.Corehost)
|
dotnetCli.Restore("--verbosity", "verbose", "--disable-parallel", "--infer-runtimes", "--fallbacksource", Dirs.Corehost)
|
||||||
.WorkingDirectory(SharedFrameworkSourceRoot)
|
.WorkingDirectory(SharedFrameworkSourceRoot)
|
||||||
.Execute()
|
.Execute()
|
||||||
|
@ -430,7 +432,7 @@ namespace Microsoft.DotNet.Cli.Build
|
||||||
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll"));
|
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll"));
|
||||||
}
|
}
|
||||||
|
|
||||||
CrossgenSharedFx(c, SharedFrameworkNameAndVersionRoot);
|
CrossgenUtil.CrossgenDirectory(c, SharedFrameworkNameAndVersionRoot);
|
||||||
|
|
||||||
// Generate .version file for sharedfx
|
// Generate .version file for sharedfx
|
||||||
var version = SharedFrameworkNugetVersion;
|
var version = SharedFrameworkNugetVersion;
|
||||||
|
@ -530,6 +532,8 @@ namespace Microsoft.DotNet.Cli.Build
|
||||||
File.Delete(compilersDeps);
|
File.Delete(compilersDeps);
|
||||||
File.Delete(compilersRuntimeConfig);
|
File.Delete(compilersRuntimeConfig);
|
||||||
|
|
||||||
|
CrossgenUtil.CrossgenDirectory(c, outputDir);
|
||||||
|
|
||||||
// Generate .version file
|
// Generate .version file
|
||||||
var version = buildVersion.NuGetVersion;
|
var version = buildVersion.NuGetVersion;
|
||||||
var content = $@"{c.BuildContext["CommitHash"]}{Environment.NewLine}{version}{Environment.NewLine}";
|
var content = $@"{c.BuildContext["CommitHash"]}{Environment.NewLine}{version}{Environment.NewLine}";
|
||||||
|
@ -538,41 +542,6 @@ namespace Microsoft.DotNet.Cli.Build
|
||||||
return c.Success();
|
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)
|
private static void ChangeEntryPointLibraryName(string depsFile, string newName)
|
||||||
{
|
{
|
||||||
JToken deps;
|
JToken deps;
|
||||||
|
@ -603,7 +572,7 @@ namespace Microsoft.DotNet.Cli.Build
|
||||||
library.Replace(new JProperty(newName + '/' + version, library.Value));
|
library.Replace(new JProperty(newName + '/' + version, library.Value));
|
||||||
}
|
}
|
||||||
using (var file = File.CreateText(depsFile))
|
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);
|
deps.WriteTo(writer);
|
||||||
}
|
}
|
||||||
|
@ -615,22 +584,5 @@ namespace Microsoft.DotNet.Cli.Build
|
||||||
File.Delete(Path.Combine(path, $"{name}.dll"));
|
File.Delete(Path.Combine(path, $"{name}.dll"));
|
||||||
File.Delete(Path.Combine(path, $"{name}.pdb"));
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,32 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Microsoft.DotNet.Cli.Build.Framework;
|
using Microsoft.DotNet.Cli.Build.Framework;
|
||||||
using Microsoft.Extensions.PlatformAbstractions;
|
using Microsoft.Extensions.PlatformAbstractions;
|
||||||
|
|
||||||
|
using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Cli.Build
|
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 arch = PlatformServices.Default.Runtime.RuntimeArchitecture;
|
||||||
string packageId;
|
string packageId;
|
||||||
|
@ -42,9 +59,51 @@ namespace Microsoft.DotNet.Cli.Build
|
||||||
return Path.Combine(
|
return Path.Combine(
|
||||||
Dirs.NuGetPackages,
|
Dirs.NuGetPackages,
|
||||||
packageId,
|
packageId,
|
||||||
coreClrVersion,
|
_coreClrVersion,
|
||||||
"tools",
|
"tools",
|
||||||
$"crossgen{Constants.ExeSuffix}");
|
$"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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
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.
|
||||||
|
string addtionalPaths = string.Join(";", Directory.GetDirectories(pathToAssemblies, "*", SearchOption.AllDirectories));
|
||||||
|
|
||||||
|
IList<string> crossgenArgs = new List<string> {
|
||||||
|
"-readytorun", "-in", file, "-out", tempPathName,
|
||||||
|
"-platform_assemblies_paths", $"{sharedFxPath};{pathToAssemblies};{addtionalPaths}"
|
||||||
|
};
|
||||||
|
|
||||||
|
ExecSilent(_crossGenPath, crossgenArgs);
|
||||||
|
|
||||||
|
File.Delete(file);
|
||||||
|
File.Move(tempPathName, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
scripts/dotnet-cli-build/Utils/PEUtils.cs
Normal file
27
scripts/dotnet-cli-build/Utils/PEUtils.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection.PortableExecutable;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Cli.Build
|
||||||
|
{
|
||||||
|
public 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue