Skip to content

Commit b702e24

Browse files
authored
Merge pull request #12410 from MrJul/fixes/ref-pdb
Generate pdb for ref assemblies
2 parents 92957eb + f253b61 commit b702e24

File tree

2 files changed

+70
-44
lines changed

2 files changed

+70
-44
lines changed

nukebuild/Build.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,9 @@ void DoMemoryTest()
279279
if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,
280280
new NumergeNukeLogger()))
281281
throw new Exception("Package merge failed");
282-
RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." +
283-
Parameters.Version + ".nupkg");
282+
RefAssemblyGenerator.GenerateRefAsmsInPackage(
283+
Parameters.NugetRoot / $"Avalonia.{Parameters.Version}.nupkg",
284+
Parameters.NugetRoot / $"Avalonia.{Parameters.Version}.snupkg");
284285
});
285286

286287
Target ValidateApiDiff => _ => _

nukebuild/RefAssemblyGenerator.cs

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1+
#nullable enable
2+
3+
using System;
14
using System.Collections.Generic;
25
using System.IO;
36
using System.IO.Compression;
47
using System.Linq;
5-
using ILRepacking;
68
using Mono.Cecil;
79
using Mono.Cecil.Cil;
810

911
public class RefAssemblyGenerator
1012
{
1113
class Resolver : DefaultAssemblyResolver, IAssemblyResolver
1214
{
13-
private readonly string _dir;
14-
Dictionary<string, AssemblyDefinition> _cache = new();
15+
readonly string _dir;
16+
readonly Dictionary<string, AssemblyDefinition> _cache = new();
1517

1618
public Resolver(string dir)
1719
{
@@ -31,17 +33,17 @@ public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderPar
3133

3234
public static void PatchRefAssembly(string file)
3335
{
34-
var reader = typeof(RefAssemblyGenerator).Assembly.GetManifestResourceStream("avalonia.snk");
36+
var reader = typeof(RefAssemblyGenerator).Assembly.GetManifestResourceStream("avalonia.snk")!;
3537
var snk = new byte[reader.Length];
36-
reader.Read(snk, 0, snk.Length);
38+
reader.ReadExactly(snk, 0, snk.Length);
3739

3840
var def = AssemblyDefinition.ReadAssembly(file, new ReaderParameters
3941
{
4042
ReadWrite = true,
4143
InMemory = true,
4244
ReadSymbols = true,
43-
SymbolReaderProvider = new DefaultSymbolReaderProvider(false),
44-
AssemblyResolver = new Resolver(Path.GetDirectoryName(file))
45+
SymbolReaderProvider = new DefaultSymbolReaderProvider(throwIfNoSymbol: true),
46+
AssemblyResolver = new Resolver(Path.GetDirectoryName(file)!)
4547
});
4648

4749
var obsoleteAttribute = def.MainModule.ImportReference(new TypeReference("System", "ObsoleteAttribute", def.MainModule,
@@ -58,7 +60,7 @@ public static void PatchRefAssembly(string file)
5860
{
5961
StrongNameKeyBlob = snk,
6062
WriteSymbols = def.MainModule.HasSymbols,
61-
SymbolWriterProvider = new EmbeddedPortablePdbWriterProvider(),
63+
SymbolWriterProvider = new PortablePdbWriterProvider(),
6264
DeterministicMvid = def.MainModule.HasSymbols
6365
});
6466
}
@@ -146,7 +148,7 @@ static void HideMethod(MethodDefinition m)
146148
m.Attributes = ((m.Attributes | dflags) ^ dflags) | MethodAttributes.Assembly;
147149
}
148150

149-
static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, ICustomAttribute unstableAttribute)
151+
static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor, ICustomAttribute? unstableAttribute)
150152
{
151153
if (def.CustomAttributes.Any(a => a.AttributeType.FullName == "System.ObsoleteAttribute"))
152154
return;
@@ -172,43 +174,66 @@ static void MarkAsUnstable(IMemberDefinition def, MethodReference obsoleteCtor,
172174
});
173175
}
174176

