diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.BeforeCommon.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.BeforeCommon.targets index 8b42b2d6e847..c3f08df257a4 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.BeforeCommon.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.BeforeCommon.targets @@ -206,10 +206,19 @@ Copyright (c) .NET Foundation. All rights reserved. + + + + <_SupportedPlatformCompatibleVersions Include="@(SupportedTargetPlatform)" Condition=" %(Identity) != '' and $([MSBuild]::VersionLessThan(%(Identity), $(TargetPlatformVersion))) " /> + <_ImplicitDefineConstant Include="@(_SupportedPlatformCompatibleVersions->'$(TargetPlatformIdentifier.ToUpper())%(Identity)'->Replace('.', '_'))" /> + + + $(DefineConstants);@(_ImplicitDefineConstant) diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs index ef98b64c861d..01a79dc6de4d 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs @@ -447,6 +447,42 @@ public void It_implicitly_defines_compilation_constants_for_the_target_platform( AssertDefinedConstantsOutput(testAsset, targetFramework, new[] { "NETCOREAPP", "NET", "NET5_0", "NETCOREAPP3_1" }.Concat(expectedDefines).ToArray()); } + [Theory] + [InlineData(new[] { "1.0", "1.1" }, "ios", "1.1", new[] { "IOS", "IOS1_1", "IOS1_0" })] + [InlineData(new[] { "11.11", "12.12", "13.13" }, "android", "12.12", new[] { "ANDROID", "ANDROID11_11", "ANDROID12_12" })] + [InlineData(new[] { "7.0", "8.0", "10.0.19041", "11.0.0" }, "windows", "11.0.0", new[] { "WINDOWS", "WINDOWS7_0", "WINDOWS8_0", "WINDOWS10_0_19041", "WINDOWS11_0_0" })] + public void It_implicitly_defines_compilation_constants_for_the_target_platform_with_backwards_compatibility(string[] supportedTargetPlatform, string targetPlatformIdentifier, string targetPlatformVersion, string[] expectedDefines) + { + var targetFramework = "net5.0"; + var testAsset = _testAssetsManager + .CopyTestAsset("AppWithLibrary", "ImplicitFrameworkConstants", targetFramework) + .WithSource() + .WithTargetFramework(targetFramework) + .WithProjectChanges(project => + { + // Manually set target plaform properties + var ns = project.Root.Name.Namespace; + var propGroup = new XElement(ns + "PropertyGroup"); + project.Root.Add(propGroup); + + var platformIdentifier = new XElement(ns + "TargetPlatformIdentifier", targetPlatformIdentifier); + propGroup.Add(platformIdentifier); + var platformVersion = new XElement(ns + "TargetPlatformVersion", targetPlatformVersion); + propGroup.Add(platformVersion); + var disableUnnecessaryImplicitFrameworkReferencesForThisTest = new XElement(ns + "DisableImplicitFrameworkReferences", "true"); + propGroup.Add(disableUnnecessaryImplicitFrameworkReferencesForThisTest); + + var itemGroup = new XElement(ns + "ItemGroup"); + project.Root.Add(itemGroup); + foreach (var targetPlatform in supportedTargetPlatform) + { + itemGroup.Add(new XElement(ns + "SupportedTargetPlatform", new XAttribute("Include", targetPlatform))); + } + }); + + AssertDefinedConstantsOutput(testAsset, targetFramework, new[] { "NETCOREAPP", "NET", "NET5_0", "NETCOREAPP3_1" }.Concat(expectedDefines).ToArray()); + } + private void AssertDefinedConstantsOutput(TestAsset testAsset, string targetFramework, string[] expectedDefines) { var libraryProjectDirectory = Path.Combine(testAsset.TestRoot, "TestLibrary"); @@ -468,6 +504,71 @@ private void AssertDefinedConstantsOutput(TestAsset testAsset, string targetFram definedConstants.Should().BeEquivalentTo(new[] { "DEBUG", "TRACE" }.Concat(expectedDefines).ToArray()); } + [WindowsOnlyTheory] + [InlineData("netcoreapp3.1", new[] { "NETCOREAPP", "NETCOREAPP3_1" })] + [InlineData("net5.0", new[] { "NETCOREAPP", "NETCOREAPP3_1", "NET", "NET5_0", "WINDOWS", "WINDOWS7_0" }, "windows", "7.0")] + public void It_can_use_implicitly_defined_compilation_constants(string targetFramework, string[] expectedOutput, string targetPlatformIdentifier = null, string targetPlatformVersion = null) + { + var testProj = new TestProject() + { + Name = "CompilationConstants", + TargetFrameworks = targetFramework, + IsExe = true, + IsSdkProject = true + }; + if (targetPlatformIdentifier != null) + { + testProj.AdditionalProperties["TargetPlatformIdentifier"] = targetPlatformIdentifier; + testProj.AdditionalProperties["TargetPlatformVersion"] = targetPlatformVersion; + } + var testAsset = _testAssetsManager.CreateTestProject(testProj); + File.WriteAllText(Path.Combine(testAsset.Path, testProj.Name, $"{testProj.Name}.cs"), @" +using System; +class Program +{ + static void Main(string[] args) + { + #if NETCOREAPP + Console.WriteLine(""NETCOREAPP""); + #endif + #if NETCOREAPP2_1 + Console.WriteLine(""NETCOREAPP2_1""); + #endif + #if NETCOREAPP3_1 + Console.WriteLine(""NETCOREAPP3_1""); + #endif + #if NET + Console.WriteLine(""NET""); + #endif + #if NET5_0 + Console.WriteLine(""NET5_0""); + #endif + #if WINDOWS + Console.WriteLine(""WINDOWS""); + #endif + #if WINDOWS7_0 + Console.WriteLine(""WINDOWS7_0""); + #endif + #if IOS + Console.WriteLine(""IOS""); + #endif + #if IOS7_0 + Console.WriteLine(""IOS7_0""); + #endif + } +}"); + + var buildCommand = new BuildCommand(Log, Path.Combine(testAsset.Path, testProj.Name)); + buildCommand + .Execute() + .Should() + .Pass(); + + var runCommand = new RunExeCommand(Log, Path.Combine(buildCommand.GetOutputDirectory(targetFramework).FullName, $"{testProj.Name}.exe")); + var stdOut = runCommand.Execute().StdOut.Split(Environment.NewLine.ToCharArray()).Where(line => !string.IsNullOrWhiteSpace(line)); + stdOut.Should().BeEquivalentTo(expectedOutput); + } + [Theory] [InlineData(false)] [InlineData(true)]