Skip to content

Commit 78b0b9a

Browse files
wackoisgod0xFA11
andauthored
refactor: ILPP on 2019.4 and 2020.2+ (#447)
* refactor: ilpp refactor to work with older versions of unity (2019.4) * fix: Removing the need to load the asmdef and fixing a compile revert issue * fix: We need to make this public as to follow the ILPP rules * ci: add unity 2019.4 version target * refactor: replace if-guards with UNITY_X_Y_OR_NEWER macros, minor fixes and styling updates * refactor: add `__` prefix to framework internal types & fields and mark them as 'Obsolete' on Unity 2019.4 * ci: disable built-in Unity ILPP on 2021.1+ (trunk) temporarily * refactor: minor naming fixes, removing 2021.1+ guards (disable ILPP on MLAPI.Runtime) Co-authored-by: M. Fatih MAR <mfatihmar@gmail.com>
1 parent 224276c commit 78b0b9a

16 files changed

Lines changed: 511 additions & 99 deletions

.yamato/project.metafile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Editors where tests will happen. The first entry of this array is also used
22
# for validation
33
test_editors:
4+
- 2019.4
45
- 2020.2
56
- trunk
67

com.unity.multiplayer.mlapi/Editor/CodeGen/CodeGenHelpers.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
using Unity.CompilationPipeline.Common.ILPostProcessing;
1313
using UnityEngine;
1414

15+
#if !UNITY_2019_4_OR_NEWER
16+
#error MLAPI requires Unity 2019.4 or newer
17+
#endif
18+
1519
namespace MLAPI.Editor.CodeGen
1620
{
1721
internal static class CodeGenHelpers
@@ -193,4 +197,4 @@ public static AssemblyDefinition AssemblyDefinitionFor(ICompiledAssembly compile
193197
return assemblyDefinition;
194198
}
195199
}
196-
}
200+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#if !UNITY_2020_2_OR_NEWER
2+
using System.IO;
3+
using Unity.CompilationPipeline.Common.ILPostProcessing;
4+
5+
namespace MLAPI.Editor.CodeGen
6+
{
7+
internal class ILPostProcessCompiledAssembly : ICompiledAssembly
8+
{
9+
private readonly string m_AssemblyFilename;
10+
private readonly string m_OutputPath;
11+
private InMemoryAssembly m_InMemoryAssembly;
12+
13+
public ILPostProcessCompiledAssembly(string asmName, string[] refs, string[] defines, string outputPath)
14+
{
15+
m_AssemblyFilename = asmName;
16+
Name = Path.GetFileNameWithoutExtension(m_AssemblyFilename);
17+
References = refs;
18+
Defines = defines;
19+
m_OutputPath = outputPath;
20+
}
21+
22+
public string Name { get; }
23+
public string[] References { get; }
24+
public string[] Defines { get; }
25+
26+
public InMemoryAssembly InMemoryAssembly
27+
{
28+
get
29+
{
30+
if (m_InMemoryAssembly == null)
31+
{
32+
m_InMemoryAssembly = new InMemoryAssembly(
33+
File.ReadAllBytes(Path.Combine(m_OutputPath, m_AssemblyFilename)),
34+
File.ReadAllBytes(Path.Combine(m_OutputPath, $"{Path.GetFileNameWithoutExtension(m_AssemblyFilename)}.pdb")));
35+
}
36+
37+
return m_InMemoryAssembly;
38+
}
39+
}
40+
}
41+
}
42+
#endif

com.unity.multiplayer.mlapi/Editor/CodeGen/ILPostProcessCompiledAssembly.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#if !UNITY_2020_2_OR_NEWER
2+
using Unity.CompilationPipeline.Common.ILPostProcessing;
3+
4+
namespace MLAPI.Editor.CodeGen
5+
{
6+
public abstract class ILPostProcessor
7+
{
8+
public abstract bool WillProcess(ICompiledAssembly compiledAssembly);
9+
public abstract ILPostProcessResult Process(ICompiledAssembly compiledAssembly);
10+
public abstract ILPostProcessor GetInstance();
11+
}
12+
}
13+
#endif

