diff --git a/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs b/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs index 42d63f164..005d24f81 100644 --- a/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs +++ b/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs @@ -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 dependencies, Func> 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 libraryAssets, IEnumerable dependencies) + private static Library[] GetLibraries(IEnumerable dependencies, + IDictionary dependencyLookup, + NuGetFramework target, + string configuration, + Func> assemblySelector) { + return dependencies.Select(export => GetLibrary(export, target, configuration, assemblySelector(export), dependencyLookup)).ToArray(); + } + + private static Library GetLibrary(LibraryExport export, + NuGetFramework target, + string configuration, + IEnumerable libraryAssets, + IDictionary 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(); - 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 dependencies) - { - var version = - dependencies.First(d => d.Library.Identity.Name == libraryRange.Name) - .Library.Identity.Version.ToString(); - return new Dependency(libraryRange.Name, version); - } } } diff --git a/src/Microsoft.DotNet.Tools.Compiler/Program.cs b/src/Microsoft.DotNet.Tools.Compiler/Program.cs index d08961c25..5c40a4a54 100644 --- a/src/Microsoft.DotNet.Tools.Compiler/Program.cs +++ b/src/Microsoft.DotNet.Tools.Compiler/Program.cs @@ -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"); diff --git a/src/Microsoft.Extensions.DependencyModel/CompilationOptions.cs b/src/Microsoft.Extensions.DependencyModel/CompilationOptions.cs new file mode 100644 index 000000000..677879436 --- /dev/null +++ b/src/Microsoft.Extensions.DependencyModel/CompilationOptions.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyModel +{ + public class CompilationOptions + { + public IEnumerable 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 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; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs index 69f112e4c..4a62481cd 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs @@ -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 CompileLibraries { get; } diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextReader.cs index f181298b2..2d1a67137 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextReader.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextReader.cs @@ -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(), + compilationOptionsObject[DependencyContextStrings.LanguageVersionPropertyName]?.Value(), + compilationOptionsObject[DependencyContextStrings.PlatformPropertyName]?.Value(), + compilationOptionsObject[DependencyContextStrings.AllowUnsafePropertyName]?.Value(), + compilationOptionsObject[DependencyContextStrings.WarningsAsErrorsPropertyName]?.Value(), + compilationOptionsObject[DependencyContextStrings.OptimizePropertyName]?.Value(), + compilationOptionsObject[DependencyContextStrings.KeyFilePropertyName]?.Value(), + compilationOptionsObject[DependencyContextStrings.DelaySignPropertyName]?.Value(), + compilationOptionsObject[DependencyContextStrings.PublicSignPropertyName]?.Value(), + compilationOptionsObject[DependencyContextStrings.EmitEntryPointPropertyName]?.Value() + ); + } + private Library[] ReadLibraries(JObject librariesObject, bool runtime, Dictionary 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 libraryStubs) { var nameWithVersion = property.Name; - DependencyContextReader.LibraryStub stub; + LibraryStub stub; if (!libraryStubs.TryGetValue(nameWithVersion, out stub)) { diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextStrings.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextStrings.cs index 9b8f81429..c6f691fd8 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextStrings.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextStrings.cs @@ -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"; } } \ No newline at end of file diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs index 1b3a1aa68..e5b4e9f6f 100644 --- a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs +++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs @@ -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) diff --git a/src/Microsoft.Extensions.DependencyModel/project.json b/src/Microsoft.Extensions.DependencyModel/project.json index 1cade77eb..6b1dc0d9d 100644 --- a/src/Microsoft.Extensions.DependencyModel/project.json +++ b/src/Microsoft.Extensions.DependencyModel/project.json @@ -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" } }