public CompileContext(ProjectContext rootProject, BuilderCommandApp args) { _rootProject = rootProject; // Cleaner to clone the args and mutate the clone than have separate CompileContext fields for mutated args // and then reasoning which ones to get from args and which ones from fields. _args = (BuilderCommandApp)args.ShallowCopy(); // Set up Output Paths. They are unique per each CompileContext var outputPathCalculator = _rootProject.GetOutputPathCalculator(_args.OutputValue); _args.OutputValue = outputPathCalculator.BaseCompilationOutputPath; _args.IntermediateValue = outputPathCalculator.GetIntermediateOutputDirectoryPath(_args.ConfigValue, _args.IntermediateValue); // Set up dependencies _dependencies = new ProjectDependenciesFacade(_rootProject, _args.ConfigValue); // gather preconditions _preconditions = GatherIncrementalPreconditions(); }
// computes all the inputs and outputs that would be used in the compilation of a project // ensures that all paths are files // ensures no missing inputs public static CompilerIO GetCompileIO( ProjectContext project, string buildConfiguration, string outputPath, string intermediaryOutputPath, ProjectDependenciesFacade dependencies) { var compilerIO = new CompilerIO(new List<string>(), new List<string>()); var calculator = project.GetOutputPathCalculator(outputPath); var binariesOutputPath = calculator.GetOutputDirectoryPath(buildConfiguration); // input: project.json compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath); // input: lock file; find when dependencies change AddLockFile(project, compilerIO); // input: source files compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project)); // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile // input: dependencies AddDependencies(dependencies, compilerIO); // output: compiler outputs foreach (var path in calculator.GetBuildOutputs(buildConfiguration)) { compilerIO.Outputs.Add(path); } // input compilation options files AddCompilationOptions(project, buildConfiguration, compilerIO); // input / output: resources without culture AddCultureResources(project, intermediaryOutputPath, compilerIO); // input / output: resources with culture AddNonCultureResources(project, binariesOutputPath, compilerIO); return compilerIO; }
/// <summary> /// Publish the project for given 'framework (ex - dnxcore50)' and 'runtimeID (ex - win7-x64)' /// </summary> /// <param name="context">project that is to be published</param> /// <param name="baseOutputPath">Location of published files</param> /// <param name="configuration">Debug or Release</param> /// <param name="nativeSubdirectories"></param> /// <returns>Return 0 if successful else return non-zero</returns> private static bool PublishProjectContext(ProjectContext context, string baseOutputPath, string configuration, bool nativeSubdirectories) { Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}"); var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); var outputPathCalculator = context.GetOutputPathCalculator(baseOutputPath); var outputPath = outputPathCalculator.GetCompilationOutputPath(configuration); var contextVariables = new Dictionary<string, string> { { "publish:ProjectPath", context.ProjectDirectory }, { "publish:Configuration", configuration }, { "publish:OutputPath", outputPath }, { "publish:PublishOutputPath", outputPathCalculator.BaseCompilationOutputPath }, { "publish:Framework", context.TargetFramework.Framework }, { "publish:Runtime", context.RuntimeIdentifier }, }; RunScripts(context, ScriptNames.PrePublish, contextVariables); if (!Directory.Exists(outputPathCalculator.BaseCompilationOutputPath)) { Directory.CreateDirectory(outputPathCalculator.BaseCompilationOutputPath); } // Compile the project (and transitively, all it's dependencies) var result = Command.Create("dotnet-build", new string[] { "--framework", $"{context.TargetFramework.DotNetFrameworkName}", "--output", $"{outputPathCalculator.BaseCompilationOutputPath}", "--configuration", $"{configuration}", "--no-host", $"{context.ProjectFile.ProjectDirectory}" }) .ForwardStdErr() .ForwardStdOut() .Execute(); if (result.ExitCode != 0) { return false; } // Use a library exporter to collect publish assets var exporter = context.CreateExporter(configuration); foreach (var export in exporter.GetAllExports()) { // Skip copying project references if (export.Library is ProjectDescription) { continue; } Reporter.Verbose.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ..."); PublishFiles(export.RuntimeAssemblies, outputPath, false); PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories); } CopyContents(context, outputPath); // Publish a host if this is an application if (options.EmitEntryPoint.GetValueOrDefault()) { Reporter.Verbose.WriteLine($"Making {context.ProjectFile.Name.Cyan()} runnable ..."); PublishHost(context, outputPath); } RunScripts(context, ScriptNames.PostPublish, contextVariables); Reporter.Output.WriteLine($"Published to {outputPath}".Green().Bold()); return true; }
private static int RunConsole(ProjectContext projectContext, CommandLineApplication app, string testRunner) { var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(Constants.DefaultConfiguration) }; commandArgs.AddRange(app.RemainingArguments); return Command.CreateDotNet($"{GetCommandName(testRunner)}", commandArgs, projectContext.TargetFramework) .ForwardStdErr() .ForwardStdOut() .Execute() .ExitCode; }
private static void HandleTestExecutionStartMessage(string testRunner, Message message, ReportingChannel channel, ProjectContext projectContext) { TestHostTracing.Source.TraceInformation("Starting Execution"); var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(Constants.DefaultConfiguration) }; commandArgs.AddRange(new[] { "--designtime" }); var tests = message.Payload?.ToObject<RunTestsMessage>().Tests; if (tests != null) { foreach (var test in tests) { commandArgs.Add("--test"); commandArgs.Add(test); } } ExecuteRunnerCommand(testRunner, channel, commandArgs); channel.Send(new Message() { MessageType = "TestExecution.Response", }); TestHostTracing.Source.TraceInformation("Completed Execution"); }
private static void HandleTestDiscoveryStartMessage(string testRunner, ReportingChannel channel, ProjectContext projectContext) { TestHostTracing.Source.TraceInformation("Starting Discovery"); var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(Constants.DefaultConfiguration) }; commandArgs.AddRange(new[] { "--list", "--designtime" }); ExecuteRunnerCommand(testRunner, channel, commandArgs); channel.Send(new Message() { MessageType = "TestDiscovery.Response", }); TestHostTracing.Source.TraceInformation("Completed Discovery"); }
// computes all the inputs and outputs that would be used in the compilation of a project // ensures that all paths are files // ensures no missing inputs public static CompilerIO GetCompileIO(ProjectContext project, string config, string outputPath, string intermediaryOutputPath, ProjectDependenciesFacade dependencies) { var compilerIO = new CompilerIO(new List<string>(), new List<string>()); var binariesOutputPath = project.GetOutputPathCalculator(outputPath).GetCompilationOutputPath(config); var compilationOutput = CompilerUtil.GetCompilationOutput(project.ProjectFile, project.TargetFramework, config, binariesOutputPath); // input: project.json compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath); // input: lock file; find when dependencies change AddLockFile(project, compilerIO); // input: source files compilerIO.Inputs.AddRange(CompilerUtil.GetCompilationSources(project)); // todo: Factor out dependency resolution between Build and Compile. Ideally Build injects the dependencies into Compile // input: dependencies AddDependencies(dependencies, compilerIO); // output: compiler output compilerIO.Outputs.Add(compilationOutput); // input / output: compilation options files AddFilesFromCompilationOptions(project, config, compilationOutput, compilerIO); // input / output: resources without culture AddCultureResources(project, intermediaryOutputPath, compilerIO); // input / output: resources with culture AddNonCultureResources(project, binariesOutputPath, compilerIO); return compilerIO; }
private static bool CompileNative( ProjectContext context, CompilerCommandApp args) { var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue); var outputPath = outputPathCalculator.GetCompilationOutputPath(args.ConfigValue); var nativeOutputPath = Path.Combine(outputPath, "native"); var intermediateOutputPath = outputPathCalculator.GetIntermediateOutputPath(args.ConfigValue, args.IntermediateValue); var nativeIntermediateOutputPath = Path.Combine(intermediateOutputPath, "native"); Directory.CreateDirectory(nativeOutputPath); Directory.CreateDirectory(nativeIntermediateOutputPath); var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, args.ConfigValue); var managedOutput = CompilerUtil.GetCompilationOutput(context.ProjectFile, context.TargetFramework, args.ConfigValue, outputPath); var nativeArgs = new List<string>(); // Input Assembly nativeArgs.Add($"{managedOutput}"); // ILC Args if (!string.IsNullOrWhiteSpace(args.IlcArgsValue)) { nativeArgs.Add("--ilcargs"); nativeArgs.Add($"{args.IlcArgsValue}"); } // ILC Path if (!string.IsNullOrWhiteSpace(args.IlcPathValue)) { nativeArgs.Add("--ilcpath"); nativeArgs.Add(args.IlcPathValue); } // ILC SDK Path if (!string.IsNullOrWhiteSpace(args.IlcSdkPathValue)) { nativeArgs.Add("--ilcsdkpath"); nativeArgs.Add(args.IlcSdkPathValue); } // AppDep SDK Path if (!string.IsNullOrWhiteSpace(args.AppDepSdkPathValue)) { nativeArgs.Add("--appdepsdk"); nativeArgs.Add(args.AppDepSdkPathValue); } // CodeGen Mode if(args.IsCppModeValue) { nativeArgs.Add("--mode"); nativeArgs.Add("cpp"); } if (!string.IsNullOrWhiteSpace(args.CppCompilerFlagsValue)) { nativeArgs.Add("--cppcompilerflags"); nativeArgs.Add(args.CppCompilerFlagsValue); } // Configuration if (args.ConfigValue != null) { nativeArgs.Add("--configuration"); nativeArgs.Add(args.ConfigValue); } // Architecture if (args.ArchValue != null) { nativeArgs.Add("--arch"); nativeArgs.Add(args.ArchValue); } // Intermediate Path nativeArgs.Add("--temp-output"); nativeArgs.Add($"{nativeIntermediateOutputPath}"); // Output Path nativeArgs.Add("--output"); nativeArgs.Add($"{nativeOutputPath}"); // Write Response File var rsp = Path.Combine(nativeIntermediateOutputPath, $"dotnet-compile-native.{context.ProjectFile.Name}.rsp"); File.WriteAllLines(rsp, nativeArgs); // TODO Add -r assembly.dll for all Nuget References // Need CoreRT Framework published to nuget // Do Native Compilation var result = Command.Create("dotnet-compile-native", new string[] { "--rsp", $"{rsp}" }) .ForwardStdErr() .ForwardStdOut() .Execute(); return result.ExitCode == 0; }
private static bool CompileProject(ProjectContext context, CompilerCommandApp args) { // Set up Output Paths var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue); var outputPath = outputPathCalculator.GetCompilationOutputPath(args.ConfigValue); var intermediateOutputPath = outputPathCalculator.GetIntermediateOutputPath(args.ConfigValue, args.IntermediateValue); Directory.CreateDirectory(outputPath); Directory.CreateDirectory(intermediateOutputPath); // Create the library exporter var exporter = context.CreateExporter(args.ConfigValue); // Gather exports for the project var dependencies = exporter.GetDependencies().ToList(); Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}"); var sw = Stopwatch.StartNew(); var diagnostics = new List<DiagnosticMessage>(); var missingFrameworkDiagnostics = new List<DiagnosticMessage>(); // Collect dependency diagnostics foreach (var diag in context.LibraryManager.GetAllDiagnostics()) { if (diag.ErrorCode == ErrorCodes.DOTNET1011 || diag.ErrorCode == ErrorCodes.DOTNET1012) { missingFrameworkDiagnostics.Add(diag); } diagnostics.Add(diag); } if (missingFrameworkDiagnostics.Count > 0) { // The framework isn't installed so we should short circuit the rest of the compilation // so we don't get flooded with errors PrintSummary(missingFrameworkDiagnostics, sw); return false; } // Get compilation options var outputName = CompilerUtil.GetCompilationOutput(context.ProjectFile, context.TargetFramework, args.ConfigValue, outputPath); // Assemble args var compilerArgs = new List<string>() { $"--temp-output:\"{intermediateOutputPath}\"", $"--out:\"{outputName}\"" }; var compilationOptions = CompilerUtil.ResolveCompilationOptions(context, args.ConfigValue); var languageId = CompilerUtil.ResolveLanguageId(context); var references = new List<string>(); // Add compilation options to the args compilerArgs.AddRange(compilationOptions.SerializeToArgs()); // Add metadata options compilerArgs.AddRange(AssemblyInfoOptions.SerializeToArgs(AssemblyInfoOptions.CreateForProject(context))); foreach (var dependency in dependencies) { var projectDependency = dependency.Library as ProjectDescription; if (projectDependency != null) { if (projectDependency.Project.Files.SourceFiles.Any()) { var projectOutputPath = CompilerUtil.GetCompilationOutput(projectDependency.Project, projectDependency.Framework, args.ConfigValue, outputPath); references.Add(projectOutputPath); } } else { references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath)); } compilerArgs.AddRange(dependency.SourceReferences.Select(s => $"\"{s}\"")); // Add analyzer references compilerArgs.AddRange(dependency.AnalyzerReferences .Where(a => a.AnalyzerLanguage == languageId) .Select(a => $"--analyzer:\"{a.AssemblyPath}\"")); } compilerArgs.AddRange(references.Select(r => $"--reference:\"{r}\"")); if (compilationOptions.PreserveCompilationContext == true) { var dependencyContext = DependencyContextBuilder.Build(compilationOptions, exporter, args.ConfigValue, context.TargetFramework, context.RuntimeIdentifier); var writer = new DependencyContextWriter(); var depsJsonFile = Path.Combine(intermediateOutputPath, context.ProjectFile.Name + "dotnet-compile.deps.json"); using (var fileStream = File.Create(depsJsonFile)) { writer.Write(dependencyContext, fileStream); } compilerArgs.Add($"--resource:\"{depsJsonFile},{context.ProjectFile.Name}.deps.json\""); var refsFolder = Path.Combine(outputPath, "refs"); if (Directory.Exists(refsFolder)) { Directory.Delete(refsFolder, true); } Directory.CreateDirectory(refsFolder); foreach (var reference in references) { File.Copy(reference, Path.Combine(refsFolder, Path.GetFileName(reference))); } } if (!AddNonCultureResources(context.ProjectFile, compilerArgs, intermediateOutputPath)) { return false; } // Add project source files var sourceFiles = CompilerUtil.GetCompilationSources(context); compilerArgs.AddRange(sourceFiles); var compilerName = CompilerUtil.ResolveCompilerName(context); // Write RSP file var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.{context.ProjectFile.Name}.rsp"); File.WriteAllLines(rsp, compilerArgs); // Run pre-compile event var contextVariables = new Dictionary<string, string>() { { "compile:TargetFramework", context.TargetFramework.DotNetFrameworkName }, { "compile:Configuration", args.ConfigValue }, { "compile:OutputFile", outputName }, { "compile:OutputDir", outputPath }, { "compile:ResponseFile", rsp } }; RunScripts(context, ScriptNames.PreCompile, contextVariables); var result = Command.Create($"dotnet-compile-{compilerName}", new string[] {"@" + $"{rsp}" }) .OnErrorLine(line => { var diagnostic = ParseDiagnostic(context.ProjectDirectory, line); if (diagnostic != null) { diagnostics.Add(diagnostic); } else { Reporter.Error.WriteLine(line); } }) .OnOutputLine(line => { var diagnostic = ParseDiagnostic(context.ProjectDirectory, line); if (diagnostic != null) { diagnostics.Add(diagnostic); } else { Reporter.Output.WriteLine(line); } }).Execute(); // Run post-compile event contextVariables["compile:CompilerExitCode"] = result.ExitCode.ToString(); RunScripts(context, ScriptNames.PostCompile, contextVariables); var success = result.ExitCode == 0; if (success) { success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, outputPath); } bool generateBindingRedirects = false; if (success && !args.NoHostValue && compilationOptions.EmitEntryPoint.GetValueOrDefault()) { generateBindingRedirects = true; var rids = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers(); var runtimeContext = ProjectContext.Create(context.ProjectDirectory, context.TargetFramework, rids); runtimeContext .MakeCompilationOutputRunnable(outputPath, args.ConfigValue); } else if (!string.IsNullOrEmpty(context.ProjectFile.TestRunner)) { generateBindingRedirects = true; var projectContext = ProjectContext.Create(context.ProjectDirectory, context.TargetFramework, new[] { PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier()}); projectContext .CreateExporter(args.ConfigValue) .GetDependencies(LibraryType.Package) .WriteDepsTo(Path.Combine(outputPath, projectContext.ProjectFile.Name + FileNameSuffixes.Deps)); } if (generateBindingRedirects && context.TargetFramework.IsDesktop()) { context.GenerateBindingRedirects(exporter, outputName); } return PrintSummary(diagnostics, sw, success); }