Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
134 changes: 134 additions & 0 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/ClassRedirectorTask.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using ClassRedirector;

using Xamarin.Messaging.Build.Client;

#nullable enable

namespace Xamarin.MacDev.Tasks {
public class ClassRedirector : XamarinTask, ITaskCallback {
[Required]
public string InputDirectory { get; set; } = string.Empty;

[Required]
public string OutputDirectory { get; set; } = string.Empty;

[Required]
public ITaskItem? ClassMapPath { get; set; }

[Required]
public string PlatformAssembly { get; set; } = string.Empty;

public override bool Execute ()
{
if (ShouldExecuteRemotely ()) {
var taskRunner = new TaskRunner (SessionId, BuildEngine4);
return taskRunner.RunAsync (this).Result;
}

return ExecuteLocally ();
}

public IEnumerable<ITaskItem> GetAdditionalItemsToBeCopied ()
{
if (!Directory.Exists (InputDirectory))
return Enumerable.Empty<ITaskItem> ();

return Directory.GetFiles (InputDirectory, "*", SearchOption.AllDirectories)
.Select (f => new TaskItem (f));
}

public bool ShouldCopyToBuildServer (ITaskItem item) => true;

public bool ShouldCreateOutputFile (ITaskItem item) => true;

bool ExecuteLocally ()
{
if (!Directory.Exists (InputDirectory)) {
Log.LogError ($"InputDirectory {InputDirectory} doesn't exist.");
return false;
}

if (InputDirectory == OutputDirectory) {
Log.LogError ($"OutputDirectory {OutputDirectory} must be difference from InputDirectory.");
return false;
}

if (!Directory.Exists (OutputDirectory)) {
try {
Directory.CreateDirectory (OutputDirectory);
} catch (Exception directoryException) {
Log.LogErrorFromException (directoryException);
}
}

if (!DirectoryIsWritable (OutputDirectory)) {
Log.LogError ($"OutputDirectory {OutputDirectory} is not writable.");
return false;
}

var classMapPath = ClassMapPath!.ItemSpec;
if (!File.Exists (classMapPath)) {
Log.LogError ($"ClassMapPath file {classMapPath} does not exist.");
return false;
}

var xamarinDll = PlatformAssembly;

if (!File.Exists (xamarinDll))
xamarinDll = Path.Combine (InputDirectory, PlatformAssembly);

if (!File.Exists (xamarinDll)) {
Log.LogError ($"PlatformAssembly {PlatformAssembly} does not exist as is or in {InputDirectory}");
return false;
}



var dllsToProcess = CollectDlls (InputDirectory);

var map = ReadRegistrarFile (classMapPath);

try {
Log.LogMessage (MessageImportance.Low, $"Redirecting class_handle usage from directory {InputDirectory} in the following dlls: {string.Join (",", dllsToProcess)}");
Log.LogMessage (MessageImportance.Low, $"Redirecting class_handle usage with the platform dll {xamarinDll}");
Log.LogMessage (MessageImportance.Low, $"Redirecting class_handle usage with the following {nameof (ClassMapPath)}: {classMapPath}");
var rewriter = new Rewriter (map, xamarinDll, dllsToProcess, OutputDirectory);
rewriter.Process ();
} catch (Exception e) {
Log.LogErrorFromException (e);
return false;
}

return true;
}

static bool DirectoryIsWritable (string path)
{
var info = new DirectoryInfo (path);
return !info.Attributes.HasFlag (FileAttributes.ReadOnly);
}

static string [] CollectDlls (string dir)
{
return Directory.GetFiles (dir, "*.dll"); // GetFiles returns full paths
}

static CSToObjCMap ReadRegistrarFile (string path)
{
var doc = XDocument.Load (path);
var map = CSToObjCMap.FromXDocument (doc);
if (map is null)
throw new Exception ($"Unable to read static registrar map file {path}");
return map;
}
}
}

Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;
using ClassRedirector;