175-
public static void GenerateRefAsmsInPackage(string packagePath)
177+
public static void GenerateRefAsmsInPackage(string mainPackagePath, string symbolsPackagePath)
176178
{
177-
using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
178-
ZipArchiveMode.Update))
179+
using var mainArchive = OpenPackage(mainPackagePath);
180+
using var symbolsArchive = OpenPackage(symbolsPackagePath);
181+
182+
foreach (var entry in mainArchive.Entries
183+
.Where(e => e.FullName.StartsWith("ref/", StringComparison.Ordinal))
184+
.ToArray())
179185
{
180-
foreach (var entry in archive.Entries.ToList())
181-
{
182-
if (entry.FullName.StartsWith("ref/"))
183-
entry.Delete();
184-
}
185-
186-
foreach (var entry in archive.Entries.ToList())
186+
entry.Delete();
187+
}
188+
189+
foreach (var libEntry in GetLibEntries(mainArchive, ".xml"))
190+
{
191+
var refEntry = mainArchive.CreateEntry("ref/" + libEntry.FullName.Substring(4), CompressionLevel.Optimal);
192+
using var src = libEntry.Open();
193+
using var dst = refEntry.Open();
194+
src.CopyTo(dst);
195+
}
196+
197+
var pdbEntries = GetLibEntries(symbolsArchive, ".pdb").ToDictionary(e => e.FullName);
198+
199+
var libs = GetLibEntries(mainArchive, ".dll")
200+
.Select(e => (NameParts: e.FullName.Split('/'), Entry: e))
201+
.Select(e => (
202+
Tfm: e.NameParts[1],
203+
DllName: e.NameParts[2],
204+
DllEntry: e.Entry,
205+
PdbName: Path.ChangeExtension(e.NameParts[2], ".pdb"),
206+
PdbEntry: pdbEntries.TryGetValue(Path.ChangeExtension(e.Entry.FullName, ".pdb"), out var pdbEntry) ?
207+
pdbEntry :
208+
throw new InvalidOperationException($"Missing symbols for {e.Entry.FullName}")))
209+
.GroupBy(e => e.Tfm);
210+
211+
foreach (var tfm in libs)
212+
{
213+
using var _ = Helpers.UseTempDir(out var temp);
214+
215+
foreach (var lib in tfm)
187216
{
188-
if (entry.FullName.StartsWith("lib/") && entry.Name.EndsWith(".xml"))
189-
{
190-
var newEntry = archive.CreateEntry("ref/" + entry.FullName.Substring(4),
191-
CompressionLevel.Optimal);
192-
using (var src = entry.Open())
193-
using (var dst = newEntry.Open())
194-
src.CopyTo(dst);
195-
}
196-
}
217+
var extractedDllPath = Path.Combine(temp, lib.DllName);
218+
var extractedPdbPath = Path.Combine(temp, lib.PdbName);
219+
220+
lib.DllEntry.ExtractToFile(extractedDllPath);
221+
lib.PdbEntry.ExtractToFile(extractedPdbPath);
197222

198-
var libs = archive.Entries.Where(e => e.FullName.StartsWith("lib/") && e.FullName.EndsWith(".dll"))
199-
.Select((e => new { s = e.FullName.Split('/'), e = e }))
200-
.Select(e => new { Tfm = e.s[1], Name = e.s[2], Entry = e.e })
201-
.GroupBy(x => x.Tfm);
202-
foreach(var tfm in libs)
203-
using (Helpers.UseTempDir(out var temp))
204-
{
205-
foreach (var l in tfm)
206-
l.Entry.ExtractToFile(Path.Combine(temp, l.Name));
207-
foreach (var l in tfm)
208-
PatchRefAssembly(Path.Combine(temp, l.Name));
209-
foreach (var l in tfm)
210-
archive.CreateEntryFromFile(Path.Combine(temp, l.Name), $"ref/{l.Tfm}/{l.Name}");
211-
}
223+
PatchRefAssembly(extractedDllPath);
224+
225+
mainArchive.CreateEntryFromFile(extractedDllPath, $"ref/{lib.Tfm}/{lib.DllName}");
226+
symbolsArchive.CreateEntryFromFile(extractedPdbPath, $"ref/{lib.Tfm}/{lib.PdbName}");
227+
}
212228
}
229+
230+
static ZipArchive OpenPackage(string packagePath)
231+
=> new(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite), ZipArchiveMode.Update);
232+
233+
static ZipArchiveEntry[] GetLibEntries(ZipArchive archive, string extension)
234+
=> archive.Entries
235+
.Where(e => e.FullName.StartsWith("lib/", StringComparison.Ordinal)
236+
&& e.FullName.EndsWith(extension, StringComparison.Ordinal))
237+
.ToArray();
213238
}
214239
}

0 commit comments

Comments
 (0)