Skip to content

$(DefineConstants) is based off of $(TargetFramework) and may be inconsistent with actual referenced assemblies #24043

@jonpryor

Description

@jonpryor

Apple platform

iOS

Framework version

net9.0-*

Affected platform version

.NET 10

Description

The set of #defines present within $(DefineConstants) is consistent with $(TargetFramework), and may be inconsistent with the actual assembly used to build the project.

Steps to Reproduce

Context: dfb9a22

Commit dfb9a22 updated WKUIDelegate.RunJavaScriptTextInputPanel() to be obsolete. However, this obsoletion was only visible on iOS 26.0 assemblies, not on iOS 18.0 assemblies; in iOS 18.0, this method is not obsolete.

When building an "unversioned" target framework, the latest reference assembly is used, which may differ from what was actually intended.

Create a new ioslib project:

dotnet new ioslib -n myioslib

Update $(TargetFramework)=net9.0-ios18.0 ("fixed"):

diff --git a/myioslib.csproj b/myioslib.csproj
index c62adc2..0853df5 100644
--- a/myioslib.csproj
+++ b/myioslib.csproj
@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>net10.0-ios</TargetFramework>
+    <TargetFramework>net9.0-ios18.0</TargetFramework>
     <Nullable>enable</Nullable>
     <ImplicitUsings>true</ImplicitUsings>

Add the following MyWKUIDelegate type to the project:

diff --git a/Class1.cs b/Class1.cs
index 648114f..5f8dbae 100644
--- a/Class1.cs
+++ b/Class1.cs
@@ -1,4 +1,14 @@
+using WebKit;
+
 namespace myioslib;
 