com.unity.multiplayer.mlapi/Editor/CodeGen/ILPostProcessor.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#if !UNITY_2020_2_OR_NEWER
2+
using System;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Linq;
6+
using Unity.CompilationPipeline.Common.Diagnostics;
7+
using Unity.CompilationPipeline.Common.ILPostProcessing;
8+
using UnityEditor;
9+
using UnityEditor.Compilation;
10+
using UnityEngine;
11+
12+
using Assembly = System.Reflection.Assembly;
13+
14+
namespace MLAPI.Editor.CodeGen
15+
{
16+
internal static class ILPostProcessProgram
17+
{
18+
private static ILPostProcessor[] s_ILPostProcessors { get; set; }
19+
20+
[InitializeOnLoadMethod]
21+
private static void OnInitializeOnLoad()
22+
{
23+
CompilationPipeline.assemblyCompilationFinished += OnCompilationFinished;
24+
s_ILPostProcessors = FindAllPostProcessors();
25+
}
26+
27+
private static ILPostProcessor[] FindAllPostProcessors()
28+
{
29+
var typesDerivedFrom = TypeCache.GetTypesDerivedFrom<ILPostProcessor>();
30+
var localILPostProcessors = new List<ILPostProcessor>(typesDerivedFrom.Count);
31+
32+
foreach (var typeCollection in typesDerivedFrom)
33+
{
34+
try
35+
{
36+
localILPostProcessors.Add((ILPostProcessor)Activator.CreateInstance(typeCollection));
37+
}
38+
catch (Exception exception)
39+
{
40+
Debug.LogError($"Could not create ILPostProcessor ({typeCollection.FullName}):{Environment.NewLine}{exception.StackTrace}");
41+
}
42+
}
43+
44+
// Default sort by type full name
45+
localILPostProcessors.Sort((left, right) => string.Compare(left.GetType().FullName, right.GetType().FullName, StringComparison.Ordinal));
46+
47+
return localILPostProcessors.ToArray();
48+
}
49+
50+
private static void OnCompilationFinished(string targetAssembly, CompilerMessage[] messages)
51+
{
52+
if (messages.Length > 0)
53+
{
54+
if (messages.Any(msg => msg.type == CompilerMessageType.Error))
55+
{
56+
return;
57+
}
58+
}
59+
60+
// Should not run on the editor only assemblies
61+
if (targetAssembly.Contains("-Editor") || targetAssembly.Contains(".Editor"))
62+
{
63+
return;
64+
}
65+
66+
// Should not run on Unity Engine modules but we can run on the MLAPI Runtime DLL
67+
if ((targetAssembly.Contains("com.unity") || Path.GetFileName(targetAssembly).StartsWith("Unity")) && !targetAssembly.Contains("Unity.Multiplayer."))
68+
{
69+
return;
70+
}
71+
72+
// Debug.Log($"Running MLAPI ILPP on {targetAssembly}");
73+
74+
var outputDirectory = $"{Application.dataPath}/../{Path.GetDirectoryName(targetAssembly)}";
75+
var unityEngine = string.Empty;
76+
var mlapiRuntimeAssemblyPath = string.Empty;
77+
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
78+
var usesMLAPI = false;
79+
var foundThisAssembly = false;
80+
81+
var depenencyPaths = new List<string>();
82+
foreach (var assembly in assemblies)
83+
{
84+
// Find the assembly currently being compiled from domain assembly list and check if it's using unet
85+
if (assembly.GetName().Name == Path.GetFileNameWithoutExtension(targetAssembly))
86+
{
87+
foundThisAssembly = true;
88+
foreach (var dependency in assembly.GetReferencedAssemblies())
89+
{
90+
// Since this assembly is already loaded in the domain this is a no-op and returns the
91+
// already loaded assembly
92+
depenencyPaths.Add(Assembly.Load(dependency).Location);
93+
if (dependency.Name.Contains(CodeGenHelpers.RuntimeAssemblyName))
94+
{
95+
usesMLAPI = true;
96+
}
97+
}
98+
}
99+
100+
try
101+
{
102+
if (assembly.Location.Contains("UnityEngine.CoreModule"))
103+
{
104+
unityEngine = assembly.Location;
105+
}
106+
107+
if (assembly.Location.Contains(CodeGenHelpers.RuntimeAssemblyName))
108+
{
109+
mlapiRuntimeAssemblyPath = assembly.Location;
110+
}
111+
}
112+
catch (NotSupportedException)
113+
{
114+
// in memory assembly, can't get location
115+
}
116+
}
117+
118+
if (!foundThisAssembly)
119+
{
120+
// Target assembly not found in current domain, trying to load it to check references
121+
// will lead to trouble in the build pipeline, so lets assume it should go to weaver.
122+
// Add all assemblies in current domain to dependency list since there could be a
123+
// dependency lurking there (there might be generated assemblies so ignore file not found exceptions).
124+
// (can happen in runtime test framework on editor platform and when doing full library reimport)
125+
foreach (var assembly in assemblies)
126+
{
127+
try
128+
{
129+
if (!(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder))
130+
{
131+
depenencyPaths.Add(Assembly.Load(assembly.GetName().Name).Location);
132+
}
133+
}
134+
catch (FileNotFoundException)
135+
{
136+
}
137+
}
138+
139+
usesMLAPI = true;
140+
}
141+
142+
// We check if we are the MLAPI!
143+
if (!usesMLAPI)
144+
{
145+
// we shall also check and see if it we are ourself
146+
usesMLAPI = targetAssembly.Contains(CodeGenHelpers.RuntimeAssemblyName);
147+
}
148+
149+
if (!usesMLAPI)
150+
{
151+
return;
152+
}
153+
154+
if (string.IsNullOrEmpty(unityEngine))
155+
{
156+
Debug.LogError("Failed to find UnityEngine assembly");
157+
return;
158+
}
159+
160+
if (string.IsNullOrEmpty(mlapiRuntimeAssemblyPath))
161+
{
162+
Debug.LogError("Failed to find mlapi runtime assembly");
163+
return;
164+
}
165+
166+
var assemblyPathName = Path.GetFileName(targetAssembly);
167+
168+
var targetCompiledAssembly = new ILPostProcessCompiledAssembly(assemblyPathName, depenencyPaths.ToArray(), null, outputDirectory);
169+
170+
void WriteAssembly(InMemoryAssembly inMemoryAssembly, string outputPath, string assName)
171+
{
172+
if (inMemoryAssembly == null)
173+
{
174+
throw new ArgumentException("InMemoryAssembly has never been accessed or modified");
175+
}
176+
177+
var asmPath = Path.Combine(outputPath, assName);
178+
var pdbFileName = $"{Path.GetFileNameWithoutExtension(assName)}.pdb";
179+
var pdbPath = Path.Combine(outputPath, pdbFileName);
180+
181+
File.WriteAllBytes(asmPath, inMemoryAssembly.PeData);
182+
File.WriteAllBytes(pdbPath, inMemoryAssembly.PdbData);
183+
}
184+
185+
foreach (var i in s_ILPostProcessors)
186+
{
187+
var result = i.Process(targetCompiledAssembly);
188+
if (result == null)
189+
continue;
190+
191+
if (result.Diagnostics.Count > 0)
192+
{
193+
Debug.LogError($"ILPostProcessor - {i.GetType().Name} failed to run on {targetCompiledAssembly.Name}");
194+
195+
foreach (var message in result.Diagnostics)
196+
{
197+
switch (message.DiagnosticType)
198+
{
199+
case DiagnosticType.Error:
200+
Debug.LogError($"ILPostProcessor Error - {message.MessageData} {message.File} {message.Line} {message.Column}");
201+
break;
202+
case DiagnosticType.Warning:
203+
Debug.LogWarning($"ILPostProcessor Warning - {message.MessageData} {message.File} {message.Line} {message.Column}");
204+
break;
205+
}
206+
}
207+
208+
continue;
209+
}
210+
211+
// we now need to write out the result?
212+
WriteAssembly(result.InMemoryAssembly, outputDirectory, assemblyPathName);
213+
}
214+
}
215+
}
216+
}
217+
#endif

com.unity.multiplayer.mlapi/Editor/CodeGen/ILPostProcessorProgram.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)