Refactor output directory code

This commit is contained in:
Pavel Krymets 2016-02-03 10:57:25 -08:00
parent 4908436958
commit 0f82ae37f3
49 changed files with 836 additions and 396 deletions

View file

@ -24,11 +24,11 @@ New-Item -ItemType Directory -Force -Path $IntermediatePackagesDir
foreach ($ProjectName in $ProjectsToPack) {
$ProjectFile = "$RepoRoot\src\$ProjectName\project.json"
& $toolsDir\dotnet pack "$ProjectFile" --basepath "$Stage2CompilationDir\forPackaging" --output "$IntermediatePackagesDir" --configuration "$Configuration" $versionArg $versionSuffix
& $toolsDir\dotnet pack "$ProjectFile" --build-base-path "$CompilationOutputDir\forPackaging" --output "$IntermediatePackagesDir" --configuration "$Configuration" $versionArg $versionSuffix
if (!$?) {
Write-Host "$toolsDir\dotnet pack failed for: $ProjectFile"
Exit 1
}
}
Get-ChildItem $IntermediatePackagesDir\$Configuration -Filter *.nupkg | ? {$_.Name -NotLike "*.symbols.nupkg"} | Copy-Item -Destination $PackagesDir
Get-ChildItem $IntermediatePackagesDir -Filter *.nupkg | ? {$_.Name -NotLike "*.symbols.nupkg"} | Copy-Item -Destination $PackagesDir

View file

@ -12,4 +12,16 @@ $env:PATH = "$Stage1Dir\bin;$env:PATH"
# Compile
_ "$RepoRoot\scripts\compile\compile-stage.ps1" @("$Tfm","$Rid","$Configuration","$Stage2Dir","$RepoRoot","$HostDir", "$Stage2CompilationDir")
# Build the projects that we are going to ship as nuget packages
. $REPOROOT\scripts\package\projectsToPack.ps1
$ProjectsToPack | ForEach-Object {
dotnet build --build-base-path "$Stage2Dir\forPackaging" --configuration "$Configuration" "$RepoRoot\src\$_"
if (!$?) {
Write-Host Command failed: dotnet build --native-subdirectory --build-base-path "$Stage2Dir\forPackaging" --configuration "$Configuration" "$RepoRoot\src\$_"
exit 1
}
}
$env:PATH=$StartPath

View file

@ -12,8 +12,6 @@ param(
[Parameter(Mandatory=$true)][string]$HostDir,
[Parameter(Mandatory=$true)][string]$CompilationOutputDir)
. $REPOROOT\scripts\package\projectsToPack.ps1
$Projects = loadBuildProjectList
$BinariesForCoreHost = @(
@ -48,15 +46,6 @@ if (!$?) {
Exit 1
}
# Build the projects that we are going to ship as nuget packages
$ProjectsToPack | ForEach-Object {
dotnet build --output "$CompilationOutputDir\forPackaging" --configuration "$Configuration" "$RepoRoot\src\$_"
if (!$?) {
Write-Host Command failed: dotnet build --native-subdirectory --output "$CompilationOutputDir\forPackaging" --configuration "$Configuration" "$RepoRoot\src\$_"
exit 1
}
}
# Clean up bogus additional files
$FilesToClean | ForEach-Object {
$path = Join-Path $RuntimeOutputDir $_

View file

@ -18,4 +18,4 @@ source "$DIR/../common/_common.sh"
header "Restoring Test Packages"
dotnet restore "$REPOROOT/test" --runtime $RID -f "$TEST_PACKAGE_DIR/Debug" $DISABLE_PARALLEL
dotnet restore "$REPOROOT/test" --runtime $RID -f "$TEST_PACKAGE_DIR" $DISABLE_PARALLEL

View file

@ -6,6 +6,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Graph;
using Microsoft.Extensions.PlatformAbstractions;
using NuGet.Packaging;
namespace Microsoft.DotNet.Cli.Utils
@ -69,7 +70,7 @@ namespace Microsoft.DotNet.Cli.Utils
if (commandPackage == null) return null;
var depsPath = projectContext.GetOutputPathCalculator().GetDepsPath(Constants.DefaultConfiguration);
var depsPath = projectContext.GetOutputPaths(Constants.DefaultConfiguration).RuntimeFiles.Deps;
return ConfigureCommandFromPackage(commandName, args, commandPackage, projectContext, depsPath, useComSpec);
}
@ -83,7 +84,7 @@ namespace Microsoft.DotNet.Cli.Utils
return null;
}
var projectContext = ProjectContext.Create(projectRootPath, framework);
var projectContext = ProjectContext.Create(projectRootPath, framework, PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers());
return projectContext;
}

View file

@ -19,51 +19,48 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
{
private readonly ProjectContext _context;
private readonly OutputPathCalculator _calculator;
private readonly OutputPaths _outputPaths;
public Executable(ProjectContext context, OutputPathCalculator calculator)
private readonly LibraryExporter _exporter;
public Executable(ProjectContext context, OutputPaths outputPaths, LibraryExporter exporter)
{
_context = context;
_calculator = calculator;
_outputPaths = outputPaths;
_exporter = exporter;
}
public void MakeCompilationOutputRunnable(string configuration)
public void MakeCompilationOutputRunnable()
{
var outputPath = _calculator.GetOutputDirectoryPath(configuration);
var outputPath = _outputPaths.RuntimeOutputPath;
CopyContentFiles(outputPath);
ExportRuntimeAssets(outputPath, configuration);
ExportRuntimeAssets(outputPath);
}
private void ExportRuntimeAssets(string outputPath, string configuration)
private void ExportRuntimeAssets(string outputPath)
{
var exporter = _context.CreateExporter(configuration);
if (_context.TargetFramework.IsDesktop())
{
MakeCompilationOutputRunnableForFullFramework(outputPath, configuration, exporter);
MakeCompilationOutputRunnableForFullFramework(outputPath);
}
else
{
MakeCompilationOutputRunnableForCoreCLR(outputPath, exporter);
MakeCompilationOutputRunnableForCoreCLR(outputPath);
}
}
}
private void MakeCompilationOutputRunnableForFullFramework(
string outputPath,
string configuration,
LibraryExporter exporter)
string outputPath)
{
CopyAllDependencies(outputPath, exporter);
CopyAllDependencies(outputPath, _exporter);
GenerateBindingRedirects(_exporter);
}
GenerateBindingRedirects(exporter, configuration);
}
private void MakeCompilationOutputRunnableForCoreCLR(string outputPath, LibraryExporter exporter)
private void MakeCompilationOutputRunnableForCoreCLR(string outputPath)
{
WriteDepsFileAndCopyProjectDependencies(exporter, _context.ProjectFile.Name, outputPath);
WriteDepsFileAndCopyProjectDependencies(_exporter, _context.ProjectFile.Name, outputPath);
// TODO: Pick a host based on the RID
CoreHost.CopyTo(outputPath, _context.ProjectFile.Name + Constants.ExeSuffix);
@ -78,7 +75,7 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
private static void CopyAllDependencies(string outputPath, LibraryExporter exporter)
{
exporter
.GetDependencies()
.GetAllExports()
.SelectMany(e => e.RuntimeAssets())
.CopyTo(outputPath);
}
@ -93,14 +90,15 @@ namespace Microsoft.Dotnet.Cli.Compiler.Common
.WriteDepsTo(Path.Combine(outputPath, projectFileName + FileNameSuffixes.Deps));
exporter
.GetDependencies(LibraryType.Project)
.GetAllExports()
.Where(e => e.Library.Identity.Type == LibraryType.Project)
.SelectMany(e => e.RuntimeAssets())
.CopyTo(outputPath);
}
}
public void GenerateBindingRedirects(LibraryExporter exporter, string configuration)
public void GenerateBindingRedirects(LibraryExporter exporter)
{
var outputName = _calculator.GetAssemblyPath(configuration);
var outputName = _outputPaths.RuntimeFiles.Assembly;
var existingConfig = new DirectoryInfo(_context.ProjectDirectory)
.EnumerateFiles()

View file

@ -40,20 +40,45 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
}));
}
internal static IEnumerable<string> RuntimeAssets(this LibraryExport export)
internal static IEnumerable<LibraryAsset> RuntimeAssets(this LibraryExport export)
{
return export.RuntimeAssemblies.Union(export.NativeLibraries)
.Select(e => e.ResolvedPath)
.Union(export.RuntimeAssets);
}
internal static void CopyTo(this IEnumerable<string> assets, string destinationPath)
public static void CopyTo(this IEnumerable<LibraryAsset> assets, string destinationPath)
{
if (!Directory.Exists(destinationPath))
{
Directory.CreateDirectory(destinationPath);
}
foreach (var asset in assets)
{
File.Copy(asset, Path.Combine(destinationPath, Path.GetFileName(asset)),
overwrite: true);
var targetName = ResolveTargetName(destinationPath, asset);
File.Copy(asset.ResolvedPath, targetName, overwrite: true);
}
}
private static string ResolveTargetName(string destinationPath, LibraryAsset asset)
{
string targetName;
if (!string.IsNullOrEmpty(asset.RelativePath))
{
targetName = Path.Combine(destinationPath, asset.RelativePath);
var destinationAssetPath = Path.GetDirectoryName(targetName);
if (!Directory.Exists(destinationAssetPath))
{
Directory.CreateDirectory(destinationAssetPath);
}
}
else
{
targetName = Path.Combine(destinationPath, Path.GetFileName(asset.ResolvedPath));
}
return targetName;
}
}
}

View file

