Add compilation options to dependency context

This commit is contained in:
Pavel Krymets 2015-12-21 10:36:20 -08:00
parent 697e99ea6e
commit e39d30ba9c
8 changed files with 223 additions and 30 deletions

View file

@ -5,49 +5,99 @@ using System.Threading.Tasks;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Compilation;
using Microsoft.DotNet.ProjectModel.Graph;
using NuGet.Frameworks;
namespace Microsoft.Extensions.DependencyModel
{
public static class DependencyContextBuilder
{
public static DependencyContext FromLibraryExporter(LibraryExporter libraryExporter, string target, string runtime)
public static DependencyContext Build(CommonCompilerOptions compilerOptions, LibraryExporter libraryExporter, string configuration, NuGetFramework target, string runtime)
{
var dependencies = libraryExporter.GetAllExports();
var dependencies = libraryExporter.GetAllExports().Where(export => export.Library.Framework.Equals(target)).ToList();
return new DependencyContext(target, runtime,
GetLibraries(dependencies, export => export.CompilationAssemblies),
GetLibraries(dependencies, export => export.RuntimeAssemblies));
// Sometimes we have package and reference assembly with the same name (System.Runtime for example) thats why we
// deduplicating them prefering reference assembly
var dependencyLookup = dependencies
.OrderBy(export => export.Library.Identity.Type == LibraryType.ReferenceAssembly)
.GroupBy(export => export.Library.Identity.Name)
.Select(exports => exports.First())
.Select(export => new Dependency(export.Library.Identity.Name, export.Library.Identity.Version.ToString()))
.ToDictionary(dependency => dependency.Name);
return new DependencyContext(target.DotNetFrameworkName, runtime,
GetCompilationOptions(compilerOptions),
GetLibraries(dependencies, dependencyLookup, target, configuration, export => export.CompilationAssemblies),
GetLibraries(dependencies, dependencyLookup, target, configuration, export => export.RuntimeAssemblies));
}
private static Library[] GetLibraries(IEnumerable<LibraryExport> dependencies, Func<LibraryExport, IEnumerable<LibraryAsset>> assemblySelector)
private static CompilationOptions GetCompilationOptions(CommonCompilerOptions compilerOptions)
{
return dependencies.Select(export => GetLibrary(export, assemblySelector(export), dependencies)).ToArray();
return new CompilationOptions(compilerOptions.Defines,
compilerOptions.LanguageVersion,
compilerOptions.Platform,
compilerOptions.AllowUnsafe,
compilerOptions.WarningsAsErrors,
compilerOptions.Optimize,
compilerOptions.KeyFile,
compilerOptions.DelaySign,
compilerOptions.PublicSign,
compilerOptions.EmitEntryPoint);
}
private static Library GetLibrary(LibraryExport export, IEnumerable<LibraryAsset> libraryAssets, IEnumerable<LibraryExport> dependencies)
private static Library[] GetLibraries(IEnumerable<LibraryExport> dependencies,
IDictionary<string, Dependency> dependencyLookup,
NuGetFramework target,
string configuration,
Func<LibraryExport, IEnumerable<LibraryAsset>> assemblySelector)
{
return dependencies.Select(export => GetLibrary(export, target, configuration, assemblySelector(export), dependencyLookup)).ToArray();
}
private static Library GetLibrary(LibraryExport export,
NuGetFramework target,
string configuration,
IEnumerable<LibraryAsset> libraryAssets,
IDictionary<string, Dependency> dependencyLookup)
{
var type = export.Library.Identity.Type.Value.ToLowerInvariant();
var serviceable = (export.Library as PackageDescription)?.Library.IsServiceable ?? false;
var version = dependencies.Where(dependency => dependency.Library.Identity == export.Library.Identity);
var libraryDependencies = new List<Dependency>();
var libraryDependencies = export.Library.Dependencies.Select(libraryRange => GetDependency(libraryRange, dependencies)).ToArray();
foreach (var libraryDependency in export.Library.Dependencies)
{
Dependency dependency;
if (dependencyLookup.TryGetValue(libraryDependency.Name, out dependency))
{
libraryDependencies.Add(dependency);
}
}
string[] assemblies;
if (type == "project")
{
var isExe = ((ProjectDescription) export.Library)
.Project
.GetCompilerOptions(target, configuration)
.EmitEntryPoint
.GetValueOrDefault(false);
assemblies = new[] { export.Library.Identity.Name + (isExe ? ".exe": ".dll") };
}
else
{
assemblies = libraryAssets.Select(libraryAsset => libraryAsset.RelativePath).ToArray();
}
return new Library(
export.Library.Identity.Type.ToString().ToLowerInvariant(),
type,
export.Library.Identity.Name,
export.Library.Identity.Version.ToString(),
export.Library.Hash,
libraryAssets.Select(libraryAsset => libraryAsset.RelativePath).ToArray(),
libraryDependencies,
assemblies,
libraryDependencies.ToArray(),
serviceable
);
}
private static Dependency GetDependency(LibraryRange libraryRange, IEnumerable<LibraryExport> dependencies)
{
var version =
dependencies.First(d => d.Library.Identity.Name == libraryRange.Name)
.Library.Identity.Version.ToString();
return new Dependency(libraryRange.Name, version);
}
}
}

