From 443aff7f6cfed9ce5453a4298c9f3bbcb787a4b9 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 29 Apr 2026 15:13:50 -0500 Subject: [PATCH] [xabt] Use Load() in RunPipeline instead of pre-loading all assemblies The pre-loading approach in #11208 eagerly loads ALL ResolvedAssemblies into the resolver cache. If any of those assemblies reference netstandard.dll (e.g. netstandard2.1 NuGet packages), Cecil lazy reference resolution will fail with FileNotFoundException since netstandard.dll is not in the search directories. Instead, use resolver.Load(source.ItemSpec) in RunPipeline to load each assembly from its exact path when processed. This ensures the correct TFM version is loaded without eagerly loading all assemblies upfront. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tasks/AssemblyModifierPipeline.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs b/src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs index 69cfedb54b4..a6e5abbc0ac 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs @@ -102,19 +102,13 @@ public override bool RunTask () var resolver = new DirectoryAssemblyResolver (this.CreateTaskLogger (), loadDebugSymbols: ReadSymbols, loadReaderParameters: readerParameters); - // Add SearchDirectories and pre-load ResolvedAssemblies into the resolver cache. - // Pre-loading ensures the correct TFM version is cached before any Cecil lazy - // reference resolution can find wrong-TFM copies from search directories (e.g., - // a net11.0 copy in a referencing project's output directory). + // Add SearchDirectories for the current architecture's ResolvedAssemblies foreach (var kvp in perArchAssemblies [sourceArch]) { ITaskItem assembly = kvp.Value; var path = Path.GetFullPath (Path.GetDirectoryName (assembly.ItemSpec)); if (!resolver.SearchDirectories.Contains (path)) { resolver.SearchDirectories.Add (path); } - if (resolver.Load (assembly.ItemSpec) == null) { - Log.LogDebugMessage ($"Could not pre-load assembly '{assembly.ItemSpec}' into resolver cache."); - } } // Set up the FixAbstractMethodsStep and AddKeepAlivesStep @@ -166,7 +160,11 @@ protected virtual void BuildPipeline (AssemblyPipeline pipeline, MSBuildLinkCont void RunPipeline (AssemblyPipeline pipeline, ITaskItem source, ITaskItem destination) { - var assembly = pipeline.Resolver.GetAssembly (source.ItemSpec); + // Use Load with the exact ItemSpec path to ensure the correct TFM version + // is loaded, rather than GetAssembly which strips the path and resolves by + // name through search directories (which may find wrong-TFM copies). + var assembly = pipeline.Resolver.Load (source.ItemSpec) + ?? throw new FileNotFoundException ($"Could not load assembly '{source.ItemSpec}'.", source.ItemSpec); var context = new StepContext (source, destination) { CodeGenerationTarget = codeGenerationTarget,