diff --git a/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/Program.cs b/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/Program.cs new file mode 100644 index 000000000..f5f4b6d13 --- /dev/null +++ b/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main() + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json b/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json new file mode 100644 index 000000000..4d87acf96 --- /dev/null +++ b/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": false + }, + + "dependencies": { }, + + "frameworks": { + "net20": { }, + "net35": { }, + "net40": { }, + "net461": { }, + "dnxcore50": { + "dependencies": { + "NETStandard.Library": "1.0.0-rc2-23811" + } + } + } +} diff --git a/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoFileGenerator.cs b/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoFileGenerator.cs index ab24413fb..3e4408bc8 100644 --- a/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoFileGenerator.cs +++ b/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoFileGenerator.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp; using System.IO; using System.Runtime.Versioning; using Microsoft.CodeAnalysis.CSharp.Syntax; +using NuGet.Frameworks; namespace Microsoft.DotNet.Cli.Compiler.Common { @@ -59,7 +60,7 @@ namespace Microsoft.DotNet.Cli.Compiler.Common private static Dictionary GetProjectAttributes(AssemblyInfoOptions metadata) { - return new Dictionary() + var attributes = new Dictionary() { [typeof(AssemblyTitleAttribute)] = EscapeCharacters(metadata.Title), [typeof(AssemblyDescriptionAttribute)] = EscapeCharacters(metadata.Description), @@ -68,9 +69,34 @@ namespace Microsoft.DotNet.Cli.Compiler.Common [typeof(AssemblyVersionAttribute)] = EscapeCharacters(metadata.AssemblyVersion?.ToString()), [typeof(AssemblyInformationalVersionAttribute)] = EscapeCharacters(metadata.InformationalVersion), [typeof(AssemblyCultureAttribute)] = EscapeCharacters(metadata.Culture), - [typeof(NeutralResourcesLanguageAttribute)] = EscapeCharacters(metadata.NeutralLanguage), - [typeof(TargetFrameworkAttribute)] = EscapeCharacters(metadata.TargetFramework) + [typeof(NeutralResourcesLanguageAttribute)] = EscapeCharacters(metadata.NeutralLanguage) }; + + if (SupportsTargetFrameworkAttribute(metadata)) + { + // TargetFrameworkAttribute only exists since .NET 4.0 + attributes[typeof(TargetFrameworkAttribute)] = EscapeCharacters(metadata.TargetFramework); + }; + + return attributes; + } + + private static bool SupportsTargetFrameworkAttribute(AssemblyInfoOptions metadata) + { + if (string.IsNullOrEmpty(metadata.TargetFramework)) + { + // target framework is unknown. to be on the safe side, return false. + return false; + } + + var targetFramework = NuGetFramework.Parse(metadata.TargetFramework); + if (!targetFramework.IsDesktop()) + { + // assuming .NET Core, which should support .NET 4.0 attributes + return true; + } + + return targetFramework.Version >= new Version(4, 0); } private static bool IsSameAttribute(Type attributeType, AttributeSyntax attributeSyntax) diff --git a/test/dotnet-build.Tests/BuildOutputTests.cs b/test/dotnet-build.Tests/BuildOutputTests.cs index 1f4a702a8..6917e83fc 100644 --- a/test/dotnet-build.Tests/BuildOutputTests.cs +++ b/test/dotnet-build.Tests/BuildOutputTests.cs @@ -3,10 +3,12 @@ using System.IO; using System.Linq; +using System.Runtime.InteropServices; using FluentAssertions; 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 @@ -128,6 +130,44 @@ namespace Microsoft.DotNet.Tools.Builder.Tests informationalVersion.Should().BeEquivalentTo("1.0.0-85"); } + [Theory] + [InlineData("net20", false, true)] + [InlineData("net40", true, true)] + [InlineData("net461", true, true)] + [InlineData("dnxcore50", true, false)] + public void MultipleFrameworks_ShouldHaveValidTargetFrameworkAttribute(string frameworkName, bool shouldHaveTargetFrameworkAttribute, bool windowsOnly) + { + var framework = NuGetFramework.Parse(frameworkName); + + var testInstance = TestAssetsManager.CreateTestInstance("TestLibraryWithMultipleFrameworks") + .WithLockFiles(); + + var cmd = new BuildCommand(Path.Combine(testInstance.TestRoot, Project.FileName), framework: framework.GetShortFolderName()); + + if (windowsOnly && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // on non-windows platforms, desktop frameworks will not build + cmd.ExecuteWithCapturedOutput().Should().Fail(); + } + else + { + cmd.ExecuteWithCapturedOutput().Should().Pass(); + + var output = Path.Combine(testInstance.TestRoot, "bin", "Debug", framework.GetShortFolderName(), "TestLibraryWithMultipleFrameworks.dll"); + var targetFramework = PeReaderUtils.GetAssemblyAttributeValue(output, "TargetFrameworkAttribute"); + + if (shouldHaveTargetFrameworkAttribute) + { + targetFramework.Should().NotBeNull(); + targetFramework.Should().BeEquivalentTo(framework.DotNetFrameworkName); + } + else + { + targetFramework.Should().BeNull(); + } + } + } + [Fact] public void ResourceTest() {