View file

@ -255,8 +255,11 @@ namespace Microsoft.DotNet.Tools.Compiler
if (compilationOptions.PreserveCompilationContext == true)
{
var dependencyContext = DependencyContextBuilder.FromLibraryExporter(
libraryExporter, context.TargetFramework.DotNetFrameworkName, context.RuntimeIdentifier);
var dependencyContext = DependencyContextBuilder.Build(compilationOptions,
libraryExporter,
args.ConfigValue,
context.TargetFramework,
context.RuntimeIdentifier);
var writer = new DependencyContextWriter();
var depsJsonFile = Path.Combine(intermediateOutputPath, context.ProjectFile.Name + "dotnet-compile.deps.json");

View file

@ -0,0 +1,50 @@
using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyModel
{
public class CompilationOptions
{
public IEnumerable<string> Defines { get; }
public string LanguageVersion { get; }
public string Platform { get; }
public bool? AllowUnsafe { get; }
public bool? WarningsAsErrors { get; }
public bool? Optimize { get; }
public string KeyFile { get; }
public bool? DelaySign { get; }
public bool? PublicSign { get; }
public bool? EmitEntryPoint { get; }
public CompilationOptions(IEnumerable<string> defines,
string languageVersion,
string platform,
bool? allowUnsafe,
bool? warningsAsErrors,
bool? optimize,
string keyFile,
bool? delaySign,
bool? publicSign,
bool? emitEntryPoint)
{
Defines = defines;
LanguageVersion = languageVersion;
Platform = platform;
AllowUnsafe = allowUnsafe;
WarningsAsErrors = warningsAsErrors;
Optimize = optimize;
KeyFile = keyFile;
DelaySign = delaySign;
PublicSign = publicSign;
EmitEntryPoint = emitEntryPoint;
}
}
}

View file

@ -12,17 +12,20 @@ namespace Microsoft.Extensions.DependencyModel
{
private const string DepsResourceSufix = ".deps.json";
public DependencyContext(string target, string runtime, Library[] compileLibraries, Library[] runtimeLibraries)
public DependencyContext(string target, string runtime, CompilationOptions compilationOptions, Library[] compileLibraries, Library[] runtimeLibraries)
{
Target = target;
Runtime = runtime;
CompilationOptions = compilationOptions;
CompileLibraries = compileLibraries;
RuntimeLibraries = runtimeLibraries;
}
public string Target { get; set; }
public string Target { get; }
public string Runtime { get; set; }
public string Runtime { get; }
public CompilationOptions CompilationOptions { get; }
public IReadOnlyList<Library> CompileLibraries { get; }

View file

@ -37,11 +37,28 @@ namespace Microsoft.Extensions.DependencyModel
return new DependencyContext(
compileTargetProperty.Key,
runtimeTargetProperty.Key.Substring(compileTargetProperty.Key.Length + 1),
ReadCompilationOptions((JObject)root[DependencyContextStrings.CompilationOptionsPropertName]),
ReadLibraries((JObject)runtimeTargetProperty.Value, true, libraryStubs),
ReadLibraries((JObject)compileTargetProperty.Value, false, libraryStubs)
);
}
private CompilationOptions ReadCompilationOptions(JObject compilationOptionsObject)
{
return new CompilationOptions(
compilationOptionsObject[DependencyContextStrings.DefinesPropertyName]?.Values<string>(),
compilationOptionsObject[DependencyContextStrings.LanguageVersionPropertyName]?.Value<string>(),
compilationOptionsObject[DependencyContextStrings.PlatformPropertyName]?.Value<string>(),
compilationOptionsObject[DependencyContextStrings.AllowUnsafePropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.WarningsAsErrorsPropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.OptimizePropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.KeyFilePropertyName]?.Value<string>(),
compilationOptionsObject[DependencyContextStrings.DelaySignPropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.PublicSignPropertyName]?.Value<bool>(),
compilationOptionsObject[DependencyContextStrings.EmitEntryPointPropertyName]?.Value<bool>()
);
}
private Library[] ReadLibraries(JObject librariesObject, bool runtime, Dictionary<string, DependencyContextReader.LibraryStub> libraryStubs)
{
return librariesObject.Properties().Select(property => ReadLibrary(property, runtime, libraryStubs)).ToArray();
@ -50,7 +67,7 @@ namespace Microsoft.Extensions.DependencyModel
private Library ReadLibrary(JProperty property, bool runtime, Dictionary<string, DependencyContextReader.LibraryStub> libraryStubs)
{
var nameWithVersion = property.Name;
DependencyContextReader.LibraryStub stub;
LibraryStub stub;
if (!libraryStubs.TryGetValue(nameWithVersion, out stub))
{

View file

@ -19,5 +19,27 @@ namespace Microsoft.Extensions.DependencyModel
internal const string TypePropertyName = "type";
internal const string ServiceablePropertyName = "serviceable";
internal const string CompilationOptionsPropertName = "compilationOptions";
internal const string DefinesPropertyName = "defines";
internal const string LanguageVersionPropertyName = "languageVersion";
internal const string PlatformPropertyName = "platform";
internal const string AllowUnsafePropertyName = "allowUnsafe";
internal const string WarningsAsErrorsPropertyName = "warningsAsErrors";
internal const string OptimizePropertyName = "optimize";
internal const string KeyFilePropertyName = "keyFile";
internal const string DelaySignPropertyName = "delaySign";
internal const string PublicSignPropertyName = "publicSign";
internal const string EmitEntryPointPropertyName = "emitEntryPoint";
}
}

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -22,10 +23,56 @@ namespace Microsoft.Extensions.DependencyModel
private JObject Write(DependencyContext context)
{
return new JObject(
new JProperty(DependencyContextStrings.CompilationOptionsPropertName, WriteCompilationOptions(context.CompilationOptions)),
new JProperty(DependencyContextStrings.TargetsPropertyName, WriteTargets(context)),
new JProperty(DependencyContextStrings.LibrariesPropertyName, WriteLibraries(context))
);
}
private JObject WriteCompilationOptions(CompilationOptions compilationOptions)
{
var o = new JObject();
if (compilationOptions.Defines != null)
{
o[DependencyContextStrings.DefinesPropertyName] = new JArray(compilationOptions.Defines);
}
if (compilationOptions.LanguageVersion != null)
{
o[DependencyContextStrings.LanguageVersionPropertyName] = compilationOptions.LanguageVersion;
}
if (compilationOptions.Platform != null)
{
o[DependencyContextStrings.PlatformPropertyName] = compilationOptions.Platform;
}
if (compilationOptions.AllowUnsafe != null)
{
o[DependencyContextStrings.AllowUnsafePropertyName] = compilationOptions.AllowUnsafe;
}
if (compilationOptions.WarningsAsErrors != null)
{
o[DependencyContextStrings.WarningsAsErrorsPropertyName] = compilationOptions.WarningsAsErrors;
}
if (compilationOptions.Optimize != null)
{
o[DependencyContextStrings.OptimizePropertyName] = compilationOptions.Optimize;
}
if (compilationOptions.KeyFile != null)
{
o[DependencyContextStrings.KeyFilePropertyName] = compilationOptions.KeyFile;
}
if (compilationOptions.DelaySign != null)
{
o[DependencyContextStrings.DelaySignPropertyName] = compilationOptions.DelaySign;
}
if (compilationOptions.PublicSign != null)
{
o[DependencyContextStrings.PublicSignPropertyName] = compilationOptions.PublicSign;
}
if (compilationOptions.EmitEntryPoint != null)
{
o[DependencyContextStrings.EmitEntryPointPropertyName] = compilationOptions.EmitEntryPoint;
}
return o;
}
private JObject WriteTargets(DependencyContext context)

View file

@ -13,10 +13,11 @@
"Newtonsoft.Json": "7.0.1"
},
"frameworks": {
"dnx451": {},
"dnxcore50": {
"net451": { },
"dotnet5.4": {
"dependencies": {
"System.Runtime": "4.0.21-rc2-23618",
"System.Linq": "4.0.1-rc2-23616",
"System.Runtime": "4.0.21-rc2-23616",
"System.Dynamic.Runtime": "4.0.11-rc2-23616"
}
}