diff --git a/src/coreclr/src/tools/r2rtest/BuildOptions.cs b/src/coreclr/src/tools/r2rtest/BuildOptions.cs index 91926496a58000..d51cb2af47ec25 100644 --- a/src/coreclr/src/tools/r2rtest/BuildOptions.cs +++ b/src/coreclr/src/tools/r2rtest/BuildOptions.cs @@ -31,7 +31,6 @@ public class BuildOptions public bool Release { get; set; } public bool LargeBubble { get; set; } public bool Composite { get; set; } - public bool PartialComposite { get; set; } public int Crossgen2Parallelism { get; set; } public int CompilationTimeoutMinutes { get; set; } public int ExecutionTimeoutMinutes { get; set; } @@ -42,6 +41,7 @@ public class BuildOptions public DirectoryInfo[] RewriteOldPath { get; set; } public DirectoryInfo[] RewriteNewPath { get; set; } public DirectoryInfo AspNetPath { get; set; } + public SerpCompositeScenario CompositeScenario { get; set; } public bool MeasurePerf { get; set; } public string InputFileSearchString { get; set; } public string ConfigurationSuffix => (Release ? "-ret.out" : "-chk.out"); @@ -117,7 +117,7 @@ public IEnumerable CompilerRunners(bool isFramework, IEnumerable List cpaotReferencePaths = new List(); cpaotReferencePaths.Add(CoreRootOutputPath(CompilerIndex.CPAOT, isFramework)); cpaotReferencePaths.AddRange(overrideReferencePaths != null ? overrideReferencePaths : ReferencePaths()); - runners.Add(new CpaotRunner(this, cpaotReferencePaths)); + runners.Add(new Crossgen2Runner(this, crossgen2RunnerOptions: null, cpaotReferencePaths)); } if (Crossgen) diff --git a/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs b/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs index 05de0f06059b41..aa7ff7a46d0cf2 100644 --- a/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs +++ b/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs @@ -144,13 +144,15 @@ Command CompileSerp() => new Option[] { InputDirectory(), - OutputDirectory(), DegreeOfParallelism(), AspNetPath(), - Composite(), - PartialComposite(), + CompositeScenario() }, - CompileSerpCommand.CompileSerpAssemblies); + options => + { + var compileSerp = new CompileSerpCommand(options); + return compileSerp.CompileSerpAssemblies(); + }); // Todo: Input / Output directories should be required arguments to the command when they're made available to handlers // https://github.com/dotnet/command-line-api/issues/297 @@ -259,8 +261,8 @@ Option PackageList() => Option AspNetPath() => new Option(new[] { "--asp-net-path", "-asp" }, "Path to SERP's ASP.NET Core folder").ExistingOnly(); - Option PartialComposite() => - new Option(new[] { "--partial-composite", "-pc" }, "Add references to framework and asp.net instead of unrooted inputs"); + Option CompositeScenario() => + new Option(new [] { "--composite-scenario", "-cs" }, "Specifies which layers of a shared framework application are compiled as composite" ); } } } diff --git a/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs b/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs index 15893256577bc7..d6d4678ebf01e4 100644 --- a/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs +++ b/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs @@ -12,154 +12,327 @@ namespace R2RTest { - class CompileSerpCommand + public enum SerpCompositeScenario { - public static int CompileSerpAssemblies(BuildOptions options) - { - if (options.InputDirectory == null) - { - Console.Error.WriteLine("Specify --response-file or --input-directory containing multiple response files."); - return 1; - } + /// + /// Compiles all Serp, Asp.Net, and Framework assemblies in their own version bubble + /// + NoComposite, + /// + /// Compiles Serp Core, Asp.Net, and Framework into their own composite images. Compiles Serp packages assemblies individually. + /// + SerpAspNetSharedFramework, + } - if (options.CoreRootDirectory == null) - { - Console.Error.WriteLine("--core-root-directory (--cr) is a required argument."); - return 1; - } + class CompileSerpCommand + { + private static readonly string BackupFolder = "backup"; + private static readonly string CompileFolder = "compile"; + private List _packageCompileAssemblies; + private List _packageReferenceAssemblies; + private List _coreCompileAssemblies = new List(); + private List _coreReferenceAssemblies = new List(); + private List _frameworkCompileAssemblies = new List(); + private List _frameworkReferenceAssemblies = new List(); + private List _aspCompileAssemblies = new List(); + private List _aspReferenceAssemblies = new List(); + private string SerpDir { get; set; } + private string BinDir { get;set; } + private BuildOptions _options; + public CompileSerpCommand(BuildOptions options) + { // This command does not work in the context of an app, just a loose set of rsp files so don't execute anything we compile options.NoJit = true; options.NoEtw = true; + options.Release = true; - string serpDir = options.InputDirectory.FullName; - if (!File.Exists(Path.Combine(serpDir, "runserp.cmd"))) + _options = options; + + if (_options.InputDirectory == null) { - Console.Error.WriteLine($"Error: InputDirectory must point at a SERP build. Could not find {Path.Combine(serpDir, "runserp.cmd")}"); - return 1; + throw new ArgumentException("Specify --response-file or --input-directory containing multiple response files."); } - string whiteListFilePath = Path.Combine(serpDir, "WhitelistDlls.txt"); - if (!File.Exists(whiteListFilePath)) + if (_options.CoreRootDirectory == null) { - Console.Error.WriteLine($"File {whiteListFilePath} was not found"); - return 1; + throw new ArgumentException("--core-root-directory (--cr) is a required argument."); } - if (!File.Exists(Path.Combine(options.AspNetPath.FullName, "Microsoft.AspNetCore.dll"))) + if (_options.AspNetPath == null || !File.Exists(Path.Combine(_options.AspNetPath.FullName, "Microsoft.AspNetCore.dll"))) { - Console.Error.WriteLine($"Error: Asp.NET Core path must contain Microsoft.AspNetCore.dll"); - return 1; + throw new ArgumentException($"Error: Asp.NET Core path must contain Microsoft.AspNetCore.dll"); } + + SerpDir = _options.InputDirectory.FullName; + BinDir = Path.Combine(SerpDir, "bin"); - string binDir = Path.Combine(serpDir, "bin"); + if (!File.Exists(Path.Combine(SerpDir, "runserp.cmd"))) + { + throw new ArgumentException($"Error: InputDirectory must point at a SERP build. Could not find {Path.Combine(SerpDir, "runserp.cmd")}"); + } + + string whiteListFilePath = Path.Combine(SerpDir, "WhitelistDlls.txt"); + if (!File.Exists(whiteListFilePath)) + { + throw new ArgumentException($"File {whiteListFilePath} was not found"); + } - // Remove existing native images - foreach (var file in Directory.GetFiles(Path.Combine(serpDir, "App_Data\\Answers\\Services\\Packages"), "*.dll", SearchOption.AllDirectories)) + // Add all assemblies from the various SERP packages (filtered by ShouldInclude) + _packageCompileAssemblies = Directory.GetFiles(Path.Combine(SerpDir, "App_Data\\Answers\\Services\\Packages"), "*.dll", SearchOption.AllDirectories) + .Where((string x) => ShouldInclude(x)) + .ToList(); + _packageReferenceAssemblies = new List(); { - if (file.EndsWith(".ni.dll") || file.EndsWith(".ni.exe")) + HashSet packageReferenceAssemblyDirectories = new HashSet(); + foreach (var binFile in _packageCompileAssemblies) { - File.Delete(file); + var directory = Path.GetDirectoryName(binFile); + if (!packageReferenceAssemblyDirectories.Contains(directory)) + packageReferenceAssemblyDirectories.Add(directory); + } + + foreach (string binFile in ResolveReferences(packageReferenceAssemblyDirectories)) + { + _packageReferenceAssemblies.Add(binFile); } } - foreach (var file in Directory.GetFiles(binDir, "*.dll", SearchOption.AllDirectories)) + _coreCompileAssemblies = new List(); + _coreReferenceAssemblies = new List(); { - if (file.EndsWith(".ni.dll") || file.EndsWith(".ni.exe")) + // Add a whitelist of assemblies from bin + foreach (string item in new HashSet(File.ReadAllLines(whiteListFilePath))) { - File.Delete(file); + string binAssembly = Path.Combine(BinDir, item); + _coreCompileAssemblies.Add(binAssembly); } - } - // Add all assemblies from the various SERP packages (filtered by ShouldInclude) - List binFiles = Directory.GetFiles(Path.Combine(serpDir, "App_Data\\Answers\\Services\\Packages"), "*.dll", SearchOption.AllDirectories) - .Where((string x) => ShouldInclude(x)) - .ToList(); + HashSet coreReferenceAssemblyDirectories = new HashSet(); + foreach (var binFile in _coreCompileAssemblies) + { + var directory = Path.GetDirectoryName(binFile); + if (!coreReferenceAssemblyDirectories.Contains(directory)) + coreReferenceAssemblyDirectories.Add(directory); + } + + foreach (string binFile in ResolveReferences(coreReferenceAssemblyDirectories)) + { + _coreReferenceAssemblies.Add(binFile); + } + } - // Add a whitelist of assemblies from bin - foreach (string item in new HashSet(File.ReadAllLines(whiteListFilePath))) + _frameworkCompileAssemblies = new List(); + _frameworkReferenceAssemblies = new List(); { - binFiles.Add(Path.Combine(binDir, item)); + foreach (string frameworkDll in ComputeManagedAssemblies.GetManagedAssembliesInFolder(options.CoreRootDirectory.FullName, "System.*.dll")) + { + string simpleName = Path.GetFileNameWithoutExtension(frameworkDll); + if (!FrameworkExclusion.Exclude(simpleName, CompilerIndex.CPAOT, out string reason)) + { + _frameworkCompileAssemblies.Add(frameworkDll); + } + } + foreach (string frameworkDll in ComputeManagedAssemblies.GetManagedAssembliesInFolder(options.CoreRootDirectory.FullName, "Microsoft.*.dll")) + { + string simpleName = Path.GetFileNameWithoutExtension(frameworkDll); + if (!FrameworkExclusion.Exclude(simpleName, CompilerIndex.CPAOT, out string reason)) + { + _frameworkCompileAssemblies.Add(frameworkDll); + } + } + _frameworkCompileAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "mscorlib.dll")); + _frameworkCompileAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "netstandard.dll")); + _frameworkReferenceAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolder(options.CoreRootDirectory.FullName, "System.*.dll")); + _frameworkReferenceAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolder(options.CoreRootDirectory.FullName, "Microsoft.*.dll")); + _frameworkReferenceAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "mscorlib.dll")); + _frameworkReferenceAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "netstandard.dll")); } - HashSet referenceAssemblyDirectories = new HashSet(); - foreach (var binFile in binFiles) + _aspCompileAssemblies = new List(); + _aspReferenceAssemblies = new List(); { - var directory = Path.GetDirectoryName(binFile); - if (!referenceAssemblyDirectories.Contains(directory)) - referenceAssemblyDirectories.Add(directory); + _aspCompileAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolder(options.AspNetPath.FullName, "Microsoft.AspNetCore.*.dll")); + _aspCompileAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolder(options.AspNetPath.FullName, "Microsoft.Extensions.*.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "Microsoft.JSInterop.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "Microsoft.Net.Http.Headers.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "Microsoft.Win32.SystemEvents.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "System.Diagnostics.EventLog.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "System.Drawing.Common.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "System.IO.Pipelines.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "System.Security.Cryptography.Pkcs.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "System.Security.Cryptography.Xml.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "System.Security.Permissions.dll")); + _aspCompileAssemblies.Add(Path.Combine(options.AspNetPath.FullName, "System.Windows.Extensions.dll")); + + _aspReferenceAssemblies = new List(_aspCompileAssemblies); } - // TestILC needs a list of all directories containing assemblies that are referenced from crossgen - List referenceAssemblies = new List(); - HashSet simpleNames = new HashSet(StringComparer.OrdinalIgnoreCase); + } + public int CompileSerpAssemblies() + { + Console.WriteLine($"Compiling serp in {_options.CompositeScenario} scenario"); + + string serpRoot = Directory.GetParent(SerpDir).Parent.Parent.Parent.FullName; + string compileOutRoot = Path.Combine(serpRoot, CompileFolder); + if (Directory.Exists(compileOutRoot)) + Directory.Delete(compileOutRoot, true); + + // Composite FX, Composite ASP.NET, Composite Serp core, Individual package assemblies + List fileCompilations = new List(); - // Reference all managed assemblies in /bin and /App_Data/answers/services/packages - foreach (string binFile in ResolveReferences(referenceAssemblyDirectories)) + bool compositeFramework = false; + bool compositeAspNet = false; + bool compositeSerpCore = false; + if (_options.CompositeScenario == SerpCompositeScenario.SerpAspNetSharedFramework) { - simpleNames.Add(Path.GetFileNameWithoutExtension(binFile)); - referenceAssemblies.Add(binFile); + compositeFramework = true; + compositeAspNet = true; + compositeSerpCore = true; } - referenceAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolderNoSimpleNameDuplicates(simpleNames, options.AspNetPath.FullName, "*.dll")); + // Composite FX + { + List frameworkCompileAssembliesBackup = BackupAndUseOriginalAssemblies(serpRoot, _frameworkCompileAssemblies); + string frameworkCompositeDll = Path.Combine(_options.CoreRootDirectory.FullName, "framework-r2r.dll"); + if (File.Exists(frameworkCompositeDll)) + File.Delete(frameworkCompositeDll); - // Add CoreRoot last because it contains various non-framework assemblies that are duplicated in SERP and we want SERP's to be used - referenceAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolderNoSimpleNameDuplicates(simpleNames, options.CoreRootDirectory.FullName, "System.*.dll")); - referenceAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolderNoSimpleNameDuplicates(simpleNames, options.CoreRootDirectory.FullName, "Microsoft.*.dll")); - referenceAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "mscorlib.dll")); - referenceAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "netstandard.dll")); + // Always restore the framework from the backup if present first since we run CG2 on it + var backupFrameworkDir = Path.GetDirectoryName(GetBackupFile(serpRoot, frameworkCompositeDll)); + var backedUpFiles = Directory.GetFiles(backupFrameworkDir, "*.dll", SearchOption.AllDirectories); + foreach (var file in backedUpFiles) + { + string destinationFile = GetOriginalFile(serpRoot, file); + File.Copy(file, destinationFile, true); + } - // - // binFiles is now all the assemblies that we want to compile (either individually or as composite) - // referenceAssemblies is all managed assemblies that are referenceable - // + if (compositeFramework) + { + string frameworkCompositeDllCompile = GetCompileFile(serpRoot, frameworkCompositeDll); + Crossgen2RunnerOptions crossgen2Options = new Crossgen2RunnerOptions() { Composite = true }; + var runner = new Crossgen2Runner(_options, crossgen2Options, new List()); + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, frameworkCompositeDllCompile, frameworkCompileAssembliesBackup)); + fileCompilations.Add(compilationProcess); + } + else + { + Crossgen2RunnerOptions crossgen2Options = new Crossgen2RunnerOptions() { Composite = false }; + var runner = new Crossgen2Runner(_options, crossgen2Options, new List()); + foreach (string assembly in frameworkCompileAssembliesBackup) + { + string dllCompile = GetCompileFile(serpRoot, assembly); + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, dllCompile, new string[] { assembly })); + fileCompilations.Add(compilationProcess); + } + } + } - // Remove all bin files except serp.dll so they're just referenced (eventually we'll be able to compile all these in a single composite) - foreach (string item in new HashSet(File.ReadAllLines(whiteListFilePath))) + // Composite Asp.Net { - if (item == "Serp.dll") - continue; + List aspCombinedReferencesBackup = BackupAndUseOriginalAssemblies(serpRoot, new List(_frameworkReferenceAssemblies)); + List aspCompileAssembliesBackup = BackupAndUseOriginalAssemblies(serpRoot, _aspCompileAssemblies); + string aspCompositeDll = Path.Combine(_options.AspNetPath.FullName, "asp-r2r.dll"); + if (File.Exists(aspCompositeDll)) + File.Delete(aspCompositeDll); - binFiles.Remove(Path.Combine(binDir, item)); + if (compositeAspNet) + { + string aspCompositeDllCompile = GetCompileFile(serpRoot, aspCompositeDll); + Crossgen2RunnerOptions crossgen2Options = new Crossgen2RunnerOptions() { Composite = true, PartialComposite = true }; + var runner = new Crossgen2Runner(_options, crossgen2Options, aspCombinedReferencesBackup); + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, aspCompositeDllCompile, aspCompileAssembliesBackup)); + fileCompilations.Add(compilationProcess); + } + else + { + Crossgen2RunnerOptions crossgen2Options = new Crossgen2RunnerOptions() { Composite = false }; + var runner = new Crossgen2Runner(_options, crossgen2Options, aspCombinedReferencesBackup); + foreach (string assembly in aspCompileAssembliesBackup) + { + string dllCompile = GetCompileFile(serpRoot, assembly); + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, dllCompile, new string[] { assembly })); + fileCompilations.Add(compilationProcess); + } + } } - List fileCompilations = new List(); - if (options.Composite) + // Composite Serp core { - string serpDll = Path.Combine(binDir, "Serp.dll"); - var runner = new CpaotRunner(options, referenceAssemblies); - var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, Path.ChangeExtension(serpDll, ".ni.dll"), binFiles)); - fileCompilations.Add(compilationProcess); + List coreCombinedReferences = new List(); + coreCombinedReferences.AddRange(_coreReferenceAssemblies); + coreCombinedReferences.AddRange(_aspReferenceAssemblies); + coreCombinedReferences.AddRange(_frameworkReferenceAssemblies); + List coreCombinedReferencesBackup = BackupAndUseOriginalAssemblies(serpRoot, coreCombinedReferences); + List coreCompileAssembliesBackup = BackupAndUseOriginalAssemblies(serpRoot, _coreCompileAssemblies); + string serpCompositeDll = Path.Combine(BinDir, "serp-r2r.dll"); + if (File.Exists(serpCompositeDll)) + File.Delete(serpCompositeDll); + + if (compositeSerpCore) + { + string coreCompositeDllCompile = GetCompileFile(serpRoot, serpCompositeDll); + Crossgen2RunnerOptions crossgen2Options = new Crossgen2RunnerOptions() { Composite = true, PartialComposite = true }; + var runner = new Crossgen2Runner(_options, crossgen2Options, coreCombinedReferencesBackup); + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, coreCompositeDllCompile, coreCompileAssembliesBackup)); + fileCompilations.Add(compilationProcess); + } + else + { + Crossgen2RunnerOptions crossgen2Options = new Crossgen2RunnerOptions() { Composite = false }; + var runner = new Crossgen2Runner(_options, crossgen2Options, coreCombinedReferencesBackup); + foreach (string assembly in coreCompileAssembliesBackup) + { + string dllCompile = GetCompileFile(serpRoot, assembly); + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, dllCompile, new string[] { assembly })); + fileCompilations.Add(compilationProcess); + } + } } - else + + // Individual Serp package assemblies { - var runner = new CpaotRunner(options, referenceAssemblies); - foreach (string assemblyName in binFiles) + List packageCombinedReferences = new List(); + packageCombinedReferences.AddRange(_packageReferenceAssemblies); + packageCombinedReferences.AddRange(_coreReferenceAssemblies); + packageCombinedReferences.AddRange(_aspReferenceAssemblies); + packageCombinedReferences.AddRange(_frameworkReferenceAssemblies); + List packageCombinedReferencesBackup = BackupAndUseOriginalAssemblies(serpRoot, packageCombinedReferences); + List packageCompileAssembliesBackup = BackupAndUseOriginalAssemblies(serpRoot, _packageCompileAssemblies); + + Crossgen2RunnerOptions crossgen2Options = new Crossgen2RunnerOptions() { Composite = false }; + var runner = new Crossgen2Runner(_options, crossgen2Options, packageCombinedReferencesBackup); + foreach (string assembly in packageCompileAssembliesBackup) { - var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, Path.ChangeExtension(assemblyName, ".ni.dll"), new string[] {assemblyName})); + string dllCompile = GetCompileFile(serpRoot, assembly); + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, dllCompile, new string[] { assembly })); fileCompilations.Add(compilationProcess); } } - - ParallelRunner.Run(fileCompilations, options.DegreeOfParallelism); + + ParallelRunner.Run(fileCompilations, _options.DegreeOfParallelism); bool success = true; - int compilationFailures = 0; foreach (var compilationProcess in fileCompilations) { if (!compilationProcess.Succeeded) { success = false; - compilationFailures++; - Console.WriteLine($"Failed compiling {compilationProcess.Parameters.OutputFileName}"); } } - Console.WriteLine("Serp Compilation Results"); - Console.WriteLine($"Total compilations: {fileCompilations.Count}"); - Console.WriteLine($"Compilation failures: {compilationFailures}"); + if (!success) + return 1; + + // Move everything we compiled to the main directory structure + var compiledFiles = Directory.GetFiles(Path.Combine(serpRoot, CompileFolder), "*.dll", SearchOption.AllDirectories); + foreach (var file in compiledFiles) + { + string destinationFile = GetOriginalFile(serpRoot, file); + File.Move(file, destinationFile, true); + } return success ? 0 : 1; } @@ -168,10 +341,6 @@ private static bool ShouldInclude(string file) { if (!string.IsNullOrEmpty(file)) { - if (file.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase)) - { - return false; - } if (file.EndsWith("Shared.Exports.dll", StringComparison.OrdinalIgnoreCase)) { return true; @@ -180,6 +349,13 @@ private static bool ShouldInclude(string file) { return false; } + // These assemblies regressed single assembly CG2 compilation + if (file.EndsWith(".FitnessRoutine.dll") || + file.EndsWith(".Intent.dll") || + file.EndsWith(".VisualSystem.dll")) + { + return false; + } if (!file.EndsWith("Exports.dll", StringComparison.OrdinalIgnoreCase)) { return true; @@ -194,11 +370,73 @@ private static IEnumerable ResolveReferences(IEnumerable folders { foreach (string reference in ComputeManagedAssemblies.GetManagedAssembliesInFolder(referenceFolder)) { - if (reference.EndsWith(".ni.dll")) - continue; yield return reference; } } } + + /// + /// Backs up the assemblies to a separate folder tree and replaces each file with the original reference + /// in the output list. This keeps the Serp folder clean of junk. + /// + private static List BackupAndUseOriginalAssemblies(string rootFolder, List assemblies) + { + List rewrittenList = new List(); + + foreach (var assembly in assemblies) + { + rewrittenList.Add(BackupAndUseOriginalAssembly(rootFolder, assembly)); + } + + return rewrittenList; + } + + private static string BackupAndUseOriginalAssembly(string rootFolder, string assembly) + { + string backupFile = GetBackupFile(rootFolder, assembly); + string backupDir = Path.GetDirectoryName(backupFile); + + if (!Directory.Exists(backupDir)) + Directory.CreateDirectory(backupDir); + + if (!File.Exists(backupFile)) + { + File.Copy(assembly, backupFile); + } + + return backupFile; + } + + private static string GetBackupFile(string rootFolder, string assembly) + { + string relativePath = GetOriginalFileRelativePath(rootFolder, assembly); + return Path.Combine(rootFolder, BackupFolder, relativePath); + } + + private static string GetCompileFile(string rootFolder, string assembly) + { + string relativePath = GetOriginalFileRelativePath(rootFolder, assembly); + return Path.Combine(rootFolder, CompileFolder, relativePath); + } + + private static string GetOriginalFile(string rootFolder, string assembly) + { + string relativePath = GetOriginalFileRelativePath(rootFolder, assembly); + return Path.Combine(rootFolder, relativePath); + } + + private static string GetOriginalFileRelativePath(string rootFolder, string assembly) + { + string relativePath = Path.GetRelativePath(rootFolder, assembly); + if (relativePath.StartsWith(CompileFolder)) + { + relativePath = Path.GetRelativePath(Path.Combine(rootFolder, CompileFolder), assembly); + } + else if (relativePath.StartsWith(BackupFolder)) + { + relativePath = Path.GetRelativePath(Path.Combine(rootFolder, BackupFolder), assembly); + } + return relativePath; + } } } diff --git a/src/coreclr/src/tools/r2rtest/CpaotRunner.cs b/src/coreclr/src/tools/r2rtest/Crossgen2Runner.cs similarity index 86% rename from src/coreclr/src/tools/r2rtest/CpaotRunner.cs rename to src/coreclr/src/tools/r2rtest/Crossgen2Runner.cs index 730ef923c33a3d..a863b238860e98 100644 --- a/src/coreclr/src/tools/r2rtest/CpaotRunner.cs +++ b/src/coreclr/src/tools/r2rtest/Crossgen2Runner.cs @@ -9,11 +9,21 @@ namespace R2RTest { + class Crossgen2RunnerOptions + { + public bool Composite { get; set; } + /// + /// True for scenarios where the composite image has dependencies outside itself that should not be unrooted inputs + /// + public bool PartialComposite { get; set; } + } + /// /// Compiles assemblies using the Cross-Platform AOT compiler /// - class CpaotRunner : CompilerRunner + class Crossgen2Runner : CompilerRunner { + private Crossgen2RunnerOptions Crossgen2RunnerOptions; public override CompilerIndex Index => CompilerIndex.CPAOT; // Crossgen2 runs on top of corerun. @@ -23,10 +33,13 @@ class CpaotRunner : CompilerRunner protected readonly List _referenceFiles = new List(); private string Crossgen2Path => Path.Combine(_options.CoreRootDirectory.FullName, "crossgen2", "crossgen2.dll"); + private bool CompositeMode => Crossgen2RunnerOptions != null ? Crossgen2RunnerOptions.Composite : _options.Composite; - public CpaotRunner(BuildOptions options, IEnumerable references) + public Crossgen2Runner(BuildOptions options, Crossgen2RunnerOptions crossgen2RunnerOptions, IEnumerable references) : base(options, references) { + Crossgen2RunnerOptions = crossgen2RunnerOptions; + // Some scenarios are easier to express when we give Crossgen2 a list of reference assemblies instead of directories, // so allow an override here. foreach (var reference in references) @@ -91,7 +104,7 @@ protected override IEnumerable BuildCommandLineArguments(IEnumerable BuildCommandLineArguments(IEnumerable BuildCommandLineArguments(IEnumerable