diff --git a/tests/common/mac/Component1.fs b/tests/common/mac/Component1.fs index 36da391d07..5be06e207f 100644 --- a/tests/common/mac/Component1.fs +++ b/tests/common/mac/Component1.fs @@ -1,3 +1,5 @@ namespace FSharpXM45Library type Class1() = member this.X = "F#" + +%CODE% diff --git a/tests/common/mac/MyClass.cs b/tests/common/mac/MyClass.cs index ef728deed5..2b4c3c6e29 100644 --- a/tests/common/mac/MyClass.cs +++ b/tests/common/mac/MyClass.cs @@ -10,3 +10,4 @@ namespace Library } } +%CODE% diff --git a/tests/common/mac/ProjectTestHelpers.cs b/tests/common/mac/ProjectTestHelpers.cs index 51b903e8e0..159ad91273 100644 --- a/tests/common/mac/ProjectTestHelpers.cs +++ b/tests/common/mac/ProjectTestHelpers.cs @@ -34,14 +34,15 @@ namespace Xamarin.MMP.Tests public bool FSharp { get; set; } public bool XM45 { get; set; } public bool DiagnosticMSBuild { get; set; } - public string ProjectName { get; set; } - public string TestCode { get; set; } - public string TestDecl { get; set; } - public string CSProjConfig { get; set; } - public string References { get; set; } - public string AssemblyName { get; set; } - public string ItemGroup { get; set; } - public string SystemMonoVersion { get; set; } + public string ProjectName { get; set; } = ""; + public string TestCode { get; set; } = ""; + public string TestDecl { get; set; } = ""; + public string CSProjConfig { get; set; } = ""; + public string References { get; set; } = ""; + public string ReferencesBeforePlatform { get; set; } = ""; + public string AssemblyName { get; set; } = ""; + public string ItemGroup { get; set; } = ""; + public string SystemMonoVersion { get; set; } = ""; // Binding project specific public string APIDefinitionConfig { get; set; } @@ -53,16 +54,6 @@ namespace Xamarin.MMP.Tests public UnifiedTestConfig (string tmpDir) { TmpDir = tmpDir; - ProjectName = ""; - TestCode = ""; - TestDecl = ""; - CSProjConfig = ""; - References = ""; - AssemblyName = ""; - APIDefinitionConfig = ""; - StructsAndEnumsConfig = ""; - ItemGroup = ""; - SystemMonoVersion = ""; } } @@ -150,7 +141,11 @@ namespace Xamarin.MMP.Tests static string ProjectTextReplacement (UnifiedTestConfig config, string text) { - return text.Replace ("%CODE%", config.CSProjConfig).Replace ("%REFERENCES%", config.References).Replace ("%NAME%", config.AssemblyName ?? Path.GetFileNameWithoutExtension (config.ProjectName)).Replace ("%ITEMGROUP%", config.ItemGroup); + return text.Replace ("%CODE%", config.CSProjConfig) + .Replace ("%REFERENCES%", config.References) + .Replace ("%REFERENCES_BEFORE_PLATFORM%", config.ReferencesBeforePlatform) + .Replace ("%NAME%", config.AssemblyName ?? Path.GetFileNameWithoutExtension (config.ProjectName)) + .Replace ("%ITEMGROUP%", config.ItemGroup); } public static string RunEXEAndVerifyGUID (string tmpDir, Guid guid, string path) @@ -196,11 +191,14 @@ namespace Xamarin.MMP.Tests string sourceDir = FindSourceDirectory (); string sourceFileName = config.FSharp ? "Component1.fs" : "MyClass.cs"; string projectSuffix = config.FSharp ? ".fsproj" : ".csproj"; - File.Copy (Path.Combine (sourceDir, sourceFileName), Path.Combine (config.TmpDir, sourceFileName), true); + + CopyFileWithSubstitutions (Path.Combine (sourceDir, sourceFileName), Path.Combine (config.TmpDir, sourceFileName), text => { + return text.Replace ("%CODE%", config.TestCode); + }); return CopyFileWithSubstitutions (Path.Combine (sourceDir, config.ProjectName + projectSuffix), Path.Combine (config.TmpDir, config.ProjectName + projectSuffix), text => { - return ProjectTextReplacement (config, text); - }); + return ProjectTextReplacement (config, text); + }); } public static string GetUnifiedExecutableProjectName (UnifiedTestConfig config) @@ -220,10 +218,10 @@ namespace Xamarin.MMP.Tests return GenerateEXEProject (config); } - public static string GenerateAndBuildUnifiedExecutable (UnifiedTestConfig config, bool shouldFail = false, string configuration = null) + public static string GenerateAndBuildUnifiedExecutable (UnifiedTestConfig config, bool shouldFail = false, bool useMSBuild = false, string configuration = null) { string csprojTarget = GenerateUnifiedExecutableProject (config); - return BuildProject (csprojTarget, isUnified: true, diagnosticMSBuild: config.DiagnosticMSBuild, shouldFail: shouldFail, configuration: configuration); + return BuildProject (csprojTarget, isUnified: true, diagnosticMSBuild: config.DiagnosticMSBuild, shouldFail: shouldFail, useMSBuild: useMSBuild, configuration: configuration); } public static string RunGeneratedUnifiedExecutable (UnifiedTestConfig config) @@ -233,7 +231,7 @@ namespace Xamarin.MMP.Tests return RunEXEAndVerifyGUID (config.TmpDir, config.guid, exePath); } - public static OutputText TestUnifiedExecutable (UnifiedTestConfig config, bool shouldFail = false, string configuration = null) + public static OutputText TestUnifiedExecutable (UnifiedTestConfig config, bool shouldFail = false, bool useMSBuild = false, string configuration = null) { // If we've already generated guid bits for this config, don't tack on a second copy if (config.guid == Guid.Empty) @@ -242,7 +240,7 @@ namespace Xamarin.MMP.Tests config.TestCode += GenerateOutputCommand (config.TmpDir, config.guid); } - string buildOutput = GenerateAndBuildUnifiedExecutable (config, shouldFail, configuration); + string buildOutput = GenerateAndBuildUnifiedExecutable (config, shouldFail, useMSBuild, configuration); if (shouldFail) return new OutputText (buildOutput, ""); diff --git a/tests/common/mac/UnifiedExample.csproj b/tests/common/mac/UnifiedExample.csproj index 077641e43b..2f0a361a2f 100644 --- a/tests/common/mac/UnifiedExample.csproj +++ b/tests/common/mac/UnifiedExample.csproj @@ -27,6 +27,7 @@ +%REFERENCES_BEFORE_PLATFORM% %REFERENCES% diff --git a/tests/mmptest/src/MMPTest.cs b/tests/mmptest/src/MMPTest.cs index cf1f800976..a760047f9b 100644 --- a/tests/mmptest/src/MMPTest.cs +++ b/tests/mmptest/src/MMPTest.cs @@ -728,5 +728,29 @@ namespace Xamarin.MMP.Tests TI.TestUnifiedExecutable (test); }); } + + [Test] + public void Unified32BitWithXMRequiringLibrary_ShouldReferenceCorrectXM_AndNotCrash () + { + RunMMPTest (tmpDir => { + TI.UnifiedTestConfig libConfig = new TI.UnifiedTestConfig (tmpDir) { + ProjectName = "UnifiedLibrary", + TestCode = "namespace Library { public static class Foo { public static void Bar () { var v = new Foundation.NSObject (); } } }" + }; + + string csprojTarget = TI.GenerateUnifiedLibraryProject (libConfig); + TI.BuildProject (csprojTarget, isUnified: true); + + string referenceCode = string.Format (@"{0}", Path.Combine (tmpDir, "bin/Debug/UnifiedLibrary.dll")); + + TI.UnifiedTestConfig test = new TI.UnifiedTestConfig (tmpDir) { + CSProjConfig = @"x86i386", + ReferencesBeforePlatform = referenceCode, + TestCode = "Library.Foo.Bar ();" + }; + + TI.TestUnifiedExecutable (test); + }); + } } } diff --git a/tools/mmp/driver.cs b/tools/mmp/driver.cs index 8bb2656287..e296c6a264 100644 --- a/tools/mmp/driver.cs +++ b/tools/mmp/driver.cs @@ -109,6 +109,7 @@ namespace Xamarin.Bundler { static string BundleName { get { return custom_bundle_name != null ? custom_bundle_name : "MonoBundle"; } } static string AppPath { get { return Path.Combine (macos_dir, app_name); } } + public static string Arch => arch; static string icon; static string certificate_name; @@ -122,12 +123,6 @@ namespace Xamarin.Bundler { static Version MinimumMonoVersion = new Version (4, 2, 0); const string pkg_config = "/Library/Frameworks/Mono.framework/Commands/pkg-config"; - static HashSet xammac_reference_assemblies = new HashSet { - "Xamarin.Mac.dll", - "Xamarin.Mac.CFNetwork.dll", - "OpenTK.dll" - }; - static void ShowHelp (OptionSet os) { Console.WriteLine ("mmp - Xamarin.Mac Packer"); Console.WriteLine ("Copyright 2010 Novell Inc."); @@ -1867,9 +1862,7 @@ namespace Xamarin.Bundler { static void GatherAssemblies () { foreach (string asm in references) { - var assembly = BuildTarget.Resolver.AddAssembly (SwapOutReferenceAssembly (asm)); - if (assembly == null) - ErrorHelper.Warning (1501, "Can not resolve reference: {0}", asm); + AssemblyDefinition assembly = AddAssemblyPathToResolver (asm); ProcessAssemblyReferences (assembly); } if (BuildTarget.Resolver.Exceptions.Count > 0) @@ -1894,33 +1887,63 @@ namespace Xamarin.Bundler { resolved_assemblies.Add (fqname); foreach (AssemblyNameReference reference in assembly.MainModule.AssemblyReferences) { - var reference_assembly = BuildTarget.Resolver.Resolve (SwapOutReferenceAssembly (reference.FullName)); + AssemblyDefinition reference_assembly = AddAssemblyReferenceToResolver (reference.Name); ProcessAssemblyReferences (reference_assembly); } } - static string SwapOutReferenceAssembly (string assembly) + static AssemblyDefinition AddAssemblyPathToResolver (string path) { - // Inject the correct Xamarin.Mac.dll - the one in the framework - // directory is a reference assembly only (stripped of IL, containing - // only API/metadata) and the correct one based on the target - // architecture needs to replace it - string fileName = Path.GetFileName (assembly); + if (AssemblySwapInfo.AssemblyNeedsSwappedOut (path)) + path = AssemblySwapInfo.GetSwappedAssemblyPath (path); - if (assembly.Contains ("OpenTK.dll") && IsUnifiedFullXamMacFramework) - return assembly; - if (IsUnified && - xammac_reference_assemblies.Contains (fileName)) { - switch (arch) { + var assembly = BuildTarget.Resolver.AddAssembly (path); + if (assembly == null) + ErrorHelper.Warning (1501, "Can not resolve reference: {0}", path); + return assembly; + } + + static AssemblyDefinition AddAssemblyReferenceToResolver (string reference) + { + if (AssemblySwapInfo.ReferencedNeedsSwappedOut (reference)) + return BuildTarget.Resolver.AddAssembly (AssemblySwapInfo.GetSwappedReference (reference)); + + return BuildTarget.Resolver.Resolve (reference); + } + } + + public static class AssemblySwapInfo { + static HashSet xammac_reference_assemblies_names = new HashSet { + "Xamarin.Mac", + "Xamarin.Mac.CFNetwork", + "OpenTK" + }; + + public static bool AssemblyNeedsSwappedOut (string path) => NeedsSwappedCore (Path.GetFileNameWithoutExtension (path)); + public static bool ReferencedNeedsSwappedOut (string reference) => NeedsSwappedCore (reference); + + static bool NeedsSwappedCore (string name) + { + if (name.Contains ("OpenTK") && Driver.IsUnifiedFullXamMacFramework) + return false; + + return Driver.IsUnified && xammac_reference_assemblies_names.Contains (name); + } + + public static string GetSwappedAssemblyPath (string path) => GetSwappedPathCore (Path.GetFileNameWithoutExtension (path)); + public static string GetSwappedReference (string reference) => GetSwappedPathCore (reference); + + static string GetSwappedPathCore (string name) + { + string flavor = (Driver.IsUnifiedFullSystemFramework || Driver.IsUnifiedFullXamMacFramework) ? "full" : "mobile"; + switch (Driver.Arch) { case "i386": case "x86_64": - return Path.Combine (GetXamMacPrefix (), "lib", arch, (IsUnifiedFullSystemFramework || IsUnifiedFullXamMacFramework) ? "full" : "mobile", fileName); + return Path.Combine (Driver.GetXamMacPrefix (), "lib", Driver.Arch, flavor, name + ".dll"); default: - throw new MonoMacException (5205, true, "Invalid architecture '{0}'. " + - "Valid architectures are i386 and x86_64 (when --profile=mobile).", arch); - } + throw new MonoMacException (5205, true, "Invalid architecture '{0}'. " + + "Valid architectures are i386 and x86_64 (when --profile=mobile).", Driver.Arch); } - return assembly; } } }