-
Notifications
You must be signed in to change notification settings - Fork 161
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
Add spec for MinimumOSVersion. #97
Conversation
|
||
|
||
- the call is guarded by a `CheckOS` or `CheckOSVersion` call against a version that is greater than or equal to the member’s minimum platform version | ||
- the caller member has a minimum platform version that is equal to or higher than the callee |
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.
There's potential to have analyzers to ensure availability attributes are logical - but it brings some special cases.
E.g. when a new type is introduced in a hierarchy, which is not a breaking change, you can end up with
[Introduced (.ios, 8,0)]
class NSFoo : NSObject {
string Id {get;}
string Name {get;}
}
becoming
[Introduced (.ios, 14,0)]
class NSMiddle : NSObject {
[Introduced (.ios, 8,0)]
string Id {get;}
}
[Introduced (.ios, 8,0)]
class NSFoo : NSMiddle {
string Name {get;}
}
and it's easy to think there's a mistake in Middle
since a member was available well before it's type. While you can't create NSMiddle
on iOS8 you can still use NSFoo.Middle
(without warnings) on iOS8.
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 can use Windows's existing version and api tagging or we could go with existing tags which are already there to expose them as such in a more .NET/WinMD way. Existing tools could be easily supported if we did follow latter idea.
Try to use ideas as much as from the Windows platform teams. They are relevant to all other platforms out there.
/cc @joshpeterson |
|
||
The `Microsoft.Net.Sdk` targets will extract the OS API Version component from the `TargetFramework` into the `TargetPlatformVersion` MSBuild property and burn it into an assembly attribute. Tools that use this value are expected to access it from the MSBuild property or from the assembly attribute. | ||
|
||
Project files may specify a `MinimumPlatformVersion`, and if they do not it will default to the `TargetPlatformVersion` value. The `MinimumPlatformVersion` must not be higher than the `TargetPlatformVersion`, and this will be validated at the start of the build. |
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.
Immo's TFM spec refers to this as TargetPlatformMinVersion
which is what we use in Windows today. Should this be changed to that?
Project files may specify a `MinimumPlatformVersion`, and if they do not it will default to the `TargetPlatformVersion` value. The `MinimumPlatformVersion` must not be higher than the `TargetPlatformVersion`, and this will be validated at the start of the build. | |
Project files may specify a `TargetPlatformMinVersion`, and if they do not it will default to the `TargetPlatformVersion` value. The `TargetPlatformMinVersion` must not be higher than the `TargetPlatformVersion`, and this will be validated at the start of the build. |
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.
These two specs were written in parallel after we had a discussion a few weeks ago - I don't think either name is canonical right now.
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.
Those property names exist in Windows SDK for a while now. That's why I suggested using those. We can conceptually map those 3 version properties for all platforms, no matter what their platform specific behaviour is.
They differ and that's why we have different platforms 😐. But we don't have to bring that complexity into the user facing project file.
|
||
> NOTE: would `{PlatformIdentifier}MinimumVersion` be better? It would sort/group more easily with other OS-specific properties. | ||
|
||
> NOTE: Using the existing `TargetPlatformVersion` property to represent the API version may be confusing for platforms such as Android that allow having different values for the target version and API version.. |
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.
when would you want to specify a different target and API version?
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.
Android always target the API levels. So *MinVersion
-> becomes minimum API level, *MaxVersion
becomes targeted API level and we can have TargetPlatformVersion
point to either of these depending on the project or have new value that mirrors the behaviour of TargetPlatformMaxVersionTested
.
Before you guys ask, yes, Windows SDK has more than 4 properties just for versions and 3 just for UWP project files!
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.
Some comments on things that could be improved.
|
||
Platform-neutral assemblies, i.e. assemblies that target a platform-neutral TFM such as `net5`, will have to declare the attribute explicitly. | ||
|
||
> NOTE: This seems a bit inconsistent. As a user, I’d expect `Minimum{OSName}Version` properties to work in platform-neutral assemblies too, but handling all those properties when building platform-neutral assemblies would be problematic as it would centralize the definitions of all of the platform-specific `MinimumVersion` properties into the `Microsoft.Net.Sdk` targets. |
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.
As a user, I expect the runtime take care of the compatibility but with escape hatches for users (like me...) who want to further configure certain behaviours (based on some custom native lib and it's interop lib that I might be introducing into the App).
But for large pool of libs, they are mostly pure IL than native code. so, yes it's inconsistent!
|
||
> NOTE: This seems a bit inconsistent. As a user, I’d expect `Minimum{OSName}Version` properties to work in platform-neutral assemblies too, but handling all those properties when building platform-neutral assemblies would be problematic as it would centralize the definitions of all of the platform-specific `MinimumVersion` properties into the `Microsoft.Net.Sdk` targets. | ||
> | ||
>Perhaps we could use items and metadata instead of platform-specific properties, e.g. `<PlatformInfo Include="ios" MinimumVersion="15.0" />`. For platform-specific projects, we could allow the simpler `MinimumPlatformVersion` property by mapping it into one of these items, e.g. `<PlatformInfo Include="$(TargetPlatformIdentifier)" Version="$(MinimumPlatformVersion)" Condition="'$(TargetPlatformIdentifier)' != ''" />`. |
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 can do Items for build side but it can't be used user facing, since they won't be available to users for customizing the builds.
You could have this...
<TargetPlatformInfo Include="$(TargetPlatformIdentifier)" MinVersion="$(TargetPlatformMinVersion)" Version="$(TargetPlatformVersion)" MaxVersion="$(TargetPlatformMaxVersion)"/>
but only for MSBuild scripts while authoring the SDKs but not as a user facing one.
<metadata> | ||
<platformInfo> | ||
<net5-ios15.0 minimumVersion="13.0" /> | ||
<net5-mac10.15 minimumVersion="10.11" /> | ||
</platformInfo> | ||
</metadata> |
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.
<metadata> | |
<platformInfo> | |
<net5-ios15.0 minimumVersion="13.0" /> | |
<net5-mac10.15 minimumVersion="10.11" /> | |
</platformInfo> | |
</metadata> | |
<metadata> | |
<platforms framework="net5.0"> | |
<platform id="ios" minVersion="13.0" targetVersion="13.2" maxVersion="14.0"> | |
<platform id="mac" minVersion="10.10" targetVersion="10.11" maxVersion="10.14"> | |
<platform id="android" minVersion="18" targetVersion="21" maxVersion="24"> | |
</platforms> | |
<platforms framework="net6.0"> | |
<platform id="ios" minVersion="13.1" targetVersion="13.3" maxVersion="14.0"> | |
<platform id="mac" minVersion="10.11" targetVersion="10.12" maxVersion="10.14"> | |
<platform id="android" minVersion="19" targetVersion="22" maxVersion="24"> | |
</platforms> | |
</metadata> |
We can use this format for the platform neutral declarations too (see below). These are only needed if we have interop between native lib and a managed implementation but could be useful for binding libs too as they are essentially more or less the same!
targetVersion
and maxVersion
are totally optional. They could used to further manage the dependencies and resolve conflicts for large typical project that targets multiple platforms.
|
||
|
||
- the call is guarded by a `CheckOS` or `CheckOSVersion` call against a version that is greater than or equal to the member’s minimum platform version | ||
- the caller member has a minimum platform version that is equal to or higher than the callee |
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 can use Windows's existing version and api tagging or we could go with existing tags which are already there to expose them as such in a more .NET/WinMD way. Existing tools could be easily supported if we did follow latter idea.
Try to use ideas as much as from the Windows platform teams. They are relevant to all other platforms out there.
```csharp | ||
[Introduced(PlatformIdentifier.macOS, 10, 2)] | ||
[Deprecated(PlatformIdentifier.macOS, 10, 9)] | ||
[Removed(PlatformIdentifier.macOS, 10, 12, 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.
Why not use solutions like WinMD
and XLang
to generate metadata (bindings) about the platforms' APIs instead manually duplicating the Swift's attributes into .NET attributes?
That way bindings can be language/framework neutral and in unified format.
@kennykerr @migueldeicaza Is this possible?
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.
This is a super simple and inexpensive mechanism. We don't want to take on heavy weight dependencies for it. It's also "OK" to duplicate attributes like this across dev stacks.
|
||
The OS API Version is part of the target framework, and affects which framework reference assemblies the app is compiled against. It does not affect which OS versions the app can run on (for well behaved platforms where backwards ABI compatibility is preserved). The primary reason for an app project to target an old OS API version is to allow the project to continue to build on older versions of the SDK that do not support the more recent API versions. A secondary reason may be to limit the API surface shown in IntelliSense so that it’s easier to avoid newer APIs, though this use case could perhaps be better supported in future by IDE experiences such allowing filtering IntelliSense by platform version. | ||
|
||
However, for libraries that are distributed as NuGets, it is useful to be able to multi-target across multiple API versions. This allows NuGets to access features available in newer API versions while continuing to ship updates for consumption by apps and libraries that (for whatever reason) target older API versions. |
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.
Maybe too niche, but in a big shop, you could also use this same pattern for P2P.
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.
True! I'm not sure it's worth specifically calling it out though
</metadata> | ||
``` | ||
|
||
A reference assembly for a platform-neutral TFM (e.g. `net5` or `net6`) may still need to express platform-specific minimum versions if the implementations are platform-specific (aka ‘bait and switch’). As before, the element matches the TFM of the reference assembly, but this time there is no `minimumVersion`. Instead there are sub-elements that provide `minimumVersion` values for platforms using the `TargetPlatformIdentifier` of those platforms to identify them: |
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.
A reference assembly for a platform-neutral TFM (e.g. `net5` or `net6`) may still need to express platform-specific minimum versions if the implementations are platform-specific (aka ‘bait and switch’). As before, the element matches the TFM of the reference assembly, but this time there is no `minimumVersion`. Instead there are sub-elements that provide `minimumVersion` values for platforms using the `TargetPlatformIdentifier` of those platforms to identify them: | |
A reference assembly for a platform-neutral TFM (e.g. `net5.0` or `net6.0`) may still need to express platform-specific minimum versions if the implementations are platform-specific (aka ‘bait and switch’). As before, the element matches the TFM of the reference assembly, but this time there is no `minimumVersion`. Instead there are sub-elements that provide `minimumVersion` values for platforms using the `TargetPlatformIdentifier` of those platforms to identify them: |
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.
Honest question ... do we have satisfactory support for bait-and-switch in dotnet pack today? If not, it should noted.
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.
No, we do not. That was one of the things that NuGetizer did well.
From the Windows Platform POV, using version numbers is only half the story. Apps should use feature-detection and light-up through runtime metadata:
Some individual Windows API also have We recognize that this matrix makes developing version-and-edition software challenging, and having a standardized approach like this is useful for declaring in code what's possible when. Are applications ever expected to call the proposed APIs, or are they only for components to know if they can do their work, or only compile-time markup? I would not want to see an application say:
Instead, the application should say:
And let the component do the light-up checks. That way when the Component figures out a way to work on Windows 10 1803 the app doesn't have to find and fix the CheckWindowsVersions points. |
7798978
to
1fef8db
Compare
Applications would be expected to call these APIs, though in some cases the JIT/AOT compiler could elide these checks.
iOS and Android don't neatly support these kinds of checks though. The bindings are thin wrappers over the native APIs of the underlying platform, which in a given OS release may add things as granular as new helper methods on existing classes. We could probably we could probably break a lot of these new APIs down into feature/component/capability groups, but it would be a lot of error-prone manual annotation work for no real gain. That said, I do think some kind of |
|
||
# MSBuild Properties | ||
|
||
The `Microsoft.Net.Sdk` targets will extract the OS API Version component from the `TargetFramework` into the `TargetPlatformVersion` MSBuild property and burn it into an assembly attribute. Tools that use this value are expected to access it from the MSBuild property or from the assembly attribute. | ||
|
||
Project files may specify a `MinimumPlatformVersion`, and if they do not it will default to the `TargetPlatformVersion` value. The `MinimumPlatformVersion` must not be higher than the `TargetPlatformVersion`, and this will be validated at the start of the build. | ||
Project files may specify an `OSMinimumVersion`, and if they do not it will default to OS Version equivalent to the OS API version specified in the `TargetPlatformVersion` value. The `OSMinimumVersion` must not be higher than the `TargetPlatformVersion`, and this will be validated at the start of the build. |
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.
How will we handle this if we update the bindings outside of the OS version. IE we ship iOS bindings 15.0.1, but it still maps to iOS 15.0. Does each workload need to keep a mapping between TargetPlatformVersion
and OSMinimumVersion
for that platform?
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.
Yes, that's unfortunate but necessary. Still thinking about whether to formally define a standard mechanism or leave it up to the platform targets.
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.
Why not define a roll forward mechanism for bindings just like the runtime packages?
That would certainly remove these complications!!
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.
@Nirmal4G it's not that easy.
For example: from the TFM net5-ios15.0
we can infer that the OSMinimumVersion
default is 15.0
. However, suppose the TFM net5-ios15.0.1
was a revision of the bindings rather than bindings for a new OS version, then its OSMinimumVersion
would also be need to be 15.0
.
We could handle that in a general way by saying that only the first two components of the binding version are the OS version and the third component is the bindings revision. However, those kinds of conventions we need to be determined on a platform by platform basis, as different platforms have different versioning schemes.
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.
This is still a problem in the current proposal with the TF having bindings revision. Do we expect people to target the same platform for each bindings revision, I don't think so. I didn't encounter any packages targeting specifically any platform with multiple bindings!!! Are there?
If so, Why not separate the bindings version into a separate property?
Say PlatformPackageVersion
if we're using nuget as the delivery mechanism for the bindings and PlatformBindingsRevision
if we're shipping bindings within the workload itself. If we're using both we could use the latter to set the former for resolving the implicit FrameworkReference.
|
||
> NOTE: Using the existing `TargetPlatformVersion` property to represent the API version may be confusing for platforms such as Android that allow having different values for the target version and API version.. | ||
> ***NOTE***: `{PlatformIdentifier}MinimumVersion` was chosen over `Minimum{PlatformIdentifier}Version` as it it's more easily searchable and sorts/group more easily with other OS-specific properties. |
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 Windows already has a property defined that follows a different format: TargetPlatformMinVersion
. We should cover how that relates to the new properties.
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.
Added a clarifying note - 7c34d18 /cc @terrajobst
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.
Apple platforms and Windows defines the same version for both API and OS. But Android has API levels. But do the MSBuild projects (and the Android SDK tools) need the OS version? If so, Why?
I expect parts to be split into other documents and refined but this should be a good starting point.
Co-Authored-By: Rolf Bjarne Kvinge <[email protected]>
Co-Authored-By: Rich Lander <[email protected]>
7c34d18
to
edf53bb
Compare
This spec describes a standard mechanism for libraries to express the availability of APIs on different platforms and different versions of those platforms using attributes and MSBuild properties, and how those annotations can be used to improve the developer experience at multiple levels. It's based on the model already present in Xamarin.iOS.
I expect parts to be split into other documents and refined but this should be a good starting point.