-public class Class1 {
+public class Class1
+{
+}
+
+class MyWKUIDelegate : WKUIDelegate
+{
+    public override void RunJavaScriptTextInputPanel(WKWebView webView, string prompt, string? defaultText, WKFrameInfo frame, Action<string> completionHandler)
+    {
+    }
 }

Build the project:

% dotnet build -bl

No warnings are generated.

Update $(TargetFramework)=net9.0-ios ("floating"):

diff --git a/myioslib.csproj b/myioslib.csproj
index c62adc2..1e1a6ca 100644
--- a/myioslib.csproj
+++ b/myioslib.csproj
@@ -1,6 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
-    <TargetFramework>net10.0-ios</TargetFramework>
+    <TargetFramework>net9.0-ios</TargetFramework>
     <Nullable>enable</Nullable>
     <ImplicitUsings>true</ImplicitUsings>

Build the project:

% dotnet build -bl
Restore complete (0.7s)
    info NETSDK1057: You are using a preview version of .NET. See: https://aka.ms/dotnet-support-policy
  myioslib net9.0-ios succeeded with 1 warning(s) (1.5s) → bin/Debug/net9.0-ios/myioslib.dll
    …/myioslib/Class1.cs(11,26): warning CS0672: Member 'MyWKUIDelegate.RunJavaScriptTextInputPanel(WKWebView, string, string?, WKFrameInfo, Action<string>)' overrides obsolete member 'WKUIDelegate.RunJavaScriptTextInputPanel(WKWebView, string, string?, WKFrameInfo, Action<string>)'. Add the Obsolete attribute to 'MyWKUIDelegate.RunJavaScriptTextInputPanel(WKWebView, string, string?, WKFrameInfo, Action<string>)'.

Build succeeded with 1 warning(s) in 2.5s

Supposedly, net9.0-ios should be an alias for net9.0-ios18.0, but it isn't: net9.0-ios18.0 builds with no warnings, while net9.0-ios emits a warning!

Why?

If you look at the Diagnostic output from the builds, and look at the Task "Csc" section for Task Parameter: References=, the net9.0-ios18.0 build has:

$HOME/.nuget/packages/microsoft.ios.ref.net9.0_18.0/18.0.9617/ref/net9.0/Microsoft.iOS.dll
        AssemblyName=Microsoft.iOS
        AssemblyVersion=18.0.0.0
        CopyLocal=false
        ExternallyResolved=true
        FileVersion=0.0.0.0
        FrameworkReferenceName=Microsoft.iOS
        FrameworkReferenceVersion=18.0.9617
        FusionName=Microsoft.iOS, Version=18.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065
        NuGetPackageId=Microsoft.iOS.Ref.net9.0_18.0
        NuGetPackageVersion=18.0.9617
        OriginalItemSpec=$HOME/.nuget/packages/microsoft.ios.ref.net9.0_18.0/18.0.9617/ref/net9.0/Microsoft.iOS.dll
        Private=false
        PublicKeyToken=84e04ff9cfb79065
        ReferenceAssembly=$HOME/.nuget/packages/microsoft.ios.ref.net9.0_18.0/18.0.9617/ref/net9.0/Microsoft.iOS.dll
        ReferenceSourceTarget=ResolveAssemblyReference
        ResolvedFrom={RawFileName}
        Version=

While the net9.0-ios (floating) build has:

$HOME/.nuget/packages/microsoft.ios.ref.net9.0_26.0/26.0.9752/ref/net9.0/Microsoft.iOS.dll
        AssemblyName=Microsoft.iOS
        AssemblyVersion=26.0.0.0
        CopyLocal=false
        ExternallyResolved=true
        FileVersion=0.0.0.0
        FrameworkReferenceName=Microsoft.iOS
        FrameworkReferenceVersion=26.0.9752
        FusionName=Microsoft.iOS, Version=26.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065
        NuGetPackageId=Microsoft.iOS.Ref.net9.0_26.0
        NuGetPackageVersion=26.0.9752
        OriginalItemSpec=$HOME/.nuget/packages/microsoft.ios.ref.net9.0_26.0/26.0.9752/ref/net9.0/Microsoft.iOS.dll
        Private=false
        PublicKeyToken=84e04ff9cfb79065
        ReferenceAssembly=$HOME/.nuget/packages/microsoft.ios.ref.net9.0_26.0/26.0.9752/ref/net9.0/Microsoft.iOS.dll
        ReferenceSourceTarget=ResolveAssemblyReference
        ResolvedFrom={RawFileName}
        Version=

In particular, note that %(AssemblyVersion) differs: net9.0-ios18.0 has %(AssemblyVersion)=18.0.0.0, while net9.0-ios has %(AssemblyVersion)=26.0.0.0.

Even though net9.0-ios is supposed to be an alias for net9.0-ios18.0 for library projects, it is using the latest assembly!

Furthermore, $(DefineConstants) for both builds is the same!

Task Parameter:DefineConstants=IOS;MOBILE;UNIFIED;TRACE;DEBUG;NET;NET9_0;NETCOREAPP;IOS;IOS18_0;NET5_0_OR_GREATER;NET6_0_OR_GREATER;NET7_0_OR_GREATER;NET8_0_OR_GREATER;NET9_0_OR_GREATER;NETCOREAPP1_0_OR_GREATER;NETCOREAPP1_1_OR_GREATER;NETCOREAPP2_0_OR_GREATER;NETCOREAPP2_1_OR_GREATER;NETCOREAPP2_2_OR_GREATER;NETCOREAPP3_0_OR_GREATER;NETCOREAPP3_1_OR_GREATER;IOS10_0_OR_GREATER;IOS10_1_OR_GREATER;IOS10_2_OR_GREATER;IOS11_0_OR_GREATER;IOS11_1_OR_GREATER;IOS11_2_OR_GREATER;IOS11_3_OR_GREATER;IOS11_4_OR_GREATER;IOS12_0_OR_GREATER;IOS12_1_OR_GREATER;IOS12_2_OR_GREATER;IOS12_3_OR_GREATER;IOS12_4_OR_GREATER;IOS13_0_OR_GREATER;IOS13_1_OR_GREATER;IOS13_2_OR_GREATER;IOS13_3_OR_GREATER;IOS13_4_OR_GREATER;IOS13_5_OR_GREATER;IOS13_6_OR_GREATER;IOS14_0_OR_GREATER;IOS14_1_OR_GREATER;IOS14_2_OR_GREATER;IOS14_3_OR_GREATER;IOS14_4_OR_GREATER;IOS14_5_OR_GREATER;IOS15_0_OR_GREATER;IOS15_2_OR_GREATER;IOS15_4_OR_GREATER;IOS16_0_OR_GREATER;IOS16_1_OR_GREATER;IOS16_2_OR_GREATER;IOS16_4_OR_GREATER;IOS17_0_OR_GREATER;IOS17_2_OR_GREATER;IOS17_4_OR_GREATER;IOS17_5_OR_GREATER;IOS18_0_OR_GREATER

There is thus no way within C# source code to know which assembly you're building against. This is problematic if you have $(TreatWarningsAsErrors)=true, in which case the warning becomes an error.

Did you find any workaround?

Don't use floating versions. Always use an explicit version.

Build logs

No response

Metadata

Metadata

Assignees

Labels

bugIf an issue is a bug or a pull request a bug fix

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions