- Make all of the code looking for built assets use the OutputPathCalculator

- Project dependencies are always built into their specific folders and the main project is the only one that uses the output path and intermediate output path variable.
- Publish respects the output path for publish only, not compile as part of publish. This means that publishing multiple runtimes will stomp on each other. So don't do that. We can throw if you specify and output location and you haven't specified a specific combination of RID and framework. Alternatively it should probably just pick the first TFM/RID pair from the lock file. This is similar to how `dotnet run` works.
- Cleaned up the incremental build output formatting
- Use a single stream (output stream) since interleaving them was causing formatting issues (like losing random characters in the middle of outputting things).
- Didn't change how pack works, it still preserves the output structure when passing `--output`, this one is worth discussing. We could leave the build output inplace and only move the package to the output location. That's more consistent with how everything else works and can be a follow up PR.
This commit is contained in:
David Fowler 2016-01-26 06:39:13 -08:00
parent 788194e48e
commit a35ae177ff
22 changed files with 190 additions and 174 deletions

View file

@ -9,7 +9,6 @@ $TestPackagesPath = "$RepoRoot\tests\packages"
$ArgTestRoot = "$RepoRoot\test\ArgumentForwardingTests" $ArgTestRoot = "$RepoRoot\test\ArgumentForwardingTests"
$ArgTestOutputRoot = "$RepoRoot\artifacts\tests\arg-forwarding" $ArgTestOutputRoot = "$RepoRoot\artifacts\tests\arg-forwarding"
$ArgTestBin = "$ArgTestOutputRoot\$Configuration\dnxcore50"
dotnet publish --framework "dnxcore50" --runtime "$Rid" --output "$ArgTestOutputRoot" --configuration "$Configuration" "$ArgTestRoot\Reflector" dotnet publish --framework "dnxcore50" --runtime "$Rid" --output "$ArgTestOutputRoot" --configuration "$Configuration" "$ArgTestRoot\Reflector"
if (!$?) { if (!$?) {
@ -23,9 +22,9 @@ if (!$?) {
Exit 1 Exit 1
} }
cp "$ArgTestRoot\Reflector\reflector_cmd.cmd" "$ArgTestBin" cp "$ArgTestRoot\Reflector\reflector_cmd.cmd" "$ArgTestOutputRoot"
pushd "$ArgTestBin" pushd "$ArgTestOutputRoot"
& ".\corerun" "xunit.console.netcore.exe" "ArgumentForwardingTests.dll" -xml "$_-testResults.xml" -notrait category=failing & ".\corerun" "xunit.console.netcore.exe" "ArgumentForwardingTests.dll" -xml "$_-testResults.xml" -notrait category=failing
$exitCode = $LastExitCode $exitCode = $LastExitCode

View file

@ -19,13 +19,12 @@ source "$DIR/../common/_common.sh"
ArgTestRoot="$REPOROOT/test/ArgumentForwardingTests" ArgTestRoot="$REPOROOT/test/ArgumentForwardingTests"
ArgTestOutputRoot="$REPOROOT/artifacts/tests/arg-forwarding" ArgTestOutputRoot="$REPOROOT/artifacts/tests/arg-forwarding"
ArgTestBin="$ArgTestOutputRoot/$CONFIGURATION/dnxcore50"
dotnet publish --framework "dnxcore50" --output "$ArgTestOutputRoot" --configuration "$CONFIGURATION" "$ArgTestRoot/Reflector" dotnet publish --framework "dnxcore50" --output "$ArgTestOutputRoot" --configuration "$CONFIGURATION" "$ArgTestRoot/Reflector"
dotnet publish --framework "dnxcore50" --output "$ArgTestOutputRoot" --configuration "$CONFIGURATION" "$ArgTestRoot/ArgumentForwardingTests" dotnet publish --framework "dnxcore50" --output "$ArgTestOutputRoot" --configuration "$CONFIGURATION" "$ArgTestRoot/ArgumentForwardingTests"
pushd "$ArgTestBin" pushd "$ArgTestOutputRoot"
./corerun "xunit.console.netcore.exe" "ArgumentForwardingTests.dll" -xml "ArgumentForwardingTests-testResults.xml" -notrait category=failing ./corerun "xunit.console.netcore.exe" "ArgumentForwardingTests.dll" -xml "ArgumentForwardingTests-testResults.xml" -notrait category=failing
popd popd

View file

@ -207,7 +207,7 @@ namespace Microsoft.DotNet.Cli.Utils
private static string GetDepsPath(ProjectContext context, string buildConfiguration) private static string GetDepsPath(ProjectContext context, string buildConfiguration)
{ {
return Path.Combine(context.GetOutputDirectoryPath(buildConfiguration), return Path.Combine(context.GetOutputPathCalculator().GetOutputDirectoryPath(buildConfiguration),
context.ProjectFile.Name + FileNameSuffixes.Deps); context.ProjectFile.Name + FileNameSuffixes.Deps);
} }

View file

@ -20,8 +20,8 @@ namespace Microsoft.DotNet.Cli.Utils
} }
public static Reporter Output { get; } = Create(AnsiConsole.GetOutput); public static Reporter Output { get; } = Create(AnsiConsole.GetOutput);
public static Reporter Error { get; } = Create(AnsiConsole.GetError); public static Reporter Error { get; } = Create(AnsiConsole.GetOutput);
public static Reporter Verbose { get; } = CommandContext.IsVerbose() ? Create(AnsiConsole.GetError) : Null; public static Reporter Verbose { get; } = CommandContext.IsVerbose() ? Create(AnsiConsole.GetOutput) : Null;
public static Reporter Create(Func<bool, AnsiConsole> getter) public static Reporter Create(Func<bool, AnsiConsole> getter)
{ {

View file

@ -1,22 +1,12 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Compilation; using Microsoft.DotNet.ProjectModel.Compilation;
namespace Microsoft.DotNet.Cli.Compiler.Common namespace Microsoft.DotNet.Cli.Compiler.Common
{ {
public static class LibraryExporterExtensions public static class LibraryExporterExtensions
{ {
internal static void CopyProjectDependenciesTo(this LibraryExporter exporter, string path, params ProjectDescription[] except)
{
exporter.GetAllExports()
.Where(e => !except.Contains(e.Library))
.Where(e => e.Library is ProjectDescription)
.SelectMany(e => e.NativeLibraries.Union(e.RuntimeAssemblies))
.CopyTo(path);
}
public static void WriteDepsTo(this IEnumerable<LibraryExport> exports, string path) public static void WriteDepsTo(this IEnumerable<LibraryExport> exports, string path)
{ {
File.WriteAllLines(path, exports.SelectMany(GenerateLines)); File.WriteAllLines(path, exports.SelectMany(GenerateLines));

View file

@ -19,6 +19,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
public static class ProjectContextExtensions public static class ProjectContextExtensions
{ {
public static string ProjectName(this ProjectContext context) => context.RootProject.Identity.Name; public static string ProjectName(this ProjectContext context) => context.RootProject.Identity.Name;
public static string GetDisplayName(this ProjectContext context) => $"{context.RootProject.Identity.Name} ({context.TargetFramework})";
public static void MakeCompilationOutputRunnable(this ProjectContext context, string outputPath, string configuration) public static void MakeCompilationOutputRunnable(this ProjectContext context, string outputPath, string configuration)
{ {

View file

@ -37,7 +37,7 @@ namespace Microsoft.DotNet.ProjectModel.Loader
dllImports, dllImports,
// Add the project's output directory path to ensure project-to-project references get located // Add the project's output directory path to ensure project-to-project references get located
new[] { context.GetOutputDirectoryPath(configuration) }); new[] { context.GetOutputPathCalculator().GetOutputDirectoryPath(configuration) });
} }
} }
} }

View file

@ -163,6 +163,11 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
assemblyPath, assemblyPath,
Path.Combine(project.Project.ProjectDirectory, assemblyPath))); Path.Combine(project.Project.ProjectDirectory, assemblyPath)));
} }
else
{
var assemblyPath = project.GetOutputPathCalculator().GetAssemblyPath(_configuration);
compileAssemblies.Add(new LibraryAsset(project.Identity.Name, null, assemblyPath));
}
// Add shared sources // Add shared sources
foreach (var sharedFile in project.Project.Files.SharedFiles) foreach (var sharedFile in project.Project.Files.SharedFiles)

