Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,19 @@ Copyright (c) .NET Foundation. All rights reserved.
</ItemGroup>
</Target>

<!-- Add conditional compilation symbols for target platform backwards compatibility. -->
<Target Name="GeneratePlatformCompatibleDefineConstants"
Condition=" '$(DisableImplicitFrameworkDefines)' != 'true' and '$(TargetPlatformIdentifier)' != '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0)) " >
<ItemGroup>
<_SupportedPlatformCompatibleVersions Include="@(SupportedTargetPlatform)" Condition=" %(Identity) != '' and $([MSBuild]::VersionLessThan(%(Identity), $(TargetPlatformVersion))) " />
<_ImplicitDefineConstant Include="@(_SupportedPlatformCompatibleVersions->'$(TargetPlatformIdentifier.ToUpper())%(Identity)'->Replace('.', '_'))" />
</ItemGroup>
</Target>

<!-- Add implicitly defined preprocessor symbols to DefineConstants -->
<Target Name="AddImplicitDefineConstants"
Condition=" '$(DisableImplicitFrameworkDefines)' != 'true' "
DependsOnTargets="GenerateTargetPlatformDefineConstants;GenerateNETCompatibleDefineConstants"
DependsOnTargets="GenerateTargetPlatformDefineConstants;GenerateNETCompatibleDefineConstants;GeneratePlatformCompatibleDefineConstants"
BeforeTargets="CoreCompile" >
<PropertyGroup>
<DefineConstants Condition=" '@(_ImplicitDefineConstant)' != '' " >$(DefineConstants);@(_ImplicitDefineConstant)</DefineConstants>
Expand Down
101 changes: 101 additions & 0 deletions src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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)]
Expand Down