public static int CompileFramework(BuildOptions options) { if (options.CoreRootDirectory == null) { Console.Error.WriteLine("--core-root-directory (--cr) is a required argument."); return(1); } string logsFolder = Path.Combine(options.CoreRootDirectory.FullName, "logs"); Directory.CreateDirectory(logsFolder); options.OutputDirectory = new DirectoryInfo(logsFolder); options.Framework = true; options.NoJit = true; options.NoEtw = true; options.NoExe = true; IEnumerable <CompilerRunner> runners = options.CompilerRunners(isFramework: false); BuildFolderSet folderSet = new BuildFolderSet(Array.Empty <BuildFolder>(), runners, options); bool success = folderSet.Build(); folderSet.WriteLogs(); return(success ? 0 : 1); }
public static int CompileDirectory(BuildOptions options) { if (options.InputDirectory == null) { Console.Error.WriteLine("--input-directory is a required argument."); return(1); } if (options.CoreRootDirectory == null) { Console.Error.WriteLine("--core-root-directory (--cr) is a required argument."); return(1); } if (options.OutputDirectory == null) { options.OutputDirectory = options.InputDirectory; } if (options.OutputDirectory.IsParentOf(options.InputDirectory)) { Console.Error.WriteLine("Error: Input and output folders must be distinct, and the output directory (which gets deleted) better not be a parent of the input directory."); return(1); } IEnumerable <CompilerRunner> runners = options.CompilerRunners(isFramework: false); if (!options.Exe) { PathExtensions.DeleteOutputFolders(options.OutputDirectory.FullName, options.CoreRootDirectory.FullName, runners, recursive: false); } BuildFolder folder = BuildFolder.FromDirectory(options.InputDirectory.FullName, runners, options.OutputDirectory.FullName, options); if (folder == null) { Console.Error.WriteLine($"No managed app found in {options.InputDirectory.FullName}"); } BuildFolderSet folderSet = new BuildFolderSet(new BuildFolder[] { folder }, runners, options); bool success = folderSet.Build(); folderSet.WriteLogs(); if (!options.NoCleanup && !options.Exe) { PathExtensions.DeleteOutputFolders(options.OutputDirectory.FullName, options.CoreRootDirectory.FullName, runners, recursive: false); } return(success ? 0 : 1); }
public static int CompileSubtree(BuildOptions options) { if (options.InputDirectory == null) { Console.WriteLine("--input-directory is a required argument."); return(1); } if (options.CoreRootDirectory == null) { Console.Error.WriteLine("--core-root-directory (--cr) is a required argument."); return(1); } if (options.OutputDirectory == null) { options.OutputDirectory = options.InputDirectory; } if (options.OutputDirectory.IsParentOf(options.InputDirectory)) { Console.WriteLine("Error: Input and output folders must be distinct, and the output directory (which gets deleted) better not be a parent of the input directory."); return(1); } IEnumerable <CompilerRunner> runners = options.CompilerRunners(isFramework: false); if (!options.Exe) { PathExtensions.DeleteOutputFolders(options.OutputDirectory.FullName, options.CoreRootDirectory.FullName, runners, recursive: true); } string[] directories = LocateSubtree(options.InputDirectory.FullName, options.CoreRootDirectory.FullName).ToArray(); ConcurrentBag <BuildFolder> folders = new ConcurrentBag <BuildFolder>(); int relativePathOffset = options.InputDirectory.FullName.Length; if (relativePathOffset > 0 && options.InputDirectory.FullName[relativePathOffset - 1] != Path.DirectorySeparatorChar) { relativePathOffset++; } int folderCount = 0; int compilationCount = 0; int executionCount = 0; Parallel.ForEach(directories, (string directory) => { string outputDirectoryPerFolder = options.OutputDirectory.FullName; if (directory.Length > relativePathOffset) { outputDirectoryPerFolder = Path.Combine(outputDirectoryPerFolder, directory.Substring(relativePathOffset)); } try { BuildFolder folder = BuildFolder.FromDirectory(directory.ToString(), runners, outputDirectoryPerFolder, options); if (folder != null) { folders.Add(folder); Interlocked.Add(ref compilationCount, folder.Compilations.Count); Interlocked.Add(ref executionCount, folder.Executions.Count); } } catch (Exception ex) { Console.Error.WriteLine("Error scanning folder {0}: {1}", directory, ex.Message); } int currentCount = Interlocked.Increment(ref folderCount); if (currentCount % 100 == 0) { StringBuilder lineReport = new StringBuilder(); lineReport.Append($@"Found {folders.Count} folders to build "); lineReport.Append($@"({compilationCount} compilations, "); if (!options.NoExe) { lineReport.Append($@"{executionCount} executions, "); } lineReport.Append($@"{currentCount} / {directories.Length} folders scanned)"); Console.WriteLine(lineReport.ToString()); } }); Console.Write($@"Found {folders.Count} folders to build ({compilationCount} compilations, "); if (!options.NoExe) { Console.Write($@"{executionCount} executions, "); } Console.WriteLine($@"{directories.Length} folders scanned)"); BuildFolderSet folderSet = new BuildFolderSet(folders, runners, options); bool success = folderSet.Build(); folderSet.WriteLogs(); if (!options.NoCleanup) { PathExtensions.DeleteOutputFolders(options.OutputDirectory.FullName, options.CoreRootDirectory.FullName, runners, recursive: true); } return(success ? 0 : 1); }
public static int CompileNuget(BuildOptions options) { if (options.CoreRootDirectory == null) { Console.Error.WriteLine("--core-root-directory (--cr) is a required argument."); return(1); } // We don't want to launch these apps when building the folder set below options.NoExe = true; options.NoJit = true; options.InputDirectory = options.OutputDirectory; IList <string> packageList = ReadPackageNames(options.PackageList.FullName); if (options.OutputDirectory == null) { Console.Error.WriteLine("--output-directory is a required argument."); return(1); } IEnumerable <string> referencePaths = options.ReferencePaths(); IEnumerable <CompilerRunner> runners = options.CompilerRunners(false); if (!options.Exe) { PathExtensions.DeleteOutputFolders(options.OutputDirectory.FullName, options.CoreRootDirectory.FullName, runners, recursive: false); } string nugetOutputFolder = Path.Combine(options.OutputDirectory.FullName, "nuget.out"); Directory.CreateDirectory(nugetOutputFolder); var publishedAppFoldersToCompile = new List <BuildFolder>(); using (StreamWriter nugetLog = File.CreateText(Path.Combine(nugetOutputFolder, "nugetLog.txt"))) { foreach (var package in packageList) { nugetLog.WriteLine($"Creating empty app for {package}"); // Create an app folder string appFolder = Path.Combine(nugetOutputFolder, $"{package}.TestApp"); Directory.CreateDirectory(appFolder); int exitCode = DotnetCli.New(appFolder, "console", nugetLog); if (exitCode != 0) { nugetLog.WriteLine($"dotnet new console for {package} failed with exit code {exitCode}"); continue; } exitCode = DotnetCli.AddPackage(appFolder, package, nugetLog); if (exitCode != 0) { nugetLog.WriteLine($"dotnet add package {package} failed with exit code {exitCode}"); continue; } exitCode = DotnetCli.Publish(appFolder, nugetLog); if (exitCode != 0) { nugetLog.WriteLine($"dotnet publish failed with exit code {exitCode}"); continue; } // This is not a reliable way of building the publish folder string publishFolder = Path.Combine(appFolder, @"artifacts\Debug\net5.0\publish"); if (!Directory.Exists(publishFolder)) { nugetLog.WriteLine($"Could not find folder {publishFolder} containing the published app."); continue; } publishedAppFoldersToCompile.Add(BuildFolder.FromDirectory(publishFolder, runners, appFolder, options)); } BuildFolderSet folderSet = new BuildFolderSet(publishedAppFoldersToCompile, runners, options); bool success = folderSet.Build(); folderSet.WriteLogs(); if (!options.NoCleanup && !options.Exe) { PathExtensions.DeleteOutputFolders(options.OutputDirectory.FullName, options.CoreRootDirectory.FullName, runners, recursive: false); } return(success ? 0 : 1); } }
/// <summary> /// Utility mode that allows compilation of a set of assemblies using their existing Crossgen response files. /// This is currently useful for workloads like Bing which have a large complicated web of binaries in different folders /// with potentially different sets of reference paths used for different assemblies. /// </summary> public static int CompileFromCrossgenRsp(BuildOptions options) { if (options.CrossgenResponseFile == null && options.InputDirectory == null) { Console.Error.WriteLine("Specify --response-file or --input-directory containing multiple response files."); return(1); } if (options.CoreRootDirectory == null) { Console.Error.WriteLine("--core-root-directory (--cr) is a required argument."); return(1); } if (options.OutputDirectory == null) { if (options.InputDirectory != null) { options.OutputDirectory = options.InputDirectory; } else { options.OutputDirectory = new DirectoryInfo(Path.GetDirectoryName(options.CrossgenResponseFile.FullName)); } } else if (options.InputDirectory != null && options.OutputDirectory.IsParentOf(options.InputDirectory)) { Console.Error.WriteLine("Error: Input and output folders must be distinct, and the output directory (which gets deleted) better not be a parent of the input directory."); return(1); } // 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; // // Determine whether we're compiling a single .rsp or a folder of them // var responseFiles = new List <string>(); if (options.CrossgenResponseFile != null) { responseFiles.Add(options.CrossgenResponseFile.FullName); } else { responseFiles = Directory.EnumerateFiles(options.InputDirectory.FullName, "*.rsp", SearchOption.TopDirectoryOnly).ToList(); } Dictionary <string, string> pathReplacements = new Dictionary <string, string>(); if ((options.RewriteOldPath == null) != (options.RewriteNewPath == null)) { Console.Error.WriteLine("Error: --rewrite-old-path and --rewrite-new-path must both be specified if either is used."); return(1); } if (options.RewriteOldPath != null && options.RewriteNewPath != null) { if (options.RewriteOldPath.Length != options.RewriteNewPath.Length) { Console.Error.WriteLine("Error: --rewrite-old-path and --rewrite-new-path were specified a different number of times."); return(1); } for (int i = 0; i < options.RewriteNewPath.Length; i++) { pathReplacements.Add(options.RewriteOldPath[i].FullName, options.RewriteNewPath[i].FullName); Console.WriteLine($"Re-writing path {options.RewriteOldPath[i].FullName} as {options.RewriteNewPath[i].FullName}"); } } bool success = true; int compilationFailures = 0; int totalCompilations = 0; // Collect all the compilations first foreach (var inputRsp in responseFiles) { var crossgenArguments = CrossgenArguments.ParseFromResponseFile(inputRsp) .ReplacePaths(pathReplacements); Console.WriteLine($"{inputRsp} -> {crossgenArguments.InputFile}"); var compilerRunners = options.CompilerRunners(false, crossgenArguments.ReferencePaths); string responseFileOuputPath = Path.Combine(options.OutputDirectory.FullName, Path.GetFileNameWithoutExtension(inputRsp)); responseFileOuputPath.RecreateDirectory(); List <ProcessInfo> fileCompilations = new List <ProcessInfo>(); foreach (CompilerRunner runner in compilerRunners) { var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, responseFileOuputPath, new string[] { crossgenArguments.InputFile })); fileCompilations.Add(compilationProcess); } ParallelRunner.Run(fileCompilations, options.DegreeOfParallelism); totalCompilations++; foreach (var compilationProcess in fileCompilations) { if (!compilationProcess.Succeeded) { success = false; compilationFailures++; Console.WriteLine($"Failed compiling {compilationProcess.Parameters.OutputFileName}"); } } } Console.WriteLine("Rsp Compilation Results"); Console.WriteLine($"Total compilations: {totalCompilations}"); Console.WriteLine($"Compilation failures: {compilationFailures}"); return(success ? 0 : 1); }