Пример #1
0
        public DotNetProjectBuilder(BuildCommandApp args) : base(args.ShouldSkipDependencies)
        {
            _args = args;

            _preconditionManager = new IncrementalPreconditionManager(
                args.ShouldPrintIncrementalPreconditions,
                args.ShouldNotUseIncrementality,
                args.ShouldSkipDependencies);

            _compilerIOManager = new CompilerIOManager(
                args.ConfigValue,
                args.OutputValue,
                args.BuildBasePathValue,
                args.GetRuntimes(),
                args.Workspace
                );

            _incrementalManager = new IncrementalManager(
                this,
                _compilerIOManager,
                _preconditionManager,
                _args.ShouldSkipDependencies,
                _args.ConfigValue,
                _args.BuildBasePathValue,
                _args.OutputValue,
                BuildIncrementalArgumentList(_args)
                );

            _scriptRunner = new ScriptRunner();

            _commandFactory = new DotNetCommandFactory();
        }
Пример #2
0
        public bool Compile(IEnumerable<ProjectContext> contexts, BuildCommandApp args)
        {
            var success = true;

            foreach (var context in contexts)
            {
                success &= _managedCompiler.Compile(context, args);
                if (args.IsNativeValue && success)
                {
                    var runtimeContext = args.Workspace.GetRuntimeContext(context, args.GetRuntimes());
                    success &= _nativeCompiler.Compile(runtimeContext, args);
                }
            }

            return success;
        }
Пример #3
0
        public bool Compile(IEnumerable <ProjectContext> contexts, BuildCommandApp args)
        {
            var success = true;

            foreach (var context in contexts)
            {
                success &= _managedCompiler.Compile(context, args);
                if (args.IsNativeValue && success)
                {
                    var runtimeContext = args.Workspace.GetRuntimeContext(context, args.GetRuntimes());
                    success &= _nativeCompiler.Compile(runtimeContext, args);
                }
            }

            return(success);
        }
Пример #4
0
        private static IEnumerable<ProjectContext> ResolveRootContexts(
            IEnumerable<string> files,
            IEnumerable<NuGetFramework> frameworks,
            BuildCommandApp args)
        {
            List<Task<ProjectContext>> tasks = new List<Task<ProjectContext>>();

            foreach (var file in files)
            {
                Project project;
                using (PerfTrace.Current.CaptureTiming(file, "Loading project.json"))
                {
                    project = args.Workspace.GetProject(file);
                }
                var projectFrameworks = project.GetTargetFrameworks().Select(f => f.FrameworkName);
                if (!projectFrameworks.Any())
                {
                    throw new InvalidOperationException(
                        $"Project '{file}' does not have any frameworks listed in the 'frameworks' section.");
                }
                IEnumerable<NuGetFramework> selectedFrameworks;
                if (frameworks != null)
                {
                    var unsupportedByProject = frameworks.Where(f => !projectFrameworks.Contains(f));
                    if (unsupportedByProject.Any())
                    {
                        throw new InvalidOperationException(
                            $"Project \'{file}\' does not support framework: {string.Join(", ", unsupportedByProject.Select(fx => fx.DotNetFrameworkName))}.");
                    }

                    selectedFrameworks = frameworks;
                }
                else
                {
                    selectedFrameworks = projectFrameworks;
                }

                foreach (var framework in selectedFrameworks)
                {
                    tasks.Add(Task.Run(() => args.Workspace.GetProjectContext(file, framework)));
                }
            }
            using (PerfTrace.Current.CaptureTiming(string.Empty, "Waiting for project contexts to finish loading"))
            {
                return Task.WhenAll(tasks).GetAwaiter().GetResult();
            }
        }
Пример #5
0
        private static bool OnExecute(IEnumerable<string> files, IEnumerable<NuGetFramework> frameworks, BuildCommandApp args)
        {
            var builderCommandApp = args;
            var graphCollector = new ProjectGraphCollector(
                !builderCommandApp.ShouldSkipDependencies,
                (project, target) => args.Workspace.GetProjectContext(project, target));

            IEnumerable<ProjectContext> contexts;
            using (PerfTrace.Current.CaptureTiming(string.Empty, nameof(ResolveRootContexts)))
            {
                contexts = ResolveRootContexts(files, frameworks, args);
            }

            ProjectGraphNode[] graph;
            using (PerfTrace.Current.CaptureTiming(string.Empty, "Collect graph"))
            {
                graph = graphCollector.Collect(contexts).ToArray();
            }
            var builder = new DotNetProjectBuilder(builderCommandApp);
            return builder.Build(graph).ToArray().All(r => r != CompilationResult.Failure);
        }
