From 197a02807f53e7be80c53e6a3650fbcc5cf87c52 Mon Sep 17 00:00:00 2001 From: Mihai Codoban Date: Mon, 14 Dec 2015 15:44:58 -0800 Subject: [PATCH 1/2] Command knows its command resolution strategy A command may be resolved from a nuget package, from the executing assembly directory, or from the path. --- src/Microsoft.DotNet.Cli.Utils/Command.cs | 44 ++++++++++++++++++----- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.DotNet.Cli.Utils/Command.cs b/src/Microsoft.DotNet.Cli.Utils/Command.cs index 11c2d9d27..c5997c5c7 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Command.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Command.cs @@ -21,9 +21,24 @@ namespace Microsoft.DotNet.Cli.Utils private readonly StreamForwarder _stdOut; private readonly StreamForwarder _stdErr; + public enum CommandResolutionStrategy + { + //command loaded from a nuget package + NugetPackage, + + //command loaded from the same directory as the executing assembly + BaseDirectory, + + //command loaded from path + Path, + + //command not found + None + } + private bool _running = false; - private Command(string executable, string args) + private Command(string executable, string args, CommandResolutionStrategy commandResolution) { // Set the things we need var psi = new ProcessStartInfo() @@ -41,6 +56,8 @@ namespace Microsoft.DotNet.Cli.Utils _stdOut = new StreamForwarder(); _stdErr = new StreamForwarder(); + + CommandResolution = commandResolution; } public static Command Create(string executable, IEnumerable args, NuGetFramework framework = null) @@ -50,20 +67,25 @@ namespace Microsoft.DotNet.Cli.Utils public static Command Create(string executable, string args, NuGetFramework framework = null) { - ResolveExecutablePath(ref executable, ref args, framework); - return new Command(executable, args); + var commandResolution = CommandResolutionStrategy.None; + + ResolveExecutablePath(ref executable, ref args, ref commandResolution, framework); + + return new Command(executable, args, commandResolution); } - private static void ResolveExecutablePath(ref string executable, ref string args, NuGetFramework framework = null) + private static void ResolveExecutablePath(ref string executable, ref string args, ref CommandResolutionStrategy commandResolution, NuGetFramework framework = null) { executable = - ResolveExecutablePathFromProject(executable, framework) ?? - ResolveExecutableFromPath(executable, ref args); + ResolveExecutablePathFromProject(executable, framework, ref commandResolution) ?? + ResolveExecutableFromPath(executable, ref args, ref commandResolution); } - private static string ResolveExecutableFromPath(string executable, ref string args) + private static string ResolveExecutableFromPath(string executable, ref string args, ref CommandResolutionStrategy commandResolution) { + commandResolution = CommandResolutionStrategy.Path; + foreach (string suffix in Constants.RunnableSuffixes) { var fullExecutable = Path.GetFullPath(Path.Combine( @@ -72,6 +94,8 @@ namespace Microsoft.DotNet.Cli.Utils if (File.Exists(fullExecutable)) { executable = fullExecutable; + + commandResolution = CommandResolutionStrategy.BaseDirectory; // In priority order we've found the best runnable extension, so break. break; @@ -93,7 +117,7 @@ namespace Microsoft.DotNet.Cli.Utils return executable; } - private static string ResolveExecutablePathFromProject(string executable, NuGetFramework framework) + private static string ResolveExecutablePathFromProject(string executable, NuGetFramework framework, ref CommandResolutionStrategy commandResolution) { if (framework == null) return null; @@ -125,6 +149,8 @@ namespace Microsoft.DotNet.Cli.Utils var commandPath = commandPackage.Library.Files .First(f => Path.GetFileName(f) == commandName + FileNameSuffixes.DotNet.Exe); + commandResolution = CommandResolutionStrategy.NugetPackage; + return Path.Combine(projectContext.PackagesDirectory, commandPackage.Path, commandPath); } @@ -286,6 +312,8 @@ namespace Microsoft.DotNet.Cli.Utils return this; } + public CommandResolutionStrategy CommandResolution { get; } + private string FormatProcessInfo(ProcessStartInfo info) { if (string.IsNullOrWhiteSpace(info.Arguments)) From 110b30ccdc3c1622bd7c457f107abfcd0de58b6d Mon Sep 17 00:00:00 2001 From: Mihai Codoban Date: Thu, 10 Dec 2015 13:06:33 -0800 Subject: [PATCH 2/2] Extract build from compile Build becomes the new compile. It decides which project to compile and how. It checks for incremental preconditions Compile's resonsibility is trimmed down to only knowing how to invoke the compiler on a project --- Microsoft.DotNet.Cli.sln | 21 +- packaging/osx/scripts/postinstall | 1 + scripts/build/build-stage.ps1 | 1 + scripts/build/build-stage.sh | 1 + scripts/compile.ps1 | 2 +- src/Microsoft.DotNet.Cli.Utils/Command.cs | 30 +- .../ProjectContextExtensions.cs | 67 +++ .../BuilderCommandApp.cs | 19 + .../CompileContext.cs | 253 +++++++++++ .../IncrementalPreconditions.cs | 79 ++++ .../Microsoft.DotNet.Tools.Builder.xproj | 20 + src/Microsoft.DotNet.Tools.Builder/Program.cs | 45 ++ src/Microsoft.DotNet.Tools.Builder/README.md | 32 ++ .../project.json | 33 ++ .../CompilerCommandApp.cs | 144 ++++++ .../CompilerUtil.cs | 121 +++++ .../Program.cs | 429 +++++------------- src/Microsoft.DotNet.Tools.Compiler/README.md | 8 +- src/Microsoft.DotNet.Tools.Pack/Program.cs | 2 +- .../PublishCommand.cs | 2 +- src/Microsoft.DotNet.Tools.Run/RunCommand.cs | 2 +- test/E2E/E2ETest.cs | 6 +- 22 files changed, 968 insertions(+), 350 deletions(-) create mode 100644 src/Microsoft.DotNet.Cli.Utils/ProjectContextExtensions.cs create mode 100644 src/Microsoft.DotNet.Tools.Builder/BuilderCommandApp.cs create mode 100644 src/Microsoft.DotNet.Tools.Builder/CompileContext.cs create mode 100644 src/Microsoft.DotNet.Tools.Builder/IncrementalPreconditions.cs create mode 100644 src/Microsoft.DotNet.Tools.Builder/Microsoft.DotNet.Tools.Builder.xproj create mode 100644 src/Microsoft.DotNet.Tools.Builder/Program.cs create mode 100644 src/Microsoft.DotNet.Tools.Builder/README.md create mode 100644 src/Microsoft.DotNet.Tools.Builder/project.json create mode 100644 src/Microsoft.DotNet.Tools.Compiler/CompilerCommandApp.cs create mode 100644 src/Microsoft.DotNet.Tools.Compiler/CompilerUtil.cs diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index 3459dd71c..bbf24bd68 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Cli", "src\Microsoft.DotNet.Cli\Microsoft.DotNet.Cli.xproj", "{60CF7E6C-D6C8-439D-B7B7-D8A27E29BE2C}" EndProject @@ -61,6 +61,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0722D325 EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MultiProjectValidator", "tools\MultiProjectValidator\MultiProjectValidator.xproj", "{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Tools.Builder", "src\Microsoft.DotNet.Tools.Builder\Microsoft.DotNet.Tools.Builder.xproj", "{0A309227-A9D8-4DDF-88DD-326B57B04379}" +EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.DependencyModel", "src\Microsoft.Extensions.DependencyModel\Microsoft.Extensions.DependencyModel.xproj", "{688870C8-9843-4F9E-8576-D39290AD0F25}" EndProject Global @@ -443,6 +445,22 @@ Global {08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {08A68C6A-86F6-4ED2-89A7-B166D33E9F85}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.Debug|x64.ActiveCfg = Debug|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.Debug|x64.Build.0 = Debug|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.Release|Any CPU.Build.0 = Release|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.Release|x64.ActiveCfg = Release|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.Release|x64.Build.0 = Release|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {0A309227-A9D8-4DDF-88DD-326B57B04379}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|Any CPU.Build.0 = Debug|Any CPU {688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -487,6 +505,7 @@ Global {7A75ACC4-3C2F-44E1-B492-0EC08704E9FF} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {BC765FBF-AD7A-4A99-9902-5540C5A74181} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} {08A68C6A-86F6-4ED2-89A7-B166D33E9F85} = {0722D325-24C8-4E83-B5AF-0A083E7F0749} + {0A309227-A9D8-4DDF-88DD-326B57B04379} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} {688870C8-9843-4F9E-8576-D39290AD0F25} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} EndGlobalSection EndGlobal diff --git a/packaging/osx/scripts/postinstall b/packaging/osx/scripts/postinstall index 12284f315..6bef2b772 100755 --- a/packaging/osx/scripts/postinstall +++ b/packaging/osx/scripts/postinstall @@ -13,6 +13,7 @@ chmod -R 755 $INSTALL_DESTINATION ln -s $INSTALL_DESTINATION/bin/dotnet /usr/local/bin/ ln -s $INSTALL_DESTINATION/bin/dotnet-compile /usr/local/bin/ +ln -s $INSTALL_DESTINATION/bin/dotnet-build /usr/local/bin/ ln -s $INSTALL_DESTINATION/bin/dotnet-compile-csc /usr/local/bin/ ln -s $INSTALL_DESTINATION/bin/dotnet-new /usr/local/bin/ ln -s $INSTALL_DESTINATION/bin/dotnet-pack /usr/local/bin/ diff --git a/scripts/build/build-stage.ps1 b/scripts/build/build-stage.ps1 index c4adefc13..7dcdb3258 100644 --- a/scripts/build/build-stage.ps1 +++ b/scripts/build/build-stage.ps1 @@ -14,6 +14,7 @@ param( $Projects = @( "Microsoft.DotNet.Cli", "Microsoft.DotNet.Tools.Compiler", + "Microsoft.DotNet.Tools.Builder", "Microsoft.DotNet.Tools.Compiler.Csc", "Microsoft.DotNet.Tools.Compiler.Native", "Microsoft.DotNet.Tools.New", diff --git a/scripts/build/build-stage.sh b/scripts/build/build-stage.sh index 644b0acc3..7c9f7ce3a 100755 --- a/scripts/build/build-stage.sh +++ b/scripts/build/build-stage.sh @@ -26,6 +26,7 @@ source "$DIR/../_common.sh" PROJECTS=( \ Microsoft.DotNet.Cli \ Microsoft.DotNet.Tools.Compiler \ + Microsoft.DotNet.Tools.Builder \ Microsoft.DotNet.Tools.Compiler.Csc \ Microsoft.DotNet.Tools.Compiler.Native \ Microsoft.DotNet.Tools.New \ diff --git a/scripts/compile.ps1 b/scripts/compile.ps1 index c932b8798..5664d9036 100644 --- a/scripts/compile.ps1 +++ b/scripts/compile.ps1 @@ -49,7 +49,7 @@ try { # Check prereqs if (!(Get-Command -ErrorAction SilentlyContinue cmake)) { throw @" -cmake is required to build the native host 'corehost'" +cmake is required to build the native host 'corehost' Download it from https://www.cmake.org "@ } diff --git a/src/Microsoft.DotNet.Cli.Utils/Command.cs b/src/Microsoft.DotNet.Cli.Utils/Command.cs index c5997c5c7..7e08f7264 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Command.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Command.cs @@ -38,7 +38,7 @@ namespace Microsoft.DotNet.Cli.Utils private bool _running = false; - private Command(string executable, string args, CommandResolutionStrategy commandResolution) + private Command(string executable, string args, CommandResolutionStrategy resolutionStrategy) { // Set the things we need var psi = new ProcessStartInfo() @@ -57,7 +57,7 @@ namespace Microsoft.DotNet.Cli.Utils _stdOut = new StreamForwarder(); _stdErr = new StreamForwarder(); - CommandResolution = commandResolution; + ResolutionStrategy = resolutionStrategy; } public static Command Create(string executable, IEnumerable args, NuGetFramework framework = null) @@ -68,23 +68,23 @@ namespace Microsoft.DotNet.Cli.Utils public static Command Create(string executable, string args, NuGetFramework framework = null) { - var commandResolution = CommandResolutionStrategy.None; + var resolutionStrategy = CommandResolutionStrategy.None; - ResolveExecutablePath(ref executable, ref args, ref commandResolution, framework); + ResolveExecutablePath(ref executable, ref args, ref resolutionStrategy, framework); - return new Command(executable, args, commandResolution); + return new Command(executable, args, resolutionStrategy); } - private static void ResolveExecutablePath(ref string executable, ref string args, ref CommandResolutionStrategy commandResolution, NuGetFramework framework = null) + private static void ResolveExecutablePath(ref string executable, ref string args, ref CommandResolutionStrategy resolutionStrategy, NuGetFramework framework = null) { executable = - ResolveExecutablePathFromProject(executable, framework, ref commandResolution) ?? - ResolveExecutableFromPath(executable, ref args, ref commandResolution); + ResolveExecutablePathFromProject(executable, framework, ref resolutionStrategy) ?? + ResolveExecutableFromPath(executable, ref args, ref resolutionStrategy); } - private static string ResolveExecutableFromPath(string executable, ref string args, ref CommandResolutionStrategy commandResolution) + private static string ResolveExecutableFromPath(string executable, ref string args, ref CommandResolutionStrategy resolutionStrategy) { - commandResolution = CommandResolutionStrategy.Path; + resolutionStrategy = CommandResolutionStrategy.Path; foreach (string suffix in Constants.RunnableSuffixes) { @@ -95,7 +95,7 @@ namespace Microsoft.DotNet.Cli.Utils { executable = fullExecutable; - commandResolution = CommandResolutionStrategy.BaseDirectory; + resolutionStrategy = CommandResolutionStrategy.BaseDirectory; // In priority order we've found the best runnable extension, so break. break; @@ -117,7 +117,7 @@ namespace Microsoft.DotNet.Cli.Utils return executable; } - private static string ResolveExecutablePathFromProject(string executable, NuGetFramework framework, ref CommandResolutionStrategy commandResolution) + private static string ResolveExecutablePathFromProject(string executable, NuGetFramework framework, ref CommandResolutionStrategy resolutionStrategy) { if (framework == null) return null; @@ -149,7 +149,7 @@ namespace Microsoft.DotNet.Cli.Utils var commandPath = commandPackage.Library.Files .First(f => Path.GetFileName(f) == commandName + FileNameSuffixes.DotNet.Exe); - commandResolution = CommandResolutionStrategy.NugetPackage; + resolutionStrategy = CommandResolutionStrategy.NugetPackage; return Path.Combine(projectContext.PackagesDirectory, commandPackage.Path, commandPath); } @@ -312,7 +312,9 @@ namespace Microsoft.DotNet.Cli.Utils return this; } - public CommandResolutionStrategy CommandResolution { get; } + public CommandResolutionStrategy ResolutionStrategy { get; } + + public string CommandName => _process.StartInfo.FileName; private string FormatProcessInfo(ProcessStartInfo info) { diff --git a/src/Microsoft.DotNet.Cli.Utils/ProjectContextExtensions.cs b/src/Microsoft.DotNet.Cli.Utils/ProjectContextExtensions.cs new file mode 100644 index 000000000..c37937e1d --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/ProjectContextExtensions.cs @@ -0,0 +1,67 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +using System.IO; +using Microsoft.DotNet.ProjectModel; +using NuGet.Frameworks; + +namespace Microsoft.DotNet.Cli.Utils +{ + internal static class ProjectContextExtensions + { + public static string ProjectName(this ProjectContext context) => context.RootProject.Identity.Name; + + public static string GetOutputPath(this ProjectContext context, string configuration, string currentOutputPath) + { + var outputPath = string.Empty; + + if (string.IsNullOrEmpty(currentOutputPath)) + { + outputPath = Path.Combine( + GetDefaultRootOutputPath(context, currentOutputPath), + Constants.BinDirectoryName, + configuration, + context.TargetFramework.GetTwoDigitShortFolderName()); + } + else + { + outputPath = currentOutputPath; + } + + return outputPath; + } + + public static string GetIntermediateOutputPath(this ProjectContext context, string configuration, string intermediateOutputValue, string currentOutputPath) + { + var intermediateOutputPath = string.Empty; + + if (string.IsNullOrEmpty(intermediateOutputValue)) + { + intermediateOutputPath = Path.Combine( + GetDefaultRootOutputPath(context, currentOutputPath), + Constants.ObjDirectoryName, + configuration, + context.TargetFramework.GetTwoDigitShortFolderName()); + } + else + { + intermediateOutputPath = intermediateOutputValue; + } + + return intermediateOutputPath; + } + + public static string GetDefaultRootOutputPath(ProjectContext context, string currentOutputPath) + { + string rootOutputPath = string.Empty; + + if (string.IsNullOrEmpty(currentOutputPath)) + { + rootOutputPath = context.ProjectFile.ProjectDirectory; + } + + return rootOutputPath; + } + } +} diff --git a/src/Microsoft.DotNet.Tools.Builder/BuilderCommandApp.cs b/src/Microsoft.DotNet.Tools.Builder/BuilderCommandApp.cs new file mode 100644 index 000000000..3d96314c3 --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Builder/BuilderCommandApp.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.DotNet.Tools.Compiler; + +namespace Microsoft.DotNet.Tools.Build +{ + internal class BuilderCommandApp : CompilerCommandApp + { + private const string BuildProfileFlag = "--build-profile"; + + public bool BuildProfileValue => OptionHasValue(BuildProfileFlag); + + public BuilderCommandApp(string name, string fullName, string description) : base(name, fullName, description) + { + AddNoValueOption(BuildProfileFlag, "Set this flag to print the incremental safety checks that prevent incremental compilation"); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Tools.Builder/CompileContext.cs b/src/Microsoft.DotNet.Tools.Builder/CompileContext.cs new file mode 100644 index 000000000..e06d4f82d --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Builder/CompileContext.cs @@ -0,0 +1,253 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.Tools.Compiler; +using Microsoft.DotNet.ProjectModel.Utilities; + + +namespace Microsoft.DotNet.Tools.Build +{ + // Knows how to orchestrate compilation for a ProjectContext + // Collects icnremental safety checks and transitively compiles a project context + internal class CompileContext + { + + public static readonly string[] KnownCompilers = { "csc", "vbc", "fsc" }; + + private readonly ProjectContext _rootProject; + private readonly BuilderCommandApp _args; + private readonly Dictionary _dependencies; + private readonly string _outputPath; + private readonly string _intermediateOutputPath; + private readonly IncrementalPreconditions _preconditions; + + public bool IsSafeForIncrementalCompilation => _preconditions.PreconditionsDetected(); + + public CompileContext(ProjectContext rootProject, BuilderCommandApp args) + { + _rootProject = rootProject; + _args = args; + + // Set up Output Paths. They are unique per each CompileContext + // Todo: clone args and mutate the clone so the rest of this class does not have special treatment for output paths + _outputPath = _rootProject.GetOutputPath(_args.ConfigValue, _args.OutputValue); + _intermediateOutputPath = _rootProject.GetIntermediateOutputPath(_args.ConfigValue, _args.IntermediateValue, _args.OutputValue); + + // Set up dependencies + _dependencies = GetProjectDependenciesWithSources(_rootProject, _args.ConfigValue); + + //gather preconditions + _preconditions = GatherIncrementalPreconditions(); + } + + public bool Compile(bool incremental) + { + CreateOutputDirectories(); + + //compile dependencies + foreach (var dependency in Sort(_dependencies)) + { + if (!InvokeCompileOnDependency(dependency, _outputPath, _intermediateOutputPath)) + { + return false; + } + } + + //compile project + var success = InvokeCompileOnRootProject(_outputPath, _intermediateOutputPath); + + PrintSummary(success); + + return success; + } + + private void PrintSummary(bool success) + { + //todo: Ideally it's the builder's responsibility for adding the time elapsed. That way we avoid cross cutting display concerns between compile and build for printing time elapsed + if (success) + { + Reporter.Output.Write(" " + _preconditions.LogMessage()); + Reporter.Output.WriteLine(); + } + + Reporter.Output.WriteLine(); + } + + private void CreateOutputDirectories() + { + Directory.CreateDirectory(_outputPath); + Directory.CreateDirectory(_intermediateOutputPath); + } + + //todo make extension of ProjectContext? + //returns map with dependencies: string projectName -> ProjectDescription + private static Dictionary GetProjectDependenciesWithSources(ProjectContext projectContext, string configuration) + { + var projects = new Dictionary(); + + // Create the library exporter + var exporter = projectContext.CreateExporter(configuration); + + // Gather exports for the project + var dependencies = exporter.GetDependencies().ToList(); + + // Build project references + foreach (var dependency in dependencies) + { + var projectDependency = dependency.Library as ProjectDescription; + + if (projectDependency != null && projectDependency.Project.Files.SourceFiles.Any()) + { + projects[projectDependency.Identity.Name] = projectDependency; + } + } + + return projects; + } + + private IncrementalPreconditions GatherIncrementalPreconditions() + { + var preconditions = new IncrementalPreconditions(_args.BuildProfileValue); + + var projectsToCheck = GetProjectsToCheck(); + + foreach (var project in projectsToCheck) + { + CollectScriptPreconditions(project, preconditions); + CollectCompilerNamePreconditions(project, preconditions); + CheckPathProbing(project, preconditions); + } + + return preconditions; + } + + //check the entire project tree that needs to be compiled, duplicated for each framework + private List GetProjectsToCheck() + { + //include initial root project + var contextsToCheck = new List(1 + _dependencies.Count) {_rootProject}; + + //convert ProjectDescription to ProjectContext + var dependencyContexts = _dependencies.Select + (keyValuePair => ProjectContext.Create(keyValuePair.Value.Path, keyValuePair.Value.TargetFrameworkInfo.FrameworkName)); + + contextsToCheck.AddRange(dependencyContexts); + + + return contextsToCheck; + } + + private void CheckPathProbing(ProjectContext project, IncrementalPreconditions preconditions) + { + var pathCommands = CompilerUtil.GetCommandsInvokedByCompile(project) + .Select(commandName => Command.Create(commandName, "", project.TargetFramework)) + .Where(c => Command.CommandResolutionStrategy.Path.Equals(c.ResolutionStrategy)); + + foreach (var pathCommand in pathCommands) + { + preconditions.AddPathProbingPrecondition(project.ProjectName(), pathCommand.CommandName); + } + } + + private void CollectCompilerNamePreconditions(ProjectContext project, IncrementalPreconditions preconditions) + { + var projectCompiler = CompilerUtil.ResolveCompilerName(project); + + if (KnownCompilers.Any(knownCompiler => knownCompiler.Equals(projectCompiler, StringComparison.Ordinal))) + { + preconditions.AddUnknownCompilerPrecondition(project.ProjectName(), projectCompiler); + } + } + + private void CollectScriptPreconditions(ProjectContext project, IncrementalPreconditions preconditions) + { + var preCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PreCompile); + var postCompileScripts = project.ProjectFile.Scripts.GetOrEmpty(ScriptNames.PostCompile); + + if (preCompileScripts.Any()) + { + preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PreCompile); + } + + if (postCompileScripts.Any()) + { + preconditions.AddPrePostScriptPrecondition(project.ProjectName(), ScriptNames.PostCompile); + } + } + + private bool InvokeCompileOnDependency(ProjectDescription projectDependency, string outputPath, string intermediateOutputPath) + { + var compileResult = Command.Create("dotnet-compile", + $"--framework {projectDependency.Framework} " + + $"--configuration {_args.ConfigValue} " + + $"--output \"{outputPath}\" " + + $"--temp-output \"{intermediateOutputPath}\" " + + (_args.NoHostValue ? "--no-host " : string.Empty) + + $"\"{projectDependency.Project.ProjectDirectory}\"") + .ForwardStdOut() + .ForwardStdErr() + .Execute(); + + return compileResult.ExitCode == 0; + } + + private bool InvokeCompileOnRootProject(string outputPath, string intermediateOutputPath) + { + //todo: add methods to CompilerCommandApp to generate the arg string + var compileResult = Command.Create("dotnet-compile", + $"--framework {_rootProject.TargetFramework} " + + $"--configuration {_args.ConfigValue} " + + $"--output \"{outputPath}\" " + + $"--temp-output \"{intermediateOutputPath}\" " + + (_args.NoHostValue ? "--no-host " : string.Empty) + + //nativeArgs + (_args.IsNativeValue ? "--native " : string.Empty) + + (_args.IsCppModeValue ? "--cpp " : string.Empty) + + (!string.IsNullOrWhiteSpace(_args.ArchValue) ? $"--arch {_args.ArchValue} " : string.Empty) + + (!string.IsNullOrWhiteSpace(_args.IlcArgsValue) ? $"--ilcargs \"{_args.IlcArgsValue}\" " : string.Empty) + + (!string.IsNullOrWhiteSpace(_args.IlcPathValue) ? $"--ilcpath \"{_args.IlcPathValue}\" " : string.Empty) + + (!string.IsNullOrWhiteSpace(_args.IlcSdkPathValue) ? $"--ilcsdkpath \"{_args.IlcSdkPathValue}\" " : string.Empty) + + $"\"{_rootProject.ProjectDirectory}\"") + .ForwardStdOut() + .ForwardStdErr() + .Execute(); + + return compileResult.ExitCode == 0; + } + + private static ISet Sort(Dictionary projects) + { + var outputs = new HashSet(); + + foreach (var pair in projects) + { + Sort(pair.Value, projects, outputs); + } + + return outputs; + } + + private static void Sort(ProjectDescription project, Dictionary projects, ISet outputs) + { + // Sorts projects in dependency order so that we only build them once per chain + foreach (var dependency in project.Dependencies) + { + ProjectDescription projectDependency; + if (projects.TryGetValue(dependency.Name, out projectDependency)) + { + Sort(projectDependency, projects, outputs); + } + } + + outputs.Add(project); + } + } + +} diff --git a/src/Microsoft.DotNet.Tools.Builder/IncrementalPreconditions.cs b/src/Microsoft.DotNet.Tools.Builder/IncrementalPreconditions.cs new file mode 100644 index 000000000..c6d2c2bf0 --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Builder/IncrementalPreconditions.cs @@ -0,0 +1,79 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Tools.Build +{ + internal class IncrementalPreconditions + { + private readonly List _preconditions; + private readonly bool _isProfile; + + public IncrementalPreconditions(bool isProfile) + { + _isProfile = isProfile; + _preconditions = new List(); + } + + public void AddPrePostScriptPrecondition(string projectName, string scriptType) + { + _preconditions.Add($"[Pre / Post Scripts] Project {projectName} is using {scriptType} scripts."); + } + + public void AddUnknownCompilerPrecondition(string projectName, string compilerName) + { + _preconditions.Add($"[Unknown Compiler] Project {projectName} is using unknown compiler {compilerName}."); + } + + public void AddPathProbingPrecondition(string projectName, string commandName) + { + _preconditions.Add($"[PATH Probing] Project {projectName} is loading tool \"{commandName}\" from PATH"); + } + + public bool PreconditionsDetected() + { + return _preconditions.Any(); + } + + private string PreconditionsMessage() + { + var log = new StringBuilder(); + + log.AppendLine(); + log.Append("Incremental compilation has been disabled due to the following project properties:"); + + foreach (var precondition in _preconditions) + { + log.AppendLine(); + log.Append("\t" + precondition); + } + + log.AppendLine(); + log.AppendLine(); + + log.Append( + "Incremental compilation will be automatically enabled if the above mentioned project properties are not used. " + + "For more information on the properties and how to address them, please consult:\n" + + @"https://github.com/cdmihai/cli/wiki/Addressing-Incremental-Compilation-Warnings"); + + log.AppendLine(); + log.AppendLine(); + + return log.ToString(); + } + + public string LogMessage() + { + if (PreconditionsDetected()) + { + return _isProfile ? PreconditionsMessage().Yellow() : "(The compilation time can be improved. Run \"dotnet build --profile\" for more information)"; + } + + return ""; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Tools.Builder/Microsoft.DotNet.Tools.Builder.xproj b/src/Microsoft.DotNet.Tools.Builder/Microsoft.DotNet.Tools.Builder.xproj new file mode 100644 index 000000000..3eafb1ca3 --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Builder/Microsoft.DotNet.Tools.Builder.xproj @@ -0,0 +1,20 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 0a309227-a9d8-4ddf-88dd-326b57b04379 + Microsoft.DotNet.Tools.Build + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin\$(MSBuildProjectName)\ + + + + 2.0 + + + diff --git a/src/Microsoft.DotNet.Tools.Builder/Program.cs b/src/Microsoft.DotNet.Tools.Builder/Program.cs new file mode 100644 index 000000000..67c2a7008 --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Builder/Program.cs @@ -0,0 +1,45 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.Tools.Compiler; + +namespace Microsoft.DotNet.Tools.Build +{ + public class Program + { + public static int Main(string[] args) + { + DebugHelper.HandleDebugSwitch(ref args); + + try + { + var app = new BuilderCommandApp("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"); + return app.Execute(OnExecute, args); + } + catch (Exception ex) + { +#if DEBUG + Console.Error.WriteLine(ex); +#else + Console.Error.WriteLine(ex.Message); +#endif + return 1; + } + } + + private static bool OnExecute(List contexts, CompilerCommandApp args) + { + var compileContexts = contexts.Select(context => new CompileContext(context, (BuilderCommandApp)args)).ToList(); + + var incrementalSafe = compileContexts.All(c => c.IsSafeForIncrementalCompilation); + + return compileContexts.All(c => c.Compile(incrementalSafe)); + } + } +} diff --git a/src/Microsoft.DotNet.Tools.Builder/README.md b/src/Microsoft.DotNet.Tools.Builder/README.md new file mode 100644 index 000000000..e9b7b16fa --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Builder/README.md @@ -0,0 +1,32 @@ +dotnet-build +=========== + +**NAME** +dotnet-build -- Orchestrates the compilation of a project and all its dependencies. + +**SYNOPSIS** +dotnet build[options] + +**DESCRIPTION** + +The build verb orchestrates the compilation of a project: it gathers the dependencies of a project and decides which to compile. + +Users should invoke the Build verb when they want the entire dependency graph compiled, and Compile when they want only a specific project compiled. + +Before any compilation begins, the build verb analyzes the project and its dependencies for incremental safety checks. If all checks clear out, then build proceeds with incremental compilation of the project and its dependencies. Otherwise it falls back to non-incremental compilation. Via a profile flag users can choose to receive additional information on how they can improve their build times. + +All the projects in the dependency graph that need compilation must pass the following safety checks in order for the compilation process to be incremental: +- not use pre / post compile scripts +- not load compilation tools from PATH (e.g., resgen, compilers) +- use only known compilers (csc, vbc, fsc) + +Please read the [documentation](https://github.com/dotnet/cli/blob/master/src/Microsoft.DotNet.Tools.Compiler/README.md) on Compile for details on compilation and project structure: + +**Options** + +Build inherits all the [Compile command line parameters](https://github.com/dotnet/cli/blob/master/src/Microsoft.DotNet.Tools.Compiler/README.md). + +In addition Compile's parameters, Build adds the following flag: + +--build-profile [exe | dynlib | lib] +Prints out the incremental safety checks that users need to address in order for incremental compilation to be automatically turned on. \ No newline at end of file diff --git a/src/Microsoft.DotNet.Tools.Builder/project.json b/src/Microsoft.DotNet.Tools.Builder/project.json new file mode 100644 index 000000000..d6a9ee7e9 --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Builder/project.json @@ -0,0 +1,33 @@ +{ + "name": "dotnet-build", + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "NETStandard.Library": "1.0.0-rc2-23608", + "System.Linq": "4.0.1-rc2-23608", + "System.Reflection.Metadata": "1.1.0", + + "Microsoft.DotNet.ProjectModel": "1.0.0-*", + "Microsoft.DotNet.Compiler.Common": "1.0.0-*", + "Microsoft.DotNet.Tools.Compiler": "1.0.0-*", + "Microsoft.DotNet.Cli.Utils": { + "type": "build", + "version": "1.0.0-*" + }, + "Microsoft.Extensions.CommandLineUtils.Sources": { + "type": "build", + "version": "1.0.0-*" + } + }, + "frameworks": { + "dnxcore50": { } + }, + "scripts": { + "postcompile": [ + "../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.dll\"", + "../../scripts/build/place-binary \"%compile:OutputDir%/%project:Name%.pdb\"" + ] + } +} diff --git a/src/Microsoft.DotNet.Tools.Compiler/CompilerCommandApp.cs b/src/Microsoft.DotNet.Tools.Compiler/CompilerCommandApp.cs new file mode 100644 index 000000000..bf71ad0db --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Compiler/CompilerCommandApp.cs @@ -0,0 +1,144 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Dnx.Runtime.Common.CommandLine; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectModel; +using NuGet.Frameworks; +using System.Linq; + +//This class is responsible with defining the arguments for the Compile verb. +//It knows how to interpret them and set default values +namespace Microsoft.DotNet.Tools.Compiler +{ + public delegate bool OnExecute(List contexts, CompilerCommandApp compilerCommand); + + public class CompilerCommandApp + { + private readonly CommandLineApplication _app; + + //options and arguments for compilation + private CommandOption _outputOption; + private CommandOption _intermediateOutputOption; + private CommandOption _frameworkOption; + private CommandOption _configurationOption; + private CommandOption _noHostOption; + private CommandArgument _projectArgument; + private CommandOption _nativeOption; + private CommandOption _archOption; + private CommandOption _ilcArgsOption; + private CommandOption _ilcPathOption; + private CommandOption _ilcSdkPathOption; + private CommandOption _appDepSdkPathOption; + private CommandOption _cppModeOption; + private CommandOption _cppCompilerFlagsOption; + + //resolved values for the options and arguments + public string ProjectPathValue { get; set; } + public string OutputValue { get; set; } + public string IntermediateValue { get; set; } + public string ConfigValue { get; set; } + public bool NoHostValue { get; set; } + public bool IsNativeValue { get; set; } + public string ArchValue { get; set; } + public string IlcArgsValue { get; set; } + public string IlcPathValue { get; set; } + public string IlcSdkPathValue { get; set; } + public bool IsCppModeValue { get; set; } + public string AppDepSdkPathValue { get; set; } + public string CppCompilerFlagsValue { get; set; } + + //workaround: CommandLineApplication is internal therefore I cannot make _app protected so baseclasses can add their own params + private readonly Dictionary baseClassOptions; + + public CompilerCommandApp(string name, string fullName, string description) + { + _app = new CommandLineApplication + { + Name = name, + FullName = fullName, + Description = description + }; + + baseClassOptions = new Dictionary(); + + AddCompileParameters(); + } + + private void AddCompileParameters() + { + _app.HelpOption("-h|--help"); + + _outputOption = _app.Option("-o|--output ", "Directory in which to place outputs", CommandOptionType.SingleValue); + _intermediateOutputOption = _app.Option("-t|--temp-output ", "Directory in which to place temporary outputs", CommandOptionType.SingleValue); + _frameworkOption = _app.Option("-f|--framework ", "Compile a specific framework", CommandOptionType.MultipleValue); + _configurationOption = _app.Option("-c|--configuration ", "Configuration under which to build", CommandOptionType.SingleValue); + _noHostOption = _app.Option("--no-host", "Set this to skip publishing a runtime host when building for CoreCLR", CommandOptionType.NoValue); + _projectArgument = _app.Argument("", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory"); + + // Native Args + _nativeOption = _app.Option("-n|--native", "Compiles source to native machine code.", CommandOptionType.NoValue); + _archOption = _app.Option("-a|--arch ", "The architecture for which to compile. x64 only currently supported.", CommandOptionType.SingleValue); + _ilcArgsOption = _app.Option("--ilcargs ", "Command line arguments to be passed directly to ILCompiler.", CommandOptionType.SingleValue); + _ilcPathOption = _app.Option("--ilcpath ", "Path to the folder containing custom built ILCompiler.", CommandOptionType.SingleValue); + _ilcSdkPathOption = _app.Option("--ilcsdkpath ", "Path to the folder containing ILCompiler application dependencies.", CommandOptionType.SingleValue); + _appDepSdkPathOption = _app.Option("--appdepsdkpath ", "Path to the folder containing ILCompiler application dependencies.", CommandOptionType.SingleValue); + _cppModeOption = _app.Option("--cpp", "Flag to do native compilation with C++ code generator.", CommandOptionType.NoValue); + _cppCompilerFlagsOption = _app.Option("--cppcompilerflags ", "Additional flags to be passed to the native compiler.", CommandOptionType.SingleValue); + } + + public int Execute(OnExecute execute, string[] args) + { + _app.OnExecute(() => + { + // Locate the project and get the name and full path + ProjectPathValue = _projectArgument.Value; + if (string.IsNullOrEmpty(ProjectPathValue)) + { + ProjectPathValue = Directory.GetCurrentDirectory(); + } + + OutputValue = _outputOption.Value(); + IntermediateValue = _intermediateOutputOption.Value(); + ConfigValue = _configurationOption.Value() ?? Constants.DefaultConfiguration; + NoHostValue = _noHostOption.HasValue(); + + IsNativeValue = _nativeOption.HasValue(); + ArchValue = _archOption.Value(); + IlcArgsValue = _ilcArgsOption.Value(); + IlcPathValue = _ilcPathOption.Value(); + IlcSdkPathValue = _ilcSdkPathOption.Value(); + AppDepSdkPathValue = _appDepSdkPathOption.Value(); + IsCppModeValue = _cppModeOption.HasValue(); + CppCompilerFlagsValue = _cppCompilerFlagsOption.Value(); + + + // Load project contexts for each framework + var contexts = _frameworkOption.HasValue() ? + _frameworkOption.Values.Select(f => ProjectContext.Create(ProjectPathValue, NuGetFramework.Parse(f))) : + ProjectContext.CreateContextForEachFramework(ProjectPathValue); + + var success = execute(contexts.ToList(), this); + + return success ? 0 : 1; + }); + + return _app.Execute(args); + } + + //CommandOptionType is internal. Cannot pass it as argument. Therefore the method name encodes the option type. + protected void AddNoValueOption(string optionTemplate, string descriptino){ + baseClassOptions[optionTemplate] = _app.Option(optionTemplate, descriptino, CommandOptionType.NoValue); + } + + protected bool OptionHasValue(string optionTemplate) + { + CommandOption option; + + return baseClassOptions.TryGetValue(optionTemplate, out option) && option.HasValue(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Tools.Compiler/CompilerUtil.cs b/src/Microsoft.DotNet.Tools.Compiler/CompilerUtil.cs new file mode 100644 index 000000000..2b0ae3829 --- /dev/null +++ b/src/Microsoft.DotNet.Tools.Compiler/CompilerUtil.cs @@ -0,0 +1,121 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.Cli.Compiler.Common; +using Microsoft.DotNet.ProjectModel.Compilation; +using Microsoft.DotNet.Tools.Common; + +//This class is responsible with defining the arguments for the Compile verb. +//It knows how to interpret them and set default values + +namespace Microsoft.DotNet.Tools.Compiler +{ + public static class CompilerUtil + { + public static string ResolveCompilerName(ProjectContext context) + { + var compilerName = context.ProjectFile.CompilerName; + compilerName = compilerName ?? "csc"; + + return compilerName; + } + + public struct NonCultureResgenIO + { + public readonly string InputFile; + public readonly string MetadataName; + + //is non-null only when resgen needs to be invoked (inputFile is .resx) + public readonly string OutputFile; + + public NonCultureResgenIO(string inputFile, string outputFile, string metadataName) + { + InputFile = inputFile; + OutputFile = outputFile; + MetadataName = metadataName; + } + } + + //used in incremental compilation + public static List GetNonCultureResources(Project project, string intermediateOutputPath) + { + return + (from resourceFile in project.Files.ResourceFiles + let inputFile = resourceFile.Key + where string.IsNullOrEmpty(ResourceUtility.GetResourceCultureName(inputFile)) + let metadataName = GetResourceFileMetadataName(project, resourceFile) + let outputFile = ResourceUtility.IsResxFile(inputFile) ? Path.Combine(intermediateOutputPath, metadataName) : null + select new NonCultureResgenIO(inputFile, outputFile, metadataName) + ).ToList(); + } + + public struct CultureResgenIO + { + public readonly string Culture; + public readonly Dictionary InputFileToMetadata; + public readonly string OutputFile; + + public CultureResgenIO(string culture, Dictionary inputFileToMetadata, string outputFile) + { + Culture = culture; + InputFileToMetadata = inputFileToMetadata; + OutputFile = outputFile; + } + } + + //used in incremental compilation + public static List GetCultureResources(Project project, string outputPath) + { + return + (from resourceFileGroup in project.Files.ResourceFiles.GroupBy(resourceFile => ResourceUtility.GetResourceCultureName(resourceFile.Key)) + let culture = resourceFileGroup.Key + where !string.IsNullOrEmpty(culture) + let inputFileToMetadata = resourceFileGroup.ToDictionary(r => r.Key, r => GetResourceFileMetadataName(project, r)) + let resourceOutputPath = Path.Combine(outputPath, culture) + let outputFile = Path.Combine(resourceOutputPath, project.Name + ".resources.dll") + select new CultureResgenIO(culture, inputFileToMetadata, outputFile) + ).ToList(); + } + + //used in incremental compilation + public static IList GetReferencePathsForCultureResgen(List dependencies) + { + return dependencies.SelectMany(libraryExport => libraryExport.CompilationAssemblies).Select(r => r.ResolvedPath).ToList(); + } + + public static string GetResourceFileMetadataName(Project project, KeyValuePair resourceFile) + { + string resourceName = null; + string rootNamespace = null; + + string root = PathUtility.EnsureTrailingSlash(project.ProjectDirectory); + string resourcePath = resourceFile.Key; + if (string.IsNullOrEmpty(resourceFile.Value)) + { + // No logical name, so use the file name + resourceName = ResourceUtility.GetResourceName(root, resourcePath); + rootNamespace = project.Name; + } + else + { + resourceName = ResourceManifestName.EnsureResourceExtension(resourceFile.Value, resourcePath); + rootNamespace = null; + } + + var name = ResourceManifestName.CreateManifestName(resourceName, rootNamespace); + return name; + } + + public static IEnumerable GetCommandsInvokedByCompile(ProjectContext project) + { + return new List {ResolveCompilerName(project)}; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Tools.Compiler/Program.cs b/src/Microsoft.DotNet.Tools.Compiler/Program.cs index ceec01a1c..9eb216245 100644 --- a/src/Microsoft.DotNet.Tools.Compiler/Program.cs +++ b/src/Microsoft.DotNet.Tools.Compiler/Program.cs @@ -22,76 +22,15 @@ namespace Microsoft.DotNet.Tools.Compiler { public class Program { + public static int Main(string[] args) { DebugHelper.HandleDebugSwitch(ref args); - var app = new CommandLineApplication(); - app.Name = "dotnet compile"; - app.FullName = ".NET Compiler"; - app.Description = "Compiler for the .NET Platform"; - app.HelpOption("-h|--help"); - - var output = app.Option("-o|--output ", "Directory in which to place outputs", CommandOptionType.SingleValue); - var intermediateOutput = app.Option("-t|--temp-output ", "Directory in which to place temporary outputs", CommandOptionType.SingleValue); - var framework = app.Option("-f|--framework ", "Compile a specific framework", CommandOptionType.MultipleValue); - var configuration = app.Option("-c|--configuration ", "Configuration under which to build", CommandOptionType.SingleValue); - var noProjectDependencies = app.Option("--no-project-dependencies", "Skips building project references.", CommandOptionType.NoValue); - var noHost = app.Option("--no-host", "Set this to skip publishing a runtime host when building for CoreCLR", CommandOptionType.NoValue); - var project = app.Argument("", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory"); - - // Native Args - var native = app.Option("-n|--native", "Compiles source to native machine code.", CommandOptionType.NoValue); - var arch = app.Option("-a|--arch ", "The architecture for which to compile. x64 only currently supported.", CommandOptionType.SingleValue); - var ilcArgs = app.Option("--ilcargs ", "Command line arguments to be passed directly to ILCompiler.", CommandOptionType.SingleValue); - var ilcPath = app.Option("--ilcpath ", "Path to the folder containing custom built ILCompiler.", CommandOptionType.SingleValue); - var ilcSdkPath = app.Option("--ilcsdkpath ", "Path to the folder containing custom built ILCompiler SDK.", CommandOptionType.SingleValue); - var appDepSdkPath = app.Option("--appdepsdkpath ", "Path to the folder containing ILCompiler application dependencies.", CommandOptionType.SingleValue); - var cppMode = app.Option("--cpp", "Flag to do native compilation with C++ code generator.", CommandOptionType.NoValue); - var cppCompilerFlags = app.Option("--cppcompilerflags ", "Additional flags to be passed to the native compiler.", CommandOptionType.SingleValue); - - app.OnExecute(() => - { - // Locate the project and get the name and full path - var path = project.Value; - if (string.IsNullOrEmpty(path)) - { - path = Directory.GetCurrentDirectory(); - } - - var buildProjectReferences = !noProjectDependencies.HasValue(); - var isNative = native.HasValue(); - var isCppMode = cppMode.HasValue(); - var archValue = arch.Value(); - var ilcArgsValue = ilcArgs.Value(); - var ilcPathValue = ilcPath.Value(); - var ilcSdkPathValue = ilcSdkPath.Value(); - var appDepSdkPathValue = appDepSdkPath.Value(); - var configValue = configuration.Value() ?? Constants.DefaultConfiguration; - var outputValue = output.Value(); - var intermediateValue = intermediateOutput.Value(); - var cppCompilerFlagsValue = cppCompilerFlags.Value(); - - // Load project contexts for each framework and compile them - bool success = true; - var contexts = framework.HasValue() ? - framework.Values.Select(f => ProjectContext.Create(path, NuGetFramework.Parse(f))) : - ProjectContext.CreateContextForEachFramework(path); - foreach (var context in contexts) - { - success &= Compile(context, configValue, outputValue, intermediateValue, buildProjectReferences, noHost.HasValue()); - if (isNative && success) - { - success &= CompileNative(context, configValue, outputValue, buildProjectReferences, intermediateValue, archValue, ilcArgsValue, ilcPathValue, ilcSdkPathValue, appDepSdkPathValue, isCppMode, cppCompilerFlagsValue); - } - } - - return success ? 0 : 1; - }); - try { - return app.Execute(args); + var compilerCommandArgs = new CompilerCommandApp("dotnet compile", ".NET Compiler", "Compiler for the .NET Platform"); + return compilerCommandArgs.Execute(OnExecute, args); } catch (Exception ex) { @@ -104,31 +43,36 @@ namespace Microsoft.DotNet.Tools.Compiler } } + private static bool OnExecute(List contexts, CompilerCommandApp args) + { + var success = true; + + foreach (var context in contexts) + { + success &= CompileProject(context, args); + if (args.IsNativeValue && success) + { + success &= CompileNative(context, args); + } + } + return success; + } + private static bool CompileNative( ProjectContext context, - string configuration, - string outputOptionValue, - bool buildProjectReferences, - string intermediateOutputValue, - string archValue, - string ilcArgsValue, - string ilcPathValue, - string ilcSdkPathValue, - string appDepSdkPathValue, - bool isCppMode, - string cppCompilerFlagsValue) + CompilerCommandApp args) { - var outputPath = GetOutputPath(context, configuration, outputOptionValue); - var nativeOutputPath = Path.Combine(GetOutputPath(context, configuration, outputOptionValue), "native"); + var outputPath = context.GetOutputPath(args.ConfigValue, args.OutputValue); + var nativeOutputPath = Path.Combine(outputPath, "native"); var intermediateOutputPath = - GetIntermediateOutputPath(context, configuration, intermediateOutputValue, outputOptionValue); + context.GetIntermediateOutputPath(args.ConfigValue, args.IntermediateValue, outputPath); Directory.CreateDirectory(nativeOutputPath); Directory.CreateDirectory(intermediateOutputPath); - var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); + var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, args.ConfigValue); var managedOutput = - GetProjectOutput(context.ProjectFile, context.TargetFramework, configuration, outputPath); + GetProjectOutput(context.ProjectFile, context.TargetFramework, args.ConfigValue, outputPath); var nativeArgs = new List(); @@ -136,58 +80,58 @@ namespace Microsoft.DotNet.Tools.Compiler nativeArgs.Add($"{managedOutput}"); // ILC Args - if (!string.IsNullOrWhiteSpace(ilcArgsValue)) + if (!string.IsNullOrWhiteSpace(args.IlcArgsValue)) { nativeArgs.Add("--ilcargs"); - nativeArgs.Add($"{ilcArgsValue}"); + nativeArgs.Add($"{args.IlcArgsValue}"); } // ILC Path - if (!string.IsNullOrWhiteSpace(ilcPathValue)) + if (!string.IsNullOrWhiteSpace(args.IlcPathValue)) { nativeArgs.Add("--ilcpath"); - nativeArgs.Add(ilcPathValue); + nativeArgs.Add(args.IlcPathValue); } // ILC SDK Path - if (!string.IsNullOrWhiteSpace(ilcSdkPathValue)) + if (!string.IsNullOrWhiteSpace(args.IlcSdkPathValue)) { nativeArgs.Add("--ilcsdkpath"); - nativeArgs.Add(ilcSdkPathValue); + nativeArgs.Add(args.IlcSdkPathValue); } // AppDep SDK Path - if (!string.IsNullOrWhiteSpace(appDepSdkPathValue)) + if (!string.IsNullOrWhiteSpace(args.AppDepSdkPathValue)) { nativeArgs.Add("--appdepsdk"); - nativeArgs.Add(appDepSdkPathValue); + nativeArgs.Add(args.AppDepSdkPathValue); } // CodeGen Mode - if(isCppMode) + if(args.IsCppModeValue) { nativeArgs.Add("--mode"); nativeArgs.Add("cpp"); } - if (!string.IsNullOrWhiteSpace(cppCompilerFlagsValue)) + if (!string.IsNullOrWhiteSpace(args.CppCompilerFlagsValue)) { nativeArgs.Add("--cppcompilerflags"); - nativeArgs.Add(cppCompilerFlagsValue); + nativeArgs.Add(args.CppCompilerFlagsValue); } // Configuration - if (configuration != null) + if (args.ConfigValue != null) { nativeArgs.Add("--configuration"); - nativeArgs.Add(configuration); + nativeArgs.Add(args.ConfigValue); } // Architecture - if (archValue != null) + if (args.ArchValue != null) { nativeArgs.Add("--arch"); - nativeArgs.Add(archValue); + nativeArgs.Add(args.ArchValue); } // Intermediate Path @@ -214,65 +158,21 @@ namespace Microsoft.DotNet.Tools.Compiler return result.ExitCode == 0; } - private static bool Compile(ProjectContext context, string configuration, string outputOptionValue, string intermediateOutputValue, bool buildProjectReferences, bool noHost) + private static bool CompileProject(ProjectContext context, CompilerCommandApp args) { // Set up Output Paths - string outputPath = GetOutputPath(context, configuration, outputOptionValue); - string intermediateOutputPath = GetIntermediateOutputPath(context, configuration, intermediateOutputValue, outputOptionValue); + string outputPath = context.GetOutputPath(args.ConfigValue, args.OutputValue); + string intermediateOutputPath = context.GetIntermediateOutputPath(args.ConfigValue, args.IntermediateValue, outputPath); Directory.CreateDirectory(outputPath); Directory.CreateDirectory(intermediateOutputPath); // Create the library exporter - var exporter = context.CreateExporter(configuration); + var exporter = context.CreateExporter(args.ConfigValue); // Gather exports for the project var dependencies = exporter.GetDependencies().ToList(); - if (buildProjectReferences) - { - var projects = new Dictionary(); - - // Build project references - foreach (var dependency in dependencies) - { - var projectDependency = dependency.Library as ProjectDescription; - - if (projectDependency != null && projectDependency.Project.Files.SourceFiles.Any()) - { - projects[projectDependency.Identity.Name] = projectDependency; - } - } - - foreach (var projectDependency in Sort(projects)) - { - // Skip compiling project dependencies since we've already figured out the build order - var compileResult = Command.Create("dotnet-compile", - $"--framework {projectDependency.Framework} " + - $"--configuration {configuration} " + - $"--output \"{outputPath}\" " + - $"--temp-output \"{intermediateOutputPath}\" " + - "--no-project-dependencies " + - (noHost ? "--no-host " : string.Empty) + - $"\"{projectDependency.Project.ProjectDirectory}\"") - .ForwardStdOut() - .ForwardStdErr() - .Execute(); - - if (compileResult.ExitCode != 0) - { - return false; - } - } - - projects.Clear(); - } - - return CompileProject(context, configuration, outputPath, intermediateOutputPath, dependencies, noHost); - } - - private static bool CompileProject(ProjectContext context, string configuration, string outputPath, string intermediateOutputPath, List dependencies, bool noHost) - { Reporter.Output.WriteLine($"Compiling {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}"); var sw = Stopwatch.StartNew(); @@ -300,7 +200,7 @@ namespace Microsoft.DotNet.Tools.Compiler } // Get compilation options - var outputName = GetProjectOutput(context.ProjectFile, context.TargetFramework, configuration, outputPath); + var outputName = GetProjectOutput(context.ProjectFile, context.TargetFramework, args.ConfigValue, outputPath); // Assemble args var compilerArgs = new List() @@ -309,7 +209,7 @@ namespace Microsoft.DotNet.Tools.Compiler $"--out:{outputName}" }; - var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); + var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, args.ConfigValue); // Path to strong naming key in environment variable overrides path in project.json var environmentKeyFile = Environment.GetEnvironmentVariable(EnvironmentNames.StrongNameKeyFile); @@ -340,7 +240,7 @@ namespace Microsoft.DotNet.Tools.Compiler { if (projectDependency.Project.Files.SourceFiles.Any()) { - var projectOutputPath = GetProjectOutput(projectDependency.Project, projectDependency.Framework, configuration, outputPath); + var projectOutputPath = GetProjectOutput(projectDependency.Project, projectDependency.Framework, args.ConfigValue, outputPath); references.Add(projectOutputPath); } } @@ -355,7 +255,7 @@ namespace Microsoft.DotNet.Tools.Compiler compilerArgs.AddRange(references.Select(r => $"--reference:{r}")); var runtimeContext = ProjectContext.Create(context.ProjectDirectory, context.TargetFramework, new[] { RuntimeIdentifier.Current }); - var libraryExporter = runtimeContext.CreateExporter(configuration); + var libraryExporter = runtimeContext.CreateExporter(args.ConfigValue); if (compilationOptions.PreserveCompilationContext == true) { @@ -384,7 +284,7 @@ namespace Microsoft.DotNet.Tools.Compiler } } - if (!AddResources(context.ProjectFile, compilerArgs, intermediateOutputPath)) + if (!AddNonCultureResources(context.ProjectFile, compilerArgs, intermediateOutputPath)) { return false; } @@ -392,8 +292,7 @@ namespace Microsoft.DotNet.Tools.Compiler var sourceFiles = context.ProjectFile.Files.SourceFiles; compilerArgs.AddRange(sourceFiles); - var compilerName = context.ProjectFile.CompilerName; - compilerName = compilerName ?? "csc"; + var compilerName = CompilerUtil.ResolveCompilerName(context); // Write RSP file var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.{context.ProjectFile.Name}.rsp"); @@ -403,7 +302,7 @@ namespace Microsoft.DotNet.Tools.Compiler var contextVariables = new Dictionary() { { "compile:TargetFramework", context.TargetFramework.DotNetFrameworkName }, - { "compile:Configuration", configuration }, + { "compile:Configuration", args.ConfigValue }, { "compile:OutputFile", outputName }, { "compile:OutputDir", outputPath }, { "compile:ResponseFile", rsp } @@ -444,10 +343,10 @@ namespace Microsoft.DotNet.Tools.Compiler if (success) { - success &= GenerateResourceAssemblies(context.ProjectFile, dependencies, outputPath, configuration); + success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, outputPath); } - if (success && !noHost && compilationOptions.EmitEntryPoint.GetValueOrDefault()) + if (success && !args.NoHostValue && compilationOptions.EmitEntryPoint.GetValueOrDefault()) { MakeRunnable(runtimeContext, outputPath, @@ -481,58 +380,6 @@ namespace Microsoft.DotNet.Tools.Compiler return Path.Combine(outputPath, project.Name + outputExtension); } - private static string GetOutputPath(ProjectContext context, string configuration, string outputOptionValue) - { - var outputPath = string.Empty; - - if (string.IsNullOrEmpty(outputOptionValue)) - { - outputPath = Path.Combine( - GetDefaultRootOutputPath(context, outputOptionValue), - Constants.BinDirectoryName, - configuration, - context.TargetFramework.GetTwoDigitShortFolderName()); - } - else - { - outputPath = outputOptionValue; - } - - return outputPath; - } - - private static string GetIntermediateOutputPath(ProjectContext context, string configuration, string intermediateOutputValue, string outputOptionValue) - { - var intermediateOutputPath = string.Empty; - - if (string.IsNullOrEmpty(intermediateOutputValue)) - { - intermediateOutputPath = Path.Combine( - GetDefaultRootOutputPath(context, outputOptionValue), - Constants.ObjDirectoryName, - configuration, - context.TargetFramework.GetTwoDigitShortFolderName()); - } - else - { - intermediateOutputPath = intermediateOutputValue; - } - - return intermediateOutputPath; - } - - private static string GetDefaultRootOutputPath(ProjectContext context, string outputOptionValue) - { - string rootOutputPath = string.Empty; - - if (string.IsNullOrEmpty(outputOptionValue)) - { - rootOutputPath = context.ProjectFile.ProjectDirectory; - } - - return rootOutputPath; - } - private static void CleanOrCreateDirectory(string path) { if (Directory.Exists(path)) @@ -686,147 +533,79 @@ namespace Microsoft.DotNet.Tools.Compiler Reporter.Output.WriteLine(); - Reporter.Output.WriteLine($"Time elapsed {sw.Elapsed}"); - Reporter.Output.WriteLine(); + Reporter.Output.Write($"Time elapsed {sw.Elapsed}"); return success; } - private static bool AddResources(Project project, List compilerArgs, string intermediateOutputPath) + private static bool AddNonCultureResources(Project project, List compilerArgs, string intermediateOutputPath) { + var resgenFiles = CompilerUtil.GetNonCultureResources(project, intermediateOutputPath); - foreach (var resourceFile in project.Files.ResourceFiles) + foreach (var resgenFile in resgenFiles) { - var resourcePath = resourceFile.Key; - - if (!string.IsNullOrEmpty(ResourceUtility.GetResourceCultureName(resourcePath))) + if (ResourceUtility.IsResxFile(resgenFile.InputFile)) { - // Include only "neutral" resources into main assembly - continue; + var result = + Command.Create("dotnet-resgen", + $"\"{resgenFile.InputFile}\" -o \"{resgenFile.OutputFile}\" -v \"{project.Version.Version}\"") + .ForwardStdErr() + .ForwardStdOut() + .Execute(); + + if (result.ExitCode != 0) + { + return false; + } + + compilerArgs.Add($"--resource:\"{resgenFile.OutputFile}\",{Path.GetFileName(resgenFile.MetadataName)}"); + } + else + { + compilerArgs.Add($"--resource:\"{resgenFile.InputFile}\",{Path.GetFileName(resgenFile.MetadataName)}"); + } + } + + return true; + } + + private static bool GenerateCultureResourceAssemblies(Project project, List dependencies, string outputPath) + { + var referencePaths = CompilerUtil.GetReferencePathsForCultureResgen(dependencies); + var resgenReferenceArgs = referencePaths.Select(referencePath => $"-r \"{referencePath}\"").ToList(); + + var cultureResgenFiles = CompilerUtil.GetCultureResources(project, outputPath); + + foreach (var resgenFile in cultureResgenFiles) + { + var resourceOutputPath = Path.GetDirectoryName(resgenFile.OutputFile); + + if (!Directory.Exists(resourceOutputPath)) + { + Directory.CreateDirectory(resourceOutputPath); } - var name = GetResourceFileMetadataName(project, resourceFile); + var arguments = new List(); - var fileName = resourcePath; + arguments.AddRange(resgenReferenceArgs); + arguments.Add($"-o \"{resgenFile.OutputFile}\""); + arguments.Add($"-c {resgenFile.Culture}"); + arguments.Add($"-v {project.Version.Version}"); + arguments.AddRange(resgenFile.InputFileToMetadata.Select(fileToMetadata => $"\"{fileToMetadata.Key}\",{fileToMetadata.Value}")); - if (ResourceUtility.IsResxFile(fileName)) - { - // {file}.resx -> {file}.resources - var resourcesFile = Path.Combine(intermediateOutputPath, name); - - var result = Command.Create("dotnet-resgen", $"\"{fileName}\" -o \"{resourcesFile}\" -v \"{project.Version.Version}\"") + var result = Command.Create("dotnet-resgen", arguments) .ForwardStdErr() .ForwardStdOut() .Execute(); - - if (result.ExitCode != 0) - { - return false; - } - - // Use this as the resource name instead - fileName = resourcesFile; + if (result.ExitCode != 0) + { + return false; } - - compilerArgs.Add($"--resource:\"{fileName}\",{name}"); } return true; } - private static string GetResourceFileMetadataName(Project project, KeyValuePair resourceFile) - { - string resourceName = null; - string rootNamespace = null; - - string root = PathUtility.EnsureTrailingSlash(project.ProjectDirectory); - string resourcePath = resourceFile.Key; - if (string.IsNullOrEmpty(resourceFile.Value)) - { - // No logical name, so use the file name - resourceName = ResourceUtility.GetResourceName(root, resourcePath); - rootNamespace = project.Name; - } - else - { - resourceName = ResourceManifestName.EnsureResourceExtension(resourceFile.Value, resourcePath); - rootNamespace = null; - } - - var name = ResourceManifestName.CreateManifestName(resourceName, rootNamespace); - return name; - } - - private static bool GenerateResourceAssemblies(Project project, List dependencies, string outputPath, string configuration) - { - var references = dependencies.SelectMany(libraryExport => libraryExport.CompilationAssemblies); - - foreach (var resourceFileGroup in project.Files.ResourceFiles.GroupBy(file => ResourceUtility.GetResourceCultureName(file.Key))) - { - var culture = resourceFileGroup.Key; - if (!string.IsNullOrEmpty(culture)) - { - var resourceOutputPath = Path.Combine(outputPath, culture); - - if (!Directory.Exists(resourceOutputPath)) - { - Directory.CreateDirectory(resourceOutputPath); - } - - var resourceOuputFile = Path.Combine(resourceOutputPath, project.Name + ".resources.dll"); - - var arguments = new List(); - arguments.AddRange(references.Select(r => $"-r \"{r.ResolvedPath}\"")); - arguments.Add($"-o \"{resourceOuputFile}\""); - arguments.Add($"-c {culture}"); - arguments.Add($"-v {project.Version.Version}"); - - foreach (var resourceFile in resourceFileGroup) - { - var metadataName = GetResourceFileMetadataName(project, resourceFile); - arguments.Add($"\"{resourceFile.Key}\",{metadataName}"); - } - - var result = Command.Create("dotnet-resgen", arguments) - .ForwardStdErr() - .ForwardStdOut() - .Execute(); - if (result.ExitCode != 0) - { - return false; - } - } - } - return true; - } - - private static ISet Sort(Dictionary projects) - { - var outputs = new HashSet(); - - foreach (var pair in projects) - { - Sort(pair.Value, projects, outputs); - } - - return outputs; - } - - private static void Sort(ProjectDescription project, Dictionary projects, ISet outputs) - { - // Sorts projects in dependency order so that we only build them once per chain - foreach (var dependency in project.Dependencies) - { - ProjectDescription projectDependency; - if (projects.TryGetValue(dependency.Name, out projectDependency)) - { - Sort(projectDependency, projects, outputs); - } - } - - outputs.Add(project); - } - private static DiagnosticMessage ParseDiagnostic(string projectRootPath, string line) { var error = CanonicalError.Parse(line); diff --git a/src/Microsoft.DotNet.Tools.Compiler/README.md b/src/Microsoft.DotNet.Tools.Compiler/README.md index 392b01ccb..4d4cff7ad 100644 --- a/src/Microsoft.DotNet.Tools.Compiler/README.md +++ b/src/Microsoft.DotNet.Tools.Compiler/README.md @@ -2,13 +2,15 @@ dotnet-compile =========== **NAME** -dotnet-compile -- Compiles source files to a binary format and saves to a target file. +dotnet-compile -- Compiles source files for a single project to a binary format and saves to a target file. **SYNOPSIS** dotnet compile [options] **DESCRIPTION** -The compile command compiles source files to a binary file, either IL byte code or native machine code, depending on the options provided. The default option is compilation to IL byte code, but may change in the future. +The compile command compiles source files from a single project to a binary file, either IL byte code or native machine code, depending on the options provided. The default option is compilation to IL byte code, but may change in the future. + +Users who want to benefit from incremental builds and who want to compile both the project and its dependencies should use the Build command. The default IL [--il] output is a PE32 exe [exe], with the default extension of ".exe" on all OSes. The exe must include a public static void or public static int main entry point, or it is an error. The dll [dll] output option has the default extension of ".dll". @@ -48,4 +50,4 @@ Compiles source to IL byte code, which is (typically) portable across machine ty Specifies the filename to be used. It is an error not to specify an output filename. If no extension is provided, the default one is provided for the output type. -v, --verbose -Prints verbose logging information, to follow the flow of execution of the command. +Prints verbose logging information, to follow the flow of execution of the command. \ No newline at end of file diff --git a/src/Microsoft.DotNet.Tools.Pack/Program.cs b/src/Microsoft.DotNet.Tools.Pack/Program.cs index b3917677c..191eb8bce 100644 --- a/src/Microsoft.DotNet.Tools.Pack/Program.cs +++ b/src/Microsoft.DotNet.Tools.Pack/Program.cs @@ -101,7 +101,7 @@ namespace Microsoft.DotNet.Tools.Compiler argsBuilder.Append($" \"{path}\""); - var result = Command.Create("dotnet-compile", argsBuilder.ToString()) + var result = Command.Create("dotnet-build", argsBuilder.ToString()) .ForwardStdOut() .ForwardStdErr() .Execute(); diff --git a/src/Microsoft.DotNet.Tools.Publish/PublishCommand.cs b/src/Microsoft.DotNet.Tools.Publish/PublishCommand.cs index 9fd50bffb..de640f35d 100644 --- a/src/Microsoft.DotNet.Tools.Publish/PublishCommand.cs +++ b/src/Microsoft.DotNet.Tools.Publish/PublishCommand.cs @@ -119,7 +119,7 @@ namespace Microsoft.DotNet.Tools.Publish } // Compile the project (and transitively, all it's dependencies) - var result = Command.Create("dotnet-compile", + var result = Command.Create("dotnet-build", $"--framework \"{context.TargetFramework.DotNetFrameworkName}\" " + $"--output \"{outputPath}\" " + $"--configuration \"{configuration}\" " + diff --git a/src/Microsoft.DotNet.Tools.Run/RunCommand.cs b/src/Microsoft.DotNet.Tools.Run/RunCommand.cs index 8995876de..010f25d14 100644 --- a/src/Microsoft.DotNet.Tools.Run/RunCommand.cs +++ b/src/Microsoft.DotNet.Tools.Run/RunCommand.cs @@ -90,7 +90,7 @@ namespace Microsoft.DotNet.Tools.Run var tempDir = Path.Combine(_context.ProjectDirectory, "bin", ".dotnetrun", Guid.NewGuid().ToString("N")); // Compile to that directory - var result = Command.Create($"dotnet-compile", $"--output \"{tempDir}\" --temp-output \"{tempDir}\" --framework \"{_context.TargetFramework}\" --configuration \"{Configuration}\" {_context.ProjectFile.ProjectDirectory}") + var result = Command.Create($"dotnet-build", $"--output \"{tempDir}\" --temp-output \"{tempDir}\" --framework \"{_context.TargetFramework}\" --configuration \"{Configuration}\" {_context.ProjectFile.ProjectDirectory}") .ForwardStdOut(onlyIfVerbose: true) .ForwardStdErr() .Execute(); diff --git a/test/E2E/E2ETest.cs b/test/E2E/E2ETest.cs index 0165f63d0..ae1df8b8c 100644 --- a/test/E2E/E2ETest.cs +++ b/test/E2E/E2ETest.cs @@ -46,7 +46,7 @@ namespace ConsoleApplication { TestSetup(); - TestRunCommand("dotnet", $"compile -o {OutputDirectory}"); + TestRunCommand("dotnet", $"build -o {OutputDirectory}"); TestOutputExecutable(OutputDirectory); } @@ -60,7 +60,7 @@ namespace ConsoleApplication TestSetup(); - TestRunCommand("dotnet", $"compile --native -o {OutputDirectory}"); + TestRunCommand("dotnet", $"build --native -o {OutputDirectory}"); var nativeOut = Path.Combine(OutputDirectory, "native"); TestOutputExecutable(nativeOut); @@ -71,7 +71,7 @@ namespace ConsoleApplication { TestSetup(); - TestRunCommand("dotnet", $"compile --native --cpp -o {OutputDirectory}"); + TestRunCommand("dotnet", $"build --native --cpp -o {OutputDirectory}"); var nativeOut = Path.Combine(OutputDirectory, "native"); TestOutputExecutable(nativeOut);