@ -12,9 +12,8 @@ namespace Microsoft.DotNet.Cli.Compiler.Common
public static class ProjectContextExtensions
{
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 bool IsTestProject(this ProjectContext context) => !string.IsNullOrEmpty(context.ProjectFile.TestRunner);
public static string GetDisplayName(this ProjectContext context) => $"{context.RootProject.Identity.Name} ({context.TargetFramework})";
public static CommonCompilerOptions GetLanguageSpecificCompilerOptions(this ProjectContext context, NuGetFramework framework, string configurationName)
{

View file

@ -38,7 +38,7 @@ namespace Microsoft.DotNet.ProjectModel.Loader
dllImports,
// Add the project's output directory path to ensure project-to-project references get located
new[] { context.GetOutputPathCalculator().GetOutputDirectoryPath(configuration) });
new[] { context.GetOutputPaths(configuration).CompilationOutputPath });
}
private class AssemblyNameComparer : IEqualityComparer<AssemblyName>

View file

@ -22,7 +22,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
/// <summary>
/// Non assembly runtime assets.
/// </summary>
public IEnumerable<string> RuntimeAssets { get; }
public IEnumerable<LibraryAsset> RuntimeAssets { get; }
/// <summary>
/// Gets a list of fully-qualified paths to native binaries required to run
@ -48,7 +48,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
IEnumerable<LibraryAsset> compileAssemblies,
IEnumerable<string> sourceReferences,
IEnumerable<LibraryAsset> runtimeAssemblies,
IEnumerable<string> runtimeAssets,
IEnumerable<LibraryAsset> runtimeAssets,
IEnumerable<LibraryAsset> nativeLibraries,
IEnumerable<AnalyzerReference> analyzers)
{

View file

@ -16,9 +16,17 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
public class LibraryExporter
{
private readonly string _configuration;
private readonly string _runtime;
private readonly ProjectDescription _rootProject;
private readonly string _buildBasePath;
private readonly string _solutionRootPath;
public LibraryExporter(ProjectDescription rootProject, LibraryManager manager, string configuration)
public LibraryExporter(ProjectDescription rootProject,
LibraryManager manager,
string configuration,
string runtime,
string buildBasePath,
string solutionRootPath)
{
if (string.IsNullOrEmpty(configuration))
{
@ -27,6 +35,9 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
LibraryManager = manager;
_configuration = configuration;
_runtime = runtime;
_buildBasePath = buildBasePath;
_solutionRootPath = solutionRootPath;
_rootProject = rootProject;
}
@ -151,7 +162,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
var analyzers = GetAnalyzerReferences(package);
return new LibraryExport(package, compileAssemblies,
sourceReferences, runtimeAssemblies, Array.Empty<string>(), nativeLibraries, analyzers);
sourceReferences, runtimeAssemblies, Array.Empty<LibraryAsset>(), nativeLibraries, analyzers);
}
private LibraryExport ExportProject(ProjectDescription project)
@ -163,13 +174,13 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
compileAssemblies: Enumerable.Empty<LibraryAsset>(),
sourceReferences: Enumerable.Empty<string>(),
nativeLibraries: Enumerable.Empty<LibraryAsset>(),
runtimeAssets: Enumerable.Empty<string>(),
runtimeAssets: Enumerable.Empty<LibraryAsset>(),
runtimeAssemblies: Array.Empty<LibraryAsset>(),
analyzers: Array.Empty<AnalyzerReference>());
}
var compileAssemblies = new List<LibraryAsset>();
var runtimeAssets = new List<string>();
var runtimeAssets = new List<LibraryAsset>();
var sourceReferences = new List<string>();
if (!string.IsNullOrEmpty(project.TargetFrameworkInfo?.AssemblyPath))
@ -184,22 +195,24 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
Path.GetFullPath(Path.Combine(project.Project.ProjectDirectory, assemblyPath)));
compileAssemblies.Add(compileAsset);
runtimeAssets.Add(pdbPath);
runtimeAssets.Add(new LibraryAsset(Path.GetFileName(pdbPath), Path.GetFileName(pdbPath), pdbPath));
}
else if (project.Project.Files.SourceFiles.Any())
{
var outputCalculator = project.GetOutputPathCalculator();
var assemblyPath = outputCalculator.GetAssemblyPath(_configuration);
var outputPaths = project.GetOutputPaths(_buildBasePath, _solutionRootPath, _configuration, _runtime);
var files = outputPaths.CompilationFiles;
var assemblyPath = files.Assembly;
compileAssemblies.Add(new LibraryAsset(project.Identity.Name, null, assemblyPath));
foreach (var path in outputCalculator.GetBuildOutputs(_configuration))
foreach (var path in files.All())
{
if (string.Equals(assemblyPath, path))
{
continue;
}
runtimeAssets.Add(path);
runtimeAssets.Add(new LibraryAsset(Path.GetFileName(path), path.Replace(files.BasePath, string.Empty), path));
}
}
@ -241,7 +254,7 @@ namespace Microsoft.DotNet.ProjectModel.Compilation
new[] { new LibraryAsset(library.Identity.Name, library.Path, library.Path) },
Array.Empty<string>(),
Array.Empty<LibraryAsset>(),
Array.Empty<string>(),
Array.Empty<LibraryAsset>(),
Array.Empty<LibraryAsset>(),
Array.Empty<AnalyzerReference>());
}

View file

@ -0,0 +1,87 @@
// 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.ProjectModel.Resources;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel
{
public class CompilationOutputFiles
{
protected readonly Project Project;
protected readonly string Configuration;
protected readonly NuGetFramework Framework;
public CompilationOutputFiles(
string basePath,
Project project,
string configuration,
NuGetFramework framework)
{
BasePath = basePath;
Project = project;
Configuration = configuration;
Framework = framework;
OutputExtension = FileNameSuffixes.DotNet.DynamicLib;
var compilationOptions = Project.GetCompilerOptions(framework, configuration);
if (framework.IsDesktop() && compilationOptions.EmitEntryPoint.GetValueOrDefault())
{
OutputExtension = FileNameSuffixes.DotNet.Exe;
}
}
public string BasePath { get; }
public string Assembly
{
get
{
return Path.Combine(
BasePath,
Project.Name + OutputExtension);
}
}
public string PdbPath
{
get
{
return Path.ChangeExtension(Assembly, FileNameSuffixes.CurrentPlatform.ProgramDatabase);
}
}
public string OutputExtension { get; }
public virtual IEnumerable<string> Resources()
{
var resourceNames = Project.Files.ResourceFiles
.Select(f => ResourceUtility.GetResourceCultureName(f.Key))
.Where(f => !string.IsNullOrEmpty(f))
.Distinct();
foreach (var resourceName in resourceNames)
{
yield return Path.Combine(BasePath, resourceName, Project.Name + ".resources" + FileNameSuffixes.DotNet.DynamicLib);
}
}
public virtual IEnumerable<string> All()
{
yield return Assembly;
yield return PdbPath;
var compilationOptions = Project.GetCompilerOptions(Framework, Configuration);
if (compilationOptions.GenerateXmlDocumentation == true)
{
yield return Path.ChangeExtension(Assembly, "xml");
}
foreach (var resource in Resources())
{
yield return resource;
}
}
}
}

View file