Пример #6
0
        public static int Run(string[] args, BuildWorkspace workspace)
        {
            DebugHelper.HandleDebugSwitch(ref args);

            try
            {
                var app = new BuildCommandApp(
                    "dotnet build",
                    ".NET Builder",
                    "Builder for the .NET Platform. It performs incremental compilation if it's safe to do so. Otherwise it delegates to dotnet-compile which performs non-incremental compilation",
                    workspace);
                return app.Execute(OnExecute, args);
            }
            catch (Exception ex)
            {
#if DEBUG
                Console.Error.WriteLine(ex);
#else
                Console.Error.WriteLine(ex.Message);
#endif
                return 1;
            }
        }
Пример #7
0
 public abstract bool Compile(ProjectContext context, BuildCommandApp args);
Пример #8
0
        public override bool Compile(ProjectContext context, BuildCommandApp args)
        {
            // Set up Output Paths
            var outputPaths            = context.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue);
            var outputPath             = outputPaths.CompilationOutputPath;
            var intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath;

            Directory.CreateDirectory(outputPath);
            Directory.CreateDirectory(intermediateOutputPath);

            // Create the library exporter
            var exporter = context.CreateExporter(args.ConfigValue, args.BuildBasePathValue);

            // 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 (diagnostics.Any(d => d.Severity == DiagnosticMessageSeverity.Error))
            {
                // We got an unresolved dependency or missing framework. Don't continue the compilation.
                PrintSummary(diagnostics, sw);
                return(false);
            }

            // Get compilation options
            var outputName = outputPaths.CompilationFiles.Assembly;

            // Assemble args
            var compilerArgs = new List <string>()
            {
                $"--temp-output:{intermediateOutputPath}",
                $"--out:{outputName}"
            };

            var compilationOptions = context.ResolveCompilationOptions(args.ConfigValue);

            // Set default platform if it isn't already set and we're on desktop
            if (compilationOptions.EmitEntryPoint == true && string.IsNullOrEmpty(compilationOptions.Platform) && context.TargetFramework.IsDesktop())
            {
                // See https://github.com/dotnet/cli/issues/2428 for more details.
                compilationOptions.Platform = RuntimeInformation.ProcessArchitecture == Architecture.X64 ?
                                              "x64" : "anycpu32bitpreferred";
            }

            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)
            {
                references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath));

                compilerArgs.AddRange(dependency.SourceReferences.Select(s => s.GetTransformedFile(intermediateOutputPath)));

                foreach (var resourceFile in dependency.EmbeddedResources)
                {
                    var transformedResource = resourceFile.GetTransformedFile(intermediateOutputPath);
                    var resourceName        = ResourceManifestName.CreateManifestName(
                        Path.GetFileName(resourceFile.ResolvedPath), compilationOptions.OutputName);
                    compilerArgs.Add($"--resource:\"{transformedResource}\",{resourceName}");
                }

                // 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 allExports        = exporter.GetAllExports().ToList();
                var dependencyContext = new DependencyContextBuilder().Build(compilationOptions,
                                                                             allExports,
                                                                             allExports,
                                                                             false, // For now, just assume non-portable mode in the legacy deps file (this is going away soon anyway)
                                                                             context.TargetFramework,
                                                                             context.RuntimeIdentifier ?? string.Empty);

                var writer       = new DependencyContextWriter();
                var depsJsonFile = Path.Combine(intermediateOutputPath, compilationOptions.OutputName + "dotnet-compile.deps.json");
                using (var fileStream = File.Create(depsJsonFile))
                {
                    writer.Write(dependencyContext, fileStream);
                }

                compilerArgs.Add($"--resource:\"{depsJsonFile}\",{compilationOptions.OutputName}.deps.json");
            }

            if (!AddNonCultureResources(context.ProjectFile, compilerArgs, intermediateOutputPath, compilationOptions))
            {
                return(false);
            }
            // Add project source files
            var sourceFiles = CompilerUtil.GetCompilationSources(context, compilationOptions);

            compilerArgs.AddRange(sourceFiles);

            var compilerName = compilationOptions.CompilerName;

            // Write RSP file
            var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.rsp");

            File.WriteAllLines(rsp, compilerArgs);

            // Run pre-compile event
            var contextVariables = new Dictionary <string, string>()
            {
                { "compile:TargetFramework", context.TargetFramework.GetShortFolderName() },
                { "compile:FullTargetFramework", context.TargetFramework.DotNetFrameworkName },
                { "compile:Configuration", args.ConfigValue },
                { "compile:OutputFile", outputName },
                { "compile:OutputDir", outputPath.TrimEnd('\\', '/') },
                { "compile:ResponseFile", rsp }
            };

            if (context.ProjectFile.HasRuntimeOutput(args.ConfigValue))
            {
                var runtimeContext    = args.Workspace.GetRuntimeContext(context, args.GetRuntimes());
                var runtimeOutputPath = runtimeContext.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue, args.OutputValue);

                contextVariables.Add(
                    "compile:RuntimeOutputDir",
                    runtimeOutputPath.RuntimeOutputPath.TrimEnd('\\', '/'));

                contextVariables.Add(
                    "compile:RuntimeIdentifier",
                    runtimeContext.RuntimeIdentifier);
            }

            _scriptRunner.RunScripts(context, ScriptNames.PreCompile, contextVariables);

            // Cache the reporters before invoking the command in case it is a built-in command, which replaces
            // the static Reporter instances.
            Reporter errorReporter  = Reporter.Error;
            Reporter outputReporter = Reporter.Output;

            CommandResult result = _commandFactory.Create($"compile-{compilerName}", new[] { $"@{rsp}" })
                                   .WorkingDirectory(context.ProjectDirectory)
                                   .OnErrorLine(line => HandleCompilerOutputLine(line, context, diagnostics, errorReporter))
                                   .OnOutputLine(line => HandleCompilerOutputLine(line, context, diagnostics, outputReporter))
                                   .Execute();

            // Run post-compile event
            contextVariables["compile:CompilerExitCode"] = result.ExitCode.ToString();
            _scriptRunner.RunScripts(context, ScriptNames.PostCompile, contextVariables);

            var success = result.ExitCode == 0;

            if (!success)
            {
                Reporter.Error.WriteLine($"{result.StartInfo.FileName} {result.StartInfo.Arguments} returned Exit Code {result.ExitCode}");
            }

            if (success)
            {
                success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, outputPath, compilationOptions);
            }

            return(PrintSummary(diagnostics, sw, success));
        }
