Skip to content
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 TFMs in .NET 5 #92

Merged
merged 38 commits into from
Mar 23, 2020
Merged

Add spec for TFMs in .NET 5 #92

merged 38 commits into from
Mar 23, 2020

Conversation

terrajobst
Copy link
Member

@terrajobst terrajobst commented Feb 14, 2020

We'd like to drastically simplify the framework names (TFMs) developers must use in project files and NuGet packages. This includes merging the concept of .NET 5 and .NET Standard while still being able to use #if to use OS-specific APIs. This document explains the motivation and resulting developer experience.

The proposal is to reuse the existing net TFM and model OS-specific APIs on top via a new syntax:

  • net5.0. This TFM is for code that runs everywhere. It combines and replaces the netcoreapp and netstandard names. This TFM will generally only include technologies that work cross-platform (modulo pragmatic concessions, like we already did in .NET Standard).

  • net5.0-winnet5.0-iosnet5.0-android. These TFMs represent OS specific flavors of .NET 5 that include net5.0 plus OS-specific bindings.

Copy link
Contributor

@keichinger keichinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found two small typos, other than that it looks pretty good 👍

accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
Copy link
Contributor

@mairaw mairaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions

accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
@dotMorten
Copy link

In your PR comment above you say:

net5.0-win, net5.0-ios, net5.0-android. These TFMs represent OS specific flavors of .NET 5 that include net5.0 plus OS-specific bindings.

However in the Q&A it says:

However, net5 will not include .NET projections of OS APIs, such as: WinRT, iOS bindings, Android bindings, Web assembly host APIs

I think the approach to not have the bindings included is a good one, so I hope the Q&A part is correct. Otherwise how would Ida specify she wants/depends on ios9+, or Ada requiring android 10x+ APIs?

@Happypig375
Copy link
Member

@dotMorten These two statements do not counter each other. net5 the TFM is not net5.0-win, net5.0-ios, nor net5.0-android.

Copy link
Member

@NickCraver NickCraver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall

  • net5 is listed as "Will work, but shouldn't be used.", but yet we're doing it in this document pretty pervasively - shouldn't we switch to net5.0 here everywhere?
    • It's also used throughout the doc as net5-win and such, should all these be net5.0-win?
  • Also: do we need to keep net5 as a thing? It'd eliminate a lot of "forever" pain if we killed it ASAP. My question after coming away from this is "why would it still exist?" If it has to, I think it'd be good to call out why in the doc...and fix all the other references to make what the future is clear.

(Minor) On iOS/Android/etc.

  • It'd might be good to cover (or explicitly state we're not covering) what happens with the difference versions of the platform, e.g. iOS and Android. What's the minimum version of their SDK we're targeting? Or does it matter? (this may be obvious for those familiar with Xamarin, but not to others)
    • I see "We need to require a minimum version for the iOS/Android/Windows SDKs." - does that mean each TFM has a corresponding foreign SDK minimum version? Phrasing it like this may be all that's needed.
    • Related: "The calls to APIs introduced in later versions must be guarded, but this is generally understood" - I would assume that thinking through it, but likely it's not "generally understood" outside current devs on those platforms (just pointing this out since we're trying to attract new users).

accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
@dotMorten
Copy link

dotMorten commented Feb 16, 2020

Good points @NickCraver. I found the use of net5 be allowed but discouraged odd too.
Regarding this:

The calls to APIs introduced in later versions must be guarded, but this is generally understood

Please don't do this. It's extremely error prone. We developers tend to be using recent devices that have all the APIs available and then don't realize we missed a guard until a customer on an older device reports a crash. I prefer targeting the minimum needed to ensure that isn't happening.

@Nirmal4G
Copy link

Nirmal4G commented Feb 17, 2020

@terrajobst Very well thought plan for .NET 5. But there are few doubts I have...

  • Why .NET 5 maps to .NETCoreApp? (technically it is .NET Core but...)
  • Why are we still using TargetFramework in .NET 5?

I prefer .NET by itself, as it represents exactly what it is, a single framework, even better solution would be removing the TargetFramework concept altogether and introduce TargetPlatform/TargetMachine (since, you basically target the platform/architecture combo aka runtime) with corresponding values any, android, ios, macos, windows/win/uap and any, x64, x86, arm.

@Nirmal4G
Copy link

Nirmal4G commented Feb 17, 2020

Examples

Here, variants 1x is using TargetPlatform/TargetMachine combo. variants 2x is using additional TargetRuntime which is already present in the SDK in the form of RuntimeIdentifier

Variant 1A

