diff --git a/.github/workflows/inter-branch-merge-flow.yml b/.github/workflows/inter-branch-merge-flow.yml
index 484253fef436..0037388e989d 100644
--- a/.github/workflows/inter-branch-merge-flow.yml
+++ b/.github/workflows/inter-branch-merge-flow.yml
@@ -30,4 +30,4 @@ permissions:
jobs:
Merge:
- uses: dotnet/arcade/.github/workflows/inter-branch-merge-base.yml@0a80b038bcc0d76b2f26c7f22062942de75779e6 # main
+ uses: dotnet/arcade/.github/workflows/inter-branch-merge-base.yml@5f63985fe82894604956e653d43c161ebbc1b576 # main
diff --git a/Directory.Build.props b/Directory.Build.props
index a5be85f32d94..f62f202265bc 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,7 +2,7 @@
true
- 2.2.158
+ 2.2.243
17.13.26
$(MicrosoftBuildPackageVersion)
$(MicrosoftBuildPackageVersion)
diff --git a/dotnet/Workloads/SignList.xml b/dotnet/Workloads/SignList.xml
index be9c22938d51..f6c08f7595b1 100644
--- a/dotnet/Workloads/SignList.xml
+++ b/dotnet/Workloads/SignList.xml
@@ -79,6 +79,9 @@
+
+
+
diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index dc2c514d4bad..d4f71cca0299 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -271,6 +271,7 @@
_ResolveAppExtensionReferences;
_ExtendAppExtensionReferences;
_ComputeLinkerArguments;
+ _PrepareAssemblies;
_ComputeFrameworkFilesToPublish;
_ComputeDynamicLibrariesToPublish;
ComputeFilesToPublish;
@@ -618,6 +619,9 @@
true
$(_TypeMapAssemblyName)
+
+ <_ExtraTrimmerArgs Condition="'$(Registrar)' == 'trimmable-static' And $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '11.0'))">$(_ExtraTrimmerArgs) --typemap-entry-assembly "$(_TypeMapAssemblyName)"
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.CollectAssembliesStep" />
+
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.CoreTypeMapStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.ProcessExportedFields" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.PreserveProtocolsStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForProtocolPreservation)' == 'true'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForSmartEnumPreservation)' == 'true'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.PreserveBlockCodeStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForBlockCodePreservation)' == 'true'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.OptimizeGeneratedCodeStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForGeneratedCodeOptimizations)' == 'true'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.ApplyPreserveAttributeStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseLinkDescriptionForApplyPreserveAttribute)' == 'true'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.MarkForStaticRegistrarStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForMarkStaticRegistrar)' == 'true'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.MarkNSObjectsStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForMarkNSObjects)' == 'true'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.InlineDlfcnMethodsStep" Condition="'$(InlineDlfcnMethods)' != ''" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.PreserveProtocolsStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForProtocolPreservation)' == 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForSmartEnumPreservation)' == 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.PreserveBlockCodeStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForBlockCodePreservation)' == 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.OptimizeGeneratedCodeStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForGeneratedCodeOptimizations)' == 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.ApplyPreserveAttributeStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseLinkDescriptionForApplyPreserveAttribute)' == 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.MarkForStaticRegistrarStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForMarkStaticRegistrar)' == 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.MarkNSObjectsStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForMarkNSObjects)' == 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.InlineDlfcnMethodsStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(InlineDlfcnMethods)' != ''" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" Condition="'$(PrepareAssemblies)' != 'true'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(Registrar)' == 'managed-static' Or '$(Registrar)' == 'trimmable-static'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.TrimmableRegistrarStep" Condition="'$(Registrar)' == 'trimmable-static'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.InlineClassGetHandleStep" Condition="'$(InlineClassGetHandle)' != '' And '$(InlineClassGetHandle)' != 'disabled'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.PreMarkDispatcher" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(PrepareAssemblies)' != 'true' And ('$(Registrar)' == 'managed-static' Or '$(Registrar)' == 'trimmable-static')" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.TrimmableRegistrarStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(Registrar)' == 'trimmable-static'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.InlineClassGetHandleStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(InlineClassGetHandle)' != '' And '$(InlineClassGetHandle)' != 'disabled'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForBlockCodePreservation)' != 'true'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForGeneratedCodeOptimizations)' != 'true'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.BackingFieldDelayHandler" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForProtocolPreservation)' != 'true'" Type="Xamarin.Linker.MarkIProtocolHandler" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForBlockCodePreservation)' != 'true'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForGeneratedCodeOptimizations)' != 'true'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.BackingFieldDelayHandler" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForProtocolPreservation)' != 'true'" Type="Xamarin.Linker.MarkIProtocolHandler" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForMarkDispatcher)' != 'true'" Type="Xamarin.Linker.Steps.MarkDispatcher" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForSmartEnumPreservation)' != 'true'" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsHandler" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForMarkDispatcher)' != 'true'" Type="Xamarin.Linker.Steps.MarkDispatcher" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForSmartEnumPreservation)' != 'true'" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsHandler" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="SweepStep" Type="Xamarin.Linker.ManagedRegistrarLookupTablesStep" Condition="'$(Registrar)' == 'managed-static'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="SweepStep" Type="Xamarin.Linker.ManagedRegistrarLookupTablesStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(Registrar)' == 'managed-static'" />
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="SweepStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PostSweepDispatcher" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="SweepStep" Condition="'$(PrepareAssemblies)' != 'true' And '$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PostSweepDispatcher" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.ManagedRegistrarStep" Condition="'$(PrepareAssemblies)' == 'true' And ('$(Registrar)' == 'managed-static' Or '$(Registrar)' == 'trimmable-static')" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.TrimmableRegistrarStep" Condition="'$(PrepareAssemblies)' == 'true' And '$(Registrar)' == 'trimmable-static'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.ManagedRegistrarLookupTablesStep" Condition="'$(PrepareAssemblies)' == 'true' And '$(Registrar)' == 'managed-static'" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.RegistrarStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.GenerateMainStep" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.GenerateReferencesStep" />
@@ -1380,6 +1393,9 @@
<_TypeMapFilePath Condition="'$(_TypeMapFilePath)' == ''">$(_LinkerCacheDirectory)/type-map.txt
+
+
+ <_UnmanagedCallersOnlyMapPath Condition="'$(_UnmanagedCallersOnlyMapPath)' == ''">$(_LinkerCacheDirectory)/unmanaged_callers_only_map.txt
@@ -1453,16 +1469,28 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ <_IntermediateAssemblyProperty>@(IntermediateAssembly)
+ <_PreparedIntermediateAssemblyProperty>@(PreparedIntermediateAssembly->WithMetadataValue('BeforePrepareAssembliesPath','$(_IntermediateAssemblyProperty)'))
+
+
+ <_PreparedRootedIntermediateAssembly Include="@(TrimmerRootAssembly->'$(_PreparedIntermediateAssemblyProperty)')" Condition="'%(Identity)' == '$(_IntermediateAssemblyProperty)'" />
+
+
+
26.0.11017
26.5.10291
- 11.0.0-prerelease.26264.1
+ 11.0.0-prerelease.26316.1
diff --git a/macios/Localize/loc/ja/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/ja/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
index 429efcd0d6a5..faf7c0361889 100644
--- a/macios/Localize/loc/ja/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
+++ b/macios/Localize/loc/ja/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
@@ -2734,6 +2734,24 @@
+ -
+
+ Components).]]>
+
+ コンポーネント) からインストールしてください。]]>
+
+
+
+
+ -
+
+ Components).]]>
+
+ コンポーネント) から更新してください。]]>
+
+
+
+
-
@@ -3661,6 +3679,15 @@
+ -
+
+
+
+
+
+
+
+
-
diff --git a/macios/Localize/loc/ru/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/ru/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
index ff190b437318..c8408a7c4bd2 100644
--- a/macios/Localize/loc/ru/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
+++ b/macios/Localize/loc/ru/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
@@ -2734,6 +2734,24 @@
+ -
+
+ Components).]]>
+
+ Компоненты).]]>
+
+
+
+
+ -
+
+ Components).]]>
+
+ Компоненты).]]>
+
+
+
+
-
@@ -3661,6 +3679,15 @@
+ -
+
+
+
+
+
+
+
+
-
diff --git a/macios/Localize/loc/tr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/tr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
index 3251464cd07f..9e41267b38b6 100644
--- a/macios/Localize/loc/tr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
+++ b/macios/Localize/loc/tr/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
@@ -2734,6 +2734,24 @@
+ -
+
+ Components).]]>
+
+ Bileşenleri).]]>
+
+
+
+
+ -
+
+ Components).]]>
+
+ Bileşenler) simülatör çalışma zamanını güncelleştirin.]]>
+
+
+
+
-
@@ -3661,6 +3679,15 @@
+ -
+
+
+
+
+
+
+
+
-
diff --git a/macios/Localize/loc/zh-Hans/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl b/macios/Localize/loc/zh-Hans/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
index 2e41c4b28761..40bd2cca9335 100644
--- a/macios/Localize/loc/zh-Hans/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
+++ b/macios/Localize/loc/zh-Hans/macios/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx.lcl
@@ -2734,6 +2734,24 @@
+ -
+
+ Components).]]>
+
+ “组件”)运行 ‘xcodebuild -downloadPlatform {0}’ 来安装它。]]>
+
+
+
+
+ -
+
+ Components).]]>
+
+ “组件”)运行 ‘xcodebuild -downloadPlatform {0}’ 来更新模拟器运行时。]]>
+
+
+
+
-
@@ -3661,6 +3679,15 @@
+ -
+
+
+
+
+
+
+
+
-
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.cs.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.de.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.es.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.fr.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.it.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ja.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ko.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pl.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.pt-BR.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.ru.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.tr.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hans.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx
index 9f4afd35224d..a677d7033efe 100644
--- a/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx
+++ b/macios/msbuild/Xamarin.Localization.MSBuild/TranslatedAssemblies/MSBStrings.zh-Hant.resx
@@ -1311,4 +1311,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
\ No newline at end of file
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.cs.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.cs.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.cs.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.cs.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.de.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.de.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.de.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.de.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.es.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.es.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.es.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.es.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.fr.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.fr.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.fr.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.fr.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.it.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.it.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.it.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.it.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.ja.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.ja.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.ja.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.ja.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.ko.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.ko.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.ko.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.ko.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.pl.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.pl.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.pl.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.pl.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.pt-BR.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.pt-BR.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.pt-BR.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.pt-BR.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.ru.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.ru.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.ru.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.ru.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.tr.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.tr.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.tr.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.tr.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hans.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hans.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hans.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hans.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hant.resx b/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hant.resx
index ce4b85b8b369..d75c16fc25af 100644
--- a/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hant.resx
+++ b/macios/tools/mtouch/TranslatedAssemblies/Errors.zh-Hant.resx
@@ -643,6 +643,9 @@
One or more reference(s) to type '{0}' still exists inside '{1}' after linking
+
+ Cannot find the product assembly '{0}' in the list of loaded assemblies.
+
Not a Mach-O dynamic library (unknown header '0x{0}'): {1}.
diff --git a/msbuild/.vscode/tasks.json b/msbuild/.vscode/tasks.json
new file mode 100644
index 000000000000..45465f774797
--- /dev/null
+++ b/msbuild/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "shell",
+ "command": "make",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": [
+ "$msCompile"
+ ],
+ "label": "make"
+ }
+ ]
+}
diff --git a/msbuild/ILMerge.targets b/msbuild/ILMerge.targets
index d8c87c68fccf..cb30898bcba4 100644
--- a/msbuild/ILMerge.targets
+++ b/msbuild/ILMerge.targets
@@ -18,6 +18,7 @@
+
diff --git a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx
index 9d5467135372..99b833b57d43 100644
--- a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx
+++ b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx
@@ -1673,4 +1673,9 @@
Shown when the tool reports a simulator runtime version mismatch.
{0} - The platform name (e.g. "iOS" or "tvOS").
+
+ Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0}
+ Shown when an MSBuild task writes to the console instead of using MSBuild logging.
+{0} - The stack trace of the offending call.
+
diff --git a/msbuild/Xamarin.MacDev.Tasks.slnx b/msbuild/Xamarin.MacDev.Tasks.slnx
index e3c799a54619..1f17eb9aa95f 100644
--- a/msbuild/Xamarin.MacDev.Tasks.slnx
+++ b/msbuild/Xamarin.MacDev.Tasks.slnx
@@ -36,4 +36,8 @@
+
+
+
+
diff --git a/msbuild/Xamarin.MacDev.Tasks/ConsoleToTaskWriter.cs b/msbuild/Xamarin.MacDev.Tasks/ConsoleToTaskWriter.cs
new file mode 100644
index 000000000000..1e97dc541697
--- /dev/null
+++ b/msbuild/Xamarin.MacDev.Tasks/ConsoleToTaskWriter.cs
@@ -0,0 +1,103 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Text;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+#nullable enable
+
+namespace Xamarin.Utils;
+
+class ConsoleToTaskWriter : TextWriter {
+ TaskLoggingHelper helper;
+ bool errorShown;
+
+ public ConsoleToTaskWriter (TaskLoggingHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ public override Encoding Encoding => Encoding.UTF8;
+
+ public override void Write (char value)
+ {
+ ShowError ();
+ helper.LogMessage (MessageImportance.Low, value.ToString ());
+ }
+
+ public override void Write (char [] buffer, int index, int count)
+ {
+ ShowError ();
+ helper.LogMessage (MessageImportance.Low, new string (buffer, index, count));
+ }
+
+ public override void Write (string? value)
+ {
+ ShowError ();
+ helper.LogMessage (MessageImportance.Low, value ?? string.Empty);
+ }
+
+ public override void WriteLine ()
+ {
+ ShowError ();
+ }
+
+ public override void WriteLine (string? value)
+ {
+ ShowError ();
+ helper.LogMessage (MessageImportance.Low, value ?? string.Empty);
+ }
+
+ void ShowError ()
+ {
+ if (errorShown)
+ return;
+ errorShown = true;
+
+ helper.LogError (null, "MT7178" /* Console.StandardOutput or Console.StandardError was accessed during a build task. This should not happen, use the MSBuild logging infrastructure instead. Stack trace: {0} */, null, null, 0, 0, 0, 0, Xamarin.Localization.MSBuild.MSBStrings.E7178, Environment.StackTrace);
+ }
+
+ public static IDisposable EnsureNoConsoleUsage (TaskLoggingHelper log)
+ {
+ return new NoConsoleUsage (new ConsoleToTaskWriter (log));
+ }
+
+ class NoConsoleUsage : IDisposable {
+ TextWriter? originalStdout;
+ TextWriter? originalStderr;
+
+ public NoConsoleUsage (ConsoleToTaskWriter redirector)
+ {
+ originalStdout = Console.Out;
+ originalStderr = Console.Error;
+ Console.SetOut (redirector);
+ Console.SetError (redirector);
+ }
+
+ ~NoConsoleUsage ()
+ {
+ Restore ();
+ }
+
+ void IDisposable.Dispose ()
+ {
+ Restore ();
+ GC.SuppressFinalize (this);
+ }
+
+ void Restore ()
+ {
+ if (originalStdout is not null) {
+ Console.SetOut (originalStdout);
+ originalStdout = null;
+ }
+ if (originalStderr is not null) {
+ Console.SetError (originalStderr);
+ originalStderr = null;
+ }
+ }
+ }
+}
diff --git a/msbuild/Xamarin.MacDev.Tasks/ErrorHelper.msbuild.cs b/msbuild/Xamarin.MacDev.Tasks/ErrorHelper.msbuild.cs
deleted file mode 100644
index 8bda5c48e690..000000000000
--- a/msbuild/Xamarin.MacDev.Tasks/ErrorHelper.msbuild.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2021, Microsoft Corp. All rights reserved,
-
-using System.Collections.Generic;
-
-using Xamarin.Utils;
-
-#nullable enable
-
-namespace Xamarin.Bundler {
- public static partial class ErrorHelper {
- public static ApplePlatform Platform;
-
- internal static string GetPrefix (IToolLog? log)
- {
- return Xamarin.MacDev.Tasks.LoggingExtensions.ErrorPrefix;
- }
-
- public enum WarningLevel {
- Error = -1,
- Warning = 0,
- Disable = 1,
- }
-
- static Dictionary? warning_levels;
-
- public static WarningLevel GetWarningLevel (IToolLog log, int code)
- {
- WarningLevel level;
-
- if (warning_levels is null)
- return WarningLevel.Warning;
-
- // code -1: all codes
- if (warning_levels.TryGetValue (-1, out level))
- return level;
-
- if (warning_levels.TryGetValue (code, out level))
- return level;
-
- return WarningLevel.Warning;
- }
-
- public static void SetWarningLevel (WarningLevel level, int? code = null /* if null, apply to all warnings */)
- {
- if (warning_levels is null)
- warning_levels = new Dictionary ();
- if (code.HasValue) {
- warning_levels [code.Value] = level;
- } else {
- warning_levels [-1] = level; // code -1: all codes.
- }
- }
- }
-}
diff --git a/msbuild/Xamarin.MacDev.Tasks/LoggingExtensions.cs b/msbuild/Xamarin.MacDev.Tasks/LoggingExtensions.cs
index 367f3f5bd46a..2f0f9b7a5538 100644
--- a/msbuild/Xamarin.MacDev.Tasks/LoggingExtensions.cs
+++ b/msbuild/Xamarin.MacDev.Tasks/LoggingExtensions.cs
@@ -74,6 +74,19 @@ public static void LogTaskProperty (this TaskLoggingHelper log, string propertyN
log.LogMessage (TaskPropertyImportance, " {0}: {1}", propertyName, value);
}
+ ///
+ /// Creates an MSBuild error following our MTErrors convention.
+ ///
+ /// For every new error we need to update "docs/website/mtouch-errors.md" and "tools/mtouch/error.cs".
+ /// In the 7xxx range for MSBuild error.
+ /// The error's message to be displayed in the error pad.
+ /// Path to the known guilty file or null.
+ /// Line number in the file where the error was found, or 0 if unknown.
+ public static void LogError (this TaskLoggingHelper log, int errorCode, string? fileName, int lineNumber, string message, params object? [] args)
+ {
+ log.LogError (null, $"{ErrorPrefix}{errorCode}", null, fileName ?? "MSBuild", lineNumber, 0, 0, 0, message, args);
+ }
+
///
/// Creates an MSBuild error following our MTErrors convention.
///
@@ -91,6 +104,16 @@ public static void LogWarning (this TaskLoggingHelper log, int errorCode, string
log.LogWarning (null, $"{ErrorPrefix}{errorCode}", null, fileName ?? "MSBuild", 0, 0, 0, 0, message, args);
}
+ public static void LogWarning (this TaskLoggingHelper log, int errorCode, string? fileName, int lineNumber, string message, params object? [] args)
+ {
+ log.LogWarning (null, $"{ErrorPrefix}{errorCode}", null, fileName ?? "MSBuild", lineNumber, 0, 0, 0, message, args);
+ }
+
+ public static void LogMessage (this TaskLoggingHelper log, MessageImportance importance, int errorCode, string? fileName, int lineNumber, string message, params object? [] args)
+ {
+ log.LogMessage (null, $"{ErrorPrefix}{errorCode}", null, fileName ?? "MSBuild", lineNumber, 0, 0, 0, importance, message, args);
+ }
+
public static bool LogErrorsFromException (this TaskLoggingHelper log, Exception exception, bool showStackTrace = true, bool showDetail = true)
{
var exceptions = new List ();
diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs
new file mode 100644
index 000000000000..6c5b49233278
--- /dev/null
+++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs
@@ -0,0 +1,110 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+using Xamarin.Build;
+using Xamarin.Bundler;
+using Xamarin.Utils;
+
+#nullable enable
+
+namespace Xamarin.MacDev.Tasks {
+ // This task is not supposed to be remoted (it doesn't need to run on a Mac).
+ public class PrepareAssemblies : XamarinTask {
+ const string ErrorPrefix = "MX";
+
+ #region Inputs
+ [Required]
+ public ITaskItem [] InputAssemblies { get; set; } = [];
+
+ public string MakeReproPath { get; set; } = "";
+
+ public string OutputDirectory { get; set; } = "";
+
+ [Required]
+ public ITaskItem? OptionsFile { get; set; }
+ #endregion
+
+ #region Outputs
+ [Output]
+ public ITaskItem [] OutputAssemblies { get; set; } = [];
+ #endregion
+
+ Dictionary map = new ();
+
+ AssemblyPreparerInfo GetAssemblyInfo (ITaskItem item)
+ {
+ var inputPath = item.ItemSpec;
+ var outputPath = Path.Combine (OutputDirectory, Path.GetFileName (inputPath));
+ var isTrimmableString = item.GetMetadata ("IsTrimmable");
+ var isTrimmable = string.IsNullOrEmpty (isTrimmableString) ? (bool?) null : string.Equals (isTrimmableString, "true", StringComparison.OrdinalIgnoreCase);
+ var trimMode = item.GetMetadata ("TrimMode");
+ var rv = new AssemblyPreparerInfo (inputPath, outputPath, isTrimmable, trimMode);
+ map [rv] = item;
+ return rv;
+ }
+
+ public override bool Execute ()
+ {
+ // Capture Console usage and show an error if anything uses Console.[Error.]Write*
+ using var consoleToLog = ConsoleToTaskWriter.EnsureNoConsoleUsage (Log);
+
+ try {
+ var infos = InputAssemblies.Select (GetAssemblyInfo).ToArray ();
+ using var preparer = new AssemblyPreparer (this, infos, OptionsFile?.ItemSpec ?? "");
+ preparer.MakeReproPath = MakeReproPath;
+ var rv = preparer.Prepare (out var exceptions);
+
+ foreach (var pe in exceptions) {
+ if (pe.IsError (this)) {
+ ((IToolLog) this).LogError (pe);
+ } else {
+ ((IToolLog) this).LogWarning (pe);
+ }
+ }
+
+ var outputAssemblies = preparer.Assemblies.Select (v => {
+ var item = new TaskItem (v.OutputPath);
+ map [v].CopyMetadataTo (item);
+ item.SetMetadata ("BeforePrepareAssembliesPath", v.InputPath);
+ return (ITaskItem) item;
+ }).ToList ();
+
+ outputAssemblies.AddRange (preparer.AddedAssemblies.Select (v => {
+ var rv = new TaskItem (v.Path);
+ rv.SetMetadata ("PostprocessAssembly", "true");
+ rv.SetMetadata ("RelativePath", preparer.Configuration.AssemblyPublishDir + Path.GetFileName (v.Path));
+ if (v.OriginatingAssembly is not null) {
+ var originatingItem = map.SingleOrDefault (kvp => Path.GetFileName (kvp.Key.InputPath) == Path.GetFileName (v.OriginatingAssembly)).Value;
+ if (originatingItem is null) {
+ Log.LogMessage (MessageImportance.Low, $"Could not find originating assembly for {v.Path} with originating assembly name {v.OriginatingAssembly}");
+ } else {
+ var metadata = originatingItem.MetadataNames.Cast ().ToList ();
+ if (metadata.Contains ("TrimMode"))
+ rv.SetMetadata ("TrimMode", originatingItem.GetMetadata ("TrimMode"));
+ if (metadata.Contains ("IsTrimmable"))
+ rv.SetMetadata ("IsTrimmable", originatingItem.GetMetadata ("IsTrimmable"));
+ }
+ }
+ return rv;
+ }));
+
+ OutputAssemblies = outputAssemblies.ToArray ();
+ return rv && !Log.HasLoggedErrors;
+ } catch (Exception e) {
+ ((IToolLog) this).LogException (e);
+ return false;
+ }
+ }
+ }
+}
diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinBuildTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinBuildTask.cs
index d9f176e8388b..3327f3a06d07 100644
--- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinBuildTask.cs
+++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinBuildTask.cs
@@ -52,7 +52,7 @@ protected string ComputeValueUsingTarget (string computeValueTarget, string targ
}
// Disable a few things that we don't care about
environment ["DOTNET_NOLOGO"] = "1";
- environment ["DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE"] = "1";
+ environment ["DOTNET_CLI_WORKLOAD_UPDATE_NOTIFY_DISABLE"] = "true";
try {
ExecuteRestoreAsync (dotnetPath, projectPath, targetName, environment).Wait ();
diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs
index 3cd5a9386821..e50cee0ce94a 100644
--- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs
+++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinTask.cs
@@ -13,7 +13,6 @@
using Xamarin.Localization.MSBuild;
using Xamarin.Messaging.Build.Client;
using Xamarin.Utils;
-using static Xamarin.Bundler.FileCopier;
#nullable enable
@@ -246,7 +245,7 @@ internal static bool ExecuteRemotely (T task) where T : Task, IHasSessionId
}
#if NET
- internal static bool ExecuteRemotely (T task, [NotNullWhen (true)] out TaskRunner? taskRunner, Action? preprocessTaskRunner = null) where T: Task, IHasSessionId
+ internal static bool ExecuteRemotely (T task, [NotNullWhen (true)] out TaskRunner? taskRunner, Action? preprocessTaskRunner = null) where T : Task, IHasSessionId
#else
internal static bool ExecuteRemotely (T task, out TaskRunner taskRunner, Action? preprocessTaskRunner = null) where T : Task, IHasSessionId
#endif
@@ -371,8 +370,11 @@ void ICustomLogger.LogError (string message, Exception? ex)
{
if (!string.IsNullOrEmpty (message))
Log.LogError (message);
- if (ex is not null)
+ if (ex is ProductException pe) {
+ LogDiagnostic (pe);
+ } else if (ex is not null) {
Log.LogErrorFromException (ex);
+ }
}
void ICustomLogger.LogWarning (string messageFormat, params object? [] args)
@@ -404,12 +406,37 @@ void IToolLog.LogError (string message)
void IToolLog.LogException (Exception exception)
{
- ((ICustomLogger) this).LogError ("", exception);
+ if (exception is ProductException pe) {
+ LogDiagnostic (pe);
+ } else {
+ ((ICustomLogger) this).LogError ($"Unexpected exception '{GetType ().Name}': {exception.Message}", exception);
+ }
+ }
+
+ void IToolLog.LogError (ProductException exception)
+ {
+ LogDiagnostic (exception);
}
- void IToolLog.LogError (Exception exception)
+ void IToolLog.LogWarning (ProductException exception)
{
- ((ICustomLogger) this).LogError ("", exception);
+ LogDiagnostic (exception);
+ }
+
+ protected void LogDiagnostic (ProductException exception)
+ {
+ switch (exception.GetWarningLevel (this)) {
+ case ErrorHelper.WarningLevel.Warning:
+ Log.LogWarning (exception.Code, exception.FileName, exception.LineNumber, exception.Message);
+ break;
+ case ErrorHelper.WarningLevel.Error:
+ Log.LogError (exception.Code, exception.FileName, exception.LineNumber, exception.Message);
+ break;
+ case ErrorHelper.WarningLevel.Disable:
+ default:
+ Log.LogMessage (MessageImportance.Low, exception.Code, exception.FileName, exception.LineNumber, exception.Message);
+ break;
+ }
}
#endregion
}
diff --git a/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj b/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj
index 713db306ebef..cbd090125523 100644
--- a/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj
+++ b/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj
@@ -1,7 +1,8 @@
- netstandard2.0;net$(BundledNETCoreAppTargetFrameworkVersion)
+ net$(BundledNETCoreAppTargetFrameworkVersion);netstandard2.0
+ net$(BundledNETCoreAppTargetFrameworkVersion)
false
compile
true
@@ -37,6 +38,7 @@
+
ProjectReference
@@ -69,45 +71,15 @@
-
- ApplePlatform.cs
-
- JsonExtensions.cs
-
-
- IToolLog.cs
+ external\JsonExtensions.cs
StringUtils.cs
-
- Symbols.cs
-
-
- FileCopier.cs
-
-
- TargetFramework.cs
-
-
- Execution.cs
-
-
- PathUtils.cs
-
PListExtensions.cs
-
- MachO.cs
-
-
- error.cs
-
-
- ErrorHelper.cs
-
external\RuntimeException.cs
diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
index c26dc90f564a..7e63298c1275 100644
--- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets
+++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
@@ -84,6 +84,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
+
@@ -3402,6 +3403,57 @@ Copyright (C) 2018 Microsoft. All rights reserved.
+
+ false
+
+
+
+ <_PrepareAssembliesForPreparationDependsOn>
+ _ComputeAssembliesToPostprocessOnPublish;
+ _ComputeLinkerInputs;
+
+
+
+
+
+
+ <_AssembliesToPrepare Include="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.Extension)' == '.dll' And '%(ResolvedFileToPublish.Culture)' == '' And !$([System.String]::Copy ('%(Filename)').EndsWith ('.resources'))" />
+
+
+ $([MSBuild]::EnsureTrailingSlash('$(DeviceSpecificIntermediateOutputPath)prepared-assemblies'))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AppKit/Enums.cs b/src/AppKit/Enums.cs
index bc8a31913034..8656ba155c77 100644
--- a/src/AppKit/Enums.cs
+++ b/src/AppKit/Enums.cs
@@ -488,7 +488,12 @@ public enum NSCellHit : ulong {
/// To be added.
EditableTextArea = 2,
/// To be added.
- TrackableArae = 4,
+ TrackableArea = 4,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'TrackableArea' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ TrackableArae = TrackableArea,
+#endif
}
[NoMacCatalyst]
@@ -1718,7 +1723,12 @@ public enum NSCompositingOperation : ulong {
[Native]
public enum NSAnimationEffect : ulong {
/// To be added.
- DissapearingItemDefault = 0,
+ DisappearingItemDefault = 0,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'DisappearingItemDefault' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ DissapearingItemDefault = DisappearingItemDefault,
+#endif
/// To be added.
EffectPoof = 10,
}
diff --git a/src/AudioUnit/AUEnums.cs b/src/AudioUnit/AUEnums.cs
index 05b4c69ff335..814065f997e3 100644
--- a/src/AudioUnit/AUEnums.cs
+++ b/src/AudioUnit/AUEnums.cs
@@ -1064,7 +1064,12 @@ public enum AudioUnitParameterType // UInt32 in AudioUnitParameterInfo
/// To be added.
GlobalReverbGain = 9,
/// To be added.
- OcclussionAttenuation = 10,
+ OcclusionAttenuation = 10,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'OcclusionAttenuation' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ OcclussionAttenuation = OcclusionAttenuation,
+#endif
/// To be added.
ObstructionAttenuation = 11,
}
diff --git a/src/CoreGraphics/CGEnums.cs b/src/CoreGraphics/CGEnums.cs
index d89f9c464287..02e76f13e9a1 100644
--- a/src/CoreGraphics/CGEnums.cs
+++ b/src/CoreGraphics/CGEnums.cs
@@ -9,6 +9,8 @@
#nullable enable
+using System.ComponentModel;
+
namespace CoreGraphics {
public enum MatrixOrder {
@@ -215,7 +217,12 @@ public enum CGPdfTagType /* int32_t */ {
RubyPunctuation,
Warichu,
WarichuText,
- WarichuPunctiation,
+ WarichuPunctuation,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'WarichuPunctuation' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ WarichuPunctiation = WarichuPunctuation,
+#endif
Figure = 700,
Formula,
Form,
diff --git a/src/CoreGraphics/CGEventSource.cs b/src/CoreGraphics/CGEventSource.cs
index 3557e5ecf8ce..a73588d0df65 100644
--- a/src/CoreGraphics/CGEventSource.cs
+++ b/src/CoreGraphics/CGEventSource.cs
@@ -13,6 +13,7 @@
#if MONOMAC || __MACCATALYST__
using CoreFoundation;
+using System.ComponentModel;
namespace CoreGraphics {
/// To be added.
@@ -157,11 +158,17 @@ public long UserData {
/// To be added.
/// To be added.
/// To be added.
- public void SetLocalEventsFilterDuringSupressionState (CGEventFilterMask filter, CGEventSuppressionState state)
+ public void SetLocalEventsFilterDuringSuppressionState (CGEventFilterMask filter, CGEventSuppressionState state)
{
CGEventSourceSetLocalEventsFilterDuringSuppressionState (Handle, filter, state);
}
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'SetLocalEventsFilterDuringSuppressionState' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ public void SetLocalEventsFilterDuringSupressionState (CGEventFilterMask filter, CGEventSuppressionState state) => SetLocalEventsFilterDuringSuppressionState (filter, state);
+#endif
+
[DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)]
extern static CGEventFilterMask CGEventSourceGetLocalEventsFilterDuringSuppressionState (IntPtr handle, CGEventSuppressionState state);
@@ -169,11 +176,17 @@ public void SetLocalEventsFilterDuringSupressionState (CGEventFilterMask filter,
/// To be added.
/// To be added.
/// To be added.
- public CGEventFilterMask GetLocalEventsFilterDuringSupressionState (CGEventSuppressionState state)
+ public CGEventFilterMask GetLocalEventsFilterDuringSuppressionState (CGEventSuppressionState state)
{
return CGEventSourceGetLocalEventsFilterDuringSuppressionState (Handle, state);
}
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'GetLocalEventsFilterDuringSuppressionState' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ public CGEventFilterMask GetLocalEventsFilterDuringSupressionState (CGEventSuppressionState state) => GetLocalEventsFilterDuringSuppressionState (state);
+#endif
+
[DllImport (Constants.ApplicationServicesCoreGraphicsLibrary)]
extern static void CGEventSourceSetLocalEventsSuppressionInterval (IntPtr handle, double seconds);
@@ -183,7 +196,7 @@ public CGEventFilterMask GetLocalEventsFilterDuringSupressionState (CGEventSuppr
/// To be added.
/// To be added.
/// To be added.
- public double LocalEventsSupressionInterval {
+ public double LocalEventsSuppressionInterval {
get {
return CGEventSourceGetLocalEventsSuppressionInterval (Handle);
}
@@ -192,6 +205,15 @@ public double LocalEventsSupressionInterval {
}
}
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'LocalEventsSuppressionInterval' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ public double LocalEventsSupressionInterval {
+ get => LocalEventsSuppressionInterval;
+ set => LocalEventsSuppressionInterval = value;
+ }
+#endif
+
}
}
diff --git a/src/CoreLocation/CLEnums.cs b/src/CoreLocation/CLEnums.cs
index 60e3c155b38b..94ad45bea1fd 100644
--- a/src/CoreLocation/CLEnums.cs
+++ b/src/CoreLocation/CLEnums.cs
@@ -71,7 +71,7 @@ public enum CLError : long {
DeferredFailed,
/// The did not enter deferred mode because location updates were already paused or disabled.
DeferredNotUpdatingLocation,
- /// Deferred mode is not available for the requested accuracy. For deferred mode, the accuracy must be or .
+ /// Deferred mode is not available for the requested accuracy. For deferred mode, the accuracy must be or .
DeferredAccuracyTooLow,
/// Deferred mode does not allow distance filters. The must be set to .
DeferredDistanceFiltered,
diff --git a/src/CoreVideo/CVBuffer.cs b/src/CoreVideo/CVBuffer.cs
index 158a44ce8596..b331e5e25e5d 100644
--- a/src/CoreVideo/CVBuffer.cs
+++ b/src/CoreVideo/CVBuffer.cs
@@ -231,7 +231,7 @@ unsafe static IntPtr CVBufferCopyAttachment (IntPtr buffer, IntPtr key, out CVAt
/// To be added.
/// To be added.
/// To be added.
- public void PropogateAttachments (CVBuffer destinationBuffer)
+ public void PropagateAttachments (CVBuffer destinationBuffer)
{
if (destinationBuffer is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (destinationBuffer));
@@ -240,6 +240,12 @@ public void PropogateAttachments (CVBuffer destinationBuffer)
GC.KeepAlive (destinationBuffer);
}
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'PropagateAttachments' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ public void PropogateAttachments (CVBuffer destinationBuffer) => PropagateAttachments (destinationBuffer);
+#endif
+
[DllImport (Constants.CoreVideoLibrary)]
extern static void CVBufferSetAttachment (/* CVBufferRef */ IntPtr buffer, /* CFStringRef */ IntPtr key, /* CFTypeRef */ IntPtr @value, CVAttachmentMode attachmentMode);
diff --git a/src/CoreWlan/Enums.cs b/src/CoreWlan/Enums.cs
index eb3d0e52ebd8..5e0f20492175 100644
--- a/src/CoreWlan/Enums.cs
+++ b/src/CoreWlan/Enums.cs
@@ -2,6 +2,7 @@
// Copyright 2019 Microsoft Corporation
using CoreFoundation;
+using System.ComponentModel;
namespace CoreWlan {
@@ -167,7 +168,12 @@ public enum CWChannelWidth : ulong {
/// To be added.
TwentyMHz = 1,
/// To be added.
- FourtyMHz = 2,
+ FortyMHz = 2,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'FortyMHz' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ FourtyMHz = FortyMHz,
+#endif
/// To be added.
EightyMHz = 3,
/// To be added.
diff --git a/src/Darwin/KernelNotification.cs b/src/Darwin/KernelNotification.cs
index 2aaba82e098e..0bf4e0733e7f 100644
--- a/src/Darwin/KernelNotification.cs
+++ b/src/Darwin/KernelNotification.cs
@@ -32,6 +32,7 @@
using CoreFoundation;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
+using System.ComponentModel;
namespace Darwin {
/// To be added.
@@ -183,7 +184,12 @@ public enum FilterFlags : uint {
// iOS only
/// To be added.
- ProcAppactive = 0x00800000,
+ ProcAppActive = 0x00800000,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'ProcAppActive' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ ProcAppactive = ProcAppActive,
+#endif
/// To be added.
ProcAppBackground = 0x00400000,
/// To be added.
diff --git a/src/Foundation/NSMetadataItem.cs b/src/Foundation/NSMetadataItem.cs
index b4fd6934196e..2f02115dacc4 100644
--- a/src/Foundation/NSMetadataItem.cs
+++ b/src/Foundation/NSMetadataItem.cs
@@ -1067,11 +1067,25 @@ public NSDate? GpsDateStamp {
[UnsupportedOSPlatform ("maccatalyst")]
[UnsupportedOSPlatform ("tvos")]
[UnsupportedOSPlatform ("ios")]
+ public double? GpsDifferential {
+ get {
+ return GetNullableDouble (NSMetadataQuery.GpsDifferentialKey);
+ }
+ }
+
+#if !XAMCORE_5_0
+ [SupportedOSPlatform ("macos")]
+ [UnsupportedOSPlatform ("maccatalyst")]
+ [UnsupportedOSPlatform ("tvos")]
+ [UnsupportedOSPlatform ("ios")]
+ [System.Obsolete ("Use 'GpsDifferential' instead.")]
+ [System.ComponentModel.EditorBrowsable (System.ComponentModel.EditorBrowsableState.Never)]
public double? GpsDifferental {
get {
- return GetNullableDouble (NSMetadataQuery.GpsDifferentalKey);
+ return GpsDifferential;
}
}
+#endif
/// To be added.
/// To be added.
diff --git a/src/Foundation/NSUrlCredential.cs b/src/Foundation/NSUrlCredential.cs
index 31d575d2b4e7..6c3462595a0e 100644
--- a/src/Foundation/NSUrlCredential.cs
+++ b/src/Foundation/NSUrlCredential.cs
@@ -2,6 +2,7 @@
using System.Reflection;
using System.Collections;
+using System.ComponentModel;
using Security;
@@ -30,7 +31,7 @@ public NSUrlCredential (SecIdentity identity, SecCertificate [] certificates, NS
/// The certificates to use for the credential.
/// Specifies how long the credential should be kept.
/// A new instance.
- public static NSUrlCredential FromIdentityCertificatesPersistance (SecIdentity identity, SecCertificate [] certificates, NSUrlCredentialPersistence persistence)
+ public static NSUrlCredential Create (SecIdentity identity, SecCertificate [] certificates, NSUrlCredentialPersistence persistence)
{
ArgumentNullException.ThrowIfNull (identity);
ArgumentNullException.ThrowIfNull (certificates);
@@ -42,6 +43,12 @@ public static NSUrlCredential FromIdentityCertificatesPersistance (SecIdentity i
}
}
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'Create' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ public static NSUrlCredential FromIdentityCertificatesPersistance (SecIdentity identity, SecCertificate [] certificates, NSUrlCredentialPersistence persistence) => Create (identity, certificates, persistence);
+#endif
+
/// Gets the identity (digital certificate + private key) associated with this credential.
/// A object representing the identity, or if no identity is available.
public SecIdentity? SecIdentity {
diff --git a/src/HomeKit/HMEnums.cs b/src/HomeKit/HMEnums.cs
index 4f773aabac45..5fbc1c320ba5 100644
--- a/src/HomeKit/HMEnums.cs
+++ b/src/HomeKit/HMEnums.cs
@@ -1,4 +1,6 @@
+using System.ComponentModel;
+
namespace HomeKit {
/// Enumerates possible failures in Home Kit operations.
@@ -156,7 +158,12 @@ public enum HMError : long {
/// The read or write failed.
ReadWriteFailure = 74,
/// The user or application is not signed in to iCloud.
- NotSignedIntoiCloud = 75,
+ NotSignedIntoICloud = 75,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'NotSignedIntoICloud' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ NotSignedIntoiCloud = NotSignedIntoICloud,
+#endif
/// Keychain synchronization was not enabled.
KeychainSyncNotEnabled = 76,
/// Data was synchronizing.
diff --git a/src/NaturalLanguage/Enums.cs b/src/NaturalLanguage/Enums.cs
index 243b2adfc4a8..f47c58854e85 100644
--- a/src/NaturalLanguage/Enums.cs
+++ b/src/NaturalLanguage/Enums.cs
@@ -368,7 +368,11 @@ public enum NLContextualEmbeddingAssetsResult : long {
}
[TV (17, 0), iOS (17, 0), MacCatalyst (17, 0)]
+#if XAMCORE_5_0
+ public enum NLContextualEmbeddingKey {
+#else
public enum NLContextualEmebeddingKey {
+#endif
[Field ("NLContextualEmbeddingKeyLanguages")]
Languages,
[Field ("NLContextualEmbeddingKeyScripts")]
diff --git a/src/Network/NWConnectionGroup.cs b/src/Network/NWConnectionGroup.cs
index 906c68727e97..4dd06976a41b 100644
--- a/src/Network/NWConnectionGroup.cs
+++ b/src/Network/NWConnectionGroup.cs
@@ -5,6 +5,7 @@
using OS_nw_parameters = System.IntPtr;
using OS_nw_content_context = System.IntPtr;
using OS_nw_path = System.IntPtr;
+using System.ComponentModel;
using OS_nw_endpoint = System.IntPtr;
using OS_nw_protocol_metadata = System.IntPtr;
using OS_nw_protocol_definition = System.IntPtr;
@@ -116,7 +117,7 @@ public void SetQueue (DispatchQueue queue)
[DllImport (Constants.NetworkLibrary)]
static extern OS_nw_endpoint nw_connection_group_copy_remote_endpoint_for_message (OS_nw_connection_group group, OS_nw_content_context context);
- public NWEndpoint? GetRemmoteEndpoint (NWContentContext context)
+ public NWEndpoint? GetRemoteEndpoint (NWContentContext context)
{
if (context is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (context));
@@ -125,6 +126,12 @@ public void SetQueue (DispatchQueue queue)
return ptr == IntPtr.Zero ? null : new NWEndpoint (ptr, owns: true);
}
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'GetRemoteEndpoint' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ public NWEndpoint? GetRemmoteEndpoint (NWContentContext context) => GetRemoteEndpoint (context);
+#endif
+
// can return null
[DllImport (Constants.NetworkLibrary)]
static extern OS_nw_connection nw_connection_group_extract_connection_for_message (OS_nw_connection_group group, OS_nw_content_context context);
diff --git a/src/ObjCRuntime/Registrar.core.cs b/src/ObjCRuntime/Registrar.core.cs
index 958a17174874..86cd2436e8d0 100644
--- a/src/ObjCRuntime/Registrar.core.cs
+++ b/src/ObjCRuntime/Registrar.core.cs
@@ -8,7 +8,11 @@ abstract partial class Registrar {
[return: NotNullIfNotNull (nameof (getterSelector))]
internal static string? CreateSetterSelector (string? getterSelector)
{
+#if NET
if (string.IsNullOrEmpty (getterSelector))
+#else
+ if (string.IsNullOrEmpty (getterSelector) || getterSelector is null)
+#endif
return getterSelector;
var first = (int) getterSelector [0];
@@ -21,7 +25,11 @@ abstract partial class Registrar {
[return: NotNullIfNotNull (nameof (name))]
public static string? SanitizeObjectiveCName (string? name)
{
+#if NET
if (string.IsNullOrEmpty (name))
+#else
+ if (string.IsNullOrEmpty (name) || name is null)
+#endif
return name;
StringBuilder? sb = null;
diff --git a/src/ObjCRuntime/Registrar.cs b/src/ObjCRuntime/Registrar.cs
index d33f63746e84..303004248263 100644
--- a/src/ObjCRuntime/Registrar.cs
+++ b/src/ObjCRuntime/Registrar.cs
@@ -220,7 +220,11 @@ public void VerifyRegisterAttribute ([NotNullIfNotNull (nameof (exceptions))] re
return;
var name = RegisterAttribute.Name;
+#if NET
if (string.IsNullOrEmpty (name))
+#else
+ if (string.IsNullOrEmpty (name) || name is null)
+#endif
return;
for (int i = 0; i < name.Length; i++) {
@@ -540,7 +544,11 @@ abstract internal class ObjCMember {
public bool SetExportAttribute (ExportAttribute ea, [NotNullIfNotNull (nameof (exceptions))] ref List? exceptions)
{
+#if NET
if (string.IsNullOrEmpty (ea.Selector)) {
+#else
+ if (string.IsNullOrEmpty (ea.Selector) || ea.Selector is null) {
+#endif
AddException (ref exceptions, Registrar.CreateException (4135, this, Errors.MT4135, FullName));
return false;
}
@@ -2181,7 +2189,11 @@ void FlattenInterfaces (TType? [] ifaces)
objcType.Add (objcGetter, ref exceptions);
+#if NET
if (!string.IsNullOrEmpty (attrib.SetterSelector)) {
+#else
+ if (!string.IsNullOrEmpty (attrib.SetterSelector) && attrib.SetterSelector is not null) {
+#endif
var objcSetter = new ObjCMethod (this, objcType, null) {
Name = attrib.Name,
Selector = attrib.SetterSelector,
diff --git a/src/PrintCore/Defs.cs b/src/PrintCore/Defs.cs
index d6fc9c73d980..af8eca7f868a 100644
--- a/src/PrintCore/Defs.cs
+++ b/src/PrintCore/Defs.cs
@@ -9,6 +9,7 @@
#nullable enable
+using System.ComponentModel;
using System.Threading;
using System.IO;
@@ -215,7 +216,12 @@ public enum PMStatusCode {
/// To be added.
PluginNotFound = -9701,
/// To be added.
- PluginRegisterationFailed = -9702,
+ PluginRegistrationFailed = -9702,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'PluginRegistrationFailed' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ PluginRegisterationFailed = PluginRegistrationFailed,
+#endif
/// To be added.
FontNotFound = -9703,
/// To be added.
diff --git a/src/SystemConfiguration/StatusCodeError.cs b/src/SystemConfiguration/StatusCodeError.cs
index cf35ba416c2c..06b74df94d3b 100644
--- a/src/SystemConfiguration/StatusCodeError.cs
+++ b/src/SystemConfiguration/StatusCodeError.cs
@@ -12,8 +12,7 @@
namespace SystemConfiguration {
// https://developer.apple.com/library/mac/#documentation/SystemConfiguration/Reference/SystemConfiguration_Utilities/Reference/reference.html
- /// Provides access to a text description associated with a .
- /// To be added.
+ /// Provides access to a text description associated with a .
public static class StatusCodeError {
[DllImport (Constants.SystemConfigurationLibrary)]
extern internal static StatusCode /* int */ SCError ();
@@ -21,10 +20,9 @@ public static class StatusCodeError {
[DllImport (Constants.SystemConfigurationLibrary)]
extern static IntPtr /* const char* */ SCErrorString (int code);
- /// To be added.
- /// Description for the status code.
- /// To be added.
- /// To be added.
+ /// Returns the human-readable description for the specified status code.
+ /// The to describe.
+ /// A string containing the description of the status code, or if no description is available.
public static string? GetErrorDescription (StatusCode statusCode)
{
var ptr = SCErrorString ((int) statusCode);
diff --git a/src/SystemConfiguration/SystemConfigurationException.cs b/src/SystemConfiguration/SystemConfigurationException.cs
index 7a5d8a605f12..dacca8378086 100644
--- a/src/SystemConfiguration/SystemConfigurationException.cs
+++ b/src/SystemConfiguration/SystemConfigurationException.cs
@@ -11,21 +11,18 @@
namespace SystemConfiguration {
- /// An exception relating to network reachability. The cause of the exception is specified by the property.
- /// To be added.
+ /// An exception relating to network reachability. The cause of the exception is specified by the property.
public class SystemConfigurationException : Exception {
- /// To be added.
- /// Creates a new wrapping the .
- /// To be added.
+ /// Creates a new wrapping the specified .
+ /// The that caused this exception.
public SystemConfigurationException (StatusCode statusErrorCode)
: base (StatusCodeError.GetErrorDescription (statusErrorCode))
{
StatusErrorCode = statusErrorCode;
}
- /// The wrapped in this .
- /// To be added.
- /// To be added.
+ /// Gets the that describes the cause of this exception.
+ /// The status code associated with this exception.
public StatusCode StatusErrorCode { get; private set; }
internal static SystemConfigurationException FromMostRecentCall ()
diff --git a/src/accessibility.cs b/src/accessibility.cs
index f6c4cd8520bc..db551e87df39 100644
--- a/src/accessibility.cs
+++ b/src/accessibility.cs
@@ -1,4 +1,5 @@
using CoreGraphics;
+using System.ComponentModel;
#nullable enable
@@ -613,7 +614,16 @@ interface AXMathExpressionFraction {
AXMathExpression NumeratorExpression { get; }
[Export ("denimonatorExpression")]
+#if XAMCORE_5_0
+ AXMathExpression DenominatorExpression { get; }
+#else
+ [Obsolete ("Use 'DenominatorExpression' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
AXMathExpression DenimonatorExpression { get; }
+
+ [Wrap ("DenimonatorExpression")]
+ AXMathExpression DenominatorExpression { get; }
+#endif
}
[TV (18, 2), Mac (15, 2), iOS (18, 2), MacCatalyst (18, 2)]
diff --git a/src/appkit.cs b/src/appkit.cs
index f3fa730c79dd..3992382d93ba 100644
--- a/src/appkit.cs
+++ b/src/appkit.cs
@@ -3882,8 +3882,17 @@ interface NSCollectionViewDataSource {
/// To be added.
[Abstract]
[Export ("collectionView:numberOfItemsInSection:")]
+#if XAMCORE_5_0
+ nint GetNumberOfItems (NSCollectionView collectionView, nint section);
+#else
+ [Obsolete ("Use 'GetNumberOfItems' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
nint GetNumberofItems (NSCollectionView collectionView, nint section);
+ [Wrap ("GetNumberofItems (collectionView, section)")]
+ nint GetNumberOfItems (NSCollectionView collectionView, nint section);
+#endif
+
/// To be added.
/// To be added.
/// To be added.
@@ -8575,8 +8584,17 @@ partial interface NSFormCell {
nfloat TitleWidth { get; set; }
[Export ("titleWidth:")]
+#if XAMCORE_5_0
+ nfloat GetTitleWidth (CGSize size);
+#else
+ [Obsolete ("Use 'GetTitleWidth' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
nfloat TitleWidthConstraintedToSize (CGSize aSize);
+ [Wrap ("TitleWidthConstraintedToSize (size)")]
+ nfloat GetTitleWidth (CGSize size);
+#endif
+
[Export ("title")]
string Title { get; set; }
@@ -14530,8 +14548,17 @@ partial interface NSPopUpButtonCell {
nint IndexOfItemWithRepresentedObject (NSObject obj);
[Export ("indexOfItemWithTarget:andAction:")]
+#if XAMCORE_5_0
+ nint IndexOfItemWithTargetAndAction (NSObject target, Selector actionSelector);
+#else
+ [Obsolete ("Use 'IndexOfItemWithTargetAndAction' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
nint IndexOfItemWithTargetandAction (NSObject target, Selector actionSelector);
+ [Wrap ("IndexOfItemWithTargetandAction (target, actionSelector)")]
+ nint IndexOfItemWithTargetAndAction (NSObject target, Selector actionSelector);
+#endif
+
[Export ("itemAtIndex:")]
NSMenuItem ItemAt (nint index);
@@ -15597,8 +15624,17 @@ interface NSStandardKeyBindingResponding {
[BaseType (typeof (NSObject))]
partial interface NSResponder : NSCoding, NSTouchBarProvider, NSUserActivityRestoring {
[Export ("tryToPerform:with:")]
+#if XAMCORE_5_0
+ bool TryToPerformWith (Selector anAction, [NullAllowed] NSObject anObject);
+#else
+ [Obsolete ("Use 'TryToPerformWith' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
bool TryToPerformwith (Selector anAction, [NullAllowed] NSObject anObject);
+ [Wrap ("TryToPerformwith (anAction, anObject)")]
+ bool TryToPerformWith (Selector anAction, [NullAllowed] NSObject anObject);
+#endif
+
[Export ("performKeyEquivalent:")]
bool PerformKeyEquivalent (NSEvent theEvent);
@@ -16183,8 +16219,17 @@ partial interface NSScreen {
CGRect ConvertRectToBacking (CGRect aRect);
[Export ("convertRectFromBacking:")]
+#if XAMCORE_5_0
+ CGRect ConvertRectFromBacking (CGRect aRect);
+#else
+ [Obsolete ("Use 'ConvertRectFromBacking' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
CGRect ConvertRectfromBacking (CGRect aRect);
+ [Wrap ("ConvertRectfromBacking (aRect)")]
+ CGRect ConvertRectFromBacking (CGRect aRect);
+#endif
+
[Export ("backingAlignedRect:options:")]
CGRect GetBackingAlignedRect (CGRect globalScreenCoordRect, NSAlignmentOptions options);
@@ -17414,8 +17459,17 @@ partial interface NSSpellChecker {
void UpdateSpellingPanelWithMisspelledWord (string word);
[Export ("updateSpellingPanelWithGrammarString:detail:")]
+#if XAMCORE_5_0
+ void UpdateSpellingPanelWithGrammarString (string theString, NSDictionary detail);
+#else
+ [Obsolete ("Use 'UpdateSpellingPanelWithGrammarString' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void UpdateSpellingPanelWithGrammarl (string theString, NSDictionary detail);
+ [Wrap ("UpdateSpellingPanelWithGrammarl (theString, detail)")]
+ void UpdateSpellingPanelWithGrammarString (string theString, NSDictionary detail);
+#endif
+
[Export ("spellingPanel")]
NSPanel SpellingPanel { get; }
@@ -26810,8 +26864,17 @@ interface NSWorkspace : NSWorkspaceAccessibilityExtensions {
NSImage IconForFileType (IntPtr fileTypeOrTypeCode);
[Export ("setIcon:forFile:options:"), ThreadSafe]
+#if XAMCORE_5_0
+ bool SetIconForFile (NSImage image, string fullPath, NSWorkspaceIconCreationOptions options);
+#else
+ [Obsolete ("Use 'SetIconForFile' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
bool SetIconforFile (NSImage image, string fullPath, NSWorkspaceIconCreationOptions options);
+ [Wrap ("SetIconforFile (image, fullPath, options)")]
+ bool SetIconForFile (NSImage image, string fullPath, NSWorkspaceIconCreationOptions options);
+#endif
+
[Export ("fileLabels"), ThreadSafe]
string [] FileLabels { get; }
diff --git a/src/authenticationservices.cs b/src/authenticationservices.cs
index 6f24ea8c0327..8000f4d46cc0 100644
--- a/src/authenticationservices.cs
+++ b/src/authenticationservices.cs
@@ -5,6 +5,7 @@
//
using Security;
+using System.ComponentModel;
#if MONOMAC
using AppKit;
using UIControl = AppKit.NSControl;
@@ -1313,7 +1314,16 @@ interface ASWebAuthenticationSessionWebBrowserSessionManager {
[NoMacCatalyst]
[Static]
[Export ("registerDefaultsForASWASInSetupAssistantIfNeeded")]
+ void RegisterDefaultsForAsWasInSetupAssistantIfNeeded ();
+
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'RegisterDefaultsForAsWasInSetupAssistantIfNeeded' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ [Wrap ("RegisterDefaultsForAsWasInSetupAssistantIfNeeded ()")]
+ [NoMacCatalyst]
+ [Static]
void RegisterDefaultsForAswasInSetupAssistantIfNeeded ();
+#endif
}
diff --git a/src/avfoundation.cs b/src/avfoundation.cs
index fd36a24e0610..ad14eb0f6688 100644
--- a/src/avfoundation.cs
+++ b/src/avfoundation.cs
@@ -22471,8 +22471,18 @@ interface AVAssetDownloadDelegate : NSUrlSessionTaskDelegate {
[MacCatalyst (18, 0), iOS (18, 0)]
[Export ("URLSession:assetDownloadTask:willDownloadToURL:")]
+#if XAMCORE_5_0
+ void WillDownloadToUrl (NSUrlSession session, AVAssetDownloadTask assetDownloadTask, NSUrl location);
+#else
+ [Obsolete ("Use 'WillDownloadToUrl' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void WilllDownloadToUrl (NSUrlSession session, AVAssetDownloadTask assetDownloadTask, NSUrl location);
+ [MacCatalyst (18, 0), Mac (14, 0), iOS (18, 0)]
+ [Wrap ("WilllDownloadToUrl (session, assetDownloadTask, location)")]
+ void WillDownloadToUrl (NSUrlSession session, AVAssetDownloadTask assetDownloadTask, NSUrl location);
+#endif
+
[MacCatalyst (26, 0), NoTV, Mac (26, 0), iOS (26, 0)]
[Export ("URLSession:assetDownloadTask:didReceiveMetricEvent:")]
void DidReceiveMetricEvent (NSUrlSession session, AVAssetDownloadTask assetDownloadTask, AVMetricEvent metricEvent);
diff --git a/src/bgen/BindingTouch.cs b/src/bgen/BindingTouch.cs
index 7b9e2d32dadb..2744ae3f2547 100644
--- a/src/bgen/BindingTouch.cs
+++ b/src/bgen/BindingTouch.cs
@@ -587,7 +587,12 @@ public void LogError (string message)
Console.Error.WriteLine (message);
}
- public void LogError (Exception exception)
+ public void LogError (BindingException exception)
+ {
+ ErrorHelper.Show (exception);
+ }
+
+ public void LogWarning (BindingException exception)
{
ErrorHelper.Show (exception);
}
diff --git a/src/corebluetooth.cs b/src/corebluetooth.cs
index 56ee620ce7a4..11f9a99b29e5 100644
--- a/src/corebluetooth.cs
+++ b/src/corebluetooth.cs
@@ -1003,7 +1003,11 @@ interface CBPeripheralDelegate {
Event raised by the object.
If developers do not assign a value to this event, this will reset the value for the WeakDelegate property to an internal handler that maps delegates to events.
""")]
+#if XAMCORE_5_0
+ void UpdatedCharacteristicValue (CBPeripheral peripheral, CBCharacteristic characteristic, [NullAllowed] NSError error);
+#else
void UpdatedCharacterteristicValue (CBPeripheral peripheral, CBCharacteristic characteristic, [NullAllowed] NSError error);
+#endif
/// To be added.
/// To be added.
diff --git a/src/coreimage.cs b/src/coreimage.cs
index 18060e955e99..bf5dfae5b996 100644
--- a/src/coreimage.cs
+++ b/src/coreimage.cs
@@ -2693,8 +2693,17 @@ interface CIFilterGenerator : CIFilterConstructor, NSSecureCoding, NSCopying {
/// To be added.
/// To be added.
[Export ("setAttributes:forExportedKey:")]
+#if XAMCORE_5_0
+ void SetAttributes (NSDictionary attributes, NSString exportedKey);
+#else
+ [Obsolete ("Use 'SetAttributes' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void SetAttributesforExportedKey (NSDictionary attributes, NSString exportedKey);
+ [Wrap ("SetAttributesforExportedKey (attributes, exportedKey)")]
+ void SetAttributes (NSDictionary attributes, NSString exportedKey);
+#endif
+
/// To be added.
/// To be added.
/// To be added.
diff --git a/src/corespotlight.cs b/src/corespotlight.cs
index a06651792445..5ffae02dde82 100644
--- a/src/corespotlight.cs
+++ b/src/corespotlight.cs
@@ -2285,8 +2285,17 @@ interface CSSearchableItemAttributeSet : NSCopying, NSSecureCoding {
/// To be added.
[NullAllowed]
[Export ("GPSDifferental", ArgumentSemantic.Strong)]
+#if XAMCORE_5_0
+ NSNumber GpsDifferential { get; set; }
+#else
+ [Obsolete ("Use 'GpsDifferential' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
NSNumber GpsDifferental { get; set; }
+ [Wrap ("GpsDifferental")]
+ NSNumber GpsDifferential { get; set; }
+#endif
+
/// Gets or sets the fully formatted geographic address of the item.
///
/// Map Kit provides this address.
diff --git a/src/foundation.cs b/src/foundation.cs
index eb9795f2e0cf..33701bf60950 100644
--- a/src/foundation.cs
+++ b/src/foundation.cs
@@ -4705,7 +4705,14 @@ interface NSMetadataQuery {
/// To be added.
[NoTV, NoiOS, NoMacCatalyst]
[Field ("NSMetadataItemGPSDifferentalKey")]
+ NSString GpsDifferentialKey { get; }
+
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'GpsDifferentialKey' instead.")]
+ [NoTV, NoiOS, NoMacCatalyst]
+ [Wrap ("GpsDifferentialKey")]
NSString GpsDifferentalKey { get; }
+#endif
/// To be added.
/// To be added.
@@ -5438,7 +5445,11 @@ interface NSMetadataQueryDelegate {
Developers assign a function, delegate or anonymous method to this property to return a value to the object. If developers assign a value to this property, it this will reset the value for the Delegate property to an internal handler that maps delegates to events.
""")]
[Export ("metadataQuery:replacementValueForAttribute:value:"), DelegateName ("NSMetadataQueryValue"), DefaultValue (null)]
+#if XAMCORE_5_0
+ NSObject ReplacementValueForAttributeValue (NSMetadataQuery query, string attributeName, NSObject value);
+#else
NSObject ReplacementValueForAttributevalue (NSMetadataQuery query, string attributeName, NSObject value);
+#endif
}
[BaseType (typeof (NSObject))]
@@ -10041,7 +10052,15 @@ interface NSUrlCredential : NSSecureCoding, NSCopying {
[Static]
[Export ("credentialWithUser:password:persistence:")]
+ NSUrlCredential Create (string user, string password, NSUrlCredentialPersistence persistence);
+
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'Create' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ [Wrap ("Create (user, password, persistence)")]
+ [Static]
NSUrlCredential FromUserPasswordPersistance (string user, string password, NSUrlCredentialPersistence persistence);
+#endif
[Export ("user")]
string User { get; }
@@ -12299,8 +12318,17 @@ interface NSString2 : NSSecureCoding, NSMutableCopying, CKRecordValue
NSString ExpandTildeInPath ();
[Export ("stringByStandardizingPath")]
+#if XAMCORE_5_0
+ NSString StandardizePath ();
+#else
+ [Obsolete ("Use 'StandardizePath' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
NSString StandarizePath ();
+ [Wrap ("StandarizePath ()")]
+ NSString StandardizePath ();
+#endif
+
[Export ("stringByResolvingSymlinksInPath")]
NSString ResolveSymlinksInPath ();
@@ -12536,8 +12564,17 @@ interface NSMutableString : NSCoding {
[PreSnippet ("Check (range);", Optimizable = true)]
[Export ("replaceOccurrencesOfString:withString:options:range:")]
+#if XAMCORE_5_0
+ nuint ReplaceOccurrences (NSString target, NSString replacement, NSStringCompareOptions options, NSRange range);
+#else
+ [Obsolete ("Use 'ReplaceOccurrences' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
nuint ReplaceOcurrences (NSString target, NSString replacement, NSStringCompareOptions options, NSRange range);
+ [Wrap ("ReplaceOcurrences (target, replacement, options, range)")]
+ nuint ReplaceOccurrences (NSString target, NSString replacement, NSStringCompareOptions options, NSRange range);
+#endif
+
[MacCatalyst (13, 1)]
[EditorBrowsable (EditorBrowsableState.Advanced)]
[Export ("applyTransform:reverse:range:updatedRange:")]
@@ -15690,7 +15727,16 @@ interface NSNotificationQueue {
void EnqueueNotification (NSNotification notification, NSPostingStyle postingStyle, NSNotificationCoalescing coalesceMask, [NullAllowed] NSRunLoopMode [] modes);
[Export ("dequeueNotificationsMatching:coalesceMask:")]
+#if XAMCORE_5_0
+ void DequeueNotifications (NSNotification notification, NSNotificationCoalescing coalesceMask);
+#else
+ [Obsolete ("Use 'DequeueNotifications' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void DequeueNotificationsMatchingcoalesceMask (NSNotification notification, NSNotificationCoalescing coalesceMask);
+
+ [Wrap ("DequeueNotificationsMatchingcoalesceMask (notification, coalesceMask)")]
+ void DequeueNotifications (NSNotification notification, NSNotificationCoalescing coalesceMask);
+#endif
}
[BaseType (typeof (NSObject))]
@@ -18675,8 +18721,17 @@ interface NSDirectoryEnumerator {
NSDictionary DirectoryAttributes { get; }
[Export ("skipDescendents")]
+#if XAMCORE_5_0
+ void SkipDescendants ();
+#else
+ [Obsolete ("Use 'SkipDescendants' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void SkipDescendents ();
+ [Wrap ("SkipDescendents ()")]
+ void SkipDescendants ();
+#endif
+
[NoMac]
[MacCatalyst (13, 1)]
[Export ("level")]
@@ -20395,8 +20450,17 @@ interface NSAppleEventDescriptor : NSSecureCoding, NSCopying {
AETransactionID TransactionID ();*/
[Export ("setParamDescriptor:forKeyword:")]
+#if XAMCORE_5_0
+ void SetParamDescriptor (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+#else
+ [Obsolete ("Use 'SetParamDescriptor' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void SetParamDescriptorforKeyword (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+ [Wrap ("SetParamDescriptorforKeyword (descriptor, keyword)")]
+ void SetParamDescriptor (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+#endif
+
[return: NullAllowed]
[Export ("paramDescriptorForKeyword:")]
NSAppleEventDescriptor ParamDescriptorForKeyword (AEKeyword keyword);
@@ -20405,8 +20469,17 @@ interface NSAppleEventDescriptor : NSSecureCoding, NSCopying {
void RemoveParamDescriptorWithKeyword (AEKeyword keyword);
[Export ("setAttributeDescriptor:forKeyword:")]
+#if XAMCORE_5_0
+ void SetAttributeDescriptor (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+#else
+ [Obsolete ("Use 'SetAttributeDescriptor' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void SetAttributeDescriptorforKeyword (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+ [Wrap ("SetAttributeDescriptorforKeyword (descriptor, keyword)")]
+ void SetAttributeDescriptor (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+#endif
+
[return: NullAllowed]
[Export ("attributeDescriptorForKeyword:")]
NSAppleEventDescriptor AttributeDescriptorForKeyword (AEKeyword keyword);
@@ -20419,8 +20492,17 @@ interface NSAppleEventDescriptor : NSSecureCoding, NSCopying {
/// To be added.
/// To be added.
[Export ("insertDescriptor:atIndex:")]
+#if XAMCORE_5_0
+ void InsertDescriptor (NSAppleEventDescriptor descriptor, nint index);
+#else
+ [Obsolete ("Use 'InsertDescriptor' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void InsertDescriptoratIndex (NSAppleEventDescriptor descriptor, nint index);
+ [Wrap ("InsertDescriptoratIndex (descriptor, index)")]
+ void InsertDescriptor (NSAppleEventDescriptor descriptor, nint index);
+#endif
+
/// To be added.
/// To be added.
/// To be added.
@@ -20436,8 +20518,17 @@ interface NSAppleEventDescriptor : NSSecureCoding, NSCopying {
void RemoveDescriptorAtIndex (nint index);
[Export ("setDescriptor:forKeyword:")]
+#if XAMCORE_5_0
+ void SetDescriptor (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+#else
+ [Obsolete ("Use 'SetDescriptor' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void SetDescriptorforKeyword (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+ [Wrap ("SetDescriptorforKeyword (descriptor, keyword)")]
+ void SetDescriptor (NSAppleEventDescriptor descriptor, AEKeyword keyword);
+#endif
+
[return: NullAllowed]
[Export ("descriptorForKeyword:")]
NSAppleEventDescriptor DescriptorForKeyword (AEKeyword keyword);
diff --git a/src/gamekit.cs b/src/gamekit.cs
index ed2a9c4f654e..011d8274b11a 100644
--- a/src/gamekit.cs
+++ b/src/gamekit.cs
@@ -14,6 +14,8 @@
#pragma warning disable 618
+using System.ComponentModel;
+
using CoreFoundation;
using CoreGraphics;
#if MONOMAC
@@ -3021,8 +3023,18 @@ interface GKTurnBasedMatch {
[MacCatalyst (13, 1)]
[Export ("exchangeDataMaximumSize")]
+#if XAMCORE_5_0
+ nuint ExchangeDataMaximumSize { get; }
+#else
+ [Obsolete ("Use 'ExchangeDataMaximumSize' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
nuint ExhangeDataMaximumSize { get; }
+ [MacCatalyst (13, 1)]
+ [Wrap ("ExhangeDataMaximumSize")]
+ nuint ExchangeDataMaximumSize { get; }
+#endif
+
[MacCatalyst (13, 1)]
[Export ("exchangeMaxInitiatedExchangesPerPlayer")]
nuint ExchangeMaxInitiatedExchangesPerPlayer { get; }
diff --git a/src/imageio.cs b/src/imageio.cs
index 1f911ab838fb..5bb76f52546c 100644
--- a/src/imageio.cs
+++ b/src/imageio.cs
@@ -369,11 +369,14 @@ interface CGImageProperties {
/// To be added.
[Field ("kCGImagePropertyExifSubsecTime")]
NSString ExifSubsecTime { get; }
+#if !XAMCORE_5_0
/// Represents the value associated with the constant kCGImagePropertyExifSubsecTimeOrginal
/// To be added.
/// To be added.
+ [Obsolete ("Use 'ExifSubsecTimeOriginal' instead.")]
[Field ("kCGImagePropertyExifSubsecTimeOrginal")]
NSString ExifSubsecTimeOrginal { get; }
+#endif
/// Represents the value associated with the constant kCGImagePropertyExifSubsecTimeOriginal.
/// To be added.
/// To be added.
@@ -830,11 +833,20 @@ interface CGImageProperties {
/// To be added.
[Field ("kCGImagePropertyGPSDateStamp")]
NSString GPSDateStamp { get; }
+ /// Represents the value associated with the constant kCGImagePropertyGPSDifferental.
+ /// To be added.
+ /// To be added.
+ [Field ("kCGImagePropertyGPSDifferental")]
+ NSString GPSDifferential { get; }
+
+#if !XAMCORE_5_0
/// Represents the value associated with the constant kCGImagePropertyGPSDifferental
/// To be added.
/// To be added.
+ [Obsolete ("Use 'GPSDifferential' instead.")]
[Field ("kCGImagePropertyGPSDifferental")]
NSString GPSDifferental { get; }
+#endif
/// Represents the value associated with the constant kCGImagePropertyGPSHPositioningError
/// To be added.
diff --git a/src/imagekit.cs b/src/imagekit.cs
index c1e5dafac0a4..3bc3dea8fed5 100644
--- a/src/imagekit.cs
+++ b/src/imagekit.cs
@@ -31,6 +31,7 @@
using ImageCaptureCore;
using CoreGraphics;
using CoreAnimation;
+using System.ComponentModel;
namespace ImageKit {
@@ -2028,7 +2029,15 @@ interface IKSlideshow {
/// To be added.
[Static]
[Export ("exportSlideshowItem:toApplication:")]
+ void ExportSlideshowItem (NSObject item, string applicationBundleIdentifier);
+
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'ExportSlideshowItem' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ [Wrap ("ExportSlideshowItem (item, applicationBundleIdentifier)")]
+ [Static]
void ExportSlideshowItemtoApplication (NSObject item, string applicationBundleIdentifier);
+#endif
/// To be added.
/// To be added.
diff --git a/src/mapkit.cs b/src/mapkit.cs
index 829a1f8e63c1..6d46ec29e2c5 100644
--- a/src/mapkit.cs
+++ b/src/mapkit.cs
@@ -14,6 +14,7 @@
using CoreFoundation;
using CoreGraphics;
using CoreLocation;
+using System.ComponentModel;
#if MONOMAC
using AppKit;
using UITraitCollection = System.Int32;
@@ -216,8 +217,20 @@ interface MKAnnotationView {
[NoTV]
[MacCatalyst (13, 1)]
[Export ("rightCalloutOffset")]
+#if XAMCORE_5_0
+ CGPoint RightCalloutOffset { get; set; }
+#else
+ [Obsolete ("Use 'RightCalloutOffset' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
CGPoint RightCallpoutOffset { get; set; }
+ [NoiOS]
+ [NoTV]
+ [MacCatalyst (13, 1)]
+ [Wrap ("RightCallpoutOffset")]
+ CGPoint RightCalloutOffset { get; set; }
+#endif
+
[MacCatalyst (13, 1)]
[NullAllowed, Export ("clusteringIdentifier")]
string ClusteringIdentifier { get; set; }
diff --git a/src/metalperformanceshadersgraph.cs b/src/metalperformanceshadersgraph.cs
index a06bb87a45cd..9c9a49e725a2 100644
--- a/src/metalperformanceshadersgraph.cs
+++ b/src/metalperformanceshadersgraph.cs
@@ -2,6 +2,7 @@
using CoreGraphics;
using Metal;
using MetalPerformanceShaders;
+using System.ComponentModel;
using MPSGraphTensorDataDictionary = Foundation.NSDictionary;
using MPSGraphTensorShapedTypeDictionary = Foundation.NSDictionary;
@@ -2477,8 +2478,17 @@ interface MPSGraphFftDescriptor : NSCopying {
MPSGraphFftScalingMode ScalingMode { get; set; }
[Export ("roundToOddHermitean")]
+#if XAMCORE_5_0
+ bool RoundToOddHermitian { get; set; }
+#else
+ [Obsolete ("Use 'RoundToOddHermitian' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
bool RoundToOddHermitean { get; set; }
+ [Wrap ("RoundToOddHermitean")]
+ bool RoundToOddHermitian { get; set; }
+#endif
+
[Static]
[Export ("descriptor")]
[return: NullAllowed]
diff --git a/src/mlcompute.cs b/src/mlcompute.cs
index ee16476111f7..7130d7ac33d7 100644
--- a/src/mlcompute.cs
+++ b/src/mlcompute.cs
@@ -1,5 +1,6 @@
using Metal;
+using System.ComponentModel;
namespace MLCompute {
@@ -108,7 +109,12 @@ enum MLCDataType {
Float16 = 3,
Boolean = 4,
Int64 = 5,
- Inot32 = 7,
+ Int32 = 7,
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'Int32' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ Inot32 = Int32,
+#endif
[iOS (15, 0), TV (15, 0), MacCatalyst (15, 0)]
Int8 = 8,
[iOS (15, 0), TV (15, 0), MacCatalyst (15, 0)]
diff --git a/src/uikit.cs b/src/uikit.cs
index badf39507942..689655e14e47 100644
--- a/src/uikit.cs
+++ b/src/uikit.cs
@@ -10256,7 +10256,16 @@ interface UILocalizedIndexedCollation {
nint GetSectionForObject (NSObject obj, Selector collationStringSelector);
[Export ("sortedArrayFromArray:collationStringSelector:")]
+#if XAMCORE_5_0
+ NSObject [] SortedArrayFromArrayCollationStringSelector (NSObject [] array, Selector collationStringSelector);
+#else
+ [Obsolete ("Use 'SortedArrayFromArrayCollationStringSelector' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
NSObject [] SortedArrayFromArraycollationStringSelector (NSObject [] array, Selector collationStringSelector);
+
+ [Wrap ("SortedArrayFromArraycollationStringSelector (array, collationStringSelector)")]
+ NSObject [] SortedArrayFromArrayCollationStringSelector (NSObject [] array, Selector collationStringSelector);
+#endif
}
/// Creates time-based notifications that the operating system delivers to the user.
@@ -16588,8 +16597,17 @@ interface UISearchBar : UIBarPositioning, UITextInputTraits, UILookToDictateCapa
/// To be added.
[Export ("setImage:forSearchBarIcon:state:")]
[Appearance]
+#if XAMCORE_5_0
+ void SetImageForSearchBarIcon ([NullAllowed] UIImage iconImage, UISearchBarIcon icon, UIControlState state);
+#else
+ [Obsolete ("Use 'SetImageForSearchBarIcon' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void SetImageforSearchBarIcon ([NullAllowed] UIImage iconImage, UISearchBarIcon icon, UIControlState state);
+ [Wrap ("SetImageforSearchBarIcon (iconImage, icon, state)")]
+ void SetImageForSearchBarIcon ([NullAllowed] UIImage iconImage, UISearchBarIcon icon, UIControlState state);
+#endif
+
/// To be added.
/// To be added.
/// The image for the specified search bar icon type and control state.
@@ -16644,8 +16662,17 @@ interface UISearchBar : UIBarPositioning, UITextInputTraits, UILookToDictateCapa
[Appearance]
[Export ("setPositionAdjustment:forSearchBarIcon:")]
+#if XAMCORE_5_0
+ void SetPositionAdjustmentForSearchBarIcon (UIOffset adjustment, UISearchBarIcon icon);
+#else
+ [Obsolete ("Use 'SetPositionAdjustmentForSearchBarIcon' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
void SetPositionAdjustmentforSearchBarIcon (UIOffset adjustment, UISearchBarIcon icon);
+ [Wrap ("SetPositionAdjustmentforSearchBarIcon (adjustment, icon)")]
+ void SetPositionAdjustmentForSearchBarIcon (UIOffset adjustment, UISearchBarIcon icon);
+#endif
+
[Appearance]
[Export ("positionAdjustmentForSearchBarIcon:")]
UIOffset GetPositionAdjustmentForSearchBarIcon (UISearchBarIcon icon);
@@ -24414,7 +24441,15 @@ interface UITextChecker {
[Static]
[Export ("availableLanguages")]
+ string AvailableLanguages { get; }
+
+#if !XAMCORE_5_0
+ [Obsolete ("Use 'AvailableLanguages' instead.")]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ [Wrap ("AvailableLanguages")]
+ [Static]
string AvailableLangauges { get; }
+#endif
}
/// Known values for that are hints to the system of the kind of data.
diff --git a/src/webkit.cs b/src/webkit.cs
index 3307429c8ab5..fd06672beaea 100644
--- a/src/webkit.cs
+++ b/src/webkit.cs
@@ -2158,7 +2158,11 @@ partial interface WebFrameLoadDelegate {
To be added.
To be added.
""")]
+#if XAMCORE_5_0
+ void CommittedLoad (WebView sender, WebFrame forFrame);
+#else
void CommitedLoad (WebView sender, WebFrame forFrame);
+#endif
/// To be added.
/// To be added.
diff --git a/tests/assembly-preparer/BaseClass.cs b/tests/assembly-preparer/BaseClass.cs
new file mode 100644
index 000000000000..93e3f02a0011
--- /dev/null
+++ b/tests/assembly-preparer/BaseClass.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AssemblyPreparerTests;
+
+public abstract class BaseClass {
+ public void AssertPrepare (AssemblyPreparer preparer)
+ {
+ if (!preparer.Prepare (out var exceptions)) {
+ foreach (var ex in exceptions) {
+ Console.WriteLine (ex.ToString ());
+ if (ex.InnerException is not null)
+ Console.WriteLine ($" Inner: {ex.InnerException}");
+ }
+ Assert.Fail ($"Prepare failed, exceptions:\n\t{string.Join ("\n\t", exceptions.Select (v => v.ToString ()))}");
+ }
+ Assert.That (exceptions, Is.Empty, "Exceptions");
+ }
+
+ public bool AssertPrepare (ApplePlatform platform, bool isCoreCLR, string code, out AssemblyDefinition assemblyDefinition)
+ {
+ return AssertPrepare (platform, isCoreCLR, RegistrarMode.Dynamic, code, out assemblyDefinition);
+ }
+
+ // returns true if the test assembly was modified
+ public bool AssertPrepare (ApplePlatform platform, bool isCoreCLR, RegistrarMode registrar, string code, out AssemblyDefinition assemblyDefinition)
+ {
+ AssemblyPreparer? preparer = null;
+ var rv = AssertPrepareCode (platform, isCoreCLR, p => {
+ p.Registrar = registrar;
+ preparer = p;
+ }, code, out string outputPath);
+ var resolver = new DefaultAssemblyResolver ();
+ var dirs = preparer!.Assemblies.Select (v => Path.GetDirectoryName (v.OutputPath)).Distinct ().ToList ();
+ dirs.ForEach (v => resolver.AddSearchDirectory (v));
+ var readerParameters = new ReaderParameters {
+ ReadSymbols = true,
+ AssemblyResolver = resolver,
+ };
+ assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath, readerParameters);
+ return rv;
+ }
+
+ // returns true if the test assembly was modified
+ public bool AssertPrepareCode (ApplePlatform platform, bool isCoreCLR, Action? configure, string code, out string outputPath)
+ {
+ Configuration.IgnoreIfIgnoredPlatform (platform);
+
+ var csproj = $@"
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-{platform.AsString ().ToLower ()}
+ false
+ true
+
+
+ ";
+
+ var tmpdir = Xamarin.Cache.CreateTemporaryDirectory ();
+
+ var config = $@"
+ AreAnyAssembliesTrimmed=true
+ PublishTrimmed=true
+ IntermediateOutputPath={Path.Combine (tmpdir, "intermediate")}
+ Platform={platform.AsString ()}
+ PlatformAssembly=Microsoft.{platform.AsString ()}.dll
+ SdkDevPath={Configuration.XcodeLocation}
+ SdkVersion={Configuration.GetSdkVersion (platform)}
+ TargetFramework={TargetFramework.GetTargetFramework (platform)}
+ ";
+ var configpath = Path.Combine (tmpdir, "config.txt");
+ File.WriteAllText (configpath, config);
+
+ File.WriteAllText (Path.Combine (tmpdir, "Test.cs"), code);
+ var csprojPath = Path.Combine (tmpdir, "Test.csproj");
+ File.WriteAllText (csprojPath, csproj);
+ var properties = new Dictionary {
+ { "TreatWarningsAsErrors", "false" },
+ };
+ DotNet.AssertBuild (csprojPath, properties);
+ var assemblyDir = Path.Combine (tmpdir, "bin", "Debug");
+
+ var assemblies = Configuration.GetImplementationAssemblies (platform, isCoreCLR);
+ assemblies.Add (Path.Combine (assemblyDir, "Test.dll"));
+ var infos = assemblies.Select (v => new AssemblyPreparerInfo (v, Path.Combine (assemblyDir, "out", Path.GetFileName (v)), true, "link")).ToArray ();
+ var logger = new TestLogger () { Platform = platform };
+ var preparer = new AssemblyPreparer (logger, infos, configpath);
+ if (configure is not null)
+ configure (preparer);
+ AssertPrepare (preparer);
+
+ var testInfo = infos.Single (v => Path.GetFileNameWithoutExtension (v.InputPath) == "Test");
+ outputPath = testInfo.OutputPath;
+ Console.WriteLine ("Output assembly: " + outputPath);
+ preparer.Dispose ();
+ return testInfo.InputPath != testInfo.OutputPath;
+ }
+}
diff --git a/tests/assembly-preparer/GlobalUsings.cs b/tests/assembly-preparer/GlobalUsings.cs
new file mode 100644
index 000000000000..4e06615734f1
--- /dev/null
+++ b/tests/assembly-preparer/GlobalUsings.cs
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+global using System.IO;
+global using System.Runtime.InteropServices;
+
+global using Mono.Cecil;
+global using NUnit.Framework;
+
+global using Xamarin;
+global using Xamarin.Bundler;
+global using Xamarin.Build;
+global using Xamarin.Tests;
+global using Xamarin.Utils;
+
+// These tests are rather memory hungry, so running them in parallel really makes my machine crawl.
+// [assembly: Parallelizable (ParallelScope.Children)]
diff --git a/tests/assembly-preparer/InlineDlfcnMethodsStepTests.cs b/tests/assembly-preparer/InlineDlfcnMethodsStepTests.cs
new file mode 100644
index 000000000000..fa0d1f66f6a4
--- /dev/null
+++ b/tests/assembly-preparer/InlineDlfcnMethodsStepTests.cs
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+
+namespace AssemblyPreparerTests;
+
+public class InlineDlfcnMethodsStepTests : BaseClass {
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void MarkedTest (ApplePlatform platform, bool isCoreCLR)
+ {
+ var code = @"
+ using System;
+ using CoreAnimation;
+ using Foundation;
+ using ObjCRuntime;
+
+ class MyClass : NSObject {
+ void GetIntPtr ()
+ {
+ Console.WriteLine (Dlfcn.GetIntPtr (0, ""NativeSymbol""));
+ }
+ }";
+
+ AssertPrepare (platform, isCoreCLR, code, out var assemblyDefinition);
+
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
+ var platformReference = assemblyDefinition.MainModule.AssemblyReferences.Single (v => v.Name == $"Microsoft.{platform.AsString ()}");
+ var platformAssembly = assemblyDefinition.MainModule.AssemblyResolver.Resolve (platformReference);
+ var dlfcn = platformAssembly.MainModule.Types.Single (v => v.Name == "Dlfcn");
+
+ var cctor = type.GetStaticConstructor ();
+ Assert.That (cctor, Is.Null, "No static constructor should be needed.");
+
+ void AssertHasDlfcnPInvokeCall (MethodDefinition method)
+ {
+ var instructions = method.Body.Instructions;
+ var call = instructions.FirstOrDefault (v => v.OpCode == OpCodes.Call && v.Operand is MethodReference mr && mr.DeclaringType.FullName == dlfcn.FullName);
+ Assert.That (call, Is.Not.Null, $"Expected a call to Dlfcn in {method}");
+ var resolvedMethod = ((MethodReference) call.Operand).Resolve ();
+ Assert.That (resolvedMethod, Is.Not.Null, $"Expected the call to resolve to a method in Dlfcn for {method}");
+ Assert.That (resolvedMethod.PInvokeInfo, Is.Null, $"Expected the method to not be a PInvoke method for {method}");
+ }
+
+ Assert.Multiple (() => {
+ AssertHasDlfcnPInvokeCall (type.Methods.Single (v => v.Name == "GetIntPtr"));
+ });
+ }
+}
diff --git a/tests/assembly-preparer/Makefile b/tests/assembly-preparer/Makefile
new file mode 100644
index 000000000000..b01174cb5734
--- /dev/null
+++ b/tests/assembly-preparer/Makefile
@@ -0,0 +1,8 @@
+TOP=../..
+include $(TOP)/Make.config
+
+build:
+ $(DOTNET) build *.csproj
+
+run-tests:
+ $(DOTNET) test *.csproj
diff --git a/tests/assembly-preparer/MarkIProtocolHandlerTests.cs b/tests/assembly-preparer/MarkIProtocolHandlerTests.cs
new file mode 100644
index 000000000000..fb7f0fcd41dd
--- /dev/null
+++ b/tests/assembly-preparer/MarkIProtocolHandlerTests.cs
@@ -0,0 +1,73 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Mono.Cecil.Rocks;
+
+namespace AssemblyPreparerTests;
+
+public class MarkIProtocolHandlerTests : BaseClass {
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void DynamicRegistrar (ApplePlatform platform, bool isCoreCLR)
+ {
+ var code = @"
+ using System;
+ using Foundation;
+ using ObjCRuntime;
+
+ [Protocol]
+ interface IProtocol {
+ }
+
+ class MyClass : NSObject, IProtocol {
+ }
+ ";
+
+ AssertPrepare (platform, isCoreCLR, RegistrarMode.Dynamic, code, out var assemblyDefinition);
+
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
+ var cctor = type.GetStaticConstructor ();
+ Assert.That (cctor, Is.Not.Null, "Expected a static constructor to be added");
+ var attribs = cctor.CustomAttributes?.Where (v => v.AttributeType.Name == "DynamicDependencyAttribute").OrderBy (v => string.Join (", ", v.ConstructorArguments.Select (v => v.Value?.ToString ()))).ToArray ();
+ Assert.That (attribs, Is.Not.Null, "Attributes");
+ Assert.That (attribs.Count, Is.EqualTo (1), "Attribute count");
+ // PreserveProtocolsStep adds DDA(DynamicallyAccessedMemberTypes.Interfaces, typeof(MyClass))
+ Assert.That ((int) attribs [0].ConstructorArguments [0].Value, Is.EqualTo (0x2000), "First attribute's first argument (DynamicallyAccessedMemberTypes.Interfaces)");
+ Assert.That (((TypeReference) attribs [0].ConstructorArguments [1].Value).FullName, Is.EqualTo ("MyClass"), "First attribute's second argument");
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void ManagedStaticRegistrar (ApplePlatform platform, bool isCoreCLR)
+ {
+ var code = @"
+ using System;
+ using Foundation;
+ using ObjCRuntime;
+
+ [Protocol]
+ interface IProtocol {
+ }
+
+ class MyClass : NSObject, IProtocol {
+ }
+ ";
+
+ // With ManagedStatic registrar, PreserveProtocolsStep doesn't run,
+ // so MyClass's cctor should not have any DDA for protocol preservation.
+ AssertPrepare (platform, isCoreCLR, RegistrarMode.ManagedStatic, code, out var assemblyDefinition);
+
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
+ var cctor = type.GetStaticConstructor ();
+ if (cctor is not null) {
+ var ddaAttribs = cctor.CustomAttributes?.Where (v => v.AttributeType.Name == "DynamicDependencyAttribute").ToArray ();
+ Assert.That (ddaAttribs, Is.Empty, "No DynamicDependencyAttributes expected on MyClass's cctor");
+ }
+ }
+}
diff --git a/tests/assembly-preparer/OptimizeGeneratedCodeHandlerTests.cs b/tests/assembly-preparer/OptimizeGeneratedCodeHandlerTests.cs
new file mode 100644
index 000000000000..5a5ee83d47e4
--- /dev/null
+++ b/tests/assembly-preparer/OptimizeGeneratedCodeHandlerTests.cs
@@ -0,0 +1,251 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+
+namespace AssemblyPreparerTests;
+
+public class OptimizeGeneratedCodeHandlerTests : BaseClass {
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void RemoveEnsureUIThread (ApplePlatform platform, bool isCoreCLR)
+ {
+ var ensureUIThreadCall = platform == ApplePlatform.MacOSX
+ ? "AppKit.NSApplication.EnsureUIThread ();"
+ : "UIKit.UIApplication.EnsureUIThread ();";
+
+ var usingDirective = platform == ApplePlatform.MacOSX
+ ? "using AppKit;"
+ : "using UIKit;";
+
+ var code = $@"
+ using System;
+ using Foundation;
+ using ObjCRuntime;
+ {usingDirective}
+
+ class MyClass : NSObject {{
+ [BindingImpl (BindingImplOptions.Optimizable)]
+ [Export (""myMethod"")]
+ public void MyMethod () {{
+ {ensureUIThreadCall}
+ }}
+ }}";
+
+ AssertPrepareCode (platform, isCoreCLR, preparer => {
+ preparer.Registrar = RegistrarMode.Dynamic;
+ preparer.Optimizations.RemoveUIThreadChecks = true;
+ }, code, out var outputPath);
+
+ using var assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath);
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
+ var method = type.Methods.Single (v => v.Name == "MyMethod");
+
+ var hasEnsureUIThread = method.Body.Instructions.Any (i =>
+ i.OpCode.Code == Code.Call &&
+ (i.Operand as MethodReference)?.Name == "EnsureUIThread");
+ Assert.That (hasEnsureUIThread, Is.False, "EnsureUIThread call should be removed");
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void KeepEnsureUIThreadWhenOptimizationDisabled (ApplePlatform platform, bool isCoreCLR)
+ {
+ var ensureUIThreadCall = platform == ApplePlatform.MacOSX
+ ? "AppKit.NSApplication.EnsureUIThread ();"
+ : "UIKit.UIApplication.EnsureUIThread ();";
+
+ var usingDirective = platform == ApplePlatform.MacOSX
+ ? "using AppKit;"
+ : "using UIKit;";
+
+ var code = $@"
+ using System;
+ using Foundation;
+ using ObjCRuntime;
+ {usingDirective}
+
+ class MyClass : NSObject {{
+ [BindingImpl (BindingImplOptions.Optimizable)]
+ [Export (""myMethod"")]
+ public void MyMethod () {{
+ {ensureUIThreadCall}
+ }}
+ }}";
+
+ AssertPrepareCode (platform, isCoreCLR, preparer => {
+ preparer.Registrar = RegistrarMode.Dynamic;
+ preparer.Optimizations.RemoveUIThreadChecks = false;
+ }, code, out var outputPath);
+
+ using var assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath);
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
+ var method = type.Methods.Single (v => v.Name == "MyMethod");
+
+ var hasEnsureUIThread = method.Body.Instructions.Any (i =>
+ i.OpCode.Code == Code.Call &&
+ (i.Operand as MethodReference)?.Name == "EnsureUIThread");
+ Assert.That (hasEnsureUIThread, Is.True, "EnsureUIThread call should be preserved when optimization is disabled");
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void OptimizeProtocolInterfaceStaticConstructor (ApplePlatform platform, bool isCoreCLR)
+ {
+ var code = @"
+ using System;
+ using Foundation;
+ using ObjCRuntime;
+
+ [Protocol]
+ interface IMyProtocol {
+ [BindingImpl (BindingImplOptions.Optimizable)]
+ static IMyProtocol () {
+ GC.KeepAlive (null);
+ }
+ }
+
+ class MyClass : NSObject, IMyProtocol {
+ }";
+
+ AssertPrepareCode (platform, isCoreCLR, preparer => {
+ preparer.Registrar = RegistrarMode.Dynamic;
+ preparer.Optimizations.RegisterProtocols = true;
+ }, code, out var outputPath);
+
+ using var assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath);
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "IMyProtocol");
+ var cctor = type.GetStaticConstructor ();
+
+ Assert.That (cctor, Is.Not.Null, "Static constructor should still exist");
+ Assert.That (cctor.Body.Instructions.Count, Is.EqualTo (1), "Static constructor should have only a ret instruction");
+ Assert.That (cctor.Body.Instructions [0].OpCode.Code, Is.EqualTo (Code.Ret), "Static constructor should only contain ret");
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void KeepProtocolStaticConstructorWhenOptimizationDisabled (ApplePlatform platform, bool isCoreCLR)
+ {
+ var code = @"
+ using System;
+ using Foundation;
+ using ObjCRuntime;
+
+ [Protocol]
+ interface IMyProtocol {
+ [BindingImpl (BindingImplOptions.Optimizable)]
+ static IMyProtocol () {
+ GC.KeepAlive (null);
+ }
+ }
+
+ class MyClass : NSObject, IMyProtocol {
+ }";
+
+ AssertPrepareCode (platform, isCoreCLR, preparer => {
+ preparer.Registrar = RegistrarMode.Dynamic;
+ preparer.Optimizations.RegisterProtocols = false;
+ }, code, out var outputPath);
+
+ using var assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath);
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "IMyProtocol");
+ var cctor = type.GetStaticConstructor ();
+
+ Assert.That (cctor, Is.Not.Null, "Static constructor should still exist");
+ Assert.That (cctor.Body.Instructions.Count, Is.GreaterThan (1), "Static constructor should not be optimized");
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void NoOptimizationWithoutBindingAttributes (ApplePlatform platform, bool isCoreCLR)
+ {
+ var ensureUIThreadCall = platform == ApplePlatform.MacOSX
+ ? "AppKit.NSApplication.EnsureUIThread ();"
+ : "UIKit.UIApplication.EnsureUIThread ();";
+
+ var usingDirective = platform == ApplePlatform.MacOSX
+ ? "using AppKit;"
+ : "using UIKit;";
+
+ var code = $@"
+ using System;
+ using Foundation;
+ using ObjCRuntime;
+ {usingDirective}
+
+ class MyClass : NSObject {{
+ [Export (""myMethod"")]
+ public void MyMethod () {{
+ {ensureUIThreadCall}
+ }}
+ }}";
+
+ AssertPrepareCode (platform, isCoreCLR, preparer => {
+ preparer.Registrar = RegistrarMode.Dynamic;
+ preparer.Optimizations.RemoveUIThreadChecks = true;
+ }, code, out var outputPath);
+
+ using var assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath);
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
+ var method = type.Methods.Single (v => v.Name == "MyMethod");
+
+ var hasEnsureUIThread = method.Body.Instructions.Any (i =>
+ i.OpCode.Code == Code.Call &&
+ (i.Operand as MethodReference)?.Name == "EnsureUIThread");
+ Assert.That (hasEnsureUIThread, Is.True, "EnsureUIThread call should be preserved without [BindingImpl(Optimizable)]");
+ }
+
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void DeadCodeElimination (ApplePlatform platform, bool isCoreCLR)
+ {
+ var code = @"
+ using System;
+ using Foundation;
+ using ObjCRuntime;
+
+ class MyClass : NSObject {
+ [BindingImpl (BindingImplOptions.Optimizable)]
+ [Export (""myMethod"")]
+ public int MyMethod () {
+ if (true) {
+ return 1;
+ }
+ return 2;
+ }
+ }";
+
+ AssertPrepareCode (platform, isCoreCLR, preparer => {
+ preparer.Registrar = RegistrarMode.Dynamic;
+ preparer.Optimizations.DeadCodeElimination = true;
+ }, code, out var outputPath);
+
+ using var assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath);
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
+ var method = type.Methods.Single (v => v.Name == "MyMethod");
+
+ // After dead code elimination, there should be no ldc.i4.2 (the unreachable return 2)
+ var hasDeadCode = method.Body.Instructions.Any (i =>
+ i.OpCode.Code == Code.Ldc_I4_2);
+ Assert.That (hasDeadCode, Is.False, "Dead code (return 2) should be eliminated");
+ }
+}
diff --git a/tests/assembly-preparer/PreserveBlockCodeHandlerTests.cs b/tests/assembly-preparer/PreserveBlockCodeHandlerTests.cs
new file mode 100644
index 000000000000..ad39cd811c5c
--- /dev/null
+++ b/tests/assembly-preparer/PreserveBlockCodeHandlerTests.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Mono.Cecil.Rocks;
+
+namespace AssemblyPreparerTests;
+
+public class PreserveBlockCodeHandlerTests : BaseClass {
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void MarkedTest (ApplePlatform platform, bool isCoreCLR)
+ {
+ var code = @"
+ using System;
+ using ObjCRuntime;
+ namespace ObjCRuntime;
+ class Trampolines {
+ static internal class SDInnerBlock {
+ // this field is not preserved by other means, but it must not be linked away
+ static internal readonly DInnerBlock Handler = Invoke;
+
+ [MonoPInvokeCallback (typeof (DInnerBlock))]
+ static internal void Invoke (IntPtr block, int magic_number)
+ {
+ }
+
+ public delegate void DInnerBlock (IntPtr block, int magic_number);
+ }
+ }";
+
+ AssertPrepare (platform, isCoreCLR, code, out var assemblyDefinition);
+
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "Trampolines").NestedTypes.Single (v => v.Name == "SDInnerBlock");
+ var cctor = type.GetStaticConstructor ();
+ var attribs = cctor.CustomAttributes?.OrderBy (v => string.Join (", ", v.ConstructorArguments.Select (v => v.Value?.ToString ()))).ToArray ();
+ Assert.That (attribs, Is.Not.Null, "Attributes");
+ Assert.That (attribs.Count, Is.EqualTo (2), "Attribute count");
+ Assert.That (attribs.All (v => v.AttributeType.Name == "DynamicDependencyAttribute"), Is.True, "Attribute name");
+ // Handler field: DDA(string memberSignature, string typeName, string assemblyName)
+ Assert.That (attribs [0].ConstructorArguments.Count, Is.EqualTo (3), "First attribute's argument count");
+ Assert.That ((string) attribs [0].ConstructorArguments [0].Value, Is.EqualTo ("Handler"), "First attribute's first argument");
+ Assert.That ((string) attribs [0].ConstructorArguments [1].Value, Is.EqualTo ("ObjCRuntime.Trampolines.SDInnerBlock"), "First attribute's second argument");
+ Assert.That ((string) attribs [0].ConstructorArguments [2].Value, Is.EqualTo ("Test"), "First attribute's third argument");
+
+ // Invoke method: DDA(string memberSignature) - same declaring type, so simpler constructor
+ Assert.That (attribs [1].ConstructorArguments.Count, Is.EqualTo (1), "Second attribute's argument count");
+ Assert.That ((string) attribs [1].ConstructorArguments [0].Value, Is.EqualTo ("Invoke(System.IntPtr,System.Int32)"), "Second attribute's first argument");
+ }
+}
diff --git a/tests/assembly-preparer/PreserveSmartEnumConversionsTest.cs b/tests/assembly-preparer/PreserveSmartEnumConversionsTest.cs
new file mode 100644
index 000000000000..7c690caa9037
--- /dev/null
+++ b/tests/assembly-preparer/PreserveSmartEnumConversionsTest.cs
@@ -0,0 +1,119 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Mono.Cecil.Rocks;
+
+namespace AssemblyPreparerTests;
+
+public class PreserveSmartEnumConversionsTests : BaseClass {
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst, false)]
+ [TestCase (ApplePlatform.iOS, false)]
+ [TestCase (ApplePlatform.TVOS, false)]
+ [TestCase (ApplePlatform.MacOSX, true)]
+ public void MarkedTest (ApplePlatform platform, bool isCoreCLR)
+ {
+ var code = @"
+ using System;
+ using CoreAnimation;
+ using Foundation;
+ using ObjCRuntime;
+
+ class MyClass : NSObject {
+ [BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))]
+ public CAToneMapMode RWProperty { get; set; }
+
+ [BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))]
+ public CAToneMapMode ROProperty { get { return default; } }
+
+ [BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))]
+ public CAToneMapMode WOProperty { set { } }
+
+ [return: BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))]
+ public CAToneMapMode Method1 () { return default; }
+
+ public void Method2 ([BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))] CAToneMapMode p1) {}
+
+ public void Method3 ([BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))] CAToneMapMode p1, [BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))] CAToneMapMode p2) {}
+
+ [return: BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))]
+ public CAToneMapMode Method4 ([BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))] CAToneMapMode p1, [BindAs (typeof (CAToneMapMode), OriginalType = typeof (NSString))] CAToneMapMode p2) { return default;}
+ }";
+
+ AssertPrepare (platform, isCoreCLR, code, out var assemblyDefinition);
+
+ var type = assemblyDefinition.MainModule.Types.Single (v => v.Name == "MyClass");
+ var cctor = type.GetStaticConstructor ();
+ Assert.That (cctor, Is.Null, "No static constructor should be needed.");
+
+ void AssertHasDynamicDependency (ICustomAttributeProvider provider, string memberSignature, string typeName, string assemblyName)
+ {
+ var ddaAttributes = provider.CustomAttributes.Where (v => v.AttributeType.FullName == "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute").ToArray ();
+ var found = 0;
+ foreach (var ca in ddaAttributes) {
+ if (ca.ConstructorArguments.Count != 3)
+ continue;
+ var attribMemberSignature = (string) ca.ConstructorArguments [0].Value!;
+ if (attribMemberSignature != memberSignature)
+ continue;
+ var attribTypeName = (string) ca.ConstructorArguments [1].Value!;
+ if (attribTypeName != typeName)
+ continue;
+ var attribAssemblyName = (string) ca.ConstructorArguments [2].Value!;
+ if (attribAssemblyName != assemblyName)
+ continue;
+
+ found++;
+ }
+
+ if (found == 1)
+ return;
+
+ var attributesAsString = ddaAttributes
+ .Select (v => {
+ switch (v.ConstructorArguments.Count) {
+ case 3:
+ return $"[DynamicDependency (\"{v.ConstructorArguments [0].Value}\", \"{v.ConstructorArguments [1].Value}\", \"{v.ConstructorArguments [2].Value}\")]";
+ case 2:
+ return $"[DynamicDependency (\"{v.ConstructorArguments [0].Value}\", \"{v.ConstructorArguments [1].Value}\")]";
+ case 1:
+ return $"[DynamicDependency (\"{v.ConstructorArguments [0].Value}\")]";
+ default:
+ return string.Join (", ", v.ConstructorArguments.Select (x => x.Value?.ToString () ?? "null"));
+ }
+ })
+ .OrderBy (v => v)
+ .ToArray ();
+
+ string msg;
+ if (found == 0) {
+ if (attributesAsString.Length == 0) {
+ msg = $"Expected [DynamicDependency (\"{memberSignature}\", \"{typeName}\", \"{assemblyName}\")] on {provider}, got no attributes.";
+ } else {
+ msg = $"Expected [DynamicDependency (\"{memberSignature}\", \"{typeName}\", \"{assemblyName}\")] on {provider}, got:\n\t{string.Join ("\n\t", attributesAsString)}";
+ }
+ } else {
+ msg = $"Expected exactly one [DynamicDependency (\"{memberSignature}\", \"{typeName}\", \"{assemblyName}\")] on {provider}, got {found}:\n\t{string.Join ("\n\t", attributesAsString)}";
+ }
+ Console.WriteLine (msg);
+ Assert.Fail (msg);
+ }
+
+ void AssertHasDynamicDependencies (ICustomAttributeProvider provider)
+ {
+ AssertHasDynamicDependency (provider, "GetConstant(CoreAnimation.CAToneMapMode)", "CoreAnimation.CAToneMapModeExtensions", $"Microsoft.{platform.AsString ()}");
+ AssertHasDynamicDependency (provider, "GetValue(Foundation.NSString)", "CoreAnimation.CAToneMapModeExtensions", $"Microsoft.{platform.AsString ()}");
+ }
+
+ Assert.Multiple (() => {
+ AssertHasDynamicDependencies (type.Methods.Single (v => v.Name == "get_RWProperty"));
+ AssertHasDynamicDependencies (type.Methods.Single (v => v.Name == "set_RWProperty"));
+ AssertHasDynamicDependencies (type.Methods.Single (v => v.Name == "get_ROProperty"));
+ AssertHasDynamicDependencies (type.Methods.Single (v => v.Name == "set_WOProperty"));
+ AssertHasDynamicDependencies (type.Methods.Single (v => v.Name == "Method1"));
+ AssertHasDynamicDependencies (type.Methods.Single (v => v.Name == "Method2"));
+ AssertHasDynamicDependencies (type.Methods.Single (v => v.Name == "Method3"));
+ AssertHasDynamicDependencies (type.Methods.Single (v => v.Name == "Method4"));
+ });
+ }
+}
diff --git a/tests/assembly-preparer/ReproTest.cs b/tests/assembly-preparer/ReproTest.cs
new file mode 100644
index 000000000000..267f7f417568
--- /dev/null
+++ b/tests/assembly-preparer/ReproTest.cs
@@ -0,0 +1,203 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Logging.StructuredLogger;
+
+namespace AssemblyPreparerTests;
+
+public class ReproTest : BaseClass {
+ [TestCase (ApplePlatform.iOS, false)]
+ public void RoundTrip (ApplePlatform platform, bool isCoreCLR)
+ {
+ Configuration.IgnoreIfIgnoredPlatform (platform);
+
+ // build once with a repro path
+ // load everything from the repro path, prepare again (with a different repro path this time),
+ // and verify that the arguments.txt files from each preparation are identical
+ //
+ // this test can also be repurposed to run an existing repro by setting the _PrepareAssembliesMakeReproPath variable
+
+ var reproPath = Environment.GetEnvironmentVariable ("_PrepareAssembliesMakeReproPath");
+ var referenceAssemblies = Configuration.GetReferenceAssemblies (platform, false);
+ if (string.IsNullOrEmpty (reproPath)) {
+ var code = @"public class SomeLibrary {}";
+
+ reproPath = Xamarin.Cache.CreateTemporaryDirectory ();
+ Directory.Delete (reproPath); // the repro path can't exist prior to Prepare
+ AssertPrepareCode (platform, isCoreCLR, (preparer) => {
+ preparer.MakeReproPath = reproPath;
+ preparer.Registrar = RegistrarMode.Dynamic;
+ }, code, out string _);
+ }
+
+ var lines = File.ReadAllLines (Path.Combine (reproPath, "arguments.txt"));
+
+ var ap = AssemblyPreparer.LoadFromReproPath (reproPath);
+ ap.MakeReproPath = Xamarin.Cache.CreateTemporaryDirectory ();
+ Directory.Delete (ap.MakeReproPath); // the repro path can't exist prior to Prepare
+ AssertPrepare (ap);
+
+ var lines2 = File.ReadAllLines (Path.Combine (ap.MakeReproPath, "arguments.txt"));
+
+ // Normalize repro paths before comparison, since they will always differ
+ var normalizedLines = lines.Select (l => l.Replace (reproPath, "")).ToArray ();
+ var normalizedLines2 = lines2.Select (l => l.Replace (ap.MakeReproPath, "")).ToArray ();
+ Assert.That (normalizedLines, Is.EqualTo (normalizedLines2), "Repro arguments match");
+ }
+
+ // This test is here only to easily debug the PrepareAssemblies task from a build that produced a binlog.
+ // Just copy the binlog to /tmp/assembly-preparer.binlog and run this test. It will find the PrepareAssemblies
+ // task in the binlog, extract the relevant parameters, and run the preparation logic with those parameters.
+ [Test]
+ public void FromBinlog ()
+ {
+ var binlogPath = "/tmp/assembly-preparer.binlog";
+ if (!File.Exists (binlogPath))
+ Assert.Ignore (); // The binlog doesn't exist, so nothing to do
+
+ var reader = new BinLogReader ();
+ var records = reader.ReadRecords (binlogPath).ToArray ();
+ var originalBinlogPath = records
+ .Select (r => r.Args)
+ .OfType ()
+ .Where (r => r.SenderName == "BinaryLogger" && r.Message?.StartsWith ("BinLogFilePath=") == true)
+ .Select (v => v.Message?.Substring ("BinLogFilePath=".Length) ?? "")
+ .SingleOrDefault ();
+ var originalBinlogDirectory = Path.GetDirectoryName (originalBinlogPath)!;
+ foreach (var record in records) {
+ if (record is null)
+ continue;
+
+ if (record.Args is null)
+ continue;
+
+ if (record.Args is TaskStartedEventArgs tsea && tsea.TaskName == "PrepareAssemblies") {
+ var taskId = tsea.BuildEventContext?.TaskId;
+ if (taskId is null)
+ continue;
+ var relevantRecords = records.
+ Select (v => v.Args).
+ Where (v => v is not null).
+ Where (v => v.BuildEventContext?.TaskId == taskId).
+ ToArray ();
+
+ var taskParameters = relevantRecords.Where (v => v is TaskParameterEventArgs).Cast ().ToArray ();
+
+ string? getProperty (string name)
+ {
+ var param = taskParameters.SingleOrDefault (v => v.ItemType == name);
+ if (param is null)
+ return null;
+ if (param.Items is null)
+ return null;
+ if (param.Items.Count != 1)
+ return null;
+ var item = param.Items [0];
+ if (item is null)
+ return null;
+ return ((ITaskItem) item).ItemSpec;
+ }
+ ITaskItem []? getItems (string name)
+ {
+ var param = taskParameters.SingleOrDefault (v => v.ItemType == name);
+ if (param is null)
+ return null;
+ if (param.Items is null)
+ return null;
+ return param.Items.Cast ().ToArray ();
+ }
+ var outputDirectory = getProperty ("OutputDirectory");
+ var optionsFile = getProperty ("OptionsFile");
+ var targetFrameworkMoniker = getProperty ("TargetFrameworkMoniker");
+ var makeReproPath = getProperty ("MakeReproPath");
+ var inputAssemblies = getItems ("InputAssemblies");
+
+ if (string.IsNullOrEmpty (outputDirectory))
+ throw new InvalidOperationException ("OutputDirectory is required");
+ outputDirectory = Path.GetFullPath (outputDirectory, originalBinlogDirectory);
+
+ if (string.IsNullOrEmpty (optionsFile))
+ throw new InvalidOperationException ("OptionsFile is required");
+ optionsFile = Path.GetFullPath (optionsFile, originalBinlogDirectory);
+
+ if (string.IsNullOrEmpty (targetFrameworkMoniker))
+ throw new InvalidOperationException ("TargetFrameworkMoniker is required");
+
+ if (inputAssemblies is null || inputAssemblies.Length == 0)
+ throw new InvalidOperationException ("InputAssemblies is required");
+
+ AssemblyPreparerInfo GetAssemblyInfo (ITaskItem item)
+ {
+ var inputPath = Path.GetFullPath (item.ItemSpec, originalBinlogDirectory);
+ var outputPath = Path.Combine (outputDirectory, Path.GetFileName (inputPath));
+ var metadataNames = item.MetadataNames.Cast ().Select (v => v.ToLowerInvariant ()).ToHashSet ();
+ var isTrimmableString = item.GetMetadata ("IsTrimmable");
+ var isTrimmable = string.IsNullOrEmpty (isTrimmableString) ? (bool?) null : string.Equals (isTrimmableString, "true", StringComparison.OrdinalIgnoreCase);
+ var trimMode = item.GetMetadata ("TrimMode");
+
+ var rv = new AssemblyPreparerInfo (inputPath, outputPath, isTrimmable, trimMode);
+ return rv;
+ }
+
+ var platformString = File.ReadAllLines (optionsFile).Single (v => v.StartsWith ("Platform=")).Substring ("Platform=".Length);
+ var platform = ApplePlatformExtensions.Parse (platformString);
+
+ var infos = inputAssemblies.Select (GetAssemblyInfo).ToArray ();
+ var logger = new TestLogger () { Platform = platform };
+ using var preparer = new AssemblyPreparer (logger, infos, optionsFile);
+ preparer.MakeReproPath = makeReproPath ?? "";
+ var rv = preparer.Prepare (out var exceptions);
+ return;
+ }
+ }
+
+ Assert.Fail ("The task 'PrepareAssemblies' was not found in the provided binlog.");
+ }
+}
+
+
+class TestLogger : IToolLog {
+ public int Verbosity => 0;
+ public required ApplePlatform Platform { get; set; }
+
+ public void Log (string value)
+ {
+ Console.WriteLine (value);
+ }
+
+ public void Log (string format, params object? [] args)
+ {
+ Console.WriteLine (format, args);
+ }
+
+ public void LogException (Exception ex)
+ {
+ Console.WriteLine (ex.ToString ());
+ }
+
+ public void LogError (ProductException ex)
+ {
+ Console.WriteLine (ex.ToString ());
+ }
+
+ public void LogError (Exception ex)
+ {
+ Console.WriteLine (ex.ToString ());
+ }
+
+ public void LogError (string value)
+ {
+ Console.WriteLine (value);
+ }
+
+ public void LogWarning (ProductException ex)
+ {
+ Console.WriteLine (ex.ToString ());
+ }
+
+ public void LogWarning (Exception ex)
+ {
+ Console.WriteLine (ex.ToString ());
+ }
+}
diff --git a/tests/assembly-preparer/assembly-preparer-tests.csproj b/tests/assembly-preparer/assembly-preparer-tests.csproj
new file mode 100644
index 000000000000..aab0b2d3d64e
--- /dev/null
+++ b/tests/assembly-preparer/assembly-preparer-tests.csproj
@@ -0,0 +1,50 @@
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)
+ latest
+ enable
+ enable
+ false
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ external/tests/common/BinLog.cs
+
+
+ external/tests/mtouch/Cache.cs
+
+
+ external/tests/common/Configuration.cs
+
+
+ external/tests/common/ConfigurationNUnit.cs
+
+
+ external/tests/common/DotNet.cs
+
+
+ external/tests/common/ExecutionHelper.cs
+
+
+ external/tools/common/SdkVersions.cs
+
+
+ external/tools/common/StringUtils.cs
+
+
+
+
diff --git a/tests/assembly-preparer/assembly-preparer.slnx b/tests/assembly-preparer/assembly-preparer.slnx
new file mode 100644
index 000000000000..990bc0a7a9fb
--- /dev/null
+++ b/tests/assembly-preparer/assembly-preparer.slnx
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/tests/cecil-tests/Documentation.KnownFailures.txt b/tests/cecil-tests/Documentation.KnownFailures.txt
index 9e1603a34248..be4383668c70 100644
--- a/tests/cecil-tests/Documentation.KnownFailures.txt
+++ b/tests/cecil-tests/Documentation.KnownFailures.txt
@@ -2191,7 +2191,7 @@ F:CoreGraphics.CGPdfTagType.TableRow
F:CoreGraphics.CGPdfTagType.Toc
F:CoreGraphics.CGPdfTagType.Toci
F:CoreGraphics.CGPdfTagType.Warichu
-F:CoreGraphics.CGPdfTagType.WarichuPunctiation
+F:CoreGraphics.CGPdfTagType.WarichuPunctuation
F:CoreGraphics.CGPdfTagType.WarichuText
F:CoreGraphics.CGToneMapping.Default
F:CoreGraphics.CGToneMapping.ExrGamma
@@ -5454,7 +5454,7 @@ F:MLCompute.MLCConvolutionType.Transposed
F:MLCompute.MLCDataType.Boolean
F:MLCompute.MLCDataType.Float16
F:MLCompute.MLCDataType.Float32
-F:MLCompute.MLCDataType.Inot32
+F:MLCompute.MLCDataType.Int32
F:MLCompute.MLCDataType.Int64
F:MLCompute.MLCDataType.Int8
F:MLCompute.MLCDataType.Invalid
@@ -8514,11 +8514,13 @@ M:AppKit.NSCollectionLayoutAnchor.Create(AppKit.NSDirectionalRectEdge,AppKit.NSC
M:AppKit.NSCollectionLayoutGroup.GetHorizontalGroup(AppKit.NSCollectionLayoutSize,AppKit.NSCollectionLayoutItem,System.IntPtr)
M:AppKit.NSCollectionLayoutGroup.GetVerticalGroup(AppKit.NSCollectionLayoutSize,AppKit.NSCollectionLayoutItem,System.IntPtr)
M:AppKit.NSCollectionView.Dispose(System.Boolean)
+M:AppKit.NSCollectionViewDataSource.GetNumberOfItems(AppKit.NSCollectionView,System.IntPtr)
M:AppKit.NSCollectionViewDelegate_Extensions.AcceptDrop(AppKit.INSCollectionViewDelegate,AppKit.NSCollectionView,AppKit.INSDraggingInfo,Foundation.NSIndexPath,AppKit.NSCollectionViewDropOperation)
M:AppKit.NSCollectionViewDelegate_Extensions.AcceptDrop(AppKit.INSCollectionViewDelegate,AppKit.NSCollectionView,AppKit.INSDraggingInfo,System.IntPtr,AppKit.NSCollectionViewDropOperation)
M:AppKit.NSCollectionViewDelegate_Extensions.UpdateDraggingItemsForDrag(AppKit.INSCollectionViewDelegate,AppKit.NSCollectionView,AppKit.INSDraggingInfo)
M:AppKit.NSCollectionViewDelegate_Extensions.ValidateDrop(AppKit.INSCollectionViewDelegate,AppKit.NSCollectionView,AppKit.INSDraggingInfo,Foundation.NSIndexPath@,AppKit.NSCollectionViewDropOperation@)
M:AppKit.NSCollectionViewDelegate_Extensions.ValidateDrop(AppKit.INSCollectionViewDelegate,AppKit.NSCollectionView,AppKit.INSDraggingInfo,System.IntPtr@,AppKit.NSCollectionViewDropOperation@)
+M:AppKit.NSCollectionViewDiffableDataSource`2.GetNumberOfItems(AppKit.NSCollectionView,System.IntPtr)
M:AppKit.NSCollectionViewItem.Dispose(System.Boolean)
M:AppKit.NSCollectionViewLayout.Dispose(System.Boolean)
M:AppKit.NSCollectionViewSectionHeaderView_Extensions.GetSectionCollapseButton(AppKit.INSCollectionViewSectionHeaderView)
@@ -8576,6 +8578,7 @@ M:AppKit.NSFont.MonospacedSystemFont(System.Runtime.InteropServices.NFloat,Syste
M:AppKit.NSFont.SystemFontOfSize(System.Runtime.InteropServices.NFloat,System.Runtime.InteropServices.NFloat,System.Runtime.InteropServices.NFloat)
M:AppKit.NSFontDescriptor.Create(AppKit.NSFontDescriptorSystemDesign)
M:AppKit.NSFontManager.Dispose(System.Boolean)
+M:AppKit.NSFormCell.GetTitleWidth(CoreGraphics.CGSize)
M:AppKit.NSGestureRecognizer.Dispose(System.Boolean)
M:AppKit.NSGraphics.DrawTiledRects(CoreGraphics.CGRect,CoreGraphics.CGRect,AppKit.NSRectEdge[],System.Runtime.InteropServices.NFloat[])
M:AppKit.NSGraphics.FrameRect(CoreGraphics.CGRect,System.Runtime.InteropServices.NFloat,AppKit.NSCompositingOperation)
@@ -8674,11 +8677,13 @@ M:AppKit.NSPathControlDelegate_Extensions.AcceptDrop(AppKit.INSPathControlDelega
M:AppKit.NSPathControlDelegate_Extensions.ValidateDrop(AppKit.INSPathControlDelegate,AppKit.NSPathControl,AppKit.INSDraggingInfo)
M:AppKit.NSPickerTouchBarItem.Dispose(System.Boolean)
M:AppKit.NSPopover.Dispose(System.Boolean)
+M:AppKit.NSPopUpButtonCell.IndexOfItemWithTargetAndAction(Foundation.NSObject,ObjCRuntime.Selector)
M:AppKit.NSPreviewRepresentableActivityItem_Extensions.GetIconProvider(AppKit.INSPreviewRepresentableActivityItem)
M:AppKit.NSPreviewRepresentableActivityItem_Extensions.GetImageProvider(AppKit.INSPreviewRepresentableActivityItem)
M:AppKit.NSPreviewRepresentableActivityItem_Extensions.GetTitle(AppKit.INSPreviewRepresentableActivityItem)
M:AppKit.NSPrintPanel.BeginSheetAsync(AppKit.NSPrintInfo,AppKit.NSWindow)
M:AppKit.NSResponder_NSWritingToolsSupport.ShowWritingTools(AppKit.NSResponder,Foundation.NSObject)
+M:AppKit.NSResponder.TryToPerformWith(ObjCRuntime.Selector,Foundation.NSObject)
M:AppKit.NSRuleEditor.add_Changed(System.EventHandler)
M:AppKit.NSRuleEditor.add_EditingBegan(System.EventHandler)
M:AppKit.NSRuleEditor.add_EditingEnded(System.EventHandler)
@@ -8700,6 +8705,7 @@ M:AppKit.NSSavePanel.remove_DidSelectType(System.EventHandler{AppKit.NSopenSaveP
M:AppKit.NSSavePanel.remove_DirectoryDidChange(System.EventHandler{AppKit.NSOpenSaveFilenameEventArgs})
M:AppKit.NSSavePanel.remove_SelectionDidChange(System.EventHandler)
M:AppKit.NSSavePanel.remove_WillExpand(System.EventHandler{AppKit.NSOpenSaveExpandingEventArgs})
+M:AppKit.NSScreen.ConvertRectFromBacking(CoreGraphics.CGRect)
M:AppKit.NSScrubber.Dispose(System.Boolean)
M:AppKit.NSScrubberLayout.Dispose(System.Boolean)
M:AppKit.NSSearchField.add_SearchingEnded(System.EventHandler)
@@ -8731,6 +8737,7 @@ M:AppKit.NSSpeechRecognizer.Dispose(System.Boolean)
M:AppKit.NSSpeechSynthesizer.Dispose(System.Boolean)
M:AppKit.NSSpellChecker.CheckString(System.String,Foundation.NSRange,Foundation.NSTextCheckingTypes,AppKit.NSTextCheckingOptions,System.IntPtr,Foundation.NSOrthography@,System.IntPtr@)
M:AppKit.NSSpellChecker.RequestChecking(System.String,Foundation.NSRange,Foundation.NSTextCheckingTypes,AppKit.NSTextCheckingOptions,System.IntPtr,System.Action{System.IntPtr,Foundation.NSTextCheckingResult[],Foundation.NSOrthography,System.IntPtr})
+M:AppKit.NSSpellChecker.UpdateSpellingPanelWithGrammarString(System.String,Foundation.NSDictionary)
M:AppKit.NSSplitView.Dispose(System.Boolean)
M:AppKit.NSSpringLoadingDestination_Extensions.DraggingEnded(AppKit.INSSpringLoadingDestination,AppKit.INSDraggingInfo)
M:AppKit.NSSpringLoadingDestination_Extensions.Entered(AppKit.INSSpringLoadingDestination,AppKit.INSDraggingInfo)
@@ -8932,6 +8939,7 @@ M:AppKit.NSView.IsAccessibilityAttributeSettable(Foundation.NSString)
M:AppKit.NSView.SetAccessibilityValue(Foundation.NSString,Foundation.NSObject)
M:AppKit.NSView.SortSubviews(System.Func{AppKit.NSView,AppKit.NSView,Foundation.NSComparisonResult})
M:AppKit.NSViewController.Dispose(System.Boolean)
+M:AppKit.NSViewController.TryToPerformWith(ObjCRuntime.Selector,Foundation.NSObject)
M:AppKit.NSWindow.add_DidBecomeKey(System.EventHandler)
M:AppKit.NSWindow.add_DidBecomeMain(System.EventHandler)
M:AppKit.NSWindow.add_DidChangeBackingProperties(System.EventHandler)
@@ -9019,6 +9027,7 @@ M:AppKit.NSWorkspace.SetDefaultApplicationToOpenContentTypeAsync(Foundation.NSUr
M:AppKit.NSWorkspace.SetDefaultApplicationToOpenContentTypeAsync(Foundation.NSUrl,UniformTypeIdentifiers.UTType)
M:AppKit.NSWorkspace.SetDefaultApplicationToOpenFileAsync(Foundation.NSUrl,Foundation.NSUrl)
M:AppKit.NSWorkspace.SetDefaultApplicationToOpenUrlsAsync(Foundation.NSUrl,System.String)
+M:AppKit.NSWorkspace.SetIconForFile(AppKit.NSImage,System.String,AppKit.NSWorkspaceIconCreationOptions)
M:AppKit.NSWritingToolsCoordinator.Dispose(System.Boolean)
M:AppTrackingTransparency.ATTrackingManager.RequestTrackingAuthorization(System.Action{AppTrackingTransparency.ATTrackingManagerAuthorizationStatus})
M:AppTrackingTransparency.ATTrackingManager.RequestTrackingAuthorizationAsync
@@ -9334,7 +9343,7 @@ M:AuthenticationServices.ASWebAuthenticationSessionRequestDelegate_Extensions.Di
M:AuthenticationServices.ASWebAuthenticationSessionRequestDelegate.DidCancel(AuthenticationServices.ASWebAuthenticationSessionRequest,Foundation.NSError)
M:AuthenticationServices.ASWebAuthenticationSessionRequestDelegate.DidComplete(AuthenticationServices.ASWebAuthenticationSessionRequest,Foundation.NSUrl)
M:AuthenticationServices.ASWebAuthenticationSessionWebBrowserSessionManager.Dispose(System.Boolean)
-M:AuthenticationServices.ASWebAuthenticationSessionWebBrowserSessionManager.RegisterDefaultsForAswasInSetupAssistantIfNeeded
+M:AuthenticationServices.ASWebAuthenticationSessionWebBrowserSessionManager.RegisterDefaultsForAsWasInSetupAssistantIfNeeded
M:AuthenticationServices.IASAccountAuthenticationModificationControllerDelegate.DidFailRequest(AuthenticationServices.ASAccountAuthenticationModificationController,AuthenticationServices.ASAccountAuthenticationModificationRequest,Foundation.NSError)
M:AuthenticationServices.IASAccountAuthenticationModificationControllerDelegate.DidSuccessfullyCompleteRequest(AuthenticationServices.ASAccountAuthenticationModificationController,AuthenticationServices.ASAccountAuthenticationModificationRequest,Foundation.NSDictionary)
M:AuthenticationServices.IASAccountAuthenticationModificationControllerPresentationContextProviding.GetPresentationAnchor(AuthenticationServices.ASAccountAuthenticationModificationController)
@@ -9399,10 +9408,10 @@ M:AVFoundation.AVAsset.LoadTracksWithMediaTypeAsync(System.String)
M:AVFoundation.AVAsset.LoadTrackWithMediaCharacteristicsAsync(System.String)
M:AVFoundation.AVAssetDownloadDelegate_Extensions.DidReceiveMetricEvent(AVFoundation.IAVAssetDownloadDelegate,Foundation.NSUrlSession,AVFoundation.AVAssetDownloadTask,AVFoundation.AVMetricEvent)
M:AVFoundation.AVAssetDownloadDelegate_Extensions.WillDownloadVariants(AVFoundation.IAVAssetDownloadDelegate,Foundation.NSUrlSession,AVFoundation.AVAssetDownloadTask,AVFoundation.AVAssetVariant[])
-M:AVFoundation.AVAssetDownloadDelegate_Extensions.WilllDownloadToUrl(AVFoundation.IAVAssetDownloadDelegate,Foundation.NSUrlSession,AVFoundation.AVAssetDownloadTask,Foundation.NSUrl)
M:AVFoundation.AVAssetDownloadDelegate.DidCreateTask(Foundation.NSUrlSession,Foundation.NSUrlSessionTask)
M:AVFoundation.AVAssetDownloadDelegate.DidReceiveInformationalResponse(Foundation.NSUrlSession,Foundation.NSUrlSessionTask,Foundation.NSHttpUrlResponse)
M:AVFoundation.AVAssetDownloadDelegate.NeedNewBodyStream(Foundation.NSUrlSession,Foundation.NSUrlSessionTask,System.Int64,System.Action{Foundation.NSInputStream})
+M:AVFoundation.AVAssetDownloadDelegate.WillDownloadToUrl(Foundation.NSUrlSession,AVFoundation.AVAssetDownloadTask,Foundation.NSUrl)
M:AVFoundation.AVAssetExportSession.EstimateMaximumDurationAsync
M:AVFoundation.AVAssetExportSession.EstimateOutputFileLengthAsync
M:AVFoundation.AVAssetImageGenerator.GenerateCGImagesAsynchronously(Foundation.NSValue[],AVFoundation.AVAssetImageGeneratorCompletionHandler2)
@@ -9691,7 +9700,6 @@ M:AVFoundation.AVVideoComposition.CreateAsync(AVFoundation.AVAsset)
M:AVFoundation.AVVideoComposition.DetermineValidityAsync(AVFoundation.AVAsset,CoreMedia.CMTimeRange,AVFoundation.IAVVideoCompositionValidationHandling)
M:AVFoundation.IAVAssetDownloadDelegate.DidReceiveMetricEvent(Foundation.NSUrlSession,AVFoundation.AVAssetDownloadTask,AVFoundation.AVMetricEvent)
M:AVFoundation.IAVAssetDownloadDelegate.WillDownloadVariants(Foundation.NSUrlSession,AVFoundation.AVAssetDownloadTask,AVFoundation.AVAssetVariant[])
-M:AVFoundation.IAVAssetDownloadDelegate.WilllDownloadToUrl(Foundation.NSUrlSession,AVFoundation.AVAssetDownloadTask,Foundation.NSUrl)
M:AVFoundation.IAVAssetReaderCaptionValidationHandling.DidVendCaption(AVFoundation.AVAssetReaderOutputCaptionAdaptor,AVFoundation.AVCaption,System.String[])
M:AVFoundation.IAVAssetWriterDelegate.DidOutputSegmentData(AVFoundation.AVAssetWriter,Foundation.NSData,AVFoundation.AVAssetSegmentType,AVFoundation.AVAssetSegmentReport)
M:AVFoundation.IAVAssetWriterDelegate.DidOutputSegmentData(AVFoundation.AVAssetWriter,Foundation.NSData,AVFoundation.AVAssetSegmentType)
@@ -10991,6 +10999,7 @@ M:CoreImage.CIContext.CreateCGImage(CoreImage.CIImage,CoreGraphics.CGRect,System
M:CoreImage.CIContext.GetOpenEXRRepresentation(CoreImage.CIImage,Foundation.NSDictionary{Foundation.NSString,Foundation.NSObject},Foundation.NSError@)
M:CoreImage.CIContext.WriteOpenExrRepresentation(CoreImage.CIImage,Foundation.NSUrl,Foundation.NSDictionary{Foundation.NSString,Foundation.NSObject},Foundation.NSError@)
M:CoreImage.CIDetectorOptions.#ctor
+M:CoreImage.CIFilterGenerator.SetAttributes(Foundation.NSDictionary,Foundation.NSString)
M:CoreImage.CIImage.#ctor(AVFoundation.AVSemanticSegmentationMatte,Foundation.NSDictionary)
M:CoreImage.CIImage.#ctor(AVFoundation.AVSemanticSegmentationMatte)
M:CoreImage.CIImage.#ctor(ImageIO.CGImageSource,System.UIntPtr,CoreImage.CIImageInitializationOptionsWithMetadata)
@@ -11850,6 +11859,10 @@ M:Foundation.INSUrlSessionTaskDelegate.NeedNewBodyStream(Foundation.NSUrlSession
M:Foundation.INSUrlSessionWebSocketDelegate.DidClose(Foundation.NSUrlSession,Foundation.NSUrlSessionWebSocketTask,Foundation.NSUrlSessionWebSocketCloseCode,Foundation.NSData)
M:Foundation.INSUrlSessionWebSocketDelegate.DidOpen(Foundation.NSUrlSession,Foundation.NSUrlSessionWebSocketTask,System.String)
M:Foundation.INSXpcListenerDelegate.ShouldAcceptConnection(Foundation.NSXpcListener,Foundation.NSXpcConnection)
+M:Foundation.NSAppleEventDescriptor.InsertDescriptor(Foundation.NSAppleEventDescriptor,System.IntPtr)
+M:Foundation.NSAppleEventDescriptor.SetAttributeDescriptor(Foundation.NSAppleEventDescriptor,System.UInt32)
+M:Foundation.NSAppleEventDescriptor.SetDescriptor(Foundation.NSAppleEventDescriptor,System.UInt32)
+M:Foundation.NSAppleEventDescriptor.SetParamDescriptor(Foundation.NSAppleEventDescriptor,System.UInt32)
M:Foundation.NSAttributedString.#ctor(System.String,AppKit.NSFont,AppKit.NSColor,AppKit.NSColor,AppKit.NSColor,AppKit.NSColor,AppKit.NSColor,Foundation.NSUnderlineStyle,Foundation.NSUnderlineStyle,AppKit.NSParagraphStyle,System.Single,AppKit.NSShadow,Foundation.NSUrl,System.Boolean,AppKit.NSTextAttachment,Foundation.NSLigatureType,System.Single,System.Single,System.Single,System.Single,AppKit.NSCursor,System.String,System.Int32,AppKit.NSGlyphInfo,Foundation.NSArray,System.Boolean,AppKit.NSTextLayoutOrientation,AppKit.NSTextAlternatives,AppKit.NSSpellingState)
M:Foundation.NSAttributedString.LoadDataAsync(System.String,Foundation.NSProgress@)
M:Foundation.NSAttributedString.LoadFromHtml(Foundation.NSData,Foundation.NSAttributedStringDocumentAttributes,Foundation.NSAttributedStringCompletionHandler)
@@ -11874,6 +11887,7 @@ M:Foundation.NSDataDetector.#ctor(Foundation.NSTextCheckingType,Foundation.NSErr
M:Foundation.NSDataDetector.Create(Foundation.NSTextCheckingType,Foundation.NSError@)
M:Foundation.NSDate.op_Explicit(Foundation.NSDate)~System.DateTime
M:Foundation.NSDate.op_Explicit(System.DateTime)~Foundation.NSDate
+M:Foundation.NSDirectoryEnumerator.SkipDescendants
M:Foundation.NSEnumerator`1.NextObject
M:Foundation.NSExceptionError.#ctor(System.Exception)
M:Foundation.NSFileAttributes.#ctor
@@ -11912,6 +11926,7 @@ M:Foundation.NSKeyValueSharedObserverRegistration_NSObject.SetSharedObservers(Fo
M:Foundation.NSKeyValueSharedObservers.#ctor(System.Type)
M:Foundation.NSMachPort.Dispose(System.Boolean)
M:Foundation.NSMetadataQuery.Dispose(System.Boolean)
+M:Foundation.NSMutableString.ReplaceOccurrences(Foundation.NSString,Foundation.NSString,Foundation.NSStringCompareOptions,Foundation.NSRange)
M:Foundation.NSNetService.add_AddressResolved(System.EventHandler)
M:Foundation.NSNetService.add_DidAcceptConnection(System.EventHandler{Foundation.NSNetServiceConnectionEventArgs})
M:Foundation.NSNetService.add_Published(System.EventHandler)
@@ -11946,6 +11961,7 @@ M:Foundation.NSNetServiceBrowser.remove_NotSearched(System.EventHandler{Foundati
M:Foundation.NSNetServiceBrowser.remove_SearchStarted(System.EventHandler)
M:Foundation.NSNetServiceBrowser.remove_SearchStopped(System.EventHandler)
M:Foundation.NSNetServiceBrowser.remove_ServiceRemoved(System.EventHandler{Foundation.NSNetServiceEventArgs})
+M:Foundation.NSNotificationQueue.DequeueNotifications(Foundation.NSNotification,Foundation.NSNotificationCoalescing)
M:Foundation.NSNotificationQueue.EnqueueNotification(Foundation.NSNotification,Foundation.NSPostingStyle,Foundation.NSNotificationCoalescing,Foundation.NSRunLoopMode[])
M:Foundation.NSObject.AddObserver(Foundation.NSObject,System.String,Foundation.NSKeyValueObservingOptions,System.IntPtr)
M:Foundation.NSObject.AutomaticallyNotifiesObserversForKey(System.String)
@@ -12008,6 +12024,7 @@ M:Foundation.NSStream.remove_OnEvent(System.EventHandler{Foundation.NSStreamEven
M:Foundation.NSStreamSocksOptions.#ctor
M:Foundation.NSString.CompareTo(Foundation.NSString)
M:Foundation.NSString.LoadDataAsync(System.String,Foundation.NSProgress@)
+M:Foundation.NSString.StandardizePath
M:Foundation.NSTimer.Dispose(System.Boolean)
M:Foundation.NSUrl.LoadDataAsync(System.String,Foundation.NSProgress@)
M:Foundation.NSUrl.op_Equality(Foundation.NSUrl,Foundation.NSUrl)
@@ -14998,7 +15015,7 @@ M:Network.NWConnectionGroup.GetLocalEndpoint(Network.NWContentContext)
M:Network.NWConnectionGroup.GetPath(Network.NWContentContext)
M:Network.NWConnectionGroup.GetProtocolMetadata(Network.NWContentContext,Network.NWProtocolDefinition)
M:Network.NWConnectionGroup.GetProtocolMetadata(Network.NWContentContext)
-M:Network.NWConnectionGroup.GetRemmoteEndpoint(Network.NWContentContext)
+M:Network.NWConnectionGroup.GetRemoteEndpoint(Network.NWContentContext)
M:Network.NWConnectionGroup.Reply(Network.NWContentContext,Network.NWContentContext,CoreFoundation.DispatchData)
M:Network.NWConnectionGroup.Send(CoreFoundation.DispatchData,Network.NWEndpoint,Network.NWContentContext,System.Action{Network.NWError})
M:Network.NWConnectionGroup.SetNewConnectionHandler(System.Action{Network.NWConnection})
@@ -17209,6 +17226,7 @@ M:UIKit.UILargeContentViewerInteractionDelegate_Extensions.GetItem(UIKit.IUILarg
M:UIKit.UILargeContentViewerInteractionDelegate_Extensions.GetViewController(UIKit.IUILargeContentViewerInteractionDelegate,UIKit.UILargeContentViewerInteraction)
M:UIKit.UILayoutGuide.Dispose(System.Boolean)
M:UIKit.UIListContentView.UIListContentViewAppearance.#ctor(System.IntPtr)
+M:UIKit.UILocalizedIndexedCollation.SortedArrayFromArrayCollationStringSelector(Foundation.NSObject[],ObjCRuntime.Selector)
M:UIKit.UIMenu.Create(System.String,UIKit.UIImage,UIKit.UIMenuIdentifier,UIKit.UIMenuOptions,UIKit.UIMenuElement[])
M:UIKit.UIMenuLeaf_Extensions.GetSelectedImage(UIKit.IUIMenuLeaf)
M:UIKit.UIMenuLeaf_Extensions.SetSelectedImage(UIKit.IUIMenuLeaf,UIKit.UIImage)
@@ -17399,9 +17417,10 @@ M:UIKit.UISearchBar.remove_OnEditingStopped(System.EventHandler)
M:UIKit.UISearchBar.remove_SearchButtonClicked(System.EventHandler)
M:UIKit.UISearchBar.remove_SelectedScopeButtonIndexChanged(System.EventHandler{UIKit.UISearchBarButtonIndexEventArgs})
M:UIKit.UISearchBar.remove_TextChanged(System.EventHandler{UIKit.UISearchBarTextChangedEventArgs})
+M:UIKit.UISearchBar.SetImageForSearchBarIcon(UIKit.UIImage,UIKit.UISearchBarIcon,UIKit.UIControlState)
+M:UIKit.UISearchBar.SetPositionAdjustmentForSearchBarIcon(UIKit.UIOffset,UIKit.UISearchBarIcon)
M:UIKit.UISearchBar.UISearchBarAppearance.#ctor(System.IntPtr)
M:UIKit.UISearchBar.UISearchBarAppearance.GetPositionAdjustmentForSearchBarIcon(UIKit.UISearchBarIcon)
-M:UIKit.UISearchBar.UISearchBarAppearance.SetPositionAdjustmentforSearchBarIcon(UIKit.UIOffset,UIKit.UISearchBarIcon)
M:UIKit.UISearchBarDelegate_Extensions.ShouldChangeText(UIKit.IUISearchBarDelegate,UIKit.UISearchBar,Foundation.NSValue[],System.String)
M:UIKit.UISearchController.Dispose(System.Boolean)
M:UIKit.UISearchControllerDelegate_Extensions.DidChangeFromSearchBarPlacement(UIKit.IUISearchControllerDelegate,UIKit.UISearchController,UIKit.UINavigationItemSearchBarPlacement)
@@ -18115,6 +18134,7 @@ M:WebKit.WKWebView.SetMicrophoneCaptureStateAsync(WebKit.WKMediaCaptureState)
M:WebKit.WKWebView.StartDownloadAsync(Foundation.NSUrlRequest)
M:WebKit.WKWebView.WKWebViewAppearance.#ctor(System.IntPtr)
P:Accessibility.AXAnimatedImagesUtilities.Enabled
+P:Accessibility.AXMathExpressionFraction.DenominatorExpression
P:Accessibility.IAXBrailleMapRenderer.AccessibilityBrailleMapRenderer
P:Accessibility.IAXBrailleMapRenderer.AccessibilityBrailleMapRenderRegion
P:Accessibility.IAXChart.AccessibilityChartDescriptor
@@ -20857,6 +20877,7 @@ P:CoreSpotlight.CSSearchableItem.IsUpdate
P:CoreSpotlight.CSSearchableItem.UpdateListenerOptions
P:CoreSpotlight.CSSearchableItemAttributeSet.ActionIdentifiers
P:CoreSpotlight.CSSearchableItemAttributeSet.DarkThumbnailUrl
+P:CoreSpotlight.CSSearchableItemAttributeSet.GpsDifferential
P:CoreSpotlight.CSSearchableItemAttributeSet.IsPriority
P:CoreSpotlight.CSSearchableItemAttributeSet.Item(CoreSpotlight.CSCustomAttributeKey)
P:CoreSpotlight.CSSearchableItemAttributeSet.SharedItemContentType
@@ -21450,6 +21471,7 @@ P:GameKit.GKPlayerEventArgs.PlayerID
P:GameKit.GKPlayersEventArgs.PlayerIDs
P:GameKit.GKStateEventArgs.PlayerId
P:GameKit.GKStateEventArgs.State
+P:GameKit.GKTurnBasedMatch.ExchangeDataMaximumSize
P:GameplayKit.GKCompositeBehavior.Item(GameplayKit.GKBehavior)
P:GameplayKit.GKCompositeBehavior.Item(System.UIntPtr)
P:GameplayKit.IGKGameModelPlayer.PlayerId
@@ -21642,6 +21664,7 @@ P:MapKit.IMKAnnotation.Subtitle
P:MapKit.IMKAnnotation.Title
P:MapKit.IMKOverlay.CanReplaceMapContent
P:MapKit.MKAnnotationEventArgs.Annotation
+P:MapKit.MKAnnotationView.RightCalloutOffset
P:MapKit.MKAnnotationViewEventArgs.View
P:MapKit.MKDidAddOverlayRenderersEventArgs.Renderers
P:MapKit.MKDidFinishRenderingMapEventArgs.FullyRendered
@@ -22354,7 +22377,7 @@ P:MetalPerformanceShadersGraph.MPSGraphExecutionDescriptor.CompletionHandler
P:MetalPerformanceShadersGraph.MPSGraphExecutionDescriptor.ScheduledHandler
P:MetalPerformanceShadersGraph.MPSGraphExecutionDescriptor.WaitUntilCompleted
P:MetalPerformanceShadersGraph.MPSGraphFftDescriptor.Inverse
-P:MetalPerformanceShadersGraph.MPSGraphFftDescriptor.RoundToOddHermitean
+P:MetalPerformanceShadersGraph.MPSGraphFftDescriptor.RoundToOddHermitian
P:MetalPerformanceShadersGraph.MPSGraphFftDescriptor.ScalingMode
P:MetalPerformanceShadersGraph.MPSGraphGruDescriptor.Bidirectional
P:MetalPerformanceShadersGraph.MPSGraphGruDescriptor.FlipZ
diff --git a/tests/common/Configuration.cs b/tests/common/Configuration.cs
index 1735ac8df815..20f92ed994ff 100644
--- a/tests/common/Configuration.cs
+++ b/tests/common/Configuration.cs
@@ -577,6 +577,63 @@ public static string GetRefLibrary (ApplePlatform platform)
{
return GetBaseLibrary (platform);
}
+
+ public static List GetBCLAssemblies (ApplePlatform platform, bool isCoreCLR)
+ {
+ var assemblies = new List ();
+ string rid;
+ string packageName;
+ switch (platform) {
+ case ApplePlatform.MacCatalyst:
+ rid = "maccatalyst-arm64";
+ packageName = isCoreCLR ? $"microsoft.netcore.app.runtime.maccatalyst-arm64" : $"microsoft.netcore.app.runtime.mono.maccatalyst-arm64";
+ break;
+ case ApplePlatform.iOS:
+ rid = "ios-arm64";
+ packageName = isCoreCLR ? $"microsoft.netcore.app.runtime.ios-arm64" : $"microsoft.netcore.app.runtime.mono.ios-arm64";
+ break;
+ case ApplePlatform.TVOS:
+ rid = "tvos-arm64";
+ packageName = isCoreCLR ? $"microsoft.netcore.app.runtime.tvOS-arm64" : $"microsoft.netcore.app.runtime.mono.tvOS-arm64";
+ break;
+ case ApplePlatform.MacOSX:
+ rid = "osx-arm64";
+ packageName = "microsoft.netcore.app.runtime.osx-arm64";
+ if (!isCoreCLR)
+ throw new InvalidOperationException ($"Mono doesn't support macOS, but was asked for the BCL assemblies for macOS");
+ break;
+ default:
+ throw new NotSupportedException ($"Unsupported platform: {platform}");
+ }
+ var microsoftNetCoreAppRefPackageVersion = File.ReadAllLines (Path.Combine (RootPath, "dotnet.config")).Single (v => v.StartsWith ("BUNDLED_NETCORE_PLATFORMS_PACKAGE_VERSION=", StringComparison.Ordinal)).Replace ("BUNDLED_NETCORE_PLATFORMS_PACKAGE_VERSION=", "");
+ var bclDir = Path.Combine (RootPath, "packages", packageName, microsoftNetCoreAppRefPackageVersion, "runtimes", rid, "lib", DotNetTfm);
+ var nativeDir = Path.Combine (RootPath, "packages", packageName, microsoftNetCoreAppRefPackageVersion, "runtimes", rid, "native");
+
+ assemblies.AddRange (Directory.GetFiles (bclDir, "*.dll"));
+ assemblies.AddRange (Directory.GetFiles (nativeDir, "*.dll"));
+
+ return assemblies;
+ }
+
+ public static List GetReferenceAssemblies (ApplePlatform platform, bool isCoreCLR)
+ {
+ var assemblies = new List ();
+
+ assemblies.AddRange (GetBCLAssemblies (platform, isCoreCLR));
+ assemblies.AddRange (GetRefLibrary (platform));
+
+ return assemblies;
+ }
+
+ public static List GetImplementationAssemblies (ApplePlatform platform, bool isCoreCLR)
+ {
+ var assemblies = new List ();
+
+ assemblies.AddRange (GetBCLAssemblies (platform, isCoreCLR));
+ assemblies.AddRange (GetBaseLibraryImplementations (platform).First ());
+
+ return assemblies;
+ }
#endif // !XAMMAC_TESTS
public static IEnumerable GetIncludedPlatforms ()
diff --git a/tests/common/DotNet.cs b/tests/common/DotNet.cs
index 1f7a5c73e868..9e01afeebe45 100644
--- a/tests/common/DotNet.cs
+++ b/tests/common/DotNet.cs
@@ -109,7 +109,7 @@ public static ExecutionResult AssertNew (string outputDirectory, string template
Console.WriteLine (output);
Assert.That (rv.ExitCode, Is.EqualTo (0), $"Exit code: {Executable} {StringUtils.FormatArguments (args)}");
}
- return new ExecutionResult (output, output, rv.ExitCode);
+ return new ExecutionResult (output, output, rv.ExitCode, rv.Duration);
}
public static ExecutionResult InstallWorkload (params string [] workloads)
@@ -136,7 +136,7 @@ public static ExecutionResult InstallWorkload (params string [] workloads)
Console.WriteLine (msg);
Assert.Fail (msg.ToString ());
}
- return new ExecutionResult (output, output, rv.ExitCode);
+ return new ExecutionResult (output, output, rv.ExitCode, rv.Duration);
}
public static ExecutionResult InstallTool (string tool, string path)
@@ -206,7 +206,7 @@ public static ExecutionResult ExecuteCommand (string exe, Dictionary? properties, bool assert_success = true, string? target = null, bool? msbuildParallelism = null, TimeSpan? timeout = null, params string [] extraArguments)
@@ -338,7 +338,7 @@ public static ExecutionResult Execute (string verb, string project, Dictionary
+
@@ -190,6 +191,11 @@
<_TestVariationApplied>true
+
+ true
+ <_TestVariationApplied>true
+
+
<_InvalidTestVariations Include="$(TestVariation.Split('|'))" Exclude="@(TestVariations)" />
diff --git a/tests/dotnet/UnitTests/PerformanceTests.cs b/tests/dotnet/UnitTests/PerformanceTests.cs
new file mode 100644
index 000000000000..73f88a7af72e
--- /dev/null
+++ b/tests/dotnet/UnitTests/PerformanceTests.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Xamarin.Tests {
+ [TestFixture]
+ public class PerformanceTests : TestBaseClass {
+ [Test]
+ [TestCase (ApplePlatform.iOS, "iossimulator-arm64")]
+ public void PrepareAssemblies (ApplePlatform platform, string runtimeIdentifiers)
+ {
+ Configuration.IgnoreIfIgnoredPlatform (platform);
+ Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers);
+
+ if (string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("ENABLE_PERFORMANCE_TESTS")))
+ Assert.Ignore ("Test ignored because ENABLE_PERFORMANCE_TESTS is not set.");
+
+ var projects = new string [] { "MySimpleApp", "monotouch-test" };
+ var results = new List ();
+ var attempts = 3;
+ foreach (var project in projects) {
+ var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath);
+
+ var result = new PrepareAssembliesTestResult {
+ Project = project,
+ };
+ foreach (var propertyValue in new bool [] { false, true }) {
+ var properties = GetDefaultProperties (runtimeIdentifiers);
+ properties ["PrepareAssemblies"] = propertyValue.ToString ();
+
+ for (var i = 1; i <= attempts; i++) {
+ Clean (project_path);
+ var rv = DotNet.AssertBuild (project_path, properties);
+ (propertyValue ? result.EnabledBuildTimes : result.DisabledBuildTimes).Add (rv.Duration);
+ }
+ }
+ results.Add (result);
+ }
+ foreach (var result in results.OrderBy (v => v.Project)) {
+ Console.WriteLine ($"Results for: {result.Project}");
+ Console.WriteLine ($" Enabled timings: {string.Join (", ", result.EnabledBuildTimes.Select (v => v.ToString ()))} average: {TimeSpan.FromTicks ((long) result.EnabledBuildTimes.Average (v => v.Ticks))}");
+ Console.WriteLine ($" Disabled timings: {string.Join (", ", result.DisabledBuildTimes.Select (v => v.ToString ()))} average: {TimeSpan.FromTicks ((long) result.DisabledBuildTimes.Average (v => v.Ticks))}");
+ }
+ }
+
+ class PrepareAssembliesTestResult {
+ public required string Project;
+ public List EnabledBuildTimes = new ();
+ public List DisabledBuildTimes = new ();
+ }
+ }
+}
+
diff --git a/tests/dotnet/UnitTests/TestBaseClass.cs b/tests/dotnet/UnitTests/TestBaseClass.cs
index e421218252eb..fbe234b535a6 100644
--- a/tests/dotnet/UnitTests/TestBaseClass.cs
+++ b/tests/dotnet/UnitTests/TestBaseClass.cs
@@ -133,6 +133,9 @@ protected static string GetDefaultRuntimeIdentifier (ApplePlatform platform, str
protected static string GetProjectPath (string project, string? subdir = null, ApplePlatform? platform = null)
{
+ if (TryGetTestProjectPath (project, platform ?? ApplePlatform.None, out var testProjectPath))
+ return testProjectPath;
+
var project_dir = Path.Combine (Configuration.SourceRoot, "tests", "dotnet", project);
if (!string.IsNullOrEmpty (subdir))
project_dir = Path.Combine (project_dir, subdir);
@@ -154,6 +157,18 @@ protected static string GetProjectPath (string project, string? subdir = null, A
return project_path;
}
+ static bool TryGetTestProjectPath (string project, ApplePlatform platform, [NotNullWhen (true)] out string? projectPath)
+ {
+ projectPath = null;
+
+ switch (project) {
+ case "monotouch-test":
+ projectPath = Path.Combine (Configuration.SourceRoot, "tests", project, "dotnet", platform.AsString (), project + ".csproj");
+ return true;
+ }
+ return false;
+ }
+
protected string GetPlugInsRelativePath (ApplePlatform platform)
{
switch (platform) {
diff --git a/tests/introspection/ApiTypoTest.cs b/tests/introspection/ApiTypoTest.cs
index 14cd4fb69cb2..1c5758bca225 100644
--- a/tests/introspection/ApiTypoTest.cs
+++ b/tests/introspection/ApiTypoTest.cs
@@ -19,11 +19,11 @@
// limitations under the License.
//
+
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Versioning;
-using System.Text;
using System.Text.RegularExpressions;
#if MONOMAC
using AppKit;
@@ -47,16 +47,6 @@ public ApiTypoTest ()
ContinueOnFailure = true;
}
- public virtual bool Skip (Type baseType, string typo)
- {
- return SkipAllowed (baseType.Name, null, typo);
- }
-
- public virtual bool Skip (MemberInfo methodName, string typo)
- {
- return SkipAllowed (methodName.DeclaringType?.Name, methodName.Name, typo);
- }
-
readonly HashSet allowedRule3 = new HashSet {
"IARAnchorCopying", // We're showing a code snippet in the 'Advice' message and that shouldn't end with a dot.
};
@@ -70,757 +60,807 @@ public virtual bool Skip (MemberInfo methodName, string typo)
};
Dictionary allowed = new Dictionary () {
- { "Aac", All },
- { "Abgr", All },
- { "Accurracy", All },
- { "Achivements", All },
- { "Acos", All },
- { "Acosh", All },
- { "Activatable", All },
- { "Addin", All },
- { "Addl", All },
- { "Addons", ApplePlatform.MacOSX },
- { "Addr", All },
- { "Adessive", All },
- { "Adjustmentfor", All & ~ApplePlatform.MacOSX },
- { "Afi", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Agc", All },
- { "Ahap", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Aifc", All },
- { "Aiff", All },
- { "Aime", ApplePlatform.MacOSX },
- { "Aio", ApplePlatform.MacOSX },
+ { "Aac", All }, // Advanced Audio Coding
+ { "Abgr", All }, // alpha-blue-green-red
+ { "Achivements", All }, // Apple API spelling
+ { "Ack", All }, // acknowledgment
+ { "Acn", All }, // Ambisonic Channel Numbering
+ { "Acos", All }, // arc cosine
+ { "Acosh", All }, // inverse hyperbolic cosine
+ { "Activatable", All }, // valid English derivative
+ { "Addin", All }, // compound word
+ { "Addl", All }, // additional abbreviation
+ { "Addons", ApplePlatform.MacOSX }, // compound word
+ { "Addr", All }, // address abbreviation
+ { "Adessive", All }, // linguistic case
+ { "Adposition", All }, // linguistic term
+ { "Aes", All }, // Advanced Encryption Standard
+ { "Afi", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API abbreviation
+ { "Agc", All }, // automatic gain control
+ { "Ahap", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // Apple Haptics Pattern
+ { "Aifc", All }, // AIFF-C audio format
+ { "Aiff", All }, // Audio Interchange File
+ { "Aime", ApplePlatform.MacOSX }, // cashless payment brand
+ { "Aio", ApplePlatform.MacOSX }, // all-in-one abbreviation
{ "Alg", All }, // short for Algorithm
- { "Aliasable", All },
- { "Allative", All },
- { "Amete", All },
- { "Amr", All },
- { "Ancs", All & ~ApplePlatform.MacOSX },
- { "Ane", All },
- { "Anglet", All },
- { "Apac", All },
- { "Apdu", All },
- { "Apl", All & ~ApplePlatform.TVOS },
+ { "Alem", All }, // Ethiopic "Amete Alem" calendar
+ { "Aliasable", All }, // valid English derivative
+ { "Allative", All }, // linguistic case
+ { "Amete", All }, // Ethiopic calendar term
+ { "Amr", All }, // Adaptive Multi-Rate
+ { "Ancs", All & ~ApplePlatform.MacOSX }, // Apple Notification Center
+ { "Ane", All }, // Apple Neural Engine
+ { "Anglet", All }, // measurement term
+ { "Apac", All }, // Asia-Pacific abbreviation
+ { "Apdu", All }, // smart-card protocol unit
+ { "Apl", All & ~ApplePlatform.TVOS }, // APL language acronym
{ "Apng", All }, // Animated Portable Network Graphics
- { "Apns", All & ~ApplePlatform.TVOS },
- { "Appactive", ApplePlatform.MacOSX },
- { "Applei", All },
- { "Aps", ApplePlatform.MacOSX },
- { "Apv", ApplePlatform.MacOSX },
- { "Arae", ApplePlatform.MacOSX },
- { "Arcball", All },
- { "Argb", All },
- { "Arraycollation", All & ~ApplePlatform.MacOSX },
- { "Asin", All },
- { "Asinh", All },
- { "Astc", All },
- { "Aswas", ApplePlatform.MacOSX },
- { "Atan", All },
- { "Atanh", All },
- { "Atm", All },
+ { "Apns", All & ~ApplePlatform.TVOS }, // Apple Push Notification Service
+ { "Applei", All }, // Apple API selector fragment
+ { "Aps", ApplePlatform.MacOSX }, // Apple Push Service
+ { "Apv", ApplePlatform.MacOSX }, // Apple API abbreviation
+ { "Arcball", All }, // 3D rotation control
+ { "Argb", All }, // alpha-red-green-blue
+#if !XAMCORE_5_0
+ { "Arraycollation", All & ~ApplePlatform.MacOSX }, // SortedArrayFromArraycollationStringSelector - will be renamed in XAMCORE_5_0
+#endif
+ { "Asin", All }, // arc sine
+ { "Asinh", All }, // inverse hyperbolic sine
+ { "Astc", All }, // Adaptive Scalable Texture Compression
+ { "Atan", All }, // arc tangent
+ { "Atanh", All }, // inverse hyperbolic tangent
+ { "Atm", All }, // asynchronous transfer mode
{ "Atmos", All }, // Dolby Atmos
- { "Atr", All },
+ { "Atr", All }, // Answer To Reset
{ "Ats", All }, // App Transport Security
- { "Atsc", All },
- { "Attr", ApplePlatform.MacOSX },
- { "Attrib", All },
- { "Attributesfor", ApplePlatform.MacOSX },
- { "Attributevalue", All },
+ { "Atsc", All }, // TV broadcast standard
+ { "Attr", ApplePlatform.MacOSX }, // attribute abbreviation
+ { "Attrib", All }, // attribute abbreviation
+#if !XAMCORE_5_0
+ { "Attributevalue", All }, // ReplacementValueForAttributevalue - will be renamed in XAMCORE_5_0
+#endif
{ "Attrs", All }, // Attributes (used by Apple for keys)
- { "Audiofile", All },
- { "Audiograph", ApplePlatform.MacOSX },
- { "Authenticatable", ApplePlatform.MacOSX },
- { "Automapping", All },
- { "Automatch", All },
- { "Automounted", All },
- { "Autoredirect", ApplePlatform.MacCatalyst | ApplePlatform.TVOS },
- { "Autospace", ApplePlatform.MacOSX },
- { "Autostarts", ApplePlatform.MacOSX },
+ { "Audiofile", All }, // compound word
+ { "Audiograph", ApplePlatform.MacOSX }, // compound word
+ { "Authenticatable", ApplePlatform.MacOSX }, // valid English derivative
+ { "Automapping", All }, // compound word
+ { "Automatch", All }, // compound word
+ { "Automounted", All }, // compound word
+ { "Autoredirect", ApplePlatform.MacCatalyst | ApplePlatform.TVOS }, // compound word
+ { "Autospace", ApplePlatform.MacOSX }, // compound word
+ { "Autostarts", ApplePlatform.MacOSX }, // compound word
{ "Avb", All }, // acronym: Audio Video Bridging
{ "Avci", All }, // file type
- { "Avg", All },
- { "Axept", All & ~ApplePlatform.TVOS },
- { "Bancomat", All & ~ApplePlatform.TVOS },
- { "Bary", All },
- { "Ber", All },
+ { "Avg", All }, // average abbreviation
+ { "Axept", All & ~ApplePlatform.TVOS }, // payment terminal brand
+ { "Bancomat", All & ~ApplePlatform.TVOS }, // Italian payment network
+ { "Bancaires", All & ~ApplePlatform.TVOS }, // Cartes Bancaires payment network
+ { "Bary", All }, // barycentric abbreviation
+ { "Ber", All }, // Basic Encoding Rules
{ "Bggr", All }, // acronym for Blue, Green, Green, Red
{ "Bgra", All }, // acrnym for Blue, Green, Red, Alpha
- { "Bgrx", All },
- { "Bim", All },
- { "Bitangent", All },
- { "Blinn", All },
- { "Blit", All },
- { "Blockmap", ApplePlatform.MacOSX },
- { "Blockquote", ApplePlatform.MacOSX },
- { "Brotli", All },
- { "Bsd", ApplePlatform.MacOSX },
- { "Bsln", All },
- { "Bssid", All & ~ApplePlatform.TVOS },
+ { "Bgrx", All }, // blue-green-red-unused
+ { "Bim", All }, // BIM file/code term
+ { "Bitangent", All }, // geometry term
+ { "Blinn", All }, // Blinn shading model
+ { "Blit", All }, // graphics copy operation
+ { "Blockmap", ApplePlatform.MacOSX }, // compound word
+ { "Blockquote", ApplePlatform.MacOSX }, // HTML element name
+ { "Brotli", All }, // compression format
+ { "Bsd", ApplePlatform.MacOSX }, // Berkeley Software Distribution
+ { "Bsln", All }, // OpenType baseline tag
+ { "Bssid", All & ~ApplePlatform.TVOS }, // wireless network identifier
{ "Btle", ApplePlatform.MacOSX }, // Bluetooth Low Energy
- { "Cabac", All },
+ { "Cabac", All }, // video coding acronym
{ "Caf", All }, // acronym: Core Audio Format
- { "Callables", All },
- { "Callpout", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
+ { "Callables", All }, // valid English plural
{ "Cartes", All & ~ApplePlatform.TVOS }, // french
- { "Catmull", All },
- { "Cavlc", All },
- { "Ccitt", ApplePlatform.MacOSX },
- { "Cct", All },
- { "Ccw", All },
+ { "Catmull", All }, // Catmull-Rom term
+ { "Cavlc", All }, // video coding acronym
+ { "Ccitt", ApplePlatform.MacOSX }, // standards body acronym
+ { "Cbc", All }, // Cipher Block Chaining
+ { "Cct", All }, // correlated color temperature
+ { "Ccw", All }, // counterclockwise abbreviation
{ "Cda", All & ~ApplePlatform.TVOS }, // acronym: Clinical Document Architecture
- { "Cdma", All },
- { "Cdrom", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Cea", All },
+ { "Cdf", All }, // Cumulative Distribution Function
+ { "Cdma", All }, // cellular standard
+ { "Cdrom", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // Compact Disc Read-Only Memory
+ { "Cea", All }, // standards acronym
{ "Celp", All }, // MPEG4ObjectID
{ "Celu", All }, // Continuously Differentiable Exponential Linear Unit (ML)
{ "Cfa", All }, // acronym: Color Filter Array
- { "Chacha", All },
- { "Chapv", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Characterteristic", All },
- { "Cholesky", All },
- { "Chromaticities", All },
- { "Chw", All },
- { "Ciexyz", ApplePlatform.MacOSX },
- { "Ciff", All },
- { "Cinemagraph", ApplePlatform.TVOS },
- { "Cinepak", All },
- { "Cla", All },
- { "Clearcoat", All },
- { "Clockstamp", All },
+ { "Chacha", All }, // ChaCha cipher
+ { "Chapv", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // CHAP variant acronym
+#if !XAMCORE_5_0
+ { "Characterteristic", All }, // UpdatedCharacterteristicValue - will be renamed in XAMCORE_5_0
+#endif
+ { "Cholesky", All }, // matrix decomposition
+ { "Chromaticities", All }, // color science term
+ { "Chw", All }, // tensor layout abbrev
+ { "Ciexyz", ApplePlatform.MacOSX }, // CIE XYZ color space
+ { "Cif", All }, // Common Intermediate Format
+ { "Ciff", All }, // Canon image format
+ { "Cinemagraph", ApplePlatform.TVOS }, // still-photo animation
+ { "Cinepak", All }, // video codec
+ { "Ciphersuite", All }, // TLS cipher suite
+ { "Cla", All }, // command class byte
+ { "Clearcoat", All }, // material property
+ { "Clockstamp", All }, // timestamp variant
{ "Cmaf", All }, // Common Media Application Format (mpeg4)
{ "Cmy", ApplePlatform.MacOSX }, // acronym: Cyan, magenta, yellow
{ "Cmyk", All }, // acronym: Cyan, magenta, yellow and key
- { "Cmyka", ApplePlatform.MacOSX },
+ { "Cmyka", ApplePlatform.MacOSX }, // CMYK plus alpha
{ "Cnn", All }, // Convolutional Neural Network
- { "Cns", ApplePlatform.MacOSX },
- { "Codabar", All },
- { "Commited", ApplePlatform.MacOSX },
- { "Conecs", All & ~ApplePlatform.TVOS },
- { "Constrainted", ApplePlatform.MacOSX },
- { "Conv", All },
- { "Copyback", All },
- { "Cose", All & ~ApplePlatform.TVOS },
- { "Crosstraining", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Csr", All },
- { "Ctm", ApplePlatform.MacOSX },
- { "Ctor", All },
- { "Cubemap", All },
- { "Cymk", ApplePlatform.MacOSX },
- { "Cymka", ApplePlatform.MacOSX },
- { "Daap", All },
- { "Dangi", All },
- { "Dankort", All & ~ApplePlatform.TVOS },
- { "Dav", All & ~ApplePlatform.TVOS },
+ { "Cns", ApplePlatform.MacOSX }, // Chinese National Standard
+ { "Codabar", All }, // barcode symbology
+#if !XAMCORE_5_0
+ { "Commited", ApplePlatform.MacOSX }, // CommitedLoad - will be renamed in XAMCORE_5_0
+#endif
+ { "Conf", All }, // configuration abbreviation
+ { "Conecs", All & ~ApplePlatform.TVOS }, // card network acronym
+ { "Conv", All }, // convolution abbreviation
+ { "Cooldown", All & ~ApplePlatform.TVOS }, // compound word
+ { "Copyback", All }, // storage operation
+ { "Cose", All & ~ApplePlatform.TVOS }, // CBOR Object Signing and Encryption
+ { "Crosstraining", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // compound word
+ { "Csr", All }, // certificate signing request
+ { "Csc", All }, // cosecant
+ { "Ctm", ApplePlatform.MacOSX }, // current transform matrix
+ { "Ctor", All }, // constructor abbreviation
+ { "Cubemap", All }, // graphics texture type
+ { "Cymk", ApplePlatform.MacOSX }, // CMYK channel order
+ { "Cymka", ApplePlatform.MacOSX }, // CMYK plus alpha
+ { "Daap", All }, // Digital Audio Access Protocol
+ { "Dangi", All }, // Korean calendar
+ { "Dankort", All & ~ApplePlatform.TVOS }, // Danish payment card
+ { "Dav", All & ~ApplePlatform.TVOS }, // DAV protocol term
{ "Dcip", All }, // acronym: Digital Cinema Implementation Partners
- { "Deca", All & ~ApplePlatform.TVOS },
- { "Decomposables", All },
- { "Deinterlace", All },
- { "Denimonator", All },
- { "Denoise", All },
- { "Denoised", All },
- { "Depthwise", All },
- { "Dequantize", All },
- { "Descendents", All },
- { "Descriptorat", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Descriptorfor", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Dfsi", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
+ { "Deca", All & ~ApplePlatform.TVOS }, // metric prefix
+ { "Decomposables", All }, // valid English plural
+ { "Deinterlace", All }, // video processing term
+ { "Denoise", All }, // noise reduction term
+ { "Denoised", All }, // noise reduction term
+ { "Denoiser", All }, // noise reduction filter
+ { "Depthwise", All }, // ML convolution term
+ { "Dequantize", All }, // signal processing term
+ { "Dfsi", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API abbreviation
{ "Dhe", All }, // Diffie–Hellman key exchange
- { "Dhs", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Dhwio", All },
- { "Dicom", All },
- { "Diconnection", All },
+ { "Dhs", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API abbreviation
+ { "Dhwio", All }, // tensor layout abbrev
+ { "Dicom", All }, // medical imaging standard
+ { "Diconnection", All }, // Apple API spelling
{ "Diffable", All }, // that you can diff it.. made up word from apple
- { "Differental", All },
- { "Diffie", All },
- { "Dirbursement", All & ~ApplePlatform.TVOS },
- { "Directionfor", All & ~ApplePlatform.MacOSX },
- { "Dirs", ApplePlatform.MacOSX },
- { "Dismissable", ApplePlatform.MacOSX },
- { "Dissapearing", ApplePlatform.MacOSX },
- { "Dist", All },
+ { "Diffie", All }, // Diffie-Hellman name
+ { "Dirbursement", All & ~ApplePlatform.TVOS }, // Apple API spelling
+ { "Dirs", ApplePlatform.MacOSX }, // directories abbreviation
+ { "Dismissable", ApplePlatform.MacOSX }, // variant of dismissible
+ { "Dist", All }, // distance abbreviation
{ "Distinguised", ApplePlatform.MacOSX }, // ITLibPlaylistPropertyDistinguisedKind
- { "dlclose", All },
- { "dlerror", All },
- { "Dlfcn", All },
- { "Dls", ApplePlatform.MacOSX },
- { "Dng", All },
- { "Dnssec", All },
- { "Dont", All },
- { "Dop", ApplePlatform.iOS },
- { "Dopesheet", All },
+ { "dlclose", All }, // POSIX dynamic loader API
+ { "dlerror", All }, // POSIX dynamic loader API
+#if !XAMCORE_5_0
+ { "Directionfor", All & ~ApplePlatform.MacOSX }, // SetBaseWritingDirectionforRange - will be renamed in XAMCORE_5_0
+#endif
+ { "Dlfcn", All }, // dynamic loader header
+ { "Dls", ApplePlatform.MacOSX }, // Downloadable Sounds
+ { "Dng", All }, // Digital Negative format
+ { "Dnssec", All }, // DNS Security Extensions
+ { "Dont", All }, // selector fragment without apostrophe
+ { "Dop", All }, // data object parameter
+ { "Dopesheet", All }, // animation timeline view
{ "Downmix", All }, // Sound terminology that means making a stereo mix from a 5.1 surround mix.
- { "Dpa", All },
+ { "Dpa", All }, // Apple API abbreviation
{ "Dpad", All }, // Directional pad (D-pad)
{ "Dpads", All }, // plural of above
{ "Drm", ApplePlatform.MacOSX }, // MediaItemProperty.IsDrmProtected
- { "Droste", All },
- { "Dsf", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Dsfi", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Dstu", All & ~ApplePlatform.TVOS },
- { "Dtls", All },
+ { "Droste", All }, // Droste effect name
+ { "Dsf", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API abbreviation
+ { "Dsfi", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API abbreviation
+ { "Dstu", All & ~ApplePlatform.TVOS }, // Ukrainian standard acronym
+ { "Dtls", All }, // Datagram TLS
{ "Dtmf", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // DTMF
- { "Dtss", ApplePlatform.MacOSX },
- { "dy", All },
- { "Eap", All },
- { "Ebu", All },
+ { "Dtss", ApplePlatform.MacOSX }, // audio format acronym
+ { "dy", All }, // tensor dimension symbol
+ { "Eap", All }, // Extensible Authentication Protocol
+ { "Ean", All }, // European Article Number (barcode standard)
+ { "Ebu", All }, // European Broadcasting Union
{ "Ecc", All }, // Elliptic Curve Cryptography
{ "Ecdh", All }, // Elliptic Curve Diffie–Hellman
{ "Ecdhe", All }, // Elliptic Curve Diffie-Hellman Ephemeral
{ "Ecdsa", All }, // Elliptic Curve Digital Signature Algorithm
- { "Ecg", All & ~ApplePlatform.TVOS },
+ { "Ecg", All & ~ApplePlatform.TVOS }, // electrocardiogram
+ { "Echos", ApplePlatform.MacOSX }, // plural of echo
{ "Ecies", All }, // Elliptic Curve Integrated Encryption Scheme
{ "Ecn", All }, // Explicit Congestion Notification
{ "Ect", All }, // ECN Capable Transport
- { "Editability", All & ~ApplePlatform.MacOSX },
- { "Edr", All },
+ { "Editability", All & ~ApplePlatform.MacOSX }, // valid English noun
+ { "Edr", All }, // extended dynamic range
{ "Eftpos", All & ~ApplePlatform.TVOS }, // Electronic funds transfer at point of sale
- { "Eisu", ApplePlatform.MacOSX },
- { "Elative", All },
- { "Elu", All },
- { "Emagic", All },
- { "Emaili", All & ~ApplePlatform.TVOS },
- { "Embd", All },
- { "Emebedding", All },
+ { "Eisu", ApplePlatform.MacOSX }, // Japanese input mode
+ { "Elative", All }, // linguistic case
+ { "Elu", All }, // activation function
+ { "Emagic", All }, // audio software brand
+ { "Embd", All }, // embedded abbreviation
+#if !XAMCORE_5_0
+ { "Emebedding", All }, // NLContextualEmebeddingKey - will be renamed in XAMCORE_5_0
+#endif
{ "Emsg", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // 4cc
- { "Enc", All },
- { "Endc", All },
+ { "Enc", All }, // encoding abbreviation
+ { "Endc", All }, // 5G dual connectivity
{ "Eof", All }, // acronym End-Of-File
- { "Eppc", All },
- { "Epub", All },
- { "Erf", All },
- { "Essive", All },
- { "Evdo", All },
- { "Evictable", ApplePlatform.MacOSX | ApplePlatform.iOS },
- { "Exabits", All },
- { "Exbibits", All },
- { "Exhange", All },
- { "Expr", All },
- { "Exr", All },
- { "Extrinsics", All },
- { "Feli", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
+ { "Eppc", All }, // program-to-program comms
+ { "Epub", All }, // ebook file format
+ { "Erf", All }, // Ericsson Texture Compression format
+ { "Essive", All }, // linguistic case
+ { "Evdo", All }, // cellular data standard
+ { "Evictable", ApplePlatform.MacOSX | ApplePlatform.iOS }, // valid English derivative
+ { "Exabits", All }, // SI unit name
+ { "Exbibits", All }, // IEC unit name
+ { "Exbibytes", All }, // IEC unit name
+ { "Exp", All }, // exponent/exponential
+ { "Expr", All }, // expression abbreviation
+ { "Exr", All }, // OpenEXR image format
+ { "Extrinsics", All }, // computer vision term
+ { "Fcp", All }, // Apple ATS Forward Compatibility Policy
+ { "Feli", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // FeliCa term
{ "Felica", All & ~ApplePlatform.TVOS }, // Japanese contactless RFID smart card system
- { "Femtowatts", All },
- { "Fft", All },
- { "Fhir", All & ~ApplePlatform.TVOS },
- { "Fieldset", All & ~ApplePlatform.MacCatalyst },
- { "Flipside", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Formati", All },
- { "Fourty", ApplePlatform.MacOSX },
- { "Fov", All },
- { "Fqdns", All },
- { "Framebuffer", All },
- { "Framesetter", All },
- { "Freq", All },
+ { "Femtowatts", All }, // SI unit name
+ { "Fft", All }, // Fast Fourier Transform
+ { "Fhir", All & ~ApplePlatform.TVOS }, // healthcare data standard
+ { "Fieldset", All & ~ApplePlatform.MacCatalyst }, // HTML element name
+ { "Formati", All }, // FormatiTunesMetadata - word split of "Format" + "iTunes"
+ { "Fov", All }, // field of view
+ { "Fqdns", All }, // fully qualified domain names
+ { "Framebuffer", All }, // graphics buffer
+ { "Framesetter", All }, // Core Text type
+ { "Freq", All }, // frequency abbreviation
{ "Froms", ApplePlatform.MacOSX }, // NSMetadataItemWhereFromsKey
- { "Ftps", All },
- { "Gadu", All & ~ApplePlatform.TVOS },
- { "Gainmap", All },
+ { "Ftps", All }, // FTP over TLS
+ { "Func", All }, // function abbreviation
+ { "Gadu", All & ~ApplePlatform.TVOS }, // Gadu-Gadu messenger
+ { "Gainmap", All }, // HDR image term
{ "Gbrg", All }, // acronym for Green-Blue-Reg-Green
- { "Gbtac", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Gbtdc", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Gcm", All },
+ { "Gbtac", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API abbreviation
+ { "Gbtdc", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API abbreviation
+ { "Gcm", All }, // Galois/Counter Mode
{ "Gelu", All }, // Gaussian Error Linear Unit (ML)
- { "Gibibits", All },
- { "Gid", ApplePlatform.MacOSX },
- { "Gigapascals", All },
- { "Girocard", All & ~ApplePlatform.TVOS },
- { "Gles", ApplePlatform.iOS | ApplePlatform.TVOS },
+ { "Gen", All }, // generation (e.g. SiriRemote1stGen)
+ { "Gibibits", All }, // IEC unit name
+ { "Gid", ApplePlatform.MacOSX }, // group identifier
+ { "Gigapascals", All }, // SI unit name
+ { "Girocard", All & ~ApplePlatform.TVOS }, // German payment network
+ { "Gles", ApplePlatform.iOS | ApplePlatform.TVOS }, // OpenGL ES abbreviation
{ "Glorot", All }, // NN
{ "Gop", All }, // acronym for Group Of Pictures
- { "Gpp", All },
- { "Gps", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Grammarl", ApplePlatform.MacOSX },
+ { "Gpp", All }, // 3GPP standards acronym
+ { "Gps", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // Global Positioning System
+ { "Gsm", All }, // Global System for Mobile Communications
{ "Grbg", All }, // acronym for Green-Red-Blue-Green
- { "Greeking", ApplePlatform.MacOSX },
- { "Groupless", All & ~ApplePlatform.TVOS },
- { "Gru", All },
- { "Gtin", All },
- { "Gui", All },
- { "Hardlink", ApplePlatform.MacOSX },
- { "Hdmi", All & ~ApplePlatform.MacOSX },
- { "Hdr", All },
+ { "Groupless", All & ~ApplePlatform.TVOS }, // valid English derivative
+ { "Gru", All }, // gated recurrent unit
+ { "Gtin", All }, // Global Trade Item Number
+ { "Gui", All }, // graphical user interface
+ { "Handwashing", All & ~ApplePlatform.TVOS }, // compound word
+ { "Hankaku", All & ~ApplePlatform.MacOSX }, // Japanese half-width text
+ { "Hardlink", ApplePlatform.MacOSX }, // filesystem term
+ { "Hdmi", All & ~ApplePlatform.MacOSX }, // video connector standard
+ { "Hdr", All }, // high dynamic range
{ "Heic", All }, // file type
{ "Heics", All }, // High Efficiency Image File Format (Sequence)
{ "Heif", All }, // High Efficiency Image File Format
- { "Hermitean", All },
+ { "Hectopascals", All }, // SI unit name
{ "Hevc", All }, // CMVideoCodecType / High Efficiency Video Coding
- { "Hfp", All & ~ApplePlatform.MacOSX },
- { "Hhr", All },
- { "Himyan", All & ~ApplePlatform.TVOS },
- { "Hindlegs", All },
- { "Hipass", All },
- { "Histogrammed", All & ~ApplePlatform.TVOS },
+ { "Hfp", All & ~ApplePlatform.MacOSX }, // Bluetooth Hands-Free Profile
+ { "Hhr", All }, // Apple API abbreviation
+ { "Himyan", All & ~ApplePlatform.TVOS }, // South Arabian script
+ { "Hermitean", All }, // Apple's spelling of Hermitian in MPSGraph FFT methods
+ { "Hindlegs", All }, // compound word
+ { "Hipass", All }, // high-pass filter
+ { "Histogrammed", All & ~ApplePlatform.TVOS }, // valid technical term
{ "Hlg", All }, // Hybrid Log-Gamma
- { "Hls", All },
- { "Hoa", All },
- { "Hpke", ApplePlatform.MacOSX },
+ { "Hls", All }, // HTTP Live Streaming
+ { "Hoa", All }, // higher-order ambisonics
+ { "Hpke", ApplePlatform.MacOSX }, // Hybrid Public Key Encryption
{ "Hrtf", All }, // acronym used in AUSpatializationAlgorithm
- { "Hsb", ApplePlatform.MacOSX },
- { "Hsba", ApplePlatform.MacOSX },
+ { "Hsb", ApplePlatform.MacOSX }, // hue-saturation-brightness
+ { "Hsba", ApplePlatform.MacOSX }, // HSB plus alpha
{ "Hvxc", All }, // MPEG4ObjectID
- { "Hwc", All },
- { "Hwio", All },
- { "Iap", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Ibss", ApplePlatform.MacOSX },
- { "Icns", All },
- { "Ico", All },
- { "Iconfor", ApplePlatform.MacOSX },
- { "Icq", All & ~ApplePlatform.TVOS },
- { "Identd", All },
- { "Iec", All },
- { "Ies", All },
- { "Imageblock", All },
- { "Imagefor", All & ~ApplePlatform.MacOSX },
- { "Imap", All },
- { "Imaps", All },
- { "Imei", All & ~ApplePlatform.MacOSX },
- { "Img", All },
+ { "Hwc", All }, // tensor layout abbrev
+ { "Hwio", All }, // tensor layout abbrev
+ { "Iap", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // in-app purchase
+ { "Ibss", ApplePlatform.MacOSX }, // Wi-Fi ad hoc mode
+ { "Icns", All }, // Apple icon format
+ { "Ico", All }, // Windows icon format
+ { "Icq", All & ~ApplePlatform.TVOS }, // ICQ messenger name
+ { "Identd", All }, // ident daemon name
+ { "Ident", All }, // identifier abbreviation
+ { "Iec", All }, // International Electrotechnical Commission
+ { "Ies", All }, // lighting data format
+ { "Ikev", All }, // Internet Key Exchange v2
+ { "Ima", All }, // Interactive Multimedia Association
+ { "Imageblock", All }, // compound word
+ { "Imap", All }, // Internet Message Access Protocol
+ { "Imaps", All }, // IMAP over TLS
+ { "Imei", All & ~ApplePlatform.MacOSX }, // device identifier acronym
+ { "Img", All }, // image abbreviation
{ "Impl", All }, // BindingImplAttribute
- { "Incrementor", ApplePlatform.MacOSX },
- { "Indoorcycle", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Indoorrun", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Indoorwalk", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Inessive", All },
- { "Inklist", All },
- { "Inode", ApplePlatform.MacOSX },
- { "Inot", All },
- { "Inser", All },
- { "Instamatic", ApplePlatform.MacOSX },
- { "Interac", All & ~ApplePlatform.TVOS },
- { "Interactable", ApplePlatform.MacOSX },
- { "Interframe", All },
- { "Interitem", All },
- { "Intermenstrual", All & ~ApplePlatform.TVOS },
- { "Intoi", All & ~ApplePlatform.MacOSX },
- { "Intravaginal", All & ~ApplePlatform.TVOS },
- { "Inv", All },
- { "Invitable", All },
- { "Iou", All },
- { "Ipa", All },
- { "Ipp", All },
- { "Iptc", All },
- { "Ircs", All },
- { "Isrc", All },
- { "Itemto", ApplePlatform.MacOSX },
- { "Itf", All },
- { "Itt", All & ~ApplePlatform.TVOS },
- { "Itu", All },
+ { "Incrementor", ApplePlatform.MacOSX }, // valid English noun
+ { "Indoorcycle", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // compound word
+ { "Indoorrun", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // compound word
+ { "Indoorwalk", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // compound word
+ { "Inessive", All }, // linguistic case
+ { "Ingles", All }, // El Corte Ingles = Spanish payment card
+ { "Inklist", All }, // compound word
+ { "Inode", ApplePlatform.MacOSX }, // filesystem metadata term
+ { "Inser", All }, // Apple API selector fragment
+ { "Instamatic", ApplePlatform.MacOSX }, // Kodak camera brand
+ { "Interac", All & ~ApplePlatform.TVOS }, // Canadian payment network
+ { "Interactable", ApplePlatform.MacOSX }, // valid English derivative
+ { "Interframe", All }, // video coding term
+ { "Interitem", All }, // compound word
+ { "Intermenstrual", All & ~ApplePlatform.TVOS }, // medical term
+ { "Intravaginal", All & ~ApplePlatform.TVOS }, // medical term
+ { "Inv", All }, // inverse abbreviation
+ { "Invitable", All }, // valid English derivative
+ { "Iou", All }, // IOU abbreviation
+ { "Ipa", All }, // International Phonetic Alphabet
+ { "Ipp", All }, // Internet Printing Protocol
+ { "Iptc", All }, // photo metadata standard
+ { "Ircs", All }, // remote control standard
+ { "Isrc", All }, // recording code standard
+ { "Itf", All }, // Interleaved 2 of 5
+ { "Itt", All & ~ApplePlatform.TVOS }, // International Tape Association
+ { "Itu", All }, // International Telecommunication Union
{ "Itur", All }, // Itur_2020_Hlg
- { "Jaywan", All & ~ApplePlatform.TVOS },
+ { "Jaywan", All & ~ApplePlatform.TVOS }, // Jordanian payment network
{ "Jcb", All & ~ApplePlatform.TVOS }, // Japanese credit card company
- { "Jfif", All },
- { "Jis", ApplePlatform.MacOSX },
- { "Jrts", All & ~ApplePlatform.TVOS },
- { "Jwks", ApplePlatform.MacOSX },
- { "Jws", All & ~ApplePlatform.TVOS },
- { "Jwt", ApplePlatform.MacOSX },
- { "Keepalive", All },
- { "Keycode", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Keyerror", All },
- { "Keyi", All },
- { "Keypath", ApplePlatform.MacOSX },
- { "Keypoint", All },
- { "Keypoints", All },
- { "Kibibits", All },
- { "Kickboard", All & ~ApplePlatform.TVOS },
- { "Kiloampere", All },
- { "Kiloamperes", All },
- { "Kiloohms", All },
- { "Kilopascals", All },
- { "ks", All },
+ { "Jfif", All }, // JPEG File Interchange Format
+ { "Jis", ApplePlatform.MacOSX }, // Japanese Industrial Standards
+ { "Jrts", All & ~ApplePlatform.TVOS }, // Apple API abbreviation
+ { "Jws", ApplePlatform.MacOSX }, // JSON Web Signature
+ { "Jwks", ApplePlatform.MacOSX }, // JSON Web Key Set
+ { "Jwt", ApplePlatform.MacOSX }, // JSON Web Token
+ { "Keepalive", All }, // networking compound word
+ { "Keycode", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // compound word
+ { "Keyerror", All }, // compound word
+ { "Keyi", All }, // Apple API selector fragment
+ { "Keypath", ApplePlatform.MacOSX }, // compound word
+ { "Keypoint", All }, // computer vision term
+ { "Keypoints", All }, // computer vision term
+ { "Kibibits", All }, // IEC unit name
+ { "Kickboard", All & ~ApplePlatform.TVOS }, // compound word
+ { "Kiloampere", All }, // SI unit name
+ { "Kiloamperes", All }, // SI unit name
+ { "Kiloohms", All }, // SI unit name
+ { "Kilopascals", All }, // SI unit name
+ { "ks", All }, // word fragment from spell checker
{ "Kullback", All }, // Kullback-Leibler Divergence
- { "Lacunarity", All },
- { "Langauges", All & ~ApplePlatform.MacOSX },
+ { "Lacunarity", All }, // fractal geometry term
{ "Latm", All }, // Low Overhead Audio Transport Multiplex
- { "Lbc", All },
- { "Ldaps", All },
- { "Lerp", All },
- { "libcompression", All },
- { "libdispatch", All },
- { "Lingustic", All },
- { "Lod", All },
- { "Lopass", All },
- { "Lowlevel", All },
- { "Lpcm", All },
- { "Lstm", All },
- { "Lte", All },
- { "Ltr", All },
- { "Lun", All },
- { "Lut", All },
+ { "Lbc", All }, // audio codec acronym
+ { "Ldaps", All }, // LDAP over TLS
+ { "Leibler", All }, // Kullback-Leibler divergence
+ { "Lerp", All }, // linear interpolation
+ { "libcompression", All }, // Apple library name
+ { "libdispatch", All }, // Apple library name
+ { "Lingustic", All }, // Apple API spelling
+ { "Lite", All }, // lightweight variant
+ { "Loas", All }, // Low Overhead Audio Stream
+ { "Lod", All }, // level of detail
+ { "Lopass", All }, // low-pass filter
+ { "Lowlevel", All }, // compound word
+ { "Lpcm", All }, // Linear PCM audio
+ { "Lsb", All }, // Least Significant Bit
+ { "Lstm", All }, // long short-term memory
+ { "Lte", All }, // Long-Term Evolution
+ { "Ltp", All }, // AAC Long Term Prediction
+ { "Ltr", All }, // left-to-right abbreviation
+ { "Luma", All }, // luminance component in video
+ { "Lun", All }, // logical unit number
+ { "Lut", All }, // lookup table
{ "Lzfse", All }, // acronym
{ "Lzma", All }, // acronym
- { "Lzw", ApplePlatform.MacOSX },
+ { "Lzw", ApplePlatform.MacOSX }, // Lempel-Ziv-Welch
{ "Mada", All & ~ApplePlatform.TVOS }, // payment system
- { "Matchingcoalesce", All },
{ "Mcp", All }, // metacarpophalangeal (hand)
- { "Mebibits", All },
- { "Mebx", All },
- { "Meeza", All & ~ApplePlatform.TVOS },
- { "Megaampere", All },
- { "Megaamperes", All },
- { "Megaliters", All },
- { "Megameters", All },
- { "Megaohms", All },
- { "Megapascals", All },
- { "Mennekes", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Metacharacters", All },
- { "Metadatas", All },
- { "Metalness", All },
- { "Mgmt", All },
- { "Microampere", All },
- { "Microamperes", All },
- { "Microohms", All },
- { "Microwatts", All },
- { "Mifare", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Millimoles", All },
- { "Milliohms", All },
- { "Minification", All },
- { "Mmw", All },
- { "Mncs", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
+ { "Mebibits", All }, // IEC unit name
+ { "Mebx", All }, // image metadata box
+ { "Meeza", All & ~ApplePlatform.TVOS }, // Egyptian payment network
+ { "Megaampere", All }, // SI unit name
+ { "Megaamperes", All }, // SI unit name
+ { "Megaliters", All }, // SI unit name
+ { "Megameters", All }, // SI unit name
+ { "Megaohms", All }, // SI unit name
+ { "Megapascals", All }, // SI unit name
+ { "Mennekes", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // EV connector brand
+ { "Metacharacters", All }, // regex syntax term
+ { "Metadatas", All }, // valid technical plural
+ { "Metalness", All }, // PBR material property
+ { "Mgmt", All }, // management abbreviation
+ { "Microampere", All }, // SI unit name
+ { "Microamperes", All }, // SI unit name
+ { "Microohms", All }, // SI unit name
+ { "Microwatts", All }, // SI unit name
+ { "Mifare", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // NFC card brand
+ { "Mihret", All }, // Ethiopic "Amete Mihret" calendar
+ { "Millimoles", All }, // SI unit name
+ { "Milliohms", All }, // SI unit name
+ { "Minification", All }, // graphics scaling term
+ { "Mmw", All }, // millimeter wave
+ { "Mncs", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API abbreviation
{ "Mobike", All }, // acronym
- { "Monoline", All & ~ApplePlatform.TVOS },
- { "Morpher", All },
+ { "Monoline", All & ~ApplePlatform.TVOS }, // single-stroke design term
+ { "Morpher", All }, // graphics/animation term
{ "Mpe", All }, // acronym
- { "Mps", All },
+ { "Mps", All }, // metal performance shaders
{ "Msaa", All }, // multisample anti-aliasing
- { "Msi", All },
+ { "Msb", All }, // Most Significant Bit
+ { "Msi", All }, // installer package format
{ "Mtc", All }, // acronym
- { "Mtgp", All },
- { "Mtl", All },
+ { "Mtgp", All }, // PRNG algorithm name
+ { "Mtl", All }, // Metal framework prefix
{ "Mtu", All }, // acronym
- { "Muid", All & ~ApplePlatform.TVOS },
- { "Mul", All },
- { "Mult", All },
- { "Multiary", All },
- { "Multipath", All },
- { "Multipeer", All },
- { "Multiscript", All },
- { "Multiselect", All & ~ApplePlatform.MacOSX },
- { "Multivariant", All },
- { "Multiview", All },
- { "Muxed", All },
- { "Nacs", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Nai", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Nanaco", All & ~ApplePlatform.TVOS },
- { "Nand", All },
- { "Nanograms", All },
- { "Nanowatts", All },
- { "Ncdhw", All },
- { "Nchw", All },
- { "nd", All },
- { "Ndef", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Ndhwc", All },
- { "Nesterov", All },
- { "Nestrov", All },
- { "Nfc", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Nfnt", All },
- { "Nhwc", All },
- { "Nntps", All },
- { "Nonenumerated", ApplePlatform.MacOSX },
- { "Noninteractive", All & ~ApplePlatform.TVOS },
- { "Noop", All },
- { "Nop", ApplePlatform.MacOSX },
- { "Nsa", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Nsevent", ApplePlatform.MacOSX },
+ { "Muid", All & ~ApplePlatform.TVOS }, // MIDI universal identifier
+ { "Mul", All }, // multiply abbreviation
+ { "Mult", All }, // multiply abbreviation
+ { "Multiary", All }, // math/logic term
+ { "Multipath", All }, // networking term
+ { "Multipeer", All }, // Apple framework term
+ { "Multiscript", All }, // compound word
+ { "Multiselect", All & ~ApplePlatform.MacOSX }, // compound word
+ { "Multivariant", All }, // valid technical term
+ { "Multiview", All }, // graphics term
+ { "Muxed", All }, // multiplexed media term
+ { "Nacs", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // EV charging standard
+ { "Nai", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // network access identifier
+ { "Nal", All }, // Network Abstraction Layer (video coding)
+ { "Nanaco", All & ~ApplePlatform.TVOS }, // Japanese payment card
+ { "Nand", All }, // flash memory type
+ { "Nanograms", All }, // SI unit name
+ { "Nanowatts", All }, // SI unit name
+ { "Napas", All & ~ApplePlatform.TVOS }, // Vietnamese payment network
+ { "Ncdhw", All }, // tensor layout abbrev
+ { "Nchw", All }, // tensor layout abbrev
+ { "nd", All }, // tensor dimension symbol
+ { "Ndef", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // NFC data exchange format
+ { "Ndhwc", All }, // tensor layout abbrev
+ { "Nesterov", All }, // optimization method
+ { "Nestrov", All }, // Apple API spelling
+ { "Nfc", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // Near Field Communication
+ { "Nfnt", All }, // classic Mac font format
+ { "Nhwc", All }, // tensor layout abbrev
+ { "Nntps", All }, // NNTP over TLS
+ { "Nonenumerated", ApplePlatform.MacOSX }, // valid English derivative
+ { "Noninteractive", All & ~ApplePlatform.TVOS }, // valid English derivative
+ { "Noop", All }, // no-op abbreviation
+ { "Nop", ApplePlatform.MacOSX }, // no-op instruction
+ { "Nsa", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // network service access
+ { "Nsevent", ApplePlatform.MacOSX }, // Apple API class name
{ "Nsl", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // InternetLocationNslNeighborhoodIcon
- { "Ntlm", All },
- { "Ntsc", All },
- { "Numberof", ApplePlatform.MacOSX },
- { "Nyquist", All & ~ApplePlatform.MacOSX },
- { "Objectness", All },
- { "Occlussion", All },
- { "Ocr", All },
+ { "Ntlm", All }, // Windows auth protocol
+ { "Ntsc", All }, // video standard acronym
+ { "Nyquist", All & ~ApplePlatform.MacOSX }, // sampling theorem term
+ { "Oaep", All }, // Optimal Asymmetric Encryption Padding
+ { "Objectness", All }, // ML detection score
+ { "Ocr", All }, // optical character recognition
{ "Ocsp", All }, // Online Certificate Status Protocol
- { "Octree", All },
- { "Ocurrences", All },
- { "Odia", All },
- { "Ohwi", All },
- { "Oid", All },
- { "Oidhw", All },
- { "Oihw", All },
- { "Onnx", All },
- { "Oper", All & ~ApplePlatform.MacOSX },
+ { "Octree", All }, // spatial partition tree
+ { "Odia", All }, // Indic language name
+ { "Ohwi", All }, // tensor layout abbrev
+ { "Oid", All }, // object identifier
+ { "Oidhw", All }, // tensor layout abbrev
+ { "Oihw", All }, // tensor layout abbrev
+ { "Onnx", All }, // Open Neural Network Exchange
+ { "Ootf", All }, // Opto-Optical Transfer Function (HDR)
+ { "Oper", All & ~ApplePlatform.MacOSX }, // operator abbreviation
{ "Organisation", All }, // kCGImagePropertyIPTCExtRegistryOrganisationID in Xcode9.3-b1
- { "Orth", All },
+ { "Orth", All }, // orthographic abbreviation
{ "Osa", All }, // Open Scripting Architecture
{ "Otsu", All }, // threshold for image binarization
- { "ove", All },
- { "Overline", All & ~ApplePlatform.TVOS },
+ { "ove", All }, // word fragment from spell checker
+ { "Overline", All & ~ApplePlatform.TVOS }, // typography term
{ "Paeth", All }, // PNG filter
- { "Palettize", All },
- { "Parms", All },
- { "Pausable", All },
- { "Pbm", ApplePlatform.MacOSX },
- { "Pci", All & ~ApplePlatform.MacOSX },
- { "Pcl", All },
- { "Pcm", All },
- { "Pde", ApplePlatform.MacOSX },
- { "Pdu", All },
- { "Peap", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Pebibits", All },
- { "Performwith", ApplePlatform.MacOSX },
- { "Perlin", All },
- { "Persistable", All },
- { "Persistance", All },
- { "Petabits", All },
+ { "Palettize", All }, // graphics term
+ { "Parms", All }, // parameters abbreviation
+ { "Pausable", All }, // valid English derivative
+ { "Pbm", ApplePlatform.MacOSX }, // Portable Bitmap format
+ { "Pci", All & ~ApplePlatform.MacOSX }, // Peripheral Component Interconnect
+ { "Pcl", All }, // Printer Command Language
+ { "Pcm", All }, // pulse-code modulation
+ { "Pde", ApplePlatform.MacOSX }, // partial differential equation
+ { "Pdu", All }, // protocol data unit
+ { "Peap", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Protected EAP
+ { "Pebibits", All }, // IEC unit name
+ { "Pebibytes", All }, // IEC unit name
+ { "Perlin", All }, // Perlin noise name
+ { "Persistable", All }, // valid English derivative
+ { "Petabits", All }, // SI unit name
{ "Pfs", All }, // acronym
- { "Philox", All },
- { "Photoplethysmogram", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Phq", All & ~ApplePlatform.TVOS },
- { "Phy", ApplePlatform.MacOSX },
- { "Picometers", All },
- { "Picowatts", All },
- { "Pkcs", All },
- { "Placemark", All },
- { "Playout", All },
+ { "Philox", All }, // PRNG algorithm name
+ { "Phong", All }, // Phong shading/reflection model
+ { "Photoplethysmogram", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // medical sensor term
+ { "Phq", All & ~ApplePlatform.TVOS }, // questionnaire acronym
+ { "Phy", ApplePlatform.MacOSX }, // physical layer term
+ { "Picometers", All }, // SI unit name
+ { "Pickleball", All & ~ApplePlatform.TVOS }, // sport name
+ { "Picowatts", All }, // SI unit name
+ { "Pkcs", All }, // crypto standard acronym
+ { "Placemark", All }, // mapping term
+ { "Playout", All }, // broadcasting term
+ { "Plessey", All }, // MSI/Plessey barcode symbology
{ "Pnc", All }, // MIDI
- { "Pnorm", All },
- { "Polyline", All },
- { "Polylines", All },
- { "Popularimeter", All },
- { "Postback", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
+ { "Pnorm", All }, // Lp norm notation
+ { "Polyline", All }, // graphics geometry term
+ { "Polylines", All }, // graphics geometry term
+ { "Popularimeter", All }, // ID3 metadata field
+ { "Postback", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // marketing/webhook term
{ "Ppd", ApplePlatform.MacOSX }, // PostScript Printer Description
- { "Ppk", All },
- { "Preauthentication", ApplePlatform.MacOSX },
- { "Preds", All },
- { "Prefilter", All },
- { "Prereleased", All },
- { "Prerolls", All },
- { "Preseti", All },
- { "Previewable", ApplePlatform.MacOSX },
- { "Prf", All & ~ApplePlatform.TVOS },
- { "Propogate", All },
- { "Psec", All },
- { "Psk", All },
- { "Pskc", All & ~ApplePlatform.TVOS },
+ { "Ppk", All }, // Apple API abbreviation
+ { "Preauthentication", ApplePlatform.MacOSX }, // compound word
+ { "Preds", All }, // predictions abbreviation
+ { "Prefilter", All }, // compound word
+ { "Prereleased", All }, // compound word
+ { "Prerolls", All }, // media playback term
+ { "Preseti", All }, // Apple API selector fragment
+ { "Prev", All }, // previous abbreviation
+ { "Previewable", ApplePlatform.MacOSX }, // valid English derivative
+ { "Prf", All & ~ApplePlatform.TVOS }, // pseudo-random function
+ { "Psec", All }, // picosecond abbreviation
+ { "Psk", All }, // pre-shared key
+ { "Pskc", All & ~ApplePlatform.TVOS }, // PSKC key container
{ "Psm", All }, // Protocol/Service Multiplexer
- { "Ptp", ApplePlatform.MacOSX },
- { "Pvr", All },
+ { "Privs", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // privileges abbreviation
+ { "Pss", All }, // Probabilistic Signature Scheme (RSA-PSS)
+ { "Ptp", ApplePlatform.MacOSX }, // Precision Time Protocol
+ { "Ptss", All & ~ApplePlatform.TVOS }, // Presentation Timestamps (plural)
+ { "Pvr", All }, // PowerVR graphics brand
{ "Pvrtc", All }, // MTLBlitOption - PowerVR Texture Compression
- { "Qos", All },
- { "Quadding", All },
- { "Quaterniond", All },
- { "Quic", All },
- { "Qura", All },
- { "Qwac", All },
- { "Raycast", ApplePlatform.iOS },
- { "Raycasts", ApplePlatform.iOS },
- { "Reacquirer", All },
- { "Reassociation", ApplePlatform.MacOSX },
- { "Reauthentication", ApplePlatform.MacOSX },
- { "Rectfrom", ApplePlatform.MacOSX },
- { "Registeration", ApplePlatform.MacOSX },
- { "Reinvitation", All },
- { "Reinvite", All },
- { "Rel", All },
- { "Relocalization", ApplePlatform.iOS },
+ { "Qos", All }, // quality of service
+ { "Quadding", All }, // typesetting term
+ { "Quaterniond", All }, // double quaternion type
+ { "Quic", All }, // transport protocol
+ { "Qura", All }, // payment network name
+ { "Qwac", All }, // qualified website cert
+ { "Raycast", ApplePlatform.iOS }, // graphics/AR term
+ { "Raycasts", ApplePlatform.iOS }, // graphics/AR term
+ { "Reacquirer", All }, // valid English noun
+ { "Reassociation", ApplePlatform.MacOSX }, // networking term
+ { "Reauthentication", ApplePlatform.MacOSX }, // compound word
+ { "Reinvitation", All }, // valid English noun
+ { "Reinvite", All }, // session protocol term
+ { "Rel", All }, // relation abbreviation
+ { "Relocalization", ApplePlatform.iOS }, // AR/vision term
{ "Relu", All }, // Rectified Linear Unit (ML)
- { "Remmote", All },
- { "Replayable", All },
- { "Reprojection", All },
- { "Rgb", All },
- { "Rgba", All },
- { "Rgbaf", All },
- { "Rgbah", All },
- { "Rgbx", All },
+ { "Replayable", All }, // valid English derivative
+ { "Reprojection", All }, // graphics/vision term
+ { "Rfc", All }, // Request for Comments
+ { "Rgb", All }, // red-green-blue
+ { "Rgba", All }, // red-green-blue-alpha
+ { "Rgbaf", All }, // RGBA float format
+ { "Rgbah", All }, // RGBA half-float format
+ { "Rgbx", All }, // RGB plus unused byte
{ "Rggb", All }, // acronym for Red, Green, Green, Blue
- { "Rint", All },
- { "Rle", All },
- { "Rnn", All },
- { "Roi", All },
+ { "Rint", All }, // round-to-integer function
+ { "Rle", All }, // run-length encoding
+ { "Rms", All }, // root mean square
+ { "Rnn", All }, // recurrent neural network
+ { "Roi", All }, // region of interest
{ "Romm", All }, // acronym: Reference Output Medium Metric
- { "Rpa", All },
+ { "Rpa", All }, // Resolvable Private Address
{ "Rpn", All }, // acronym
{ "Rsa", All }, // Rivest, Shamir and Adleman
- { "Rsapss", All },
+ { "Rsapss", All }, // RSA-PSS signature scheme
{ "Rsqrt", All }, // reciprocal square root
- { "Rssi", All },
- { "Rtl", All },
- { "Rtp", All & ~ApplePlatform.MacOSX },
- { "Rtsp", All },
+ { "Rssi", All }, // signal strength acronym
+ { "Rtl", All }, // right-to-left abbreviation
+ { "Rtp", All & ~ApplePlatform.MacOSX }, // Real-time Transport Protocol
+ { "Rtsp", All }, // streaming control protocol
{ "Saml", All & ~ApplePlatform.MacCatalyst }, // acronym
- { "Scc", All },
- { "Scn", All },
- { "Sdh", ApplePlatform.TVOS },
- { "Sdk", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Sdnn", All & ~ApplePlatform.TVOS },
- { "Sdof", ApplePlatform.MacOSX },
- { "Sdr", All },
+ { "Sbr", All }, // Spectral Band Replication (AAC)
+ { "Scc", All }, // subtitle/timing format
+ { "Scn", All }, // SceneKit prefix
+ { "Sdh", ApplePlatform.TVOS }, // subtitles for deaf/hard hearing
+ { "Sdk", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // software development kit
+ { "Sdnn", All & ~ApplePlatform.TVOS }, // Apple API abbreviation
+ { "Sdof", ApplePlatform.MacOSX }, // synthetic depth of field
+ { "Sdr", All }, // standard dynamic range
{ "Sdtv", ApplePlatform.TVOS }, // acronym: Standard Definition Tele Vision
- { "Securit", ApplePlatform.iOS },
- { "Seekable", All },
- { "Sel", All & ~ApplePlatform.MacOSX },
+ { "Securit", ApplePlatform.iOS }, // Apple API selector fragment
+ { "Seekable", All }, // valid English derivative
+ { "Sel", All & ~ApplePlatform.MacOSX }, // Objective-C selector
{ "Selu", All }, // Scaled Exponential Linear unit (ML)
- { "Semitransient", ApplePlatform.MacOSX },
- { "Sensel", All },
- { "Shadable", All },
- { "Siemen", All & ~ApplePlatform.TVOS },
- { "Signbit", All },
+ { "Semitransient", ApplePlatform.MacOSX }, // valid technical term
+ { "Sensel", All }, // pressure sensor brand
+ { "Sha", All }, // Secure Hash Algorithm
+ { "Shadable", All }, // graphics term
+ { "Siemen", All & ~ApplePlatform.TVOS }, // Apple API singular form
+ { "Signbit", All }, // math library term
{ "Sint", All }, // as in "Signed Integer"
- { "Sixtyfour", ApplePlatform.MacOSX },
- { "Slerp", All },
- { "Slomo", All },
- { "Smpte", All },
- { "Snapshotter", All },
- { "Snn", All },
- { "Snorm", All },
- { "Sobel", All },
+ { "Sixtyfour", ApplePlatform.MacOSX }, // compound number word
+ { "Slerp", All }, // spherical interpolation
+ { "Slomo", All }, // slow motion shorthand
+ { "Smpte", All }, // media standards body
+ { "Snapshotter", All }, // valid English noun
+ { "Snn", All }, // Apple API abbreviation
+ { "Snorm", All }, // signed normalized format
+ { "Sobel", All }, // image filter name
{ "Softmax", All }, // get_SoftmaxNormalization
- { "Sopen", ApplePlatform.MacOSX },
- { "Spacei", All },
- { "Spl", All },
- { "Sqrt", All },
- { "Srgb", All },
- { "Ssid", All },
- { "Ssids", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Ssml", All },
- { "Sso", ApplePlatform.MacOSX },
- { "st", All },
- { "Sta", ApplePlatform.MacOSX },
- { "Standarize", All },
- { "Strided", All },
- { "Subband", All & ~ApplePlatform.TVOS },
- { "Subbeat", All },
- { "Subcaption", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Subcardioid", All & ~ApplePlatform.MacOSX },
- { "Subentities", All },
- { "Subfilter", All & ~ApplePlatform.TVOS },
- { "Subfilters", All & ~ApplePlatform.TVOS },
- { "Subheadline", All },
- { "Sublocality", All },
- { "Sublocation", All },
- { "Submesh", All },
- { "Submeshes", All },
- { "Subpixel", All },
- { "Subresources", All },
- { "Subsec", All },
+ { "Sopen", ApplePlatform.MacOSX }, // Apple API abbreviation
+ { "Spacei", All }, // Apple API selector fragment
+ { "Spl", All }, // sound pressure level
+ { "Sqrt", All }, // square root function
+ { "Srgb", All }, // standard RGB color space
+ { "Ssid", All }, // Wi-Fi network identifier
+ { "Ssids", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // plural of SSID
+ { "Ssml", All }, // Speech Synthesis Markup Language
+ { "Sso", ApplePlatform.MacOSX }, // single sign-on
+ { "Ssr", All }, // Scalable Sample Rate (AAC)
+ { "st", All }, // ordinal suffix
+ { "Sta", ApplePlatform.MacOSX }, // station mode acronym
+ { "Strided", All }, // linear algebra term
+ { "Subband", All & ~ApplePlatform.TVOS }, // signal processing term
+ { "Subbeat", All }, // music timing term
+ { "Subcaption", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // compound word
+ { "Subcardioid", All & ~ApplePlatform.MacOSX }, // microphone polar pattern
+ { "Subentities", All }, // valid English plural
+ { "Subfilter", All & ~ApplePlatform.TVOS }, // compound word
+ { "Subfilters", All & ~ApplePlatform.TVOS }, // compound word
+ { "Subheadline", All }, // compound word
+ { "Sublocality", All }, // MapKit placemark term
+ { "Sublocation", All }, // compound word
+ { "Submesh", All }, // graphics geometry term
+ { "Submeshes", All }, // graphics geometry term
+ { "Subpixel", All }, // display/graphics term
+ { "Subresources", All }, // valid English plural
+ { "Subsec", All }, // subsecond abbreviation
{ "Suica", All & ~ApplePlatform.TVOS }, // Japanese contactless smart card type
- { "Superentity", All },
- { "Supertype", All },
- { "Supertypes", All },
- { "Supression", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Svfg", All },
+ { "Superentity", All }, // Core Data term
+ { "Supertype", All }, // type-system term
+ { "Supertypes", All }, // type-system term
+ { "Svfg", All }, // stochastic variance filtering
{ "Svg", All }, // Scalable Vector Graphics
- { "Svgf", All },
- { "Swolf", All & ~ApplePlatform.TVOS },
- { "Sysex", All },
- { "Targetand", ApplePlatform.MacOSX },
- { "Tbgr", All },
- { "Tdoa", ApplePlatform.iOS },
- { "Tebibits", All },
- { "Tensorflow", All },
- { "Tessellator", All },
- { "Texcoord", All },
- { "Texel", All },
- { "Tga", All },
- { "th", All },
- { "Threadgroup", All },
- { "Threadgroups", All },
- { "Thumbnailing", All & ~ApplePlatform.TVOS },
- { "Thumbstick", All },
- { "Thumbsticks", ApplePlatform.iOS },
- { "Timecodes", All & ~ApplePlatform.TVOS },
- { "Tls", All },
- { "Tlv", All },
- { "Tmoney", All & ~ApplePlatform.TVOS },
- { "Toc", All },
- { "Toci", All },
- { "Tonemap", All },
- { "Transceive", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Trc", All },
- { "Tri", All },
- { "Ttls", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Tweening", All },
- { "Twentyfour", ApplePlatform.MacOSX },
- { "Twips", ApplePlatform.MacOSX },
- { "tx", All },
- { "ty", All },
- { "Udi", All & ~ApplePlatform.TVOS },
- { "Udp", All },
- { "Uid", All & ~ApplePlatform.TVOS },
- { "Unconfigured", All & ~ApplePlatform.MacOSX },
- { "Undecodable", All },
- { "Underrun", All },
- { "Unemphasized", ApplePlatform.MacOSX },
- { "Unentitled", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Unfetched", All },
- { "Unioning", All },
- { "Unmap", All },
- { "Unmatch", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Unorm", All },
- { "Unpremultiplied", All },
- { "Unpremultiplying", All },
- { "Unprepare", All },
- { "Unproject", All },
- { "Unpublish", All },
- { "Unsolo", All },
- { "Unsynced", ApplePlatform.MacOSX | ApplePlatform.iOS },
- { "Untrash", ApplePlatform.iOS },
- { "Upce", All },
- { "Upi", ApplePlatform.iOS },
- { "Uri", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
+ { "Svgf", All }, // spatiotemporal variance-guided filter
+ { "Swolf", All & ~ApplePlatform.TVOS }, // swim efficiency score
+ { "Symbologies", All }, // plural of symbology (barcode)
+ { "Synchronizable", All }, // valid English derivative
+ { "Sysex", All }, // MIDI system exclusive
+ { "Tbgr", All }, // texture color format
+ { "Tdoa", ApplePlatform.iOS }, // time difference of arrival
+ { "Tebibits", All }, // IEC unit name
+ { "Tensorflow", All }, // machine learning framework
+ { "Tessellator", All }, // graphics term
+ { "Texcoord", All }, // texture coordinate
+ { "Texel", All }, // texture pixel term
+ { "Tga", All }, // Targa image format
+ { "th", All }, // ordinal suffix
+ { "Threadgroup", All }, // Metal compute term
+ { "Threadgroups", All }, // Metal compute term
+ { "Thumbnailing", All & ~ApplePlatform.TVOS }, // valid technical term
+ { "Thumbstick", All }, // game controller term
+ { "Thumbsticks", ApplePlatform.iOS }, // plural of thumbstick
+ { "Timecodes", All & ~ApplePlatform.TVOS }, // media timing term
+ { "Timelapse", All }, // compound word
+ { "Timelapses", All }, // plural of timelapse
+ { "Tls", All }, // Transport Layer Security
+ { "Tlv", All }, // tag-length-value
+ { "Tmoney", All & ~ApplePlatform.TVOS }, // Korean transit card
+ { "Toc", All }, // table of contents
+ { "Toci", All }, // Apple API selector fragment
+ { "Tonemap", All }, // image processing term
+ { "Touchpads", All }, // plural of touchpad
+ { "Transceive", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // communications verb
+ { "Trc", All }, // tone reproduction curve
+ { "Tri", All }, // triangle abbreviation
+ { "Ttls", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // tunneled TLS
+ { "Tweening", All }, // animation term
+ { "Twentyfour", ApplePlatform.MacOSX }, // compound number word
+ { "Twips", ApplePlatform.MacOSX }, // typography unit
+ { "tx", All }, // translation x axis
+ { "ty", All }, // translation y axis
+ { "Udi", All & ~ApplePlatform.TVOS }, // device identifier standard
+ { "Udp", All }, // User Datagram Protocol
+ { "Uid", All & ~ApplePlatform.TVOS }, // user identifier
+ { "Unconfigured", All & ~ApplePlatform.MacOSX }, // valid English derivative
+ { "Undecodable", All }, // valid English derivative
+ { "Underrun", All }, // audio/buffer term
+ { "Unemphasized", ApplePlatform.MacOSX }, // valid English derivative
+ { "Unentitled", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // security entitlement term
+ { "Unfetched", All }, // valid English derivative
+ { "Unfocus", All }, // valid UI verb
+ { "Unioning", All }, // set operation term
+ { "Unmap", All }, // memory mapping verb
+ { "Unmatch", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Apple API verb
+ { "Unorm", All }, // unsigned normalized format
+ { "Unpair", ApplePlatform.MacOSX }, // device pairing verb
+ { "Unpremultiplied", All }, // graphics term
+ { "Unpremultiplying", All }, // graphics term
+ { "Unprepare", All }, // API verb form
+ { "Unproject", All }, // graphics math term
+ { "Unpublish", All }, // content management verb
+ { "Unsend", All & ~ApplePlatform.TVOS }, // messaging verb
+ { "Unsolo", All }, // audio control verb
+ { "Unsynced", ApplePlatform.MacOSX | ApplePlatform.iOS }, // sync state adjective
+ { "Untrash", ApplePlatform.iOS }, // mail/files verb
+ { "Upce", All }, // UPC-E barcode
+ { "Upi", ApplePlatform.iOS }, // Unified Payments Interface
+ { "Uri", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // Uniform Resource Identifier
{ "Usac", All }, // Unified Speech and Audio Coding
{ "Usd", All }, // Universal Scene Description
{ "Usdz", All }, // USD zip
- { "Usec", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Ussd", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Uterance", All },
- { "Utf", All },
- { "Uti", All & ~ApplePlatform.TVOS },
- { "Varispeed", All },
- { "Vbr", All },
- { "Vbv", All },
- { "Vergence", All },
- { "Vnode", All },
- { "Voip", ApplePlatform.MacCatalyst },
- { "Voronoi", All },
- { "Vpn", All },
- { "Vtt", All },
- { "Waon", All & ~ApplePlatform.TVOS },
- { "Warichu", All },
- { "Warpable", All },
- { "Wcdma", All },
- { "Wep", ApplePlatform.iOS | ApplePlatform.MacCatalyst },
- { "Wifes", All & ~ApplePlatform.TVOS },
- { "Willl", All & ~ApplePlatform.TVOS },
- { "Wlan", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst },
- { "Wpa", All & ~ApplePlatform.TVOS },
- { "Writeability", All },
- { "Xattr", ApplePlatform.MacOSX },
- { "Xattrs", ApplePlatform.MacOSX },
- { "Xbgr", All },
- { "Xmp", All },
- { "Xnor", All },
- { "Xrgb", All },
- { "xy", All },
- { "Xyz", All },
- { "Xzy", All },
- { "Yobibits", All },
- { "Yottabits", All },
- { "Yuv", ApplePlatform.MacOSX },
- { "Yuvk", ApplePlatform.MacOSX },
- { "yuvs", All },
- { "yx", All },
- { "Yxz", All },
- { "yy", All },
- { "Yyy", All },
- { "Yzx", All },
- { "Zebibits", All },
- { "Zenkaku", All & ~ApplePlatform.MacOSX },
- { "Zettabits", All },
- { "Zlib", All },
- { "Zxy", All },
- { "Zyx", All },
+ { "Usec", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // microsecond abbreviation
+ { "Ussd", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // cellular signaling code
+ { "Uterance", All }, // speech synthesis term
+ { "Utf", All }, // Unicode Transformation Format
+ { "Uti", All & ~ApplePlatform.TVOS }, // Uniform Type Identifier
+ { "Varispeed", All }, // audio playback effect
+ { "Vbr", All }, // variable bitrate
+ { "Vbv", All }, // video buffering verifier
+ { "Vergence", All }, // binocular vision term
+ { "Vnode", All }, // virtual node term
+ { "Voip", ApplePlatform.MacCatalyst }, // voice over IP
+ { "Voronoi", All }, // geometry diagram name
+ { "Vpn", All }, // virtual private network
+ { "Vtt", All }, // WebVTT subtitle format
+ { "Waon", All & ~ApplePlatform.TVOS }, // Japanese e-money card
+ { "Warichu", All }, // Japanese annotation term
+ { "Warpable", All }, // valid English derivative
+ { "Wcdma", All }, // cellular standard
+ { "Wep", ApplePlatform.iOS | ApplePlatform.MacCatalyst }, // Wi-Fi security protocol
+ { "Wlan", ApplePlatform.MacOSX | ApplePlatform.MacCatalyst }, // wireless LAN acronym
+ { "Wpa", All & ~ApplePlatform.TVOS }, // Wi-Fi security standard
+ { "Writeability", All }, // variant of writability
+ { "Xattr", ApplePlatform.MacOSX }, // extended attribute
+ { "Xattrs", ApplePlatform.MacOSX }, // plural of xattr
+ { "Xbgr", All }, // X-blue-green-red format
+ { "Xmp", All }, // Extensible Metadata Platform
+ { "Xnor", All }, // logic gate name
+ { "Xrgb", All }, // X-red-green-blue format
+ { "xy", All }, // coordinate axis pair
+ { "Xyz", All }, // axis order abbreviation
+ { "Xzy", All }, // axis order abbreviation
+ { "Yobibits", All }, // IEC unit name
+ { "Yobibytes", All }, // IEC unit name
+ { "Yottabits", All }, // SI unit name
+ { "Yuv", ApplePlatform.MacOSX }, // luma/chroma color space
+ { "Yuvk", ApplePlatform.MacOSX }, // YUV plus black channel
+ { "yuvs", All }, // packed YUV format
+ { "yx", All }, // coordinate axis pair
+ { "Yxz", All }, // axis order abbreviation
+ { "yy", All }, // coordinate repetition term
+ { "Yyy", All }, // axis placeholder term
+ { "Yzx", All }, // axis order abbreviation
+ { "Zebibits", All }, // IEC unit name
+ { "Zebibytes", All }, // IEC unit name
+ { "Zenkaku", All & ~ApplePlatform.MacOSX }, // Japanese full-width text
+ { "Zettabits", All }, // SI unit name
+ { "Zlib", All }, // compression library name
+ { "Zxy", All }, // axis order abbreviation
+ { "Zyx", All }, // axis order abbreviation
};
- // tracks which allowed words were actually seen during TypoTest
- HashSet used = new HashSet ();
-
- bool SkipAllowed (string? typeName, string? methodName, string typo)
+ // Check if any API name in the assembly contains the given word.
+ // This is used to avoid false "unnecessary allowed typo" reports caused
+ // by the spell checker not flagging the word on some machines (the spell
+ // checker is non-deterministic across machines/OS versions/locales).
+ bool IsWordInAnyApiName (Type [] types, string word)
{
- if (allowed.TryGetValue (typo, out var platforms) && platforms.HasFlag (TestRuntime.CurrentPlatform)) {
- used.Add (typo);
- return true;
+ foreach (var t in types) {
+ if (!t.IsPublic || IsObsolete (t))
+ continue;
+ if (t.Name.Contains (word, StringComparison.OrdinalIgnoreCase))
+ return true;
+ foreach (var f in t.GetFields ()) {
+ if ((!f.IsPublic && !f.IsFamily) || IsObsolete (f))
+ continue;
+ if (f.Name.Contains (word, StringComparison.OrdinalIgnoreCase))
+ return true;
+ }
+ foreach (var m in t.GetMethods ()) {
+ if ((!m.IsPublic && !m.IsFamily) || IsObsolete (m))
+ continue;
+ if (m.Name.Contains (word, StringComparison.OrdinalIgnoreCase))
+ return true;
+ }
}
return false;
}
@@ -833,6 +873,21 @@ bool IsObsolete (MemberInfo? mi)
return true;
if (MemberHasObsolete (mi))
return true;
+ if (MemberHasEditorBrowsableNever (mi))
+ return true;
+ // Property accessors may not have [Obsolete] even if the property does
+ if (mi is MethodInfo method && method.IsSpecialName && mi.DeclaringType is not null) {
+ var name = mi.Name;
+ if (name.StartsWith ("get_", StringComparison.Ordinal) || name.StartsWith ("set_", StringComparison.Ordinal)) {
+ var propName = name.Substring (4);
+ foreach (var prop in mi.DeclaringType.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) {
+ if (prop.Name != propName)
+ continue;
+ if (prop.GetCustomAttributes (true).Any () || MemberHasObsolete (prop))
+ return true;
+ }
+ }
+ }
return IsObsolete (mi.DeclaringType);
}
@@ -869,7 +924,6 @@ void AttributeTypo (Type t, ref int totalErrors)
}
[Test]
- [Ignore ("https://github.com/dotnet/macios/issues/25397")]
public virtual void TypoTest ()
{
AssertMatchingOSVersionAndSdkVersion ();
@@ -880,82 +934,89 @@ public virtual void TypoTest ()
using var checker = new SpellChecker ();
+ // Collect all unique words from public API names (split on uppercase boundaries)
+ var words = new HashSet (StringComparer.Ordinal);
var types = Assembly.GetTypes ();
- int totalErrors = 0;
foreach (Type t in types) {
- if (t.IsPublic) {
- if (IsObsolete (t))
- continue;
-
- string txt = NameCleaner (t.Name);
- var typo = GetCachedTypo (checker, txt);
- if (typo.Length > 0) {
- if (!Skip (t, typo)) {
- ReportError ("Typo in TYPE: {0} - {1} ", t.Name, typo);
- totalErrors++;
- }
- }
-
- var fields = t.GetFields ();
- foreach (FieldInfo f in fields) {
- if (!f.IsPublic && !f.IsFamily)
- continue;
-
- if (IsObsolete (f))
- continue;
+ if (!t.IsPublic || IsObsolete (t))
+ continue;
- txt = NameCleaner (f.Name);
- typo = GetCachedTypo (checker, txt);
- if (typo.Length > 0) {
- if (!Skip (f, typo)) {
- ReportError ("Typo in FIELD name: {0} - {1}, Type: {2}", f.Name, typo, t.Name);
- totalErrors++;
- }
- }
- }
+ SplitIntoWords (words, t.Name);
- var methods = t.GetMethods ();
- foreach (MethodInfo m in methods) {
- if (!m.IsPublic && !m.IsFamily)
- continue;
+ foreach (FieldInfo f in t.GetFields ()) {
+ if ((!f.IsPublic && !f.IsFamily) || IsObsolete (f))
+ continue;
+ SplitIntoWords (words, f.Name);
+ }
- if (IsObsolete (m))
- continue;
+ foreach (MethodInfo m in t.GetMethods ()) {
+ if ((!m.IsPublic && !m.IsFamily) || IsObsolete (m))
+ continue;
+ SplitIntoWords (words, m.Name);
+ }
+ }
- txt = NameCleaner (m.Name);
- typo = GetCachedTypo (checker, txt);
- if (typo.Length > 0) {
- if (!Skip (m, typo)) {
- ReportError ("Typo in METHOD name: {0} - {1}, Type: {2}", m.Name, typo, t.Name);
- totalErrors++;
- }
- }
-#if false
- var parameters = m.GetParameters ();
- foreach (ParameterInfo p in parameters) {
- txt = NameCleaner (p.Name);
- typo = GetCachedTypo (checker, txt);
- if (typo.Length > 0) {
- ReportError ("Typo in PARAMETER Name: {0} - {1}, Method: {2}, Type: {3}", p.Name, typo, m.Name, t.Name);
- totalErrors++;
- }
- }
+ // Check each unique word individually with the spell checker
+ var typos = new HashSet (StringComparer.Ordinal);
+ foreach (var word in words) {
+ var checkRange = new NSRange (0, word.Length);
+#if MONOMAC
+ var typoRange = checker.CheckSpelling (word, 0, "en_US", false, 0, out var _);
+#else
+ var typoRange = checker.RangeOfMisspelledWordInString (word, checkRange, checkRange.Location, false, "en_US");
#endif
- }
- }
+ if (typoRange.Length > 0)
+ typos.Add (word.Substring ((int) typoRange.Location, (int) typoRange.Length));
}
- // verify that all allowed words for the current platform are still needed
+
+ // Check each typo against allowed list
+ int totalErrors = 0;
var currentPlatform = TestRuntime.CurrentPlatform;
- var unused = allowed.Keys
+ var usedAllowed = new HashSet ();
+ foreach (var typo in typos) {
+ if (allowed.TryGetValue (typo, out var platforms) && platforms.HasFlag (currentPlatform)) {
+ usedAllowed.Add (typo);
+ continue;
+ }
+ ReportError ("Typo: {0}", typo);
+ totalErrors++;
+ }
+
+ // Verify that all allowed words for the current platform are still needed
+ var unusedAllowed = allowed.Keys
.Where (w => allowed [w].HasFlag (currentPlatform))
- .Except (used);
- foreach (var typo in unused) {
+ .Except (usedAllowed);
+ foreach (var typo in unusedAllowed) {
+ if (IsWordInAnyApiName (types, typo))
+ continue;
ReportError ($"Unnecessary allowed typo \"{typo}\" is not present in any API name");
totalErrors++;
}
Assert.That (totalErrors, Is.EqualTo (0), "Typos!");
}
+ // Split an API name into words on uppercase/digit/symbol boundaries and add to the set
+ static void SplitIntoWords (HashSet words, string name)
+ {
+ int start = -1;
+ for (int i = 0; i < name.Length; i++) {
+ char c = name [i];
+ if (Char.IsUpper (c)) {
+ if (start >= 0 && i > start)
+ words.Add (name.Substring (start, i - start));
+ start = i;
+ } else if (Char.IsDigit (c) || c == '<' || c == '>' || c == '_') {
+ if (start >= 0 && i > start)
+ words.Add (name.Substring (start, i - start));
+ start = -1;
+ } else if (start < 0) {
+ // lowercase char with no word start — skip
+ }
+ }
+ if (start >= 0 && name.Length > start)
+ words.Add (name.Substring (start));
+ }
+
string? GetMessage (object attribute)
{
string? message = null;
@@ -1023,55 +1084,6 @@ void AttributesMessageTypoRules (MemberInfo mi, string typeName, ref int totalEr
}
}
- Dictionary cached_typoes = new Dictionary ();
- string GetCachedTypo (SpellChecker checker, string txt)
- {
- if (!cached_typoes.TryGetValue (txt, out var rv))
- cached_typoes [txt] = rv = GetTypo (checker, txt);
- return rv;
- }
-
- string GetTypo (SpellChecker checker, string txt)
- {
- var checkRange = new NSRange (0, txt.Length);
-#if MONOMAC
- var typoRange = checker.CheckSpelling (txt, 0, "en_US", false, 0, out var _);
-#else
- var typoRange = checker.RangeOfMisspelledWordInString (txt, checkRange, checkRange.Location, false, "en_US");
-#endif
- if (typoRange.Length == 0)
- return String.Empty;
- return txt.Substring ((int) typoRange.Location, (int) typoRange.Length);
- }
-
- static StringBuilder clean = new StringBuilder ();
-
- static string NameCleaner (string name)
- {
- clean.Clear ();
- foreach (char c in name) {
- if (Char.IsUpper (c)) {
- clean.Append (' ').Append (c);
- continue;
- }
- if (Char.IsDigit (c)) {
- clean.Append (' ');
- continue;
- }
- switch (c) {
- case '<':
- case '>':
- case '_':
- clean.Append (' ');
- break;
- default:
- clean.Append (c);
- break;
- }
- }
- return clean.ToString ();
- }
-
bool CheckLibrary (string? lib)
{
#if MONOMAC
diff --git a/tests/linker/link all/dotnet/shared.csproj b/tests/linker/link all/dotnet/shared.csproj
index 6b75ec2a2d4e..bf4a46cecf39 100644
--- a/tests/linker/link all/dotnet/shared.csproj
+++ b/tests/linker/link all/dotnet/shared.csproj
@@ -9,6 +9,7 @@
$(MtouchLink)
--optimize=all,-remove-dynamic-registrar,-force-rejected-types-removal
$(MtouchExtraArgs) --optimize=-remove-uithread-checks
+ $(MtouchExtraArgs) --nowarn:2003
$(MtouchExtraArgs)
$(RootTestsDirectory)\linker\link all
true
@@ -72,6 +73,9 @@
NetworkResources.cs
+
+ HttpbinTestServer.cs
+
diff --git a/tests/linker/link sdk/dotnet/shared.csproj b/tests/linker/link sdk/dotnet/shared.csproj
index 464d06986f00..985c68f62ebe 100644
--- a/tests/linker/link sdk/dotnet/shared.csproj
+++ b/tests/linker/link sdk/dotnet/shared.csproj
@@ -66,6 +66,9 @@
NetworkResources.cs
+
+ HttpbinTestServer.cs
+
diff --git a/tests/linker/trimmode link/dotnet/shared.csproj b/tests/linker/trimmode link/dotnet/shared.csproj
index 48401810a36d..abe1e66a3c38 100644
--- a/tests/linker/trimmode link/dotnet/shared.csproj
+++ b/tests/linker/trimmode link/dotnet/shared.csproj
@@ -70,6 +70,9 @@
NetworkResources.cs
+
+ HttpbinTestServer.cs
+
TestRuntime.cs
diff --git a/tests/monotouch-test/CoreGraphics/PdfTagTypeTest.cs b/tests/monotouch-test/CoreGraphics/PdfTagTypeTest.cs
index da9fdecbb354..078d1c45debe 100644
--- a/tests/monotouch-test/CoreGraphics/PdfTagTypeTest.cs
+++ b/tests/monotouch-test/CoreGraphics/PdfTagTypeTest.cs
@@ -60,7 +60,7 @@ public void EnumExtension ()
Assert.That (CGPdfTagType.RubyPunctuation.GetName (), Is.EqualTo ("/RP"), "RubyPunctuation");
Assert.That (CGPdfTagType.Warichu.GetName (), Is.EqualTo ("/Warichu"), "Warichu");
Assert.That (CGPdfTagType.WarichuText.GetName (), Is.EqualTo ("/WT"), "WarichuText");
- Assert.That (CGPdfTagType.WarichuPunctiation.GetName (), Is.EqualTo ("/WP"), "WarichuPunctiation");
+ Assert.That (CGPdfTagType.WarichuPunctuation.GetName (), Is.EqualTo ("/WP"), "WarichuPunctuation");
Assert.That (CGPdfTagType.Figure.GetName (), Is.EqualTo ("/Figure"), "Figure");
Assert.That (CGPdfTagType.Formula.GetName (), Is.EqualTo ("/Formula"), "Formula");
Assert.That (CGPdfTagType.Form.GetName (), Is.EqualTo ("/Form"), "Form");
diff --git a/tests/monotouch-test/Foundation/UrlSessionTest.cs b/tests/monotouch-test/Foundation/UrlSessionTest.cs
index 6cd40f773c95..bca101c54e34 100644
--- a/tests/monotouch-test/Foundation/UrlSessionTest.cs
+++ b/tests/monotouch-test/Foundation/UrlSessionTest.cs
@@ -23,19 +23,12 @@ namespace MonoTouchFixtures.Foundation {
[TestFixture]
[Preserve (AllMembers = true)]
public class UrlSessionTest {
- void AssertTrueOrIgnoreInCI (Task task, string message)
+ void AssertCompleted (Task task, string message)
{
var value = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), task, out var ex);
- if (value) {
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
- Assert.That (ex, Is.Null, message + " Exception");
- return;
- }
-
- TestRuntime.IgnoreInCI ($"This test times out randomly in CI due to bad network: {message}");
- Assert.That (ex, Is.Null, $"Exception - {message}");
- Assert.Fail (message);
+ Assert.That (value, Is.True, $"Request timed out: {message}");
+ Assert.That (ex, Is.Null, message + " Exception");
}
[Test]
@@ -54,16 +47,16 @@ public void CreateDataTaskAsync ()
uploadRequest.HttpMethod = "POST";
/* CreateDataTask */
- AssertTrueOrIgnoreInCI (session.CreateDataTaskAsync (request), "CreateDataTask a");
- AssertTrueOrIgnoreInCI (session.CreateDataTaskAsync (url), "CreateDataTask b");
+ AssertCompleted (session.CreateDataTaskAsync (request), "CreateDataTask a");
+ AssertCompleted (session.CreateDataTaskAsync (url), "CreateDataTask b");
/* CreateDownloadTask */
- AssertTrueOrIgnoreInCI (session.CreateDownloadTaskAsync (request), "CreateDownloadTask a");
- AssertTrueOrIgnoreInCI (session.CreateDownloadTaskAsync (url), "CreateDownloadTask b");
+ AssertCompleted (session.CreateDownloadTaskAsync (request), "CreateDownloadTask a");
+ AssertCompleted (session.CreateDownloadTaskAsync (url), "CreateDownloadTask b");
/* CreateUploadTask */
- AssertTrueOrIgnoreInCI (session.CreateUploadTaskAsync (uploadRequest, file_url), "CreateUploadTask a");
- AssertTrueOrIgnoreInCI (session.CreateUploadTaskAsync (uploadRequest, file_data), "CreateUploadTask b");
+ AssertCompleted (session.CreateUploadTaskAsync (uploadRequest, file_url), "CreateUploadTask a");
+ AssertCompleted (session.CreateUploadTaskAsync (uploadRequest, file_data), "CreateUploadTask b");
}
[Test]
diff --git a/tests/monotouch-test/System.Net.Http/HttpbinTestServer.cs b/tests/monotouch-test/System.Net.Http/HttpbinTestServer.cs
new file mode 100644
index 000000000000..595999ae8729
--- /dev/null
+++ b/tests/monotouch-test/System.Net.Http/HttpbinTestServer.cs
@@ -0,0 +1,406 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+//
+// An in-process HTTP server that mimics httpbin.org endpoints for testing,
+// eliminating external network dependencies and the associated flakiness.
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MonoTests.System.Net.Http {
+ [Preserve (AllMembers = true)]
+ static class HttpbinTestServer {
+ static readonly Lazy lazyBaseUrl = new Lazy (Start);
+
+ public static string BaseUrl => lazyBaseUrl.Value;
+
+ static string Start ()
+ {
+ // IANA suggested range for dynamic/private ports
+ const int MinPort = 49152;
+ const int MaxPort = 65535;
+
+ HttpListener? listener = null;
+ int port = -1;
+
+ for (var p = MinPort; p < MaxPort; p++) {
+ listener = new HttpListener ();
+ listener.Prefixes.Add ($"http://127.0.0.1:{p}/");
+ try {
+ listener.Start ();
+ port = p;
+ break;
+ } catch {
+ // port in use, try next
+ listener.Close ();
+ listener = null;
+ }
+ }
+
+ if (listener is null || port == -1)
+ throw new InvalidOperationException ("HttpbinTestServer: Could not find an available port.");
+
+ Task.Run (async () => {
+ try {
+ while (listener.IsListening) {
+ var context = await listener.GetContextAsync ();
+ _ = Task.Run (() => {
+ try {
+ HandleRequest (context);
+ } catch (Exception ex) {
+ try {
+ context.Response.StatusCode = 500;
+ var body = Encoding.UTF8.GetBytes (ex.ToString ());
+ context.Response.OutputStream.Write (body, 0, body.Length);
+ } catch {
+ // nothing we can do
+ }
+ } finally {
+ try {
+ context.Response.Close ();
+ } catch {
+ // nothing we can do
+ }
+ }
+ });
+ }
+ } catch (ObjectDisposedException) {
+ // listener was stopped
+ } catch (HttpListenerException) {
+ // listener was stopped
+ }
+ });
+
+ return $"http://127.0.0.1:{port}";
+ }
+
+ static void HandleRequest (HttpListenerContext context)
+ {
+ var path = context.Request.Url!.AbsolutePath;
+
+ if (path == "/get" || path == "/") {
+ HandleGet (context);
+ } else if (path == "/post") {
+ HandlePost (context);
+ } else if (path == "/cookies") {
+ HandleCookies (context);
+ } else if (path.StartsWith ("/cookies/set", StringComparison.Ordinal)) {
+ HandleSetCookies (context);
+ } else if (path.StartsWith ("/redirect-to", StringComparison.Ordinal)) {
+ HandleRedirectTo (context);
+ } else if (path.StartsWith ("/redirect/", StringComparison.Ordinal)) {
+ HandleRedirect (context);
+ } else if (path.StartsWith ("/basic-auth/", StringComparison.Ordinal)) {
+ HandleBasicAuth (context);
+ } else if (path.StartsWith ("/digest-auth/", StringComparison.Ordinal)) {
+ HandleDigestAuth (context);
+ } else if (path == "/gzip") {
+ HandleGzip (context);
+ } else if (path == "/html") {
+ HandleHtml (context);
+ } else if (path.StartsWith ("/status/", StringComparison.Ordinal)) {
+ HandleStatus (context);
+ } else {
+ // Default: 200 OK with empty JSON
+ WriteJsonResponse (context, "{}");
+ }
+ }
+
+ // GET / or GET /get: return request info as JSON (including headers)
+ static void HandleGet (HttpListenerContext context)
+ {
+ var headerLines = new List ();
+ foreach (string key in context.Request.Headers) {
+ var value = context.Request.Headers [key]!;
+ headerLines.Add ($" \"{key}\": \"{EscapeJsonString (value)}\"");
+ }
+
+ var json = "{\n \"headers\": {\n" + string.Join (",\n", headerLines) + "\n }\n}";
+ WriteJsonResponse (context, json);
+ }
+
+ // POST /post: echo the posted body and request info
+ static void HandlePost (HttpListenerContext context)
+ {
+ string data;
+ using (var reader = new StreamReader (context.Request.InputStream, context.Request.ContentEncoding)) {
+ data = reader.ReadToEnd ();
+ }
+
+ var json = "{\n \"data\": \"" + EscapeJsonString (data) + "\",\n \"url\": \"" + EscapeJsonString (context.Request.Url!.ToString ()) + "\"\n}";
+ WriteJsonResponse (context, json);
+ }
+
+ // GET /cookies: echo cookies from request as JSON
+ static void HandleCookies (HttpListenerContext context)
+ {
+ var cookieLines = new List ();
+ var cookieHeader = context.Request.Headers ["Cookie"];
+ if (cookieHeader is not null) {
+ var pairs = cookieHeader.Split (';');
+ foreach (var pair in pairs) {
+ var trimmed = pair.Trim ();
+ var eqIdx = trimmed.IndexOf ('=');
+ if (eqIdx > 0) {
+ var name = trimmed.Substring (0, eqIdx);
+ var value = trimmed.Substring (eqIdx + 1);
+ cookieLines.Add ($" \"{name}\": \"{EscapeJsonString (value)}\"");
+ }
+ }
+ }
+
+ var json = "{\n \"cookies\": {\n" + string.Join (",\n", cookieLines) + "\n }\n}";
+ WriteJsonResponse (context, json);
+ }
+
+ // GET /cookies/set?name=value: set cookie(s) via Set-Cookie header and redirect to /cookies
+ static void HandleSetCookies (HttpListenerContext context)
+ {
+ var queryString = context.Request.QueryString;
+ foreach (string? key in queryString) {
+ if (key is not null) {
+ context.Response.AppendHeader ("Set-Cookie", $"{key}={queryString [key]}; Path=/");
+ }
+ }
+
+ context.Response.StatusCode = 302;
+ context.Response.RedirectLocation = $"{BaseUrl}/cookies";
+ }
+
+ // GET /redirect/{n}: chain of redirects, ending at /get
+ static void HandleRedirect (HttpListenerContext context)
+ {
+ var path = context.Request.Url!.AbsolutePath;
+ var countStr = path.Substring ("/redirect/".Length);
+ if (!int.TryParse (countStr, out var count) || count < 1) {
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ context.Response.StatusCode = 302;
+ if (count > 1)
+ context.Response.RedirectLocation = $"{BaseUrl}/redirect/{count - 1}";
+ else
+ context.Response.RedirectLocation = $"{BaseUrl}/get";
+ }
+
+ // GET /redirect-to?url={url}: single redirect to the specified URL
+ static void HandleRedirectTo (HttpListenerContext context)
+ {
+ var url = context.Request.QueryString ["url"];
+ if (url is null) {
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ context.Response.StatusCode = 302;
+ context.Response.RedirectLocation = url;
+ }
+
+ // GET /basic-auth/{user}/{pass}: HTTP Basic authentication
+ static void HandleBasicAuth (HttpListenerContext context)
+ {
+ var path = context.Request.Url!.AbsolutePath;
+ var parts = path.Substring ("/basic-auth/".Length).Split ('/');
+ if (parts.Length != 2) {
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ var validUser = Uri.UnescapeDataString (parts [0]);
+ var validPass = Uri.UnescapeDataString (parts [1]);
+
+ var authHeader = context.Request.Headers ["Authorization"];
+ if (authHeader is not null && authHeader.StartsWith ("Basic ", StringComparison.Ordinal)) {
+ try {
+ var credentials = Encoding.UTF8.GetString (Convert.FromBase64String (authHeader.Substring (6)));
+ var colonIdx = credentials.IndexOf (':');
+ if (colonIdx > 0) {
+ var user = credentials.Substring (0, colonIdx);
+ var pass = credentials.Substring (colonIdx + 1);
+ if (user == validUser && pass == validPass) {
+ WriteJsonResponse (context, $"{{\"authenticated\": true, \"user\": \"{EscapeJsonString (user)}\"}}");
+ return;
+ }
+ }
+ } catch {
+ // bad base64 or encoding
+ }
+ }
+
+ context.Response.StatusCode = 401;
+ context.Response.AddHeader ("WWW-Authenticate", "Basic realm=\"Fake Realm\"");
+ }
+
+ // GET /digest-auth/auth/{user}/{pass}: HTTP Digest authentication
+ static void HandleDigestAuth (HttpListenerContext context)
+ {
+ var path = context.Request.Url!.AbsolutePath;
+ var parts = path.Substring ("/digest-auth/auth/".Length).Split ('/');
+ if (parts.Length != 2) {
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ var validUser = Uri.UnescapeDataString (parts [0]);
+ var validPass = Uri.UnescapeDataString (parts [1]);
+ const string realm = "test@example.org";
+
+ var authHeader = context.Request.Headers ["Authorization"];
+ if (authHeader is not null && authHeader.StartsWith ("Digest ", StringComparison.Ordinal)) {
+ var authParams = ParseDigestAuthHeader (authHeader);
+
+ if (authParams.TryGetValue ("username", out var username) &&
+ authParams.TryGetValue ("nonce", out var nonce) &&
+ authParams.TryGetValue ("uri", out var uri) &&
+ authParams.TryGetValue ("response", out var response)) {
+
+ authParams.TryGetValue ("nc", out var nc);
+ authParams.TryGetValue ("cnonce", out var cnonce);
+ authParams.TryGetValue ("qop", out var qop);
+
+ var ha1 = ComputeMD5 ($"{username}:{realm}:{validPass}");
+ var ha2 = ComputeMD5 ($"GET:{uri}");
+
+ string expected;
+ if (!string.IsNullOrEmpty (qop))
+ expected = ComputeMD5 ($"{ha1}:{nonce}:{nc}:{cnonce}:{qop}:{ha2}");
+ else
+ expected = ComputeMD5 ($"{ha1}:{nonce}:{ha2}");
+
+ if (username == validUser && response == expected) {
+ WriteJsonResponse (context, $"{{\"authenticated\": true, \"user\": \"{EscapeJsonString (username)}\"}}");
+ return;
+ }
+ }
+ }
+
+ // Send digest challenge
+ var newNonce = Guid.NewGuid ().ToString ("N");
+ context.Response.StatusCode = 401;
+ context.Response.AddHeader ("WWW-Authenticate",
+ $"Digest realm=\"{realm}\", nonce=\"{newNonce}\", qop=\"auth\", opaque=\"{Guid.NewGuid ():N}\", algorithm=MD5, stale=FALSE");
+ }
+
+ // GET /gzip: return gzip-compressed JSON response
+ static void HandleGzip (HttpListenerContext context)
+ {
+ var json = "{\"gzipped\": true, \"method\": \"GET\", \"origin\": \"127.0.0.1\"}";
+ var jsonBytes = Encoding.UTF8.GetBytes (json);
+
+ using var ms = new MemoryStream ();
+ using (var gzip = new GZipStream (ms, CompressionMode.Compress, leaveOpen: true)) {
+ gzip.Write (jsonBytes, 0, jsonBytes.Length);
+ }
+
+ var compressed = ms.ToArray ();
+ context.Response.ContentType = "application/json";
+ context.Response.AddHeader ("Content-Encoding", "gzip");
+ context.Response.ContentLength64 = compressed.Length;
+ context.Response.OutputStream.Write (compressed, 0, compressed.Length);
+ }
+
+ // GET /html: return an HTML response with Content-Length
+ static void HandleHtml (HttpListenerContext context)
+ {
+ const string html = "TestHerman Melville - Moby Dick
";
+ var bytes = Encoding.UTF8.GetBytes (html);
+ context.Response.ContentType = "text/html; charset=utf-8";
+ context.Response.ContentLength64 = bytes.Length;
+ context.Response.OutputStream.Write (bytes, 0, bytes.Length);
+ }
+
+ // GET /status/{code}: return a response with the specified HTTP status code
+ static void HandleStatus (HttpListenerContext context)
+ {
+ var path = context.Request.Url!.AbsolutePath;
+ var codeStr = path.Substring ("/status/".Length);
+ if (int.TryParse (codeStr, out var code))
+ context.Response.StatusCode = code;
+ else
+ context.Response.StatusCode = 400;
+ }
+
+ static void WriteJsonResponse (HttpListenerContext context, string json)
+ {
+ var bytes = Encoding.UTF8.GetBytes (json);
+ context.Response.ContentType = "application/json";
+ context.Response.ContentLength64 = bytes.Length;
+ context.Response.StatusCode = 200;
+ context.Response.OutputStream.Write (bytes, 0, bytes.Length);
+ }
+
+ static string EscapeJsonString (string value)
+ {
+ return value
+ .Replace ("\\", "\\\\")
+ .Replace ("\"", "\\\"")
+ .Replace ("\n", "\\n")
+ .Replace ("\r", "\\r")
+ .Replace ("\t", "\\t");
+ }
+
+ static Dictionary ParseDigestAuthHeader (string header)
+ {
+ var result = new Dictionary (StringComparer.OrdinalIgnoreCase);
+ var content = header.Substring ("Digest ".Length);
+
+ var i = 0;
+ while (i < content.Length) {
+ // Skip whitespace and commas
+ while (i < content.Length && (content [i] == ' ' || content [i] == ','))
+ i++;
+
+ if (i >= content.Length)
+ break;
+
+ // Read key
+ var keyStart = i;
+ while (i < content.Length && content [i] != '=')
+ i++;
+
+ if (i >= content.Length)
+ break;
+
+ var key = content.Substring (keyStart, i - keyStart).Trim ();
+ i++; // skip '='
+
+ // Read value (quoted or unquoted)
+ string value;
+ if (i < content.Length && content [i] == '"') {
+ i++; // skip opening quote
+ var valueStart = i;
+ while (i < content.Length && content [i] != '"')
+ i++;
+ value = content.Substring (valueStart, i - valueStart);
+ if (i < content.Length)
+ i++; // skip closing quote
+ } else {
+ var valueStart = i;
+ while (i < content.Length && content [i] != ',' && content [i] != ' ')
+ i++;
+ value = content.Substring (valueStart, i - valueStart);
+ }
+
+ result [key] = value;
+ }
+
+ return result;
+ }
+
+ static string ComputeMD5 (string input)
+ {
+ var bytes = MD5.HashData (Encoding.UTF8.GetBytes (input));
+ return Convert.ToHexStringLower (bytes);
+ }
+ }
+}
diff --git a/tests/monotouch-test/System.Net.Http/MessageHandlers.cs b/tests/monotouch-test/System.Net.Http/MessageHandlers.cs
index 2811dd23ee2c..75cf7a9b6125 100644
--- a/tests/monotouch-test/System.Net.Http/MessageHandlers.cs
+++ b/tests/monotouch-test/System.Net.Http/MessageHandlers.cs
@@ -116,8 +116,6 @@ void TestNSUrlSessionHandlerCookiesImpl (NSUrlSessionHandler nativeHandler)
var managedHasExpectedCookie = managedCookies?.Any (v => v.StartsWith ("cookie=chocolate-chip;", StringComparison.Ordinal)) == true;
var nativeHasExpectedCookie = nativeCookies?.Any (v => v.StartsWith ("cookie=chocolate-chip;", StringComparison.Ordinal)) == true;
- if (!completed || !managedCookieResult || !nativeCookieResult || !managedHasExpectedCookie || !nativeHasExpectedCookie)
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
Assert.That (completed, Is.True, "Network request completed");
Assert.That (ex, Is.Null, "Exception");
Assert.That (managedCookieResult, Is.True, $"Failed to get managed cookies");
@@ -166,17 +164,6 @@ void TestNSUrlSessionHandlerCookieContainerImpl (NSUrlSessionHandler nativeHandl
nativeCookieResult = await nativeResponse.Content.ReadAsStringAsync ();
}, out var ex);
- if (!completed)
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
- var intermittentFailures = new string [] {
- "500 Internal Server Error",
- "502 Bad Gateway",
- "503 Service Temporarily Unavailable",
- "504 Gateway Time-out",
- };
- if (intermittentFailures.Any (v => managedCookieResult.Contains (v) || nativeCookieResult.Contains (v)))
- TestRuntime.IgnoreInCI ("Intermittent network failure - ignore in CI");
-
Assert.That (completed, Is.True, "Network request completed");
Assert.That (ex, Is.Null, "Exception");
Assert.That (managedCookieResult, Is.Not.Null, "Managed cookies result");
@@ -204,15 +191,11 @@ public void TestNSurlSessionHandlerCookieContainerSetCookie ()
nativeCookieResult = await nativeResponse.Content.ReadAsStringAsync ();
}, out var ex);
- if (!completed)
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
Assert.That (completed, Is.True, "Network request completed");
Assert.That (ex, Is.Null, "Exception");
Assert.That (nativeCookieResult, Is.Not.Null, "Native cookies result");
var cookiesFromServer = cookieContainer.GetCookies (new Uri (url));
var hasExpectedCookie = cookiesFromServer.Cast ().Any (v => v.Name == "cookie" && v.Value == "chocolate-chip");
- if (!hasExpectedCookie)
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
Assert.That (hasExpectedCookie, Is.True, "Cookies received from server.");
}
@@ -241,8 +224,6 @@ public void TestNSUrlSessionDefaultDisabledCookies ()
nativeCookieResult = await nativeResponse.Content.ReadAsStringAsync ();
}, out var ex);
- if (!completed)
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
Assert.That (completed, Is.True, "Network request completed");
Assert.That (ex, Is.Null, "Exception");
Assert.That (nativeSetCookieResult, Is.Not.Null, "Native set-cookies result");
@@ -276,8 +257,6 @@ public void TestNSUrlSessionDefaultDisableCookiesWithManagedContainer ()
nativeCookieResult = await nativeResponse.Content.ReadAsStringAsync ();
}, out var ex);
- if (!completed)
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
Assert.That (completed, Is.True, "Network request completed");
Assert.That (ex, Is.Null, "Exception");
Assert.That (nativeSetCookieResult, Is.Not.Null, "Native set-cookies result");
@@ -469,17 +448,10 @@ public void RedirectionWithAuthorizationHeaders (Type handlerType)
containsHeaders = json.Contains ("headers"); // ensure we do have the headers in the response
}, out var ex);
- if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail
- TestRuntime.IgnoreInCIIfHttpClientTimedOut ();
- Assert.Inconclusive ("Request timedout.");
- } else if (ex is not null) {
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
- Assert.That (ex, Is.Null, $"Exception {ex} for {json}");
- } else if (!containsHeaders) {
- Assert.Inconclusive ("Response from httpbin does not contain headers, therefore we cannot ensure that if the authoriation is present.");
- } else {
- Assert.That (containsAuthorizarion, Is.False, $"Authorization header did reach the final destination. {json}");
- }
+ Assert.That (done, Is.True, "Request completed");
+ Assert.That (ex, Is.Null, $"Exception {ex} for {json}");
+ Assert.That (containsHeaders, Is.True, "Response does not contain headers");
+ Assert.That (containsAuthorizarion, Is.False, $"Authorization header did reach the final destination. {json}");
}
[TestCase (true, false, HttpStatusCode.Unauthorized, false, TestName = "NSUrlSessionHandlerOriginCredentialCacheNotSentToCrossOriginRedirectTarget")]
@@ -668,10 +640,9 @@ public void RejectSslCertificatesServicePointManager (Type handlerType)
var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => {
try {
HttpClient client = new HttpClient (handler);
- client.BaseAddress = NetworkResources.Httpbin.Uri;
var byteArray = new UTF8Encoding ().GetBytes ("username:password");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("Basic", Convert.ToBase64String (byteArray));
- result = await client.GetAsync (NetworkResources.Httpbin.GetRedirectUrl (3));
+ result = await client.GetAsync (NetworkResources.MicrosoftUrl);
} finally {
#pragma warning disable SYSLIB0014 // 'ServicePointManager' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead. Settings on ServicePointManager no longer affect SslStream or HttpClient.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
ServicePointManager.ServerCertificateValidationCallback = null;
@@ -720,10 +691,9 @@ public void AcceptSslCertificatesServicePointManager (Type handlerType)
var done = TestRuntime.TryRunAsync (TimeSpan.FromSeconds (30), async () => {
try {
HttpClient client = new HttpClient (handler);
- client.BaseAddress = NetworkResources.Httpbin.Uri;
var byteArray = new UTF8Encoding ().GetBytes ("username:password");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("Basic", Convert.ToBase64String (byteArray));
- var result = await client.GetAsync (NetworkResources.Httpbin.GetRedirectUrl (3));
+ var result = await client.GetAsync (NetworkResources.MicrosoftUrl);
} finally {
#pragma warning disable SYSLIB0014 // 'ServicePointManager' is obsolete: 'WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead. Settings on ServicePointManager no longer affect SslStream or HttpClient.' (https://aka.ms/dotnet-warnings/SYSLIB0014)
ServicePointManager.ServerCertificateValidationCallback = null;
@@ -1194,14 +1164,9 @@ public void GHIssue8342 (HttpStatusCode expectedStatus, string validUsername, st
httpStatus = result.StatusCode;
}, out var ex);
- if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail
- Assert.Inconclusive ("Request timedout.");
- } else {
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
- TestRuntime.IgnoreInCIIfBadNetwork (httpStatus);
- Assert.That (ex, Is.Null, "Exception not null");
- Assert.That (httpStatus, Is.EqualTo (expectedStatus), "Status not ok");
- }
+ Assert.That (done, Is.True, "Request completed");
+ Assert.That (ex, Is.Null, "Exception not null");
+ Assert.That (httpStatus, Is.EqualTo (expectedStatus), "Status not ok");
}
[TestCase (HttpStatusCode.OK, "mandel", "12345678", "mandel", "12345678")]
@@ -1221,14 +1186,9 @@ public void SupportsDigestAuthentication (HttpStatusCode expectedStatus, string
httpStatus = result.StatusCode;
}, out var ex);
- if (!done) {
- Assert.Inconclusive ("Request timedout.");
- } else {
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
- TestRuntime.IgnoreInCIIfBadNetwork (httpStatus);
- Assert.That (ex, Is.Null, "Exception not null");
- Assert.That (httpStatus, Is.EqualTo (expectedStatus), "Status not ok");
- }
+ Assert.That (done, Is.True, "Request completed");
+ Assert.That (ex, Is.Null, "Exception not null");
+ Assert.That (httpStatus, Is.EqualTo (expectedStatus), "Status not ok");
}
[TestCase]
@@ -1252,13 +1212,10 @@ public void GHIssue8344 ()
httpStatus = result.StatusCode;
}, out var ex);
- if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail
- Assert.Inconclusive ("First request timedout.");
- } else {
- TestRuntime.IgnoreInCIIfBadNetwork (httpStatus);
- Assert.That (ex, Is.Null, "First request exception not null");
- Assert.That (httpStatus, Is.EqualTo (HttpStatusCode.OK), "First status not ok");
- }
+ Assert.That (done, Is.True, "First request completed");
+ Assert.That (ex, Is.Null, "First request exception not null");
+ Assert.That (httpStatus, Is.EqualTo (HttpStatusCode.OK), "First status not ok");
+
// exactly same operation, diff handler, wrong password, should fail
var secondHandler = new NSUrlSessionHandler () {
@@ -1273,13 +1230,9 @@ public void GHIssue8344 ()
httpStatus = result.StatusCode;
}, out ex);
- if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail
- Assert.Inconclusive ("Second request timedout.");
- } else {
- TestRuntime.IgnoreInCIIfBadNetwork (httpStatus);
- Assert.That (ex, Is.Null, "Second request exception not null");
- Assert.That (httpStatus, Is.EqualTo (HttpStatusCode.Unauthorized), "Second status not ok");
- }
+ Assert.That (done, Is.True, "Second request completed");
+ Assert.That (ex, Is.Null, "Second request exception not null");
+ Assert.That (httpStatus, Is.EqualTo (HttpStatusCode.Unauthorized), "Second status not ok");
}
class TestDelegateHandler : DelegatingHandler {
@@ -1333,27 +1286,22 @@ public void GHIssue16339 ()
}
}, out var ex);
- if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc.. we do not want to fail
- Assert.Inconclusive ("Request timedout.");
- } else {
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
- Assert.That (ex, Is.Null, "Exception");
+ Assert.That (done, Is.True, "Request completed");
+ Assert.That (ex, Is.Null, "Exception");
- for (var i = 0; i < iterations; i++) {
- var rsp = delegatingHandler.Responses [i];
- TestRuntime.IgnoreInCIIfBadNetwork (rsp.StatusCode);
- Assert.That (delegatingHandler.IsCompleted (i), Is.True, $"Completed #{i}");
- Assert.That (rsp.ReasonPhrase, Is.EqualTo ("OK"), $"ReasonPhrase #{i}");
- Assert.That (rsp.StatusCode, Is.EqualTo (HttpStatusCode.OK), $"StatusCode #{i}");
-
- var body = bodies [i];
- // Poor-man's json parser
- var data = body.Split ('\n', '\r').Single (v => v.Contains ("\"data\": \""));
- data = data.Trim ().Replace ("\"data\": \"", "").TrimEnd ('"', ',');
- data = data.Replace ("\\\"", "\"");
-
- Assert.That (data, Is.EqualTo (json), $"Post data #{i}");
- }
+ for (var i = 0; i < iterations; i++) {
+ var rsp = delegatingHandler.Responses [i];
+ Assert.That (delegatingHandler.IsCompleted (i), Is.True, $"Completed #{i}");
+ Assert.That (rsp.ReasonPhrase, Is.EqualTo ("OK"), $"ReasonPhrase #{i}");
+ Assert.That (rsp.StatusCode, Is.EqualTo (HttpStatusCode.OK), $"StatusCode #{i}");
+
+ var body = bodies [i];
+ // Poor-man's json parser
+ var data = body.Split ('\n', '\r').Single (v => v.Contains ("\"data\": \""));
+ data = data.Trim ().Replace ("\"data\": \"", "").TrimEnd ('"', ',');
+ data = data.Replace ("\\\"", "\"");
+
+ Assert.That (data, Is.EqualTo (json), $"Post data #{i}");
}
}
@@ -1373,17 +1321,11 @@ public void UpdateRequestUriAfterRedirect (Type handlerType)
using var request = new HttpRequestMessage (HttpMethod.Get, initialRequestUri);
Assert.That (request.RequestUri.ToString (), Is.EqualTo (initialRequestUri), "Initial RequestUri");
using var response = await client.SendAsync (request);
- TestRuntime.IgnoreInCIIfBadNetwork (response.StatusCode);
Assert.That (request.RequestUri.ToString (), Is.EqualTo (postRequestUri), "Post RequestUri");
}, out var ex);
- if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc. we do not want to fail
- TestRuntime.IgnoreInCIIfHttpClientTimedOut ();
- Assert.Inconclusive ("Request timedout.");
- } else {
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
- Assert.That (ex, Is.Null, "Exception");
- }
+ Assert.That (done, Is.True, "Request completed");
+ Assert.That (ex, Is.Null, "Exception");
}
[TestCase (typeof (NSUrlSessionHandler))]
@@ -1401,17 +1343,11 @@ public void RequestUriNotUpdatedIfNotRedirect (Type handlerType)
using var request = new HttpRequestMessage (HttpMethod.Get, requestUri);
Assert.That (request.RequestUri.ToString (), Is.EqualTo (requestUri), "Initial RequestUri");
using var response = await client.SendAsync (request);
- TestRuntime.IgnoreInCIIfBadNetwork (response.StatusCode);
Assert.That (request.RequestUri.ToString (), Is.EqualTo (requestUri), "Post RequestUri");
}, out var ex);
- if (!done) { // timeouts happen in the bots due to dns issues, connection issues etc. we do not want to fail
- TestRuntime.IgnoreInCIIfHttpClientTimedOut ();
- Assert.Inconclusive ("Request timedout.");
- } else {
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
- Assert.That (ex, Is.Null, "Exception");
- }
+ Assert.That (done, Is.True, "Request completed");
+ Assert.That (ex, Is.Null, "Exception");
}
// https://github.com/dotnet/macios/issues/23764
diff --git a/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs b/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs
index 79c787d387c1..e25ede8113e8 100644
--- a/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs
+++ b/tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs
@@ -34,22 +34,14 @@ public void DecompressedResponseDoesNotHaveContentEncodingOrContentLength ()
// Use ResponseHeadersRead so that the response content is not buffered,
// which would cause HttpContent to compute Content-Length from the buffer.
var response = await client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead);
-
- if (!response.IsSuccessStatusCode) {
- Assert.Inconclusive ($"Request failed with status {response.StatusCode}");
- return;
- }
+ response.EnsureSuccessStatusCode ();
noContentEncoding = response.Content.Headers.ContentEncoding.Count == 0;
noContentLength = response.Content.Headers.ContentLength is null;
body = await response.Content.ReadAsStringAsync ();
}, out var ex);
- if (!done) {
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
- Assert.Inconclusive ("Request timed out.");
- }
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
+ Assert.That (done, Is.True, "Request completed");
Assert.That (ex, Is.Null, $"Exception: {ex}");
Assert.That (noContentEncoding, Is.True, "Content-Encoding header should be removed for decompressed content");
Assert.That (noContentLength, Is.True, "Content-Length header should be removed for decompressed content");
@@ -73,22 +65,14 @@ public void NonCompressedResponseHasContentLength ()
// Use ResponseHeadersRead so that the response content is not buffered,
// which would cause HttpContent to compute Content-Length from the buffer.
var response = await client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead);
-
- if (!response.IsSuccessStatusCode) {
- Assert.Inconclusive ($"Request failed with status {response.StatusCode}");
- return;
- }
+ response.EnsureSuccessStatusCode ();
noContentEncoding = response.Content.Headers.ContentEncoding.Count == 0;
contentLength = response.Content.Headers.ContentLength;
body = await response.Content.ReadAsStringAsync ();
}, out var ex);
- if (!done) {
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
- Assert.Inconclusive ("Request timed out.");
- }
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
+ Assert.That (done, Is.True, "Request completed");
Assert.That (ex, Is.Null, $"Exception: {ex}");
Assert.That (noContentEncoding, Is.True, "Content-Encoding should not be present for non-compressed content");
Assert.That (contentLength, Is.Not.Null, "Content-Length header should be present for non-compressed content");
@@ -112,22 +96,14 @@ public void KeepHeadersAfterDecompressionSwitch ()
using var request = new HttpRequestMessage (HttpMethod.Get, $"{NetworkResources.Httpbin.Url}/gzip");
request.Headers.TryAddWithoutValidation ("Accept-Encoding", "gzip");
var response = await client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead);
-
- if (!response.IsSuccessStatusCode) {
- Assert.Inconclusive ($"Request failed with status {response.StatusCode}");
- return;
- }
+ response.EnsureSuccessStatusCode ();
hasContentEncoding = response.Content.Headers.ContentEncoding.Count > 0;
hasContentLength = response.Content.Headers.ContentLength is not null;
body = await response.Content.ReadAsStringAsync ();
}, out var ex);
- if (!done) {
- TestRuntime.IgnoreInCI ("Transient network failure - ignore in CI");
- Assert.Inconclusive ("Request timed out.");
- }
- TestRuntime.IgnoreInCIIfBadNetwork (ex);
+ Assert.That (done, Is.True, "Request completed");
Assert.That (ex, Is.Null, $"Exception: {ex}");
Assert.That (hasContentEncoding, Is.True, "Content-Encoding header should be preserved when KeepHeadersAfterDecompression is enabled");
Assert.That (hasContentLength, Is.True, "Content-Length header should be preserved when KeepHeadersAfterDecompression is enabled");
diff --git a/tests/monotouch-test/System.Net.Http/NetworkResources.cs b/tests/monotouch-test/System.Net.Http/NetworkResources.cs
index 2a887a52a3d6..26cf0f7ee030 100644
--- a/tests/monotouch-test/System.Net.Http/NetworkResources.cs
+++ b/tests/monotouch-test/System.Net.Http/NetworkResources.cs
@@ -20,7 +20,6 @@ public static class NetworkResources {
public static string [] HttpsUrls => new [] {
MicrosoftUrl,
XamarinUrl,
- Httpbin.Url,
};
public static string [] HttpUrls => new [] {
@@ -87,7 +86,8 @@ static string AssertNetworkConnection (string url)
}
public static class Httpbin {
- public static string Url => AssertNetworkConnection ("https://httpbin.org");
+ // Uses an in-proc HTTP server to avoid external network dependencies.
+ public static string Url => HttpbinTestServer.BaseUrl;
public static Uri Uri => new Uri ($"{Url}");
public static string DeleteUrl => $"{Url}/delete";
public static string GetUrl => $"{Url}/get";
@@ -95,13 +95,13 @@ public static class Httpbin {
public static string PostUrl => $"{Url}/post";
public static string PutUrl => $"{Url}/put";
public static string CookiesUrl => $"{Url}/cookies";
- public static string HttpUrl => AssertNetworkConnection ("http://httpbin.org");
+ public static string HttpUrl => Url;
public static string GetAbsoluteRedirectUrl (int count) => $"{Url}/absolute-redirect/{count}";
public static string GetRedirectUrl (int count) => $"{Url}/redirect/{count}";
public static string GetRelativeRedirectUrl (int count) => $"{Url}/relative-redirect/{count}";
public static string GetRedirectToUrl (string redirectTo) => $"{Url}/redirect-to?url={Uri.EscapeDataString (redirectTo)}";
- public static string GetStatusCodeUrl (HttpStatusCode status) => $"{HttpUrl}/status/{(int) status}";
+ public static string GetStatusCodeUrl (HttpStatusCode status) => $"{Url}/status/{(int) status}";
public static string GetSetCookieUrl (string cookie, string value) => $"{Url}/cookies/set?{cookie}={value}";
public static string GetBasicAuthUrl (string username, string password) => $"{Url}/basic-auth/{username}/{password}";
public static string GetDigestAuthUrl (string username, string password) => $"{Url}/digest-auth/auth/{username}/{password}";
diff --git a/tests/xharness/Harness.cs b/tests/xharness/Harness.cs
index 33cf6b5ffb93..a8490b532f08 100644
--- a/tests/xharness/Harness.cs
+++ b/tests/xharness/Harness.cs
@@ -355,6 +355,13 @@ void PopulateUnitTestProjects ()
Timeout = (TimeSpan?) TimeSpan.FromMinutes (10),
Filter = "",
},
+ new {
+ Label = TestLabel.AssemblyProcessing,
+ ProjectPath = Path.GetFullPath (Path.Combine (HarnessConfiguration.RootDirectory, "assembly-preparer", "assembly-preparer-tests.csproj")),
+ Name = "Assembly processing tests",
+ Timeout = (TimeSpan?) TimeSpan.FromMinutes (10),
+ Filter = "",
+ },
new {
Label = TestLabel.Generator,
ProjectPath = Path.GetFullPath (Path.Combine (HarnessConfiguration.RootDirectory, "bgen", "bgen-tests.csproj")),
diff --git a/tests/xharness/Jenkins/TestVariationsFactory.cs b/tests/xharness/Jenkins/TestVariationsFactory.cs
index 67e10a4b01fb..3a1a28462bb8 100644
--- a/tests/xharness/Jenkins/TestVariationsFactory.cs
+++ b/tests/xharness/Jenkins/TestVariationsFactory.cs
@@ -32,9 +32,9 @@ IEnumerable GetTestData (RunTestTask test)
var x64_runtime_identifier = string.Empty;
var arm64_sim_runtime_identifier = string.Empty;
var x64_sim_runtime_identifier = string.Empty;
- var supports_mono = test.Platform != TestPlatform.Mac;
var supports_coreclr = true;
var ignore_coreclr = ignore;
+ var supports_mono = test.Platform != TestPlatform.Mac;
var supports_x64 = string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("ACES")); // x64 is not supported on ACES machines
switch (test.Platform) {
@@ -57,7 +57,39 @@ IEnumerable GetTestData (RunTestTask test)
}
switch (test.TestName) {
+ case "dont link":
+ if (supports_coreclr) {
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, CoreCLR, Dynamic Registrar)", TestVariation = "coreclr|prepare-assemblies|dynamic-registrar", Ignored = ignore };
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, CoreCLR, Managed Static Registrar)", TestVariation = "coreclr|prepare-assemblies|managed-static-registrar", Ignored = ignore };
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, CoreCLR, Trimmable Static Registrar)", TestVariation = "coreclr|prepare-assemblies|trimmable-static-registrar", Ignored = ignore };
+ }
+ if (supports_mono) {
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, MonoVM, Dynamic Registrar)", TestVariation = "monovm|prepare-assemblies|dynamic-registrar", Ignored = ignore };
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, MonoVM, Managed Static Registrar)", TestVariation = "monovm|prepare-assemblies|managed-static-registrar", Ignored = ignore };
+ if (jenkins.Harness.DotNetVersion.Major >= 11) { // on Mono, the trimmable static registrar only works in .NET 11
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, MonoVM, Trimmable Static Registrar)", TestVariation = "monovm|prepare-assemblies|trimmable-static-registrar", Ignored = ignore };
+ }
+ }
+ break;
+ case "link sdk":
+ if (supports_coreclr) {
+ // if prepare-assemblies is enabled, then linking only works in any meaningful way when using the trimmable static registrar, which only works on CoreCLR in .NET 10
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, CoreCLR, Trimmable Static Registrar)", TestVariation = "coreclr|prepare-assemblies|trimmable-static-registrar", Ignored = ignore };
+ }
+ if (supports_mono && jenkins.Harness.DotNetVersion.Major >= 11) {
+ // if prepare-assemblies is enabled, then linking only works in any meaningful way when using the trimmable static registrar, which, on Mono, only works in .NET 11
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, MonoVM, Trimmable Static Registrar)", TestVariation = "monovm|prepare-assemblies|trimmable-static-registrar", Ignored = ignore };
+ }
+ break;
case "link all":
+ if (supports_coreclr) {
+ // if prepare-assemblies is enabled, then linking only works in any meaningful way when using the trimmable static registrar, which only works on CoreCLR in .NET 10
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, CoreCLR, Trimmable Static Registrar)", TestVariation = "coreclr|prepare-assemblies|trimmable-static-registrar", Ignored = ignore };
+ }
+ if (supports_mono && jenkins.Harness.DotNetVersion.Major >= 11) {
+ // if prepare-assemblies is enabled, then linking only works in any meaningful way when using the trimmable static registrar, which, on Mono, only works in .NET 11
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies, MonoVM, Trimmable Static Registrar)", TestVariation = "monovm|prepare-assemblies|trimmable-static-registrar", Ignored = ignore };
+ }
if (test.ProjectConfiguration == "Debug") {
yield return new TestData { Variation = "Debug (don't bundle original resources)", TestVariation = "do-not-bundle-original-resources" };
}
@@ -77,6 +109,7 @@ IEnumerable GetTestData (RunTestTask test)
}
yield return new TestData { Variation = "Release (link sdk)", TestVariation = "release|linksdk", Ignored = ignore };
yield return new TestData { Variation = "Release (link all)", TestVariation = "release|linkall", Ignored = ignore };
+ yield return new TestData { Variation = $"{test.ProjectConfiguration} (PrepareAssemblies)", TestVariation = "prepare-assemblies", Ignored = ignore };
break;
}
diff --git a/tests/xharness/TestLabel.cs b/tests/xharness/TestLabel.cs
index 9085a1eb815f..0bc5e9d78910 100644
--- a/tests/xharness/TestLabel.cs
+++ b/tests/xharness/TestLabel.cs
@@ -44,7 +44,8 @@ public enum TestLabel : Int64 {
Generator = 1 << 11,
[Label ("interdependent-binding-projects")]
InterdependentBindingProjects = 1 << 12,
- // 1 << 13 is unused
+ [Label ("assembly-processing")]
+ AssemblyProcessing = 1 << 13,
[Label ("introspection")]
Introspection = 1 << 14,
[Label ("linker")]
diff --git a/tools/.vscode/tasks.json b/tools/.vscode/tasks.json
new file mode 100644
index 000000000000..45465f774797
--- /dev/null
+++ b/tools/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "shell",
+ "command": "make",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": [
+ "$msCompile"
+ ],
+ "label": "make"
+ }
+ ]
+}
diff --git a/tools/Makefile b/tools/Makefile
index 00d896286809..c4c969bf82b7 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -14,3 +14,4 @@ SUBDIRS+=mlaunch
SUBDIRS += dotnet-linker
+SUBDIRS += assembly-preparer
diff --git a/tools/ap-launcher/.gitignore b/tools/ap-launcher/.gitignore
new file mode 100644
index 000000000000..af1e7137432d
--- /dev/null
+++ b/tools/ap-launcher/.gitignore
@@ -0,0 +1,2 @@
+.build-stamp
+
diff --git a/tools/ap-launcher/.vscode/tasks.json b/tools/ap-launcher/.vscode/tasks.json
new file mode 100644
index 000000000000..69a9b5f361b2
--- /dev/null
+++ b/tools/ap-launcher/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "shell",
+ "command": "make",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": [
+ "$msCompile"
+ ],
+ "label": "build"
+ }
+ ]
+}
diff --git a/tools/ap-launcher/Makefile b/tools/ap-launcher/Makefile
new file mode 100644
index 000000000000..adb26c8c4e3c
--- /dev/null
+++ b/tools/ap-launcher/Makefile
@@ -0,0 +1,8 @@
+TOP=../..
+include $(TOP)/Make.config
+include $(TOP)/mk/rules.mk
+
+build:
+ $(Q_BUILD) $(DOTNET) build /bl:$@.binlog *.csproj $(DOTNET_BUILD_VERBOSITY)
+
+all-local:: build
diff --git a/tools/ap-launcher/Program.cs b/tools/ap-launcher/Program.cs
new file mode 100644
index 000000000000..44da342c46a9
--- /dev/null
+++ b/tools/ap-launcher/Program.cs
@@ -0,0 +1,74 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Xamarin.Build;
+using Xamarin.Bundler;
+using Xamarin.Utils;
+
+class Program {
+ public static int Main (string [] args)
+ {
+ var optionsFile = args.Single (v => v.StartsWith ("--options-file=")).Substring ("--options-file=".Length);
+ var makeReproPath = args.SingleOrDefault (v => v.StartsWith ("--make-repro-path="))?.Substring ("--make-repro-path=".Length) ?? "";
+
+ var api = new List ();
+ foreach (var inputArgs in args.Where (v => v.StartsWith ("--input-assembly=")).Select (v => v.Substring ("--input-assembly=".Length))) {
+ var ia = inputArgs.Split ('|');
+ var inputPath = ia.Single (v => v.StartsWith ("InputPath="))?.Substring ("InputPath=".Length) ?? throw new InvalidOperationException ("InputPath is required");
+ var outputPath = ia.Single (v => v.StartsWith ("OutputPath="))?.Substring ("OutputPath=".Length) ?? throw new InvalidOperationException ("OutputPath is required");
+ var isTrimmableString = ia.Single (v => v.StartsWith ("IsTrimmable="))?.Substring ("IsTrimmable=".Length);
+ var isTrimmable = string.IsNullOrEmpty (isTrimmableString) ? (bool?) null : string.Equals (isTrimmableString, "true", StringComparison.OrdinalIgnoreCase);
+ var trimMode = ia.Single (v => v.StartsWith ("TrimMode="))?.Substring ("TrimMode=".Length) ?? "";
+
+ api.Add (new AssemblyPreparerInfo (inputPath, outputPath, isTrimmable, trimMode));
+ }
+
+ var platformString = File.ReadAllLines (optionsFile).Single (v => v.StartsWith ("Platform=")).Substring ("Platform=".Length);
+ var platform = ApplePlatformExtensions.Parse (platformString);
+
+ var infos = api.ToArray ();
+ var logger = new TestLogger () {
+ Platform = platform,
+ };
+ using var preparer = new AssemblyPreparer (logger, infos, optionsFile);
+ preparer.MakeReproPath = makeReproPath ?? "";
+ var rv = preparer.Prepare (out var exceptions);
+
+ return rv && exceptions.Count == 0 ? 0 : 1;
+ }
+}
+
+class TestLogger : IToolLog {
+ public int Verbosity => 0;
+ public required ApplePlatform Platform { get; set; }
+
+ public void Log (string value)
+ {
+ Console.WriteLine (value);
+ }
+
+ public void LogError (string value)
+ {
+ Console.WriteLine (value);
+ }
+
+ public void Log (string format, params object? [] args)
+ {
+ Console.WriteLine (format, args);
+ }
+
+ public void LogException (Exception ex)
+ {
+ Console.Error.WriteLine (ex.ToString ());
+ }
+
+ public void LogError (ProductException ex)
+ {
+ Console.Error.WriteLine (ex.ToString ());
+ }
+
+ public void LogWarning (ProductException ex)
+ {
+ Console.WriteLine (ex.ToString ());
+ }
+}
diff --git a/tools/ap-launcher/README.md b/tools/ap-launcher/README.md
new file mode 100644
index 000000000000..5007c9cc4226
--- /dev/null
+++ b/tools/ap-launcher/README.md
@@ -0,0 +1,2 @@
+This is just a simple project that references the assembly-preparer library, to make it easy to debug the library in a debugger.
+
diff --git a/tools/ap-launcher/ap-launcher.csproj b/tools/ap-launcher/ap-launcher.csproj
new file mode 100644
index 000000000000..ea7daa76d3f5
--- /dev/null
+++ b/tools/ap-launcher/ap-launcher.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net$(BundledNETCoreAppTargetFrameworkVersion)
+ false
+ false
+ ap_launcher
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/tools/ap-launcher/ap-launcher.slnx b/tools/ap-launcher/ap-launcher.slnx
new file mode 100644
index 000000000000..f543c9a91276
--- /dev/null
+++ b/tools/ap-launcher/ap-launcher.slnx
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/tools/assembly-preparer/.gitignore b/tools/assembly-preparer/.gitignore
new file mode 100644
index 000000000000..65bf06abaee5
--- /dev/null
+++ b/tools/assembly-preparer/.gitignore
@@ -0,0 +1,2 @@
+*.csproj.inc
+
diff --git a/tools/assembly-preparer/.vscode/tasks.json b/tools/assembly-preparer/.vscode/tasks.json
new file mode 100644
index 000000000000..69a9b5f361b2
--- /dev/null
+++ b/tools/assembly-preparer/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "shell",
+ "command": "make",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": [
+ "$msCompile"
+ ],
+ "label": "build"
+ }
+ ]
+}
diff --git a/tools/assembly-preparer/AssemblyPreparer.cs b/tools/assembly-preparer/AssemblyPreparer.cs
new file mode 100644
index 000000000000..f26d3c2f573a
--- /dev/null
+++ b/tools/assembly-preparer/AssemblyPreparer.cs
@@ -0,0 +1,388 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Runtime.Serialization;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.CompilerServices.SymbolWriter;
+using Mono.Linker;
+using Mono.Linker.Steps;
+using Mono.Tuner;
+using MonoTouch.Tuner;
+using Xamarin.Bundler;
+using Xamarin.Linker;
+using Xamarin.Linker.Steps;
+using Xamarin.Tuner;
+using Xamarin.Utils;
+
+namespace Xamarin.Build;
+
+public class AssemblyPreparer : IDisposable {
+ AggregateLog log = new AggregateLog ();
+
+ LinkerConfiguration configuration;
+
+ public LinkerConfiguration Configuration => configuration;
+
+ public string MakeReproPath { get; set; } = "";
+
+ public RegistrarMode Registrar {
+ get => configuration.Application.Registrar;
+ set => configuration.Application.Registrar = value;
+ }
+
+ public string IntermediateOutputPath {
+ get => configuration.IntermediateOutputPath;
+ }
+
+ public Optimizations Optimizations => configuration.Application.Optimizations;
+
+ public List Assemblies { get; set; } = new List ();
+
+ public IList<(string Path, AssemblyDefinition Assembly, string? OriginatingAssembly)> AddedAssemblies => configuration.AddedAssemblies;
+
+ LinkerConfiguration.Configurator GetConfigurator (string? reproPath = null, Func? assemblyPreparerInfoFactory = null)
+ {
+ var dict = new LinkerConfiguration.Configurator () {
+ { "AssemblyPreparer", (
+ new LinkerConfiguration.LoadValue ((key, value) => {
+ var split = value.Split ('|');
+ var input = split[0];
+ var output = split[1];
+ var isTrimmableString = split[2];
+ var isTrimmable = string.IsNullOrEmpty (isTrimmableString) ? (bool?) null : string.Equals (isTrimmableString, "true", StringComparison.OrdinalIgnoreCase);
+ var trimMode = split[3];
+ var apinfo = assemblyPreparerInfoFactory is not null ? assemblyPreparerInfoFactory (input, output) : new AssemblyPreparerInfo (input, output, isTrimmable, trimMode);
+ Assemblies.Add (apinfo);
+ }),
+ new LinkerConfiguration.SaveValue ((key, storage) => SaveAssemblies (key, storage, reproPath, Assemblies))
+ )},
+ };
+ return dict;
+ }
+
+ static void SaveAssemblies (string key, List storage, string? reproPath, IList assemblies)
+ {
+ foreach (var assembly in assemblies) {
+ var input = assembly.InputPath;
+ var output = assembly.OutputPath;
+ if (!string.IsNullOrEmpty (reproPath)) {
+ output = Path.Combine (reproPath, Path.GetFileName (output));
+ File.Copy (input, output);
+ }
+ storage.Add ($"{key}={input}|{output}|{(assembly.IsTrimmable.HasValue ? (assembly.IsTrimmable.Value ? "true" : "false") : "")}|{assembly.TrimMode}");
+ }
+ }
+
+ public AssemblyPreparer (IToolLog log, AssemblyPreparerInfo [] assemblies, string linker_file)
+ {
+ var lines = File.ReadAllLines (linker_file).ToList ();
+ SaveAssemblies ("AssemblyPreparer", lines, null, assemblies);
+ configuration = new LinkerConfiguration (log, lines, linker_file, GetConfigurator (null, assemblies.Length == 0 ? null : (input, output) => assemblies.Single (a => a.InputPath == input && a.OutputPath == output)));
+ }
+
+ public void AddLog (IAssemblyPreparerLog log)
+ {
+ if (log is null)
+ throw new ArgumentNullException (nameof (log));
+ this.log.Add (log);
+ }
+
+ bool SaveToReproPath (List exceptions)
+ {
+ if (File.Exists (MakeReproPath) || Directory.Exists (MakeReproPath)) {
+ exceptions.Add (ErrorHelper.CreateError (99, $"Repro location already exists: {MakeReproPath}"));
+ return false;
+ }
+ Directory.CreateDirectory (MakeReproPath);
+ var lines = new List ();
+ configuration.Save (lines, GetConfigurator (MakeReproPath));
+ File.WriteAllLines (Path.Combine (MakeReproPath, "arguments.txt"), lines);
+ log.Log ($"Created repro in {MakeReproPath}");
+
+ return true;
+ }
+
+ public static AssemblyPreparer LoadFromReproPath (string reproPath)
+ {
+ var file = Path.Combine (reproPath, "arguments.txt");
+ if (!File.Exists (file))
+ throw new FileNotFoundException ($"Repro arguments file not found: {file}");
+ return new AssemblyPreparer (ConsoleLog.Instance, [], file);
+ }
+
+ public bool Prepare (out List exceptions)
+ {
+ exceptions = configuration.Exceptions;
+
+ if (Registrar == RegistrarMode.Default) {
+ exceptions.Add (ErrorHelper.CreateError (99, "RegistrarMode must be explicitly set."));
+ return false;
+ }
+
+ if (!string.IsNullOrEmpty (MakeReproPath) && !SaveToReproPath (exceptions))
+ return false;
+
+ var steps = new ConfigurationAwareStep [] {
+ // All the same steps as the custom trimmer steps that are run before MarkStep in Xamarin.Shared.Sdk.targets (and in the same order).
+ // CollectAssembliesStep
+ new CoreTypeMapStep (),
+ // ProcessExportedFields
+ new PreserveProtocolsStep (),
+ new PreserveSmartEnumConversionsStep (),
+ new PreserveBlockCodeStep (),
+ new OptimizeGeneratedCodeStep (),
+ new ApplyPreserveAttributeStep (),
+ new MarkForStaticRegistrarStep (),
+ new MarkNSObjectsStep (),
+ new InlineDlfcnMethodsStep (),
+ new RegistrarRemovalTrackingStep (),
+ // PreMarkDispatcher: I don't think we need this one
+ new ManagedRegistrarStep (),
+ new TrimmableRegistrarStep (),
+ new ManagedRegistrarLookupTablesStep (),
+ };
+
+ var linkContext = configuration.DerivedLinkContext;
+
+ var parameters = new ReaderParameters {
+ AssemblyResolver = configuration.AssemblyResolver,
+ MetadataResolver = configuration.MetadataResolver,
+ ReadSymbols = true,
+ SymbolReaderProvider = new DefaultSymbolReaderProvider (throwIfNoSymbol: false),
+ };
+
+ var skippedAssemblies = new List ();
+ foreach (var assembly in Assemblies) {
+ AssemblyDefinition assemblyDefinition;
+ try {
+ assemblyDefinition = AssemblyDefinition.ReadAssembly (assembly.InputPath, parameters);
+ } catch (BadImageFormatException) {
+ // Not a managed assembly, skip it (pass it through unchanged).
+ log.Log ($"Skipping non-managed assembly: {assembly.InputPath}");
+ assembly.OutputPath = assembly.InputPath;
+ skippedAssemblies.Add (assembly);
+ continue;
+ }
+ linkContext.Assemblies.Add (assemblyDefinition);
+ assembly.Assembly = assemblyDefinition;
+ configuration.Context.Annotations.SetAction (assemblyDefinition, ComputeAssemblyAction (assemblyDefinition, assembly));
+ var assemblyName = assemblyDefinition.Name.Name;
+ if (configuration.AssemblyResolver.ResolverCache.ContainsKey (assemblyName))
+ exceptions.Add (ErrorHelper.CreateWarning (99, $"Duplicate assembly name '{assemblyName}' in the list of assemblies to prepare (new: {assembly.InputPath})."));
+ configuration.AssemblyResolver.ResolverCache [assemblyName] = assemblyDefinition;
+ }
+
+ configuration.Context.Annotations.CollectOverrides (linkContext.Assemblies, linkContext);
+
+ // Populate FieldSymbols for InlineDlfcnMethodsStep's compatibility mode.
+ // This is equivalent to what ProcessExportedFields does in the ILLink pipeline.
+ if (configuration.InlineDlfcnMethodsEnabled) {
+ foreach (var assembly in linkContext.Assemblies) {
+ if (!assembly.MainModule.HasTypeReference (Namespaces.Foundation + ".FieldAttribute"))
+ continue;
+ foreach (var type in assembly.MainModule.Types)
+ CollectFieldSymbols (configuration, type);
+ }
+ }
+
+ foreach (var step in steps) {
+ step.Process (linkContext);
+ }
+
+ // save assemblies
+
+ foreach (var assembly in Assemblies) {
+ if (skippedAssemblies.Contains (assembly))
+ continue;
+
+ var assemblyDefinition = assembly.Assembly;
+ if (assemblyDefinition is null) {
+ exceptions.Add (ErrorHelper.CreateError (99, $"Assembly definition is null for {assembly.InputPath}"));
+ return false;
+ }
+
+ var action = configuration.Context.Annotations.GetAction (assemblyDefinition);
+ switch (action) {
+ case AssemblyAction.Copy:
+ case AssemblyAction.CopyUsed:
+ assembly.OutputPath = assembly.InputPath;
+ continue;
+ case AssemblyAction.Link:
+ case AssemblyAction.Save:
+ log.Log ($"Saving {assembly.InputPath} to {assembly.OutputPath}");
+ break;
+ default:
+ exceptions.Add (ErrorHelper.CreateError (99, $"Unknown link action: {action} for assembly {assemblyDefinition.Name}"));
+ return false;
+ }
+
+ PathUtils.CreateDirectoryForFile (assembly.OutputPath);
+ var writerParameters = new WriterParameters ();
+ if (assemblyDefinition.MainModule.HasSymbols) {
+ var provider = new CustomSymbolWriterProvider ();
+ try {
+ using (var tmp = provider.GetSymbolWriter (assemblyDefinition.MainModule, Path.ChangeExtension (assembly.OutputPath, ".pdb"))) { }
+ File.Delete (Path.ChangeExtension (assembly.OutputPath, ".pdb"));
+ writerParameters.WriteSymbols = true;
+ writerParameters.SymbolWriterProvider = provider;
+ } catch (Exception e) {
+ log.Log ($"Failed to create symbol writer for {assembly.OutputPath}, not writing symbols: {e.Message}");
+ }
+ }
+
+ RemoveCrossGen (assemblyDefinition);
+
+ try {
+ assemblyDefinition.Write (assembly.OutputPath, writerParameters);
+ ModuleAttributes m = assemblyDefinition.MainModule.Attributes;
+ } catch (Exception e) {
+ exceptions.Add (ErrorHelper.CreateError (99, e, $"Failed to write {assembly.OutputPath}: {e.Message}"));
+ log.Log ($"Failed to write {assembly.OutputPath}: {e}");
+ return false;
+ }
+ }
+
+ return exceptions.Count == 0;
+ }
+
+ void RemoveCrossGen (AssemblyDefinition assemblyDefinition)
+ {
+ // Drop crossgened code from the assembly
+ // Ref: https://github.com/dotnet/runtime/blob/b86458593223f866effa63122b05bec37f83015e/src/tools/illink/src/linker/Linker.Steps/OutputStep.cs#L95-L105
+ foreach (var module in assemblyDefinition.Modules) {
+ var moduleAttributes = module.Attributes;
+ var isCrossGened = (moduleAttributes & ModuleAttributes.ILOnly) == 0 && (moduleAttributes & ModuleAttributes.ILLibrary) == ModuleAttributes.ILLibrary;
+ if (isCrossGened) {
+ moduleAttributes |= ModuleAttributes.ILOnly;
+ moduleAttributes &= ~ModuleAttributes.ILLibrary;
+ module.Attributes = moduleAttributes;
+ module.Architecture = TargetArchitecture.I386;
+ module.Characteristics |= ModuleCharacteristics.NoSEH;
+ }
+ }
+ }
+
+ // Figure out if an assembly is trimmed or not.
+ // This must be identical to how it's done for ILLink/ILC.
+ AssemblyAction ComputeAssemblyAction (AssemblyDefinition assembly, AssemblyPreparerInfo info)
+ {
+ // Unless 'PublishTrimmed=true', nothing is trimmed, because we won't run the trimmer.
+ if (!configuration.PublishTrimmed)
+ return AssemblyAction.Copy;
+
+ // Then if 'TrimMode' is set on the assembly, then that takes precedence
+ switch (info.TrimMode?.ToLowerInvariant () ?? "") {
+ case "link":
+ return AssemblyAction.Link;
+ case "copy":
+ return AssemblyAction.Copy;
+ case "":
+ break;
+ default:
+ throw new ArgumentException ($"Unknown trim mode: {info.TrimMode} for assembly {assembly.Name}");
+ }
+
+ // Then if 'IsTrimmable' is set on the assembly, that takes precedence over the default for the platform.
+ if (info.IsTrimmable == false)
+ return AssemblyAction.CopyUsed;
+ else if (info.IsTrimmable == true)
+ return AssemblyAction.Link;
+
+ // Check the global 'TrimMode' property, if it's not 'link', 'partial' or 'full', then we're not trimming anything
+ var globalTrimMode = configuration.TrimMode.ToLowerInvariant ();
+ switch (globalTrimMode) {
+ case "copy":
+ case "":
+ return AssemblyAction.Copy;
+ case "partial":
+ case "full":
+ case "link":
+ break;
+ default:
+ throw new ArgumentException ($"Unknown global trim mode: {configuration.TrimMode}");
+ }
+
+ // Check the [AssemblyMetadata] attribute
+ var isTrimmableAttribute = assembly.CustomAttributes
+ .Where (v => v.AttributeType.FullName == "System.Reflection.AssemblyMetadataAttribute")
+ .Where (v => v.HasConstructorArguments && v.ConstructorArguments.Count == 2 && v.ConstructorArguments [0].Type.Is ("System", "String") && v.ConstructorArguments [1].Type.Is ("System", "String"))
+ .Where (v => (v.ConstructorArguments [0].Value as string) == "IsTrimmable" && string.Equals (v.ConstructorArguments [1].Value as string, "true", StringComparison.OrdinalIgnoreCase))
+ .SingleOrDefault ();
+
+ if (isTrimmableAttribute is null) {
+ // If the attribute is not present, then we trim if the global 'TrimMode' is 'full'
+ return globalTrimMode switch {
+ "link" => AssemblyAction.Copy,
+ "partial" => AssemblyAction.Copy,
+ "full" => AssemblyAction.Link,
+ _ => throw new ArgumentException ($"Unknown global trim mode: {configuration.TrimMode}"),
+ };
+ }
+
+ // if the attribute is present, then we trim if the global 'TrimMode' is 'partial', 'full' or 'link', which are the only values it should have at this point
+ switch (globalTrimMode) {
+ case "partial":
+ case "full":
+ case "link":
+ break;
+ default:
+ // we shouldn't get here for any other trim mode value
+ throw new ArgumentException ($"Unexpected global trim mode: {configuration.TrimMode}");
+ }
+
+ return AssemblyAction.Link;
+ }
+
+ public void Dispose ()
+ {
+ foreach (var assembly in Assemblies)
+ assembly.Assembly?.Dispose ();
+ configuration.AssemblyResolver.ResolverCache.Clear ();
+ configuration.DerivedLinkContext.Assemblies.Clear ();
+ }
+
+ static void CollectFieldSymbols (LinkerConfiguration configuration, TypeDefinition type)
+ {
+ if (type.HasNestedTypes) {
+ foreach (var nested in type.NestedTypes)
+ CollectFieldSymbols (configuration, nested);
+ }
+
+ if (!type.HasProperties)
+ return;
+
+ foreach (var property in type.Properties) {
+ if (!property.HasCustomAttributes)
+ continue;
+
+ foreach (var attrib in property.CustomAttributes) {
+ var declaringType = attrib.Constructor.DeclaringType.Resolve ();
+ if (!declaringType.Is (Namespaces.Foundation, "FieldAttribute"))
+ continue;
+ if (attrib.ConstructorArguments.Count < 1)
+ continue;
+ configuration.FieldSymbols.Add ((string) attrib.ConstructorArguments [0].Value);
+ break;
+ }
+ }
+ }
+}
+
+public class AssemblyPreparerInfo {
+ internal AssemblyDefinition? Assembly { get; set; }
+
+ public string InputPath { get; private set; }
+ public bool? IsTrimmable { get; set; }
+ public string TrimMode { get; set; }
+ public string OutputPath { get; set; }
+
+ public AssemblyPreparerInfo (string inputPath, string outputPath, bool? isTrimmable, string trimMode)
+ {
+ InputPath = inputPath;
+ OutputPath = outputPath;
+ IsTrimmable = isTrimmable;
+ TrimMode = trimMode;
+ }
+}
diff --git a/tools/assembly-preparer/DynamicallyAccessedMemberTypes.cs b/tools/assembly-preparer/DynamicallyAccessedMemberTypes.cs
new file mode 100644
index 000000000000..4a42e76ab54c
--- /dev/null
+++ b/tools/assembly-preparer/DynamicallyAccessedMemberTypes.cs
@@ -0,0 +1,176 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// This file is needed because we compile the current project under netstandard2.0, and this type doesn't exist there.
+
+#if !NET
+
+// From https://raw.githubusercontent.com/dotnet/dotnet/b0f34d51fccc69fd334253924abd8d6853fad7aa/src/runtime/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMemberTypes.cs
+
+global using DynamicallyAccessedMemberTypes = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes2;
+
+namespace System.Diagnostics.CodeAnalysis {
+ using System.ComponentModel;
+
+ ///
+ /// Specifies the types of members that are dynamically accessed.
+ ///
+ /// This enumeration has a attribute that allows a
+ /// bitwise combination of its member values.
+ ///
+ [Flags]
+ enum DynamicallyAccessedMemberTypes2 {
+ ///
+ /// Specifies no members.
+ ///
+ None = 0,
+
+ ///
+ /// Specifies the default, parameterless public constructor.
+ ///
+ PublicParameterlessConstructor = 0x0001,
+
+ ///
+ /// Specifies all public constructors.
+ ///
+ PublicConstructors = 0x0002 | PublicParameterlessConstructor,
+
+ ///
+ /// Specifies all non-public constructors.
+ ///
+ NonPublicConstructors = 0x0004,
+
+ ///
+ /// Specifies all public methods.
+ ///
+ PublicMethods = 0x0008,
+
+ ///
+ /// Specifies all non-public methods.
+ ///
+ NonPublicMethods = 0x0010,
+
+ ///
+ /// Specifies all public fields.
+ ///
+ PublicFields = 0x0020,
+
+ ///
+ /// Specifies all non-public fields.
+ ///
+ NonPublicFields = 0x0040,
+
+ ///
+ /// Specifies all public nested types.
+ ///
+ PublicNestedTypes = 0x0080,
+
+ ///
+ /// Specifies all non-public nested types.
+ ///
+ NonPublicNestedTypes = 0x0100,
+
+ ///
+ /// Specifies all public properties.
+ ///
+ PublicProperties = 0x0200,
+
+ ///
+ /// Specifies all non-public properties.
+ ///
+ NonPublicProperties = 0x0400,
+
+ ///
+ /// Specifies all public events.
+ ///
+ PublicEvents = 0x0800,
+
+ ///
+ /// Specifies all non-public events.
+ ///
+ NonPublicEvents = 0x1000,
+
+ ///
+ /// Specifies all interfaces implemented by the type.
+ ///
+ Interfaces = 0x2000,
+
+ ///
+ /// Specifies all non-public constructors, including those inherited from base classes.
+ ///
+ NonPublicConstructorsWithInherited = NonPublicConstructors | 0x4000,
+
+ ///
+ /// Specifies all non-public methods, including those inherited from base classes.
+ ///
+ NonPublicMethodsWithInherited = NonPublicMethods | 0x8000,
+
+ ///
+ /// Specifies all non-public fields, including those inherited from base classes.
+ ///
+ NonPublicFieldsWithInherited = NonPublicFields | 0x10000,
+
+ ///
+ /// Specifies all non-public nested types, including those inherited from base classes.
+ ///
+ NonPublicNestedTypesWithInherited = NonPublicNestedTypes | 0x20000,
+
+ ///
+ /// Specifies all non-public properties, including those inherited from base classes.
+ ///
+ NonPublicPropertiesWithInherited = NonPublicProperties | 0x40000,
+
+ ///
+ /// Specifies all non-public events, including those inherited from base classes.
+ ///
+ NonPublicEventsWithInherited = NonPublicEvents | 0x80000,
+
+ ///
+ /// Specifies all public constructors, including those inherited from base classes.
+ ///
+ PublicConstructorsWithInherited = PublicConstructors | 0x100000,
+
+ ///
+ /// Specifies all public nested types, including those inherited from base classes.
+ ///
+ PublicNestedTypesWithInherited = PublicNestedTypes | 0x200000,
+
+ ///
+ /// Specifies all constructors, including those inherited from base classes.
+ ///
+ AllConstructors = PublicConstructorsWithInherited | NonPublicConstructorsWithInherited,
+
+ ///
+ /// Specifies all methods, including those inherited from base classes.
+ ///
+ AllMethods = PublicMethods | NonPublicMethodsWithInherited,
+
+ ///
+ /// Specifies all fields, including those inherited from base classes.
+ ///
+ AllFields = PublicFields | NonPublicFieldsWithInherited,
+
+ ///
+ /// Specifies all nested types, including those inherited from base classes.
+ ///
+ AllNestedTypes = PublicNestedTypesWithInherited | NonPublicNestedTypesWithInherited,
+
+ ///
+ /// Specifies all properties, including those inherited from base classes.
+ ///
+ AllProperties = PublicProperties | NonPublicPropertiesWithInherited,
+
+ ///
+ /// Specifies all events, including those inherited from base classes.
+ ///
+ AllEvents = PublicEvents | NonPublicEventsWithInherited,
+
+ ///
+ /// Specifies all members.
+ ///
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ All = ~None
+ }
+}
+
+#endif // !NET
diff --git a/tools/assembly-preparer/GlobalUsings.cs b/tools/assembly-preparer/GlobalUsings.cs
new file mode 100644
index 000000000000..ba0a28435170
--- /dev/null
+++ b/tools/assembly-preparer/GlobalUsings.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+global using System;
+global using System.Collections.Generic;
+global using System.Diagnostics.CodeAnalysis;
+global using System.Linq;
+global using System.Runtime.InteropServices;
+
+global using Foundation;
+global using ObjCRuntime;
+
+global using Xamarin.Linker;
+
+namespace Xamarin.Tuner { }
+namespace Mono.Linker.Steps { }
diff --git a/tools/assembly-preparer/IAssemblyPreparerLog.cs b/tools/assembly-preparer/IAssemblyPreparerLog.cs
new file mode 100644
index 000000000000..f41de7ca475e
--- /dev/null
+++ b/tools/assembly-preparer/IAssemblyPreparerLog.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using Xamarin.Bundler;
+
+namespace Xamarin.Build;
+
+public interface IAssemblyPreparerLog {
+ void Log (string message);
+}
+
+class AggregateLog : IAssemblyPreparerLog {
+ List logs = new ();
+
+ public void Add (IAssemblyPreparerLog log)
+ {
+ logs.Add (log);
+ }
+
+ public void Log (string message)
+ {
+ foreach (var log in logs)
+ log.Log (message);
+ }
+}
diff --git a/tools/assembly-preparer/Makefile b/tools/assembly-preparer/Makefile
new file mode 100644
index 000000000000..587a1d6116f5
--- /dev/null
+++ b/tools/assembly-preparer/Makefile
@@ -0,0 +1,25 @@
+TOP=../..
+include $(TOP)/Make.config
+include $(TOP)/mk/rules.mk
+include ../common/Make.common
+
+# assembly-preparer.csproj.inc contains the $(assembly_preparer_dependencies) variable used to determine if assembly-preparer needs to be rebuilt or not.
+assembly-preparer.csproj.inc: export BUILD_VERBOSITY=$(MSBUILD_VERBOSITY)
+-include assembly-preparer.csproj.inc
+
+ASSEMBLY_PREPARER_NETCORE=bin/Debug/$(DOTNET_TFM)/assembly-preparer.dll
+ASSEMBLY_PREPARER_NETSTD=bin/Debug/netstandard2.0/assembly-preparer.dll
+ASSEMBLIES=$(ASSEMBLY_PREPARER_NETCORE) $(ASSEMBLY_PREPARER_NETSTD)
+
+.build-stamp: $(assembly_preparer_dependencies)
+ $(Q_BUILD) $(DOTNET) build /bl:$@.binlog *.csproj $(DOTNET_BUILD_VERBOSITY)
+ $(Q) touch $(ASSEMBLIES)
+
+$(ASSEMBLIES): .build-stamp
+
+all-local:: .build-stamp
+
+run-tests:
+ $(Q_BUILD) $(DOTNET) test $(TOP)/tests/assembly-preparer/assembly-preparer-tests.csproj --logger "console;verbosity=detailed" $(DOTNET_BUILD_VERBOSITY) -bl:$@.binlog
+
+generated-files: $(abspath ../common/SdkVersions.cs) $(abspath ../common/ProductConstants.cs)
diff --git a/tools/assembly-preparer/NetStandardExtensions.cs b/tools/assembly-preparer/NetStandardExtensions.cs
new file mode 100644
index 000000000000..5f81fd7f1b93
--- /dev/null
+++ b/tools/assembly-preparer/NetStandardExtensions.cs
@@ -0,0 +1,109 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// This file is needed because we compile the current project under netstandard2.0, and the types here don't exist in netstandard2.0
+
+#if !NET
+
+public static class QueueExtensions {
+ public static bool TryDequeue (this Queue queue, [MaybeNullWhen (false)] out T item)
+ {
+ if (queue.Count == 0) {
+ item = default;
+ return false;
+ }
+ item = queue.Dequeue ();
+ return true;
+ }
+
+ public static bool TryAdd (this Dictionary dictionary, T key, V value)
+ {
+ if (dictionary.ContainsKey (key))
+ return false;
+ dictionary.Add (key, value);
+ return true;
+ }
+}
+
+public static class DictionaryExtensions {
+ public static bool Remove (this Dictionary dictionary, T key, [MaybeNullWhen (false)] out V value)
+ {
+ if (dictionary.TryGetValue (key, out value)) {
+ dictionary.Remove (key);
+ return true;
+ }
+ return false;
+ }
+}
+
+public static class EnumerableExtensions {
+ public static IEnumerable SkipLast (this IEnumerable source, int count)
+ {
+ // very naive implementation, but it's only for netstandard2.0, which will go away soon, so no need to optimize it
+ var rv = source.ToList ();
+ if (rv.Count <= count)
+ return [];
+ rv.RemoveRange (rv.Count - count, count);
+ return rv;
+ }
+}
+
+// From: https://github.com/dotnet/dotnet/blob/b0f34d51fccc69fd334253924abd8d6853fad7aa/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RequiredMemberAttribute.cs
+namespace System.Runtime.CompilerServices {
+ using System.ComponentModel;
+
+ /// Specifies that a type has required members or that a member is required.
+ [AttributeUsage (AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ internal sealed class RequiredMemberAttribute : Attribute { }
+}
+
+// From: https://github.com/dotnet/dotnet/blob/b0f34d51fccc69fd334253924abd8d6853fad7aa/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/CompilerFeatureRequiredAttribute.cs
+namespace System.Runtime.CompilerServices {
+ using System.ComponentModel;
+
+ ///
+ /// Indicates that compiler support for a particular feature is required for the location where this attribute is applied.
+ ///
+ [AttributeUsage (AttributeTargets.All, AllowMultiple = true, Inherited = false)]
+ internal sealed class CompilerFeatureRequiredAttribute : Attribute {
+ public CompilerFeatureRequiredAttribute (string featureName)
+ {
+ FeatureName = featureName;
+ }
+
+ ///
+ /// The name of the compiler feature.
+ ///
+ public string FeatureName { get; }
+
+ ///
+ /// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand .
+ ///
+ public bool IsOptional { get; init; }
+
+ ///
+ /// The used for the ref structs C# feature.
+ ///
+ public const string RefStructs = nameof (RefStructs);
+
+ ///
+ /// The used for the required members C# feature.
+ ///
+ public const string RequiredMembers = nameof (RequiredMembers);
+ }
+}
+
+// From: https://github.com/dotnet/dotnet/blob/b0f34d51fccc69fd334253924abd8d6853fad7aa/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/IsExternalInit.cs
+namespace System.Runtime.CompilerServices {
+ using System.ComponentModel;
+
+ ///
+ /// Reserved to be used by the compiler for tracking metadata.
+ /// This class should not be used by developers in source code.
+ ///
+ [EditorBrowsable (EditorBrowsableState.Never)]
+ internal static class IsExternalInit {
+ }
+}
+#endif
diff --git a/tools/assembly-preparer/README.md b/tools/assembly-preparer/README.md
new file mode 100644
index 000000000000..696974bf073f
--- /dev/null
+++ b/tools/assembly-preparer/README.md
@@ -0,0 +1,35 @@
+# Assembly preparer
+
+This is a library that will modify assemblies when a project is built for a few reasons:
+
+* Collect required information for a successful build
+* Transform some code patterns so that they can be properly recognized and handled correctly by trimmers.
+* Optimize some code patterns we can easily recognize
+* Precompute some things at build time to be able to make apps smaller and run faster.
+
+Currently it can:
+
+* PreserveCodeBlockHandler: in some cases user assemblies might contain code
+ created by the generator that's not trimmer safe; this handler will inject
+ code to ensure that trimmers don't trim way some things that shouldn't be
+ trimmed away.
+
+## Design principles
+
+* Easy to test (there's a unit test project, VSCode can run & debug its tests)
+* Can be called from an MSBuild task (which means it currently needs to target `netstandard2.0`).
+* Good error handling/reporting.
+* We have two main scenarios:
+ * Debug loop, where we shouldn't do more than absolutely necessary to make
+ debug builds as fast as possible. In particular, we'll only do whatever
+ is necessary for a correct build, and if possible, no assembly
+ modification, only information gathering.
+ * Release builds, where we want to optimize as much as possible.
+* To ease integration with existing custom linker steps, it's provides a
+ very simplified API of ILLink's custom linker step API - much of it is
+ stubbed out until it's needed.
+* Until fully complete and both correctness and performance have been
+ validated, it should be possible to use either custom linker steps or the
+ assembly preparer, and as such any code that's used by both will have to
+ keep working in both modes.
+
diff --git a/tools/assembly-preparer/Scaffolding/AnnotationStore.cs b/tools/assembly-preparer/Scaffolding/AnnotationStore.cs
new file mode 100644
index 000000000000..e1fc186bbf11
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/AnnotationStore.cs
@@ -0,0 +1,167 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Diagnostics;
+using Mono.Cecil;
+
+namespace Mono.Linker;
+
+public class AnnotationStore {
+ Dictionary assemblyActions = new Dictionary ();
+ Dictionary> overrides = new Dictionary> ();
+ public AssemblyAction GetAction (AssemblyDefinition assembly)
+ {
+ if (assemblyActions.TryGetValue (assembly, out var action))
+ return action;
+ throw new InvalidOperationException ($"Assembly {assembly.Name} not found in the annotation store");
+ }
+
+ public void SetAction (AssemblyDefinition assembly, AssemblyAction action)
+ {
+ assemblyActions [assembly] = action;
+ }
+
+ public IEnumerable? GetOverrides (MethodDefinition method)
+ {
+ if (overrides.TryGetValue (method, out var list))
+ return list;
+ return null;
+ }
+
+ // Scan all types in the given assemblies and build the overrides map.
+ // For each method that overrides a base virtual method (or explicitly implements an interface method),
+ // record an OverrideInformation entry keyed by the base method.
+ public void CollectOverrides (IEnumerable assemblies, LinkContext context)
+ {
+ foreach (var assembly in assemblies) {
+ foreach (var module in assembly.Modules) {
+ foreach (var type in module.GetTypes ()) {
+ CollectOverridesForType (type, context);
+ }
+ }
+ }
+ }
+
+ void CollectOverridesForType (TypeDefinition type, LinkContext context)
+ {
+ if (!type.HasMethods)
+ return;
+
+ foreach (var method in type.Methods) {
+ // Handle explicit overrides (.override directive in IL / method.Overrides in Cecil)
+ if (method.HasOverrides) {
+ foreach (var overriddenRef in method.Overrides) {
+ var baseMethod = TryResolve (overriddenRef);
+ if (baseMethod is not null)
+ AddOverride (baseMethod, method);
+ }
+ }
+
+ // Handle implicit virtual method overrides via the type hierarchy
+ if (method.IsVirtual && !method.IsNewSlot) {
+ var baseMethod = GetBaseMethodInTypeHierarchy (type, method, context);
+ if (baseMethod is not null)
+ AddOverride (baseMethod, method);
+ }
+ }
+ }
+
+ void AddOverride (MethodDefinition baseMethod, MethodDefinition overridingMethod)
+ {
+ if (!overrides.TryGetValue (baseMethod, out var list)) {
+ list = new List ();
+ overrides [baseMethod] = list;
+ }
+ list.Add (new OverrideInformation (overridingMethod));
+ }
+
+ static MethodDefinition? GetBaseMethodInTypeHierarchy (TypeDefinition type, MethodDefinition method, LinkContext context)
+ {
+ var baseTypeRef = type.BaseType;
+ while (baseTypeRef is not null) {
+ TypeDefinition? baseType;
+ try {
+ baseType = context.Resolve (baseTypeRef);
+ } catch {
+ break;
+ }
+
+ if (baseType.HasMethods) {
+ foreach (var candidate in baseType.Methods) {
+ if (candidate.IsVirtual && MethodMatch (candidate, method))
+ return candidate;
+ }
+ }
+
+ baseTypeRef = baseType.BaseType;
+ }
+ return null;
+ }
+
+ static bool MethodMatch (MethodDefinition candidate, MethodDefinition method)
+ {
+ if (candidate.Name != method.Name)
+ return false;
+ if (candidate.HasGenericParameters != method.HasGenericParameters)
+ return false;
+ if (candidate.GenericParameters.Count != method.GenericParameters.Count)
+ return false;
+ if (candidate.ReturnType.FullName != method.ReturnType.FullName)
+ return false;
+ if (candidate.HasParameters != method.HasParameters)
+ return false;
+ if (!candidate.HasParameters)
+ return true;
+ if (candidate.Parameters.Count != method.Parameters.Count)
+ return false;
+ for (int i = 0; i < candidate.Parameters.Count; i++) {
+ if (candidate.Parameters [i].ParameterType.FullName != method.Parameters [i].ParameterType.FullName)
+ return false;
+ }
+ return true;
+ }
+
+ static MethodDefinition? TryResolve (MethodReference methodRef)
+ {
+ try {
+ return methodRef.Resolve ();
+ } catch {
+ // FIXME: figure out a way that doesn't require throwing and catching exceptions.
+ return null;
+ }
+ }
+
+ Dictionary