@ -1,153 +0,0 @@
// 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.Runtime.InteropServices;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel
{
public class OutputPathCalculator
{
private const string ObjDirectoryName = "obj";
private readonly Project _project;
private readonly NuGetFramework _framework;
private readonly string _runtimeIdentifier;
/// <summary>
/// Unaltered output path. Either what is passed in in the constructor, or the project directory.
/// </summary>
private string BaseOutputPath { get; }
public string BaseCompilationOutputPath { get; }
public OutputPathCalculator(
Project project,
NuGetFramework framework,
string runtimeIdentifier,
string baseOutputPath)
{
_project = project;
_framework = framework;
_runtimeIdentifier = runtimeIdentifier;
BaseOutputPath = string.IsNullOrWhiteSpace(baseOutputPath) ? _project.ProjectDirectory : baseOutputPath;
BaseCompilationOutputPath = string.IsNullOrWhiteSpace(baseOutputPath)
? Path.Combine(_project.ProjectDirectory, DirectoryNames.Bin)
: baseOutputPath;
}
public string GetOutputDirectoryPath(string buildConfiguration)
{
var outDir = Path.Combine(BaseCompilationOutputPath,
buildConfiguration,
_framework.GetShortFolderName());
if (!string.IsNullOrEmpty(_runtimeIdentifier))
{
outDir = Path.Combine(outDir, _runtimeIdentifier);
}
return outDir;
}
public string GetIntermediateOutputDirectoryPath(string buildConfiguration, string intermediateOutputValue)
{
string intermediateOutputPath;
if (string.IsNullOrEmpty(intermediateOutputValue))
{
intermediateOutputPath = Path.Combine(
BaseOutputPath,
ObjDirectoryName,
buildConfiguration,
_framework.GetTwoDigitShortFolderName());
}
else
{
intermediateOutputPath = intermediateOutputValue;
}
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 IEnumerable<string> GetBuildOutputs(string buildConfiguration)
{
var assemblyPath = GetAssemblyPath(buildConfiguration);
yield return assemblyPath;
yield return Path.ChangeExtension(assemblyPath, "pdb");
var compilationOptions = _project.GetCompilerOptions(_framework, buildConfiguration);
if (compilationOptions.GenerateXmlDocumentation == true)
{
yield return Path.ChangeExtension(assemblyPath, "xml");
}
// This should only exist in desktop framework
var configFile = assemblyPath + ".config";
if (File.Exists(configFile))
{
yield return configFile;
}
// Deps file
var depsFile = GetDepsPath(buildConfiguration);
if (File.Exists(depsFile))
{
yield return depsFile;
}
}
public string GetDepsPath(string buildConfiguration)
{
return Path.Combine(GetOutputDirectoryPath(buildConfiguration), _project.Name + FileNameSuffixes.Deps);
}
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 (_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

@ -0,0 +1,58 @@
// 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;
namespace Microsoft.DotNet.ProjectModel
{
public class OutputPaths
{
private readonly string _runtimePath;
private readonly RuntimeOutputFiles _runtimeFiles;
public OutputPaths(string intermediateOutputDirectoryPath,
string compilationOutputPath,
string runtimePath,
CompilationOutputFiles compilationFiles,
RuntimeOutputFiles runtimeFiles)
{
_runtimePath = runtimePath;
_runtimeFiles = runtimeFiles;
CompilationOutputPath = compilationOutputPath;
IntermediateOutputDirectoryPath = intermediateOutputDirectoryPath;
CompilationFiles = compilationFiles;
}
public string CompilationOutputPath { get; }
public string IntermediateOutputDirectoryPath { get; }
public string RuntimeOutputPath
{
get
{
if (_runtimePath == null)
{
throw new InvalidOperationException(
$"Cannot get runtime output path for {nameof(OutputPaths)} with no runtime set");
}
return _runtimePath;
}
}
public CompilationOutputFiles CompilationFiles { get; }
public RuntimeOutputFiles RuntimeFiles
{
get
{
if (_runtimeFiles == null)
{
throw new InvalidOperationException(
$"Cannot get runtime output files for {nameof(OutputPaths)} with no runtime set");
}
return _runtimeFiles;
}
}
}
}

View file

@ -0,0 +1,75 @@
// 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.Utilities;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel
{
public class OutputPathsCalculator
{
private const string ObjDirectoryName = "obj";
private const string BinDirectoryName = "bin";
public static OutputPaths GetOutputPaths(
Project project,
NuGetFramework framework,
string runtimeIdentifier,
string configuration,
string solutionRootPath,
string buildBasePath,
string outputPath)
{
string resolvedBuildBasePath;
if (string.IsNullOrEmpty(buildBasePath))
{
resolvedBuildBasePath = project.ProjectDirectory;
}
else
{
if (string.IsNullOrEmpty(solutionRootPath))
{
resolvedBuildBasePath = Path.Combine(buildBasePath, project.Name);
}
else
{
resolvedBuildBasePath = project.ProjectDirectory.Replace(solutionRootPath, buildBasePath);
}
}
var compilationOutputPath = PathUtility.EnsureTrailingSlash(Path.Combine(resolvedBuildBasePath,
BinDirectoryName,
configuration,
framework.GetShortFolderName()));
string runtimeOutputPath = null;
if (string.IsNullOrEmpty(outputPath))
{
if (!string.IsNullOrEmpty(runtimeIdentifier))
{
runtimeOutputPath= PathUtility.EnsureTrailingSlash(Path.Combine(compilationOutputPath, runtimeIdentifier));
}
}
else
{
runtimeOutputPath= PathUtility.EnsureTrailingSlash(Path.GetFullPath(outputPath));
}
var intermediateOutputPath = PathUtility.EnsureTrailingSlash(Path.Combine(
resolvedBuildBasePath,
ObjDirectoryName,
configuration,
framework.GetTwoDigitShortFolderName()));
var compilationFiles = new CompilationOutputFiles(compilationOutputPath, project, configuration, framework);
RuntimeOutputFiles runtimeFiles = null;
if (runtimeOutputPath != null)
{
runtimeFiles = new RuntimeOutputFiles(runtimeOutputPath, project, configuration, framework);
}
return new OutputPaths(intermediateOutputPath, compilationOutputPath, runtimeOutputPath, compilationFiles, runtimeFiles);
}
}
}

View file

@ -88,6 +88,8 @@ namespace Microsoft.DotNet.ProjectModel
public IDictionary<string, IEnumerable<string>> Scripts { get; } = new Dictionary<string, IEnumerable<string>>(StringComparer.OrdinalIgnoreCase);
public bool IsTestProject => !string.IsNullOrEmpty(TestRunner);
public IEnumerable<TargetFrameworkInformation> GetTargetFrameworks()
{
return _targetFrameworks.Values;
@ -120,6 +122,14 @@ namespace Microsoft.DotNet.ProjectModel
return targetFrameworkInfo ?? _defaultTargetFrameworkConfiguration;
}
public bool HasRuntimeOutput(string configuration)
{
var compilationOptions = GetCompilerOptions(targetFramework: null, configurationName: configuration);
// TODO: Make this opt in via another mechanism
return compilationOptions.EmitEntryPoint.GetValueOrDefault() || IsTestProject;
}
private CommonCompilerOptions GetCompilerOptions()
{
return _defaultCompilerOptions;

View file

@ -1,6 +1,7 @@
// 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;
@ -25,7 +26,7 @@ namespace Microsoft.DotNet.ProjectModel
public LockFile LockFile { get; }
public string RootDirectory => GlobalSettings.DirectoryPath;
public string RootDirectory => GlobalSettings?.DirectoryPath;
public string ProjectDirectory => ProjectFile.ProjectDirectory;
@ -51,9 +52,9 @@ namespace Microsoft.DotNet.ProjectModel
LockFile = lockfile;
}
public LibraryExporter CreateExporter(string configuration)
public LibraryExporter CreateExporter(string configuration, string buildBasePath = null)
{
return new LibraryExporter(RootProject, LibraryManager, configuration);
return new LibraryExporter(RootProject, LibraryManager, configuration, RuntimeIdentifier, buildBasePath, RootDirectory);
}
/// <summary>
@ -86,7 +87,7 @@ namespace Microsoft.DotNet.ProjectModel
/// <summary>
/// Creates a project context for each framework located in the project at <paramref name="projectPath"/>
/// </summary>
public static IEnumerable<ProjectContext> CreateContextForEachFramework(string projectPath, ProjectReaderSettings settings = null)
public static IEnumerable<ProjectContext> CreateContextForEachFramework(string projectPath, ProjectReaderSettings settings = null, IEnumerable<string> runtimeIdentifiers = null)
{
if (!projectPath.EndsWith(Project.FileName))
{
@ -100,6 +101,7 @@ namespace Microsoft.DotNet.ProjectModel
.WithProject(project)
.WithTargetFramework(framework.FrameworkName)
.WithReaderSettings(settings)
.WithRuntimeIdentifiers(runtimeIdentifiers ?? Enumerable.Empty<string>())
.Build();
}
}
@ -120,9 +122,15 @@ namespace Microsoft.DotNet.ProjectModel
.BuildAllTargets();
}
public OutputPathCalculator GetOutputPathCalculator(string baseOutputPath = null)
public OutputPaths GetOutputPaths(string configuration, string buidBasePath = null, string outputPath = null)
{
return new OutputPathCalculator(ProjectFile, TargetFramework, RuntimeIdentifier, baseOutputPath);
return OutputPathsCalculator.GetOutputPaths(ProjectFile,
TargetFramework,
RuntimeIdentifier,
configuration,
RootDirectory,
buidBasePath,
outputPath);
}
}
}

View file

@ -44,9 +44,15 @@ namespace Microsoft.DotNet.ProjectModel
public TargetFrameworkInformation TargetFrameworkInfo { get; }
public OutputPathCalculator GetOutputPathCalculator()
public OutputPaths GetOutputPaths(string buildBasePath, string solutionRootPath, string configuration, string runtime)
{
return new OutputPathCalculator(Project, Framework, runtimeIdentifier: null, baseOutputPath: null);
return OutputPathsCalculator.GetOutputPaths(Project,
Framework,
runtimeIdentifier: runtime,
configuration: configuration,
solutionRootPath: solutionRootPath,
buildBasePath: buildBasePath,
outputPath: null);
}
}
}

