Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using Java.Interop.Tools.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Linker;
using Mono.Tuner;
using MonoDroid.Tuner;
using NUnit.Framework;
using Xamarin.ProjectTools;
Expand Down Expand Up @@ -525,13 +528,24 @@ public void DoNotErrorOnPerArchJavaTypeDuplicates ()
lib.Sources.Add (new BuildItem.Source ("Library1.cs") {
TextContent = () => @"
namespace Lib1;
public class Library1 : Java.Lang.Object {
public class Library1 : Com.Example.Androidlib.MyRunner {
private static bool Is64Bits = IntPtr.Size >= 8;

public static bool Is64 () {
return Is64Bits;
}

public override void Run () => Console.WriteLine (Is64Bits);
}",
});
lib.Sources.Add (new BuildItem ("AndroidJavaSource", "MyRunner.java") {
Encoding = new UTF8Encoding (encoderShouldEmitUTF8Identifier: false),
TextContent = () => @"
package com.example.androidlib;

public abstract class MyRunner {
public abstract void run();
}"
});
var proj = new XamarinAndroidApplicationProject { IsRelease = true, ProjectName = "App1" };
proj.References.Add(new BuildItem.ProjectReference (Path.Combine ("..", "Lib1", "Lib1.csproj"), "Lib1"));
Expand All @@ -545,6 +559,41 @@ public static bool Is64 () {
using var b = CreateApkBuilder (Path.Combine (path, "App1"));
Assert.IsTrue (lb.Build (lib), "build should have succeeded.");
Assert.IsTrue (b.Build (proj), "build should have succeeded.");

var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);
var dll = $"{lib.ProjectName}.dll";
Assert64Bit ("android-arm", expected64: false);
Assert64Bit ("android-arm64", expected64: true);
Assert64Bit ("android-x86", expected64: false);
Assert64Bit ("android-x64", expected64: true);

void Assert64Bit(string rid, bool expected64)
{
var assembly = AssemblyDefinition.ReadAssembly (Path.Combine (intermediate, rid, "linked", "shrunk", dll));
var type = assembly.MainModule.FindType ("Lib1.Library1");
Assert.NotNull (type, "Should find Lib1.Library1!");
var cctor = type.GetTypeConstructor ();
Assert.NotNull (type, "Should find Lib1.Library1.cctor!");
Assert.AreNotEqual (0, cctor.Body.Instructions.Count);

/*
* IL snippet
* .method private hidebysig specialname rtspecialname static
* void .cctor () cil managed
* {
* // Is64Bits = 4 >= 8;
* IL_0000: ldc.i4 4
* IL_0005: ldc.i4.8
* ...
*/
var instruction = cctor.Body.Instructions [0];
Assert.AreEqual (OpCodes.Ldc_I4, instruction.OpCode);
if (expected64) {
Assert.AreEqual (8, instruction.Operand, $"Expected 64-bit: {expected64}");
} else {
Assert.AreEqual (4, instruction.Operand, $"Expected 64-bit: {expected64}");
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,47 +114,37 @@ public void Rewrite (DirectoryAssemblyResolver resolver, List<string> targetAsse
}
}

var newAssemblyPaths = new List<string> ();
var newAssemblyPaths = new List<ValueTuple<string, string>> ();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not use the glorious (string Something, string SomethingElse) tuple syntax?

foreach (AssemblyDefinition asm in uniqueAssemblies) {
foreach (string path in GetAssemblyPaths (asm)) {
foreach (string original in GetAssemblyPaths (asm)) {
var writerParams = new WriterParameters {
WriteSymbols = File.Exists (Path.ChangeExtension (path, ".pdb")),
WriteSymbols = File.Exists (Path.ChangeExtension (original, ".pdb")),
};

string directory = Path.Combine (Path.GetDirectoryName (path), "new");
string directory = Path.Combine (Path.GetDirectoryName (original), "new");
Directory.CreateDirectory (directory);
string output = Path.Combine (directory, Path.GetFileName (path));
log.LogDebugMessage ($"Writing new version of assembly: {output}");
string temp = Path.Combine (directory, Path.GetFileName (original));
log.LogDebugMessage ($"Writing new version of assembly: {temp}");

// TODO: this should be used eventually, but it requires that all the types are reloaded from the assemblies before typemaps are generated
// since Cecil doesn't update the MVID in the already loaded types
//asm.MainModule.Mvid = Guid.NewGuid ();
asm.Write (output, writerParams);
newAssemblyPaths.Add (output);
asm.Write (temp, writerParams);
newAssemblyPaths.Add ((original, temp));
}
}

// Replace old versions of the assemblies only after we've finished rewriting without issues, otherwise leave the new
// versions around.
foreach (string path in newAssemblyPaths) {
string? pdb = null;

string source = Path.ChangeExtension (path, ".pdb");
if (File.Exists (source)) {
pdb = source;
}

foreach (string targetPath in targetAssemblyPaths) {
string target = Path.Combine (targetPath, Path.GetFileName (path));
CopyFile (path, target);

if (!String.IsNullOrEmpty (pdb)) {
CopyFile (pdb, Path.ChangeExtension (target, ".pdb"));
}
foreach ((string original, string temp) in newAssemblyPaths) {
CopyFile (temp, original);
RemoveFile (temp);

var pdb = Path.ChangeExtension (temp, ".pdb");
if (File.Exists(pdb)) {
CopyFile (pdb, Path.ChangeExtension (original, ".pdb"));
RemoveFile (pdb);
}

RemoveFile (path);
RemoveFile (pdb);
}

void CopyFile (string source, string target)
Expand Down