Browse Source

SourceLink?

pull/11062/head
Nikita Tsukanov 3 years ago
parent
commit
0f7fba7f7f
  1. 131
      nukebuild/RefAssemblyGenerator.cs
  2. 1
      nukebuild/_build.csproj

131
nukebuild/RefAssemblyGenerator.cs

@ -1,39 +1,69 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.Writer;
using ILRepacking;
using Mono.Cecil;
using Mono.Cecil.Cil;
public class RefAssemblyGenerator
{
static void PatchRefAssembly(string file)
class Resolver : DefaultAssemblyResolver, IAssemblyResolver
{
private readonly string _dir;
Dictionary<string, AssemblyDefinition> _cache = new();
public Resolver(string dir)
{
_dir = dir;
}
public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
if (_cache.TryGetValue(name.Name, out var asm))
return asm;
var path = Path.Combine(_dir, name.Name + ".dll");
if (File.Exists(path))
return _cache[name.Name] = AssemblyDefinition.ReadAssembly(path, parameters);
return base.Resolve(name, parameters);
}
}
public static void PatchRefAssembly(string file)
{
var reader = typeof(RefAssemblyGenerator).Assembly.GetManifestResourceStream("avalonia.snk");
var snk = new byte[reader.Length];
reader.Read(snk, 0, snk.Length);
var def = AssemblyDef.Load(new MemoryStream(File.ReadAllBytes(file)));
var obsoleteAttribute = new TypeRefUser(def.ManifestModule, "System", "ObsoleteAttribute", def.ManifestModule.CorLibTypes.AssemblyRef);
var obsoleteCtor = def.ManifestModule.Import(new MemberRefUser(def.ManifestModule, ".ctor",
new MethodSig(CallingConvention.Default, 0, def.ManifestModule.CorLibTypes.Void, new TypeSig[]
{
def.ManifestModule.CorLibTypes.String
}), obsoleteAttribute));
foreach(var t in def.ManifestModule.Types)
var def = AssemblyDefinition.ReadAssembly(file, new ReaderParameters
{
ReadWrite = true,
InMemory = true,
ReadSymbols = true,
SymbolReaderProvider = new DefaultSymbolReaderProvider(false),
AssemblyResolver = new Resolver(Path.GetDirectoryName(file))
});
var obsoleteAttribute = def.MainModule.ImportReference(new TypeReference("System", "ObsoleteAttribute", def.MainModule,
def.MainModule.TypeSystem.CoreLibrary));
var obsoleteCtor = def.MainModule.ImportReference(new MethodReference(".ctor",
def.MainModule.TypeSystem.Void, obsoleteAttribute)
{
Parameters = { new ParameterDefinition(def.MainModule.TypeSystem.String) }
});
foreach(var t in def.MainModule.Types)
ProcessType(t, obsoleteCtor);
def.Write(file, new ModuleWriterOptions(def.ManifestModule)
def.Write(file, new WriterParameters()
{
StrongNameKey = new StrongNameKey(snk),
StrongNameKeyBlob = snk,
WriteSymbols = def.MainModule.HasSymbols,
SymbolWriterProvider = new EmbeddedPortablePdbWriterProvider(),
DeterministicMvid = def.MainModule.HasSymbols
});
}
static void ProcessType(TypeDef type, MemberRef obsoleteCtor)
static void ProcessType(TypeDefinition type, MethodReference obsoleteCtor)
{
foreach (var nested in type.NestedTypes)
ProcessType(nested, obsoleteCtor);
@ -59,12 +89,11 @@ public class RefAssemblyGenerator
if(injectMethod)
{
type.Methods.Add(new MethodDefUser("NotClientImplementable",
new MethodSig(CallingConvention.Default, 0, type.Module.CorLibTypes.Void),
type.Methods.Add(new MethodDefinition("NotClientImplementable",
MethodAttributes.Assembly
| MethodAttributes.Abstract
| MethodAttributes.NewSlot
| MethodAttributes.HideBySig));
| MethodAttributes.HideBySig, type.Module.TypeSystem.Void));
}
var forceUnstable = type.CustomAttributes.Any(a =>
@ -80,21 +109,24 @@ public class RefAssemblyGenerator
}
}
static void MarkAsUnstable(IMemberDef def, MemberRef obsoleteCtor, bool force)
static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, bool force)
{
if (!force
|| def.HasCustomAttributes == false
|| def.CustomAttributes.All(a => a.AttributeType.FullName != "Avalonia.Metadata.UnstableAttribute"))
return;
if (def.CustomAttributes.Any(a => a.TypeFullName == "System.ObsoleteAttribute"))
if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
return;
def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor, new CAArgument[]
def.CustomAttributes.Add(new CustomAttribute(obsoleteCtor)
{
new(def.Module.CorLibTypes.String,
"This is a part of unstable API and can be changed in minor releases. You have been warned")
}));
ConstructorArguments =
{
new CustomAttributeArgument(obsoleteCtor.Module.TypeSystem.String,
"This is a part of unstable API and can be changed in minor releases. You have been warned")
}
});
}
public static void GenerateRefAsmsInPackage(string packagePath)
@ -110,29 +142,30 @@ public class RefAssemblyGenerator
foreach (var entry in archive.Entries.ToList())
{
if (entry.FullName.StartsWith("lib/"))
if (entry.FullName.StartsWith("lib/") && entry.Name.EndsWith(".xml"))
{
if (entry.Name.EndsWith(".dll"))
{
using (Helpers.UseTempDir(out var temp))
{
var file = Path.Combine(temp, entry.Name);
entry.ExtractToFile(file);
PatchRefAssembly(file);
archive.CreateEntryFromFile(file, "ref/" + entry.FullName.Substring(4));
}
}
else if (entry.Name.EndsWith(".xml"))
{
var newEntry = archive.CreateEntry("ref/" + entry.FullName.Substring(4),
CompressionLevel.Optimal);
using (var src = entry.Open())
using (var dst = newEntry.Open())
src.CopyTo(dst);
}
var newEntry = archive.CreateEntry("ref/" + entry.FullName.Substring(4),
CompressionLevel.Optimal);
using (var src = entry.Open())
using (var dst = newEntry.Open())
src.CopyTo(dst);
}
}
var libs = archive.Entries.Where(e => e.FullName.StartsWith("lib/") && e.FullName.EndsWith(".dll"))
.Select((e => new { s = e.FullName.Split('/'), e = e }))
.Select(e => new { Tfm = e.s[1], Name = e.s[2], Entry = e.e })
.GroupBy(x => x.Tfm);
foreach(var tfm in libs)
using (Helpers.UseTempDir(out var temp))
{
foreach (var l in tfm)
l.Entry.ExtractToFile(Path.Combine(temp, l.Name));
foreach (var l in tfm)
PatchRefAssembly(Path.Combine(temp, l.Name));
foreach (var l in tfm)
archive.CreateEntryFromFile(Path.Combine(temp, l.Name), $"ref/{l.Tfm}/{l.Name}");
}
}
}
}

1
nukebuild/_build.csproj

@ -18,7 +18,6 @@
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="SourceLink" Version="1.1.0" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" PrivateAssets="All" />
<PackageReference Include="dnlib" Version="3.6.0" />
<PackageReference Include="xunit.runner.console" Version="2.4.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

Loading…
Cancel
Save