View file

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
namespace Microsoft.DotNet.Cli.Compiler.Common
namespace Microsoft.DotNet.ProjectModel.Resources
{
/// <summary>
/// Contains a list of known culture names that can be used to create a <see cref="System.Globalization.CultureInfo"/>.

View file

@ -2,12 +2,12 @@
// 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 System.Collections.Generic;
using Microsoft.DotNet.Tools.Common;
using Microsoft.DotNet.ProjectModel.Utilities;
namespace Microsoft.DotNet.Cli.Compiler.Common
namespace Microsoft.DotNet.ProjectModel.Resources
{
public static class ResourceUtility
{

View file

@ -0,0 +1,66 @@
// 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 NuGet.Frameworks;
namespace Microsoft.DotNet.ProjectModel
{
public class RuntimeOutputFiles : CompilationOutputFiles
{
public RuntimeOutputFiles(string basePath,
Project project,
string configuration,
NuGetFramework framework) : base(basePath, project, configuration, framework)
{
}
public string Executable
{
get
{
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 (Framework.IsDesktop())
{
extension = FileNameSuffixes.DotNet.Exe;
}
return Path.Combine(BasePath, Project.Name + extension);
}
}
public string Deps
{
get
{
return Path.ChangeExtension(Assembly, FileNameSuffixes.Deps);
}
}
public string Config
{
get { return Assembly + ".config"; }
}
public override IEnumerable<string> All()
{
foreach (var file in base.All())
{
yield return file;
}
if (File.Exists(Config))
{
yield return Config;
}
if (File.Exists(Deps))
{
yield return Deps;
}
}
}
}

View file

@ -36,12 +36,9 @@ namespace Microsoft.DotNet.Tools.Build
// Cleaner to clone the args and mutate the clone than have separate CompileContext fields for mutated args
// and then reasoning which ones to get from args and which ones from fields.
_args = (BuilderCommandApp)args.ShallowCopy();
// Set up Output Paths. They are unique per each CompileContext
var outputPathCalculator = _rootProject.GetOutputPathCalculator(_args.OutputValue);
_args.OutputValue = outputPathCalculator.BaseCompilationOutputPath;
_args.IntermediateValue =
outputPathCalculator.GetIntermediateOutputDirectoryPath(_args.ConfigValue, _args.IntermediateValue);
_args.OutputValue = _args.OutputValue;
_args.BuildBasePathValue = _args.BuildBasePathValue;
// Set up dependencies
_dependencies = new ProjectDependenciesFacade(_rootProject, _args.ConfigValue);
@ -59,9 +56,9 @@ namespace Microsoft.DotNet.Tools.Build
{
if (incremental)
{
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework);
var dependencyProjectContext = ProjectContext.Create(dependency.Path, dependency.Framework, new[] { _rootProject.RuntimeIdentifier });
if (!DependencyNeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue)))
if (!NeedsRebuilding(dependencyProjectContext, new ProjectDependenciesFacade(dependencyProjectContext, _args.ConfigValue)))
{
continue;
}
@ -87,19 +84,14 @@ namespace Microsoft.DotNet.Tools.Build
return success;
}
private bool DependencyNeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies)
{
return NeedsRebuilding(project, dependencies, buildOutputPath: null, intermediateOutputPath: null);
}
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies)
{
return NeedsRebuilding(project, dependencies, _args.OutputValue, _args.IntermediateValue);
return NeedsRebuilding(project, dependencies, _args.BuildBasePathValue);
}
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies, string buildOutputPath, string intermediateOutputPath)
private bool NeedsRebuilding(ProjectContext project, ProjectDependenciesFacade dependencies, string baseBuildPath)
{
var compilerIO = GetCompileIO(project, _args.ConfigValue, buildOutputPath, intermediateOutputPath, dependencies);
var compilerIO = GetCompileIO(project, _args.ConfigValue, baseBuildPath, _args.OutputValue, dependencies);
// rebuild if empty inputs / outputs
if (!(compilerIO.Outputs.Any() && compilerIO.Inputs.Any()))
@ -191,8 +183,14 @@ namespace Microsoft.DotNet.Tools.Build
private void CreateOutputDirectories()
{
Directory.CreateDirectory(_args.OutputValue);
Directory.CreateDirectory(_args.IntermediateValue);
if (!string.IsNullOrEmpty(_args.OutputValue))
{
Directory.CreateDirectory(_args.OutputValue);
}
if (!string.IsNullOrEmpty(_args.BuildBasePathValue))
{
Directory.CreateDirectory(_args.BuildBasePathValue);
}
}
private IncrementalPreconditions GatherIncrementalPreconditions()
@ -281,6 +279,12 @@ namespace Microsoft.DotNet.Tools.Build
args.Add(_args.ConfigValue);
args.Add(projectDependency.Project.ProjectDirectory);
if (!string.IsNullOrWhiteSpace(_args.BuildBasePathValue))
{
args.Add("--build-base-path");
args.Add(_args.BuildBasePathValue);
}
var compileResult = CommpileCommand.Run(args.ToArray());
return compileResult == 0;
@ -294,10 +298,18 @@ namespace Microsoft.DotNet.Tools.Build
args.Add(_rootProject.TargetFramework.ToString());
args.Add("--configuration");
args.Add(_args.ConfigValue);
args.Add("--output");
args.Add(_args.OutputValue);
args.Add("--temp-output");
args.Add(_args.IntermediateValue);
if (!string.IsNullOrEmpty(_args.OutputValue))
{
args.Add("--output");
args.Add(_args.OutputValue);
}
if (!string.IsNullOrEmpty(_args.BuildBasePathValue))
{
args.Add("--build-base-path");
args.Add(_args.BuildBasePathValue);
}
//native args
if (_args.IsNativeValue)
@ -342,37 +354,45 @@ namespace Microsoft.DotNet.Tools.Build
if (succeeded)
{
MakeRunnableIfNecessary();
}
return succeeded;
}
private void MakeRunnableIfNecessary()
{
var compilationOptions = CompilerUtil.ResolveCompilationOptions(_rootProject, _args.ConfigValue);
// TODO: Make this opt in via another mechanism
var makeRunnable = compilationOptions.EmitEntryPoint.GetValueOrDefault() ||
_rootProject.IsTestProject();
if (makeRunnable)
{
var outputPathCalculator = _rootProject.GetOutputPathCalculator(_args.OutputValue);
var rids = new List<string>();
if (string.IsNullOrEmpty(_args.RuntimeValue))
if (_rootProject.ProjectFile.HasRuntimeOutput(_args.ConfigValue))
{
rids.AddRange(PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers());
MakeRunnable();
}
else
{
rids.Add(_args.RuntimeValue);
CopyCompilationOutput();
}
var runtimeContext = ProjectContext.Create(_rootProject.ProjectDirectory, _rootProject.TargetFramework, rids);
var executable = new Executable(runtimeContext, outputPathCalculator);
executable.MakeCompilationOutputRunnable(_args.ConfigValue);
}
return succeeded;
}
private void CopyCompilationOutput()
{
if (!string.IsNullOrEmpty(_args.OutputValue))
{
var calculator = _rootProject.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);
var dest = calculator.RuntimeOutputPath;
var source = calculator.CompilationOutputPath;
foreach (var file in calculator.CompilationFiles.All())
{
var destFileName = file.Replace(source, dest);
var directoryName = Path.GetDirectoryName(destFileName);
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
File.Copy(file, destFileName, true);
}
}
}
private void MakeRunnable()
{
var outputPaths = _rootProject.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue);
var libraryExporter = _rootProject.CreateExporter(_args.ConfigValue, _args.BuildBasePathValue);
var executable = new Executable(_rootProject, outputPaths, libraryExporter);
executable.MakeCompilationOutputRunnable();
}
private static ISet<ProjectDescription> Sort(Dictionary<string, ProjectDescription> projects)
@ -420,15 +440,13 @@ namespace Microsoft.DotNet.Tools.Build
public static CompilerIO GetCompileIO(
ProjectContext project,
string buildConfiguration,
string buildBasePath,
string outputPath,
string intermediaryOutputPath,
ProjectDependenciesFacade dependencies)
{
var compilerIO = new CompilerIO(new List<string>(), new List<string>());
var calculator = project.GetOutputPathCalculator(outputPath);
var binariesOutputPath = calculator.GetOutputDirectoryPath(buildConfiguration);
intermediaryOutputPath = calculator.GetIntermediateOutputDirectoryPath(buildConfiguration, intermediaryOutputPath);
var calculator = project.GetOutputPaths(buildConfiguration, buildBasePath, outputPath);
var binariesOutputPath = calculator.CompilationOutputPath;
// input: project.json
compilerIO.Inputs.Add(project.ProjectFile.ProjectFilePath);
@ -443,17 +461,22 @@ namespace Microsoft.DotNet.Tools.Build
// input: dependencies
AddDependencies(dependencies, compilerIO);
var allOutputPath = new List<string>(calculator.CompilationFiles.All());
if (!string.IsNullOrEmpty(project.RuntimeIdentifier))
{
allOutputPath.AddRange(calculator.RuntimeFiles.All());
}
// output: compiler outputs
foreach (var path in calculator.GetBuildOutputs(buildConfiguration))
foreach (var path in allOutputPath)
{
compilerIO.Outputs.Add(path);
}
// input compilation options files
AddCompilationOptions(project, buildConfiguration, compilerIO);
// input / output: resources without culture
AddCultureResources(project, intermediaryOutputPath, compilerIO);
AddCultureResources(project, binariesOutputPath, compilerIO);
// input / output: resources with culture
AddNonCultureResources(project, binariesOutputPath, compilerIO);

View file

@ -5,7 +5,7 @@ dotnet-compile
dotnet-compile -- Compiles source files for a single project to a binary format and saves to a target file.
# SYNOPSIS
dotnet compile [--output] [--temp-output] [--framework] [--configuration] [--output] [--arch] [--verbose]
dotnet compile [--output] [--build-base-path] [--framework] [--configuration] [--output] [--arch] [--verbose]
# DESCRIPTION
The compile command compiles source files from a single project to a binary file, either intermmediate language (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 dotnet-build(1) command.
@ -31,8 +31,8 @@ This command relies on the following artifacts: source files, project.json proje
`-n, --native`
Compiles source to native machine code, for the local machine. The default is a native executable. The default executable extension is no extension and ".exe" on Windows.
`-t, --temp-output <PATH>`
Path where to drop the temporary binaries that are produced during compile. By default, the temporary binaries are dropped in the `obj` directory in the directory where `project.json` files lives, that is, where the application lives.
`-b, --build-base-path <PATH>`
Path where to drop the output produced during compile. By default, the binaries are dropped in the `bin` and `obj` directory in the directory where `project.json` files lives, that is, where the application lives.
`-f, --framework <FID>`
Compile the application for the specified framework. If the framework is not specified, one specified in `project.json` will be used.

View file

@ -1,13 +1,15 @@
// 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.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.Extensions.PlatformAbstractions;
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
@ -21,7 +23,7 @@ namespace Microsoft.DotNet.Tools.Compiler
// options and arguments for compilation
private CommandOption _outputOption;
private CommandOption _intermediateOutputOption;
private CommandOption _buildBasePath;
private CommandOption _frameworkOption;
private CommandOption _runtimeOption;
private CommandOption _configurationOption;
@ -37,8 +39,8 @@ namespace Microsoft.DotNet.Tools.Compiler
// resolved values for the options and arguments
public string ProjectPathValue { get; set; }
public string BuildBasePathValue { get; set; }
public string OutputValue { get; set; }
public string IntermediateValue { get; set; }
public string RuntimeValue{ get; set; }
public string ConfigValue { get; set; }
public bool IsNativeValue { get; set; }
@ -72,7 +74,7 @@ namespace Microsoft.DotNet.Tools.Compiler
_app.HelpOption("-h|--help");
_outputOption = _app.Option("-o|--output <OUTPUT_DIR>", "Directory in which to place outputs", CommandOptionType.SingleValue);
_intermediateOutputOption = _app.Option("-t|--temp-output <OUTPUT_DIR>", "Directory in which to place temporary outputs", CommandOptionType.SingleValue);
_buildBasePath = _app.Option("-b|--build-base-path <OUTPUT_DIR>", "Directory in which to place temporary outputs", CommandOptionType.SingleValue);
_frameworkOption = _app.Option("-f|--framework <FRAMEWORK>", "Compile a specific framework", CommandOptionType.MultipleValue);
_configurationOption = _app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
_runtimeOption = _app.Option("-r|--runtime <RUNTIME_IDENTIFIER>", "Target runtime to publish for", CommandOptionType.SingleValue);
@ -101,7 +103,7 @@ namespace Microsoft.DotNet.Tools.Compiler
}
OutputValue = _outputOption.Value();
IntermediateValue = _intermediateOutputOption.Value();
BuildBasePathValue = _buildBasePath.Value();
ConfigValue = _configurationOption.Value() ?? Constants.DefaultConfiguration;
RuntimeValue = _runtimeOption.Value();
@ -114,10 +116,34 @@ namespace Microsoft.DotNet.Tools.Compiler
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 rids = new List<string>();
if (string.IsNullOrEmpty(RuntimeValue))
{
rids.AddRange(PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers());
}
else
{
rids.Add(RuntimeValue);
}
IEnumerable<ProjectContext> contexts;
if (_frameworkOption.HasValue())
{
contexts = _frameworkOption.Values
.Select(f => ProjectContext.Create(ProjectPathValue, NuGetFramework.Parse(f), rids));
}
else
{
if (!string.IsNullOrEmpty(OutputValue))
{
throw new InvalidOperationException($"'{_frameworkOption.LongName}' is required when '{_outputOption.LongName}' is specified");
}
else
{
contexts = ProjectContext.CreateContextForEachFramework(ProjectPathValue, settings: null, runtimeIdentifiers: rids);
}
}
var success = execute(contexts.ToList(), this);

View file

@ -10,6 +10,7 @@ using System.Linq;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Resources;
using Microsoft.DotNet.Tools.Common;
// This class is responsible with defining the arguments for the Compile verb.

View file

@ -11,6 +11,7 @@ using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Resources;
using Microsoft.DotNet.ProjectModel.Utilities;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.PlatformAbstractions;
@ -59,17 +60,16 @@ namespace Microsoft.DotNet.Tools.Compiler
ProjectContext context,
CompilerCommandApp args)
{
var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue);
var outputPath = outputPathCalculator.GetOutputDirectoryPath(args.ConfigValue);
var outputPaths = context.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue, args.OutputValue);
var outputPath = outputPaths.RuntimeOutputPath;
var nativeOutputPath = Path.Combine(outputPath, "native");
var intermediateOutputPath =
outputPathCalculator.GetIntermediateOutputDirectoryPath(args.ConfigValue, args.IntermediateValue);
var nativeIntermediateOutputPath = Path.Combine(intermediateOutputPath, "native");
outputPaths.IntermediateOutputDirectoryPath;
var nativeTempOutput = Path.Combine(intermediateOutputPath, "native");
Directory.CreateDirectory(nativeOutputPath);
Directory.CreateDirectory(nativeIntermediateOutputPath);
Directory.CreateDirectory(nativeTempOutput);
var compilationOptions = context.ProjectFile.GetCompilerOptions(context.TargetFramework, args.ConfigValue);
var managedOutput = outputPathCalculator.GetAssemblyPath(args.ConfigValue);
var managedOutput = outputPaths.CompilationFiles.Assembly;
var nativeArgs = new List<string>();
@ -133,14 +133,14 @@ namespace Microsoft.DotNet.Tools.Compiler
// Intermediate Path
nativeArgs.Add("--temp-output");
nativeArgs.Add($"{nativeIntermediateOutputPath}");
nativeArgs.Add($"{nativeTempOutput}");
// Output Path
nativeArgs.Add("--output");
nativeArgs.Add($"{nativeOutputPath}");
// Write Response File
var rsp = Path.Combine(nativeIntermediateOutputPath, $"dotnet-compile-native.{context.ProjectFile.Name}.rsp");
var rsp = Path.Combine(nativeTempOutput, $"dotnet-compile-native.{context.ProjectFile.Name}.rsp");
File.WriteAllLines(rsp, nativeArgs);
// TODO Add -r assembly.dll for all Nuget References
@ -155,16 +155,16 @@ namespace Microsoft.DotNet.Tools.Compiler
private static bool CompileProject(ProjectContext context, CompilerCommandApp args)
{
// Set up Output Paths
var outputPathCalculator = context.GetOutputPathCalculator(args.OutputValue);
var outputPath = outputPathCalculator.GetOutputDirectoryPath(args.ConfigValue);
var outputPaths = context.GetOutputPaths(args.ConfigValue, args.BuildBasePathValue);
var outputPath = outputPaths.CompilationOutputPath;
var intermediateOutputPath =
outputPathCalculator.GetIntermediateOutputDirectoryPath(args.ConfigValue, args.IntermediateValue);
outputPaths.IntermediateOutputDirectoryPath;
Directory.CreateDirectory(outputPath);
Directory.CreateDirectory(intermediateOutputPath);
// Create the library exporter
var exporter = context.CreateExporter(args.ConfigValue);
var exporter = context.CreateExporter(args.ConfigValue, args.BuildBasePathValue);
// Gather exports for the project
var dependencies = exporter.GetDependencies().ToList();
@ -196,7 +196,7 @@ namespace Microsoft.DotNet.Tools.Compiler
}
// Get compilation options
var outputName = outputPathCalculator.GetAssemblyPath(args.ConfigValue);
var outputName = outputPaths.CompilationFiles.Assembly;
// Assemble args
var compilerArgs = new List<string>()
@ -313,7 +313,7 @@ namespace Microsoft.DotNet.Tools.Compiler
{
success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, intermediateOutputPath, outputPath);
}
return PrintSummary(diagnostics, sw, success);
}

View file

@ -7,7 +7,7 @@ dotnet-compile -- Compiles source files for a single project to a binary format
# SYNOPSIS
dotnet compile [--native] [--output]
[--temp-output] [--framework] [--configuration]
[--build-base-path] [--framework] [--configuration]
[--output] [--arch] [--cpp] [-ilc-args] [--verbose]
# DESCRIPTION
@ -35,9 +35,9 @@ This command relies on the following artifacts: source files, project.json proje
Compiles source to native machine code, for the local machine. The default is a native executable. The default executable extension is no extension and ".exe" on Windows.
`-t, --temp-output <PATH>`
`-b, --build-base-path <PATH>`
Path where to drop the temporary binaries that are produced during compile. By default, the temporary binaries are dropped in the `obj` directory in the directory where `project.json` files lives, that is, where the application lives.
Path where to drop the output produced during compile. By default, the binaries are dropped in the `bin` and `obj` directory in the directory where `project.json` files lives, that is, where the application lives.
`-f, --framework <FID>`

View file

@ -6,6 +6,7 @@ using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.ProjectModel.Resources;
namespace Microsoft.DotNet.Tools.Compiler
{

View file

@ -56,10 +56,13 @@ namespace Microsoft.DotNet.Tools.Pack
public string InputPathForContext(ProjectContext context)
{
return Path.Combine(
CompiledArtifactsPath,
return OutputPathsCalculator.GetOutputPaths(context.ProjectFile,
context.TargetFramework,
context.RuntimeIdentifier,
_configuration,
context.TargetFramework.GetTwoDigitShortFolderName());
}
context.RootDirectory,
CompiledArtifactsPathParameter,
null).CompilationOutputPath;
}
}
}

View file

@ -14,7 +14,7 @@ namespace Microsoft.DotNet.Tools.Pack
private readonly Project _project;
private readonly ArtifactPathsCalculator _artifactPathsCalculator;
private readonly string _intermediateOutputPath;
private readonly string _buildBasePath;
private readonly string _configuration;
private bool SkipBuild => _artifactPathsCalculator.CompiledArtifactsPathSet;
@ -22,12 +22,12 @@ namespace Microsoft.DotNet.Tools.Pack
public BuildProjectCommand(
Project project,
ArtifactPathsCalculator artifactPathsCalculator,
string intermediateOutputPath,
string buildBasePath,
string configuration)
{
_project = project;
_artifactPathsCalculator = artifactPathsCalculator;
_intermediateOutputPath = intermediateOutputPath;
_buildBasePath = buildBasePath;
_configuration = configuration;
}
@ -44,16 +44,10 @@ namespace Microsoft.DotNet.Tools.Pack
argsBuilder.Add("--configuration");
argsBuilder.Add($"{_configuration}");
if (_artifactPathsCalculator.PackageOutputPathSet)
if (!string.IsNullOrEmpty(_buildBasePath))
{
argsBuilder.Add("--output");
argsBuilder.Add($"{_artifactPathsCalculator.PackageOutputPathParameter}");
}
if (!string.IsNullOrEmpty(_intermediateOutputPath))
{
argsBuilder.Add("--temp-output");
argsBuilder.Add($"{_intermediateOutputPath}");
argsBuilder.Add("--build-base-path");
argsBuilder.Add($"{_buildBasePath}");
}
argsBuilder.Add($"{_project.ProjectFilePath}");

