[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
|
namespace FSharpXM45Library
|
||||||
type Class1() =
|
type Class1() =
|
||||||
member this.X = "F#"
|
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 FSharp { get; set; }
|
||||||
public bool XM45 { get; set; }
|
public bool XM45 { get; set; }
|
||||||
public bool DiagnosticMSBuild { get; set; }
|
public bool DiagnosticMSBuild { get; set; }
|
||||||
public string ProjectName { get; set; }
|
public string ProjectName { get; set; } = "";
|
||||||
public string TestCode { get; set; }
|
public string TestCode { get; set; } = "";
|
||||||
public string TestDecl { get; set; }
|
public string TestDecl { get; set; } = "";
|
||||||
public string CSProjConfig { get; set; }
|
public string CSProjConfig { get; set; } = "";
|
||||||
public string References { get; set; }
|
public string References { get; set; } = "";
|
||||||
public string AssemblyName { get; set; }
|
public string ReferencesBeforePlatform { get; set; } = "";
|
||||||
public string ItemGroup { get; set; }
|
public string AssemblyName { get; set; } = "";
|
||||||
public string SystemMonoVersion { get; set; }
|
public string ItemGroup { get; set; } = "";
|
||||||
|
public string SystemMonoVersion { get; set; } = "";
|
||||||
|
|
||||||
// Binding project specific
|
// Binding project specific
|
||||||
public string APIDefinitionConfig { get; set; }
|
public string APIDefinitionConfig { get; set; }
|
||||||
|
@ -53,16 +54,6 @@ namespace Xamarin.MMP.Tests
|
||||||
public UnifiedTestConfig (string tmpDir)
|
public UnifiedTestConfig (string tmpDir)
|
||||||
{
|
{
|
||||||
TmpDir = 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)
|
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)
|
public static string RunEXEAndVerifyGUID (string tmpDir, Guid guid, string path)
|
||||||
|
@ -196,11 +191,14 @@ namespace Xamarin.MMP.Tests
|
||||||
string sourceDir = FindSourceDirectory ();
|
string sourceDir = FindSourceDirectory ();
|
||||||
string sourceFileName = config.FSharp ? "Component1.fs" : "MyClass.cs";
|
string sourceFileName = config.FSharp ? "Component1.fs" : "MyClass.cs";
|
||||||
string projectSuffix = config.FSharp ? ".fsproj" : ".csproj";
|
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 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)
|
public static string GetUnifiedExecutableProjectName (UnifiedTestConfig config)
|
||||||
|
@ -220,10 +218,10 @@ namespace Xamarin.MMP.Tests
|
||||||
return GenerateEXEProject (config);
|
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);
|
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)
|
public static string RunGeneratedUnifiedExecutable (UnifiedTestConfig config)
|
||||||
|
@ -233,7 +231,7 @@ namespace Xamarin.MMP.Tests
|
||||||
return RunEXEAndVerifyGUID (config.TmpDir, config.guid, exePath);
|
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 we've already generated guid bits for this config, don't tack on a second copy
|
||||||
if (config.guid == Guid.Empty)
|
if (config.guid == Guid.Empty)
|
||||||
|
@ -242,7 +240,7 @@ namespace Xamarin.MMP.Tests
|
||||||
config.TestCode += GenerateOutputCommand (config.TmpDir, config.guid);
|
config.TestCode += GenerateOutputCommand (config.TmpDir, config.guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
string buildOutput = GenerateAndBuildUnifiedExecutable (config, shouldFail, configuration);
|
string buildOutput = GenerateAndBuildUnifiedExecutable (config, shouldFail, useMSBuild, configuration);
|
||||||
if (shouldFail)
|
if (shouldFail)
|
||||||
return new OutputText (buildOutput, "");
|
return new OutputText (buildOutput, "");
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
%REFERENCES_BEFORE_PLATFORM%
|
||||||
<Reference Include="Xamarin.Mac" />
|
<Reference Include="Xamarin.Mac" />
|
||||||
%REFERENCES%
|
%REFERENCES%
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -728,5 +728,29 @@ namespace Xamarin.MMP.Tests
|
||||||
TI.TestUnifiedExecutable (test);
|
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 BundleName { get { return custom_bundle_name != null ? custom_bundle_name : "MonoBundle"; } }
|
||||||
static string AppPath { get { return Path.Combine (macos_dir, app_name); } }
|
static string AppPath { get { return Path.Combine (macos_dir, app_name); } }
|
||||||
|
public static string Arch => arch;
|
||||||
|
|
||||||
static string icon;
|
static string icon;
|
||||||
static string certificate_name;
|
static string certificate_name;
|
||||||
|
@ -122,12 +123,6 @@ namespace Xamarin.Bundler {
|
||||||
static Version MinimumMonoVersion = new Version (4, 2, 0);
|
static Version MinimumMonoVersion = new Version (4, 2, 0);
|
||||||
const string pkg_config = "/Library/Frameworks/Mono.framework/Commands/pkg-config";
|
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) {
|
static void ShowHelp (OptionSet os) {
|
||||||
Console.WriteLine ("mmp - Xamarin.Mac Packer");
|
Console.WriteLine ("mmp - Xamarin.Mac Packer");
|
||||||
Console.WriteLine ("Copyright 2010 Novell Inc.");
|
Console.WriteLine ("Copyright 2010 Novell Inc.");
|
||||||
|
@ -1867,9 +1862,7 @@ namespace Xamarin.Bundler {
|
||||||
|
|
||||||
static void GatherAssemblies () {
|
static void GatherAssemblies () {
|
||||||
foreach (string asm in references) {
|
foreach (string asm in references) {
|
||||||
var assembly = BuildTarget.Resolver.AddAssembly (SwapOutReferenceAssembly (asm));
|
AssemblyDefinition assembly = AddAssemblyPathToResolver (asm);
|
||||||
if (assembly == null)
|
|
||||||
ErrorHelper.Warning (1501, "Can not resolve reference: {0}", asm);
|
|
||||||
ProcessAssemblyReferences (assembly);
|
ProcessAssemblyReferences (assembly);
|
||||||
}
|
}
|
||||||
if (BuildTarget.Resolver.Exceptions.Count > 0)
|
if (BuildTarget.Resolver.Exceptions.Count > 0)
|
||||||
|
@ -1894,33 +1887,63 @@ namespace Xamarin.Bundler {
|
||||||
resolved_assemblies.Add (fqname);
|
resolved_assemblies.Add (fqname);
|
||||||
|
|
||||||
foreach (AssemblyNameReference reference in assembly.MainModule.AssemblyReferences) {
|
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);
|
ProcessAssemblyReferences (reference_assembly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static string SwapOutReferenceAssembly (string assembly)
|
static AssemblyDefinition AddAssemblyPathToResolver (string path)
|
||||||
{
|
{
|
||||||
// Inject the correct Xamarin.Mac.dll - the one in the framework
|
if (AssemblySwapInfo.AssemblyNeedsSwappedOut (path))
|
||||||
// directory is a reference assembly only (stripped of IL, containing
|
path = AssemblySwapInfo.GetSwappedAssemblyPath (path);
|
||||||
// only API/metadata) and the correct one based on the target
|
|
||||||
// architecture needs to replace it
|
|
||||||
string fileName = Path.GetFileName (assembly);
|
|
||||||
|
|
||||||
if (assembly.Contains ("OpenTK.dll") && IsUnifiedFullXamMacFramework)
|
var assembly = BuildTarget.Resolver.AddAssembly (path);
|
||||||
return assembly;
|
if (assembly == null)
|
||||||
if (IsUnified &&
|
ErrorHelper.Warning (1501, "Can not resolve reference: {0}", path);
|
||||||
xammac_reference_assemblies.Contains (fileName)) {
|
return assembly;
|
||||||
switch (arch) {
|
}
|
||||||
|
|
||||||
|
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 "i386":
|
||||||
case "x86_64":
|
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:
|
default:
|
||||||
throw new MonoMacException (5205, true, "Invalid architecture '{0}'. " +
|
throw new MonoMacException (5205, true, "Invalid architecture '{0}'. " +
|
||||||
"Valid architectures are i386 and x86_64 (when --profile=mobile).", arch);
|
"Valid architectures are i386 and x86_64 (when --profile=mobile).", Driver.Arch);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return assembly;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче