123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- // hook via ILPostProcessor from Unity 2020.3+
- // (2020.1 has errors https://github.com/vis2k/Mirror/issues/2912)
- #if UNITY_2020_3_OR_NEWER
- // Unity.CompilationPipeline reference is only resolved if assembly name is
- // Unity.*.CodeGen:
- // https://forum.unity.com/threads/how-does-unity-do-codegen-and-why-cant-i-do-it-myself.853867/#post-5646937
- using System.IO;
- using System.Linq;
- // to use Mono.CecilX here, we need to 'override references' in the
- // Unity.Mirror.CodeGen assembly definition file in the Editor, and add CecilX.
- // otherwise we get a reflection exception with 'file not found: CecilX'.
- using Mono.CecilX;
- using Mono.CecilX.Cil;
- using Unity.CompilationPipeline.Common.ILPostProcessing;
- // IMPORTANT: 'using UnityEngine' does not work in here.
- // Unity gives "(0,0): error System.Security.SecurityException: ECall methods must be packaged into a system module."
- //using UnityEngine;
- namespace Mirror.Weaver
- {
- public class ILPostProcessorHook : ILPostProcessor
- {
- // from CompilationFinishedHook
- const string MirrorRuntimeAssemblyName = "Mirror";
- // ILPostProcessor is invoked by Unity.
- // we can not tell it to ignore certain assemblies before processing.
- // add a 'ignore' define for convenience.
- // => WeaverTests/WeaverAssembler need it to avoid Unity running it
- public const string IgnoreDefine = "ILPP_IGNORE";
- // we can't use Debug.Log in ILPP, so we need a custom logger
- ILPostProcessorLogger Log = new ILPostProcessorLogger();
- // ???
- public override ILPostProcessor GetInstance() => this;
- // check if assembly has the 'ignore' define
- static bool HasDefine(ICompiledAssembly assembly, string define) =>
- assembly.Defines != null &&
- assembly.Defines.Contains(define);
- // process Mirror, or anything that references Mirror
- public override bool WillProcess(ICompiledAssembly compiledAssembly)
- {
- // compiledAssembly.References are file paths:
- // Library/Bee/artifacts/200b0aE.dag/Mirror.CompilerSymbols.dll
- // Assets/Mirror/Plugins/Mono.Cecil/Mono.CecilX.dll
- // /Applications/Unity/Hub/Editor/2021.2.0b6_apple_silicon/Unity.app/Contents/NetStandard/ref/2.1.0/netstandard.dll
- //
- // log them to see:
- // foreach (string reference in compiledAssembly.References)
- // LogDiagnostics($"{compiledAssembly.Name} references {reference}");
- bool relevant = compiledAssembly.Name == MirrorRuntimeAssemblyName ||
- compiledAssembly.References.Any(filePath => Path.GetFileNameWithoutExtension(filePath) == MirrorRuntimeAssemblyName);
- bool ignore = HasDefine(compiledAssembly, IgnoreDefine);
- return relevant && !ignore;
- }
- public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
- {
- //Log.Warning($"Processing {compiledAssembly.Name}");
- // load the InMemoryAssembly peData into a MemoryStream
- byte[] peData = compiledAssembly.InMemoryAssembly.PeData;
- //LogDiagnostics($" peData.Length={peData.Length} bytes");
- using (MemoryStream stream = new MemoryStream(peData))
- using (ILPostProcessorAssemblyResolver asmResolver = new ILPostProcessorAssemblyResolver(compiledAssembly, Log))
- {
- // we need to load symbols. otherwise we get:
- // "(0,0): error Mono.CecilX.Cil.SymbolsNotFoundException: No symbol found for file: "
- using (MemoryStream symbols = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData))
- {
- ReaderParameters readerParameters = new ReaderParameters{
- SymbolStream = symbols,
- ReadWrite = true,
- ReadSymbols = true,
- AssemblyResolver = asmResolver,
- // custom reflection importer to fix System.Private.CoreLib
- // not being found in custom assembly resolver above.
- ReflectionImporterProvider = new ILPostProcessorReflectionImporterProvider()
- };
- using (AssemblyDefinition asmDef = AssemblyDefinition.ReadAssembly(stream, readerParameters))
- {
- // resolving a Mirror.dll type like NetworkServer while
- // weaving Mirror.dll does not work. it throws a
- // NullReferenceException in WeaverTypes.ctor
- // when Resolve() is called on the first Mirror type.
- // need to add the AssemblyDefinition itself to use.
- asmResolver.SetAssemblyDefinitionForCompiledAssembly(asmDef);
- // weave this assembly.
- Weaver weaver = new Weaver(Log);
- if (weaver.Weave(asmDef, asmResolver, out bool modified))
- {
- //Log.Warning($"Weaving succeeded for: {compiledAssembly.Name}");
- // write if modified
- if (modified)
- {
- // when weaving Mirror.dll with ILPostProcessor,
- // Weave() -> WeaverTypes -> resolving the first
- // type in Mirror.dll adds a reference to
- // Mirror.dll even though we are in Mirror.dll.
- // -> this would throw an exception:
- // "Mirror references itself" and not compile
- // -> need to detect and fix manually here
- if (asmDef.MainModule.AssemblyReferences.Any(r => r.Name == asmDef.Name.Name))
- {
- asmDef.MainModule.AssemblyReferences.Remove(asmDef.MainModule.AssemblyReferences.First(r => r.Name == asmDef.Name.Name));
- //Log.Warning($"fixed self referencing Assembly: {asmDef.Name.Name}");
- }
- MemoryStream peOut = new MemoryStream();
- MemoryStream pdbOut = new MemoryStream();
- WriterParameters writerParameters = new WriterParameters
- {
- SymbolWriterProvider = new PortablePdbWriterProvider(),
- SymbolStream = pdbOut,
- WriteSymbols = true
- };
- asmDef.Write(peOut, writerParameters);
- InMemoryAssembly inMemory = new InMemoryAssembly(peOut.ToArray(), pdbOut.ToArray());
- return new ILPostProcessResult(inMemory, Log.Logs);
- }
- }
- // if anything during Weave() fails, we log an error.
- // don't need to indicate 'weaving failed' again.
- // in fact, this would break tests only expecting certain errors.
- //else Log.Error($"Weaving failed for: {compiledAssembly.Name}");
- }
- }
- }
- // always return an ILPostProcessResult with Logs.
- // otherwise we won't see Logs if weaving failed.
- return new ILPostProcessResult(compiledAssembly.InMemoryAssembly, Log.Logs);
- }
- }
- }
- #endif
|