View file

@ -17,6 +17,7 @@ using NuGet.Frameworks;
using NuGet.Packaging.Core;
using NuGet.Versioning;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.ProjectModel.Resources;
using Microsoft.DotNet.Tools.Pack;
using PackageBuilder = NuGet.PackageBuilder;
@ -59,7 +60,6 @@ namespace Microsoft.DotNet.Tools.Compiler
var packageOutputPath = Path.Combine(
ArtifactPathsCalculator.PackageOutputPath,
Configuration,
GetPackageName() + NuGet.Constants.PackageExtension);
if (GeneratePackage(packageOutputPath, packDiagnostics))

View file

@ -23,9 +23,8 @@ namespace Microsoft.DotNet.Tools.Compiler
app.Description = "Packager for the .NET Platform";
app.HelpOption("-h|--help");
var basePath = app.Option("-b|--basepath <BASE_PATH>", "Directory from where the assets to be packaged are going to be picked up", CommandOptionType.SingleValue);
var output = app.Option("-o|--output <OUTPUT_DIR>", "Directory in which to place outputs", CommandOptionType.SingleValue);
var intermediateOutput = app.Option("-t|--temp-output <OUTPUT_DIR>", "Directory in which to place temporary outputs", CommandOptionType.SingleValue);
var buildBasePath = app.Option("-b|--build-base-path <OUTPUT_DIR>", "Directory in which to place temporary build outputs", CommandOptionType.SingleValue);
var configuration = app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
var versionSuffix = app.Option("--version-suffix <VERSION_SUFFIX>", "Defines what `*` should be replaced with in version field in project.json", CommandOptionType.SingleValue);
var path = app.Argument("<PROJECT>", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory");
@ -63,14 +62,13 @@ namespace Microsoft.DotNet.Tools.Compiler
var contexts = ProjectContext.CreateContextForEachFramework(pathValue, settings);
var configValue = configuration.Value() ?? Cli.Utils.Constants.DefaultConfiguration;
var basePathValue = basePath.Value();
var outputValue = output.Value();
var intermediateOutputValue = intermediateOutput.Value();
var buildBasePathValue = buildBasePath.Value();
var project = contexts.First().ProjectFile;
var artifactPathsCalculator = new ArtifactPathsCalculator(project, basePathValue, outputValue, configValue);
var buildProjectCommand = new BuildProjectCommand(project, artifactPathsCalculator, intermediateOutputValue, configValue);
var artifactPathsCalculator = new ArtifactPathsCalculator(project, buildBasePathValue, outputValue, configValue);
var buildProjectCommand = new BuildProjectCommand(project, artifactPathsCalculator, buildBasePathValue, configValue);
var packageBuilder = new PackagesGenerator(contexts, artifactPathsCalculator, configValue);
var buildResult = buildProjectCommand.Execute();

View file

@ -22,6 +22,7 @@ namespace Microsoft.DotNet.Tools.Publish
var framework = app.Option("-f|--framework <FRAMEWORK>", "Target framework to compile for", CommandOptionType.SingleValue);
var runtime = app.Option("-r|--runtime <RUNTIME_IDENTIFIER>", "Target runtime to publish for", CommandOptionType.SingleValue);
var buildBasePath = app.Option("-b|--build-base-path <OUTPUT_DIR>", "Directory in which to place temporary outputs", CommandOptionType.SingleValue);
var output = app.Option("-o|--output <OUTPUT_PATH>", "Path in which to publish the app", CommandOptionType.SingleValue);
var configuration = app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
var projectPath = app.Argument("<PROJECT>", "The project to publish, defaults to the current directory. Can be a path to a project.json or a project directory");
@ -33,11 +34,12 @@ namespace Microsoft.DotNet.Tools.Publish
publish.Framework = framework.Value();
publish.Runtime = runtime.Value();
publish.BuildBasePath = buildBasePath.Value();
publish.OutputPath = output.Value();
publish.Configuration = configuration.Value() ?? Constants.DefaultConfiguration;
publish.NativeSubdirectories = nativeSubdirectories.HasValue();
publish.ProjectPath = projectPath.Value;
if (string.IsNullOrEmpty(publish.ProjectPath))
{
publish.ProjectPath = Directory.GetCurrentDirectory();

View file

@ -9,6 +9,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.DotNet.Files;
using Microsoft.DotNet.Tools.Common;
@ -20,6 +21,7 @@ namespace Microsoft.DotNet.Tools.Publish
{
public string ProjectPath { get; set; }
public string Configuration { get; set; }
public string BuildBasePath { get; set; }
public string OutputPath { get; set; }
public string Framework { get; set; }
public string Runtime { get; set; }
@ -61,7 +63,7 @@ namespace Microsoft.DotNet.Tools.Publish
foreach (var project in ProjectContexts)
{
if (PublishProjectContext(project, OutputPath, Configuration, NativeSubdirectories))
if (PublishProjectContext(project, BuildBasePath, OutputPath, Configuration, NativeSubdirectories))
{
NumberOfPublishedProjects++;
}
@ -78,7 +80,7 @@ namespace Microsoft.DotNet.Tools.Publish
/// <param name="configuration">Debug or Release</param>
/// <param name="nativeSubdirectories"></param>
/// <returns>Return 0 if successful else return non-zero</returns>
private static bool PublishProjectContext(ProjectContext context, string outputPath, string configuration, bool nativeSubdirectories)
private static bool PublishProjectContext(ProjectContext context, string buildBasePath, string outputPath, string configuration, bool nativeSubdirectories)
{
Reporter.Output.WriteLine($"Publishing {context.RootProject.Identity.Name.Yellow()} for {context.TargetFramework.DotNetFrameworkName.Yellow()}/{context.RuntimeIdentifier.Yellow()}");
@ -86,7 +88,7 @@ namespace Microsoft.DotNet.Tools.Publish
if (string.IsNullOrEmpty(outputPath))
{
outputPath = context.GetOutputPathCalculator().GetOutputDirectoryPath(configuration);
outputPath = context.GetOutputPaths(configuration, buildBasePath, outputPath).RuntimeOutputPath;
}
var contextVariables = new Dictionary<string, string>
@ -106,17 +108,22 @@ namespace Microsoft.DotNet.Tools.Publish
}
// Compile the project (and transitively, all it's dependencies)
var result = Build.BuildCommand.Run(
new string[] {
"--framework",
$"{context.TargetFramework.DotNetFrameworkName}",
"--runtime",
context.RuntimeIdentifier,
"--configuration",
configuration,
context.ProjectFile.ProjectDirectory
});
var args = new List<string>() {
"--framework",
$"{context.TargetFramework.DotNetFrameworkName}",
"--runtime",
context.RuntimeIdentifier,
"--configuration",
configuration,
context.ProjectFile.ProjectDirectory
};
if (!string.IsNullOrEmpty(buildBasePath))
{
args.Add("--build-base-path");
args.Add(buildBasePath);
}
var result = Build.BuildCommand.Run(args.ToArray());
if (result != 0)
{
return false;
@ -131,7 +138,7 @@ namespace Microsoft.DotNet.Tools.Publish
PublishFiles(export.RuntimeAssemblies, outputPath, nativeSubdirectories: false);
PublishFiles(export.NativeLibraries, outputPath, nativeSubdirectories);
PublishFiles(export.RuntimeAssets, outputPath);
export.RuntimeAssets.CopyTo(outputPath);
if (options.PreserveCompilationContext.GetValueOrDefault())
{
@ -200,6 +207,7 @@ namespace Microsoft.DotNet.Tools.Publish
return 0;
}
private static void PublishFiles(IEnumerable<string> files, string outputPath)
{
foreach (var file in files)

View file

@ -58,13 +58,10 @@ namespace Microsoft.DotNet.Tools.Repl.Csi
Reporter.Output.WriteLine($"Compiling {projectContext.RootProject.Identity.Name.Yellow()} for {projectContext.TargetFramework.DotNetFrameworkName.Yellow()} to use with the {"C# REPL".Yellow()} environment.");
// --temp-output is actually the intermediate output folder and can be the same as --output for our temporary compilation (`dotnet run` can be seen doing the same)
return Build.BuildCommand.Run(new[]
{
$"--output",
$"{tempOutputDir}",
$"--temp-output",
$"{tempOutputDir}",
$"--framework",
$"{projectContext.TargetFramework}",
$"--configuration",

View file

@ -173,14 +173,14 @@ namespace Microsoft.DotNet.Tools.Restore
Path.GetDirectoryName(toolDescription.Target.RuntimeAssemblies.First().Path),
toolDescription.Identity.Name + FileNameSuffixes.Deps);
var calculator = context.GetOutputPathCalculator(context.ProjectDirectory);
var executable = new Executable(context, calculator);
var calculator = context.GetOutputPaths(Constants.DefaultConfiguration, buidBasePath: null, outputPath: context.ProjectDirectory);
var executable = new Executable(context, calculator, context.CreateExporter(Constants.DefaultConfiguration));
executable.MakeCompilationOutputRunnable(Constants.DefaultConfiguration);
executable.MakeCompilationOutputRunnable();
if (File.Exists(depsPath)) File.Delete(depsPath);
File.Move(Path.Combine(calculator.GetOutputDirectoryPath(Constants.DefaultConfiguration), "bin" + FileNameSuffixes.Deps), depsPath);
File.Move(Path.Combine(calculator.RuntimeOutputPath, "bin" + FileNameSuffixes.Deps), depsPath);
}
private static bool RestoreToolToPath(LibraryRange tooldep, IEnumerable<string> args, string tempPath, bool quiet)

View file

@ -8,6 +8,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using Microsoft.Extensions.PlatformAbstractions;
using NuGet.Frameworks;
namespace Microsoft.DotNet.Tools.Run
@ -59,15 +60,27 @@ namespace Microsoft.DotNet.Tools.Run
Configuration = Constants.DefaultConfiguration;
}
var contexts = ProjectContext.CreateContextForEachFramework(Project);
var rids = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers();
if (Framework == null)
{
_context = contexts.First();
var defaultFrameworks = new[]
{
FrameworkConstants.FrameworkIdentifiers.DnxCore,
FrameworkConstants.FrameworkIdentifiers.NetStandardApp,
};
var contexts = ProjectContext.CreateContextForEachFramework(Project, null, rids);
_context = contexts.FirstOrDefault(c =>
defaultFrameworks.Contains(c.TargetFramework.Framework) && !string.IsNullOrEmpty(c.RuntimeIdentifier));
if (_context == null)
{
throw new InvalidOperationException($"Couldn't find default target with framework: {string.Join(",", defaultFrameworks)}");
}
}
else
{
var fx = NuGetFramework.Parse(Framework);
_context = contexts.FirstOrDefault(c => c.TargetFramework.Equals(fx));
_context = ProjectContext.Create(Project, NuGetFramework.Parse(Framework), rids);
}
if (Args == null)
@ -90,7 +103,7 @@ namespace Microsoft.DotNet.Tools.Run
$"--framework",
$"{_context.TargetFramework}",
$"--configuration",
$"{Configuration}",
Configuration,
$"{_context.ProjectFile.ProjectDirectory}"
});
@ -100,7 +113,7 @@ namespace Microsoft.DotNet.Tools.Run
}
// Now launch the output and give it the results
var outputName = _context.GetOutputPathCalculator().GetExecutablePath(Configuration);
var outputName = _context.GetOutputPaths(Configuration).RuntimeFiles.Executable;
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{

View file

@ -95,7 +95,7 @@ namespace Microsoft.DotNet.Tools.Test
private static int RunConsole(ProjectContext projectContext, CommandLineApplication app, string testRunner, string configuration)
{
var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(configuration) };
var commandArgs = new List<string> { projectContext.GetOutputPaths(configuration).CompilationFiles.Assembly };
commandArgs.AddRange(app.RemainingArguments);
return Command.CreateDotNet($"{GetCommandName(testRunner)}", commandArgs, projectContext.TargetFramework)
@ -174,7 +174,7 @@ namespace Microsoft.DotNet.Tools.Test
{
TestHostTracing.Source.TraceInformation("Starting Discovery");
var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(configuration) };
var commandArgs = new List<string> { projectContext.GetOutputPaths(configuration).CompilationFiles.Assembly };
commandArgs.AddRange(new[]
{
@ -196,7 +196,7 @@ namespace Microsoft.DotNet.Tools.Test
{
TestHostTracing.Source.TraceInformation("Starting Execution");
var commandArgs = new List<string> { projectContext.GetOutputPathCalculator().GetAssemblyPath(configuration) };
var commandArgs = new List<string> { projectContext.GetOutputPaths(configuration).CompilationFiles.Assembly };
commandArgs.AddRange(new[]
{

View file

@ -42,7 +42,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
[Fact]
public void TestDotnetBuild()
{
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory);
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: DefaultFramework);
buildCommand.Execute().Should().Pass();
@ -53,7 +53,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
public void TestDotnetIncrementalBuild()
{
// first build
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory);
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: DefaultFramework);
buildCommand.Execute().Should().Pass();
TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput);
@ -90,7 +90,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
return;
}
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true);
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, framework: DefaultFramework);
buildCommand.Execute().Should().Pass();
@ -106,7 +106,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
return;
}
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true);
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: DefaultFramework);
buildCommand.Execute().Should().Pass();
@ -123,7 +123,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd
}
// first build
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true);
var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: DefaultFramework);
var binariesOutputDirectory = GetCompilationOutputPath(OutputDirectory, false);
buildCommand.Execute().Should().Pass();

