Use custom assembly resolver

Before, I was relying on a bit of luck that the resolver would
use the correct asms - now I make sure it does.

The build step will now fail if a resolution failure occurs -
this is better than runtime errors.
This commit is contained in:
Frank A. Krueger 2018-04-25 15:46:01 -07:00
parent bb78f433e3
commit 6b3581bb6c
No known key found for this signature in database
GPG Key ID: 0471C67474FFE664
1 changed files with 51 additions and 8 deletions

View File

@ -24,9 +24,12 @@ namespace Ooui.Wasm.Build.Tasks
public string OutputPath { get; set; } public string OutputPath { get; set; }
public string ReferencePath { get; set; } public string ReferencePath { get; set; }
bool ok = false;
public override bool Execute () public override bool Execute ()
{ {
try { try {
ok = true;
InstallSdk (); InstallSdk ();
GetBcl (); GetBcl ();
CreateDist (); CreateDist ();
@ -35,9 +38,10 @@ namespace Ooui.Wasm.Build.Tasks
ExtractClientJs (); ExtractClientJs ();
DiscoverEntryPoint (); DiscoverEntryPoint ();
GenerateHtml (); GenerateHtml ();
return true; return ok;
} }
catch (Exception ex) { catch (Exception ex) {
Console.WriteLine (ex);
Log.LogErrorFromException (ex); Log.LogErrorFromException (ex);
return false; return false;
} }
@ -117,21 +121,24 @@ namespace Ooui.Wasm.Build.Tasks
foreach (var r in references) { foreach (var r in references) {
var name = Path.GetFileName (r); var name = Path.GetFileName (r);
if (bclAssemblies.ContainsKey (name)) { if (bclAssemblies.ContainsKey (name)) {
refpaths.Add (bclAssemblies[name]); refpaths.Add (bclAssemblies[name]);
//Console.WriteLine ($"+ {name}");
} }
else { else {
refpaths.Add (r); refpaths.Add (r);
//Console.WriteLine ($"- {r}");
} }
} }
var asmPath = Path.GetFullPath (Assembly); var asmPath = Path.GetFullPath (Assembly);
var pipeline = GetLinkerPipeline (); var pipeline = GetLinkerPipeline ();
using (var context = new LinkContext (pipeline)) { var resolver = new AsmResolver (this);
using (var context = new LinkContext (pipeline, resolver)) {
context.CoreAction = AssemblyAction.CopyUsed; context.CoreAction = AssemblyAction.CopyUsed;
context.UserAction = AssemblyAction.CopyUsed; context.UserAction = AssemblyAction.CopyUsed;
context.OutputDirectory = managedPath; context.OutputDirectory = managedPath;
context.IgnoreUnresolved = true; context.IgnoreUnresolved = false;
pipeline.PrependStep (new ResolveFromAssemblyStep (asmPath, ResolveFromAssemblyStep.RootVisibility.Any)); pipeline.PrependStep (new ResolveFromAssemblyStep (asmPath, ResolveFromAssemblyStep.RootVisibility.Any));
@ -222,7 +229,7 @@ namespace Ooui.Wasm.Build.Tasks
p.AppendStep (new PreserveUsingAttributesStep (bclAssemblies.Values.Select (Path.GetFileNameWithoutExtension))); p.AppendStep (new PreserveUsingAttributesStep (bclAssemblies.Values.Select (Path.GetFileNameWithoutExtension)));
p.AppendStep (new BlacklistStep ()); p.AppendStep (new BlacklistStep ());
p.AppendStep (new TypeMapStep ()); p.AppendStep (new TypeMapStep ());
p.AppendStep (new MarkStepWithUnresolvedLogging { Log = Log }); p.AppendStep (new MarkStepWithUnresolvedLogging (this));
p.AppendStep (new SweepStep ()); p.AppendStep (new SweepStep ());
p.AppendStep (new CleanStep ()); p.AppendStep (new CleanStep ());
p.AppendStep (new RegenerateGuidStep ()); p.AppendStep (new RegenerateGuidStep ());
@ -242,16 +249,23 @@ namespace Ooui.Wasm.Build.Tasks
class MarkStepWithUnresolvedLogging : MarkStep class MarkStepWithUnresolvedLogging : MarkStep
{ {
public TaskLoggingHelper Log; BuildDistTask task;
public MarkStepWithUnresolvedLogging (BuildDistTask task)
{
this.task = task;
}
protected override void HandleUnresolvedType (TypeReference reference) protected override void HandleUnresolvedType (TypeReference reference)
{ {
Log.LogWarning ($"Failed to resolve type {reference}"); task.ok = false;
task.Log.LogError ($"Linker failed to resolve type {reference} in {reference.Scope}");
} }
protected override void HandleUnresolvedMethod (MethodReference reference) protected override void HandleUnresolvedMethod (MethodReference reference)
{ {
Log.LogWarning ($"Failed to resolve method {reference}"); task.ok = false;
task.Log.LogError ($"Linker failed to resolve method {reference}");
} }
} }
@ -326,5 +340,34 @@ namespace Ooui.Wasm.Build.Tasks
} }
Log.LogMessage ($"HTML {htmlPath}"); Log.LogMessage ($"HTML {htmlPath}");
} }
class AsmResolver : Mono.Linker.AssemblyResolver
{
BuildDistTask task;
public AsmResolver (BuildDistTask buildDistTask)
{
task = buildDistTask;
}
public override AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters)
{
AssemblyDefinition asm = null;
if (!AssemblyCache.TryGetValue (name.Name, out asm)) {
var path = task.refpaths.FirstOrDefault (x => {
var rname = Path.GetFileNameWithoutExtension (x);
var eq = rname.Equals (name.Name, StringComparison.InvariantCultureIgnoreCase);
return eq;
});
if (path != null) {
//Console.WriteLine ($"SUCCESS {path}");
asm = ModuleDefinition.ReadModule (path, parameters).Assembly;
CacheAssembly (asm);
}
return base.Resolve (name, parameters);
}
return asm;
}
}
} }
} }