View file

@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using NuGet.Frameworks; using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel namespace Microsoft.DotNet.ProjectModel
@ -10,7 +11,10 @@ namespace Microsoft.DotNet.ProjectModel
{ {
private const string ObjDirectoryName = "obj"; private const string ObjDirectoryName = "obj";
private readonly ProjectContext _project; private readonly Project _project;
private readonly NuGetFramework _framework;
private readonly string _runtimeIdentifier;
/// <summary> /// <summary>
/// Unaltered output path. Either what is passed in in the constructor, or the project directory. /// Unaltered output path. Either what is passed in in the constructor, or the project directory.
@ -20,10 +24,14 @@ namespace Microsoft.DotNet.ProjectModel
public string BaseCompilationOutputPath { get; } public string BaseCompilationOutputPath { get; }
public OutputPathCalculator( public OutputPathCalculator(
ProjectContext project, Project project,
NuGetFramework framework,
string runtimeIdentifier,
string baseOutputPath) string baseOutputPath)
{ {
_project = project; _project = project;
_framework = framework;
_runtimeIdentifier = runtimeIdentifier;
BaseOutputPath = string.IsNullOrWhiteSpace(baseOutputPath) ? _project.ProjectDirectory : baseOutputPath; BaseOutputPath = string.IsNullOrWhiteSpace(baseOutputPath) ? _project.ProjectDirectory : baseOutputPath;
@ -32,17 +40,21 @@ namespace Microsoft.DotNet.ProjectModel
: baseOutputPath; : baseOutputPath;
} }
public string GetCompilationOutputPath(string buildConfiguration) public string GetOutputDirectoryPath(string buildConfiguration)
{ {
var outDir = Path.Combine( var outDir = Path.Combine(BaseCompilationOutputPath,
BaseCompilationOutputPath,
buildConfiguration, buildConfiguration,
_project.TargetFramework.GetTwoDigitShortFolderName()); _framework.GetShortFolderName());
if (!string.IsNullOrEmpty(_runtimeIdentifier))
{
outDir = Path.Combine(outDir, _runtimeIdentifier);
}
return outDir; return outDir;
} }
public string GetIntermediateOutputPath(string buildConfiguration, string intermediateOutputValue) public string GetIntermediateOutputDirectoryPath(string buildConfiguration, string intermediateOutputValue)
{ {
string intermediateOutputPath; string intermediateOutputPath;
@ -52,7 +64,7 @@ namespace Microsoft.DotNet.ProjectModel
BaseOutputPath, BaseOutputPath,
ObjDirectoryName, ObjDirectoryName,
buildConfiguration, buildConfiguration,
_project.TargetFramework.GetTwoDigitShortFolderName()); _framework.GetTwoDigitShortFolderName());
} }
else else
{ {
@ -61,5 +73,43 @@ namespace Microsoft.DotNet.ProjectModel
return intermediateOutputPath; return intermediateOutputPath;
} }
public string GetAssemblyPath(string buildConfiguration)
{
var compilationOptions = _project.GetCompilerOptions(_framework, buildConfiguration);
var outputExtension = FileNameSuffixes.DotNet.DynamicLib;
if (_framework.IsDesktop() && compilationOptions.EmitEntryPoint.GetValueOrDefault())
{
outputExtension = FileNameSuffixes.DotNet.Exe;
}
return Path.Combine(
GetOutputDirectoryPath(buildConfiguration),
_project.Name + outputExtension);
}
public string GetExecutablePath(string buildConfiguration)
{
var extension = FileNameSuffixes.CurrentPlatform.Exe;
// This is the check for mono, if we're not on windows and producing outputs for
// the desktop framework then it's an exe
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _framework.IsDesktop())
{
extension = FileNameSuffixes.DotNet.Exe;
}
return Path.Combine(
GetOutputDirectoryPath(buildConfiguration),
_project.Name + extension);
}
public string GetPdbPath(string buildConfiguration)
{
return Path.Combine(
GetOutputDirectoryPath(buildConfiguration),
_project.Name + FileNameSuffixes.DotNet.ProgramDatabase);
}
} }
} }

View file

@ -120,37 +120,9 @@ namespace Microsoft.DotNet.ProjectModel
.BuildAllTargets(); .BuildAllTargets();
} }
public string GetAssemblyPath(string buildConfiguration) public OutputPathCalculator GetOutputPathCalculator(string baseOutputPath = null)
{ {
return Path.Combine( return new OutputPathCalculator(ProjectFile, TargetFramework, RuntimeIdentifier, baseOutputPath);
GetOutputDirectoryPath(buildConfiguration),
ProjectFile.Name + FileNameSuffixes.DotNet.DynamicLib);
}
public string GetPdbPath(string buildConfiguration)
{
return Path.Combine(
GetOutputDirectoryPath(buildConfiguration),
ProjectFile.Name + FileNameSuffixes.DotNet.ProgramDatabase);
}
public string GetOutputDirectoryPath(string buildConfiguration)
{
var outDir = Path.Combine(
ProjectDirectory,
DirectoryNames.Bin,
buildConfiguration,
TargetFramework.GetShortFolderName());
if (!string.IsNullOrEmpty(RuntimeIdentifier))
{
outDir = Path.Combine(outDir, RuntimeIdentifier);
}
return outDir;
}
public OutputPathCalculator GetOutputPathCalculator(string rootOutputPath)
{
return new OutputPathCalculator(this, rootOutputPath);
} }
} }
} }

View file

@ -43,5 +43,10 @@ namespace Microsoft.DotNet.ProjectModel
public Project Project { get; } public Project Project { get; }
public TargetFrameworkInformation TargetFrameworkInfo { get; } public TargetFrameworkInformation TargetFrameworkInfo { get; }
public OutputPathCalculator GetOutputPathCalculator()
{
return new OutputPathCalculator(Project, Framework, runtimeIdentifier: null, baseOutputPath: null);
}
} }
} }

View file

