diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs
index 40232947d9..630c532686 100644
--- a/nukebuild/Build.cs
+++ b/nukebuild/Build.cs
@@ -273,6 +273,8 @@ partial class Build : NukeBuild
if(!Numerge.NugetPackageMerger.Merge(Parameters.NugetIntermediateRoot, Parameters.NugetRoot, config,
new NumergeNukeLogger()))
throw new Exception("Package merge failed");
+ RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." +
+ Parameters.Version + ".nupkg");
});
Target RunTests => _ => _
diff --git a/nukebuild/Helpers.cs b/nukebuild/Helpers.cs
new file mode 100644
index 0000000000..d8d06559bf
--- /dev/null
+++ b/nukebuild/Helpers.cs
@@ -0,0 +1,24 @@
+using System;
+using System.IO;
+using Nuke.Common.Utilities;
+
+class Helpers
+{
+ public static IDisposable UseTempDir(out string dir)
+ {
+ var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
+ Directory.CreateDirectory(path);
+ dir = path;
+ return DelegateDisposable.CreateBracket(null, () =>
+ {
+ try
+ {
+ Directory.Delete(path, true);
+ }
+ catch
+ {
+ // ignore
+ }
+ });
+ }
+}
diff --git a/nukebuild/RefAssemblyGenerator.cs b/nukebuild/RefAssemblyGenerator.cs
new file mode 100644
index 0000000000..912f74cdf9
--- /dev/null
+++ b/nukebuild/RefAssemblyGenerator.cs
@@ -0,0 +1,99 @@
+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;
+
+public class RefAssemblyGenerator
+{
+ 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)));
+
+ foreach(var t in def.ManifestModule.Types)
+ ProcessType(t);
+ def.Write(file, new ModuleWriterOptions(def.ManifestModule)
+ {
+ StrongNameKey = new StrongNameKey(snk),
+ });
+ }
+
+ static void ProcessType(TypeDef type)
+ {
+ foreach (var nested in type.NestedTypes)
+ ProcessType(nested);
+ if (type.IsInterface)
+ {
+ var hideMethods = type.Name.EndsWith("Impl");
+ var injectMethod = hideMethods
+ || type.CustomAttributes.Any(a =>
+ a.AttributeType.FullName.EndsWith("NotClientImplementableAttribute"));
+
+ if (hideMethods)
+ {
+ foreach (var m in type.Methods)
+ {
+ m.Attributes |= MethodAttributes.Public | MethodAttributes.Assembly;
+ m.Attributes ^= MethodAttributes.Public;
+ }
+ }
+
+ if(injectMethod)
+ {
+ type.Methods.Add(new MethodDefUser("NotClientImplementable",
+ new MethodSig(CallingConvention.Default, 0, type.Module.CorLibTypes.Void),
+ MethodAttributes.Assembly
+ | MethodAttributes.Abstract
+ | MethodAttributes.NewSlot
+ | MethodAttributes.HideBySig));
+ }
+ }
+ }
+
+ public static void GenerateRefAsmsInPackage(string packagePath)
+ {
+ using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
+ ZipArchiveMode.Update))
+ {
+ foreach (var entry in archive.Entries.ToList())
+ {
+ if (entry.FullName.StartsWith("ref/"))
+ entry.Delete();
+ }
+
+ foreach (var entry in archive.Entries.ToList())
+ {
+ if (entry.FullName.StartsWith("lib/"))
+ {
+ 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);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj
index 13bac4b7db..cc3ce9f0b0 100644
--- a/nukebuild/_build.csproj
+++ b/nukebuild/_build.csproj
@@ -18,6 +18,7 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -31,18 +32,11 @@
-
-
-
-
-
-
-
+
+
-
-
-
+