diff --git a/docs/building-apps/build-properties.md b/docs/building-apps/build-properties.md
index 6089dc2ed05c..3b56409369d9 100644
--- a/docs/building-apps/build-properties.md
+++ b/docs/building-apps/build-properties.md
@@ -543,6 +543,20 @@ Removing the dynamic registrar requires a static registrar (`Registrar=static` o
`Registrar=managed-static`) and trimming, so setting this property has no effect (and the
build warns) when those conditions aren't met.
+## TrimExportAttributes
+
+Controls whether `Foundation.ExportAttribute`, `Foundation.ActionAttribute`,
+and `Foundation.OutletAttribute` instances are removed during trimming.
+
+If this property is not specified, the build automatically removes these
+attributes when assembly preparation and post-processing are enabled, the
+trimmable static registrar is selected, dynamic registration is not required,
+and no runtime fallback needs the attributes.
+
+Set this property to `false` to preserve the attributes. Set it to `true` to
+require their removal; the build will fail if it detects that the attributes
+are needed at runtime.
+
## EmbedOnDemandResources
Controls where on-demand resource asset packs are placed, so that the on-demand
diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index 65987e7381b7..15627866305d 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -294,6 +294,7 @@
_PrepareAssemblies;
_SetDynamicRegistrationSupportedFeature;
_SetSmartEnumConversionsRootDescriptor;
+ _SetTrimExportAttributesFeature;
_ComputeFrameworkFilesToPublish;
_ComputeDynamicLibrariesToPublish;
ComputeFilesToPublish;
@@ -642,7 +643,7 @@
+
+
+
+
+
+ <_TrimExportAttributesLine Include="@(_AssemblyPreparerTrimExportAttributesProperty)" Condition="$([System.String]::Copy('%(Identity)').StartsWith('TrimExportAttributes='))" />
+
+
+ <_TrimExportAttributesLineText>@(_TrimExportAttributesLine)
+ <_TrimExportAttributes>false
+ <_TrimExportAttributes Condition="'$(_TrimExportAttributesLineText)' != ''">$(_TrimExportAttributesLineText.Replace('TrimExportAttributes=', ''))
+
+
+
+
+
+
+
+
@@ -726,8 +760,16 @@
/>
+
+
+ <_TrimExportAttributes>false
+ <_TrimExportAttributes Condition="'$(PrepareAssemblies)' == 'true' And '$(PostProcessAssemblies)' == 'true' And '$(Registrar)' == 'trimmable-static'">$(TrimExportAttributes)
+
<_UseDynamicDependenciesInsteadOfMarking Condition="'$(_UseDynamicDependenciesInsteadOfMarking)' == ''">true
<_UseDynamicDependenciesForProtocolPreservation Condition="'$(_UseDynamicDependenciesForProtocolPreservation)' == ''">$(_UseDynamicDependenciesInsteadOfMarking)
<_UseDynamicDependenciesForSmartEnumPreservation Condition="'$(_UseDynamicDependenciesForSmartEnumPreservation)' == ''">$(_UseDynamicDependenciesInsteadOfMarking)
@@ -898,6 +940,7 @@
SkipMarkingNSObjectsInUserAssemblies=$(_SkipMarkingNSObjectsInUserAssemblies)
TargetArchitectures=$(TargetArchitectures)
TargetFramework=$(_ComputedTargetFrameworkMoniker)
+ TrimExportAttributes=$(_TrimExportAttributes)
TrimMode=$(TrimMode)
TypeMapAssemblyName=$(_TypeMapAssemblyName)
TypeMapFilePath=$(_TypeMapFilePath)
@@ -1027,7 +1070,7 @@
<_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" Condition="'$(PrepareAssemblies)' != 'true'" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.DetectApiUsageStep" Condition="'$(PrepareAssemblies)' != 'true'" />
<_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')" />
diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs
index 5419736fa4b6..5d360855e883 100644
--- a/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs
+++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs
@@ -31,7 +31,7 @@ public class PrepareAssemblies : XamarinTask {
public string MakeReproPath { get; set; } = "";
// The value of the $(_DynamicRegistrationSupported) MSBuild property. During post-processing this is
- // how the value RegistrarRemovalTrackingStep computed during the preparation pass is passed back to
+ // how the value DetectApiUsageStep computed during the preparation pass is passed back to
// the assembly-preparer (the native main file is generated during post-processing, and it must agree
// with the managed side about whether the dynamic registrar is available).
public string DynamicRegistrationSupported { get; set; } = "";
@@ -44,8 +44,8 @@ public class PrepareAssemblies : XamarinTask {
public bool PostProcessing { get; set; }
- // The pre-trim (untrimmed) assemblies (the trimmer's input), used during post-processing to read
- // the [ProtocolMember] attributes the trimmer removed from the post-trim assemblies.
+ // The original assemblies from before preparation and trimming, used during post-processing to read
+ // selected registrar attributes removed during trimming.
public ITaskItem [] PreTrimAssemblies { get; set; } = [];
// When set (to ILC's output object file), the defined symbols in this file are used to determine
@@ -78,10 +78,13 @@ public override bool Execute ()
{
// Capture Console usage and show an error if anything uses Console.[Error.]Write*
using var consoleToLog = ConsoleToTaskWriter.EnsureNoConsoleUsage (Log);
+ var success = false;
+ var msbuildOutputFile = "";
try {
var infos = InputAssemblies.Select (GetAssemblyInfo).ToArray ();
using var preparer = new AssemblyPreparer (this, infos, OptionsFile?.ItemSpec ?? "");
+ msbuildOutputFile = PostProcessing ? preparer.Configuration.MSBuildPostProcessOutputFile : preparer.Configuration.MSBuildOutputFile;
preparer.MakeReproPath = MakeReproPath;
preparer.PreTrimAssemblies.AddRange (PreTrimAssemblies.Select (v => v.ItemSpec));
@@ -140,8 +143,10 @@ public override bool Execute ()
outputAssemblies.AddRange (preparer.AddedAssemblies.Select (v => {
var rv = new TaskItem (v.Path);
+ var relativePath = preparer.Configuration.AssemblyPublishDir + Path.GetFileName (v.Path);
rv.SetMetadata ("PostprocessAssembly", "true");
- rv.SetMetadata ("RelativePath", preparer.Configuration.AssemblyPublishDir + Path.GetFileName (v.Path));
+ rv.SetMetadata ("OriginalRelativePath", relativePath);
+ rv.SetMetadata ("RelativePath", relativePath);
if (v.OriginatingAssembly is not null) {
var originatingAssembly = preparer.Assemblies.SingleOrDefault (assembly => assembly.InputPath == v.OriginatingAssembly);
originatingAssembly ??= preparer.Assemblies.SingleOrDefault (assembly => assembly.IsCILAssembly && Path.GetFileName (assembly.InputPath) == Path.GetFileName (v.OriginatingAssembly));
@@ -162,10 +167,14 @@ public override bool Execute ()
OutputAssemblies = outputAssemblies.ToArray ();
if (!rv && !Log.HasLoggedErrors)
Log.LogError (MSBStrings.E0192);
- return rv && !Log.HasLoggedErrors;
+ success = rv && !Log.HasLoggedErrors;
+ return success;
} catch (Exception e) {
((IToolLog) this).LogException (e);
return false;
+ } finally {
+ if (!success && !string.IsNullOrEmpty (msbuildOutputFile))
+ File.Delete (msbuildOutputFile);
}
}
}
diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
index 1bfd17c95dd6..96584743f73e 100644
--- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets
+++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
@@ -3715,13 +3715,20 @@ Copyright (C) 2018 Microsoft. All rights reserved.
$([MSBuild]::EnsureTrailingSlash('$(DeviceSpecificIntermediateOutputPath)prepared-assemblies'))
+ <_AssemblyPreparerConfigurationStamp>$(DeviceSpecificIntermediateOutputPath)assembly-preparer-configuration.txt
+
@@ -3739,6 +3746,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
+
@@ -3780,7 +3788,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
OptionsFile="$(_CustomLinkerOptionsFile)"
OutputDirectory="$(_PostprocessedAssembliesDirectory)"
Postprocessing="true"
- PreTrimAssemblies="@(ManagedAssemblyToLink)"
+ PreTrimAssemblies="@(_AssembliesToPrepare)"
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
>
diff --git a/src/ILLink.LinkAttributes.xml.in b/src/ILLink.LinkAttributes.xml.in
index 764df73f8023..c74e23e59c1c 100644
--- a/src/ILLink.LinkAttributes.xml.in
+++ b/src/ILLink.LinkAttributes.xml.in
@@ -7,6 +7,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/tests/assembly-preparer/ComputeExportAttributeRemovalStepTests.cs b/tests/assembly-preparer/ComputeExportAttributeRemovalStepTests.cs
new file mode 100644
index 000000000000..dc594e46e70a
--- /dev/null
+++ b/tests/assembly-preparer/ComputeExportAttributeRemovalStepTests.cs
@@ -0,0 +1,130 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using MonoTouch.Tuner;
+
+using Xamarin.Linker;
+
+namespace AssemblyPreparerTests;
+
+public class ComputeExportAttributeRemovalStepTests : BaseClass {
+ [TestCase (null, true)]
+ [TestCase (false, true)]
+ [TestCase (true, false)]
+ public void NonTrimmableRegistrar (bool? trimExportAttributes, bool expectedSuccess)
+ {
+ using var preparer = CreatePreparer (ApplePlatform.iOS, false, preparer => {
+ preparer.Registrar = RegistrarMode.ManagedStatic;
+ preparer.TrimExportAttributes = trimExportAttributes;
+ }, "public class C {}", out _);
+
+ var success = preparer.Prepare (out var exceptions);
+
+ Assert.That (success, Is.EqualTo (expectedSuccess), "Success");
+ if (expectedSuccess) {
+ Assert.That (exceptions, Is.Empty, "Exceptions");
+ Assert.That (preparer.TrimExportAttributes, Is.False, "Removal");
+ } else {
+ Assert.That (exceptions, Has.Count.EqualTo (1), "Exceptions");
+ Assert.That (exceptions [0].Message, Is.EqualTo ("Export attributes can only be trimmed with the trimmable static registrar."), "Error message");
+ }
+ }
+
+ [TestCase (false, false, false)]
+ [TestCase (null, false, true)]
+ [TestCase (true, false, true)]
+ [TestCase (null, true, false)]
+ public void DynamicRegistration (bool? trimExportAttributes, bool dynamicRegistrationSupported, bool expectedRemoval)
+ {
+ using var preparer = CreatePreparer (ApplePlatform.iOS, false, preparer => {
+ preparer.Registrar = RegistrarMode.TrimmableStatic;
+ preparer.TrimExportAttributes = trimExportAttributes;
+ preparer.Optimizations.RemoveDynamicRegistrar = !dynamicRegistrationSupported;
+ preparer.Optimizations.OptimizeBlockLiteralSetupBlock = true;
+ preparer.Optimizations.StaticBlockToDelegateLookup = true;
+ }, "public class C {}", out _);
+
+ var context = preparer.Configuration.DerivedLinkContext;
+ new LoadAssembliesStep ().Process (context);
+ new ComputeExportAttributeRemovalStep ().Process (context);
+
+ Assert.That (preparer.Configuration.Application.TrimExportAttributes, Is.EqualTo (expectedRemoval), "Removal");
+ }
+
+ [TestCase (true, true, true)]
+ [TestCase (false, true, false)]
+ [TestCase (true, false, false)]
+ public void RequiredOptimizations (bool optimizeBlockLiteralSetupBlock, bool staticBlockToDelegateLookup, bool expectedRemoval)
+ {
+ using var preparer = CreatePreparer (ApplePlatform.iOS, false, preparer => {
+ preparer.Registrar = RegistrarMode.TrimmableStatic;
+ preparer.TrimExportAttributes = true;
+ preparer.Optimizations.RemoveDynamicRegistrar = true;
+ preparer.Optimizations.OptimizeBlockLiteralSetupBlock = optimizeBlockLiteralSetupBlock;
+ preparer.Optimizations.StaticBlockToDelegateLookup = staticBlockToDelegateLookup;
+ }, "public class C {}", out _);
+
+ var context = preparer.Configuration.DerivedLinkContext;
+ new LoadAssembliesStep ().Process (context);
+ new ComputeExportAttributeRemovalStep ().Process (context);
+
+ Assert.That (preparer.Configuration.Application.TrimExportAttributes, Is.EqualTo (expectedRemoval), "Removal");
+ }
+
+ [Test]
+ public void ExplicitBlocker ()
+ {
+ using var preparer = CreatePreparer (ApplePlatform.iOS, false, preparer => {
+ preparer.Registrar = RegistrarMode.TrimmableStatic;
+ preparer.TrimExportAttributes = true;
+ preparer.Optimizations.RemoveDynamicRegistrar = true;
+ preparer.Optimizations.OptimizeBlockLiteralSetupBlock = true;
+ preparer.Optimizations.StaticBlockToDelegateLookup = true;
+ }, "public class C {}", out _);
+
+ var context = preparer.Configuration.DerivedLinkContext;
+ new LoadAssembliesStep ().Process (context);
+ preparer.Configuration.Application.TrimExportAttributesBlockers.Add (ExportAttributeRemovalBlocker.RuntimeGetBlockWrapperCreatorRequired);
+ new ComputeExportAttributeRemovalStep ().Process (context);
+
+ Assert.That (preparer.Configuration.Application.TrimExportAttributes, Is.False, "Removal");
+ }
+
+ [Test]
+ public void NSXpcInterfaceMethodInfoOverload ()
+ {
+ var code = """
+ using System.Reflection;
+ using Foundation;
+ using ObjCRuntime;
+
+ public class C {
+ public void GetAllowedClasses (NSXpcInterface value, MethodInfo method)
+ {
+ value.GetAllowedClasses (method, 0, false);
+ }
+
+ public void SetAllowedClasses (NSXpcInterface value, MethodInfo method, NSSet classes)
+ {
+ value.SetAllowedClasses (method, classes, 0, false);
+ }
+ }
+ """;
+
+ using var preparer = CreatePreparer (ApplePlatform.iOS, false, preparer => {
+ preparer.Registrar = RegistrarMode.TrimmableStatic;
+ preparer.TrimExportAttributes = true;
+ preparer.Optimizations.RemoveDynamicRegistrar = true;
+ preparer.Optimizations.OptimizeBlockLiteralSetupBlock = true;
+ preparer.Optimizations.StaticBlockToDelegateLookup = true;
+ }, code, out _);
+
+ var context = preparer.Configuration.DerivedLinkContext;
+ new LoadAssembliesStep ().Process (context);
+ new DetectApiUsageStep ().Process (context);
+ new ComputeExportAttributeRemovalStep ().Process (context);
+
+ Assert.That (preparer.Configuration.Application.TrimExportAttributes, Is.False, "Removal");
+ Assert.That (preparer.Configuration.Application.TrimExportAttributesBlockers.Single (), Is.EqualTo (ExportAttributeRemovalBlocker.NSXpcInterfaceMethodInfoOverloadUsed), "Blocker");
+ }
+}
diff --git a/tests/common/DotNet.cs b/tests/common/DotNet.cs
index 8ee3922753c0..e292e0ef01dc 100644
--- a/tests/common/DotNet.cs
+++ b/tests/common/DotNet.cs
@@ -94,9 +94,9 @@ public static ExecutionResult AssertRun (string project, Dictionary? properties = null)
+ public static ExecutionResult AssertBuildFailure (string project, Dictionary? properties = null, string? target = null)
{
- var rv = Execute ("build", project, properties, false);
+ var rv = Execute ("build", project, properties, false, target: target);
Assert.That (rv.ExitCode, Is.Not.EqualTo (0), "Unexpected success");
return rv;
}
diff --git a/tests/dotnet/ExportAttributeRemovalApp/AppDelegate.cs b/tests/dotnet/ExportAttributeRemovalApp/AppDelegate.cs
new file mode 100644
index 000000000000..4926a096c764
--- /dev/null
+++ b/tests/dotnet/ExportAttributeRemovalApp/AppDelegate.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Reflection;
+
+using Foundation;
+using ObjCRuntime;
+
+namespace ExportAttributeRemovalApp {
+ [Register]
+ class ExportMetadataApplicationType : NSObject {
+ [Export ("applicationExport")]
+ public void ApplicationExport ()
+ {
+ }
+
+ [Action ("applicationAction:")]
+ public void ApplicationAction (NSObject sender)
+ {
+ }
+
+ [Outlet ("applicationOutlet")]
+ public NSObject? ApplicationOutlet { get; set; }
+
+ public override string Description => base.Description;
+ }
+
+ public class Program {
+#if EXPORT_ATTRIBUTE_REMOVAL_NSXPC
+ static void UseNSXpcInterfaceMethodInfoOverload (NSXpcInterface value, MethodInfo method)
+ {
+ value.GetAllowedClasses (method, 0, false);
+ }
+#endif
+
+ static int Main (string [] args)
+ {
+ GC.KeepAlive (typeof (NSObject));
+ GC.KeepAlive (typeof (INSUrlSessionDelegate));
+ GC.KeepAlive (typeof (ExportMetadataApplicationType));
+ Console.WriteLine (NSBundle.MainBundle.BundlePath);
+ Console.WriteLine (new ExportMetadataApplicationType ().Description);
+
+ return args.Length;
+ }
+ }
+}
diff --git a/tests/dotnet/ExportAttributeRemovalApp/iOS/ExportAttributeRemovalApp.csproj b/tests/dotnet/ExportAttributeRemovalApp/iOS/ExportAttributeRemovalApp.csproj
new file mode 100644
index 000000000000..86d408734aa8
--- /dev/null
+++ b/tests/dotnet/ExportAttributeRemovalApp/iOS/ExportAttributeRemovalApp.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-ios
+
+
+
diff --git a/tests/dotnet/ExportAttributeRemovalApp/shared.csproj b/tests/dotnet/ExportAttributeRemovalApp/shared.csproj
new file mode 100644
index 000000000000..ee28bc877c78
--- /dev/null
+++ b/tests/dotnet/ExportAttributeRemovalApp/shared.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+
+ ExportAttributeRemovalApp
+ com.xamarin.exportattributeremovalapp
+ $(DefineConstants);$(AdditionalDefineConstants)
+
+
+
+
+
+
+
+
diff --git a/tests/dotnet/UnitTests/DynamicRegistrationSupportedTest.cs b/tests/dotnet/UnitTests/DynamicRegistrationSupportedTest.cs
index 4c5c93c1b626..bc3b2e533d07 100644
--- a/tests/dotnet/UnitTests/DynamicRegistrationSupportedTest.cs
+++ b/tests/dotnet/UnitTests/DynamicRegistrationSupportedTest.cs
@@ -16,7 +16,7 @@ public void UserSpecifiedValue (ApplePlatform platform, string runtimeIdentifier
{
// When the user sets $(DynamicRegistrationSupported), the value must be passed straight through to
// the 'ObjCRuntime.Runtime.DynamicRegistrationSupported' trimmer feature switch (the assembly-preparer
- // doesn't need to compute it, so RegistrarRemovalTrackingStep is skipped).
+ // doesn't need to compute it, so DetectApiUsageStep is skipped).
var project = "MySimpleApp";
Configuration.IgnoreIfIgnoredPlatform (platform);
Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers);
@@ -58,7 +58,7 @@ public void UserSpecifiedValue (ApplePlatform platform, string runtimeIdentifier
public void SkippedWhenPlatformAssemblyNotTrimmed (ApplePlatform platform, string runtimeIdentifiers)
{
// When the platform assembly isn't being trimmed (link mode None), the dynamic registrar can't be
- // removed, so RegistrarRemovalTrackingStep is skipped and no DynamicRegistrationSupported feature
+ // removed, so DetectApiUsageStep is skipped and no DynamicRegistrationSupported feature
// switch is emitted (the dynamic registrar is kept, which is the default).
var project = "MySimpleApp";
Configuration.IgnoreIfIgnoredPlatform (platform);
diff --git a/tests/dotnet/UnitTests/PrepareAssembliesTest.cs b/tests/dotnet/UnitTests/PrepareAssembliesTest.cs
index 0a5bb4a3c04a..42bb161abe14 100644
--- a/tests/dotnet/UnitTests/PrepareAssembliesTest.cs
+++ b/tests/dotnet/UnitTests/PrepareAssembliesTest.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using Mono.Cecil;
+
#nullable enable
namespace Xamarin.Tests {
@@ -34,5 +36,125 @@ public void IncrementalBuild (ApplePlatform platform, string runtimeIdentifiers,
// The second (incremental) build, without any changes, must also succeed.
DotNet.AssertBuild (project_path, properties);
}
+
+ [TestCase (true, true, "trimmable-static", null, null, true)]
+ [TestCase (false, true, "trimmable-static", null, null, false)]
+ [TestCase (true, false, "trimmable-static", null, null, false)]
+ [TestCase (true, true, "managed-static", null, null, false)]
+ [TestCase (true, true, "trimmable-static", "false", null, false)]
+ [TestCase (true, true, "trimmable-static", null, "true", false)]
+ public void ExportAttributeRemovalEligibility (bool prepareAssemblies, bool postProcessAssemblies, string registrar, string? trimExportAttributes, string? dynamicRegistrationSupported, bool expectedRemoval)
+ {
+ var platform = ApplePlatform.iOS;
+ var runtimeIdentifiers = "iossimulator-arm64";
+ var project = "ExportAttributeRemovalApp";
+ var configuration = "Release";
+ Configuration.IgnoreIfIgnoredPlatform (platform);
+ Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers);
+
+ var projectPath = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out _, configuration: configuration);
+ Clean (projectPath);
+ var properties = GetDefaultProperties (runtimeIdentifiers);
+ properties ["Configuration"] = configuration;
+ properties ["EnableAssemblyILStripping"] = "true";
+ properties ["MtouchLink"] = registrar == "managed-static" ? "SdkOnly" : "Full";
+ properties ["PublishReadyToRun"] = "false";
+ properties ["PostProcessAssemblies"] = postProcessAssemblies.ToString ();
+ properties ["PrepareAssemblies"] = prepareAssemblies.ToString ();
+ properties ["Registrar"] = registrar;
+ if (trimExportAttributes is not null)
+ properties ["TrimExportAttributes"] = trimExportAttributes;
+ if (dynamicRegistrationSupported is not null)
+ properties ["DynamicRegistrationSupported"] = dynamicRegistrationSupported;
+
+ string platformAssemblyPath;
+ string appAssemblyPath;
+ string? target = null;
+ if (!prepareAssemblies) {
+ DotNet.AssertBuild (projectPath, properties, target: "Compile");
+ platformAssemblyPath = Configuration.GetBaseLibraryImplementations (platform).First ();
+ appAssemblyPath = Path.Combine (GetObjDir (projectPath, platform, runtimeIdentifiers, configuration), project + ".dll");
+ } else {
+ target = "Compile;_ComputePublishTrimmed;_ComputeLinkMode;_ComputeLinkerArguments;_PrepareAssemblies;_SetDynamicRegistrationSupportedFeature;_SetTrimExportAttributesFeature;_ComputeFrameworkFilesToPublish;_ComputeDynamicLibrariesToPublish;ComputeFilesToPublish;_ComputeStripAssemblyIL;_StripAssemblyIL";
+ var assemblyDirectory = Path.Combine (GetObjDir (projectPath, platform, runtimeIdentifiers, configuration), "stripped");
+ DotNet.AssertBuild (projectPath, properties, target: target);
+ platformAssemblyPath = Path.Combine (assemblyDirectory, Configuration.GetBaseLibraryName (platform));
+ appAssemblyPath = Path.Combine (assemblyDirectory, project + ".dll");
+ }
+
+ AssertExportMetadata (platformAssemblyPath, appAssemblyPath, !expectedRemoval);
+
+ if (expectedRemoval) {
+ properties ["DynamicRegistrationSupported"] = "true";
+ DotNet.AssertBuild (projectPath, properties, target: target);
+ AssertExportMetadata (platformAssemblyPath, appAssemblyPath, true);
+ }
+ }
+
+ static void AssertExportMetadata (string platformAssemblyPath, string appAssemblyPath, bool expected)
+ {
+ using var platformAssembly = AssemblyDefinition.ReadAssembly (platformAssemblyPath);
+ var bundlePath = platformAssembly.MainModule.GetType ("Foundation.NSBundle").Properties.Single (v => v.Name == "BundlePath");
+ AssertExport (bundlePath.GetMethod, expected, "direct-binding NSObject wrapper");
+
+ var nsObjectDescription = platformAssembly.MainModule.GetType ("Foundation.NSObject").Properties.Single (v => v.Name == "Description");
+ AssertExport (nsObjectDescription.GetMethod, expected, "wrapper ancestor with application subclasses");
+
+ using var appAssembly = AssemblyDefinition.ReadAssembly (appAssemblyPath);
+ var applicationType = appAssembly.MainModule.GetType ("ExportAttributeRemovalApp.ExportMetadataApplicationType");
+ AssertAttribute (applicationType.Methods.Single (v => v.Name == "ApplicationExport"), "ExportAttribute", expected, "application export");
+ AssertAttribute (applicationType.Methods.Single (v => v.Name == "ApplicationAction"), "ActionAttribute", expected, "application action");
+ AssertAttribute (applicationType.Properties.Single (v => v.Name == "ApplicationOutlet"), "OutletAttribute", expected, "application outlet");
+ }
+
+ [TestCase (false)]
+ [TestCase (true)]
+ public void ExportAttributeRemovalWithNSXpcInterfaceUsage (bool explicitlyEnabled)
+ {
+ var platform = ApplePlatform.iOS;
+ var runtimeIdentifiers = "iossimulator-arm64";
+ var project = "ExportAttributeRemovalApp";
+ var configuration = "Release";
+ Configuration.IgnoreIfIgnoredPlatform (platform);
+ Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers);
+
+ var projectPath = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out _, configuration: configuration);
+ Clean (projectPath);
+ var properties = GetDefaultProperties (runtimeIdentifiers);
+ properties ["AdditionalDefineConstants"] = "EXPORT_ATTRIBUTE_REMOVAL_NSXPC";
+ properties ["Configuration"] = configuration;
+ properties ["MtouchLink"] = "Full";
+ properties ["PostProcessAssemblies"] = "true";
+ properties ["PrepareAssemblies"] = "true";
+ properties ["Registrar"] = "trimmable-static";
+ properties ["DynamicRegistrationSupported"] = "false";
+ if (explicitlyEnabled)
+ properties ["TrimExportAttributes"] = "true";
+
+ var target = "Compile;_ComputePublishTrimmed;_ComputeLinkMode;_ComputeLinkerArguments;_PrepareAssemblies";
+ var expectedMessage = "Export attributes cannot be removed because the application uses an NSXpcInterface overload that obtains a selector from MethodInfo.";
+ if (explicitlyEnabled) {
+ for (var i = 0; i < 2; i++) {
+ var result = DotNet.AssertBuildFailure (projectPath, properties, target: target);
+ var errors = BinLog.GetBuildLogErrors (result.BinLogPath).ToArray ();
+ AssertErrorMessages (errors, expectedMessage);
+ }
+ } else {
+ var result = DotNet.AssertBuild (projectPath, properties, target: target);
+ var warnings = BinLog.GetBuildLogWarnings (result.BinLogPath).FilterWarnings (platform).ToArray ();
+ AssertWarningMessages (warnings, expectedMessage);
+ }
+ }
+
+ static void AssertExport (ICustomAttributeProvider provider, bool expected, string message)
+ {
+ AssertAttribute (provider, "ExportAttribute", expected, message);
+ }
+
+ static void AssertAttribute (ICustomAttributeProvider provider, string name, bool expected, string message)
+ {
+ var actual = provider.CustomAttributes.Any (v => v.AttributeType.Namespace == "Foundation" && v.AttributeType.Name == name);
+ Assert.That (actual, Is.EqualTo (expected), message);
+ }
}
}
diff --git a/tests/dotnet/UnitTests/ProjectTest.cs b/tests/dotnet/UnitTests/ProjectTest.cs
index 7db2614ce7e3..798b4e6746d8 100644
--- a/tests/dotnet/UnitTests/ProjectTest.cs
+++ b/tests/dotnet/UnitTests/ProjectTest.cs
@@ -2956,6 +2956,8 @@ public void PublishAotMonoTouchTest_NoIL2009 (ApplePlatform platform, string run
new ExpectedBuildMessage ($"MSBuild", $"It's not safe to remove the dynamic registrar, because monotouchtest references 'ObjCRuntime.Runtime.ConnectMethod (System.Type, System.Reflection.MethodInfo, Foundation.ExportAttribute)'."),
new ExpectedBuildMessage ($"MSBuild", $"It's not safe to remove the dynamic registrar, because monotouchtest references 'ObjCRuntime.Runtime.ConnectMethod (System.Type, System.Reflection.MethodInfo, ObjCRuntime.Selector)'."),
new ExpectedBuildMessage ($"MSBuild", $"It's not safe to remove the dynamic registrar, because monotouchtest references 'ObjCRuntime.Runtime.RegisterAssembly (System.Reflection.Assembly)'."),
+ new ExpectedBuildMessage ($"MSBuild", $"Export attributes cannot be removed because the managed registrar must use Runtime.GetBlockWrapperCreator."),
+ new ExpectedBuildMessage ($"MSBuild", $"Export attributes cannot be removed because the managed registrar must use RegistrarHelper.GetBlockForDelegate."),
new ExpectedBuildMessage ($"tests/bindings-test/RegistrarBindingTest.cs", $"Unable to locate the block to delegate conversion method for the method System.Void Xamarin.BindingTests.RegistrarBindingTest/FakePropertyBlock::set_MyOptionalProperty(Bindings.Test.SimpleCallback)'s parameter #1."),
new ExpectedBuildMessage ($"tests/bindings-test/RegistrarBindingTest.cs", $"Unable to locate the block to delegate conversion method for the method System.Void Xamarin.BindingTests.RegistrarBindingTest/FakePropertyBlock::set_MyOptionalStaticProperty(Bindings.Test.SimpleCallback)'s parameter #1."),
new ExpectedBuildMessage ($"tests/bindings-test/RegistrarBindingTest.cs", $"Unable to locate the block to delegate conversion method for the method System.Void Xamarin.BindingTests.RegistrarBindingTest/FakePropertyBlock::set_MyRequiredProperty(Bindings.Test.SimpleCallback)'s parameter #1."),
diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-CoreCLR-Interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-CoreCLR-Interpreter-preservedapis.txt
index 38bd0035a6b4..3f7565cf4043 100644
--- a/tests/dotnet/UnitTests/expected/MacCatalyst-CoreCLR-Interpreter-preservedapis.txt
+++ b/tests/dotnet/UnitTests/expected/MacCatalyst-CoreCLR-Interpreter-preservedapis.txt
@@ -183,9 +183,6 @@ Microsoft.MacCatalyst.dll:CoreGraphics.CGRect.Equals(System.Object)
Microsoft.MacCatalyst.dll:CoreGraphics.CGRect.GetHashCode()
Microsoft.MacCatalyst.dll:CoreGraphics.CGRect.NSStringFromCGRect(CoreGraphics.CGRect)
Microsoft.MacCatalyst.dll:CoreGraphics.CGRect.ToString()
-Microsoft.MacCatalyst.dll:Foundation.ExportAttribute
-Microsoft.MacCatalyst.dll:Foundation.ExportAttribute..ctor(System.String, ObjCRuntime.ArgumentSemantic)
-Microsoft.MacCatalyst.dll:Foundation.ExportAttribute..ctor(System.String)
Microsoft.MacCatalyst.dll:Foundation.INSObjectFactory
Microsoft.MacCatalyst.dll:Foundation.INSObjectFactory._Xamarin_ConstructNSObject(ObjCRuntime.NativeHandle)
Microsoft.MacCatalyst.dll:Foundation.ModelAttribute
@@ -403,15 +400,6 @@ Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_IsWrapper()
Microsoft.MacCatalyst.dll:Foundation.TrackedMemory
Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method
Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor()
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic Foundation.ExportAttribute::semantic
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Assign
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Copy
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::None
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Retain
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Strong
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::UnsafeUnretained
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Weak
Microsoft.MacCatalyst.dll:ObjCRuntime.BlockCollector
Microsoft.MacCatalyst.dll:ObjCRuntime.BlockCollector..ctor(System.IntPtr)
Microsoft.MacCatalyst.dll:ObjCRuntime.BlockCollector.Add(System.IntPtr)
@@ -1099,7 +1087,6 @@ Microsoft.MacCatalyst.dll:System.Int32 Foundation.NSDictionary::System.Collectio
Microsoft.MacCatalyst.dll:System.Int32 Foundation.NSDictionary/d__66::<>1__state
Microsoft.MacCatalyst.dll:System.Int32 Foundation.NSDictionary/d__66::<>7__wrap2
Microsoft.MacCatalyst.dll:System.Int32 Foundation.NSObjectFlag::value__
-Microsoft.MacCatalyst.dll:System.Int32 ObjCRuntime.ArgumentSemantic::value__
Microsoft.MacCatalyst.dll:System.Int32 ObjCRuntime.BlockCollector::count
Microsoft.MacCatalyst.dll:System.Int32 ObjCRuntime.Dlfcn/Mode::value__
Microsoft.MacCatalyst.dll:System.Int32 ObjCRuntime.MarshalManagedExceptionMode::value__
@@ -1282,7 +1269,6 @@ Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGR
Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::y
Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.ObjectiveC.ObjectiveCMarshal/UnhandledExceptionPropagationHandler ObjCRuntime.Runtime/<>O::<0>__UnhandledExceptionPropagationHandler
Microsoft.MacCatalyst.dll:System.String CoreFoundation.CFString::str
-Microsoft.MacCatalyst.dll:System.String Foundation.ExportAttribute::selector
Microsoft.MacCatalyst.dll:System.String Foundation.NSException::Name()
Microsoft.MacCatalyst.dll:System.String Foundation.NSException::Reason()
Microsoft.MacCatalyst.dll:System.String Foundation.NSNumber::StringValue()
diff --git a/tests/dotnet/UnitTests/expected/MacCatalyst-CoreCLR-R2R-preservedapis.txt b/tests/dotnet/UnitTests/expected/MacCatalyst-CoreCLR-R2R-preservedapis.txt
index 38bd0035a6b4..3f7565cf4043 100644
--- a/tests/dotnet/UnitTests/expected/MacCatalyst-CoreCLR-R2R-preservedapis.txt
+++ b/tests/dotnet/UnitTests/expected/MacCatalyst-CoreCLR-R2R-preservedapis.txt
@@ -183,9 +183,6 @@ Microsoft.MacCatalyst.dll:CoreGraphics.CGRect.Equals(System.Object)
Microsoft.MacCatalyst.dll:CoreGraphics.CGRect.GetHashCode()
Microsoft.MacCatalyst.dll:CoreGraphics.CGRect.NSStringFromCGRect(CoreGraphics.CGRect)
Microsoft.MacCatalyst.dll:CoreGraphics.CGRect.ToString()
-Microsoft.MacCatalyst.dll:Foundation.ExportAttribute
-Microsoft.MacCatalyst.dll:Foundation.ExportAttribute..ctor(System.String, ObjCRuntime.ArgumentSemantic)
-Microsoft.MacCatalyst.dll:Foundation.ExportAttribute..ctor(System.String)
Microsoft.MacCatalyst.dll:Foundation.INSObjectFactory
Microsoft.MacCatalyst.dll:Foundation.INSObjectFactory._Xamarin_ConstructNSObject(ObjCRuntime.NativeHandle)
Microsoft.MacCatalyst.dll:Foundation.ModelAttribute
@@ -403,15 +400,6 @@ Microsoft.MacCatalyst.dll:Foundation.RegisterAttribute.get_IsWrapper()
Microsoft.MacCatalyst.dll:Foundation.TrackedMemory
Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method
Microsoft.MacCatalyst.dll:Foundation.You_Should_Not_Call_base_In_This_Method..ctor()
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic Foundation.ExportAttribute::semantic
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Assign
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Copy
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::None
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Retain
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Strong
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::UnsafeUnretained
-Microsoft.MacCatalyst.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Weak
Microsoft.MacCatalyst.dll:ObjCRuntime.BlockCollector
Microsoft.MacCatalyst.dll:ObjCRuntime.BlockCollector..ctor(System.IntPtr)
Microsoft.MacCatalyst.dll:ObjCRuntime.BlockCollector.Add(System.IntPtr)
@@ -1099,7 +1087,6 @@ Microsoft.MacCatalyst.dll:System.Int32 Foundation.NSDictionary::System.Collectio
Microsoft.MacCatalyst.dll:System.Int32 Foundation.NSDictionary/d__66::<>1__state
Microsoft.MacCatalyst.dll:System.Int32 Foundation.NSDictionary/d__66::<>7__wrap2
Microsoft.MacCatalyst.dll:System.Int32 Foundation.NSObjectFlag::value__
-Microsoft.MacCatalyst.dll:System.Int32 ObjCRuntime.ArgumentSemantic::value__
Microsoft.MacCatalyst.dll:System.Int32 ObjCRuntime.BlockCollector::count
Microsoft.MacCatalyst.dll:System.Int32 ObjCRuntime.Dlfcn/Mode::value__
Microsoft.MacCatalyst.dll:System.Int32 ObjCRuntime.MarshalManagedExceptionMode::value__
@@ -1282,7 +1269,6 @@ Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGR
Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::y
Microsoft.MacCatalyst.dll:System.Runtime.InteropServices.ObjectiveC.ObjectiveCMarshal/UnhandledExceptionPropagationHandler ObjCRuntime.Runtime/<>O::<0>__UnhandledExceptionPropagationHandler
Microsoft.MacCatalyst.dll:System.String CoreFoundation.CFString::str
-Microsoft.MacCatalyst.dll:System.String Foundation.ExportAttribute::selector
Microsoft.MacCatalyst.dll:System.String Foundation.NSException::Name()
Microsoft.MacCatalyst.dll:System.String Foundation.NSException::Reason()
Microsoft.MacCatalyst.dll:System.String Foundation.NSNumber::StringValue()
diff --git a/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-R2R-size.txt b/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-R2R-size.txt
index 3e88d0271157..e25f6a8d50d0 100644
--- a/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-R2R-size.txt
+++ b/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-R2R-size.txt
@@ -1,9 +1,9 @@
-AppBundleSize: 329,710,665 bytes (321,983.1 KB = 314.4 MB)
+AppBundleSize: 329,715,517 bytes (321,987.8 KB = 314.4 MB)
# The following list of files and their sizes is just informational / for review, and isn't used in the test:
Contents/Info.plist:
- 745 bytes (0.7 KB = 0.0 MB)
+ 749 bytes (0.7 KB = 0.0 MB)
Contents/MacOS/SizeTestApp:
- 7,351,240 bytes (7,178.9 KB = 7.0 MB)
+ 7,351,480 bytes (7,179.2 KB = 7.0 MB)
Contents/MonoBundle/_Microsoft.macOS.TypeMaps.dll:
2,560 bytes (2.5 KB = 0.0 MB)
Contents/MonoBundle/.xamarin/osx-arm64/_Microsoft.macOS.TypeMap.dll:
@@ -31,7 +31,7 @@ Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Options.dll:
Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Extensions.Primitives.dll:
90,408 bytes (88.3 KB = 0.1 MB)
Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.macOS.dll:
- 73,306,112 bytes (71,588.0 KB = 69.9 MB)
+ 73,308,672 bytes (71,590.5 KB = 69.9 MB)
Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.Core.dll:
1,337,128 bytes (1,305.8 KB = 1.3 MB)
Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.dll:
@@ -401,7 +401,7 @@ Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Options.dll:
Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Extensions.Primitives.dll:
83,240 bytes (81.3 KB = 0.1 MB)
Contents/MonoBundle/.xamarin/osx-x64/Microsoft.macOS.dll:
- 62,666,752 bytes (61,198.0 KB = 59.8 MB)
+ 62,668,800 bytes (61,200.0 KB = 59.8 MB)
Contents/MonoBundle/.xamarin/osx-x64/Microsoft.VisualBasic.Core.dll:
1,191,720 bytes (1,163.8 KB = 1.1 MB)
Contents/MonoBundle/.xamarin/osx-x64/Microsoft.VisualBasic.dll:
diff --git a/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt b/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt
index dba976dc39fe..55dfcf5120cb 100644
--- a/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt
+++ b/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt
@@ -1,8 +1,8 @@
-AppBundleSize: 4,599,936 bytes (4,492.1 KB = 4.4 MB)
+AppBundleSize: 4,599,917 bytes (4,492.1 KB = 4.4 MB)
# The following list of files and their sizes is just informational / for review, and isn't used in the test:
Contents/Info.plist:
- 752 bytes (0.7 KB = 0.0 MB)
+ 749 bytes (0.7 KB = 0.0 MB)
Contents/MacOS/SizeTestApp:
- 4,599,176 bytes (4,491.4 KB = 4.4 MB)
+ 4,599,160 bytes (4,491.4 KB = 4.4 MB)
Contents/PkgInfo:
8 bytes (0.0 KB = 0.0 MB)
diff --git a/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-size.txt b/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-size.txt
index dba976dc39fe..55dfcf5120cb 100644
--- a/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-size.txt
+++ b/tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-size.txt
@@ -1,8 +1,8 @@
-AppBundleSize: 4,599,936 bytes (4,492.1 KB = 4.4 MB)
+AppBundleSize: 4,599,917 bytes (4,492.1 KB = 4.4 MB)
# The following list of files and their sizes is just informational / for review, and isn't used in the test:
Contents/Info.plist:
- 752 bytes (0.7 KB = 0.0 MB)
+ 749 bytes (0.7 KB = 0.0 MB)
Contents/MacOS/SizeTestApp:
- 4,599,176 bytes (4,491.4 KB = 4.4 MB)
+ 4,599,160 bytes (4,491.4 KB = 4.4 MB)
Contents/PkgInfo:
8 bytes (0.0 KB = 0.0 MB)
diff --git a/tests/dotnet/UnitTests/expected/TVOS-CoreCLR-Interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/TVOS-CoreCLR-Interpreter-preservedapis.txt
index 84eb345629fb..06c01435b0cf 100644
--- a/tests/dotnet/UnitTests/expected/TVOS-CoreCLR-Interpreter-preservedapis.txt
+++ b/tests/dotnet/UnitTests/expected/TVOS-CoreCLR-Interpreter-preservedapis.txt
@@ -167,9 +167,6 @@ Microsoft.tvOS.dll:CoreGraphics.CGRect.Equals(System.Object)
Microsoft.tvOS.dll:CoreGraphics.CGRect.GetHashCode()
Microsoft.tvOS.dll:CoreGraphics.CGRect.NSStringFromCGRect(CoreGraphics.CGRect)
Microsoft.tvOS.dll:CoreGraphics.CGRect.ToString()
-Microsoft.tvOS.dll:Foundation.ExportAttribute
-Microsoft.tvOS.dll:Foundation.ExportAttribute..ctor(System.String, ObjCRuntime.ArgumentSemantic)
-Microsoft.tvOS.dll:Foundation.ExportAttribute..ctor(System.String)
Microsoft.tvOS.dll:Foundation.INSObjectFactory
Microsoft.tvOS.dll:Foundation.INSObjectFactory._Xamarin_ConstructNSObject(ObjCRuntime.NativeHandle)
Microsoft.tvOS.dll:Foundation.ModelAttribute
@@ -391,15 +388,6 @@ Microsoft.tvOS.dll:ObjCRuntime.Arch
Microsoft.tvOS.dll:ObjCRuntime.Arch ObjCRuntime.Arch::DEVICE
Microsoft.tvOS.dll:ObjCRuntime.Arch ObjCRuntime.Arch::SIMULATOR
Microsoft.tvOS.dll:ObjCRuntime.Arch ObjCRuntime.Runtime::Arch
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic Foundation.ExportAttribute::semantic
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Assign
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Copy
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::None
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Retain
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Strong
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::UnsafeUnretained
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Weak
Microsoft.tvOS.dll:ObjCRuntime.BlockCollector
Microsoft.tvOS.dll:ObjCRuntime.BlockCollector..ctor(System.IntPtr)
Microsoft.tvOS.dll:ObjCRuntime.BlockCollector.Add(System.IntPtr)
@@ -1084,7 +1072,6 @@ Microsoft.tvOS.dll:System.Int32 Foundation.NSDictionary/d__66::<>
Microsoft.tvOS.dll:System.Int32 Foundation.NSDictionary/d__66::<>7__wrap2
Microsoft.tvOS.dll:System.Int32 Foundation.NSObjectFlag::value__
Microsoft.tvOS.dll:System.Int32 ObjCRuntime.Arch::value__
-Microsoft.tvOS.dll:System.Int32 ObjCRuntime.ArgumentSemantic::value__
Microsoft.tvOS.dll:System.Int32 ObjCRuntime.BlockCollector::count
Microsoft.tvOS.dll:System.Int32 ObjCRuntime.Dlfcn/Mode::value__
Microsoft.tvOS.dll:System.Int32 ObjCRuntime.MarshalManagedExceptionMode::value__
@@ -1265,7 +1252,6 @@ Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x
Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::y
Microsoft.tvOS.dll:System.Runtime.InteropServices.ObjectiveC.ObjectiveCMarshal/UnhandledExceptionPropagationHandler ObjCRuntime.Runtime/<>O::<0>__UnhandledExceptionPropagationHandler
Microsoft.tvOS.dll:System.String CoreFoundation.CFString::str
-Microsoft.tvOS.dll:System.String Foundation.ExportAttribute::selector
Microsoft.tvOS.dll:System.String Foundation.NSException::Name()
Microsoft.tvOS.dll:System.String Foundation.NSException::Reason()
Microsoft.tvOS.dll:System.String Foundation.NSNumber::StringValue()
diff --git a/tests/dotnet/UnitTests/expected/TVOS-CoreCLR-R2R-preservedapis.txt b/tests/dotnet/UnitTests/expected/TVOS-CoreCLR-R2R-preservedapis.txt
index 84eb345629fb..06c01435b0cf 100644
--- a/tests/dotnet/UnitTests/expected/TVOS-CoreCLR-R2R-preservedapis.txt
+++ b/tests/dotnet/UnitTests/expected/TVOS-CoreCLR-R2R-preservedapis.txt
@@ -167,9 +167,6 @@ Microsoft.tvOS.dll:CoreGraphics.CGRect.Equals(System.Object)
Microsoft.tvOS.dll:CoreGraphics.CGRect.GetHashCode()
Microsoft.tvOS.dll:CoreGraphics.CGRect.NSStringFromCGRect(CoreGraphics.CGRect)
Microsoft.tvOS.dll:CoreGraphics.CGRect.ToString()
-Microsoft.tvOS.dll:Foundation.ExportAttribute
-Microsoft.tvOS.dll:Foundation.ExportAttribute..ctor(System.String, ObjCRuntime.ArgumentSemantic)
-Microsoft.tvOS.dll:Foundation.ExportAttribute..ctor(System.String)
Microsoft.tvOS.dll:Foundation.INSObjectFactory
Microsoft.tvOS.dll:Foundation.INSObjectFactory._Xamarin_ConstructNSObject(ObjCRuntime.NativeHandle)
Microsoft.tvOS.dll:Foundation.ModelAttribute
@@ -391,15 +388,6 @@ Microsoft.tvOS.dll:ObjCRuntime.Arch
Microsoft.tvOS.dll:ObjCRuntime.Arch ObjCRuntime.Arch::DEVICE
Microsoft.tvOS.dll:ObjCRuntime.Arch ObjCRuntime.Arch::SIMULATOR
Microsoft.tvOS.dll:ObjCRuntime.Arch ObjCRuntime.Runtime::Arch
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic Foundation.ExportAttribute::semantic
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Assign
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Copy
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::None
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Retain
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Strong
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::UnsafeUnretained
-Microsoft.tvOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Weak
Microsoft.tvOS.dll:ObjCRuntime.BlockCollector
Microsoft.tvOS.dll:ObjCRuntime.BlockCollector..ctor(System.IntPtr)
Microsoft.tvOS.dll:ObjCRuntime.BlockCollector.Add(System.IntPtr)
@@ -1084,7 +1072,6 @@ Microsoft.tvOS.dll:System.Int32 Foundation.NSDictionary/d__66::<>
Microsoft.tvOS.dll:System.Int32 Foundation.NSDictionary/d__66::<>7__wrap2
Microsoft.tvOS.dll:System.Int32 Foundation.NSObjectFlag::value__
Microsoft.tvOS.dll:System.Int32 ObjCRuntime.Arch::value__
-Microsoft.tvOS.dll:System.Int32 ObjCRuntime.ArgumentSemantic::value__
Microsoft.tvOS.dll:System.Int32 ObjCRuntime.BlockCollector::count
Microsoft.tvOS.dll:System.Int32 ObjCRuntime.Dlfcn/Mode::value__
Microsoft.tvOS.dll:System.Int32 ObjCRuntime.MarshalManagedExceptionMode::value__
@@ -1265,7 +1252,6 @@ Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x
Microsoft.tvOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::y
Microsoft.tvOS.dll:System.Runtime.InteropServices.ObjectiveC.ObjectiveCMarshal/UnhandledExceptionPropagationHandler ObjCRuntime.Runtime/<>O::<0>__UnhandledExceptionPropagationHandler
Microsoft.tvOS.dll:System.String CoreFoundation.CFString::str
-Microsoft.tvOS.dll:System.String Foundation.ExportAttribute::selector
Microsoft.tvOS.dll:System.String Foundation.NSException::Name()
Microsoft.tvOS.dll:System.String Foundation.NSException::Reason()
Microsoft.tvOS.dll:System.String Foundation.NSNumber::StringValue()
diff --git a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-Interpreter-preservedapis.txt b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-Interpreter-preservedapis.txt
index c9d5794c3068..51bafb9b050c 100644
--- a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-Interpreter-preservedapis.txt
+++ b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-Interpreter-preservedapis.txt
@@ -167,9 +167,6 @@ Microsoft.iOS.dll:CoreGraphics.CGRect.Equals(System.Object)
Microsoft.iOS.dll:CoreGraphics.CGRect.GetHashCode()
Microsoft.iOS.dll:CoreGraphics.CGRect.NSStringFromCGRect(CoreGraphics.CGRect)
Microsoft.iOS.dll:CoreGraphics.CGRect.ToString()
-Microsoft.iOS.dll:Foundation.ExportAttribute
-Microsoft.iOS.dll:Foundation.ExportAttribute..ctor(System.String, ObjCRuntime.ArgumentSemantic)
-Microsoft.iOS.dll:Foundation.ExportAttribute..ctor(System.String)
Microsoft.iOS.dll:Foundation.INSObjectFactory
Microsoft.iOS.dll:Foundation.INSObjectFactory._Xamarin_ConstructNSObject(ObjCRuntime.NativeHandle)
Microsoft.iOS.dll:Foundation.ModelAttribute
@@ -391,15 +388,6 @@ Microsoft.iOS.dll:ObjCRuntime.Arch
Microsoft.iOS.dll:ObjCRuntime.Arch ObjCRuntime.Arch::DEVICE
Microsoft.iOS.dll:ObjCRuntime.Arch ObjCRuntime.Arch::SIMULATOR
Microsoft.iOS.dll:ObjCRuntime.Arch ObjCRuntime.Runtime::Arch
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic Foundation.ExportAttribute::semantic
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Assign
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Copy
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::None
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Retain
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Strong
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::UnsafeUnretained
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Weak
Microsoft.iOS.dll:ObjCRuntime.BlockCollector
Microsoft.iOS.dll:ObjCRuntime.BlockCollector..ctor(System.IntPtr)
Microsoft.iOS.dll:ObjCRuntime.BlockCollector.Add(System.IntPtr)
@@ -1084,7 +1072,6 @@ Microsoft.iOS.dll:System.Int32 Foundation.NSDictionary/d__66::<>1
Microsoft.iOS.dll:System.Int32 Foundation.NSDictionary/d__66::<>7__wrap2
Microsoft.iOS.dll:System.Int32 Foundation.NSObjectFlag::value__
Microsoft.iOS.dll:System.Int32 ObjCRuntime.Arch::value__
-Microsoft.iOS.dll:System.Int32 ObjCRuntime.ArgumentSemantic::value__
Microsoft.iOS.dll:System.Int32 ObjCRuntime.BlockCollector::count
Microsoft.iOS.dll:System.Int32 ObjCRuntime.Dlfcn/Mode::value__
Microsoft.iOS.dll:System.Int32 ObjCRuntime.MarshalManagedExceptionMode::value__
@@ -1265,7 +1252,6 @@ Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x
Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::y
Microsoft.iOS.dll:System.Runtime.InteropServices.ObjectiveC.ObjectiveCMarshal/UnhandledExceptionPropagationHandler ObjCRuntime.Runtime/<>O::<0>__UnhandledExceptionPropagationHandler
Microsoft.iOS.dll:System.String CoreFoundation.CFString::str
-Microsoft.iOS.dll:System.String Foundation.ExportAttribute::selector
Microsoft.iOS.dll:System.String Foundation.NSException::Name()
Microsoft.iOS.dll:System.String Foundation.NSException::Reason()
Microsoft.iOS.dll:System.String Foundation.NSNumber::StringValue()
diff --git a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-preservedapis.txt b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-preservedapis.txt
index c9d5794c3068..51bafb9b050c 100644
--- a/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-preservedapis.txt
+++ b/tests/dotnet/UnitTests/expected/iOS-CoreCLR-R2R-preservedapis.txt
@@ -167,9 +167,6 @@ Microsoft.iOS.dll:CoreGraphics.CGRect.Equals(System.Object)
Microsoft.iOS.dll:CoreGraphics.CGRect.GetHashCode()
Microsoft.iOS.dll:CoreGraphics.CGRect.NSStringFromCGRect(CoreGraphics.CGRect)
Microsoft.iOS.dll:CoreGraphics.CGRect.ToString()
-Microsoft.iOS.dll:Foundation.ExportAttribute
-Microsoft.iOS.dll:Foundation.ExportAttribute..ctor(System.String, ObjCRuntime.ArgumentSemantic)
-Microsoft.iOS.dll:Foundation.ExportAttribute..ctor(System.String)
Microsoft.iOS.dll:Foundation.INSObjectFactory
Microsoft.iOS.dll:Foundation.INSObjectFactory._Xamarin_ConstructNSObject(ObjCRuntime.NativeHandle)
Microsoft.iOS.dll:Foundation.ModelAttribute
@@ -391,15 +388,6 @@ Microsoft.iOS.dll:ObjCRuntime.Arch
Microsoft.iOS.dll:ObjCRuntime.Arch ObjCRuntime.Arch::DEVICE
Microsoft.iOS.dll:ObjCRuntime.Arch ObjCRuntime.Arch::SIMULATOR
Microsoft.iOS.dll:ObjCRuntime.Arch ObjCRuntime.Runtime::Arch
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic Foundation.ExportAttribute::semantic
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Assign
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Copy
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::None
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Retain
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Strong
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::UnsafeUnretained
-Microsoft.iOS.dll:ObjCRuntime.ArgumentSemantic ObjCRuntime.ArgumentSemantic::Weak
Microsoft.iOS.dll:ObjCRuntime.BlockCollector
Microsoft.iOS.dll:ObjCRuntime.BlockCollector..ctor(System.IntPtr)
Microsoft.iOS.dll:ObjCRuntime.BlockCollector.Add(System.IntPtr)
@@ -1084,7 +1072,6 @@ Microsoft.iOS.dll:System.Int32 Foundation.NSDictionary/d__66::<>1
Microsoft.iOS.dll:System.Int32 Foundation.NSDictionary/d__66::<>7__wrap2
Microsoft.iOS.dll:System.Int32 Foundation.NSObjectFlag::value__
Microsoft.iOS.dll:System.Int32 ObjCRuntime.Arch::value__
-Microsoft.iOS.dll:System.Int32 ObjCRuntime.ArgumentSemantic::value__
Microsoft.iOS.dll:System.Int32 ObjCRuntime.BlockCollector::count
Microsoft.iOS.dll:System.Int32 ObjCRuntime.Dlfcn/Mode::value__
Microsoft.iOS.dll:System.Int32 ObjCRuntime.MarshalManagedExceptionMode::value__
@@ -1265,7 +1252,6 @@ Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::x
Microsoft.iOS.dll:System.Runtime.InteropServices.NFloat CoreGraphics.CGRect::y
Microsoft.iOS.dll:System.Runtime.InteropServices.ObjectiveC.ObjectiveCMarshal/UnhandledExceptionPropagationHandler ObjCRuntime.Runtime/<>O::<0>__UnhandledExceptionPropagationHandler
Microsoft.iOS.dll:System.String CoreFoundation.CFString::str
-Microsoft.iOS.dll:System.String Foundation.ExportAttribute::selector
Microsoft.iOS.dll:System.String Foundation.NSException::Name()
Microsoft.iOS.dll:System.String Foundation.NSException::Reason()
Microsoft.iOS.dll:System.String Foundation.NSNumber::StringValue()
diff --git a/tools/assembly-preparer/AssemblyPreparer.cs b/tools/assembly-preparer/AssemblyPreparer.cs
index 2de85e5e11db..4cbc8b1f911e 100644
--- a/tools/assembly-preparer/AssemblyPreparer.cs
+++ b/tools/assembly-preparer/AssemblyPreparer.cs
@@ -30,12 +30,16 @@ public class AssemblyPreparer : IDisposable {
public string MakeReproPath { get; set; } = "";
- // The pre-trim (untrimmed) assemblies. Used during post-processing with the trimmable static
- // registrar to read [ProtocolMember] attributes that the trimmer has removed. This is the complete
- // set of assemblies that were fed into the trimmer (ILLink's input), so it forms a self-contained
- // metadata universe separate from the post-trim assemblies.
+ // The original assemblies from before preparation and trimming. Used during post-processing with the
+ // trimmable static registrar to read selected registrar attributes that were removed during trimming.
+ // This is a complete metadata universe separate from the post-trim assemblies.
public List PreTrimAssemblies { get; } = new List ();
+ public bool? TrimExportAttributes {
+ get => configuration.Application.TrimExportAttributes;
+ set => configuration.Application.TrimExportAttributes = value;
+ }
+
public RegistrarMode Registrar {
get => configuration.Application.Registrar;
set => configuration.Application.Registrar = value;
@@ -161,10 +165,10 @@ public bool Prepare (out List exceptions)
var steps = new List {
// CollectAssembliesStep
new LoadAssembliesStep (),
- new ComputeMethodOverridesStep (),
- new CoreTypeMapStep (),
- new CollectFieldsStep (), // ProcessExportedFields
};
+ steps.Add (new ComputeMethodOverridesStep ());
+ steps.Add (new CoreTypeMapStep ());
+ steps.Add (new CollectFieldsStep ()); // ProcessExportedFields
// These steps only do anything for assemblies that are being trimmed (their IsActiveFor requires
// AssemblyAction.Link), so don't even add them to the list when nothing's being trimmed.
@@ -180,16 +184,17 @@ public bool Prepare (out List exceptions)
steps.Add (new InlineDlfcnMethodsStep ());
- // Only add RegistrarRemovalTrackingStep if it's needed:
- // * If the user explicitly set $(DynamicRegistrationSupported), we don't need to compute the value (it's
- // passed straight through to the trimmer feature switch).
+ // Only add DetectApiUsageStep if it's needed:
+ // * If the user explicitly set $(DynamicRegistrationSupported), we don't need to compute the value, but
+ // Export attribute removal still needs the step to detect NSXpcInterface reflection.
// * If nothing is being trimmed, the dynamic registrar (which lives in the platform assembly, an SDK
// assembly that's only trimmed when trimming is enabled) can't be removed, so there's nothing to compute.
- if (!configuration.DynamicRegistrationSupported.HasValue && configuration.Application.AreAnyAssembliesTrimmed)
- steps.Add (new RegistrarRemovalTrackingStep ());
+ if (configuration.Application.AreAnyAssembliesTrimmed && (!configuration.DynamicRegistrationSupported.HasValue || configuration.Application.TrimExportAttributes != false))
+ steps.Add (new DetectApiUsageStep ());
// PreMarkDispatcher: I don't think we need this one
steps.Add (new ManagedRegistrarStep ());
+ steps.Add (new ComputeExportAttributeRemovalStep ());
steps.Add (new TrimmableRegistrarStep ());
steps.Add (new ManagedRegistrarLookupTablesStep ());
steps.Add (new InlineClassGetHandleStep ());
@@ -198,12 +203,11 @@ public bool Prepare (out List exceptions)
return RunSteps (steps, out exceptions);
}
- // Load the pre-trim (untrimmed) assemblies so the trimmable static registrar can read the
- // [ProtocolMember] attributes the trimmer removed from the post-trim assemblies. The pre-trim
- // assemblies are loaded into their own resolver (a separate, self-contained metadata universe from
- // the post-trim assemblies), and stored on the Application for the registrar to consult. There's no
- // fallback to the post-trim resolver: the pre-trim set is complete (it's the trimmer's input), and
- // falling back would mix the two universes and resolve trimmed-away references incorrectly.
+ // Load the original assemblies so the trimmable static registrar can read selected attributes removed
+ // during trimming. The assemblies are loaded into their own resolver (a separate, self-contained
+ // metadata universe from the post-trim assemblies), and stored on the Application for the registrar to
+ // consult. There's no fallback to the post-trim resolver: the original set is complete, and falling back
+ // would mix the two universes and resolve trimmed-away references incorrectly.
void LoadPreTrimAssemblies ()
{
if (PreTrimAssemblies.Count == 0)
@@ -297,6 +301,13 @@ bool RunSteps (IList steps, out List e
exceptions.Add (ErrorHelper.CreateError (99, "RegistrarMode must be explicitly set."));
return false;
}
+ if (Registrar != RegistrarMode.TrimmableStatic) {
+ if (TrimExportAttributes == true) {
+ exceptions.Add (ErrorHelper.CreateError (99, "Export attributes can only be trimmed with the trimmable static registrar."));
+ return false;
+ }
+ TrimExportAttributes = false;
+ }
if (!string.IsNullOrEmpty (MakeReproPath) && !SaveToReproPath (exceptions))
return false;
diff --git a/tools/assembly-preparer/ComputeExportAttributeRemovalStep.cs b/tools/assembly-preparer/ComputeExportAttributeRemovalStep.cs
new file mode 100644
index 000000000000..5ead9636a435
--- /dev/null
+++ b/tools/assembly-preparer/ComputeExportAttributeRemovalStep.cs
@@ -0,0 +1,67 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Linq;
+
+using Xamarin.Bundler;
+using Xamarin.Linker;
+
+#nullable enable
+
+namespace Xamarin.Linker;
+
+public class ComputeExportAttributeRemovalStep : ConfigurationAwareStep {
+ protected override string Name { get; } = "ComputeExportAttributeRemoval";
+ protected override int ErrorCode { get; } = 2530;
+
+ protected override void TryProcess ()
+ {
+ if (App.TrimExportAttributes == false) {
+ Configuration.SetOutputForMSBuild ("TrimExportAttributes", "false");
+ return;
+ }
+
+ var explicitlyEnabled = App.TrimExportAttributes == true;
+ if (App.DynamicRegistrationSupported) {
+ App.TrimExportAttributes = false;
+ Configuration.SetOutputForMSBuild ("TrimExportAttributes", "false");
+ if (explicitlyEnabled) {
+ var (code, message) = GetDiagnostic (ExportAttributeRemovalBlocker.DynamicRegistrationSupported);
+ Report (ErrorHelper.CreateError (code, message));
+ }
+ return;
+ }
+ if (App.Optimizations.OptimizeBlockLiteralSetupBlock != true)
+ App.TrimExportAttributesBlockers.Add (ExportAttributeRemovalBlocker.BlockLiteralSetupBlockOptimizationDisabled);
+ if (App.Optimizations.StaticBlockToDelegateLookup != true)
+ App.TrimExportAttributesBlockers.Add (ExportAttributeRemovalBlocker.StaticBlockToDelegateLookupOptimizationDisabled);
+
+ var trimExportAttributes = App.TrimExportAttributesBlockers.Count == 0;
+ App.TrimExportAttributes = trimExportAttributes;
+ Configuration.SetOutputForMSBuild ("TrimExportAttributes", trimExportAttributes ? "true" : "false");
+
+ if (trimExportAttributes)
+ return;
+
+ foreach (var blocker in App.TrimExportAttributesBlockers.OrderBy (v => v)) {
+ var (code, message) = GetDiagnostic (blocker);
+ var exception = explicitlyEnabled
+ ? ErrorHelper.CreateError (code, message)
+ : ErrorHelper.CreateWarning (code, message);
+ Report (exception);
+ }
+ }
+
+ static (int Code, string Message) GetDiagnostic (ExportAttributeRemovalBlocker blocker)
+ {
+ return blocker switch {
+ ExportAttributeRemovalBlocker.DynamicRegistrationSupported => (4193, Errors.MX4193),
+ ExportAttributeRemovalBlocker.BlockLiteralSetupBlockOptimizationDisabled => (4194, Errors.MX4194),
+ ExportAttributeRemovalBlocker.StaticBlockToDelegateLookupOptimizationDisabled => (4195, Errors.MX4195),
+ ExportAttributeRemovalBlocker.RuntimeGetBlockWrapperCreatorRequired => (4196, Errors.MX4196),
+ ExportAttributeRemovalBlocker.RegistrarHelperGetBlockForDelegateRequired => (4197, Errors.MX4197),
+ ExportAttributeRemovalBlocker.NSXpcInterfaceMethodInfoOverloadUsed => (4198, Errors.MX4198),
+ _ => throw new InvalidOperationException ($"Unknown Export attribute removal blocker: {blocker}."),
+ };
+ }
+}
diff --git a/tools/assembly-preparer/assembly-preparer.csproj b/tools/assembly-preparer/assembly-preparer.csproj
index 69e3e12f26ec..f8800110d5b0 100644
--- a/tools/assembly-preparer/assembly-preparer.csproj
+++ b/tools/assembly-preparer/assembly-preparer.csproj
@@ -249,8 +249,8 @@
external/tools/linker/OptimizeGeneratedCode.cs
-
- external/tools/linker/RegistrarRemovalTrackingStep.cs
+
+ external/tools/linker/DetectApiUsageStep.cs
external/tools/linker/RemoveUserResourcesSubStep.cs
diff --git a/tools/common/Application.cs b/tools/common/Application.cs
index 27b79cd470aa..d72666d07f2d 100644
--- a/tools/common/Application.cs
+++ b/tools/common/Application.cs
@@ -57,6 +57,15 @@ public enum RegistrarOptions {
Trace = 1,
}
+ public enum ExportAttributeRemovalBlocker {
+ DynamicRegistrationSupported,
+ BlockLiteralSetupBlockOptimizationDisabled,
+ StaticBlockToDelegateLookupOptimizationDisabled,
+ RuntimeGetBlockWrapperCreatorRequired,
+ RegistrarHelperGetBlockForDelegateRequired,
+ NSXpcInterfaceMethodInfoOverloadUsed,
+ }
+
public partial class Application : IToolLog {
public Cache? Cache;
public string AppDirectory = ".";
@@ -83,6 +92,8 @@ public partial class Application : IToolLog {
public List? AotOtherArguments = null;
public bool? AotFloat32 = null;
public bool PrepareAssemblies; // True if '$(PrepareAssemblies)' == 'true'
+ public bool? TrimExportAttributes;
+ public HashSet TrimExportAttributesBlockers = new HashSet ();
// The set of UnmanagedCallersOnly trampoline symbols (without the leading Mach-O underscore)
// that survived the NativeAOT compiler (ILC). This is only set when the native registrar code
@@ -122,10 +133,10 @@ public bool IsClassReferencedByInlinedClassGetHandle (string exportedName)
#if ASSEMBLY_PREPARER
public bool InCustomTrimmerStep = false;
public bool IsPostProcessingAssemblies;
- // When post-processing assemblies with the trimmable static registrar, the [ProtocolMember] attributes
- // have been removed by the trimmer, so the registrar reads them from the pre-trim (untrimmed) assemblies
- // instead. This resolver provides access to the pre-trim assemblies (a separate metadata universe from
- // the post-trim assemblies), and is null when not applicable.
+ // When post-processing assemblies with the trimmable static registrar, selected registrar attributes
+ // have been removed during trimming, so the registrar reads them from the original assemblies.
+ // This resolver provides access to the original assemblies (a separate metadata universe from the
+ // post-trim assemblies), and is null when not applicable.
public Mono.Cecil.IAssemblyResolver? PreTrimAssemblyResolver;
#else
public bool InCustomTrimmerStep = true;
diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs
index be6a84f1cdc1..a3c40a26ee8a 100644
--- a/tools/common/StaticRegistrar.cs
+++ b/tools/common/StaticRegistrar.cs
@@ -655,25 +655,109 @@ public Xamarin.Tuner.DerivedLinkContext LinkContext {
// Look for linked away attributes as well as attributes on the attribute provider.
IEnumerable GetCustomAttributes (ICustomAttributeProvider provider, string @namespace, string name, bool inherits = false)
{
+#if ASSEMBLY_PREPARER
+ var found = false;
+#endif
#if !LEGACY_TOOLS
var dict = LinkContext?.Annotations?.GetCustomAnnotations (name);
if (dict?.TryGetValue (provider, out var annotations) == true) {
var attributes = (IEnumerable) annotations;
foreach (var attrib in attributes) {
- if (IsAttributeMatch (attrib, @namespace, name, inherits))
+ if (IsAttributeMatch (attrib, @namespace, name, inherits)) {
+#if ASSEMBLY_PREPARER
+ found = true;
+#endif
yield return attrib;
+ }
}
}
#endif
if (provider.HasCustomAttributes) {
foreach (var attrib in provider.CustomAttributes) {
- if (IsAttributeMatch (attrib, @namespace, name, inherits))
+ if (IsAttributeMatch (attrib, @namespace, name, inherits)) {
+#if ASSEMBLY_PREPARER
+ found = true;
+#endif
yield return attrib;
+ }
}
}
+
+#if ASSEMBLY_PREPARER
+ if (found || !ShouldReadAttributeFromPreTrimAssembly (@namespace, name))
+ yield break;
+
+ var preTrimProvider = GetPreTrimAttributeProvider (provider);
+ if (preTrimProvider is null)
+ yield break;
+ foreach (var attrib in preTrimProvider.CustomAttributes) {
+ if (IsAttributeMatch (attrib, @namespace, name, inherits))
+ yield return attrib;
+ }
+#endif
}
+#if ASSEMBLY_PREPARER
+ bool ShouldReadAttributeFromPreTrimAssembly (string @namespace, string name)
+ {
+ if (!App.IsPostProcessingAssemblies || App.PreTrimAssemblyResolver is null)
+ return false;
+
+ if (@namespace != Foundation)
+ return false;
+
+ if (name == StringConstants.ProtocolMemberAttribute)
+ return true;
+
+ return App.TrimExportAttributes == true && name == StringConstants.ExportAttribute;
+ }
+
+ ICustomAttributeProvider? GetPreTrimAttributeProvider (ICustomAttributeProvider postTrimProvider)
+ {
+ var resolver = App.PreTrimAssemblyResolver;
+ if (resolver is null)
+ throw new InvalidOperationException ("The pre-trim assembly resolver is not available.");
+
+ switch (postTrimProvider) {
+ case AssemblyDefinition assembly:
+ return resolver.Resolve (assembly.Name);
+ case ModuleDefinition module:
+ var preTrimAssembly = resolver.Resolve (module.Assembly.Name);
+ return GetSinglePreTrimProvider (preTrimAssembly.Modules, v => v.Name == module.Name, module);
+ case TypeDefinition type:
+ var preTrimModule = (ModuleDefinition?) GetPreTrimAttributeProvider (type.Module);
+ return preTrimModule?.GetType (type.FullName);
+ case MethodDefinition method:
+ var preTrimType = (TypeDefinition?) GetPreTrimAttributeProvider (method.DeclaringType);
+ return preTrimType is null ? null : GetSinglePreTrimProvider (preTrimType.Methods, v => v.FullName == method.FullName && v.GenericParameters.Count == method.GenericParameters.Count, method);
+ case PropertyDefinition property:
+ var preTrimPropertyType = (TypeDefinition?) GetPreTrimAttributeProvider (property.DeclaringType);
+ return preTrimPropertyType is null ? null : GetSinglePreTrimProvider (preTrimPropertyType.Properties, v => v.FullName == property.FullName, property);
+ case ParameterDefinition parameter:
+ var preTrimMethod = (MethodDefinition?) GetPreTrimAttributeProvider ((MethodDefinition) parameter.Method);
+ if (preTrimMethod is null || parameter.Index < 0 || parameter.Index >= preTrimMethod.Parameters.Count)
+ return null;
+ return preTrimMethod.Parameters [parameter.Index];
+ case MethodReturnType returnType:
+ var preTrimReturnMethod = (MethodDefinition?) GetPreTrimAttributeProvider ((MethodDefinition) returnType.Method);
+ return preTrimReturnMethod?.MethodReturnType;
+ default:
+ throw new InvalidOperationException ($"Unable to map the post-trim custom attribute provider '{postTrimProvider}' ({postTrimProvider.GetType ().FullName}) to a pre-trim provider.");
+ }
+ }
+
+ static T? GetSinglePreTrimProvider (IEnumerable providers, Func predicate, ICustomAttributeProvider postTrimProvider) where T : class, ICustomAttributeProvider
+ {
+ var matches = providers.Where (predicate).Take (2).ToArray ();
+ if (matches.Length == 1)
+ return matches [0];
+ if (matches.Length == 0)
+ return null;
+ throw new InvalidOperationException ($"The post-trim custom attribute provider '{postTrimProvider}' maps to multiple pre-trim providers.");
+ }
+#endif
+
public bool TryGetAttribute (ICustomAttributeProvider provider, string @namespace, string attributeName, [NotNullWhen (true)] out ICustomAttribute? attribute)
{
attribute = null;
@@ -1586,18 +1670,6 @@ protected override IEnumerable GetProtocolMemberAttribu
if (td is null)
yield break;
-#if ASSEMBLY_PREPARER
- // When post-processing assemblies with the trimmable static registrar, the [ProtocolMember]
- // attributes have been removed by the trimmer, so read them from the pre-trim (untrimmed)
- // assemblies instead.
- if (App.IsPostProcessingAssemblies && App.PreTrimAssemblyResolver is not null) {
- var preTrimAssembly = App.PreTrimAssemblyResolver.Resolve (td.Module.Assembly.Name);
- var preTrimType = preTrimAssembly?.MainModule.GetType (td.FullName);
- if (preTrimType is not null)
- td = preTrimType;
- }
-#endif
-
foreach (var ca in GetCustomAttributes (td, Foundation, StringConstants.ProtocolMemberAttribute)) {
var rv = new ProtocolMemberAttribute ();
@@ -1924,7 +1996,7 @@ static BindAsAttribute CreateBindAsAttribute (ICustomAttribute attrib, IMemberDe
}
}
- public static ExportAttribute? CreateExportAttribute (IMemberDefinition candidate)
+ public ExportAttribute? CreateExportAttribute (IMemberDefinition candidate)
{
bool is_variadic = false;
var attribute = GetExportAttribute (candidate);
@@ -1957,16 +2029,9 @@ static BindAsAttribute CreateBindAsAttribute (ICustomAttribute attrib, IMemberDe
}
// [Export] is not sealed anymore - so we cannot simply compare strings
- public static ICustomAttribute? GetExportAttribute (ICustomAttributeProvider candidate)
+ public ICustomAttribute? GetExportAttribute (ICustomAttributeProvider candidate)
{
- if (!candidate.HasCustomAttributes)
- return null;
-
- foreach (CustomAttribute ca in candidate.CustomAttributes) {
- if (ca.Constructor.DeclaringType.Inherits (Foundation, StringConstants.ExportAttribute))
- return ca;
- }
- return null;
+ return GetCustomAttributes (candidate, Foundation, StringConstants.ExportAttribute, inherits: true).FirstOrDefault ();
}
PropertyDefinition GetBasePropertyInTypeHierarchy (PropertyDefinition property)
diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs
index 5ba1ac6a5c51..4751014e988f 100644
--- a/tools/dotnet-linker/LinkerConfiguration.cs
+++ b/tools/dotnet-linker/LinkerConfiguration.cs
@@ -32,8 +32,9 @@ public class LinkerConfiguration {
public string CacheDirectory { get; private set; } = string.Empty;
public Version? DeploymentTarget { get; private set; }
// The user-provided value of the $(DynamicRegistrationSupported) MSBuild property (null if not set).
- // When set, RegistrarRemovalTrackingStep doesn't need to run in the assembly-preparer.
- // This is also how the value RegistrarRemovalTrackingStep computed during the preparation pass is
+ // When set, DetectApiUsageStep doesn't need to compute this value in the assembly-preparer,
+ // although it may still run to detect blockers for other optimizations.
+ // This is also how the value DetectApiUsageStep computed during the preparation pass is
// passed to the post-processing pass (which needs it to generate the native main file).
public bool? DynamicRegistrationSupported { get; set; }
public HashSet FrameworkAssemblies { get; private set; } = new HashSet ();
@@ -320,12 +321,12 @@ Configurator GetConfigurator (string linker_file)
{ "DynamicRegistrationSupported", (
// This is the user-overridable $(DynamicRegistrationSupported) MSBuild property. It maps to
// the RemoveDynamicRegistrar optimization (inverted): if dynamic registration is supported,
- // then we're not removing the dynamic registrar. When set, RegistrarRemovalTrackingStep doesn't
- // need to run in the assembly-preparer (the value is passed straight through to the trimmer
+ // then we're not removing the dynamic registrar. When set, DetectApiUsageStep doesn't
+ // need to compute the value in the assembly-preparer (it's passed straight through to the trimmer
// feature switch), and it won't recompute the value in the real linker either.
new LoadValue ((key, value) => {
if (string.IsNullOrEmpty (value))
- return; // Not set: RegistrarRemovalTrackingStep will compute a default value.
+ return; // Not set: DetectApiUsageStep will compute a default value.
if (!TryParseOptionalBoolean (value, out var dynamicRegistrationSupported))
throw new InvalidOperationException ($"Unable to parse the {key} value: {value} in {linker_file}");
if (dynamicRegistrationSupported.HasValue) {
@@ -646,6 +647,16 @@ Configurator GetConfigurator (string linker_file)
new LoadValue ((key, value) => TrimMode = value),
new SaveValue ((key, storage) => saveNonEmpty (key, TrimMode, storage))
)},
+ { "TrimExportAttributes", (
+ new LoadValue ((key, value) => {
+ if (string.IsNullOrEmpty (value)) {
+ Application.TrimExportAttributes = null;
+ } else {
+ loadNullableBool (key, value, out Application.TrimExportAttributes);
+ }
+ }),
+ new SaveValue ((key, storage) => saveNullableBool (key, Application.TrimExportAttributes, storage))
+ )},
{ "TypeMapAssemblyName", (
new LoadValue ((key, value) => Application.TypeMapAssemblyName = value),
new SaveValue ((key, storage) => saveNonEmpty (key, Application.TypeMapAssemblyName, storage))
diff --git a/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs b/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs
index bca1ac585acd..2f539ea87447 100644
--- a/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs
+++ b/tools/dotnet-linker/Steps/ManagedRegistrarStep.cs
@@ -1669,6 +1669,8 @@ bool EmitConversion (MethodDefinition method, ILProcessor il, TypeReference type
if (toManaged) {
var createMethod = StaticRegistrar.GetBlockWrapperCreator (objcMethod, parameter);
if (createMethod is null) {
+ if (App.TrimExportAttributes != false)
+ App.TrimExportAttributesBlockers.Add (ExportAttributeRemovalBlocker.RuntimeGetBlockWrapperCreatorRequired);
AddException (ErrorHelper.CreateWarning (App, 4174 /* Unable to locate the block to delegate conversion method for the method {0}'s parameter #{1}. */, method, Errors.MT4174, method.FullName, parameter + 1));
// var blockCopy = BlockLiteral.Copy (block);
var tmpVariable = il.Body.AddVariable (abr.System_IntPtr);
@@ -1725,6 +1727,8 @@ bool EmitConversion (MethodDefinition method, ILProcessor il, TypeReference type
il.Emit (OpCodes.Ldstr, signature);
il.Emit (OpCodes.Call, abr.BlockLiteral_CreateBlockForDelegate);
} else {
+ if (App.TrimExportAttributes != false)
+ App.TrimExportAttributesBlockers.Add (ExportAttributeRemovalBlocker.RegistrarHelperGetBlockForDelegateRequired);
il.Emit (OpCodes.Ldtoken, method);
il.Emit (OpCodes.Call, abr.RegistrarHelper_GetBlockForDelegate);
}
diff --git a/tools/dotnet-linker/dotnet-linker.csproj b/tools/dotnet-linker/dotnet-linker.csproj
index 9a5d2966bc7b..563b834f1c22 100644
--- a/tools/dotnet-linker/dotnet-linker.csproj
+++ b/tools/dotnet-linker/dotnet-linker.csproj
@@ -227,8 +227,8 @@
external/tools/common/XamarinRuntime.cs
-
- external/tools/linker/RegistrarRemovalTrackingStep.cs
+
+ external/tools/linker/DetectApiUsageStep.cs
diff --git a/tools/linker/RegistrarRemovalTrackingStep.cs b/tools/linker/DetectApiUsageStep.cs
similarity index 89%
rename from tools/linker/RegistrarRemovalTrackingStep.cs
rename to tools/linker/DetectApiUsageStep.cs
index 36f9e17306fb..90ee6a9f01ce 100644
--- a/tools/linker/RegistrarRemovalTrackingStep.cs
+++ b/tools/linker/DetectApiUsageStep.cs
@@ -3,6 +3,7 @@
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Linker;
+using Mono.Tuner;
using Xamarin.Bundler;
using Xamarin.Linker;
@@ -10,9 +11,9 @@
#nullable enable
namespace MonoTouch.Tuner {
- public class RegistrarRemovalTrackingStep : ConfigurationAwareStep {
+ public class DetectApiUsageStep : ConfigurationAwareStep {
- protected override string Name { get; } = "RegistrarRemovalTracking";
+ protected override string Name { get; } = "DetectApiUsage";
protected override int ErrorCode { get; } = 2380;
int WarnCode => ErrorCode + 7;
@@ -87,6 +88,9 @@ bool RequiresDynamicRegistrar (AssemblyDefinition assembly, bool warnIfRequired)
if (name != productAssemblyName)
continue;
+ if (App.TrimExportAttributes != false && IsNSXpcInterfaceMethodInfoOverload (mr))
+ App.TrimExportAttributesBlockers.Add (ExportAttributeRemovalBlocker.NSXpcInterfaceMethodInfoOverloadUsed);
+
switch (mr.DeclaringType.Namespace) {
case "ObjCRuntime":
switch (mr.DeclaringType.Name) {
@@ -155,6 +159,18 @@ bool RequiresDynamicRegistrar (AssemblyDefinition assembly, bool warnIfRequired)
return requires;
}
+ static bool IsNSXpcInterfaceMethodInfoOverload (MemberReference member)
+ {
+ if (member is not MethodReference method)
+ return false;
+ if (!method.DeclaringType.Is ("Foundation", "NSXpcInterface"))
+ return false;
+ if (method.Parameters.Count == 0 || !method.Parameters [0].ParameterType.Is ("System.Reflection", "MethodInfo"))
+ return false;
+
+ return method.Name == "GetAllowedClasses" || method.Name == "SetAllowedClasses";
+ }
+
void Warn (AssemblyDefinition assembly, MemberReference mr)
{
ErrorHelper.Warning (App, WarnCode, Errors.MM2107, assembly.Name.Name, mr.DeclaringType.FullName, mr.Name, string.Join (", ", ((MethodReference) mr).Parameters.Select ((v) => v.ParameterType.FullName)));
diff --git a/tools/mtouch/Errors.designer.cs b/tools/mtouch/Errors.designer.cs
index 8201fdecc511..77d077170643 100644
--- a/tools/mtouch/Errors.designer.cs
+++ b/tools/mtouch/Errors.designer.cs
@@ -3677,6 +3677,60 @@ public static string MX4191 {
}
}
+ ///
+ /// Looks up a localized string similar to Export attributes cannot be removed because dynamic registration is supported..
+ ///
+ public static string MX4193 {
+ get {
+ return ResourceManager.GetString("MX4193", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Export attributes cannot be removed because the blockliteral-setupblock optimization is disabled..
+ ///
+ public static string MX4194 {
+ get {
+ return ResourceManager.GetString("MX4194", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Export attributes cannot be removed because the static-block-to-delegate-lookup optimization is disabled..
+ ///
+ public static string MX4195 {
+ get {
+ return ResourceManager.GetString("MX4195", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Export attributes cannot be removed because the managed registrar must use Runtime.GetBlockWrapperCreator..
+ ///
+ public static string MX4196 {
+ get {
+ return ResourceManager.GetString("MX4196", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Export attributes cannot be removed because the managed registrar must use RegistrarHelper.GetBlockForDelegate..
+ ///
+ public static string MX4197 {
+ get {
+ return ResourceManager.GetString("MX4197", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Export attributes cannot be removed because the application uses an NSXpcInterface overload that obtains a selector from MethodInfo..
+ ///
+ public static string MX4198 {
+ get {
+ return ResourceManager.GetString("MX4198", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The native linker failed to execute: {0}. Please file a bug report at https://github.com/dotnet/macios/issues/new
/// .
diff --git a/tools/mtouch/Errors.resx b/tools/mtouch/Errors.resx
index 9ce37f3745c1..b9ef8941c4dc 100644
--- a/tools/mtouch/Errors.resx
+++ b/tools/mtouch/Errors.resx
@@ -1644,6 +1644,30 @@
The registrar cannot use the model class '{0}' as a generic type argument in the generic type '{1}'. Use the protocol interface instead of the model class.
+
+ Export attributes cannot be removed because dynamic registration is supported.
+
+
+
+ Export attributes cannot be removed because the blockliteral-setupblock optimization is disabled.
+
+
+
+ Export attributes cannot be removed because the static-block-to-delegate-lookup optimization is disabled.
+
+
+
+ Export attributes cannot be removed because the managed registrar must use Runtime.GetBlockWrapperCreator.
+
+
+
+ Export attributes cannot be removed because the managed registrar must use RegistrarHelper.GetBlockForDelegate.
+
+
+
+ Export attributes cannot be removed because the application uses an NSXpcInterface overload that obtains a selector from MethodInfo.
+
+
Missing '{0}' compiler. Please install Xcode 'Command-Line Tools' component