@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -20,7 +19,6 @@ namespace Microsoft.DotNet.Tools.Build
// Collects icnremental safety checks and transitively compiles a project context // Collects icnremental safety checks and transitively compiles a project context
internal class CompileContext internal class CompileContext
{ {
public static readonly string[] KnownCompilers = { "csc", "vbc", "fsc" }; public static readonly string[] KnownCompilers = { "csc", "vbc", "fsc" };
private readonly ProjectContext _rootProject; private readonly ProjectContext _rootProject;
@ -36,13 +34,13 @@ namespace Microsoft.DotNet.Tools.Build
// Cleaner to clone the args and mutate the clone than have separate CompileContext fields for mutated args // Cleaner to clone the args and mutate the clone than have separate CompileContext fields for mutated args
// and then reasoning which ones to get from args and which ones from fields. // and then reasoning which ones to get from args and which ones from fields.
_args = (BuilderCommandApp) args.ShallowCopy(); _args = (BuilderCommandApp)args.ShallowCopy();
// Set up Output Paths. They are unique per each CompileContext // Set up Output Paths. They are unique per each CompileContext
var outputPathCalculator = _rootProject.GetOutputPathCalculator(_args.OutputValue); var outputPathCalculator = _rootProject.GetOutputPathCalculator(_args.OutputValue);
_args.OutputValue = outputPathCalculator.BaseCompilationOutputPath; _args.OutputValue = outputPathCalculator.BaseCompilationOutputPath;
_args.IntermediateValue = _args.IntermediateValue =
outputPathCalculator.GetIntermediateOutputPath(_args.ConfigValue, _args.IntermediateValue); outputPathCalculator.GetIntermediateOutputDirectoryPath(_args.ConfigValue, _args.IntermediateValue);
// Set up dependencies // Set up dependencies
_dependencies = new ProjectDependenciesFacade(_rootProject, _args.ConfigValue); _dependencies = new ProjectDependenciesFacade(_rootProject, _args.ConfigValue);
@ -62,7 +60,7 @@ namespace Microsoft.DotNet.Tools.Build
{ {
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework); var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework);
if (!NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue))) if (!DependencyNeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue)))
{ {
continue; continue;
} }
@ -88,14 +86,24 @@ namespace Microsoft.DotNet.Tools.Build
return success; return success;
} }
private bool DependencyNeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies)
{
return NeedsRebuilding(project, dependencies, buildOutputPath: null, intermediateOutputPath: null);
}
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies) private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies)
{ {
var compilerIO = GetCompileIO(project, _args.ConfigValue, _args.OutputValue, _args.IntermediateValue, dependencies); return NeedsRebuilding(project, dependencies, _args.OutputValue, _args.IntermediateValue);
}
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies, string buildOutputPath, string intermediateOutputPath)
{
var compilerIO = GetCompileIO(project, _args.ConfigValue, buildOutputPath, intermediateOutputPath, dependencies);
// rebuild if empty inputs / outputs // rebuild if empty inputs / outputs
if (!(compilerIO.Outputs.Any() && compilerIO.Inputs.Any())) if (!(compilerIO.Outputs.Any() && compilerIO.Inputs.Any()))
{ {
Reporter.Output.WriteLine($"\nProject {project.ProjectName()} will be compiled because it either has empty inputs or outputs"); Reporter.Output.WriteLine($"Project {project.GetDisplayName()} will be compiled because it either has empty inputs or outputs");
return true; return true;
} }
@ -125,19 +133,25 @@ namespace Microsoft.DotNet.Tools.Build
if (!newInputs.Any()) if (!newInputs.Any())
{ {
Reporter.Output.WriteLine($"\nProject {project.ProjectName()} was previously compiled. Skipping compilation."); Reporter.Output.WriteLine($"Project {project.GetDisplayName()} was previously compiled. Skipping compilation.");
return false; return false;
} }
Reporter.Output.WriteLine($"\nProject {project.ProjectName()} will be compiled because some of its inputs were newer than its oldest output."); Reporter.Output.WriteLine($"Project {project.GetDisplayName()} will be compiled because some of its inputs were newer than its oldest output.");
Reporter.Verbose.WriteLine($"Oldest output item was written at {minDate} : {minOutputPath}"); Reporter.Verbose.WriteLine();
Reporter.Verbose.WriteLine($"Inputs newer than the oldest output item:"); Reporter.Verbose.WriteLine($" Oldest output item:");
Reporter.Verbose.WriteLine($" {minDate}: {minOutputPath}");
Reporter.Verbose.WriteLine();
Reporter.Verbose.WriteLine($" Inputs newer than the oldest output item:");
foreach (var newInput in newInputs) foreach (var newInput in newInputs)
{ {
Reporter.Verbose.WriteLine($"\t{File.GetLastWriteTime(newInput)}\t:\t{newInput}"); Reporter.Verbose.WriteLine($" {File.GetLastWriteTime(newInput)}: {newInput}");
} }
Reporter.Verbose.WriteLine();
return true; return true;
} }
@ -150,14 +164,14 @@ namespace Microsoft.DotNet.Tools.Build
return false; return false;
} }
Reporter.Output.WriteLine($"\nProject {project.ProjectName()} will be compiled because expected {itemsType} are missing. "); Reporter.Verbose.WriteLine($"Project {project.GetDisplayName()} will be compiled because expected {itemsType} are missing.");
foreach (var missing in missingItems) foreach (var missing in missingItems)
{ {
Reporter.Verbose.WriteLine($"\t {missing}"); Reporter.Verbose.WriteLine($" {missing}");
} }
Reporter.Output.WriteLine(); Reporter.Verbose.WriteLine(); ;
return true; return true;
} }
@ -205,7 +219,7 @@ namespace Microsoft.DotNet.Tools.Build
private List<ProjectContext> GetProjectsToCheck() private List<ProjectContext> GetProjectsToCheck()
{ {
// include initial root project // include initial root project
var contextsToCheck = new List<ProjectContext>(1 + _dependencies.ProjectDependenciesWithSources.Count) {_rootProject}; var contextsToCheck = new List<ProjectContext>(1 + _dependencies.ProjectDependenciesWithSources.Count) { _rootProject };
// convert ProjectDescription to ProjectContext // convert ProjectDescription to ProjectContext
var dependencyContexts = _dependencies.ProjectDependenciesWithSources.Select var dependencyContexts = _dependencies.ProjectDependenciesWithSources.Select
@ -262,12 +276,8 @@ namespace Microsoft.DotNet.Tools.Build
args.Add("--framework"); args.Add("--framework");
args.Add($"{projectDependency.Framework}"); args.Add($"{projectDependency.Framework}");
args.Add("--configuration"); args.Add("--configuration");
args.Add($"{_args.ConfigValue}"); args.Add(_args.ConfigValue);
args.Add("--output"); args.Add(projectDependency.Project.ProjectDirectory);
args.Add($"{_args.OutputValue}");
args.Add("--temp-output");
args.Add($"{_args.IntermediateValue}");
args.Add($"{projectDependency.Project.ProjectDirectory}");
if (_args.NoHostValue) if (_args.NoHostValue)
{ {
@ -337,7 +347,7 @@ namespace Microsoft.DotNet.Tools.Build
args.Add(_rootProject.ProjectDirectory); args.Add(_rootProject.ProjectDirectory);
var compileResult = Command.Create("dotnet-compile",args) var compileResult = Command.Create("dotnet-compile", args)
.ForwardStdOut() .ForwardStdOut()
.ForwardStdErr() .ForwardStdErr()
.Execute(); .Execute();
@ -387,11 +397,17 @@ namespace Microsoft.DotNet.Tools.Build
// computes all the inputs and outputs that would be used in the compilation of a project // computes all the inputs and outputs that would be used in the compilation of a project
// ensures that all paths are files // ensures that all paths are files
// ensures no missing inputs // ensures no missing inputs
public static CompilerIO GetCompileIO(ProjectContext project, string config, string outputPath, string intermediaryOutputPath, ProjectDependenciesFacade dependencies) public static CompilerIO GetCompileIO(
ProjectContext project,
string buildConfiguration,
string outputPath,
string intermediaryOutputPath,
ProjectDependenciesFacade dependencies)
{ {
var compilerIO = new CompilerIO(new List<string>(), new List<string>()); var compilerIO = new CompilerIO(new List<string>(), new List<string>());
var binariesOutputPath = project.GetOutputPathCalculator(outputPath).GetCompilationOutputPath(config); var calculator = project.GetOutputPathCalculator(outputPath);
var compilationOutput = CompilerUtil.GetCompilationOutput(project.ProjectFile, project.TargetFramework, config, binariesOutputPath); var binariesOutputPath = calculator.GetOutputDirectoryPath(buildConfiguration);
var compilationOutput = calculator.GetAssemblyPath(buildConfiguration);
// input: project.json // input: project.json
compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath); compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);
@ -410,7 +426,7 @@ namespace Microsoft.DotNet.Tools.Build
compilerIO.Outputs.Add(compilationOutput); compilerIO.Outputs.Add(compilationOutput);
// input / output: compilation options files // input / output: compilation options files
AddFilesFromCompilationOptions(project, config, compilationOutput, compilerIO); AddFilesFromCompilationOptions(project, buildConfiguration, compilationOutput, compilerIO);
// input / output: resources without culture // input / output: resources without culture
AddCultureResources(project, intermediaryOutputPath, compilerIO); AddCultureResources(project, intermediaryOutputPath, compilerIO);
@ -423,7 +439,7 @@ namespace Microsoft.DotNet.Tools.Build
private static void AddLockFile(ProjectContext project, CompilerIO compilerIO) private static void AddLockFile(ProjectContext project, CompilerIO compilerIO)
{ {
if(project.LockFile == null) if (project.LockFile == null)
{ {
var errorMessage = $"Project {project.ProjectName()} does not have a lock file."; var errorMessage = $"Project {project.ProjectName()} does not have a lock file.";
Reporter.Error.WriteLine(errorMessage); Reporter.Error.WriteLine(errorMessage);

View file

@ -125,20 +125,6 @@ namespace Microsoft.DotNet.Tools.Compiler
// used in incremental compilation // used in incremental compilation
public static IEnumerable<string> GetCompilationSources(ProjectContext project) => project.ProjectFile.Files.SourceFiles; public static IEnumerable<string> GetCompilationSources(ProjectContext project) => project.ProjectFile.Files.SourceFiles;
// used in incremental compilation
public static string GetCompilationOutput(Project project, NuGetFramework framework, string configuration, string outputPath)
{
var compilationOptions = project.GetCompilerOptions(framework, configuration);
var outputExtension = ".dll";
if (framework.IsDesktop() && compilationOptions.EmitEntryPoint.GetValueOrDefault())
{
outputExtension = ".exe";
}
return Path.Combine(outputPath, project.Name + outputExtension);
}
// used in incremental compilation for the key file // used in incremental compilation for the key file
public static CommonCompilerOptions ResolveCompilationOptions(ProjectContext context, string configuration) public static CommonCompilerOptions ResolveCompilationOptions(ProjectContext context, string configuration)
{ {

View file

@ -61,17 +61,16 @@ namespace Microsoft.DotNet.Tools.Compiler
CompilerCommandApp args) CompilerCommandApp args)
{ {
var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue); var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue);
var outputPath = outputPathCalculator.GetCompilationOutputPath(args.ConfigValue); var outputPath = outputPathCalculator.GetOutputDirectoryPath(args.ConfigValue);
var nativeOutputPath = Path.Combine(outputPath, "native"); var nativeOutputPath = Path.Combine(outputPath, "native");
var intermediateOutputPath = var intermediateOutputPath =
outputPathCalculator.GetIntermediateOutputPath(args.ConfigValue, args.IntermediateValue); outputPathCalculator.GetIntermediateOutputDirectoryPath(args.ConfigValue, args.IntermediateValue);
var nativeIntermediateOutputPath = Path.Combine(intermediateOutputPath, "native"); var nativeIntermediateOutputPath = Path.Combine(intermediateOutputPath, "native");
Directory.CreateDirectory(nativeOutputPath); Directory.CreateDirectory(nativeOutputPath);
Directory.CreateDirectory(nativeIntermediateOutputPath); Directory.CreateDirectory(nativeIntermediateOutputPath);
var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, args.ConfigValue); var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, args.ConfigValue);
var managedOutput = var managedOutput = outputPathCalculator.GetAssemblyPath(args.ConfigValue);
CompilerUtil.GetCompilationOutput(context.ProjectFile, context.TargetFramework, args.ConfigValue, outputPath);
var nativeArgs = new List<string>(); var nativeArgs = new List<string>();
@ -161,9 +160,9 @@ namespace Microsoft.DotNet.Tools.Compiler
{ {
// Set up Output Paths // Set up Output Paths
var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue); var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue);
var outputPath = outputPathCalculator.GetCompilationOutputPath(args.ConfigValue); var outputPath = outputPathCalculator.GetOutputDirectoryPath(args.ConfigValue);
var intermediateOutputPath = var intermediateOutputPath =
outputPathCalculator.GetIntermediateOutputPath(args.ConfigValue, args.IntermediateValue); outputPathCalculator.GetIntermediateOutputDirectoryPath(args.ConfigValue, args.IntermediateValue);
Directory.CreateDirectory(outputPath); Directory.CreateDirectory(outputPath);
Directory.CreateDirectory(intermediateOutputPath); Directory.CreateDirectory(intermediateOutputPath);
@ -201,7 +200,7 @@ namespace Microsoft.DotNet.Tools.Compiler
} }
// Get compilation options // Get compilation options
var outputName = CompilerUtil.GetCompilationOutput(context.ProjectFile, context.TargetFramework, args.ConfigValue, outputPath); var outputName = outputPathCalculator.GetAssemblyPath(args.ConfigValue);
// Assemble args // Assemble args
var compilerArgs = new List<string>() var compilerArgs = new List<string>()
@ -223,21 +222,7 @@ namespace Microsoft.DotNet.Tools.Compiler
foreach (var dependency in dependencies) foreach (var dependency in dependencies)
{ {
var projectDependency = dependency.Library as ProjectDescription; references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath));
if (projectDependency != null)
{
if (projectDependency.Project.Files.SourceFiles.Any())
{
var projectOutputPath = CompilerUtil.GetCompilationOutput(projectDependency.Project, projectDependency.Framework, args.ConfigValue, outputPath);
references.Add(projectOutputPath);
}
}
else
{
references.AddRange(dependency.CompilationAssemblies.Select(r => r.ResolvedPath));
}
compilerArgs.AddRange(dependency.SourceReferences.Select(s => $"\"{s}\"")); compilerArgs.AddRange(dependency.SourceReferences.Select(s => $"\"{s}\""));
// Add analyzer references // Add analyzer references
@ -289,7 +274,7 @@ namespace Microsoft.DotNet.Tools.Compiler
var compilerName = CompilerUtil.ResolveCompilerName(context); var compilerName = CompilerUtil.ResolveCompilerName(context);
// Write RSP file // Write RSP file
var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.{context.ProjectFile.Name}.rsp"); var rsp = Path.Combine(intermediateOutputPath, $"dotnet-compile.rsp");
File.WriteAllLines(rsp, compilerArgs); File.WriteAllLines(rsp, compilerArgs);
// Run pre-compile event // Run pre-compile event

View file

@ -77,29 +77,31 @@ namespace Microsoft.DotNet.Tools.Publish
/// <param name="configuration">Debug or Release</param> /// <param name="configuration">Debug or Release</param>
/// <param name="nativeSubdirectories"></param> /// <param name="nativeSubdirectories"></param>
/// <returns>Return 0 if successful else return non-zero</returns> /// <returns>Return 0 if successful else return non-zero</returns>
private static bool PublishProjectContext(ProjectContext context, string baseOutputPath, string configuration, bool nativeSubdirectories) private static bool PublishProjectContext(ProjectContext context, string outputPath, string configuration, bool nativeSubdirectories)
{ {
Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}"); Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}");
var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration); var options = context.ProjectFile.GetCompilerOptions(context.TargetFramework, configuration);
var outputPathCalculator = context.GetOutputPathCalculator(baseOutputPath);
var outputPath = outputPathCalculator.GetCompilationOutputPath(configuration); if (string.IsNullOrEmpty(outputPath))
{
outputPath = context.GetOutputPathCalculator().GetOutputDirectoryPath(configuration);
}
var contextVariables = new Dictionary<string, string> var contextVariables = new Dictionary<string, string>
{ {
{ "publish:ProjectPath", context.ProjectDirectory }, { "publish:ProjectPath", context.ProjectDirectory },
{ "publish:Configuration", configuration }, { "publish:Configuration", configuration },
{ "publish:OutputPath", outputPath }, { "publish:OutputPath", outputPath },
{ "publish:PublishOutputPath", outputPathCalculator.BaseCompilationOutputPath },
{ "publish:Framework", context.TargetFramework.Framework }, { "publish:Framework", context.TargetFramework.Framework },
{ "publish:Runtime", context.RuntimeIdentifier }, { "publish:Runtime", context.RuntimeIdentifier },
}; };
RunScripts(context, ScriptNames.PrePublish, contextVariables); RunScripts(context, ScriptNames.PrePublish, contextVariables);
if (!Directory.Exists(outputPathCalculator.BaseCompilationOutputPath)) if (!Directory.Exists(outputPath))
{ {
Directory.CreateDirectory(outputPathCalculator.BaseCompilationOutputPath); Directory.CreateDirectory(outputPath);
} }
// Compile the project (and transitively, all it's dependencies) // Compile the project (and transitively, all it's dependencies)
@ -107,8 +109,6 @@ namespace Microsoft.DotNet.Tools.Publish
new string[] { new string[] {
"--framework", "--framework",
$"{context.TargetFramework.DotNetFrameworkName}", $"{context.TargetFramework.DotNetFrameworkName}",
"--output",
$"{outputPathCalculator.BaseCompilationOutputPath}",
"--configuration", "--configuration",
$"{configuration}", $"{configuration}",
"--no-host", "--no-host",
@ -128,15 +128,9 @@ namespace Microsoft.DotNet.Tools.Publish
foreach (var export in exporter.GetAllExports()) foreach (var export in exporter.GetAllExports())
{ {
// Skip copying project references
if (export.Library is ProjectDescription)
{
continue;
}
Reporter.Verbose.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ..."); Reporter.Verbose.WriteLine($"Publishing {export.Library.Identity.ToString().Green().Bold()} ...");
PublishFiles(export.RuntimeAssemblies, outputPath, false); PublishFiles(export.RuntimeAssemblies, outputPath, nativeSubdirectories: false);
PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories); PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories);
} }
@ -193,6 +187,14 @@ namespace Microsoft.DotNet.Tools.Publish
} }
File.Copy(file.ResolvedPath, Path.Combine(destinationDirectory, Path.GetFileName(file.ResolvedPath)), overwrite: true); File.Copy(file.ResolvedPath, Path.Combine(destinationDirectory, Path.GetFileName(file.ResolvedPath)), overwrite: true);
// Copy pdbs
var pdbPath = Path.ChangeExtension(file.ResolvedPath, FileNameSuffixes.DotNet.ProgramDatabase);
if (File.Exists(pdbPath))
{
File.Copy(pdbPath, Path.Combine(destinationDirectory, Path.GetFileName(pdbPath)), overwrite: true);
}
} }
} }