Пример #9
0
        public override bool Compile(ProjectContext context, BuildCommandApp args)
        {
            // Set up Output Paths
            var outputPaths = context.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue);
            var outputPath = outputPaths.CompilationOutputPath;
            var intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath;

            Directory.CreateDirectory(outputPath);
            Directory.CreateDirectory(intermediateOutputPath);

            // Create the library exporter
            var exporter = context.CreateExporter(args.ConfigValue, args.BuildBasePathValue);

            // 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(diagnostics.Any(d => d.Severity == DiagnosticMessageSeverity.Error))
            {
                // We got an unresolved dependency or missing framework. Don't continue the compilation.
                PrintSummary(diagnostics, sw);
                return false;
            }

            // Get compilation options
            var outputName = outputPaths.CompilationFiles.Assembly;

            // Assemble args
            var compilerArgs = new List<string>()
            {
                $"--temp-output:{intermediateOutputPath}",
                $"--out:{outputName}"
            };

            var compilationOptions = context.ResolveCompilationOptions(args.ConfigValue);

            // Set default platform if it isn't already set and we're on desktop
            if (compilationOptions.EmitEntryPoint == true && string.IsNullOrEmpty(compilationOptions.Platform) && context.TargetFramework.IsDesktop())
            {
                // See https://github.com/dotnet/cli/issues/2428 for more details.
                compilationOptions.Platform = RuntimeInformation.ProcessArchitecture == Architecture.X64 ?
                    "x64" : "anycpu32bitpreferred";
            }

            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)
            {
                references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath));

                compilerArgs.AddRange(dependency.SourceReferences.Select(s => s.GetTransformedFile(intermediateOutputPath)));

                foreach (var resourceFile in dependency.EmbeddedResources)
                {
                    var transformedResource = resourceFile.GetTransformedFile(intermediateOutputPath);
                    var resourceName = ResourceManifestName.CreateManifestName(
                        Path.GetFileName(resourceFile.ResolvedPath), compilationOptions.OutputName);
                    compilerArgs.Add($"--resource:\"{transformedResource}\",{resourceName}");
                }

                // 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 allExports = exporter.GetAllExports().ToList();
                var exportsLookup = allExports.ToDictionary(e => e.Library.Identity.Name);
                var buildExclusionList = context.GetTypeBuildExclusionList(exportsLookup);
                var filteredExports = allExports
                    .Where(e => e.Library.Identity.Type.Equals(LibraryType.ReferenceAssembly) ||
                        !buildExclusionList.Contains(e.Library.Identity.Name));

                var dependencyContext = new DependencyContextBuilder().Build(compilationOptions,
                    filteredExports,
                    filteredExports,
                    false, // For now, just assume non-portable mode in the legacy deps file (this is going away soon anyway)
                    context.TargetFramework,
                    context.RuntimeIdentifier ?? string.Empty);

                var writer = new DependencyContextWriter();
                var depsJsonFile = Path.Combine(intermediateOutputPath, compilationOptions.OutputName + "dotnet-compile.deps.json");
                using (var fileStream = File.Create(depsJsonFile))
                {
                    writer.Write(dependencyContext, fileStream);
                }

                compilerArgs.Add($"--resource:\"{depsJsonFile}\",{compilationOptions.OutputName}.deps.json");
            }

            if (!AddNonCultureResources(context.ProjectFile, compilerArgs, intermediateOutputPath, compilationOptions))
            {
                return false;
            }
            // Add project source files
            var sourceFiles = CompilerUtil.GetCompilationSources(context, compilationOptions);
            compilerArgs.AddRange(sourceFiles);

            var compilerName = compilationOptions.CompilerName;

            // Write RSP file
            var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.rsp");
            File.WriteAllLines(rsp, compilerArgs);

            // Run pre-compile event
            var contextVariables = new Dictionary<string, string>()
            {
                { "compile:TargetFramework", context.TargetFramework.GetShortFolderName() },
                { "compile:FullTargetFramework", context.TargetFramework.DotNetFrameworkName },
                { "compile:Configuration", args.ConfigValue },
                { "compile:OutputFile", outputName },
                { "compile:OutputDir", outputPath.TrimEnd('\\', '/') },
                { "compile:ResponseFile", rsp }
            };

            if (context.ProjectFile.HasRuntimeOutput(args.ConfigValue))
            {
                var runtimeContext = args.Workspace.GetRuntimeContext(context, args.GetRuntimes());
                var runtimeOutputPath = runtimeContext.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue, args.OutputValue);

                contextVariables.Add(
                    "compile:RuntimeOutputDir",
                    runtimeOutputPath.RuntimeOutputPath.TrimEnd('\\', '/'));

                contextVariables.Add(
                    "compile:RuntimeIdentifier",
                    runtimeContext.RuntimeIdentifier);
            }

            _scriptRunner.RunScripts(context, ScriptNames.PreCompile, contextVariables);

            // Cache the reporters before invoking the command in case it is a built-in command, which replaces
            // the static Reporter instances.
            Reporter errorReporter = Reporter.Error;
            Reporter outputReporter = Reporter.Output;

            CommandResult result = _commandFactory.Create($"compile-{compilerName}", new[] { $"@{rsp}" })
                .WorkingDirectory(context.ProjectDirectory)
                .OnErrorLine(line => HandleCompilerOutputLine(line, context, diagnostics, errorReporter))
                .OnOutputLine(line => HandleCompilerOutputLine(line, context, diagnostics, outputReporter))
                .Execute();

            // Run post-compile event
            contextVariables["compile:CompilerExitCode"] = result.ExitCode.ToString();
            _scriptRunner.RunScripts(context, ScriptNames.PostCompile, contextVariables);

            var success = result.ExitCode == 0;

            if (!success)
            {
                Reporter.Error.WriteLine($"{result.StartInfo.FileName} {result.StartInfo.Arguments} returned Exit Code {result.ExitCode}");
            }

            if (success)
            {
                success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, outputPath, compilationOptions);
            }

            return PrintSummary(diagnostics, sw, success);
        }
Пример #10
0
 public abstract bool Compile(ProjectContext context, BuildCommandApp args);
Пример #11
0
 private static IDictionary<string, string> BuildIncrementalArgumentList(BuildCommandApp args) => new Dictionary<string, string>()
 {
     ["version-suffix"] = args.VersionSuffixValue
 };