Example Properties in Project File
<Project Sdk="MSBuild.NET.Sdk">

  <PropertyGroup>
    <TargetPlatforms>Windows;Android;Tizen</TargetPlatforms>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetPlatform)' == 'Windows'">
    <TargetPlatformMinVersion>10.0.10150.0</TargetPlatformMinVersion>
    <TargetPlatformMaxVersion>10.0.19500.0</TargetPlatformMaxVersion>
    <TargetMachines>x64;ARM32;ARM64</TargetMachines>
  </PropertyGroup>

  <!-- OR -->

  <PropertyGroup Condition="'$(TargetPlatform)' == 'Windows'">
    <TargetPlatformMinVersion>5.0</TargetPlatformMinVersion>
    <TargetPlatformMaxVersion>10.0</TargetPlatformMaxVersion>
    <TargetMachines>x64;x86</TargetMachines>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetPlatform)' == 'Android'">
    <TargetPlatformMinVersion>7.0</TargetPlatformMinVersion>
    <TargetPlatformMaxVersion>10.0</TargetPlatformMaxVersion>
    <TargetMachines>x86;ARM64</TargetMachines>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetPlatform)' == 'Tizen'">
    <TargetPlatformMinVersion>3.0</TargetPlatformMinVersion>
    <TargetPlatformMaxVersion>5.0</TargetPlatformMaxVersion>
    <TargetMachine>ARM</TargetMachine>
  </PropertyGroup>

</Project>

Variant 1B

Example Properties in Project File
<Project Sdk="MSBuild.NET.Sdk">

  <PropertyGroup>
    <TargetPlatform>Any</TargetPlatform>
    <TargetMachine>Any</TargetMachine><!-- OR -->
    <TargetMachines>x64;x86;ARM64</TargetMachines>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetMachine)' == 'x64'"/>
  <PropertyGroup Condition="'$(TargetMachine)' == 'x86'"/>
  <PropertyGroup Condition="'$(TargetMachine)' == 'ARM64'"/>

</Project>

Variant 2A

Example Properties in Project File
<Project Sdk="MSBuild.NET.Sdk">

  <PropertyGroup>
    <TargetRuntimes>win10.0-x64;win7-x86;win8.1-arm;macos11.14-x64;android10.0-arm32;ios11.2-arm64</TargetRuntimes>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetRuntime)' == 'win10.0-x64'">
    <TargetRuntimeMoniker>Windows-v10.0-x64,Version=5.0</TargetRuntimeMoniker>
    <TargetRuntimeIdentifier>Windows-v10.0-x64</TargetRuntimeIdentifier>
    <TargetRuntimeVersion>5.0</TargetRuntimeVersion>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetRuntime)' == 'android10.0-arm32'">
    <TargetPlatformMoniker>Android,Version=10.0</TargetPlatformMoniker>
    <TargetPlatformIdentifier>Android</TargetPlatformIdentifier>
    <TargetPlatformVersion>10.0</TargetPlatformVersion>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetRuntime)' == 'ios11.2-arm64'">
    <TargetPlatform>ios11.2</TargetPlatform>
    <TargetMachine>arm64</TargetMachine>
  </PropertyGroup>

</Project>

Variant 2B

Example Properties in Project File
<Project Sdk="MSBuild.NET.Sdk">

  <PropertyGroup>
    <TargetRuntimes>any;any-x64;any-arm</TargetRuntimes>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetRuntime)' == 'any'">
    <TargetRuntimeMoniker>Any,Version=5.0</TargetRuntimeMoniker>
    <TargetRuntimeIdentifier>Any</TargetRuntimeIdentifier>
    <TargetRuntimeVersion>5.0</TargetRuntimeVersion>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetRuntime)' == 'any-x64'">
    <TargetPlatformMoniker>Any,Version=0.0</TargetPlatformMoniker>
    <TargetPlatformIdentifier>Any</TargetPlatformIdentifier>
    <TargetPlatformVersion>0.0</TargetPlatformVersion>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetRuntime)' == 'any-arm'">
    <TargetPlatform>any</TargetPlatform>
    <TargetMachine>arm</TargetMachine>
  </PropertyGroup>

</Project>

@Redth
Copy link
Member

Redth commented Feb 19, 2020

@NickCraver to add a bit more detail on the minimum supported iOS/Android versions:

Xamarin.iOS today already ships an API which targets the newest iOS version we support targeting (so iOS 13). We add attributes on these API's to expose what iOS version they were actually added in and there is some analyzer support to highlight API calls the user might want to consider guarding against at runtime.

Xamarin.Android has similar attributes as well but has traditionally shipped multiple API's for the different API levels we support which provided compile time safety around API call guarding. In net5.0-android this will move to the same model as iOS uses and we will only ship API's for the latest Android API level we support.

Apps built targeting the latest versions can still run on older iOS/Android versions, but the developer must guard the usage of API's which aren't supported at runtime on these older OS versions.

There will of course be a minimum iOS and Android version which is supported at runtime as well. I'm not sure we've settled on either of those yet, but somewhere around iOS 8.0 and Android 4.1 or 4.4 is where we are likely to land.

@svick
Copy link

svick commented Feb 19, 2020

I'm confused about the relationship between the new OS-specific TFMs and console/server applications:

  • Do I understand it correctly that there won't be net5.0-linux? Why not? Varying implementation based on OS certainly happens in these kinds of apps too and varying API might be useful too.

    Or are you saying that different techniques should be used for varying implementation for consose/server apps than for GUI/Xamarin apps?

  • Will I be able to use a net5.0-win or net5.0-macos library from a console app running on Windows or MacOS? Or are those TFMs just for Winforms/WPF/WinUI and Xamarin apps?

accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
@bitbonk
Copy link

bitbonk commented Feb 22, 2020

I have the same question as @svick here.

Why is there no net5.0-linux?

@AustinWise
Copy link
Contributor

I had the same question as @bitbonk and @svick with regards to net5.0-linux. My understanding of why there is no net5.0-linux is that these platform dependent TFM are used to light up a large platform-specific set of .NET APIs. There is prior art in WinForms/WPF (mapped to net5.0-win) and Xamarin (mapped to net5.0-ios and net5.0-android). There is no .NET projection of Linux APIs, so there is no TFM.

My understanding is that this means if you want to target Linux API specifically, you either need to use the RID system or runtime detection.

Something sort of off topic: I would like a .NET Compact Framework TFM so I could multi-target my build using SDK-style projects. Failing that, some build-tool extensibility for defining my own TFM would be nice. (This might already exist, I have not checked).

@gulbanana
Copy link

Sounds like the only feasible TFM for ASP.NET Core under this systematisation is net5.0?

accepted/2020/net5/net5.md Outdated Show resolved Hide resolved
Copy link

@Nirmal4G Nirmal4G left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments on versioning of platform bindings and preprocessor defines.

accepted/2020/net5/net5.md Show resolved Hide resolved
accepted/2020/net5/net5.md Show resolved Hide resolved
@@ -281,6 +281,9 @@ We'll have the following TFMs:

_**Open Issue**. Will the above scheme work for iPad?_

_**Open Issue**. Can we use a syntax that differentiates revving the bindings
from the OS?, such as `net5.0-ios13.0-r1` or `net5.0-ios13.0A`?_

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't... 🤯

Instead, we can do like what the UWP guys do, revise and version the binding packages and ask the devs to explicitly add Framework/Package reference to the new revision. When the SDK is revised we can update the implicit references to the newer version. This is easier and predictable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're still debating this. We don't want to play tricks by forcing people to add packages -- the point of this feature is to expose the OS APIs by changing the TFM alone. This ensures that that the OS bindings are also compatible with the .NET platform API surface, which we learned we can't do well when shipping these kind of sets via packages.

@Nirmal4G
Copy link

Nirmal4G commented Mar 13, 2020

Note regarding API Bloat

It seems that new .NET is locked on the fact that Every API ever and will be developed should be available in newer .NET, which is very bad. Overtime we would have a bloat in BCL and in our libraries. I don't want that, nor any of us!

If we have a new language features or API that could effectively obsolete older APIs then those should be moved to System.Compatibility or Microsoft.NET.Compatibility similar to jQuery Migrate. To enable this kind of workflow, we would need better Extensions support in both the language and the runtime.

@marek-safar
Copy link
Contributor

/cc @joshpeterson

Co-Authored-By: Drew Noakes <[email protected]>
@Perksey
Copy link
Member

Perksey commented Mar 13, 2020

I agree with @Nirmal4G, similar to OpenGL a .NET Core Profile and Compatibility Profile wouldn't be a bad idea (hang on, .NET Core Profile rings a bell)

But yeah going forward I don't think the .NET team should object to move certain APIs out of the core framework and into a compatibility package because otherwise, as Nirmal said, the API will get very bloated!

@terrajobst
Copy link
Member Author

terrajobst commented Mar 13, 2020

@Nirmal4G @Perksey

If we have a new language features or API that could effectively obsolete older APIs then those should be moved to System.Compatibility or Microsoft.NET.Compatibility similar to jQuery Migrate. To enable this kind of workflow, we would need better Extensions support in both the language and the runtime.

We're not interested in allowing for .NET implementations with fewer APIs than what was in .NET Standard 2.1 because it breaks the entire library ecosystem (and moving APIs without making it a binary breaking change is either very hard or impossible for most BCL APIs). We have a viable plan for obsoleting more APIs in the future. Also, I consider this out of scope for this feature here.

@Perksey
Copy link
Member

Perksey commented Mar 13, 2020

Got it, and apologies for going off-topic here.

@Nirmal4G
Copy link

We have a viable plan for obsoleting more APIs in the future.

IMHO That's not a viable plan, that's not even a plan... OK... more like 12% of a plan!!! 😅😇

Still, I liked the Idea of an Compatibility package with all of the obsolete APIs. If there's an additive change in the runtime to allow that without breaking older libraries (more like a compat switch), I'm all for that!

@Perksey
Copy link
Member

Perksey commented Mar 14, 2020

@Nirmal4G I think that's best suited for discussion in another proposal.

@Nirmal4G
Copy link

Nirmal4G commented Mar 14, 2020

@Perksey True, but when I saw the proposal and the word 'plan', I couldn't hold it in! 😉

@terrajobst Can we open a new issue in this repo for community proposals or is it restricted to .NET org members only?

You can mark these conversations as Off-Topic, will help reduce some clutter...

1. Validated that the scheme will work for iPad
2. Decided that the duplication is an implementation that MSBuild/SDK will
   figure out.
@terrajobst
Copy link
Member Author

Alright, I think we have enough terrain covered to consider this accepted. I'll be merging this and refine in separate PRs if necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.