View file

@ -112,15 +112,14 @@ namespace Microsoft.DotNet.Tools.Run
} }
// Now launch the output and give it the results // Now launch the output and give it the results
var outputName = Path.Combine( var outputName = _context.GetOutputPathCalculator(tempDir).GetExecutablePath(Configuration);
_context.GetOutputPathCalculator(tempDir).GetCompilationOutputPath(Configuration),
_context.ProjectFile.Name + Constants.ExeSuffix);
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {
if (_context.TargetFramework.IsDesktop()) if (_context.TargetFramework.IsDesktop())
{ {
// Run mono if we're running a desktop target on non windows // Run mono if we're running a desktop target on non windows
_args.Insert(0, outputName + ".exe"); _args.Insert(0, outputName);
if (string.Equals(Configuration, "Debug", StringComparison.OrdinalIgnoreCase)) if (string.Equals(Configuration, "Debug", StringComparison.OrdinalIgnoreCase))
{ {

View file

@ -92,7 +92,7 @@ namespace Microsoft.DotNet.Tools.Test
private static int RunConsole(ProjectContext projectContext, CommandLineApplication app, string testRunner) private static int RunConsole(ProjectContext projectContext, CommandLineApplication app, string testRunner)
{ {
var commandArgs = new List<string> {projectContext.GetAssemblyPath(Constants.DefaultConfiguration)}; var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(Constants.DefaultConfiguration) };
commandArgs.AddRange(app.RemainingArguments); commandArgs.AddRange(app.RemainingArguments);
return Command.Create($"{GetCommandName(testRunner)}", commandArgs, projectContext.TargetFramework) return Command.Create($"{GetCommandName(testRunner)}", commandArgs, projectContext.TargetFramework)
@ -171,7 +171,7 @@ namespace Microsoft.DotNet.Tools.Test
{ {
TestHostTracing.Source.TraceInformation("Starting Discovery"); TestHostTracing.Source.TraceInformation("Starting Discovery");
var commandArgs = new List<string> { projectContext.GetAssemblyPath(Constants.DefaultConfiguration) }; var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(Constants.DefaultConfiguration) };
commandArgs.AddRange(new[] commandArgs.AddRange(new[]
{ {
@ -193,7 +193,7 @@ namespace Microsoft.DotNet.Tools.Test
{ {
TestHostTracing.Source.TraceInformation("Starting Execution"); TestHostTracing.Source.TraceInformation("Starting Execution");
var commandArgs = new List<string> { projectContext.GetAssemblyPath(Constants.DefaultConfiguration) }; var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(Constants.DefaultConfiguration) };
commandArgs.AddRange(new[] commandArgs.AddRange(new[]
{ {

View file

@ -166,7 +166,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
var publishCommand = new PublishCommand(TestProject, output: OutputDirectory); var publishCommand = new PublishCommand(TestProject, output: OutputDirectory);
publishCommand.Execute().Should().Pass(); publishCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, publishCommand.GetOutputExecutable(), s_expectedOutput); TestExecutable(OutputDirectory, publishCommand.GetOutputExecutable(), s_expectedOutput);
} }
private void TestSetup() private void TestSetup()

View file

@ -75,12 +75,12 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
protected static void AssertProjectSkipped(string skippedProject, CommandResult buildResult) protected static void AssertProjectSkipped(string skippedProject, CommandResult buildResult)
{ {
Assert.Contains($"Project {skippedProject} was previously compiled. Skipping compilation.", buildResult.StdOut, StringComparison.OrdinalIgnoreCase); Assert.Contains($"Project {skippedProject} (DNXCore,Version=v5.0) was previously compiled. Skipping compilation.", buildResult.StdOut, StringComparison.OrdinalIgnoreCase);
} }
protected static void AssertProjectCompiled(string rebuiltProject, CommandResult buildResult) protected static void AssertProjectCompiled(string rebuiltProject, CommandResult buildResult)
{ {
Assert.Contains($"Project {rebuiltProject} will be compiled", buildResult.StdOut, StringComparison.OrdinalIgnoreCase); Assert.Contains($"Project {rebuiltProject} (DNXCore,Version=v5.0) will be compiled", buildResult.StdOut, StringComparison.OrdinalIgnoreCase);
} }
protected string GetBinDirectory() protected string GetBinDirectory()

View file

@ -63,7 +63,7 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
Assert.False(File.Exists(lockFile)); Assert.False(File.Exists(lockFile));
buildResult = BuildProject(expectBuildFailure : true); buildResult = BuildProject(expectBuildFailure : true);
Assert.Contains("does not have a lock file", buildResult.StdErr); Assert.Contains("does not have a lock file", buildResult.StdOut);
} }
[Fact(Skip="https://github.com/dotnet/cli/issues/980")] [Fact(Skip="https://github.com/dotnet/cli/issues/980")]

View file

@ -61,8 +61,8 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
string framework = string.IsNullOrEmpty(_framework) ? string framework = string.IsNullOrEmpty(_framework) ?
_project.GetTargetFrameworks().First().FrameworkName.GetShortFolderName() : _framework; _project.GetTargetFrameworks().First().FrameworkName.GetShortFolderName() : _framework;
string runtime = string.IsNullOrEmpty(_runtime) ? PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier() : _runtime; string runtime = string.IsNullOrEmpty(_runtime) ? PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier() : _runtime;
//TODO: add runtime back as soon as it gets propagated through the various commands.
string output = Path.Combine(config, framework); string output = Path.Combine(config, framework, runtime);
return output; return output;
} }
@ -71,7 +71,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
{ {
if (!string.IsNullOrEmpty(_output)) if (!string.IsNullOrEmpty(_output))
{ {
return new DirectoryInfo(Path.Combine(_output, BuildRelativeOutputPath())); return new DirectoryInfo(_output);
} }
string output = Path.Combine(_project.ProjectDirectory, "bin", BuildRelativeOutputPath()); string output = Path.Combine(_project.ProjectDirectory, "bin", BuildRelativeOutputPath());

View file

@ -58,13 +58,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
string.Equals("on", val, StringComparison.OrdinalIgnoreCase)); string.Equals("on", val, StringComparison.OrdinalIgnoreCase));
} }
protected void TestOutputExecutable( protected void TestExecutable(string outputDir,
string outputDir,
string executableName, string executableName,
string expectedOutput, string expectedOutput)
bool native = false)
{ {
var executablePath = Path.Combine(GetCompilationOutputPath(outputDir, native), executableName); var executablePath = Path.Combine(outputDir, executableName);
var executableCommand = new TestCommand(executablePath); var executableCommand = new TestCommand(executablePath);
@ -75,6 +73,15 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
result.Should().Pass(); result.Should().Pass();
} }
protected void TestOutputExecutable(
string outputDir,
string executableName,
string expectedOutput,
bool native = false)
{
TestExecutable(GetCompilationOutputPath(outputDir, native), executableName, expectedOutput);
}
protected void TestNativeOutputExecutable(string outputDir, string executableName, string expectedOutput) protected void TestNativeOutputExecutable(string outputDir, string executableName, string expectedOutput)
{ {
TestOutputExecutable(outputDir, executableName, expectedOutput, true); TestOutputExecutable(outputDir, executableName, expectedOutput, true);