From 846e359f7672b80db5f75ca14cda4cf2c1e084b0 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 17 Jul 2018 17:14:26 -0500 Subject: [PATCH] [xabuild] MSBuild assemblies should not "Copy Local" Mono 2018-04 (or 5.14.x) has some changes to MSBuild assemblies that cause the following failure when using `xabuild.exe`: Mono: The following assembly referenced from monodroid/external/xamarin-android/bin/Debug/bin/Microsoft.Build.Tasks.Core.dll could not be loaded: Assembly: System.Reflection.Metadata (assemblyref_index=7) Version: 1.3.0.0 Public Key: b03f5f7f11d50a3a Currently `xabuild.exe` is referencing various MSBuild assemblies that get copied into `bin/$(Configuration)/bin` and shipped in the OSS zip. This isn't exactly desirable, since we don't really want to ship these assemblies... These assemblies are OS-specific (as far as I can tell), I noticed that these assemblies coming from a zip built on macOS do not work on Windows. `xabuild.exe` does not need to reference any MSBuild assemblies, and we can use reflection + custom assembly loading to load MSBuild. This keeps `bin/Debug/bin` free of additional assemblies, and now only contains a few files: - xabuild - xabuild.exe - xabuild.exe.config - xabuild.pdb By using the `AppDomain.AssemblyResolve` event, we can add some code to probe the MSBuild bin directory for assemblies. If not found, we can return `null` and let the runtime do its default behavior. --- tools/xabuild/XABuild.cs | 51 +++++++++++++++++++++++++++++++++--- tools/xabuild/xabuild.csproj | 7 ----- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/tools/xabuild/XABuild.cs b/tools/xabuild/XABuild.cs index b230b71cd0c..52af2e1416e 100644 --- a/tools/xabuild/XABuild.cs +++ b/tools/xabuild/XABuild.cs @@ -1,7 +1,7 @@ -using Microsoft.Build.CommandLine; -using System; +using System; using System.IO; using System.Linq; +using System.Reflection; using System.Threading; using System.Xml; @@ -9,6 +9,17 @@ namespace Xamarin.Android.Build { class XABuild { + static Assembly Load (AssemblyName name, string path) + { + Console.WriteLine ($"[xabuild] custom assembly resolution '{name.FullName}' -> '{path}'"); + + //NOTE: may/may not be more correct? + //name.CodeBase = path; + //return Assembly.Load (name); + + return Assembly.LoadFrom (path); + } + [MTAThread] static int Main () { @@ -19,6 +30,25 @@ static int Main () return 1; } + AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => { + var name = new AssemblyName (e.Name); + var path = Path.Combine (paths.MSBuildBin, name.Name + ".dll"); + if (File.Exists (path)) { + return Load (name, path); + } + path = Path.Combine (paths.MSBuildBin, name.Name + ".exe"); + if (File.Exists (path)) { + return Load (name, path); + } + + if (e.RequestingAssembly != null) { + Console.WriteLine ($"[xabuild] assembly `{e.Name}` requested by `{e.RequestingAssembly.FullName}` not found at path `{paths.MSBuildBin}`, using default runtime behavior..."); + } else { + Console.WriteLine ($"[xabuild] assembly `{e.Name}` not found at path `{paths.MSBuildBin}`, using default runtime behavior..."); + } + return null; //Let the default runtime behavior occur + }; + //Create a custom xabuild.exe.config var xml = CreateConfig (paths); @@ -45,7 +75,22 @@ static int Main () } } - int exitCode = MSBuildApp.Main (); + //NOTE: Using Reflection to call MSBuildApp.Main allows us to wire up AppDomain.AssemblyResolve. + // Running on Mono, I could not even get a static ctor to work. It was loading MSBuild.dll up front. + var typeName = "Microsoft.Build.CommandLine.MSBuildApp, MSBuild"; + var type = Type.GetType (typeName); + if (type == null) { + Console.WriteLine ($"Unable to load type `{typeName}`!"); + return 1; + } + var method = type.GetMethod ("Main", BindingFlags.Static | BindingFlags.Public); + if (method == null) { + Console.WriteLine ($"Unable to find method `Main` on type `{type.FullName}`!"); + return 1; + } + + var main = (Func)method.CreateDelegate (typeof (Func)); + int exitCode = main (); if (exitCode != 0) { Console.WriteLine ($"MSBuildApp.Main exited with {exitCode}, xabuild configuration is:"); diff --git a/tools/xabuild/xabuild.csproj b/tools/xabuild/xabuild.csproj index fcbedb56250..2af5374eb00 100644 --- a/tools/xabuild/xabuild.csproj +++ b/tools/xabuild/xabuild.csproj @@ -1,7 +1,6 @@  - Debug AnyCPU @@ -35,9 +34,6 @@ 4 - - $(MSBuildReferencePath)\MSBuild.$(_MSBuildExtension) - @@ -60,7 +56,4 @@ - - - \ No newline at end of file