-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add filtering to SdkSupportedTargetPlatformVersion validation. Fixes #38016. #38017
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…otnet#38016. The SdkSupportedTargetPlatformVersion item group is used for (at least) two things: 1. Generate the _OR_GREATER preprocessing symbols: https://github.com/dotnet/sdk/blob/bfd2919bc446cad68d11de90cec4025d3683591c/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.BeforeCommon.targets#L230-L237 2. Validate the TargetPlatformVersion: https://github.com/dotnet/sdk/blob/bfd2919bc446cad68d11de90cec4025d3683591c/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.TargetFrameworkInference.targets#L233-L246 The problem is that these two uses aren't equivalent. Take for example the following scenario: We release bindings for iOS 10, and a library developer takes advantage of the bindings for the new iOS version, while at the same time supporting multi-targeting to older platforms: ```csharp #if IOS10_0_OR_GREATER UseNewApi (); #else UseOldApi (); #endif ``` Time passes, iOS 11 comes out, and we stop shipping bindings specifically for iOS 10 (the APIs themselves would be included in the bindings for iOS 11). The code above should continue to work, but iOS 10 is not a valid TargetPlatformVersion anymore. However, with the current situation there's no way to express this, because the moment we remove the "10.0" version from SdkSupportedTargetPlatformVersion, the IOS10_0_OR_GREATER define isn't generated anymore. We discussed this in a meeting internally, and the suggestion that came up was to use metadata to handle this situation. So to solve this, I've added metadata to the SdkSupportedTargetPlatformVersion item group to indicate that a particular value is only valid to produce the _OR_GREATER processing symbol: ```xml <ItemGroup> <SdkSupportedTargetPlatformVersion Include="10.0" OrGreaterHistoricalValue="true" /> <SdkSupportedTargetPlatformVersion Include="12.0" /> </ItemGroup> ``` And then filter out these historical values when validating the TargetPlatformVersion. Fixes dotnet#38016.
| Condition="'$(TargetPlatformVersion)' != '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0)) and ('$(Language)' != 'C++' or '$(_EnablePackageReferencesInVCProjects)' == 'true')"> | ||
| <ItemGroup> | ||
| <_ValidTargetPlatformVersion Include="@(SdkSupportedTargetPlatformVersion)" Condition="'@(SdkSupportedTargetPlatformVersion)' != '' and $([MSBuild]::VersionEquals(%(Identity), $(TargetPlatformVersion)))" /> | ||
| <_ApplicableTargetPlatformVersion Include="@(SdkSupportedTargetPlatformVersion)" Condition="'@(SdkSupportedTargetPlatformVersion)' != '' and '%(SdkSupportedTargetPlatformVersion.OrGreaterHistoricalValue)' != 'true'" RemoveMetadata="OrGreaterHistoricalValue" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestions welcome for a better name than OrGreaterHistoricalValue!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If these are really only for $(DefineConstants), maybe the name should be something like %(DefineConstantsOnly)?
This is a continuation of the problem here: dotnet/android#8569 (comment)
And using %(MaximumNETVersion) or %(MinimumNETVersion) wouldn't be sufficient?
/cc @dsplaisted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And using
%(MaximumNETVersion)or%(MinimumNETVersion)wouldn't be sufficient?
We might want to have strange combination of valid values SdkSupportedTargetPlatformVersion. For a given iOS release, these might be the versions we'd want to support (all in .NET 8):
iOS 17.0: 17.0
iOS 17.1: 17.0 + 17.1
iOS 17.2: 17.0 + 17.2 (but not 17.1)
and the .NET version range check becomes weird in that case (we'd have to come up with something non-intuitive to exclude 17.1).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I like the name DefineConstantsOnly a lot better than OrGreaterHistoricalValue.
dsplaisted
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Can we switch to DefineConstantsOnly for the metadata name (or something else, if anyone has a better idea).
| .And | ||
| .HaveStdOutContaining("NETSDK1140") | ||
| .And | ||
| .HaveStdOutContaining("111.0 is not a valid TargetPlatformVersion") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We try to avoid hard-coding expected strings from resources in tests, as that won't work if we are trying to test under localization. The tests should have access to the resources used in the messages, so you should be able to get the original resource string and format it to get the expected string.
| Condition="'$(TargetPlatformVersion)' != '' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0)) and ('$(Language)' != 'C++' or '$(_EnablePackageReferencesInVCProjects)' == 'true')"> | ||
| <ItemGroup> | ||
| <_ValidTargetPlatformVersion Include="@(SdkSupportedTargetPlatformVersion)" Condition="'@(SdkSupportedTargetPlatformVersion)' != '' and $([MSBuild]::VersionEquals(%(Identity), $(TargetPlatformVersion)))" /> | ||
| <_ApplicableTargetPlatformVersion Include="@(SdkSupportedTargetPlatformVersion)" Condition="'@(SdkSupportedTargetPlatformVersion)' != '' and '%(SdkSupportedTargetPlatformVersion.OrGreaterHistoricalValue)' != 'true'" RemoveMetadata="OrGreaterHistoricalValue" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I like the name DefineConstantsOnly a lot better than OrGreaterHistoricalValue.
|
@dsplaisted I've updated the PR according to your comments. |
dsplaisted
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Feel free to merge when ready, or let me know if you need me to click the button.
| .And | ||
| .HaveStdOutContaining("NETSDK1140") | ||
| .And | ||
| .HaveStdOutContaining("111.0 is not a valid TargetPlatformVersion") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to make the string formatting change from the previous test here too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, forgot I did the same thing twice.
The SdkSupportedTargetPlatformVersion item group is used for (at least) two things:
sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.BeforeCommon.targets
Lines 230 to 237 in bfd2919
sdk/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.TargetFrameworkInference.targets
Lines 233 to 246 in bfd2919
The problem is that these two uses aren't equivalent.
Take for example the following scenario:
We release bindings for iOS 10, and a library developer takes advantage of the
bindings for the new iOS version, while at the same time supporting
multi-targeting to older platforms:
Time passes, iOS 11 comes out, and we stop shipping bindings specifically for
iOS 10 (the APIs themselves would be included in the bindings for iOS 11). The
code above should continue to work, but iOS 10 is not a valid
TargetPlatformVersion anymore. However, with the current situation there's no
way to express this, because the moment we remove the "10.0" version from
SdkSupportedTargetPlatformVersion, the IOS10_0_OR_GREATER define isn't
generated anymore.
We discussed this in a meeting internally, and the suggestion that came up
was to use metadata to handle this situation.
So to solve this, I've added metadata to the SdkSupportedTargetPlatformVersion
item group to indicate that a particular value is only valid to produce the
_OR_GREATER processing symbol:
And then filter out these historical values when validating the
TargetPlatformVersion.
Fixes #38016.