namespace ClassRedirector {
#nullable enable

namespace Xamarin.MacDev.Tasks {
public class Rewriter {
const string runtimeName = "ObjCRuntime.Runtime";
const string classHandleName = "ObjCRuntime.Runtime/ClassHandles";
Expand All @@ -15,14 +19,16 @@ public class Rewriter {
CSToObjCMap map;
string pathToXamarinAssembly;
string [] assembliesToPatch;
string outputDirectory;
SimpleAssemblyResolver resolver;
Dictionary<string, FieldDefinition> csTypeToFieldDef = new Dictionary<string, FieldDefinition> ();

public Rewriter (CSToObjCMap map, string pathToXamarinAssembly, string [] assembliesToPatch)
public Rewriter (CSToObjCMap map, string pathToXamarinAssembly, string [] assembliesToPatch, string outputDirectory)
{
this.map = map;
this.pathToXamarinAssembly = pathToXamarinAssembly;
this.assembliesToPatch = assembliesToPatch;
this.outputDirectory = outputDirectory;
resolver = new SimpleAssemblyResolver (assembliesToPatch);
}

Expand Down Expand Up @@ -60,13 +66,15 @@ Dictionary<string, FieldDefinition> CreateClassHandles ()
if (nativeHandleOpImplicit is null)
throw new Exception ($"Unable to find implicit cast in {nativeHandleName}");

foreach (var (csName, nameIndex) in map) {
foreach (var nameIndexPair in map) {
var csName = nameIndexPair.Key;
var nameIndex = nameIndexPair.Value;
var fieldDef = AddPublicStaticField (classHandles, nameIndex.ObjCName, nativeHandle);
AddInitializer (nativeHandleOpImplicit, processor, mtClassMapDef, nameIndex.MapIndex, fieldDef);
classMap [csName] = fieldDef;
}

module.Write ();
module.Write (ToOutputFileName (pathToXamarinAssembly));
return classMap;
}

Expand Down Expand Up @@ -132,7 +140,7 @@ void PatchClassPtrUsage (Dictionary<string, FieldDefinition> classMap)
using var stm = new FileStream (path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
using var module = ModuleDefinition.ReadModule (stm);
PatchClassPtrUsage (classMap, module);
module.Write ();
module.Write (ToOutputFileName (path));
}
}

Expand Down Expand Up @@ -247,8 +255,8 @@ bool IsGetClassHandle (ILProcessor il, int index)
if (index < 0)
return false;
var instr = il.Body.Instructions [index]!;
var operand = instr.Operand?.ToString () ?? "";
return instr.OpCode == OpCodes.Call && operand.Contains ("Class::GetHandle", StringComparison.Ordinal);
var operand = instr.Operand?.ToString () ?? string.Empty;
return instr.OpCode == OpCodes.Call && operand.Contains ("Class::GetHandle");
}

bool IsLdStr (ILProcessor il, int index)
Expand Down Expand Up @@ -278,6 +286,11 @@ IEnumerable<TypeDefinition> AllTypes (TypeDefinition type)
}
}
}

string ToOutputFileName (string pathToInputFileName)
{
return Path.Combine (outputDirectory, Path.GetFileName (pathToInputFileName));
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#nullable enable

namespace ClassRedirector {
namespace Xamarin.MacDev.Tasks {
public class SimpleAssemblyResolver : DefaultAssemblyResolver {
public SimpleAssemblyResolver (params string [] filesOrDirectories)
: base ()
Expand Down
6 changes: 6 additions & 0 deletions msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.Tasks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
<Compile Include="..\..\tools\common\SdkVersions.cs">
<Link>external\SdkVersions.cs</Link>
</Compile>
<Compile Include="..\..\tools\common\CSToObjCMap.cs">
<Link>external\CSToObjCMap.cs</Link>
</Compile>
<Compile Include="..\..\tools\common\ObjCNameIndex.cs">
<Link>external\ObjCNameIndex.cs</Link>
</Compile>
</ItemGroup>

<ItemGroup>
Expand Down
106 changes: 0 additions & 106 deletions tools/class-redirector/class-redirector/Program.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<OutputType>Library</OutputType>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>class_redirector</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
Expand All @@ -10,7 +10,7 @@

<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.5.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\common\CSToObjCMap.cs">
Expand Down