diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 635443931e..333eaf401f 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -137,6 +137,7 @@ PlatformAssembly=$(_PlatformAssemblyName).dll SdkVersion=$(_SdkVersion) TargetArchitectures=$(TargetArchitectures) + TargetFramework=$(_ComputedTargetFrameworkMoniker) Verbosity=$(_BundlerVerbosity) <_ExtraTrimmerArgs>$(_ExtraTrimmerArgs) --custom-data "LinkerOptionsFile=$(_CustomLinkerOptionsFile)" @@ -181,6 +182,18 @@ + + + + + + + + + + + + @@ -315,8 +328,9 @@ ))] @@ -84,7 +84,7 @@ namespace Registrar { } abstract partial class Registrar { -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER public Application App { get; protected set; } #endif @@ -124,7 +124,7 @@ namespace Registrar { public bool IsInformalProtocol; public bool IsWrapper; public bool IsGeneric; -#if !MTOUCH && !MMP +#if !MTOUCH && !MMP && !BUNDLER public IntPtr Handle; #else public TType ProtocolWrapperType; @@ -140,7 +140,7 @@ namespace Registrar { public bool IsCategory { get { return CategoryAttribute != null; } } -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER HashSet all_protocols; // This contains all protocols in the type hierarchy. // Given a type T that implements a protocol with super protocols: @@ -585,7 +585,7 @@ namespace Registrar { } } -#if !MMP && !MTOUCH +#if !MMP && !MTOUCH && !BUNDLER // The ArgumentSemantic enum is public, and // I don't want to add another enum value there which // is just an internal implementation detail, so just @@ -832,7 +832,7 @@ namespace Registrar { if (trampoline != Trampoline.None) return trampoline; -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER throw ErrorHelper.CreateError (8018, Errors.MT8018); #else var mi = (System.Reflection.MethodInfo) Method; @@ -1001,7 +1001,7 @@ namespace Registrar { } internal class ObjCField : ObjCMember { -#if !MTOUCH && !MMP +#if !MTOUCH && !MMP && !BUNDLER public int Size; public byte Alignment; #else @@ -1259,7 +1259,7 @@ namespace Registrar { #if MONOMAC internal const string AssemblyName = "Xamarin.Mac"; #else -#if MTOUCH +#if MTOUCH || BUNDLER internal string AssemblyName { get { @@ -1305,7 +1305,7 @@ namespace Registrar { } } -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER // "#if MTOUCH" code does not need locking when accessing 'types', because mtouch is single-threaded. public Dictionary Types { get { return types; } @@ -1884,7 +1884,7 @@ namespace Registrar { protected bool SupportsModernObjectiveC { get { -#if MTOUCH || MONOTOUCH +#if MTOUCH || MONOTOUCH || BUNDLER return true; #elif MMP return App.Is64Build; @@ -1935,7 +1935,7 @@ namespace Registrar { isInformalProtocol = pAttr.IsInformal; isProtocol = true; -#if MMP || MTOUCH +#if MMP || MTOUCH || BUNDLER if (pAttr.FormalSinceVersion != null && pAttr.FormalSinceVersion > App.SdkVersion) isInformalProtocol = !isInformalProtocol; #endif @@ -1969,7 +1969,7 @@ namespace Registrar { objcType.VerifyAdoptedProtocolsNames (ref exceptions); objcType.BaseType = isProtocol ? null : (baseObjCType ?? objcType); objcType.Protocols = GetProtocols (objcType, ref exceptions); -#if MMP || MTOUCH +#if MMP || MTOUCH || BUNDLER objcType.ProtocolWrapperType = (isProtocol && !isInformalProtocol) ? GetProtocolAttributeWrapperType (objcType.Type) : null; #endif objcType.IsWrapper = (isProtocol && !isInformalProtocol) ? (GetProtocolAttributeWrapperType (objcType.Type) != null) : (objcType.RegisterAttribute != null && objcType.RegisterAttribute.IsWrapper); @@ -2064,7 +2064,7 @@ namespace Registrar { } } -#if MMP || MTOUCH +#if MMP || MTOUCH || BUNDLER // Special fields if (is_first_nonWrapper) { // static registrar @@ -2131,7 +2131,7 @@ namespace Registrar { } } else { TMethod method = null; -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER method = attrib.Method; #endif var objcMethod = new ObjCMethod (this, objcType, method) { @@ -2180,7 +2180,7 @@ namespace Registrar { objcType.Add (new ObjCField () { DeclaringType = objcType, Name = ca.Name ?? GetPropertyName (property), -#if !MTOUCH && !MMP +#if !MTOUCH && !MMP && !BUNDLER Size = Is64Bits ? 8 : 4, Alignment = (byte) (Is64Bits ? 3 : 2), #endif @@ -2460,7 +2460,7 @@ namespace Registrar { if (exceptions.Count > 0) { Exception ae = exceptions.Count == 1 ? exceptions [0] : new AggregateException (exceptions); -#if !MTOUCH && !MMP +#if !MTOUCH && !MMP && !BUNDLER Runtime.NSLog (ae.ToString ()); #endif throw ae; @@ -2689,7 +2689,7 @@ namespace Registrar { System.Threading.Monitor.Exit (types); } -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER internal static void NSLog (string format, params object [] args) { Console.WriteLine (format, args); diff --git a/src/ObjCRuntime/RuntimeOptions.cs b/src/ObjCRuntime/RuntimeOptions.cs index f99690ed17..24acb310ee 100644 --- a/src/ObjCRuntime/RuntimeOptions.cs +++ b/src/ObjCRuntime/RuntimeOptions.cs @@ -2,7 +2,7 @@ using System; using System.IO; using System.Text; -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER using Mono.Cecil; using Xamarin.Linker; #else @@ -11,7 +11,7 @@ using Foundation; using ObjCRuntime; #endif -#if MMP || MMP_TEST || MTOUCH +#if MMP || MMP_TEST || MTOUCH || BUNDLER namespace Xamarin.Bundler { #else namespace ObjCRuntime { @@ -24,7 +24,7 @@ namespace ObjCRuntime { string http_message_handler; -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER /* * This section is only used by the tools */ diff --git a/tests/bindings-test/dotnet/shared.targets b/tests/bindings-test/dotnet/shared.targets index 76425ccb68..ffc5acd1e7 100644 --- a/tests/bindings-test/dotnet/shared.targets +++ b/tests/bindings-test/dotnet/shared.targets @@ -45,7 +45,7 @@ Registrar.cs - + TestRuntime.cs diff --git a/tests/bindings-test2/dotnet/iOS/bindings-test2.csproj b/tests/bindings-test2/dotnet/iOS/bindings-test2.csproj index 5a7c3cbd34..662296c7d1 100644 --- a/tests/bindings-test2/dotnet/iOS/bindings-test2.csproj +++ b/tests/bindings-test2/dotnet/iOS/bindings-test2.csproj @@ -3,6 +3,11 @@ ios-fat iOS + ..\..\.. + + + + diff --git a/tests/bindings-test2/dotnet/macOS/bindings-test2.csproj b/tests/bindings-test2/dotnet/macOS/bindings-test2.csproj index e4c2fdcd47..43be3f9d00 100644 --- a/tests/bindings-test2/dotnet/macOS/bindings-test2.csproj +++ b/tests/bindings-test2/dotnet/macOS/bindings-test2.csproj @@ -3,6 +3,11 @@ macos macOS + ..\..\.. + + + + diff --git a/tests/bindings-test2/dotnet/shared.targets b/tests/bindings-test2/dotnet/shared.targets index db29771015..ef600332be 100644 --- a/tests/bindings-test2/dotnet/shared.targets +++ b/tests/bindings-test2/dotnet/shared.targets @@ -8,17 +8,10 @@ latest true - $(MSBuildThisFileDirectory)\..\.. $(RootTestsDirectory)\bindings-test2 $(RootTestsDirectory)\test-libraries - - - - - - diff --git a/tests/bindings-test2/dotnet/tvOS/bindings-test2.csproj b/tests/bindings-test2/dotnet/tvOS/bindings-test2.csproj index de9b244243..9bf780dbaf 100644 --- a/tests/bindings-test2/dotnet/tvOS/bindings-test2.csproj +++ b/tests/bindings-test2/dotnet/tvOS/bindings-test2.csproj @@ -3,6 +3,11 @@ tvos-fat tvOS + ..\..\.. + + + + diff --git a/tests/bindings-test2/dotnet/watchOS/bindings-test2.csproj b/tests/bindings-test2/dotnet/watchOS/bindings-test2.csproj index 09be0a846b..332cb51a9c 100644 --- a/tests/bindings-test2/dotnet/watchOS/bindings-test2.csproj +++ b/tests/bindings-test2/dotnet/watchOS/bindings-test2.csproj @@ -3,6 +3,11 @@ watchos-fat watchOS + ..\..\.. + + + + diff --git a/tests/dotnet/UnitTests/ProjectTest.cs b/tests/dotnet/UnitTests/ProjectTest.cs index 8a42171ac4..33e5b67475 100644 --- a/tests/dotnet/UnitTests/ProjectTest.cs +++ b/tests/dotnet/UnitTests/ProjectTest.cs @@ -258,11 +258,77 @@ namespace Xamarin.Tests { Assert.That (ad.MainModule.Resources [0].Name, Is.EqualTo ("libtest2.a"), "libtest2.a"); } - void CopyDotNetSupportingFiles (string targetDirectory) + [TestCase ("iOS")] + [TestCase ("tvOS")] + // [TestCase ("watchOS")] // No watchOS Touch.Client project for .NET yet + // [TestCase ("macOS")] // No macOS Touch.Client project for .NET yet + public void BuildInterdependentBindingProjects (string platform) + { + var assemblyName = "interdependent-binding-projects"; + var dotnet_bindings_dir = Path.Combine (Configuration.SourceRoot, "tests", assemblyName, "dotnet"); + var project_dir = Path.Combine (dotnet_bindings_dir, platform); + var project_path = Path.Combine (project_dir, $"{assemblyName}.csproj"); + + Clean (project_path); + CopyDotNetSupportingFiles (dotnet_bindings_dir); + CopyDotNetSupportingFiles (dotnet_bindings_dir.Replace (assemblyName, "bindings-test")); + CopyDotNetSupportingFiles (dotnet_bindings_dir.Replace (assemblyName, "bindings-test2")); + var cleanupSupportFiles = CopyDotNetSupportingFiles (Path.Combine (Configuration.SourceRoot, "external", "Touch.Unit", "Touch.Client/dotnet")); + try { + var result = DotNet.AssertBuild (project_path, verbosity); + var lines = result.StandardOutput.ToString ().Split ('\n'); + // Find the resulting binding assembly from the build log + var assemblies = lines. + Select (v => v.Trim ()). + Where (v => { + if (v.Length < 10) + return false; + if (v [0] != '/') + return false; + if (!v.EndsWith ($"{assemblyName}.dll", StringComparison.Ordinal)) + return false; + if (!v.Contains ("/bin/", StringComparison.Ordinal)) + return false; + if (!v.Contains ($"{assemblyName}.app", StringComparison.Ordinal)) + return false; + return true; + }); + Assert.That (assemblies, Is.Not.Empty, "Assemblies"); + // Make sure there's no other assembly confusing our logic + assemblies = assemblies.Distinct (); + Assert.That (assemblies.Count (), Is.EqualTo (1), $"Unique assemblies: {string.Join (", ", assemblies)}"); + var asm = assemblies.First (); + Assert.That (asm, Does.Exist, "Assembly existence"); + + // Verify that the resources + var asmDir = Path.GetDirectoryName (asm); + var ad = AssemblyDefinition.ReadAssembly (asm, new ReaderParameters { ReadingMode = ReadingMode.Deferred }); + Assert.That (ad.MainModule.Resources.Count, Is.EqualTo (0), "0 resources for interdependent-binding-projects.dll"); + + var ad1 = AssemblyDefinition.ReadAssembly (Path.Combine (asmDir, "bindings-test.dll"), new ReaderParameters { ReadingMode = ReadingMode.Deferred }); + Assert.That (ad1.MainModule.Resources.Count, Is.EqualTo (1), "1 resource for bindings-test.dll"); + Assert.That (ad1.MainModule.Resources [0].Name, Is.EqualTo ("libtest.a"), "libtest.a - bindings-test.dll"); + + var ad2 = AssemblyDefinition.ReadAssembly (Path.Combine (asmDir, "bindings-test2.dll"), new ReaderParameters { ReadingMode = ReadingMode.Deferred }); + Assert.That (ad2.MainModule.Resources.Count, Is.EqualTo (1), "1 resource for bindings-test2.dll"); + Assert.That (ad2.MainModule.Resources [0].Name, Is.EqualTo ("libtest2.a"), "libtest2.a - bindings-test2.dll"); + } finally { + foreach (var file in cleanupSupportFiles) + File.Delete (file); + } + } + + string[] CopyDotNetSupportingFiles (string targetDirectory) { var srcDirectory = Path.Combine (Configuration.SourceRoot, "tests", "dotnet"); - foreach (var fn in new string [] { "global.json", "NuGet.config" }) - File.Copy (Path.Combine (srcDirectory, fn), Path.Combine (targetDirectory, fn), true); + var files = new string [] { "global.json", "NuGet.config" }; + var targets = new string [files.Length]; + for (var i = 0; i < files.Length; i++) { + var fn = files [i]; + targets [i] = Path.Combine (targetDirectory, fn); + File.Copy (Path.Combine (srcDirectory, fn), targets [i], true); + } + return targets; } void AssertThatLinkerExecuted (ExecutionResult result) diff --git a/tests/interdependent-binding-projects/dotnet/.gitignore b/tests/interdependent-binding-projects/dotnet/.gitignore new file mode 100644 index 0000000000..71d64b8653 --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/.gitignore @@ -0,0 +1,3 @@ +global.json +NuGet.config + diff --git a/tests/interdependent-binding-projects/dotnet/iOS/Info.plist b/tests/interdependent-binding-projects/dotnet/iOS/Info.plist new file mode 100644 index 0000000000..0c59aa4d9d --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/iOS/Info.plist @@ -0,0 +1,19 @@ + + + + + CFBundleDisplayName + InterdependentBindingProject + CFBundleIdentifier + com.xamarin.dotnet.interdependentbindingprojects + CFBundleName + InterdependentBindingProject + MinimumOSVersion + 7.0 + UIDeviceFamily + + 1 + 2 + + + diff --git a/tests/interdependent-binding-projects/dotnet/iOS/interdependent-binding-projects.csproj b/tests/interdependent-binding-projects/dotnet/iOS/interdependent-binding-projects.csproj new file mode 100644 index 0000000000..2f752a63f4 --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/iOS/interdependent-binding-projects.csproj @@ -0,0 +1,30 @@ + + + + net5.0 + Exe + true + latest + ios-x64 + xamarinios10;$(AssetTargetFallback) + ..\..\..\ + + $(DefaultItemExcludes);packages/**; + $(RootTestsDirectory)\..\product.snk + + + + + + + + + + + + + + + + + diff --git a/tests/interdependent-binding-projects/dotnet/macOS/Info.plist b/tests/interdependent-binding-projects/dotnet/macOS/Info.plist new file mode 100644 index 0000000000..3a70a4c319 --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/macOS/Info.plist @@ -0,0 +1,14 @@ + + + + + CFBundleDisplayName + InterdependentBindingProject + CFBundleIdentifier + com.xamarin.dotnet.interdependentbindingprojects + CFBundleName + CFBundleIdentifier + LSMinimumSystemVersion + 10.9 + + diff --git a/tests/interdependent-binding-projects/dotnet/macOS/interdependent-binding-projects.csproj b/tests/interdependent-binding-projects/dotnet/macOS/interdependent-binding-projects.csproj new file mode 100644 index 0000000000..9b8c2d5528 --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/macOS/interdependent-binding-projects.csproj @@ -0,0 +1,26 @@ + + + + net5.0 + Exe + true + latest + osx-x64 + ..\..\..\ + + $(DefaultItemExcludes);packages/**; + $(RootTestsDirectory)\..\product.snk + + + + + + + + + + + + + + diff --git a/tests/interdependent-binding-projects/dotnet/tvOS/Info.plist b/tests/interdependent-binding-projects/dotnet/tvOS/Info.plist new file mode 100644 index 0000000000..361708d682 --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/tvOS/Info.plist @@ -0,0 +1,18 @@ + + + + + CFBundleDisplayName + InterdependentBindingProject + CFBundleIdentifier + com.xamarin.dotnet.interdependentbindingprojects + CFBundleName + InterdependentBindingProject + MinimumOSVersion + 9.0 + UIDeviceFamily + + 3 + + + diff --git a/tests/interdependent-binding-projects/dotnet/tvOS/interdependent-binding-projects.csproj b/tests/interdependent-binding-projects/dotnet/tvOS/interdependent-binding-projects.csproj new file mode 100644 index 0000000000..7629282f02 --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/tvOS/interdependent-binding-projects.csproj @@ -0,0 +1,30 @@ + + + + net5.0 + Exe + true + latest + tvos-x64 + xamarintvos10;$(AssetTargetFallback) + ..\..\..\ + + $(DefaultItemExcludes);packages/**; + $(RootTestsDirectory)\..\product.snk + + + + + + + + + + + + + + + + + diff --git a/tests/interdependent-binding-projects/dotnet/watchOS/Info.plist b/tests/interdependent-binding-projects/dotnet/watchOS/Info.plist new file mode 100644 index 0000000000..710fcccd29 --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/watchOS/Info.plist @@ -0,0 +1,35 @@ + + + + + CFBundleDisplayName + InterdependentBindingProject + CFBundleIdentifier + com.xamarin.dotnet.interdependentbindingprojects_watch.watchkitapp.watchkitextension + CFBundleName + InterdependentBindingProject + MinimumOSVersion + 2.0 + UIDeviceFamily + + 4 + + RemoteInterfacePrincipleClass + InterfaceController + NSExtension + + NSExtensionAttributes + + WKAppBundleIdentifier + com.xamarin.dotnet.interdependentbindingprojects_watch.watchkitapp + + NSExtensionPointIdentifier + com.apple.watchkit + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + + diff --git a/tests/interdependent-binding-projects/dotnet/watchOS/interdependent-binding-projects.csproj b/tests/interdependent-binding-projects/dotnet/watchOS/interdependent-binding-projects.csproj new file mode 100644 index 0000000000..76227cb41e --- /dev/null +++ b/tests/interdependent-binding-projects/dotnet/watchOS/interdependent-binding-projects.csproj @@ -0,0 +1,26 @@ + + + + net5.0 + Exe + true + latest + watchos-x86 + ..\..\..\ + + $(DefaultItemExcludes);packages/**; + $(RootTestsDirectory)\..\product.snk + + + + + + + + + + + + + + diff --git a/tests/xharness/Harness.cs b/tests/xharness/Harness.cs index c2bb0ba34b..23afae1056 100644 --- a/tests/xharness/Harness.cs +++ b/tests/xharness/Harness.cs @@ -371,7 +371,7 @@ namespace Xharness { void AutoConfigureIOS () { - var test_suites = new string [] { "monotouch-test", "framework-test", "interdependent-binding-projects" }; + var test_suites = new string [] { "monotouch-test", "framework-test" }; var library_projects = new string [] { "BundledResources", "EmbeddedResources", "bindings-test2", "bindings-framework-test" }; var fsharp_test_suites = new string [] { "fsharp" }; var fsharp_library_projects = new string [] { "fsharplibrary" }; @@ -387,6 +387,8 @@ namespace Xharness { IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "bindings-test", "iOS", "bindings-test.csproj")), false) { Name = "bindings-test" }); + IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "interdependent-binding-projects", "interdependent-binding-projects.csproj"))) { Name = "interdependent-binding-projects" }); + IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "interdependent-binding-projects", "dotnet", "iOS", "interdependent-binding-projects.csproj"))) { Name = "interdependent-binding-projects", IsDotNetProject = true, SkipiOSVariation = false, SkiptvOSVariation = true, SkipwatchOSVariation = true, SkipTodayExtensionVariation = true, SkipDeviceVariations = true, SkipiOS32Variation = true, }); IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "introspection", "iOS", "introspection-ios.csproj"))) { Name = "introspection" }); IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "introspection", "iOS", "introspection-ios-dotnet.csproj"))) { Name = "introspection", IsDotNetProject = true, SkipiOSVariation = false, SkiptvOSVariation = false, SkipwatchOSVariation = true, SkipTodayExtensionVariation = true, SkipDeviceVariations = true, SkipiOS32Variation = true, }); IOSTestProjects.Add (new iOSTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "linker", "ios", "dont link", "dont link.csproj"))) { Configurations = new string [] { "Debug", "Release" } }); diff --git a/tests/xharness/Jenkins/Jenkins.cs b/tests/xharness/Jenkins/Jenkins.cs index 281764cf85..2007e2d15b 100644 --- a/tests/xharness/Jenkins/Jenkins.cs +++ b/tests/xharness/Jenkins/Jenkins.cs @@ -223,7 +223,7 @@ namespace Xharness.Jenkins { TestProject = buildDotNetTestsProject, Platform = TestPlatform.All, TestName = "DotNet tests", - Timeout = TimeSpan.FromMinutes (5), + Timeout = TimeSpan.FromMinutes (15), Ignored = !IncludeDotNet, }; Tasks.Add (runDotNetTests); diff --git a/tests/xharness/Jenkins/MacTestTasksEnumerable.cs b/tests/xharness/Jenkins/MacTestTasksEnumerable.cs index 0bdadab2d6..c56b7d5e7a 100644 --- a/tests/xharness/Jenkins/MacTestTasksEnumerable.cs +++ b/tests/xharness/Jenkins/MacTestTasksEnumerable.cs @@ -81,7 +81,7 @@ namespace Xharness.Jenkins { foreach (var config in configurations) { MSBuildTask build = new MSBuildTask (jenkins: jenkins, testProject: project, processManager: processManager); build.Platform = platform; - build.CloneTestProject (jenkins.MainLog, processManager, project); + build.CloneTestProject (jenkins.MainLog, processManager, project, HarnessConfiguration.RootDirectory); build.ProjectConfiguration = config; build.ProjectPlatform = project.Platform; build.SpecifyPlatform = false; diff --git a/tests/xharness/Jenkins/RunDeviceTasksFactory.cs b/tests/xharness/Jenkins/RunDeviceTasksFactory.cs index 222bbef5a3..b94a5291be 100644 --- a/tests/xharness/Jenkins/RunDeviceTasksFactory.cs +++ b/tests/xharness/Jenkins/RunDeviceTasksFactory.cs @@ -52,7 +52,7 @@ namespace Xharness.Jenkins { Platform = TestPlatform.iOS_Unified64, TestName = project.Name, }; - build64.CloneTestProject (jenkins.MainLog, processManager, project); + build64.CloneTestProject (jenkins.MainLog, processManager, project, HarnessConfiguration.RootDirectory); projectTasks.Add (new RunDeviceTask ( jenkins: jenkins, devices: jenkins.Devices, @@ -69,7 +69,7 @@ namespace Xharness.Jenkins { Platform = TestPlatform.iOS_Unified32, TestName = project.Name, }; - build32.CloneTestProject (jenkins.MainLog, processManager, project); + build32.CloneTestProject (jenkins.MainLog, processManager, project, HarnessConfiguration.RootDirectory); projectTasks.Add (new RunDeviceTask ( jenkins: jenkins, devices: jenkins.Devices, @@ -88,7 +88,7 @@ namespace Xharness.Jenkins { Platform = TestPlatform.iOS_TodayExtension64, TestName = project.Name, }; - buildToday.CloneTestProject (jenkins.MainLog, processManager, todayProject); + buildToday.CloneTestProject (jenkins.MainLog, processManager, todayProject, HarnessConfiguration.RootDirectory); projectTasks.Add (new RunDeviceTask ( jenkins: jenkins, devices: jenkins.Devices, @@ -109,7 +109,7 @@ namespace Xharness.Jenkins { Platform = TestPlatform.tvOS, TestName = project.Name, }; - buildTV.CloneTestProject (jenkins.MainLog, processManager, tvOSProject); + buildTV.CloneTestProject (jenkins.MainLog, processManager, tvOSProject, HarnessConfiguration.RootDirectory); projectTasks.Add (new RunDeviceTask ( jenkins: jenkins, devices: jenkins.Devices, @@ -130,7 +130,7 @@ namespace Xharness.Jenkins { Platform = TestPlatform.watchOS_32, TestName = project.Name, }; - buildWatch32.CloneTestProject (jenkins.MainLog, processManager, watchOSProject); + buildWatch32.CloneTestProject (jenkins.MainLog, processManager, watchOSProject, HarnessConfiguration.RootDirectory); projectTasks.Add (new RunDeviceTask ( jenkins: jenkins, devices: jenkins.Devices, @@ -149,7 +149,7 @@ namespace Xharness.Jenkins { Platform = TestPlatform.watchOS_64_32, TestName = project.Name, }; - buildWatch64_32.CloneTestProject (jenkins.MainLog, processManager, watchOSProject); + buildWatch64_32.CloneTestProject (jenkins.MainLog, processManager, watchOSProject, HarnessConfiguration.RootDirectory); projectTasks.Add (new RunDeviceTask ( jenkins: jenkins, devices: jenkins.Devices, diff --git a/tests/xharness/Jenkins/RunSimulatorTasksFactory.cs b/tests/xharness/Jenkins/RunSimulatorTasksFactory.cs index 5209ed75a3..716553721b 100644 --- a/tests/xharness/Jenkins/RunSimulatorTasksFactory.cs +++ b/tests/xharness/Jenkins/RunSimulatorTasksFactory.cs @@ -74,7 +74,7 @@ namespace Xharness.Jenkins { derived.Ignored = configIgnored; derived.TestName = project.Name; derived.Dependency = project.Dependency; - derived.CloneTestProject (jenkins.MainLog, processManager, pair.Item1); + derived.CloneTestProject (jenkins.MainLog, processManager, pair.Item1, HarnessConfiguration.RootDirectory); var simTasks = CreateAsync (jenkins, processManager, derived); runSimulatorTasks.AddRange (simTasks); foreach (var task in simTasks) { diff --git a/tests/xharness/Jenkins/TestVariationsFactory.cs b/tests/xharness/Jenkins/TestVariationsFactory.cs index 21c3349f72..3853f8096a 100644 --- a/tests/xharness/Jenkins/TestVariationsFactory.cs +++ b/tests/xharness/Jenkins/TestVariationsFactory.cs @@ -160,7 +160,7 @@ namespace Xharness.Jenkins { var clone = task.TestProject.Clone (); var clone_task = Task.Run (async () => { await task.BuildTask.InitialTask; // this is the project cloning above - await clone.CreateCopyAsync (jenkins.MainLog, processManager, task); + await clone.CreateCopyAsync (jenkins.MainLog, processManager, task, HarnessConfiguration.RootDirectory); var isMac = task.Platform.IsMac (); var canSymlink = task.Platform.CanSymlink(); diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Tasks/TestTask.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Tasks/TestTask.cs index bd37eb489b..672cf23d50 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Tasks/TestTask.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Tasks/TestTask.cs @@ -242,7 +242,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Tasks { return Task.CompletedTask; } - public void CloneTestProject (ILog log, IProcessManager processManager, TestProject project) + public void CloneTestProject (ILog log, IProcessManager processManager, TestProject project, string rootDirectory) { // Don't build in the original project directory // We can build multiple projects in parallel, and if some of those @@ -252,7 +252,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Tasks { // So we clone the project file to a separate directory and build there instead. // This is done asynchronously to speed to the initial test load. TestProject = project.Clone (); - InitialTask = TestProject.CreateCopyAsync (log, processManager, this); + InitialTask = TestProject.CreateCopyAsync (log, processManager, this, rootDirectory); } protected Stopwatch waitingDuration = new Stopwatch (); diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestProject.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestProject.cs index 04300aaa41..fe10b822ee 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestProject.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestProject.cs @@ -69,14 +69,20 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared { return rv; } - internal async Task CreateCloneAsync (ILog log, IProcessManager processManager, ITestTask test) + internal async Task CreateCloneAsync (ILog log, IProcessManager processManager, ITestTask test, string rootDirectory) { var rv = Clone (); - await rv.CreateCopyAsync (log, processManager, test); + await rv.CreateCopyAsync (log, processManager, test, rootDirectory); return rv; } - public async Task CreateCopyAsync (ILog log, IProcessManager processManager, ITestTask test) + public Task CreateCopyAsync (ILog log, IProcessManager processManager, ITestTask test, string rootDirectory) + { + var pr = new Dictionary (); + return CreateCopyAsync (log, processManager, test, rootDirectory, pr); + } + + async Task CreateCopyAsync (ILog log, IProcessManager processManager, ITestTask test, string rootDirectory, Dictionary allProjectReferences) { var directory = DirectoryUtilities.CreateTemporaryDirectory (test?.TestName ?? System.IO.Path.GetFileNameWithoutExtension (Path)); Directory.CreateDirectory (directory); @@ -89,7 +95,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared { doc = new XmlDocument (); doc.LoadWithoutNetworkAccess (original_path); var original_name = System.IO.Path.GetFileName (original_path); - doc.ResolveAllPaths (original_path); + doc.ResolveAllPaths (original_path, rootDirectory); if (doc.IsDotNetProject ()) { if (doc.GetEnableDefaultItems () != false) { @@ -154,8 +160,12 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared { var projectReferences = new List (); foreach (var pr in doc.GetProjectReferences ()) { - var tp = new TestProject (pr.Replace ('\\', '/')); - await tp.CreateCopyAsync (log, processManager, test); + var prPath = pr.Replace ('\\', '/'); + if (!allProjectReferences.TryGetValue (prPath, out var tp)) { + tp = new TestProject (pr.Replace ('\\', '/')); + await tp.CreateCopyAsync (log, processManager, test, rootDirectory, allProjectReferences); + allProjectReferences.Add (prPath, tp); + } doc.SetProjectReferenceInclude (pr, tp.Path.Replace ('/', '\\')); projectReferences.Add (tp); } diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Utilities/ProjectFileExtensions.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Utilities/ProjectFileExtensions.cs index f935757b1f..6d35e5a682 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Utilities/ProjectFileExtensions.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Utilities/ProjectFileExtensions.cs @@ -912,7 +912,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Utilities { } } - public static void ResolveAllPaths (this XmlDocument csproj, string project_path) + public static void ResolveAllPaths (this XmlDocument csproj, string project_path, string rootDirectory = null) { var dir = System.IO.Path.GetDirectoryName (project_path); var nodes_with_paths = new string [] @@ -942,7 +942,7 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Utilities { new string [] { "ObjcBindingCoreSource", "Include" }, new string [] { "ObjcBindingNativeLibrary", "Include" }, new string [] { "ObjcBindingNativeFramework", "Include" }, - new string [] { "Import", "Project", "CustomBuildActions.targets" }, + new string [] { "Import", "Project", "CustomBuildActions.targets", "..\\shared.targets" }, new string [] { "FilesToCopy", "Include" }, new string [] { "FilesToCopyFoo", "Include" }, new string [] { "FilesToCopyFooBar", "Include" }, @@ -967,6 +967,10 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Utilities { if (input.StartsWith ("$(MSBuildBinPath)", StringComparison.Ordinal)) return input; // This is already a full path. input = input.Replace ('\\', '/'); // make unix-style + + if (rootDirectory != null) + input = input.Replace ("$(RootTestsDirectory)", rootDirectory); + input = System.IO.Path.GetFullPath (System.IO.Path.Combine (dir, input)); input = input.Replace ('/', '\\'); // make windows-style again return input; @@ -1064,9 +1068,12 @@ namespace Microsoft.DotNet.XHarness.iOS.Shared.Utilities { foreach (var prop in properties) args.Add ($"/p:{prop.Key}={prop.Value}"); args.Add (inspector); + var env = new Dictionary { + { "MSBUILD_EXE_PATH", null }, + }; proc.StartInfo.Arguments = StringUtils.FormatArguments (args); proc.StartInfo.WorkingDirectory = dir; - var rv = await processManager.RunAsync (proc, log, timeout: TimeSpan.FromSeconds (15)); + var rv = await processManager.RunAsync (proc, log, environment_variables: env, timeout: TimeSpan.FromSeconds (15)); if (!rv.Succeeded) throw new Exception ($"Unable to evaluate the property {evaluateProperty}."); return File.ReadAllText (output).Trim (); diff --git a/tests/xharness/Targets/Target.cs b/tests/xharness/Targets/Target.cs index 581fe6a1fb..9136db1d9e 100644 --- a/tests/xharness/Targets/Target.cs +++ b/tests/xharness/Targets/Target.cs @@ -199,6 +199,7 @@ namespace Xharness.Targets protected void CreateLibraryProject () { ProcessProject (); + inputProject.ResolveAllPaths (TemplateProjectPath); inputProject.Save (ProjectPath, (l, m) => Harness.Log (l,m)); ProjectGuid = inputProject.GetProjectGuid (); diff --git a/tests/xharness/Targets/TodayExtensionTarget.cs b/tests/xharness/Targets/TodayExtensionTarget.cs index 552b850d8a..aa3c68d178 100644 --- a/tests/xharness/Targets/TodayExtensionTarget.cs +++ b/tests/xharness/Targets/TodayExtensionTarget.cs @@ -51,6 +51,7 @@ namespace Xharness.Targets { TodayContainerGuid = "{" + Helpers.GenerateStableGuid ().ToString ().ToUpper () + "}"; ProjectGuid = TodayContainerGuid; csproj.SetProjectGuid (TodayContainerGuid); + csproj.ResolveAllPaths (Harness.TodayContainerTemplate); csproj.Save(TodayContainerProjectPath, (l, m) => Harness.Log (l,m)); XmlDocument info_plist = new XmlDocument (); @@ -79,7 +80,7 @@ namespace Xharness.Targets { csproj.AddInterfaceDefinition (Path.Combine (Harness.TodayExtensionTemplate, "TodayView.storyboard").Replace ('/', '\\')); csproj.SetExtraLinkerDefs ("extra-linker-defs" + ExtraLinkerDefsSuffix + ".xml"); csproj.FixProjectReferences (Path.Combine (ProjectsDir, GetTargetSpecificDir ()), "-today", FixProjectReference); - + csproj.ResolveAllPaths (TemplateProjectPath); csproj.Save (TodayExtensionProjectPath, (l,m) => Harness.Log (l,m)); TodayExtensionGuid = csproj.GetProjectGuid (); diff --git a/tools/common/Application.cs b/tools/common/Application.cs index c2abfc10af..7bccce1923 100644 --- a/tools/common/Application.cs +++ b/tools/common/Application.cs @@ -16,8 +16,12 @@ using ObjCRuntime; #if MONOTOUCH using PlatformResolver = MonoTouch.Tuner.MonoTouchResolver; -#else +#elif MMP using PlatformResolver = Xamarin.Bundler.MonoMacResolver; +#elif NET +using PlatformResolver = Xamarin.Linker.DotNetResolver; +#else +#error Invalid defines #endif namespace Xamarin.Bundler { diff --git a/tools/common/Assembly.cs b/tools/common/Assembly.cs index 0f3054e8c2..6aceca94f3 100644 --- a/tools/common/Assembly.cs +++ b/tools/common/Assembly.cs @@ -55,25 +55,31 @@ namespace Xamarin.Bundler { public AssemblyDefinition AssemblyDefinition; public Target Target; - public bool IsFrameworkAssembly { get { return is_framework_assembly.Value; } } + public bool? IsFrameworkAssembly { get { return is_framework_assembly; } } public string FullPath { get { return full_path; } set { full_path = value; - if (!is_framework_assembly.HasValue) { + if (!is_framework_assembly.HasValue && !string.IsNullOrEmpty (full_path)) { var real_full_path = Target.GetRealPath (full_path); +#if NET + // TODO: Figure out how to determine whether an assembly is a framework assembly or not (but it's not urgent to implement, it's just a performance improvement) +#else is_framework_assembly = real_full_path.StartsWith (Path.GetDirectoryName (Path.GetDirectoryName (Target.Resolver.FrameworkDirectory)), StringComparison.Ordinal); +#endif } } } public string FileName { get { return Path.GetFileName (FullPath); } } - public string Identity { get { return GetIdentity (FullPath); } } + public string Identity { get { return GetIdentity (AssemblyDefinition); } } public static string GetIdentity (AssemblyDefinition ad) { - return Path.GetFileNameWithoutExtension (ad.MainModule.FileName); + if (!string.IsNullOrEmpty (ad.MainModule.FileName)) + return Path.GetFileNameWithoutExtension (ad.MainModule.FileName); + return ad.Name.Name; } public static string GetIdentity (string path) @@ -143,7 +149,7 @@ namespace Xamarin.Bundler { public void ExtractNativeLinkInfo () { // ignore framework assemblies, they won't have any LinkWith attributes - if (IsFrameworkAssembly) + if (IsFrameworkAssembly == true) return; var assembly = AssemblyDefinition; diff --git a/tools/common/DerivedLinkContext.cs b/tools/common/DerivedLinkContext.cs index 4b44bc0afe..6e7f3c2e6a 100644 --- a/tools/common/DerivedLinkContext.cs +++ b/tools/common/DerivedLinkContext.cs @@ -9,6 +9,10 @@ using Registrar; using Mono.Tuner; using Xamarin.Bundler; +#if NET +using LinkContext = Xamarin.Bundler.DotNetLinkContext; +#endif + namespace Xamarin.Tuner { public class DerivedLinkContext : LinkContext diff --git a/tools/common/Driver.cs b/tools/common/Driver.cs index bd42d52b1b..bb9bdebb20 100644 --- a/tools/common/Driver.cs +++ b/tools/common/Driver.cs @@ -28,6 +28,7 @@ namespace Xamarin.Bundler { public static bool Force { get; set; } static Version min_xcode_version = new Version (6, 0); +#if !NET public static int Main (string [] args) { try { @@ -327,6 +328,7 @@ namespace Xamarin.Bundler { return false; } +#endif // !NET static int Jobs; public static int Concurrency { diff --git a/tools/common/Driver.execution.cs b/tools/common/Driver.execution.cs index 1dde08fa9b..2a6d7e3d1f 100644 --- a/tools/common/Driver.execution.cs +++ b/tools/common/Driver.execution.cs @@ -139,7 +139,7 @@ namespace Xamarin.Bundler { return Task.Run (() => RunCommand (path, args, env, output, output, suppressPrintOnErrors, verbosity ?? Verbosity)); } -#if !MTOUCH && !MMP +#if !MTOUCH && !MMP && !BUNDLER internal static int Verbosity; #endif } diff --git a/tools/common/SdkVersions.cs.in b/tools/common/SdkVersions.cs.in index c80db22a9a..d7d1fa7a47 100644 --- a/tools/common/SdkVersions.cs.in +++ b/tools/common/SdkVersions.cs.in @@ -1,6 +1,6 @@ using System; -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER using Xamarin.Bundler; using Xamarin.Utils; #endif @@ -62,7 +62,7 @@ namespace Xamarin { public static Version XcodeVersion { get { return new Version (Xcode); }} -#if MTOUCH || MMP +#if MTOUCH || MMP || BUNDLER public static Version GetVersion (Application app) { switch (app.Platform) { diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index 24cbd18108..7296f56e01 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -20,6 +20,7 @@ using Registrar; using Foundation; using ObjCRuntime; using Mono.Cecil; +using Mono.Linker; using Mono.Tuner; namespace Registrar { diff --git a/tools/common/Target.cs b/tools/common/Target.cs index a54480f470..87368ff872 100644 --- a/tools/common/Target.cs +++ b/tools/common/Target.cs @@ -26,10 +26,16 @@ using MonoTouch; using MonoTouch.Tuner; using PlatformResolver = MonoTouch.Tuner.MonoTouchResolver; using PlatformLinkContext = MonoTouch.Tuner.MonoTouchLinkContext; -#else +#elif MMP using MonoMac.Tuner; using PlatformResolver = Xamarin.Bundler.MonoMacResolver; using PlatformLinkContext = MonoMac.Tuner.MonoMacLinkContext; +#elif NET +using LinkerOptions = Xamarin.Linker.LinkerConfiguration; +using PlatformLinkContext = Xamarin.Tuner.DerivedLinkContext; +using PlatformResolver = Xamarin.Linker.DotNetResolver; +#else +#error Invalid defines #endif namespace Xamarin.Bundler { @@ -80,6 +86,13 @@ namespace Xamarin.Bundler { this.StaticRegistrar = new StaticRegistrar (this); } + public Assembly AddAssembly (AssemblyDefinition assembly) + { + var asm = new Assembly (this, assembly); + Assemblies.Add (asm); + return asm; + } + // This will find the link context, possibly looking in container targets. public PlatformLinkContext GetLinkContext () { diff --git a/tools/common/cache.cs b/tools/common/cache.cs index 934c8955cc..acc3187744 100644 --- a/tools/common/cache.cs +++ b/tools/common/cache.cs @@ -13,6 +13,8 @@ public class Cache { const string NAME = "mmp"; #elif MTOUCH const string NAME = "mtouch"; +#elif BUNDLER + const string NAME = "dotnet-linker"; #else #error Wrong defines #endif diff --git a/tools/dotnet-linker/Compat.cs b/tools/dotnet-linker/Compat.cs index 53253a97ce..8ca426c02e 100644 --- a/tools/dotnet-linker/Compat.cs +++ b/tools/dotnet-linker/Compat.cs @@ -1,51 +1,109 @@ // Compat.cs: might not be ideal but it eases code sharing with existing code during the initial implementation. using System; +using System.Collections.Generic; + +using Mono.Cecil; +using Mono.Linker; +using Mono.Linker.Steps; using Xamarin.Linker; using Xamarin.Utils; namespace Xamarin.Bundler { - public class Application { + public partial class Application { public LinkerConfiguration Configuration { get; private set; } - public Application (LinkerConfiguration configuration) + public Application (LinkerConfiguration configuration, string[] arguments) + : this (arguments) { this.Configuration = configuration; } - // This method is needed for ErrorHelper.tools.cs to compile. - public void LoadSymbols () - { - } - - public string GetProductName () - { - switch (Platform) { - case ApplePlatform.iOS: - case ApplePlatform.TVOS: - case ApplePlatform.WatchOS: - return "Xamarin.iOS"; - case ApplePlatform.MacOSX: - return "Xamarin.Mac"; - default: - throw ErrorHelper.CreateError (177, Errors.MX0177 /* "Unknown platform: {0}. This usually indicates a bug; please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new with a test case." */, Platform); + public string ProductName { + get { + switch (Platform) { + case ApplePlatform.iOS: + return "Microsoft.iOS"; + case ApplePlatform.TVOS: + return "Microsoft.tvOS"; + case ApplePlatform.WatchOS: + return "Microsoft.watchOS"; + case ApplePlatform.MacOSX: + return "Microsoft.macOS"; + default: + throw ErrorHelper.CreateError (177, Errors.MX0177 /* "Unknown platform: {0}. This usually indicates a bug; please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new with a test case." */, Platform); + } } } - public Version SdkVersion { - get { return Configuration.SdkVersion; } + public void SelectRegistrar () + { + throw new NotImplementedException (); + } + } + + public partial class Driver { + public static string NAME { + get { return "xamarin-bundler"; } } - public Version DeploymentTarget { - get { return Configuration.DeploymentTarget; } + public static string GetArch32Directory (Application app) + { + throw new NotImplementedException (); } - public bool IsSimulatorBuild { - get { return Configuration.IsSimulatorBuild; } + public static string GetArch64Directory (Application app) + { + throw new NotImplementedException (); + } + } + + public class DotNetLinkContext { + public DotNetLinkContext () + { + throw new NotImplementedException (); } - public ApplePlatform Platform { - get { return Configuration.Platform; } + public DotNetLinkContext (Pipeline pipeline, AssemblyResolver resolver) + { + throw new NotImplementedException (); + } + + public AssemblyAction UserAction { + get { throw new NotImplementedException (); } + set { throw new NotImplementedException (); } + } + + public AnnotationStore Annotations { + get { + throw new NotImplementedException (); + } + } + + public AssemblyDefinition GetAssembly (string name) + { + throw new NotImplementedException (); + } + } + + public class Pipeline { + + } +} + +namespace Mono.Linker { + public static class LinkContextExtensions { + public static void LogMessage (this LinkContext context, string messsage) + { + throw new NotImplementedException (); + } + public static IEnumerable GetAssemblies (this LinkContext context) + { + throw new NotImplementedException (); + } + public static Dictionary GetCustomAnnotations (this AnnotationStore self, string name) + { + throw new NotImplementedException (); } } } diff --git a/tools/dotnet-linker/Constants.cs b/tools/dotnet-linker/Constants.cs new file mode 100644 index 0000000000..9c51e76ee3 --- /dev/null +++ b/tools/dotnet-linker/Constants.cs @@ -0,0 +1,15 @@ +using System; + +namespace Xamarin.Bundler { + public static partial class Constants { + public static string Version { + get { throw new NotImplementedException (); } + } + internal static string Revision { + get { throw new NotImplementedException (); } + } + public static string SdkVersion { + get { throw new NotImplementedException (); } + } + } +} diff --git a/tools/dotnet-linker/DotNetResolver.cs b/tools/dotnet-linker/DotNetResolver.cs new file mode 100644 index 0000000000..9f51e55ff7 --- /dev/null +++ b/tools/dotnet-linker/DotNetResolver.cs @@ -0,0 +1,14 @@ +using System; + +using Mono.Cecil; + +using Xamarin.Bundler; + +namespace Xamarin.Linker { + public class DotNetResolver : CoreResolver { + public override AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters) + { + throw new NotImplementedException (); + } + } +} diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs index 3dc90438dd..b77bd61c83 100644 --- a/tools/dotnet-linker/LinkerConfiguration.cs +++ b/tools/dotnet-linker/LinkerConfiguration.cs @@ -5,11 +5,14 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Xml.Linq; +using Mono.Cecil; using Mono.Linker; using Xamarin.Bundler; using Xamarin.Utils; +using ObjCRuntime; + namespace Xamarin.Linker { public class LinkerConfiguration { public List Abis; @@ -27,13 +30,19 @@ namespace Xamarin.Linker { static ConditionalWeakTable configurations = new ConditionalWeakTable (); public Application Application { get; private set; } + public Target Target { get; private set; } + + public LinkContext Context { get; private set; } public static LinkerConfiguration GetInstance (LinkContext context) { if (!configurations.TryGetValue (context, out var instance)) { if (!context.TryGetCustomData ("LinkerOptionsFile", out var linker_options_file)) throw new Exception ($"No custom linker options file was passed to the linker (using --custom-data LinkerOptionsFile=..."); - instance = new LinkerConfiguration (linker_options_file); + instance = new LinkerConfiguration (linker_options_file) { + Context = context, + }; + configurations.Add (context, instance); } @@ -46,6 +55,7 @@ namespace Xamarin.Linker { throw new FileNotFoundException ($"The custom linker file {linker_file} does not exist."); var lines = File.ReadAllLines (linker_file); + var significantLines = new List (); // This is the input the cache uses to verify if the cache is still valid for (var i = 0; i < lines.Length; i++) { var line = lines [i].TrimStart (); if (line.Length == 0 || line [0] == '#') @@ -55,6 +65,8 @@ namespace Xamarin.Linker { if (eq == -1) throw new InvalidOperationException ($"Invalid syntax for line {i + 1} in {linker_file}: No equals sign."); + significantLines.Add (line); + var key = line [..eq]; var value = line [(eq + 1)..]; @@ -116,6 +128,11 @@ namespace Xamarin.Linker { Abis.Add (a); } break; + case "TargetFramework": + if (!TargetFramework.TryParse (value, out var tf)) + throw new InvalidOperationException ($"Invalid TargetFramework '{value}' in {linker_file}"); + Driver.TargetFramework = TargetFramework.Parse (value); + break; case "Verbosity": if (!int.TryParse (value, out var verbosity)) throw new InvalidOperationException ($"Invalid Verbosity '{value}' in {linker_file}"); @@ -128,7 +145,29 @@ namespace Xamarin.Linker { ErrorHelper.Platform = Platform; - Application = new Application (this); + Application = new Application (this, significantLines.ToArray ()); + Target = new Target (Application); + + Application.Cache.Location = CacheDirectory; + Application.DeploymentTarget = DeploymentTarget; + Application.SdkVersion = SdkVersion; + + switch (Platform) { + case ApplePlatform.iOS: + case ApplePlatform.TVOS: + case ApplePlatform.WatchOS: + Application.BuildTarget = IsSimulatorBuild ? BuildTarget.Simulator : BuildTarget.Device; + break; + case ApplePlatform.MacOSX: + default: + break; + } + + if (Driver.TargetFramework.Platform != Platform) + throw ErrorHelper.CreateError (99, "Inconsistent platforms. TargetFramework={0}, Platform={1}", Driver.TargetFramework.Platform, Platform); + + Driver.Verbosity = Verbosity; + ErrorHelper.Verbosity = Verbosity; } public void Write () @@ -148,6 +187,15 @@ namespace Xamarin.Linker { } } + public string GetAssemblyFileName (AssemblyDefinition assembly) + { + // See: https://github.com/mono/linker/issues/1313 + // Call LinkContext.Resolver.GetAssemblyFileName (https://github.com/mono/linker/blob/da2cc0fcd6c3a8e8e5d1b5d4a655f3653baa8980/src/linker/Linker/AssemblyResolver.cs#L88) using reflection. + var resolver = typeof (LinkContext).GetProperty ("Resolver").GetValue (Context); + var filename = (string) resolver.GetType ().GetMethod ("GetAssemblyFileName", new Type [] { typeof (AssemblyDefinition) }).Invoke (resolver, new object [] { assembly }); + return filename; + } + public void WriteOutputForMSBuild (string itemName, List items) { var xmlNs = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003"); diff --git a/tools/dotnet-linker/SetupStep.cs b/tools/dotnet-linker/SetupStep.cs index 96884a3ac4..ace37ceb6a 100644 --- a/tools/dotnet-linker/SetupStep.cs +++ b/tools/dotnet-linker/SetupStep.cs @@ -29,6 +29,8 @@ namespace Xamarin { // Don't use --custom-step to load each step, because this assembly // is loaded into the current process once per --custom-step, // which makes it very difficult to share state between steps. + Steps.Add (new LoadNonSkippedAssembliesStep ()); + Steps.Add (new ExtractBindingLibrariesStep ()); Steps.Add (new GenerateMainStep ()); Steps.Add (new GatherFrameworksStep ()); diff --git a/tools/dotnet-linker/Steps/ConfigurationAwareStep.cs b/tools/dotnet-linker/Steps/ConfigurationAwareStep.cs index f784a67330..04c96bcd23 100644 --- a/tools/dotnet-linker/Steps/ConfigurationAwareStep.cs +++ b/tools/dotnet-linker/Steps/ConfigurationAwareStep.cs @@ -1,9 +1,20 @@ +using System; +using System.Collections.Generic; using Mono.Linker.Steps; +using Xamarin.Bundler; + namespace Xamarin.Linker { public abstract class ConfigurationAwareStep : BaseStep { public LinkerConfiguration Configuration { get { return LinkerConfiguration.GetInstance (Context); } } + + protected void Report (List exceptions) + { + // Maybe there's a better way to show errors that integrates with the linker? + // We can't just throw an exception or exit here, since there might be only warnings in the list of exceptions. + ErrorHelper.Show (exceptions); + } } } diff --git a/tools/dotnet-linker/Steps/ExtractBindingLibrariesStep.cs b/tools/dotnet-linker/Steps/ExtractBindingLibrariesStep.cs new file mode 100644 index 0000000000..0327986f07 --- /dev/null +++ b/tools/dotnet-linker/Steps/ExtractBindingLibrariesStep.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; + +namespace Xamarin.Linker { + + public class ExtractBindingLibrariesStep : ConfigurationAwareStep { + protected override void EndProcess () + { + base.EndProcess (); + + // No attributes are currently linked away, which means we don't need to worry about linked away LinkWith attributes. + // Ref: https://github.com/mono/linker/issues/952 (still open as of this writing). + var exceptions = new List (); + Configuration.Target.ExtractNativeLinkInfo (exceptions); + Report (exceptions); + + // Tell MSBuild about the native libraries we found + var linkWith = new List (); + foreach (var asm in Configuration.Target.Assemblies) { + foreach (var arg in asm.LinkWith) { + var item = new MSBuildItem { + Include = arg, + Metadata = new Dictionary { + { "ForceLoad", "true" }, + { "Assembly", asm.Identity }, + }, + }; + linkWith.Add (item); + } + } + Configuration.WriteOutputForMSBuild ("_BindingLibraryLinkWith", linkWith); + + // Tell MSBuild about the frameworks libraries we found + var frameworks = new List (); + foreach (var asm in Configuration.Target.Assemblies) { + foreach (var fw in asm.Frameworks) { + var item = new MSBuildItem { + Include = fw, + Metadata = new Dictionary { + { "Assembly", asm.Identity }, + }, + }; + frameworks.Add (item); + } + foreach (var fw in asm.WeakFrameworks) { + var item = new MSBuildItem { + Include = fw, + Metadata = new Dictionary { + { "IsWeak", "true " }, + { "Assembly", asm.Identity }, + }, + }; + frameworks.Add (item); + } + } + Configuration.WriteOutputForMSBuild ("_BindingLibraryFrameworks", frameworks); + + // Tell MSBuild about any additional linker flags we found + var linkerFlags = new List (); + foreach (var asm in Configuration.Target.Assemblies) { + if (asm.LinkerFlags == null) + continue; + foreach (var arg in asm.LinkerFlags) { + var item = new MSBuildItem { + Include = arg, + Metadata = new Dictionary { + { "Assembly", asm.Identity }, + }, + }; + linkerFlags.Add (item); + } + } + Configuration.WriteOutputForMSBuild ("_BindingLibraryLinkerFlags", linkerFlags); + } + } +} diff --git a/tools/dotnet-linker/Steps/LoadNonSkippedAssembliesStep.cs b/tools/dotnet-linker/Steps/LoadNonSkippedAssembliesStep.cs new file mode 100644 index 0000000000..a6a7d99054 --- /dev/null +++ b/tools/dotnet-linker/Steps/LoadNonSkippedAssembliesStep.cs @@ -0,0 +1,42 @@ +using System; + +using Mono.Cecil; +using Mono.Linker; + +namespace Xamarin.Linker { + // List all the assemblies we care about (i.e. the ones that have not been linked away) + public class LoadNonSkippedAssembliesStep : ConfigurationAwareStep { + + protected override void ProcessAssembly (AssemblyDefinition assembly) + { + base.ProcessAssembly (assembly); + + // Figure out if an assembly is linked away or not + if (Context.Annotations.HasAction (assembly)) { + var action = Context.Annotations.GetAction (assembly); + switch (action) { + case AssemblyAction.Delete: + case AssemblyAction.Skip: + break; + case AssemblyAction.Copy: + case AssemblyAction.CopyUsed: + case AssemblyAction.Link: + case AssemblyAction.Save: + var ad = Configuration.Target.AddAssembly (assembly); + var assemblyFileName = Configuration.GetAssemblyFileName (assembly); + ad.FullPath = assemblyFileName; + break; + case AssemblyAction.AddBypassNGen: // This should be turned into Save or Delete + case AssemblyAction.AddBypassNGenUsed: // This should be turned into Save or Delete + // Log this? + break; + default: + // Log this? + break; + } + } else { + // Log this? + } + } + } +} diff --git a/tools/dotnet-linker/dotnet-linker.csproj b/tools/dotnet-linker/dotnet-linker.csproj index 13634632af..0e734c9372 100644 --- a/tools/dotnet-linker/dotnet-linker.csproj +++ b/tools/dotnet-linker/dotnet-linker.csproj @@ -3,6 +3,7 @@ net5.0 dotnet_linker $(DefineConstants);BUNDLER + true @@ -18,6 +19,9 @@ src\ObjCRuntime\ErrorHelper.cs + + external\tools\common\CoreResolver.cs + tools\common\error.cs @@ -31,6 +35,123 @@ tools\common\Frameworks.cs + + external\tools\mtouch\Stripper.cs + + + external\tools\common\Application.cs + + + external\tools\common\cache.cs + + + external\tools\common\Assembly.cs + + + external\tools\common\Driver.cs + + + external\tools\common\Driver.execution.cs + + + external\tools\common\Execution.cs + + + external\tools\common\FileCopier.cs + + + external\tools\common\LinkMode.cs + + + external\tools\common\SdkVersions.cs + + + external\tools\common\Symbols.cs + + + external\tools\common\Assembly.cs + + + external\tools\common\DerivedLinkContext.cs + + + external\tools\common\Optimizations.cs + + + external\tools\common\PInvokeWrapperGenerator.cs + + + external\tools\common\PListExtensions.cs + + + external\tools\common\StaticRegistrar.cs + + + external\tools\common\StringUtils.cs + + + external\tools\common\TargetFramework.cs + + + external\tools\linker\CustomSymbolWriter.cs + + + external\src\ObjCRuntime\Registrar.cs + + + external\src\ObjCRuntime\Registrar.core.cs + + + external\src\ObjCRuntime\ArgumentSemantic.cs + + + external\src\ObjCRuntime\BindingImplAttribute.cs + + + external\src\ObjCRuntime\Constants.cs + + + external\src\Foundation\ExportAttribute.cs + + + external\src\Foundation\ConnectAttribute.cs + + + external\src\ObjCRuntime\ExceptionMode.cs + + + external\src\ObjCRuntime\LinkWithAttribute.cs + + + external\src\ObjCRuntime\PlatformAvailability2.cs + + + external\src\ObjCRuntime\RuntimeOptions.cs + + + external\tools\linker\MonoTouch.Tuner\Extensions.cs + + + external\tools\linker\MobileExtensions.cs + + + external\tools\linker\ObjCExtensions.cs + + + external\mono-archive\Mono.Tuner\Extensions.cs + + + external\mono-archive\Linker\AssemblyResolver.cs + + + external\mono-archive\Linker\I18nAssemblies.cs + + + external\mono-archive\Mono.Tuner\CecilRocks.cs + + + external\Xamarin.MacDev\Xamarin.MacDev\PListObject.cs + diff --git a/tools/mmp/driver.cs b/tools/mmp/driver.cs index f885579f84..23f4ebbfad 100644 --- a/tools/mmp/driver.cs +++ b/tools/mmp/driver.cs @@ -1609,9 +1609,8 @@ namespace Xamarin.Bundler { Target.PrintAssemblyReferences (assembly); - var asm = new Assembly (BuildTarget, assembly); + var asm = BuildTarget.AddAssembly (assembly); asm.ComputeSatellites (); - BuildTarget.Assemblies.Add (asm); resolved_assemblies.Add (fqname); diff --git a/tools/mtouch/Target.mtouch.cs b/tools/mtouch/Target.mtouch.cs index 09f8af52d6..361bbc1e50 100644 --- a/tools/mtouch/Target.mtouch.cs +++ b/tools/mtouch/Target.mtouch.cs @@ -336,9 +336,8 @@ namespace Xamarin.Bundler // Load all the assemblies in the cached list of assemblies foreach (var assembly in assemblies) { var ad = ManifestResolver.Load (assembly); - var asm = new Assembly (this, ad); + var asm = AddAssembly (ad); asm.ComputeSatellites (); - this.Assemblies.Add (asm); } return; } @@ -381,9 +380,8 @@ namespace Xamarin.Bundler PrintAssemblyReferences (assembly); assemblies.Add (fqname); - var asm = new Assembly (this, assembly); + var asm = AddAssembly (assembly); asm.ComputeSatellites (); - this.Assemblies.Add (asm); var main = assembly.MainModule; foreach (AssemblyNameReference reference in main.AssemblyReferences) { diff --git a/tools/mtouch/mtouch.cs b/tools/mtouch/mtouch.cs index 4f285fdd74..9c5f4f4325 100644 --- a/tools/mtouch/mtouch.cs +++ b/tools/mtouch/mtouch.cs @@ -1154,7 +1154,7 @@ namespace Xamarin.Bundler static bool IsBoundAssembly (Assembly s) { - if (s.IsFrameworkAssembly) + if (s.IsFrameworkAssembly == true) return false; AssemblyDefinition ad = s.AssemblyDefinition;