Add linker to wasm build task

This commit is contained in:
Frank A. Krueger 2018-03-13 13:16:59 -07:00
parent 664bcbb8ec
commit 7d70351418
No known key found for this signature in database
GPG Key ID: 0471C67474FFE664
6 changed files with 131 additions and 19 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "Ooui.Wasm.Build.Tasks/linker"]
path = Ooui.Wasm.Build.Tasks/linker
url = git@github.com:mono/linker.git

View File

@ -9,6 +9,9 @@ using Microsoft.Build.Framework;
using Microsoft.Build.Utilities; using Microsoft.Build.Utilities;
using System.Text; using System.Text;
using Mono.Cecil; using Mono.Cecil;
using System.Diagnostics;
using Mono.Linker;
using Mono.Linker.Steps;
namespace Ooui.Wasm.Build.Tasks namespace Ooui.Wasm.Build.Tasks
{ {
@ -82,9 +85,6 @@ namespace Ooui.Wasm.Build.Tasks
distPath = Path.Combine (outputPath, "dist"); distPath = Path.Combine (outputPath, "dist");
managedPath = Path.Combine (distPath, "managed"); managedPath = Path.Combine (distPath, "managed");
Directory.CreateDirectory (managedPath); Directory.CreateDirectory (managedPath);
//foreach (var dll in Directory.GetFiles (managedPath, "*.dll")) {
// File.Delete (dll);
//}
} }
void CopyRuntime () void CopyRuntime ()
@ -99,35 +99,124 @@ namespace Ooui.Wasm.Build.Tasks
} }
} }
List<string> linkedAsmNames;
List<string> linkedAsmPaths; List<string> linkedAsmPaths;
void LinkAssemblies () void LinkAssemblies ()
{ {
var references = ReferencePath.Split (';').Select (x => x.Trim ()).Where (x => x.Length > 0).ToList (); var references = ReferencePath.Split (';').Select (x => x.Trim ()).Where (x => x.Length > 0).ToList ();
references.Add (Path.GetFullPath (Assembly)); var refpaths = new List<string> ();
linkedAsmPaths = new List<string> ();
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)) {
linkedAsmPaths.Add (bclAssemblies[name]); refpaths.Add (bclAssemblies[name]);
} }
else { else {
linkedAsmPaths.Add (r); refpaths.Add (r);
} }
} }
linkedAsmNames = new List<string> (); var asmPath = Path.GetFullPath (Assembly);
foreach (var l in linkedAsmPaths) {
var name = Path.GetFileName (l); var pipeline = GetLinkerPipeline ();
linkedAsmNames.Add (name); using (var context = new LinkContext (pipeline)) {
var dest = Path.Combine (managedPath, name); context.CoreAction = AssemblyAction.CopyUsed;
if (bclAssemblies.ContainsKey (name) && File.Exists (dest)) context.UserAction = AssemblyAction.CopyUsed;
continue; context.OutputDirectory = managedPath;
File.Copy (l, dest, true);
Log.LogMessage ($"Managed {l} -> {dest}"); pipeline.PrependStep (new ResolveFromAssemblyStep (asmPath, ResolveFromAssemblyStep.RootVisibility.Any));
var refdirs = refpaths.Select (x => Path.GetDirectoryName (x)).Distinct ().ToList ();
refdirs.Insert (0, Path.Combine (bclPath, "Facades"));
refdirs.Insert (0, bclPath);
foreach (var d in refdirs.Distinct ()) {
context.Resolver.AddSearchDirectory (d);
}
pipeline.AddStepAfter (typeof (LoadReferencesStep), new LoadI18nAssemblies (I18nAssemblies.None));
foreach (var dll in Directory.GetFiles (managedPath, "*.dll")) {
File.Delete (dll);
}
pipeline.Process (context);
} }
linkedAsmPaths = Directory.GetFiles (managedPath, "*.dll").OrderBy (x => Path.GetFileName (x)).ToList ();
}
class PreserveUsingAttributesStep : ResolveStep
{
readonly HashSet<string> ignoreAsmNames;
public PreserveUsingAttributesStep (IEnumerable<string> ignoreAsmNames)
{
this.ignoreAsmNames = new HashSet<string> (ignoreAsmNames);
}
protected override void Process ()
{
var asms = Context.GetAssemblies ();
foreach (var a in asms.Where (x => !ignoreAsmNames.Contains (x.Name.Name))) {
foreach (var m in a.Modules) {
foreach (var t in m.Types) {
PreserveTypeIfRequested (t);
}
}
}
}
void PreserveTypeIfRequested (TypeDefinition type)
{
var typePreserved = IsTypePreserved (type);
if (IsTypePreserved (type)) {
MarkAndPreserveAll (type);
}
else {
foreach (var m in type.Methods.Where (IsMethodPreserved)) {
Annotations.AddPreservedMethod (type, m);
}
foreach (var t in type.NestedTypes) {
PreserveTypeIfRequested (t);
}
}
}
static bool IsTypePreserved (TypeDefinition m)
{
return m.CustomAttributes.FirstOrDefault (x => x.AttributeType.Name.StartsWith ("Preserve", StringComparison.Ordinal)) != null;
}
static bool IsMethodPreserved (MethodDefinition m)
{
return m.CustomAttributes.FirstOrDefault (x => x.AttributeType.Name.StartsWith ("Preserve", StringComparison.Ordinal)) != null;
}
void MarkAndPreserveAll (TypeDefinition type)
{
Annotations.MarkAndPush (type);
Annotations.SetPreserve (type, TypePreserve.All);
if (!type.HasNestedTypes) {
Tracer.Pop ();
return;
}
foreach (TypeDefinition nested in type.NestedTypes)
MarkAndPreserveAll (nested);
Tracer.Pop ();
}
}
Pipeline GetLinkerPipeline ()
{
var p = new Pipeline ();
p.AppendStep (new LoadReferencesStep ());
p.AppendStep (new PreserveUsingAttributesStep (bclAssemblies.Values.Select (Path.GetFileNameWithoutExtension)));
p.AppendStep (new BlacklistStep ());
p.AppendStep (new TypeMapStep ());
p.AppendStep (new MarkStep ());
p.AppendStep (new SweepStep ());
p.AppendStep (new CleanStep ());
p.AppendStep (new RegenerateGuidStep ());
p.AppendStep (new OutputStep ());
return p;
} }
void ExtractClientJs () void ExtractClientJs ()
@ -182,7 +271,7 @@ namespace Ooui.Wasm.Build.Tasks
<script type=""text/javascript""> <script type=""text/javascript"">
var assemblies = ["); var assemblies = [");
var head = ""; var head = "";
foreach (var l in linkedAsmNames) { foreach (var l in linkedAsmPaths.Select (x => Path.GetFileName (x))) {
w.Write (head); w.Write (head);
w.Write ('\"'); w.Write ('\"');
w.Write (l); w.Write (l);

View File

@ -16,4 +16,12 @@
<ProjectReference Include="..\Ooui\Ooui.csproj" /> <ProjectReference Include="..\Ooui\Ooui.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Remove="linker\**" />
<Compile Include="linker\linker\Linker\**" />
<Compile Remove="linker\linker\Linker\Driver.cs" />
<Compile Include="linker\linker\Linker.Steps\**" />
<Compile Remove="linker\linker\Linker\AssemblyInfo.cs" />
</ItemGroup>
</Project> </Project>

@ -0,0 +1 @@
Subproject commit a4f1133b0b06ec3d152b41186732f485413bd1c9

View File

@ -0,0 +1,8 @@
using System;
namespace Ooui
{
class PreserveAttribute : Attribute
{
}
}

View File

@ -6,6 +6,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Net; using System.Net;
using System.Runtime.InteropServices;
namespace Ooui namespace Ooui
{ {
@ -596,6 +597,7 @@ namespace Ooui
} }
} }
[Preserve]
public static void StartWebAssemblySession (string sessionId, string globalElementId, string initialSize) public static void StartWebAssemblySession (string sessionId, string globalElementId, string initialSize)
{ {
Element element; Element element;
@ -613,6 +615,7 @@ namespace Ooui
g.StartSession (); g.StartSession ();
} }
[Preserve]
public static void ReceiveWebAssemblySessionMessageJson (string sessionId, string json) public static void ReceiveWebAssemblySessionMessageJson (string sessionId, string json)
{ {
WebAssemblySession g; WebAssemblySession g;