[macos] Teach mmp to correctly swap arch specific assemblies (#2503)
- https://bugzilla.xamarin.com/show_bug.cgi?id=58826 - If the first instance of Xamarin.Mac.dll or another arch specific assembly is found as a library reference, it would not be handled correctly. This caused the "reference" assembly to be copied in, which is 64-bit. - This causes startup crashes in 32-bit applications
This commit is contained in:
Родитель
52119f8a1a
Коммит
125fe51ad7
|
@ -1,3 +1,5 @@
|
|||
namespace FSharpXM45Library
|
||||
type Class1() =
|
||||
member this.X = "F#"
|
||||
|
||||
%CODE%
|
||||
|
|
|
@ -10,3 +10,4 @@ namespace Library
|
|||
}
|
||||
}
|
||||
|
||||
%CODE%
|
||||
|
|
|
@ -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, "");
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
%REFERENCES_BEFORE_PLATFORM%
|
||||
<Reference Include="Xamarin.Mac" />
|
||||
%REFERENCES%
|
||||
</ItemGroup>
|
||||
|
|
|
@ -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 (@"<Reference Include=""UnifiedLibrary""><HintPath>{0}</HintPath></Reference>", Path.Combine (tmpDir, "bin/Debug/UnifiedLibrary.dll"));
|
||||
|
||||
TI.UnifiedTestConfig test = new TI.UnifiedTestConfig (tmpDir) {
|
||||
CSProjConfig = @"<PlatformTarget>x86</PlatformTarget><XamMacArch>i386</XamMacArch>",
|
||||
ReferencesBeforePlatform = referenceCode,
|
||||
TestCode = "Library.Foo.Bar ();"
|
||||
};
|
||||
|
||||
TI.TestUnifiedExecutable (test);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<string> xammac_reference_assemblies = new HashSet<string> {
|
||||
"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<string> xammac_reference_assemblies_names = new HashSet<string> {
|
||||
"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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче