public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
        {
            if (!WillProcess(compiledAssembly))
            {
                return(null);
            }

            var logger = new Logger();
            var weaver = new Weaver(logger);

            AssemblyDefinition assemblyDefinition = weaver.Weave(compiledAssembly);

            // write
            var pe  = new MemoryStream();
            var pdb = new MemoryStream();

            var writerParameters = new WriterParameters
            {
                SymbolWriterProvider = new PortablePdbWriterProvider(),
                SymbolStream         = pdb,
                WriteSymbols         = true
            };

            assemblyDefinition?.Write(pe, writerParameters);

            return(new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), logger.Diagnostics));
        }
Example #2
0
        public static AssemblyDefinition Build(IWeaverLogger logger)
        {
            AssemblyDefinition assembly = null;

            var assemblyBuilder = new AssemblyBuilder(Path.Combine(OutputDirectory, OutputFile), SourceFiles.ToArray())
            {
                referencesOptions = ReferencesOptions.UseEngineModules
            };

            if (AllowUnsafe)
            {
                assemblyBuilder.compilerOptions.AllowUnsafeCode = true;
            }

            assemblyBuilder.buildFinished += delegate(string assemblyPath, CompilerMessage[] compilerMessages)
            {
                CompilerMessages.AddRange(compilerMessages);
                foreach (CompilerMessage cm in compilerMessages)
                {
                    if (cm.type == CompilerMessageType.Error)
                    {
                        Debug.LogErrorFormat("{0}:{1} -- {2}", cm.file, cm.line, cm.message);
                        CompilerErrors = true;
                    }
                }

                // assembly builder does not call ILPostProcessor (WTF Unity?),  so we must invoke it ourselves.
                var compiledAssembly = new CompiledAssembly(assemblyPath)
                {
                    Defines    = assemblyBuilder.defaultDefines,
                    References = assemblyBuilder.defaultReferences
                };

                var weaver = new Weaver(logger);

                assembly = weaver.Weave(compiledAssembly);
            };

            // Start build of assembly
            if (!assemblyBuilder.Build())
            {
                Debug.LogErrorFormat("Failed to start build of assembly {0}", assemblyBuilder.assemblyPath);
                return(assembly);
            }

            while (assemblyBuilder.status != AssemblyBuilderStatus.Finished)
            {
                System.Threading.Thread.Sleep(10);
            }

            return(assembly);
        }
Example #3
0
        // helper function to invoke Weaver with an AssemblyDefinition from a
        // file path, with dependencies added.
        static bool WeaveFromFile(string assemblyPath, string[] dependencies)
        {
            // resolve assembly from stream
            using (DefaultAssemblyResolver asmResolver = new DefaultAssemblyResolver())
                using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters {
                    ReadWrite = true, ReadSymbols = true, AssemblyResolver = asmResolver
                }))
                {
                    // add this assembly's path and unity's assembly path
                    asmResolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath));
                    asmResolver.AddSearchDirectory(Helpers.UnityEngineDllDirectoryName());

                    // add dependencies
                    if (dependencies != null)
                    {
                        foreach (string path in dependencies)
                        {
                            asmResolver.AddSearchDirectory(path);
                        }
                    }

                    // create weaver with logger
                    weaver = new Weaver(new CompilationFinishedLogger());
                    if (weaver.Weave(assembly, asmResolver, out bool modified))
                    {
                        // write changes to file if modified
                        if (modified)
                        {
                            assembly.Write(new WriterParameters {
                                WriteSymbols = true
                            });
                        }

                        return(true);
                    }
                    return(false);
                }
        }
        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));
        }