diff --git a/tools/assembly-preparer/AssemblyPreparer.cs b/tools/assembly-preparer/AssemblyPreparer.cs index 520bd720ccd..6e552be7d19 100644 --- a/tools/assembly-preparer/AssemblyPreparer.cs +++ b/tools/assembly-preparer/AssemblyPreparer.cs @@ -225,7 +225,10 @@ bool RunSteps (IList steps, out List e // Subscribe once the assemblies have been loaded: accessing the AppBundleRewriter before // that point would create it without finding the corlib and platform assemblies. if (assemblySavedHandler is null && configuration.Assemblies.Count > 0) { - assemblySavedHandler = (_) => currentStepModifiedAssemblies = true; + assemblySavedHandler = (asm) => { + currentStepModifiedAssemblies = true; + configuration.ModifiedAssemblies.Add (asm); + }; configuration.AppBundleRewriter.AssemblySaved += assemblySavedHandler; } diff --git a/tools/assembly-preparer/SaveAssembliesStep.cs b/tools/assembly-preparer/SaveAssembliesStep.cs index 1b23b2f5bd9..7addcabe6d3 100644 --- a/tools/assembly-preparer/SaveAssembliesStep.cs +++ b/tools/assembly-preparer/SaveAssembliesStep.cs @@ -37,16 +37,17 @@ protected override void TryProcess () switch (action) { case AssemblyAction.Copy: case AssemblyAction.CopyUsed: - if (configuration.Application.IsPostProcessingAssemblies && assembly.InputPath != assembly.OutputPath) { - // During post-processing, copy unchanged assemblies to the output directory - // so all assemblies are in the same directory (required for AOT compilation). - CopyAssemblyToOutput (assembly.InputPath, assembly.OutputPath); - } else { - assembly.OutputPath = assembly.InputPath; - } + OutputWithoutRewriting (assembly); continue; case AssemblyAction.Link: case AssemblyAction.Save: + if (!configuration.ModifiedAssemblies.Contains (assemblyDefinition)) { + // The assembly is marked to be saved (e.g. it's part of the set of assemblies to + // trim), but the assembly-preparer didn't actually modify it, so there's no need to + // re-serialize it - just output the original assembly. + OutputWithoutRewriting (assembly); + continue; + } log.Log ($"Saving {assembly.InputPath} to {assembly.OutputPath}"); break; default: @@ -80,6 +81,17 @@ protected override void TryProcess () } } + void OutputWithoutRewriting (Xamarin.Build.AssemblyPreparerInfo assembly) + { + if (Configuration.Application.IsPostProcessingAssemblies && assembly.InputPath != assembly.OutputPath) { + // During post-processing, copy unchanged assemblies to the output directory + // so all assemblies are in the same directory (required for AOT compilation). + CopyAssemblyToOutput (assembly.InputPath, assembly.OutputPath); + } else { + assembly.OutputPath = assembly.InputPath; + } + } + void RemoveCrossGen (AssemblyDefinition assemblyDefinition) { // Drop crossgened code from the assembly diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs index ca103ddf655..31d012ddd3a 100644 --- a/tools/dotnet-linker/LinkerConfiguration.cs +++ b/tools/dotnet-linker/LinkerConfiguration.cs @@ -97,6 +97,9 @@ public List Exceptions { public List Assemblies => Application.LinkContext.Assemblies; public required List AssemblyInfos; public List<(string Path, AssemblyDefinition Assembly, string? OriginatingAssembly)> AddedAssemblies = new (); + // The set of assemblies that were modified (i.e. that AppBundleRewriter.SaveAssembly was called for). + // Assemblies that aren't modified don't need to be re-serialized when saved. + public HashSet ModifiedAssemblies = new (); #else // The list of assemblies is populated in CollectAssembliesStep. public List Assemblies = new List ();