This is because `EnablePreviewFeatures=true` doesn't quite work, since it
requires the building .NET and the target .NET to be on the same version.
We might want to build with .NET 9, but the Xcode branch is targeting .NET 8,
so it doesn't work.
This behavior is explained here:
https://github.com/dotnet/designs/blob/main/accepted/2021/preview-features/preview-features.md#meaning-of-property-in-multi-targeted-projects
The best solution seems to switch to using the Experimental attribute instead,
which was designed for our scenario (and explicitly to fix the problem we're
running into): bba3216250/accepted/2023/preview-apis/preview-apis.md
This also meant we had to augment `-nowarn` for bgen to:
* Pass any nowarn values to the compiler when bgen compiles stuff.
* Pass `$(NoWarn)` (the MSBuild property) to bgen when building a binding project.
---------
Co-authored-by: Alex Soto <alex@soto.dev>
Add multi-targeting support for our initial .NET 8 packs (for Xcode
15.0).
This means a library/binding project can do:
```xml
<TargetFrameworks>net8.0-ios17.0;net8.0-ios17.2</TargetFrameworks>
```
and the library will be built in two varieties: once using our iOS 17.0
bindings, and once using our iOS 17.2 bindings.
An app project can also do:
```xml
<TargetFramework>net8.0-ios17.0</TargetFramework>
```
to build with the iOS 17.0 bindings (which is typically not very useful,
since building with the latest iOS SDK is usually best).
We've used to ignore the target platform version (the "17.0" part in "net8.0-ios17.0")
since our initial .NET relaese - customers could specify any valid OS version between
the minimum and maximum versions, and we'd completely ignore the value [1].
The purpose of the target platform version is to specify which bindings to choose:
"net8.0-ios17.0" would mean that the developer wants packages that have bindings
for iOS 17.0 (and earlier iOS versions, but not later iOS versions).
So saying "net8.0-ios11.0" would technically mean that the developer would want our
bindings for iOS 11.0 (and earlier iOS versions, but not later iOS versions). The
problem is that we don't ship any such thing... we shipped iOS 17.0 bindings in .NET
8, and that's it, you can't choose to build with something that does *not* have bindings
for iOS 17.0.
This will change with multi-targeting: we'll support *some* matrix of bindings. For
instance, we might want to support the OS version we shipped initial support in any
given .NET release + the latest OS version.
For example, we might want to support both of these:
* net8.0-ios17.0
* net8.0-ios17.2
This means that the target platform version (17.0/17.2) can't keep staying ignored.
There was an somewhat related issue with the `SdkSupportedTargetPlatformVersion`,
where we're now able to distinguish between old versions we no longer support and
new versions that limits the valid values for TargetPlatformVersion (see 74d83ca7e3).
We've already taken advantage of this to properly annotate every version, even in
.NET 8 (in a future service update), because the dotnet/sdk change required to understand
the new annotations (and ignore old versions in the `SdkSupportedTargetPlatformVersion`
item group) won't be shipped until .NET 9, so this won't be a breaking change in
.NET 8.
However, we'd still like to give customers a heads up that their project files need
to change, so this PR adds a warning (that tells developers what to do), and then
in .NET 9 we'll make the warning an error instead. Side note: Android is also making
an invalid target platform version an error in .NET 9: https://github.com/xamarin/xamarin-android/pull/8569.
[1]: We'd ignore the value for executable projects. It did have an effect for library
projects that were packed into NuGets: the target platform version would be stored
in the NuGet.
This is a manual and squashed backport of
https://github.com/xamarin/xamarin-macios/pull/19717 and it was updated
to use Xcode 15.2 since Xcode 15.2 contains the same SDKs as Xcode 15.1
but Xcode 15.2 has visionOS SDK and it is the new stable release from
Apple.
---------
Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com>
In theory we should define the default platform version if it's not specified
in the TFM, and this default should not change for a given .NET version:
* We release support for iOS 17.0 with .NET 8
* Apple releases iOS 18.0, we're still using .NET 8. This default continues to be iOS 17.0
* .NET 9 is shipped, and at this point we bump the default to iOS 18.0
Basically: this should be the last OS version of the platform in question when
the current major .NET version is first released to stable.
Ref: 8e6394406d/accepted/2020/net5/net5.md (os-versions)
However, this doesn't work well for Apple platforms: whenever Apple releases
new Xcode versions, our existing workloads might not be compatible with the
new Xcode. We'll of course ship updateds workload with support for the new
Xcode, but defaulting to an older target platform version would mean that
developers wouldn't get the new workload, they'd get the old one. This is
exacerbated by the fact that Apple aggressively auto-updates Xcode on
developers' machines: they might wake up one day to a broken build - the
obvious fix ("dotnet workload update") doesn't fix anything - even if we've
shipped updated workloads - because the default is to use the old one. They'd
have to manually specify the target platform version in the target platform to
get the updated workload ("net8.0-ios17.2" to use the iOS 17.2 workload
instead of "net8.0-ios", which would use the default (old/initial/17.0) .NET 8
workload) - and then update _again_ when the next Xcode comes around. At this
point the point of having a sane default value is totally out the window,
because everybody would have to specify (and continuously update) a platform
version in their project files to keep their projects building.
So we've made the decision that the default target platform version is always
the latest target platform version.
Context: https://dotnet.microsoft.com/platform/support/policy/maui
> A major version of .NET MAUI receives support for a minimum of 6
> months after a successor (the next major release) ships. For
> example, .NET MAUI 6.0 will be supported for 6 months after .NET
> MAUI 7.0 ships. Similarly, .NET MAUI 7.0 will receive support for 6
> months after .NET MAUI 8.0 ships.
By the time .NET 8 GA ships, .NET 6 MAUI projects will not be supported.
Remove .NET 6 support from our .NET 8 workloads.
We need the latest released version numbers for the previous .NET version so
that we can reference and consume those when building projects using the
corresponding target framework.
Luckily we have a system for keeping dependencies up-to-date, so let's use it
to notify the current branch for any updates to the release branch for the
previous .NET version.
Then I had to bump the Xamarin.iOS version too, so that we have the same commit distance for both, otherwise this happens:
```
*** The commit distance for Xamarin.iOS (111) and Xamarin.Mac (0) are different.
*** To fix this problem, bump the revision (the third number) for both IOS_PACKAGE_NUMBER and MAC_PACKAGE_NUMBER in Make.versions.
*** Once fixed, you need to commit the changes for them to pass this check.
```
The KnownFrameworkReference now references the exact versions of the ref and runtime
packs we're shipping with the sdk pack, instead of telling the build to use whatever
version is defined in the workload.
Then in the workload we specify the latest released version of the .NET 6 for the
ref and runtime packs.
Finally we add an aliased sdk pack, which points to the .NET 6 sdk pack, and
when we're building a .NET 6 TargetFramework we load this aliased sdk pack
instead of the one we're shipping with this workload.
Putting this together means that:
* When we're building a .NET 7 TargetFramework, we load the sdk pack shipped
with the workload, which adds a KnownFrameworkReference which references the
ref and runtime packs with the same version as the sdk pack.
* When we're building a .NET 6 TargetFramework, we load the (aliased) sdk pack
which points to the latest stable .NET 6 sdk pack. That sdk pack will add a
KnownFrameworkReference that tells the build to use the ref and runtime pack
versions specified in the workload - which are now pointing to the .NET 6
ref and runtime pack versions.
Thus we use the .NET 6 sdk, ref and runtime packs when building a .NET 6
TargetFramework, and we use the .NET 7 sdk, ref and runtime packs when
building a .NET 7 TargetFramework.
According to the workload design spec [1], this is supposed to be implemented
by using aliased ref and runtime packs, but that doesn't work due to
https://github.com/dotnet/sdk/issues/26384.
Fixes https://github.com/xamarin/xamarin-macios/issues/15375.
[1]: https://github.com/dotnet/designs/blob/main/accepted/2020/workloads/workload-manifest.md?rgh-link-date=2022-06-30T08%3A25%3A10Z#side-by-side-workload-pattern
Adjust our versioning scheme so that the NuGet version is
`Major.Minor.CommitDistance`. The previous scheme ("Major.Minor.<fixed-ish
version>") causes problems on branches producing stable builds, because each
new commit would end up with the same NuGet version, and we wouldn't be able
to push those to a NuGet feed because there might already be an existing
version there.
By using the commit distance in the NuGet version we ensure that every commit
has a different version.
This is a follow up to 92ee92eeb5, where we
changed the assembly version from four digits to three digits (i.e not include
the build number), because our managed API should be identical for (released)
versions where only the build number changes.
In this PR we go a bit further, because we're not supposed to have any API
differences unless the first two parts of the product version changes, which
means that we should only use need the two first parts of our product version
as the assembly version.