View file

@ -21,9 +21,10 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
_dirInfo = dir;
}
public DirectoryInfo DirectoryInfo => _dirInfo;
public AndConstraint<DirectoryInfoAssertions> Exist()
{
_dirInfo.Exists.Should().BeTrue();
Execute.Assertion.ForCondition(_dirInfo.Exists)
.FailWith("Expected directory {0} does not exist.", _dirInfo.FullName);
return new AndConstraint<DirectoryInfoAssertions>(this);

View file

@ -12,8 +12,13 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
public static class DirectoryInfoExtensions
{
public static DirectoryInfoAssertions Should(this DirectoryInfo dir)
{
{
return new DirectoryInfoAssertions(dir);
}
public static DirectoryInfo Sub(this DirectoryInfo dir, string name)
{
return new DirectoryInfo(Path.Combine(dir.FullName, name));
}
}
}

View file

@ -13,8 +13,9 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private Project _project;
private string _projectPath;
private string _outputDirectory;
private string _tempOutputDirectory;
private string _buidBasePathDirectory;
private string _configuration;
private string _framework;
private bool _noHost;
private bool _native;
private string _architecture;
@ -36,13 +37,13 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
}
}
private string TempOutputOption
private string BuildBasePathOption
{
get
{
return _tempOutputDirectory == string.Empty ?
return _buidBasePathDirectory == string.Empty ?
"" :
$"-t {_tempOutputDirectory}";
$"-b {_buidBasePathDirectory}";
}
}
@ -55,6 +56,15 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
$"-c {_configuration}";
}
}
private string FrameworkOption
{
get
{
return _framework == string.Empty ?
"" :
$"--framework {_framework}";
}
}
private string NoHostOption
{
@ -159,8 +169,9 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
public BuildCommand(
string projectPath,
string output="",
string tempOutput="",
string buidBasePath="",
string configuration="",
string framework="",
bool noHost=false,
bool native=false,
string architecture="",
@ -179,8 +190,9 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
_project = ProjectReader.GetProject(projectPath);
_outputDirectory = output;
_tempOutputDirectory = tempOutput;
_buidBasePathDirectory = buidBasePath;
_configuration = configuration;
_framework = framework;
_noHost = noHost;
_native = native;
_architecture = architecture;
@ -214,7 +226,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
private string BuildArgs()
{
return $"{BuildProfile} {NoIncremental} \"{_projectPath}\" {OutputOption} {TempOutputOption} {ConfigurationOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}";
return $"{BuildProfile} {NoIncremental} \"{_projectPath}\" {OutputOption} {BuildBasePathOption} {ConfigurationOption} {FrameworkOption} {NoHostOption} {NativeOption} {ArchitectureOption} {IlcArgsOption} {IlcPathOption} {AppDepSDKPathOption} {NativeCppModeOption} {CppCompilerFlagsOption}";
}
}
}

View file

@ -48,6 +48,8 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
get { return _path; }
}
public DirectoryInfo DirectoryInfo => new DirectoryInfo(Path);
/// <summary>
/// Creates a file in this directory.
/// </summary>
@ -78,7 +80,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
/// <returns></returns>
public TempDirectory CopyDirectory(string sourceDirectory)
{
Debug.Assert(Directory.Exists(sourceDirectory));
Debug.Assert(Directory.Exists(sourceDirectory), $"{sourceDirectory} does not exists");
var tempCopy = CreateDirectory(new DirectoryInfo(sourceDirectory).Name);

View file

@ -16,6 +16,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
/// </summary>
public abstract class TestBase : IDisposable
{
protected const string DefaultFramework = "dnxcore50";
private TempRoot _temp;
protected TestBase()
@ -89,10 +90,10 @@ namespace Microsoft.DotNet.Tools.Test.Utilities
protected string GetCompilationOutputPath(string outputDir, bool native)
{
var executablePath = Path.Combine(outputDir, "Debug", "dnxcore50");
var executablePath = outputDir;
if (native)
{
executablePath = Path.Combine(outputDir, "Debug", "dnxcore50", "native");
executablePath = Path.Combine(executablePath, "native");
}
return executablePath;

View file

@ -0,0 +1,160 @@
// 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.IO;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Common;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.Extensions.PlatformAbstractions;
using NuGet.Frameworks;
using Xunit;
namespace Microsoft.DotNet.Tools.Builder.Tests
{
public class BuildOutputTests : TestBase
{
private readonly string _testProjectsRoot;
private readonly string[] _runtimeFiles =
{
"TestApp" + FileNameSuffixes.DotNet.DynamicLib,
"TestApp" + FileNameSuffixes.DotNet.ProgramDatabase,
"TestApp" + FileNameSuffixes.CurrentPlatform.Exe,
"TestApp" + FileNameSuffixes.Deps,
"TestLibrary" + FileNameSuffixes.DotNet.DynamicLib,
"TestLibrary" + FileNameSuffixes.DotNet.ProgramDatabase
};
private readonly string[] _appCompileFiles =
{
"TestApp" + FileNameSuffixes.DotNet.DynamicLib,
"TestApp" + FileNameSuffixes.DotNet.ProgramDatabase
};
private readonly string[] _libCompileFiles =
{
"TestLibrary" + FileNameSuffixes.DotNet.DynamicLib,
"TestLibrary" + FileNameSuffixes.DotNet.ProgramDatabase,
};
public BuildOutputTests()
{
_testProjectsRoot = Path.Combine(AppContext.BaseDirectory, "TestAssets", "TestProjects");
}
private void PrepareProject(out TempDirectory root, out TempDirectory testAppDir, out TempDirectory testLibDir, out string runtime)
{
root = Temp.CreateDirectory();
var src = root.CreateDirectory("src");
testAppDir = src.CreateDirectory("TestApp");
testLibDir = src.CreateDirectory("TestLibrary");
// copy projects to the temp dir
CopyProjectToTempDir(Path.Combine(_testProjectsRoot, "TestApp"), testAppDir);
CopyProjectToTempDir(Path.Combine(_testProjectsRoot, "TestLibrary"), testLibDir);
var contexts = ProjectContext.CreateContextForEachFramework(
testLibDir.Path,
null,
PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers());
runtime = contexts.FirstOrDefault(c => !string.IsNullOrEmpty(c.RuntimeIdentifier))?.RuntimeIdentifier;
}
private string FormatPath(string input, string framework, string runtime)
{
return input.Replace("{fw}", framework).Replace("{rid}", runtime);
}
[Theory]
// global.json exists
[InlineData(true, null, null, "src/TestLibrary/bin/debug/{fw}", "src/TestApp/bin/debug/{fw}", "src/TestApp/bin/debug/{fw}/{rid}")]
[InlineData(true, "out", null, "src/TestLibrary/bin/debug/{fw}", "src/TestApp/bin/debug/{fw}", "out")]
[InlineData(true, null, "build", "build/src/TestLibrary/bin/debug/{fw}", "build/src/TestApp/bin/debug/{fw}", "build/src/TestApp/bin/debug/{fw}/{rid}")]
[InlineData(true, "out", "build", "build/src/TestLibrary/bin/debug/{fw}", "build/src/TestApp/bin/debug/{fw}", "out")]
//no global.json
//[InlineData(false, null, null, "src/TestLibrary/bin/debug/{fw}", "src/TestApp/bin/debug/{fw}", "src/TestApp/bin/debug/{fw}/{rid}")]
//[InlineData(false, "out", null, "src/TestLibrary/bin/debug/{fw}", "src/TestApp/bin/debug/{fw}", "out")]
//[InlineData(false, null, "build", "build/TestLibrary/bin/debug/{fw}", "build/TestApp/bin/debug/{fw}", "build/TestApp/bin/debug/{fw}/{rid}")]
//[InlineData(false, "out", "build", "build/TestLibrary/bin/debug/{fw}", "build/TestApp/bin/debug/{fw}", "out")]
public void DefaultPaths(bool global, string outputValue, string baseValue, string expectedLibCompile, string expectedAppCompile, string expectedAppRuntime)
{
TempDirectory root;
TempDirectory testAppDir;
TempDirectory testLibDir;
string runtime;
PrepareProject(out root, out testAppDir, out testLibDir, out runtime);
if (global)
{
root.CopyFile(Path.Combine(_testProjectsRoot, "global.json"));
}
new BuildCommand(GetProjectPath(testAppDir),
output: outputValue != null ? Path.Combine(root.Path, outputValue) : string.Empty,
buidBasePath: baseValue != null ? Path.Combine(root.Path, baseValue) : string.Empty,
framework: DefaultFramework)
.ExecuteWithCapturedOutput().Should().Pass();
var libdebug = root.DirectoryInfo.Sub(FormatPath(expectedLibCompile, DefaultFramework, runtime));
var appdebug = root.DirectoryInfo.Sub(FormatPath(expectedAppCompile, DefaultFramework, runtime));
var appruntime = root.DirectoryInfo.Sub(FormatPath(expectedAppRuntime, DefaultFramework, runtime));
libdebug.Should().Exist().And.HaveFiles(_libCompileFiles);
appdebug.Should().Exist().And.HaveFiles(_appCompileFiles);
appruntime.Should().Exist().And.HaveFiles(_runtimeFiles);
}
[Fact]
public void ResourceTest()
{
TempDirectory root;
TempDirectory testAppDir;
TempDirectory testLibDir;
string runtime;
PrepareProject(out root, out testAppDir, out testLibDir, out runtime);
var names = new[]
{
"uk-UA",
"en",
"en-US"
};
foreach (var folder in new [] { testAppDir, testLibDir })
{
foreach (var name in names)
{
folder.CreateFile($"Resource.{name}.resx").WriteAllText("<root></root>");
}
}
new BuildCommand(GetProjectPath(testAppDir), framework: DefaultFramework)
.ExecuteWithCapturedOutput().Should().Pass();
var libdebug = testLibDir.DirectoryInfo.Sub("bin/Debug").Sub(DefaultFramework);
var appdebug = testAppDir.DirectoryInfo.Sub("bin/Debug").Sub(DefaultFramework);
var appruntime = appdebug.Sub(runtime);
foreach (var name in names)
{
libdebug.Sub(name).Should().Exist().And.HaveFile("TestLibrary.resources.dll");
appdebug.Sub(name).Should().Exist().And.HaveFile("TestApp.resources.dll");
appruntime.Sub(name).Should().Exist().And.HaveFiles(new [] { "TestLibrary.resources.dll", "TestApp.resources.dll" });
}
}
private void CopyProjectToTempDir(string projectDir, TempDirectory tempDir)
{
// copy all the files to temp dir
foreach (var file in Directory.EnumerateFiles(projectDir))
{
tempDir.CopyFile(file);
}
}
private string GetProjectPath(TempDirectory projectDir)
{
return Path.Combine(projectDir.Path, "project.json");
}
}
}

View file

@ -7,7 +7,6 @@ using System.IO;
using System.Linq;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Tools.Test.Utilities;
using Xunit;
namespace Microsoft.DotNet.Tools.Builder.Tests
{
@ -48,17 +47,15 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
protected CommandResult BuildProject(bool noIncremental = false, bool expectBuildFailure = false)
{
var outputDir = GetBinRoot();
var intermediateOutputDir = Path.Combine(Directory.GetParent(outputDir).FullName, "obj", MainProject);
var mainProjectFile = GetProjectFile(MainProject);
var buildCommand = new BuildCommand(mainProjectFile, output: outputDir, tempOutput: intermediateOutputDir ,noIncremental : noIncremental);
var buildCommand = new BuildCommand(mainProjectFile, output: GetBinRoot(), framework: "dnxcore50", noIncremental : noIncremental);
var result = buildCommand.ExecuteWithCapturedOutput();
if (!expectBuildFailure)
{
result.Should().Pass();
TestOutputExecutable(outputDir, buildCommand.GetOutputExecutableName(), ExpectedOutput);
TestOutputExecutable(GetBinRoot(), buildCommand.GetOutputExecutableName(), ExpectedOutput);
}
else
{

View file

@ -126,14 +126,14 @@ namespace Microsoft.DotNet.Tools.Builder.Tests
var buildResult = BuildProject();
buildResult.Should().HaveCompiledProject(MainProject);
Reporter.Verbose.WriteLine($"Files in {GetCompilationOutputPath()}");
foreach (var file in Directory.EnumerateFiles(GetCompilationOutputPath()))
Reporter.Verbose.WriteLine($"Files in {GetBinRoot()}");
foreach (var file in Directory.EnumerateFiles(GetBinRoot()))
{
Reporter.Verbose.Write($"\t {file}");
}
// delete output files with extensions
foreach (var outputFile in Directory.EnumerateFiles(GetCompilationOutputPath()).Where(f =>
foreach (var outputFile in Directory.EnumerateFiles(GetBinRoot()).Where(f =>
{
var fileName = Path.GetFileName(f);
return fileName.StartsWith(MainProject, StringComparison.OrdinalIgnoreCase) &&

View file

@ -21,6 +21,8 @@
},
"content": [
"../../TestAssets/TestProjects/TestApp/**/*",
"../../TestAssets/TestProjects/TestLibrary/**/*",
"../../TestAssets/TestProjects/TestSimpleIncrementalApp/*",
"../../TestAssets/TestProjects/TestProjectToProjectDependencies/**/*",
"../../TestAssets/TestProjects/global.json"

View file

@ -32,17 +32,17 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
// run compile
var outputDir = Path.Combine(testLibDir.Path, "bin");
var testProject = GetProjectPath(testLibDir);
var buildCommand = new BuildCommand(testProject, output: outputDir);
var buildCommand = new BuildCommand(testProject, output: outputDir, framework: DefaultFramework);
var result = buildCommand.ExecuteWithCapturedOutput();
result.Should().Pass();
// verify the output xml file
var outputXml = Path.Combine(outputDir, "Debug", "dnxcore50", "TestLibrary.xml");
var outputXml = Path.Combine(outputDir, "Debug", DefaultFramework, "TestLibrary.xml");
Console.WriteLine("OUTPUT XML PATH: " + outputXml);
Assert.True(File.Exists(outputXml));
Assert.Contains("Gets the message from the helper", File.ReadAllText(outputXml));
}
[Fact]
public void LibraryWithAnalyzer()
{
@ -55,7 +55,7 @@ namespace Microsoft.DotNet.Tools.Compiler.Tests
// run compile
var outputDir = Path.Combine(testLibDir.Path, "bin");
var testProject = GetProjectPath(testLibDir);
var buildCmd = new BuildCommand(testProject, output: outputDir);
var buildCmd = new BuildCommand(testProject, output: outputDir, framework: DefaultFramework);
var result = buildCmd.ExecuteWithCapturedOutput();
result.Should().Pass();
Assert.Contains("CA1018", result.StdOut);