diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker/MethodDefinitionExtensions.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker/MethodDefinitionExtensions.cs
index cc1d5b6896ee..a0fce1fb423a 100644
--- a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker/MethodDefinitionExtensions.cs
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker/MethodDefinitionExtensions.cs
@@ -1,5 +1,7 @@
using Mono.Cecil;
+#nullable disable
+
namespace Mono.Linker {
public static class MethodDefinitionExtensions {
public static bool IsDefaultConstructor (this MethodDefinition method)
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/CecilRocks.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/CecilRocks.cs
index 6d2abeef6e04..c9d0b6b102f4 100644
--- a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/CecilRocks.cs
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/CecilRocks.cs
@@ -33,6 +33,8 @@
using Mono.Cecil;
using Mono.Cecil.Cil;
+#nullable disable
+
namespace Mono.Tuner {
public static class MethodBodyRocks {
diff --git a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/Extensions.cs b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/Extensions.cs
index 0f85e17196de..a5759b496ddd 100644
--- a/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/Extensions.cs
+++ b/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/Extensions.cs
@@ -5,6 +5,8 @@
using Mono.Linker;
+#nullable disable
+
namespace Mono.Tuner {
public static partial class Extensions {
diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets
index bed4b2b282f3..49ab0125ece8 100644
--- a/dotnet/targets/Xamarin.Shared.Sdk.targets
+++ b/dotnet/targets/Xamarin.Shared.Sdk.targets
@@ -253,6 +253,7 @@
_ResolveAppExtensionReferences;
_ExtendAppExtensionReferences;
_ComputeLinkerArguments;
+ _PrepareAssemblies;
_ComputeFrameworkFilesToPublish;
_ComputeDynamicLibrariesToPublish;
ComputeFilesToPublish;
@@ -729,7 +730,7 @@
- <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" />
+ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(PrepareAssemblies)' != 'true'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.BackingFieldDelayHandler" />
<_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true'" Type="Xamarin.Linker.MarkIProtocolHandler" />
@@ -1271,15 +1272,28 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ <_IntermediateAssemblyProperty>@(IntermediateAssembly)
+ <_PreparedIntermediateAssemblyProperty>@(PreparedIntermediateAssembly->WithMetadataValue('BeforePrepareAssembliesPath','$(_IntermediateAssemblyProperty)'))
+
+
+ <_PreparedRootedIntermediateAssembly Include="@(TrimmerRootAssembly->'$(_PreparedIntermediateAssemblyProperty)')" Condition="'%(Identity)' == '$(_IntermediateAssemblyProperty)'" />
+
+
+
-
+
diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs
new file mode 100644
index 000000000000..e93813f8459d
--- /dev/null
+++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+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.Utils;
+
+#nullable enable
+
+namespace Xamarin.MacDev.Tasks {
+ public class PrepareAssemblies : XamarinTask {
+ const string ErrorPrefix = "AP";
+
+ #region Inputs
+ [Required]
+ public ITaskItem [] InputAssemblies { get; set; } = [];
+
+ public string MakeReproPath { get; set; } = "";
+
+ public string OutputDirectory { 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)); // FIXME: wrong for resource assemblies, at the very least.
+ var rv = new AssemblyPreparerInfo (inputPath, outputPath);
+ map [rv] = item;
+ return rv;
+ }
+
+ public override bool Execute ()
+ {
+ try {
+ var infos = InputAssemblies.Select (GetAssemblyInfo).ToArray ();
+ using var preparer = new AssemblyPreparer (infos, Platform);
+ preparer.MakeReproPath = MakeReproPath;
+ var rv = preparer.Prepare (out var exceptions);
+
+ foreach (var pe in exceptions) {
+ if (pe.Error) {
+ Log.LogError (null, $"{ErrorPrefix}{pe.Code}", null, pe.FileName ?? "MSBuild", 0, 0, 0, 0, message: pe.Message);
+ Exception? ie = pe.InnerException;
+ while (ie is not null) {
+ Log.LogMessage (MessageImportance.Low, "Inner exception: {0}\n{1}", ie.Message, ie.StackTrace);
+ ie = ie.InnerException;
+ }
+ } else {
+ Log.LogWarning (null, $"{ErrorPrefix}{pe.Code}", null, pe.FileName ?? "MSBuild", 0, 0, 0, 0, message: pe.Message);
+ }
+ }
+
+ OutputAssemblies = preparer.Assemblies.Select (v => {
+ var item = map [v];
+ item.ItemSpec = v.OutputPath;
+ item.SetMetadata ("BeforePrepareAssembliesPath", v.InputPath);
+ return item;
+ }).ToArray ();
+ return rv && !Log.HasLoggedErrors;
+ } catch (Exception e) {
+ Log.LogError ("Unexpected error while preparing assemblies: {0}", e);
+ return false;
+ }
+ }
+ }
+}
diff --git a/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj b/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj
index 6a2594989fc6..216fe9ab9d91 100644
--- a/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj
+++ b/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj
@@ -38,6 +38,7 @@
+
ProjectReference
@@ -70,9 +71,6 @@
-
- ApplePlatform.cs
-
StringUtils.cs
diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
index 984ba1c916a5..6cb75c700807 100644
--- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets
+++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets
@@ -88,6 +88,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
+
@@ -3259,6 +3260,48 @@ Copyright (C) 2018 Microsoft. All rights reserved.
+
+ true
+
+
+
+
+ <_AssembliesToPrepare Include="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.PostprocessAssembly)' == 'true'" />
+
+ <__PDBToPrepare Include="@(ResolvedFileToPublish)" Exclude="@(_AssembliesToPrepare->'%(RelativeDir)%(Filename).pdb')" />
+ <_PDBToPrepare Include="@(ResolvedFileToPublish)" Exclude="@(__PDBToLink)" />
+
+
+ $([MSBuild]::EnsureTrailingSlash('$(DeviceSpecificIntermediateOutputPath)prepared-assemblies'))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ObjCRuntime/Constants.cs b/src/ObjCRuntime/Constants.cs
index c1dd1d8476c3..0428bc6ed4a2 100644
--- a/src/ObjCRuntime/Constants.cs
+++ b/src/ObjCRuntime/Constants.cs
@@ -1,4 +1,4 @@
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
namespace Xamarin.Bundler {
#else
namespace ObjCRuntime {
diff --git a/src/ObjCRuntime/ErrorHelper.cs b/src/ObjCRuntime/ErrorHelper.cs
index d3793878758b..9255beafa0b1 100644
--- a/src/ObjCRuntime/ErrorHelper.cs
+++ b/src/ObjCRuntime/ErrorHelper.cs
@@ -2,7 +2,7 @@
#nullable enable
-#if MTOUCH || MMP || MMP_TEST || MTOUCH_TESTS
+#if MTOUCH || MMP || MMP_TEST || MTOUCH_TESTS || ASSEMBLY_PREPARER
#define BUNDLER
#endif
diff --git a/src/ObjCRuntime/Registrar.cs b/src/ObjCRuntime/Registrar.cs
index 9a2371fd9633..e4adb3998c0f 100644
--- a/src/ObjCRuntime/Registrar.cs
+++ b/src/ObjCRuntime/Registrar.cs
@@ -20,7 +20,7 @@
using ObjCRuntime;
using Xamarin.Bundler;
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
using Xamarin.Utils;
using TAssembly = Mono.Cecil.AssemblyDefinition;
using TType = Mono.Cecil.TypeReference;
@@ -93,7 +93,7 @@ public static List GetMT4127 (TMethod impl, List ifac
}
abstract partial class Registrar {
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
public Application App { get; protected set; }
#endif
@@ -156,7 +156,7 @@ internal class ObjCType {
public bool IsCategory { get { return CategoryAttribute is not null; } }
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
HashSet all_protocols;
// This contains all protocols in the type hierarchy.
// Given a type T that implements a protocol with super protocols:
@@ -884,7 +884,7 @@ public Trampoline Trampoline {
if (trampoline != Trampoline.None)
return trampoline;
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
throw ErrorHelper.CreateError (8018, Errors.MT8018);
#else
var mi = (System.Reflection.MethodInfo) Method;
@@ -1331,7 +1331,7 @@ internal static string AppKit {
}
#endif
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
internal string AssemblyName {
get {
switch (App.Platform) {
@@ -1379,7 +1379,7 @@ public string PlatformAssembly {
}
}
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
// "#if MTOUCH" code does not need locking when accessing 'types', because mtouch is single-threaded.
public Dictionary Types {
get { return types; }
@@ -2205,7 +2205,7 @@ ObjCType RegisterTypeUnsafe (TType type, ref List exceptions)
}
} else {
TMethod method = null;
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
method = attrib.Method;
#endif
var objcMethod = new ObjCMethod (this, objcType, method) {
@@ -2261,7 +2261,7 @@ ObjCType RegisterTypeUnsafe (TType type, ref List exceptions)
FieldType = "@",
IsProperty = true,
IsStatic = IsStatic (property),
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
Property = property,
#endif
}, ref exceptions);
@@ -2657,7 +2657,7 @@ protected string GetExportedTypeName (TType type)
string GetBoolEncoding ()
{
// map managed 'bool' to ObjC BOOL = 'unsigned char' in OSX and 32bit iOS architectures and 'bool' in 64bit iOS architectures
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
switch (App.Platform) {
case ApplePlatform.iOS:
case ApplePlatform.TVOS:
@@ -2782,7 +2782,7 @@ protected void UnlockRegistrar ()
System.Threading.Monitor.Exit (types);
}
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
internal static void NSLog (string format, params object [] args)
{
Console.WriteLine (format, args);
diff --git a/tests/assembly-preparer/GlobalUsings.cs b/tests/assembly-preparer/GlobalUsings.cs
new file mode 100644
index 000000000000..68feec6faf4d
--- /dev/null
+++ b/tests/assembly-preparer/GlobalUsings.cs
@@ -0,0 +1,9 @@
+global using System.IO;
+
+global using Mono.Cecil;
+global using NUnit.Framework;
+
+global using Xamarin;
+global using Xamarin.Build;
+global using Xamarin.Tests;
+global using Xamarin.Utils;
diff --git a/tests/assembly-preparer/Makefile b/tests/assembly-preparer/Makefile
new file mode 100644
index 000000000000..59fa8b078157
--- /dev/null
+++ b/tests/assembly-preparer/Makefile
@@ -0,0 +1,5 @@
+TOP=../..
+include $(TOP)/Make.config
+
+run-tests:
+ $(DOTNET) test *.csproj
\ No newline at end of file
diff --git a/tests/assembly-preparer/PreserveBlockCodeHandlerTests.cs b/tests/assembly-preparer/PreserveBlockCodeHandlerTests.cs
new file mode 100644
index 000000000000..1313bddb548a
--- /dev/null
+++ b/tests/assembly-preparer/PreserveBlockCodeHandlerTests.cs
@@ -0,0 +1,104 @@
+using Mono.Cecil.Rocks;
+
+namespace AssemblyPreparerTests;
+
+public class PreserveBlockCodeHandlerTests {
+ [Test]
+ [TestCase (ApplePlatform.MacCatalyst)]
+ [TestCase (ApplePlatform.iOS)]
+ [TestCase (ApplePlatform.TVOS)]
+ [TestCase (ApplePlatform.MacOSX)]
+ public void First (ApplePlatform platform)
+ {
+ 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);
+ }
+ }";
+
+ var csproj = $@"
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)-{platform.AsString ().ToLower ()}
+ false
+ true
+
+
+ ";
+
+ var tmpdir = Cache.CreateTemporaryDirectory ();
+ File.WriteAllText (Path.Combine (tmpdir, "Test.cs"), code);
+ var csprojPath = Path.Combine (tmpdir, "Test.csproj");
+ File.WriteAllText (csprojPath, csproj);
+ DotNet.AssertBuild (csprojPath);
+ var assemblyDir = Path.Combine (tmpdir, "bin", "Debug");
+
+ var assemblies = GetAssemblies (platform);
+ assemblies.Add (Path.Combine (assemblyDir, "Test.dll"));
+ var infos = assemblies.Select (v => new AssemblyPreparerInfo (v, Path.Combine (assemblyDir, "out", Path.GetFileName (v)))).ToArray ();
+ var preparer = new AssemblyPreparer (infos, platform);
+ Assert.That (preparer.Prepare (out var exceptions), Is.True, "Prepare");
+ Assert.That (exceptions, Is.Empty, "Exceptions");
+
+ var outputPath = Path.Combine (assemblyDir, "out", "Test.dll");
+ var assemblyDefinition = AssemblyDefinition.ReadAssembly (outputPath);
+ 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");
+ Assert.That ((string) attribs [0].ConstructorArguments [0].Value, Is.EqualTo ("Handler"), "First attribute's first argument");
+ Assert.That ((string) attribs [1].ConstructorArguments [0].Value, Is.EqualTo ("Invoke(System.IntPtr,System.Int32)"), "Second attribute's first argument");
+ Assert.That (((TypeDefinition) attribs [0].ConstructorArguments [1].Value).FullName, Is.EqualTo ("ObjCRuntime.Trampolines/SDInnerBlock"), "First attribute's second argument");
+ Assert.That (((TypeDefinition) attribs [1].ConstructorArguments [1].Value).FullName, Is.EqualTo ("ObjCRuntime.Trampolines/SDInnerBlock"), "Second attribute's second argument");
+ }
+
+ List GetAssemblies (ApplePlatform platform)
+ {
+ var assemblies = new List ();
+ string rid;
+ string packageName;
+ switch (platform) {
+ case ApplePlatform.MacCatalyst:
+ rid = "maccatalyst-arm64";
+ packageName = "microsoft.netcore.app.runtime.mono.maccatalyst-arm64";
+ break;
+ case ApplePlatform.iOS:
+ rid = "ios-arm64";
+ packageName = "microsoft.netcore.app.runtime.mono.ios-arm64";
+ break;
+ case ApplePlatform.TVOS:
+ rid = "tvos-arm64";
+ packageName = "microsoft.netcore.app.runtime.mono.tvos-arm64";
+ break;
+ case ApplePlatform.MacOSX:
+ rid = "osx-arm64";
+ packageName = "microsoft.netcore.app.runtime.osx-arm64";
+ break;
+ default:
+ throw new NotSupportedException ($"Unsupported platform: {platform}");
+ }
+ var microsoftNetCoreAppRefPackageVersion = File.ReadAllLines (Path.Combine (Configuration.RootPath, "dotnet.config")).Single (v => v.StartsWith ("BUNDLED_NETCORE_PLATFORMS_PACKAGE_VERSION=", StringComparison.Ordinal)).Replace ("BUNDLED_NETCORE_PLATFORMS_PACKAGE_VERSION=", "");
+ var bclDir = Path.Combine (Configuration.RootPath, "packages", packageName, microsoftNetCoreAppRefPackageVersion, "runtimes", rid, "lib", Configuration.DotNetTfm);
+ var nativeDir = Path.Combine (Configuration.RootPath, "packages", packageName, microsoftNetCoreAppRefPackageVersion, "runtimes", rid, "native");
+
+ assemblies.AddRange (Directory.GetFiles (bclDir, "*.dll"));
+ assemblies.AddRange (Directory.GetFiles (nativeDir, "*.dll"));
+ assemblies.Add (Path.Combine (Configuration.GetRuntimeDirectory (platform, rid), "lib", Configuration.DotNetTfm, Configuration.GetBaseLibraryName (platform)));
+
+ return assemblies;
+ }
+}
diff --git a/tests/assembly-preparer/ReproTest.cs b/tests/assembly-preparer/ReproTest.cs
new file mode 100644
index 000000000000..e7daa58523cd
--- /dev/null
+++ b/tests/assembly-preparer/ReproTest.cs
@@ -0,0 +1,30 @@
+namespace AssemblyPreparerTests;
+
+public class ReproTest {
+ [Test]
+ public void Rerun ()
+ {
+ var reproPath = Environment.GetEnvironmentVariable ("_PrepareAssembliesMakeReproPath");
+ if (string.IsNullOrEmpty (reproPath))
+ reproPath = "/tmp/assembly-preparer-repro";
+ if (!Directory.Exists (reproPath))
+ return;
+
+ var platform = ApplePlatform.None;
+ var assemblies = new List ();
+ var lines = File.ReadAllLines (Path.Combine (reproPath, "arguments.txt"));
+ foreach (var line in lines) {
+ if (line.StartsWith ("Platform: ")) {
+ var platformStr = line.Substring ("Platform: ".Length);
+ platform = Enum.Parse (platformStr);
+ } else if (line.StartsWith ("Assembly: ")) {
+ var assembly = line.Substring ("Assembly: ".Length);
+ assemblies.Add (new AssemblyPreparerInfo (Path.Combine (reproPath, assembly), Path.Combine (reproPath, "out", assembly)));
+ } else {
+ throw new Exception ($"Unknown line: {line}");
+ }
+ }
+ var ap = new AssemblyPreparer (assemblies.ToArray (), platform);
+ ap.Prepare (out var exceptions);
+ }
+}
diff --git a/tests/assembly-preparer/assembly-preparer-tests.csproj b/tests/assembly-preparer/assembly-preparer-tests.csproj
new file mode 100644
index 000000000000..0a16e10a8edd
--- /dev/null
+++ b/tests/assembly-preparer/assembly-preparer-tests.csproj
@@ -0,0 +1,53 @@
+
+
+ net$(BundledNETCoreAppTargetFrameworkVersion)
+ latest
+ enable
+ enable
+ false
+ 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/tools/common/Execution.cs
+
+
+ external/tests/common/ExecutionHelper.cs
+
+
+ external/tools/common/SdkVersions.cs
+
+
+ external/tools/common/StringUtils.cs
+
+
+ external/tools/common/TargetFramework.cs
+
+
+
+
diff --git a/tests/assembly-preparer/assembly-preparer.sln b/tests/assembly-preparer/assembly-preparer.sln
new file mode 100644
index 000000000000..65c7089325aa
--- /dev/null
+++ b/tests/assembly-preparer/assembly-preparer.sln
@@ -0,0 +1,30 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "assembly-preparer-tests", "assembly-preparer-tests.csproj", "{7FC61F95-BECF-E3B2-CFB2-185C4687F051}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "assembly-preparer", "..\..\tools\assembly-preparer\assembly-preparer.csproj", "{38C6599D-4B02-4F6B-A778-B468595C66BB}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7FC61F95-BECF-E3B2-CFB2-185C4687F051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7FC61F95-BECF-E3B2-CFB2-185C4687F051}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7FC61F95-BECF-E3B2-CFB2-185C4687F051}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7FC61F95-BECF-E3B2-CFB2-185C4687F051}.Release|Any CPU.Build.0 = Release|Any CPU
+ {38C6599D-4B02-4F6B-A778-B468595C66BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {38C6599D-4B02-4F6B-A778-B468595C66BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {38C6599D-4B02-4F6B-A778-B468595C66BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {38C6599D-4B02-4F6B-A778-B468595C66BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {6D0A58D0-09F3-4518-8D2E-577564445FB3}
+ EndGlobalSection
+EndGlobal
diff --git a/tests/common/DotNet.cs b/tests/common/DotNet.cs
index f39ec36b451c..7cf367023ffc 100644
--- a/tests/common/DotNet.cs
+++ b/tests/common/DotNet.cs
@@ -37,7 +37,7 @@ public static ExecutionResult AssertPack (string project, Dictionary? properties = null, bool? msbuildParallelism = null)
{
var rv = Execute ("pack", project, properties, false, msbuildParallelism: msbuildParallelism);
- Assert.AreNotEqual (0, rv.ExitCode, "Unexpected success");
+ Assert.That (rv.ExitCode, Is.Not.EqualTo (0), "Unexpected success");
return rv;
}
@@ -49,7 +49,7 @@ public static ExecutionResult AssertPublish (string project, Dictionary? properties = null)
{
var rv = Execute ("publish", project, properties, false);
- Assert.AreNotEqual (0, rv.ExitCode, "Unexpected success");
+ Assert.That (rv.ExitCode, Is.Not.EqualTo (0), "Unexpected success");
return rv;
}
@@ -71,7 +71,7 @@ public static ExecutionResult AssertBuild (string project, Dictionary? properties = null)
{
var rv = Execute ("build", project, properties, false);
- Assert.AreNotEqual (0, rv.ExitCode, "Unexpected success");
+ Assert.That (rv.ExitCode, Is.Not.EqualTo (0), "Unexpected success");
return rv;
}
@@ -105,7 +105,7 @@ public static ExecutionResult AssertNew (string outputDirectory, string template
if (rv.ExitCode != 0) {
Console.WriteLine ($"'{Executable} {StringUtils.FormatArguments (args)}' failed with exit code {rv.ExitCode}.");
Console.WriteLine (output);
- Assert.AreEqual (0, rv.ExitCode, $"Exit code: {Executable} {StringUtils.FormatArguments (args)}");
+ Assert.That (rv.ExitCode, Is.EqualTo (0), $"Exit code: {Executable} {StringUtils.FormatArguments (args)}");
}
return new ExecutionResult (output, output, rv.ExitCode);
}
@@ -333,7 +333,7 @@ public static ExecutionResult Execute (string verb, string project, Dictionary exceptions)
+ {
+ exceptions = configuration.Exceptions;
+
+ if (!string.IsNullOrEmpty (MakeReproPath)) {
+ if (File.Exists (MakeReproPath) || Directory.Exists (MakeReproPath)) {
+ configuration.Exceptions.Add (ErrorHelper.CreateError (99, $"Repro location already exists: {MakeReproPath}"));
+ return false;
+ }
+ Directory.CreateDirectory (MakeReproPath);
+ var lines = new List ();
+ lines.Add ($"Platform: {configuration.Platform}");
+ foreach (var assembly in Assemblies) {
+ lines.Add ($"Assembly: {Path.GetFileName (assembly.InputPath)}");
+ File.Copy (assembly.InputPath, Path.Combine (MakeReproPath, Path.GetFileName (assembly.InputPath)));
+ }
+ File.WriteAllLines (Path.Combine (MakeReproPath, "arguments.txt"), lines);
+ log.Log ($"Created repro in {MakeReproPath}");
+ }
+
+ var markHandlers = new IMarkHandler [] {
+ new PreserveBlockCodeHandler (),
+ };
+
+ var linkContext = new DerivedLinkContext (configuration);
+ configuration.DerivedLinkContext = linkContext;
+
+ var markContext = new MarkContext ();
+ foreach (var handler in markHandlers) {
+ handler.Initialize (linkContext, markContext);
+ }
+
+ // load assemblies
+
+ var assemblyResolver = new DefaultAssemblyResolver ();
+ // var metadataResolver = new DefaultMetadataResolver ();
+
+ var parameters = new ReaderParameters {
+ AssemblyResolver = assemblyResolver,
+ // MetadataResolver = metadataResolver,
+ ReadSymbols = true,
+ SymbolReaderProvider = new DefaultSymbolReaderProvider (throwIfNoSymbol: false),
+ };
+ foreach (var assembly in Assemblies) {
+ var assemblyDefinition = AssemblyDefinition.ReadAssembly (assembly.InputPath, parameters); // FIXME: symbols
+ linkContext.Assemblies.Add (assemblyDefinition);
+ assembly.Assembly = assemblyDefinition;
+ configuration.Context.Annotations.SetAction (assemblyDefinition, AssemblyAction.Copy);
+ }
+
+ foreach (var assembly in linkContext.GetAssemblies ()) {
+ // Skip SDK asemblies, they have nothing we need to process at the moment.
+ if (!assembly.MainModule.HasAssemblyReferences)
+ continue;
+ if (!configuration.IsProductAssembly (assembly) && !assembly.MainModule.AssemblyReferences.Any (v => configuration.IsProductAssembly (v.Name)))
+ continue;
+
+ foreach (var type in assembly.MainModule.Types) {
+ markContext.MarkType (type);
+ }
+ }
+
+ // save assemblies
+
+ foreach (var assembly in Assemblies) {
+ var assemblyDefinition = assembly.Assembly!;
+
+ var action = configuration.Context.Annotations.GetAction (assemblyDefinition);
+ switch (action) {
+ case AssemblyAction.Copy:
+ assembly.OutputPath = assembly.InputPath;
+ continue;
+ case AssemblyAction.Link:
+ case AssemblyAction.Save:
+ Console.WriteLine ($"Saving {assembly.InputPath} to {assembly.OutputPath}");
+ break;
+ default:
+ throw new NotImplementedException ($"Unknown link action: {action}");
+ }
+
+ Directory.CreateDirectory (Path.GetDirectoryName (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) {
+ Console.WriteLine ($"Failed to create symbol writer for {assembly.OutputPath}, not writing symbols: {e.Message}");
+ }
+ }
+ try {
+ assemblyDefinition.Write (assembly.OutputPath, writerParameters);
+ } catch (Exception e) {
+ Console.WriteLine ($"Failed to write {assembly.OutputPath}: {e}");
+ throw;
+ }
+ }
+
+ return true;
+ }
+
+ public void Dispose ()
+ {
+ foreach (var assembly in Assemblies)
+ assembly.Assembly?.Dispose ();
+ }
+}
+
+public class AssemblyPreparerInfo {
+ internal AssemblyDefinition? Assembly { get; set; }
+
+ public string InputPath { get; private set; }
+ public string OutputPath { get; set; }
+
+ public AssemblyPreparerInfo (string inputPath, string outputPath)
+ {
+ InputPath = inputPath;
+ OutputPath = outputPath;
+ }
+}
diff --git a/tools/assembly-preparer/GlobalUsings.cs b/tools/assembly-preparer/GlobalUsings.cs
new file mode 100644
index 000000000000..c429b6757790
--- /dev/null
+++ b/tools/assembly-preparer/GlobalUsings.cs
@@ -0,0 +1,7 @@
+global using System;
+global using System.Collections.Generic;
+global using System.Linq;
+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..fbc16aad17aa
--- /dev/null
+++ b/tools/assembly-preparer/IAssemblyPreparerLog.cs
@@ -0,0 +1,30 @@
+using System;
+using Xamarin.Bundler;
+
+namespace Xamarin.Build;
+
+public interface IAssemblyPreparerLog {
+ void Log (string message);
+}
+
+public class ConsoleLog : IAssemblyPreparerLog {
+ public void Log (string message)
+ {
+ Console.WriteLine (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..bdfabb2fc468
--- /dev/null
+++ b/tools/assembly-preparer/Makefile
@@ -0,0 +1,6 @@
+TOP=../..
+include $(TOP)/Make.config
+include $(TOP)/mk/rules.mk
+
+all-local::
+ $(DOTNET) build /bl *.csproj
diff --git a/tools/assembly-preparer/Scaffolding/AnnotationStore.cs b/tools/assembly-preparer/Scaffolding/AnnotationStore.cs
new file mode 100644
index 000000000000..3359b92933e3
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/AnnotationStore.cs
@@ -0,0 +1,26 @@
+using Mono.Cecil;
+
+namespace Mono.Linker;
+
+public class AnnotationStore {
+ Dictionary assemblyActions = 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 void Mark (TypeDefinition type)
+ {
+ throw new NotImplementedException ();
+ }
+ public void Mark (ExportedType type)
+ {
+ throw new NotImplementedException ();
+ }
+}
diff --git a/tools/assembly-preparer/Scaffolding/Application.cs b/tools/assembly-preparer/Scaffolding/Application.cs
new file mode 100644
index 000000000000..062043b37835
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/Application.cs
@@ -0,0 +1,12 @@
+using Xamarin.Utils;
+
+namespace Xamarin.Bundler;
+
+public class Application {
+ public ApplePlatform Platform { get => throw new NotImplementedException (); }
+ public string ProductName => "assembly-preparer";
+ public void LoadSymbols ()
+ {
+ throw new NotImplementedException ();
+ }
+}
diff --git a/tools/assembly-preparer/Scaffolding/AssemblyAction.cs b/tools/assembly-preparer/Scaffolding/AssemblyAction.cs
new file mode 100644
index 000000000000..364ac0c74697
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/AssemblyAction.cs
@@ -0,0 +1,7 @@
+namespace Mono.Linker;
+
+public enum AssemblyAction {
+ Copy,
+ Link,
+ Save,
+}
diff --git a/tools/assembly-preparer/Scaffolding/DerivedLinkContext.cs b/tools/assembly-preparer/Scaffolding/DerivedLinkContext.cs
new file mode 100644
index 000000000000..74172ea37bc2
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/DerivedLinkContext.cs
@@ -0,0 +1,10 @@
+namespace Xamarin.Tuner;
+
+using Mono.Linker;
+using Xamarin.Bundler;
+
+public class DerivedLinkContext : LinkContext {
+ public DerivedLinkContext (LinkerConfiguration configuration) : base (configuration)
+ {
+ }
+}
diff --git a/tools/assembly-preparer/Scaffolding/Driver.cs b/tools/assembly-preparer/Scaffolding/Driver.cs
new file mode 100644
index 000000000000..95185356f591
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/Driver.cs
@@ -0,0 +1,5 @@
+namespace Xamarin.Bundler;
+
+public static class Driver {
+ public const string CorlibName = "System.Private.CoreLib";
+}
diff --git a/tools/assembly-preparer/Scaffolding/IMarkHandler.cs b/tools/assembly-preparer/Scaffolding/IMarkHandler.cs
new file mode 100644
index 000000000000..dc9286ad5610
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/IMarkHandler.cs
@@ -0,0 +1,16 @@
+namespace Mono.Linker;
+
+using Mono.Cecil;
+
+public interface IMarkHandler {
+ void Initialize (LinkContext context, MarkContext markContext);
+ // void Initialize (LinkContext context, MarkContext markContext);
+ // void ProcessAssembly (AssemblyDefinition assembly);
+ // void ProcessType (TypeDefinition type);
+ // void ProcessField (FieldDefinition field);
+ // void ProcessMethod (MethodDefinition method);
+ // void ProcessParameter (ParameterDefinition parameter);
+ // void ProcessProperty (PropertyDefinition property);
+ // void ProcessEvent (EventDefinition eventDef);
+
+}
diff --git a/tools/assembly-preparer/Scaffolding/LinkContext.cs b/tools/assembly-preparer/Scaffolding/LinkContext.cs
new file mode 100644
index 000000000000..7a882b608a22
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/LinkContext.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using Mono.Cecil;
+using Xamarin.Bundler;
+
+namespace Mono.Linker;
+
+public class LinkContext {
+ AnnotationStore annotations = new AnnotationStore ();
+ public AnnotationStore Annotations { get => annotations; }
+
+ public List Assemblies = new List ();
+ public AssemblyDefinition [] GetAssemblies () { return Assemblies.ToArray (); }
+
+ public LinkerConfiguration Configuration { get; private set; }
+
+ public LinkContext (LinkerConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+}
diff --git a/tools/assembly-preparer/Scaffolding/LinkerConfiguration.cs b/tools/assembly-preparer/Scaffolding/LinkerConfiguration.cs
new file mode 100644
index 000000000000..7ee1f7087f6d
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/LinkerConfiguration.cs
@@ -0,0 +1,76 @@
+using System;
+using Mono.Cecil;
+using Xamarin.Linker;
+using Xamarin.Tuner;
+using Mono.Linker;
+using System.Collections.Generic;
+using Xamarin.Utils;
+
+namespace Xamarin.Bundler;
+
+public class LinkerConfiguration {
+ List exceptions = new List ();
+ public List Exceptions {
+ get {
+ return exceptions;
+ }
+ }
+
+ AppBundleRewriter? abr;
+ internal AppBundleRewriter AppBundleRewriter {
+ get {
+ if (abr is null)
+ abr = new AppBundleRewriter (this);
+ return abr;
+ }
+ }
+
+ DerivedLinkContext? derivedLinkContext;
+ public DerivedLinkContext DerivedLinkContext {
+ get {
+ if (derivedLinkContext is null)
+ throw new InvalidOperationException ($"No derived link context set?");
+ return derivedLinkContext!;
+ }
+ set => derivedLinkContext = value;
+ }
+ public DerivedLinkContext Context { get => DerivedLinkContext; }
+ public Profile Profile { get => throw new NotImplementedException (); }
+ public AssemblyDefinition [] Assemblies { get => Context.GetAssemblies (); }
+
+ public ApplePlatform Platform { get; set; }
+ public string PlatformAssembly {
+ get {
+ return $"Microsoft.{Platform.AsString ()}";
+ }
+ }
+ public static LinkerConfiguration GetInstance (LinkContext context)
+ {
+ return context.Configuration;
+ }
+ public static void Report (LinkContext context, Exception exception)
+ {
+ var pe = exception as ProductException;
+ if (pe is null)
+ pe = ErrorHelper.CreateError (99, exception, "Unexpected error: {0}}", exception.Message);
+ GetInstance (context).exceptions.Add (pe);
+ }
+
+ public static void Report (LinkContext context, List exceptions)
+ {
+ foreach (var exception in exceptions) {
+ Report (context, exception);
+ }
+ }
+
+ public bool IsProductAssembly (string assemblyName)
+ {
+ return assemblyName == PlatformAssembly;
+ }
+
+ public bool IsProductAssembly (AssemblyDefinition assembly)
+ {
+ return assembly.Name.Name == PlatformAssembly;
+ }
+
+}
diff --git a/tools/assembly-preparer/Scaffolding/MarkContext.cs b/tools/assembly-preparer/Scaffolding/MarkContext.cs
new file mode 100644
index 000000000000..acfa37cb746e
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/MarkContext.cs
@@ -0,0 +1,37 @@
+namespace Mono.Linker;
+
+using System.Collections.Generic;
+using Mono.Cecil;
+
+public class MarkContext {
+ List> markTypeActions = new List> ();
+
+ // takes care of nested types as well
+ public void MarkType (TypeDefinition type)
+ {
+ foreach (var action in markTypeActions) {
+ action (type);
+ }
+
+ if (type.HasNestedTypes) {
+ foreach (var nested in type.NestedTypes) {
+ MarkType (nested);
+ }
+ }
+ }
+
+ public void RegisterMarkAssemblyAction (Action action)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void RegisterMarkTypeAction (Action action)
+ {
+ markTypeActions.Add (action);
+ }
+
+ public void RegisterMarkMethodAction (Action action)
+ {
+ throw new NotImplementedException ();
+ }
+}
diff --git a/tools/assembly-preparer/Scaffolding/Profile.cs b/tools/assembly-preparer/Scaffolding/Profile.cs
new file mode 100644
index 000000000000..bc642085fdeb
--- /dev/null
+++ b/tools/assembly-preparer/Scaffolding/Profile.cs
@@ -0,0 +1,5 @@
+namespace Mono.Linker;
+
+public class Profile {
+
+}
diff --git a/tools/assembly-preparer/assembly-preparer.csproj b/tools/assembly-preparer/assembly-preparer.csproj
new file mode 100644
index 000000000000..d12f7a6924e5
--- /dev/null
+++ b/tools/assembly-preparer/assembly-preparer.csproj
@@ -0,0 +1,132 @@
+
+
+
+ assembly-preparer
+ net$(BundledNETCoreAppTargetFrameworkVersion);netstandard2.0
+ $(DefineConstants);PRETRIM;ASSEMBLY_PREPARER
+ Library
+ true
+ latest
+ enable
+
+
+
+
+
+
+
+
+
+
+ external/tools/common/ApplePlatform.cs
+
+
+ external/tools/common/error.cs
+
+
+ external/tools/common/ErrorHelper.tools.cs
+
+
+ external/tools/dotnet-linker/AppBundleRewriter.cs
+
+
+ external/tools/dotnet-linker/Steps/ConfigurationAwareMarkHandler.cs
+
+
+ external/tools/dotnet-linker/Steps/ExceptionalMarkHandler.cs
+
+
+ external/tools/dotnet-linker/Steps/PreserveBlockCodeHandler.cs
+
+
+ external/tools/linker/CustomSymbolWriter.cs
+
+
+ external/src/ObjCRuntime/ErrorHelper.cs
+
+
+ external/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/Extensions.cs
+
+
+ external/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/linker/Linker/MethodDefinitionExtensions.cs
+
+
+ external/builds/mono-ios-sdk-destdir/ios-sources/external/linker/src/tuner/Mono.Tuner/CecilRocks.cs
+
+
+ external/tools/dotnet-linker/CecilExtensions.cs
+
+
+ external/tools/dotnet-linker/DocumentionComments.cs
+
+
+ external/tools/common/SdkVersions.cs
+
+
+
+
+
+ external/tools/mtouch/Errors.designer.cs
+ Errors.resx
+
+
+ external/tools/mtouch/Errors.resx
+ ResXFileCodeGenerator
+ Errors.designer.cs
+ Xamarin.Bundler
+ Xamarin.Bundler.Errors
+
+
+ external/tools/mtouch/Errors.cs.resx
+ Xamarin.Bundler.Errors.cs
+
+
+ external/tools/mtouch/Errors.de.resx
+ Xamarin.Bundler.Errors.de
+
+
+ external/tools/mtouch/Errors.es.resx
+ Xamarin.Bundler.Errors.es
+
+
+ external/tools/mtouch/Errors.fr.resx
+ Xamarin.Bundler.Errors.fr
+
+
+ external/tools/mtouch/Errors.it.resx
+ Xamarin.Bundler.Errors.it
+
+
+ external/tools/mtouch/Errors.ja.resx
+ Xamarin.Bundler.Errors.ja
+
+
+ external/tools/mtouch/Errors.ko.resx
+ Xamarin.Bundler.Errors.ko
+
+
+ external/tools/mtouch/Errors.pl.resx
+ Xamarin.Bundler.Errors.pl
+
+
+ external/tools/mtouch/Errors.pt-BR.resx
+ Xamarin.Bundler.Errors.pt-BR
+
+
+ external/tools/mtouch/Errors.ru.resx
+ Xamarin.Bundler.Errors.ru
+
+
+ external/tools/mtouch/Errors.tr.resx
+ Xamarin.Bundler.Errors.tr
+
+
+ external/tools/mtouch/Errors.zh-Hans.resx
+ Xamarin.Bundler.Errors.zh-Hans
+
+
+ external/tools/mtouch/Errors.zh-Hant.resx
+ Xamarin.Bundler.Errors.zh-Hant
+
+
+
diff --git a/tools/assembly-preparer/assembly-preparer.sln b/tools/assembly-preparer/assembly-preparer.sln
new file mode 100644
index 000000000000..459364162482
--- /dev/null
+++ b/tools/assembly-preparer/assembly-preparer.sln
@@ -0,0 +1,50 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "assembly-preparer", "assembly-preparer.csproj", "{93089210-F742-462A-95CA-33CFF3B4D906}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "assembly-preparer-tests", "..\..\tests\assembly-preparer\assembly-preparer-tests.csproj", "{D5C190C5-2A98-47B4-BC51-9135F1B4D18E}"
+EndProject
+Global
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Debug|x64.Build.0 = Debug|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Debug|x86.Build.0 = Debug|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Release|Any CPU.Build.0 = Release|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Release|x64.ActiveCfg = Release|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Release|x64.Build.0 = Release|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Release|x86.ActiveCfg = Release|Any CPU
+ {93089210-F742-462A-95CA-33CFF3B4D906}.Release|x86.Build.0 = Release|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Debug|x64.Build.0 = Debug|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Debug|x86.Build.0 = Debug|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Release|x64.ActiveCfg = Release|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Release|x64.Build.0 = Release|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Release|x86.ActiveCfg = Release|Any CPU
+ {D5C190C5-2A98-47B4-BC51-9135F1B4D18E}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ EndGlobalSection
+EndGlobal
diff --git a/tools/common/Application.cs b/tools/common/Application.cs
index f8901565d8c9..b40e9a208891 100644
--- a/tools/common/Application.cs
+++ b/tools/common/Application.cs
@@ -28,6 +28,7 @@
using PlatformResolver = Xamarin.Bundler.MonoMacResolver;
#elif NET && !LEGACY_TOOLS
using PlatformResolver = Xamarin.Linker.DotNetResolver;
+#elif PRETRIM
#else
#error Invalid defines
#endif
diff --git a/tools/common/Frameworks.cs b/tools/common/Frameworks.cs
index 7fb52455ad71..d649063e6bc9 100644
--- a/tools/common/Frameworks.cs
+++ b/tools/common/Frameworks.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
using Mono.Cecil;
using Xamarin.Bundler;
@@ -32,7 +32,7 @@ public string LibraryPath {
}
}
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
public bool IsFrameworkAvailableInSimulator (Application app)
{
if (VersionAvailableInSimulator is null)
@@ -688,7 +688,7 @@ public static Frameworks GetFrameworks (ApplePlatform platform, bool is_simulato
}
}
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
static void Gather (Application app, AssemblyDefinition product_assembly, HashSet frameworks, HashSet weak_frameworks, Func include_framework)
{
var namespaces = new HashSet ();
diff --git a/tools/common/Make.common b/tools/common/Make.common
index 248e8f480575..910fe4cf662d 100644
--- a/tools/common/Make.common
+++ b/tools/common/Make.common
@@ -1,5 +1,6 @@
# We check in SdkVersions.cs so that it's easier to use this file when building tests on Windows.
+all-local:: $(abspath ../common/SdkVersions.cs)
$(abspath ../common/SdkVersions.cs): ../common/SdkVersions.in.cs Makefile $(TOP)/Make.config $(TOP)/Make.versions
$(Q_GEN) sed \
-e 's/@IOS_SDK_VERSION@/$(IOS_SDK_VERSION)/g' -e 's/@TVOS_SDK_VERSION@/$(TVOS_SDK_VERSION)/' -e 's/@MACOS_SDK_VERSION@/$(MACOS_SDK_VERSION)/' \
@@ -46,6 +47,7 @@ $(abspath ../common/SdkVersions.cs): ../common/SdkVersions.in.cs Makefile $(TOP)
$(Q) if ! diff $@ $@.tmp >/dev/null; then $(CP) $@.tmp $@; git diff "$@"; echo "The file $(TOP)/tools/common/SdkVersions.cs has been automatically re-generated; please commit the changes."; exit 1; fi
$(Q) touch $@
+all-local:: $(abspath ../common/ProductConstants.cs)
$(abspath ../common/ProductConstants.cs): ../common/ProductConstants.in.cs Makefile $(TOP)/Make.config $(GIT_DIRECTORY)/index
$(Q_GEN) sed \
$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),-e 's/@$(platform)_REVISION@/$($(platform)_COMMIT_DISTANCE) ($(CURRENT_BRANCH_SED_ESCAPED): $(CURRENT_HASH))/g') \
@@ -54,3 +56,4 @@ $(abspath ../common/ProductConstants.cs): ../common/ProductConstants.in.cs Makef
\
-e "s/@PRODUCT_HASH@/$(CURRENT_HASH_LONG)/g" \
$< > $@
+
diff --git a/tools/common/Makefile b/tools/common/Makefile
new file mode 100644
index 000000000000..6a27eba55f77
--- /dev/null
+++ b/tools/common/Makefile
@@ -0,0 +1,5 @@
+TOP=../..
+
+include $(TOP)/Make.config
+include $(TOP)/mk/rules.mk
+include ../common/Make.common
diff --git a/tools/common/ProductConstants.in.cs b/tools/common/ProductConstants.in.cs
index 8272feab2785..5244ce633b68 100644
--- a/tools/common/ProductConstants.in.cs
+++ b/tools/common/ProductConstants.in.cs
@@ -1,6 +1,6 @@
using System;
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
using Xamarin.Bundler;
using Xamarin.Utils;
#endif
diff --git a/tools/common/SdkVersions.cs b/tools/common/SdkVersions.cs
index 7b6570cf5a81..8fb6385e9799 100644
--- a/tools/common/SdkVersions.cs
+++ b/tools/common/SdkVersions.cs
@@ -1,6 +1,6 @@
using System;
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
using Xamarin.Bundler;
#endif
@@ -69,7 +69,7 @@ static class SdkVersions {
public static Version XcodeVersion { get { return new Version (Xcode); } }
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
public static Version GetVersion (Application app)
{
switch (app.Platform) {
diff --git a/tools/common/SdkVersions.in.cs b/tools/common/SdkVersions.in.cs
index 560c806fa57c..5c2bdd405bcd 100644
--- a/tools/common/SdkVersions.in.cs
+++ b/tools/common/SdkVersions.in.cs
@@ -1,6 +1,6 @@
using System;
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
using Xamarin.Bundler;
#endif
@@ -69,7 +69,7 @@ static class SdkVersions {
public static Version XcodeVersion { get { return new Version (Xcode); } }
-#if MTOUCH || MMP || BUNDLER
+#if MTOUCH || MMP || BUNDLER || PRETRIM
public static Version GetVersion (Application app)
{
switch (app.Platform) {
diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs
index 37f0ea5ee52d..bd35cf230423 100644
--- a/tools/common/StaticRegistrar.cs
+++ b/tools/common/StaticRegistrar.cs
@@ -25,6 +25,7 @@
using PlatformResolver = Xamarin.Bundler.MonoMacResolver;
#elif NET
using PlatformResolver = Xamarin.Linker.DotNetResolver;
+#elif PRETRIM
#else
#error Invalid defines
#endif
diff --git a/tools/common/Target.cs b/tools/common/Target.cs
index def2a09e6bf1..03c48f7c7697 100644
--- a/tools/common/Target.cs
+++ b/tools/common/Target.cs
@@ -34,6 +34,7 @@
using LinkerOptions = Xamarin.Linker.LinkerConfiguration;
using PlatformLinkContext = Xamarin.Tuner.DerivedLinkContext;
using PlatformResolver = Xamarin.Linker.DotNetResolver;
+#elif PRETRIM
#else
#error Invalid defines
#endif
diff --git a/tools/common/cache.cs b/tools/common/cache.cs
index e11c0a1b19c4..b866eab99582 100644
--- a/tools/common/cache.cs
+++ b/tools/common/cache.cs
@@ -15,6 +15,8 @@ public class Cache {
const string NAME = "mtouch";
#elif BUNDLER
const string NAME = "dotnet-linker";
+#elif PRETRIM
+ const string NAME = "assembly-preparer";
#else
#error Wrong defines
#endif
diff --git a/tools/dotnet-linker/AppBundleRewriter.cs b/tools/dotnet-linker/AppBundleRewriter.cs
index 05d1805a7a37..7e1f48a8d854 100644
--- a/tools/dotnet-linker/AppBundleRewriter.cs
+++ b/tools/dotnet-linker/AppBundleRewriter.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
-
+using System.Reflection;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Linker;
@@ -10,6 +10,7 @@
using Xamarin.Bundler;
using Xamarin.Linker;
+using Xamarin.Utils;
#nullable enable
@@ -61,6 +62,8 @@ public AppBundleRewriter (LinkerConfiguration configuration)
// Find corlib and the platform assemblies
foreach (var asm in configuration.Assemblies) {
if (asm.Name.Name == Driver.CorlibName) {
+ if (corlib_assembly is not null)
+ throw new InvalidOperationException ($"Already have a corlib assembly named {corlib_assembly.Name}");
corlib_assembly = asm;
} else if (asm.Name.Name == configuration.PlatformAssembly) {
platform_assembly = asm;
@@ -1268,7 +1271,11 @@ public CustomAttribute CreateDynamicDependencyAttribute (string memberSignature,
return attribute;
}
+#if NET
public CustomAttribute CreateDynamicDependencyAttribute (DynamicallyAccessedMemberTypes memberTypes, TypeDefinition type)
+#else
+ public CustomAttribute CreateDynamicDependencyAttribute (int memberTypes, TypeDefinition type)
+#endif
{
var attribute = new CustomAttribute (DynamicDependencyAttribute_ctor__DynamicallyAccessedMemberTypes_Type);
// typed as 'int' because that's how the linker expects it: https://github.com/dotnet/runtime/blob/3c5ad6c677b4a3d12bc6a776d654558cca2c36a9/src/tools/illink/src/linker/Linker/DynamicDependency.cs#L97
@@ -1276,5 +1283,39 @@ public CustomAttribute CreateDynamicDependencyAttribute (DynamicallyAccessedMemb
attribute.ConstructorArguments.Add (new CustomAttributeArgument (System_Type, type));
return attribute;
}
+
+
+ public void AddDynamicDependencyAttributeToStaticConstructor (TypeDefinition onType, MethodDefinition forMethod)
+ {
+ AddDynamicDependencyAttributeToStaticConstructor (onType, DocumentationComments.GetSignature (forMethod));
+ }
+
+ public void AddDynamicDependencyAttributeToStaticConstructor (TypeDefinition onType, FieldDefinition forField)
+ {
+ AddDynamicDependencyAttributeToStaticConstructor (onType, DocumentationComments.GetSignature (forField));
+ }
+
+ void AddDynamicDependencyAttributeToStaticConstructor (TypeDefinition onType, string signature)
+ {
+ ClearCurrentAssembly ();
+ SetCurrentAssembly (onType.Module.Assembly);
+
+ var cctor = GetOrCreateStaticConstructor (onType);
+ var attrib = CreateDynamicDependencyAttribute (signature, onType);
+ cctor.CustomAttributes.Add (attrib);
+
+ ClearCurrentAssembly ();
+ }
+ MethodDefinition GetOrCreateStaticConstructor (TypeDefinition type)
+ {
+ var staticCtor = type.GetTypeConstructor ();
+ if (staticCtor is null) {
+ staticCtor = type.AddMethod (".cctor", Mono.Cecil.MethodAttributes.Private | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.RTSpecialName | Mono.Cecil.MethodAttributes.SpecialName | Mono.Cecil.MethodAttributes.Static, System_Void);
+ staticCtor.CreateBody (out var il);
+ il.Emit (OpCodes.Ret);
+ }
+
+ return staticCtor;
+ }
}
}
diff --git a/tools/dotnet-linker/Steps/PreserveBlockCodeHandler.cs b/tools/dotnet-linker/Steps/PreserveBlockCodeHandler.cs
index 63dfee5b5742..9aaebe19ead9 100644
--- a/tools/dotnet-linker/Steps/PreserveBlockCodeHandler.cs
+++ b/tools/dotnet-linker/Steps/PreserveBlockCodeHandler.cs
@@ -2,7 +2,8 @@
using System.Linq;
using Mono.Cecil;
-
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
using Mono.Linker;
using Mono.Linker.Steps;
using Mono.Tuner;
@@ -18,6 +19,7 @@ public class PreserveBlockCodeHandler : ConfigurationAwareMarkHandler {
protected override string Name { get; } = "Preserve Block Code";
protected override int ErrorCode { get; } = 2240;
+ AppBundleRewriter abr { get { return Configuration.AppBundleRewriter; } }
public override void Initialize (LinkContext context, MarkContext markContext)
{
base.Initialize (context);
@@ -79,9 +81,16 @@ and the Invoke method.
if (method is null)
return;
- // The type was used, so preserve the method and field
- Context.Annotations.Mark (method);
- Context.Annotations.Mark (field);
+ // Preserve the method and field on the static constructor of the type.
+ abr.AddDynamicDependencyAttributeToStaticConstructor (type, method);
+ abr.AddDynamicDependencyAttributeToStaticConstructor (type, field);
+ // Remove the BeforeFieldInit attribute from the type, otherwise the linker may trim away the static constructor, and taking our DynamicDependency attributes with it.
+ type.Attributes &= ~TypeAttributes.BeforeFieldInit;
+
+#if ASSEMBLY_PREPARER
+ abr.SetCurrentAssembly (type.Module.Assembly);
+ abr.SaveCurrentAssembly ();
+#endif
}
}
}
diff --git a/tools/linker/CustomSymbolWriter.cs b/tools/linker/CustomSymbolWriter.cs
index eadad6cfaebf..db4f79b22316 100644
--- a/tools/linker/CustomSymbolWriter.cs
+++ b/tools/linker/CustomSymbolWriter.cs
@@ -78,7 +78,7 @@ static ImageDebugHeaderEntry ProcessEntry (ImageDebugHeaderEntry entry)
public void Write (MethodDebugInformation info) => _symbolWriter.Write (info);
public void Write () => _symbolWriter.Write ();
public void Dispose () => _symbolWriter.Dispose ();
-#if NET && !LEGACY_TOOLS
+#if (NET && !LEGACY_TOOLS) || ASSEMBLY_PREPARER
public void Write (ICustomDebugInformationProvider provider) => _symbolWriter.Write (provider);
#endif
}