dotnet-installer/src/Microsoft.DotNet.Compiler.Common/Executable.cs

241 lines
8.7 KiB
C#
Raw Normal View History

// 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;
2016-02-09 12:01:52 -08:00
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.DotNet.Cli.Compiler.Common;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Files;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Graph;
2016-03-08 16:46:50 -08:00
using Microsoft.Extensions.DependencyModel;
using NuGet.Frameworks;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
namespace Microsoft.Dotnet.Cli.Compiler.Common
{
public class Executable
{
// GROOOOOSS
private static readonly string RedistPackageName = "Microsoft.NETCore.App";
private readonly ProjectContext _context;
2016-02-17 10:08:27 -08:00
private readonly LibraryExporter _exporter;
2016-02-03 10:57:25 -08:00
private readonly OutputPaths _outputPaths;
2016-02-17 10:08:27 -08:00
private readonly string _runtimeOutputPath;
private readonly string _intermediateOutputPath;
2016-02-03 10:57:25 -08:00
private readonly CommonCompilerOptions _compilerOptions;
2016-03-08 16:46:50 -08:00
public Executable(ProjectContext context, OutputPaths outputPaths, LibraryExporter exporter, string configuration)
{
_context = context;
2016-02-03 10:57:25 -08:00
_outputPaths = outputPaths;
2016-02-17 10:08:27 -08:00
_runtimeOutputPath = outputPaths.RuntimeOutputPath;
_intermediateOutputPath = outputPaths.IntermediateOutputDirectoryPath;
2016-02-03 10:57:25 -08:00
_exporter = exporter;
_compilerOptions = _context.ProjectFile.GetCompilerOptions(_context.TargetFramework, configuration);
}
2016-02-03 10:57:25 -08:00
public void MakeCompilationOutputRunnable()
{
2016-02-17 10:08:27 -08:00
CopyContentFiles();
ExportRuntimeAssets();
}
2016-02-17 10:08:27 -08:00
private void ExportRuntimeAssets()
{
if (_context.TargetFramework.IsDesktop())
{
2016-02-17 10:08:27 -08:00
MakeCompilationOutputRunnableForFullFramework();
}
else
{
2016-02-17 10:08:27 -08:00
MakeCompilationOutputRunnableForCoreCLR();
}
2016-02-03 10:57:25 -08:00
}
2016-02-17 10:08:27 -08:00
private void MakeCompilationOutputRunnableForFullFramework()
{
2016-02-17 10:08:27 -08:00
var dependencies = _exporter.GetDependencies();
CopyAssemblies(dependencies);
CopyAssets(dependencies);
2016-02-03 10:57:25 -08:00
GenerateBindingRedirects(_exporter);
}
2016-02-17 10:08:27 -08:00
private void MakeCompilationOutputRunnableForCoreCLR()
{
2016-02-17 10:08:27 -08:00
WriteDepsFileAndCopyProjectDependencies(_exporter);
var emitEntryPoint = _compilerOptions.EmitEntryPoint ?? false;
if (emitEntryPoint && !string.IsNullOrEmpty(_context.RuntimeIdentifier))
{
// TODO: Pick a host based on the RID
CoreHost.CopyTo(_runtimeOutputPath, GetOutputName() + Constants.ExeSuffix);
}
}
2016-02-17 10:08:27 -08:00
private void CopyContentFiles()
{
var contentFiles = new ContentFiles(_context);
2016-02-17 10:08:27 -08:00
contentFiles.StructuredCopyTo(_runtimeOutputPath);
}
private void CopyAssemblies(IEnumerable<LibraryExport> libraryExports)
{
foreach (var libraryExport in libraryExports)
{
libraryExport.RuntimeAssemblies.CopyTo(_runtimeOutputPath);
libraryExport.NativeLibraries.CopyTo(_runtimeOutputPath);
}
}
2016-02-17 10:08:27 -08:00
private void CopyAssets(IEnumerable<LibraryExport> libraryExports)
{
2016-02-10 10:07:22 -08:00
foreach (var libraryExport in libraryExports)
{
2016-02-17 10:08:27 -08:00
libraryExport.RuntimeAssets.StructuredCopyTo(
_runtimeOutputPath,
_intermediateOutputPath);
2016-02-10 10:07:22 -08:00
}
}
2016-02-17 10:08:27 -08:00
private void WriteDepsFileAndCopyProjectDependencies(LibraryExporter exporter)
{
2016-03-08 16:46:50 -08:00
WriteDeps(exporter);
WriteRuntimeConfig(exporter);
2016-02-16 15:30:39 -08:00
var projectExports = exporter.GetDependencies(LibraryType.Project);
2016-02-17 10:08:27 -08:00
CopyAssemblies(projectExports);
CopyAssets(projectExports);
2016-02-09 12:01:52 -08:00
2016-02-17 10:08:27 -08:00
var packageExports = exporter.GetDependencies(LibraryType.Package);
CopyAssets(packageExports);
2016-02-03 10:57:25 -08:00
}
private void WriteRuntimeConfig(LibraryExporter exporter)
{
if (!_context.TargetFramework.IsDesktop())
{
// TODO: Suppress this file if there's nothing to write? RuntimeOutputFiles would have to be updated
// in order to prevent breaking incremental compilation...
var json = new JObject();
var runtimeOptions = new JObject();
json.Add("runtimeOptions", runtimeOptions);
var redistExport = exporter
.GetAllExports()
.FirstOrDefault(l => l.Library.Identity.Name.Equals(RedistPackageName, StringComparison.OrdinalIgnoreCase));
if (redistExport != null)
{
var framework = new JObject(
new JProperty("name", redistExport.Library.Identity.Name),
new JProperty("version", redistExport.Library.Identity.Version.ToNormalizedString()));
runtimeOptions.Add("framework", framework);
}
var runtimeConfigJsonFile =
Path.Combine(_runtimeOutputPath, GetOutputName() + FileNameSuffixes.RuntimeConfigJson);
using (var writer = new JsonTextWriter(new StreamWriter(File.Create(runtimeConfigJsonFile))))
{
writer.Formatting = Formatting.Indented;
json.WriteTo(writer);
}
}
}
2016-03-08 16:46:50 -08:00
public void WriteDeps(LibraryExporter exporter)
{
Directory.CreateDirectory(_runtimeOutputPath);
var depsFilePath = Path.Combine(_runtimeOutputPath, GetOutputName() + FileNameSuffixes.Deps);
File.WriteAllLines(depsFilePath, exporter
2016-03-08 16:46:50 -08:00
.GetDependencies(LibraryType.Package)
.SelectMany(GenerateLines));
var includeCompile = _compilerOptions.PreserveCompilationContext == true;
2016-03-08 16:46:50 -08:00
var exports = exporter.GetAllExports().ToArray();
var dependencyContext = new DependencyContextBuilder().Build(
compilerOptions: includeCompile ? _compilerOptions : null,
2016-03-08 16:46:50 -08:00
compilationExports: includeCompile ? exports : null,
runtimeExports: exports,
portable: string.IsNullOrEmpty(_context.RuntimeIdentifier),
target: _context.TargetFramework,
runtime: _context.RuntimeIdentifier ?? string.Empty);
var writer = new DependencyContextWriter();
var depsJsonFilePath = Path.Combine(_runtimeOutputPath, GetOutputName() + FileNameSuffixes.DepsJson);
using (var fileStream = File.Create(depsJsonFilePath))
2016-03-08 16:46:50 -08:00
{
writer.Write(dependencyContext, fileStream);
}
}
2016-02-03 10:57:25 -08:00
public void GenerateBindingRedirects(LibraryExporter exporter)
{
2016-02-03 10:57:25 -08:00
var outputName = _outputPaths.RuntimeFiles.Assembly;
var existingConfig = new DirectoryInfo(_context.ProjectDirectory)
.EnumerateFiles()
.FirstOrDefault(f => f.Name.Equals("app.config", StringComparison.OrdinalIgnoreCase));
XDocument baseAppConfig = null;
if (existingConfig != null)
{
using (var fileStream = File.OpenRead(existingConfig.FullName))
{
baseAppConfig = XDocument.Load(fileStream);
}
}
var appConfig = exporter.GetAllExports().GenerateBindingRedirects(baseAppConfig);
if (appConfig == null) { return; }
var path = outputName + ".config";
using (var stream = File.Create(path))
{
appConfig.Save(stream);
}
}
2016-03-08 16:46:50 -08:00
private string GetOutputName()
2016-03-08 16:46:50 -08:00
{
return _compilerOptions.OutputName ?? _context.ProjectFile.Name;
2016-03-08 16:46:50 -08:00
}
private static IEnumerable<string> GenerateLines(LibraryExport export)
{
return GenerateLines(export, export.RuntimeAssemblies, "runtime")
.Union(GenerateLines(export, export.NativeLibraries, "native"));
}
private static IEnumerable<string> GenerateLines(LibraryExport export, IEnumerable<LibraryAsset> items, string type)
{
return items.Select(i => DepsFormatter.EscapeRow(new[]
{
export.Library.Identity.Type.Value,
export.Library.Identity.Name,
export.Library.Identity.Version.ToNormalizedString(),
export.Library.Hash,
type,
i.Name,
i.RelativePath
}));
}
}
}