Esempio n. 1
0
        static void ProcessAssembly(AssemblyDefinition bindingsAssembly, string assemblyPath, string outputPath, BaseAssemblyResolver resolver, string [] knownPaths, NativeTypeManifest manifest, bool verify)
        {
            string metadataFileName = Path.ChangeExtension(outputPath, "json");

            var readerParams = new ReaderParameters {
                AssemblyResolver     = resolver,
                ReadSymbols          = true,
                SymbolReaderProvider = new PortablePdbReaderProvider(),
                ReadingMode          = ReadingMode.Deferred
            };

            var assembly = AssemblyDefinition.ReadAssembly(assemblyPath, readerParams);
            var metadata = new AssemblyMetadata {
                AssemblyName = assembly.Name.Name,
                AssemblyPath = assemblyPath,
                References   = (from module in assembly.Modules
                                from reference in module.AssemblyReferences
                                select AssemblyReferenceMetadata.ResolveReference(reference, resolver, assembly.Name.Name, knownPaths)).ToArray()
            };


            ///////////////////////////////////////////////////////////////////

            //Enums
            var unrealEnums = (from module in assembly.Modules
                               from type in module.Types
                               where type.IsEnum && IsUnrealEnum(type)
                               select type);

            unrealEnums = manifest.CheckForCollisions(unrealEnums, "Enum");

            //Generate metadata
            bool errorGeneratingEnumMetadata = false;
            var  enumMetadata = unrealEnums.ToDictionaryErrorEmit(type => type, type => new EnumMetadata(type), out errorGeneratingEnumMetadata);

            metadata.Enums = enumMetadata.Values.ToArray();

            ///////////////////////////////////////////////////////////////////

            //Structs

            // Capture the current struct list in an array, as IL rewriting for UStructs may add array marshaler types.
            var unrealStructs = (from module in assembly.Modules
                                 from type in module.Types
                                 where type.IsValueType && IsUnrealStruct(type)
                                 select type);


            unrealStructs = manifest.CheckForCollisions(unrealStructs, "Struct");



            // We need to create struct metadata in the correct order to ensure that blittable structs have
            // their UStruct attributes updated before other referencing structs use them to create UnrealTypes.
            var  structStack                    = new Stack <TypeDefinition> ();
            var  pushedStructs                  = new HashSet <TypeDefinition> ();
            var  structHandlingOrder            = new List <TypeDefinition> ();
            var  structMetadata                 = new Dictionary <TypeDefinition, StructMetadata> ();
            bool errorsGeneratingStructMetadata = false;

            foreach (var unrealStruct in unrealStructs)
            {
                if (!pushedStructs.Contains(unrealStruct))
                {
                    structStack.Push(unrealStruct);
                    pushedStructs.Add(unrealStruct);

                    PushReferencedStructsFromAssembly(assembly, unrealStruct, structStack, pushedStructs);

                    while (structStack.Count > 0)
                    {
                        var currentStruct = structStack.Pop();
                        try {
                            if (structMetadata.ContainsKey(currentStruct))
                            {
                                throw new InternalRewriteException(currentStruct, "Attempted to create struct metadata twice");
                            }
                            var currentMetadata = new StructMetadata(currentStruct);

                            structHandlingOrder.Add(currentStruct);
                            structMetadata.Add(currentStruct, currentMetadata);
                        } catch (MonoAssemblyProcessError error) {
                            errorsGeneratingStructMetadata = true;
                            ErrorEmitter.Error(error);
                        }
                    }
                }
            }
            metadata.Structs = structMetadata.Values.ToArray();

            // Rewrite as a separate pass.  For substructs, we need access to metadata.Structs to propagate hashes.
            foreach (var currentStruct in structHandlingOrder)
            {
                StructMetadata currentMetadata = structMetadata [currentStruct];
                RewriteUnrealStruct(metadata, assembly, currentStruct, currentMetadata, bindingsAssembly);
            }

            ///////////////////////////////////////////////////////////////////

            //Classes

            bool unrealClassError;
            // get all the unreal classes (we don't care if they are exported)
            var unrealClasses = assembly.Modules.SelectMany(x => x.Types).SelectWhereErrorEmit(type => type.IsClass && type.BaseType != null && IsUnrealClass(type), type => type, out unrealClassError);

            unrealClasses = manifest.CheckForCollisions(unrealClasses, "Class");

            bool errorGeneratingMetadata;
            var  unrealClassDictionary = unrealClasses.ToDictionaryErrorEmit(type => type, type => ClassMetadata.Create(type, GetUnrealClass(type)), out errorGeneratingMetadata);

            if (errorGeneratingMetadata || errorsGeneratingStructMetadata || errorGeneratingEnumMetadata)
            {
                throw new MetaDataGenerationException();
            }
            metadata.Classes = unrealClassDictionary.Values.ToArray();

            if (unrealClassDictionary.Count > 0)
            {
                var rewriteStack     = new Stack <KeyValuePair <TypeDefinition, ClassMetadata> > ();
                var rewrittenClasses = new HashSet <TypeDefinition> ();

                // make sure we write base classes before derived ones
                foreach (var pair in unrealClassDictionary)
                {
                    var  currentPair = pair;
                    bool needRewrite = true;
                    while (needRewrite)
                    {
                        if (!rewrittenClasses.Contains(currentPair.Key))
                        {
                            rewriteStack.Push(currentPair);
                            var baseType = currentPair.Key.BaseType.Resolve();

                            if (unrealClassDictionary.ContainsKey(baseType))
                            {
                                ClassMetadata baseClassMetadata = unrealClassDictionary [baseType];

                                currentPair = new KeyValuePair <TypeDefinition, ClassMetadata> (baseType, baseClassMetadata);
                            }
                            else
                            {
                                needRewrite = false;
                            }
                        }
                        else
                        {
                            needRewrite = false;
                        }
                    }

                    while (rewriteStack.Count > 0)
                    {
                        currentPair = rewriteStack.Pop();
                        if (rewrittenClasses.Contains(currentPair.Key))
                        {
                            throw new InternalRewriteException(currentPair.Key, "Attempted to rewrite class twice");
                        }
                        var baseType = currentPair.Key.BaseType;
                        if (baseType != null && unrealClassDictionary.ContainsKey(baseType.Resolve()))
                        {
                            ClassMetadata superClassMetadata = unrealClassDictionary [baseType.Resolve()];
                            currentPair.Value.SetSuperClassHash(superClassMetadata);
                        }

                        RewriteUnrealClass(metadata, assembly, currentPair.Key, currentPair.Value, bindingsAssembly);
                        rewrittenClasses.Add(currentPair.Key);
                    }
                }

                var writer = new WriterParameters {
                    WriteSymbols = true, SymbolWriterProvider = new PortablePdbWriterProvider()
                };
                assembly.Write(outputPath, writer);

                VerifyAssembly(outputPath, knownPaths, verify);

                //for some reason msbuild uses creation time or incrementral builds, not mtime
                //but cecil preserves the creation time from the original so we have to reset it
                File.SetCreationTimeUtc(outputPath, DateTime.UtcNow);

                string metadataContents = fastJSON.JSON.ToNiceJSON(metadata, new fastJSON.JSONParameters {
                    UseExtensions = false
                });
                File.WriteAllText(metadataFileName, metadataContents);
            }
            else
            {
                File.Delete(metadataFileName);
            }
        }