示例#1
0
            public IEnumerable <T> CheckForCollisions <T> (IEnumerable <T> collection, string type) where T : IMemberDefinition
            {
                void FindCollisions(HashSet <string> names, string kind)
                {
                    var collisions = collection.Where(item => names.Contains(item.Name));

                    foreach (var collision in collisions)
                    {
                        SequencePoint point = ErrorEmitter.GetSequencePointFromMemberDefinition(collision);
                        ErrorEmitter.Error(ErrorCode.CollidingTypeName, $"All Unreal types live in same namespace. {type} '{collision.Name}' conflicts with existing native {kind}", point);
                    }
                    collection = collection.Except(collisions);
                }

                FindCollisions(Classes, "class");
                FindCollisions(Structs, "struct");
                FindCollisions(Enums, "enum");

                return(collection);
            }
示例#2
0
 public InvalidUnrealFunctionException(MethodDefinition method, string message, Exception innerException = null)
     : base(String.Format("Method '{0}' is not a valid Unreal function: {1}", method.Name, message), innerException, ErrorEmitter.GetSequencePointFromMemberDefinition(method))
 {
 }
示例#3
0
 public InvalidUnrealPropertyException(IMemberDefinition property, string message)
     : this(property.FullName, ErrorEmitter.GetSequencePointFromMemberDefinition(property), message)
 {
 }
示例#4
0
 public InvalidUnrealEnumException(TypeDefinition enom, string message)
     : base(String.Format("Enum '{0}' is not a valid Unreal enum: {1}", enom.FullName, message), ErrorEmitter.GetSequencePointFromMemberDefinition(enom))
 {
 }
示例#5
0
 public InvalidUnrealStructException(TypeDefinition strukt, string message)
     : base(String.Format("Struct '{0}' is not a valid Unreal struct: {1}", strukt.FullName, message), ErrorEmitter.GetSequencePointFromMemberDefinition(strukt))
 {
 }
示例#6
0
 public InvalidUnrealClassException(TypeDefinition klass, string message)
     : this(klass.FullName, ErrorEmitter.GetSequencePointFromMemberDefinition(klass), message)
 {
 }
示例#7
0
 public ConstructorNotFoundException(TypeDefinition type, string message)
     : base(message, ErrorEmitter.GetSequencePointFromMemberDefinition(type))
 {
 }
示例#8
0
 public InternalRewriteException(TypeDefinition type, string message)
     : base($"Internal error rewriting type {type.FullName}: {message}", ErrorEmitter.GetSequencePointFromMemberDefinition(type))
 {
 }
示例#9
0
 public UnsupportedPropertyInitializerException(PropertyDefinition property, SequencePoint seq)
     : base($"Property initializers are not supported for properties of type {property.PropertyType.FullName}", seq ?? ErrorEmitter.GetSequencePointFromMemberDefinition(property))
 {
 }
示例#10
0
 public UnableToFixPropertyBackingReferenceException(MethodDefinition constructor, PropertyDefinition property, OpCode opCode)
     : base($"The type {constructor.DeclaringType.FullName}'s constructor references the property {property.Name} using an unsupported IL pattern", ErrorEmitter.GetSequencePointFromMemberDefinition(constructor))
 {
 }
示例#11
0
 public InvalidConstructorException(MethodDefinition constructor, string message)
     : base(message, ErrorEmitter.GetSequencePointFromMemberDefinition(constructor))
 {
 }
示例#12
0
 public NotDerivableClassException(TypeDefinition klass, TypeDefinition superKlass)
     : base(String.Format("Class '{0}' is invalid because '{1}' may not be derived from in managed code.", klass.FullName, superKlass.FullName), ErrorEmitter.GetSequencePointFromMemberDefinition(klass))
 {
 }
示例#13
0
 public InvalidEnumMemberException(TypeDefinition enom, FieldReference field, string message, Exception innerException = null)
     : base(String.Format("Enum '{0}' has invalid field '{1}': {2}", enom.Name, field.Name, message), innerException, ErrorEmitter.GetSequencePointFromMemberDefinition(enom))
 {
 }
示例#14
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);
            }
        }
示例#15
0
        static bool ProcessAssemblyInPlace(AssemblyDefinition bindingsAssembly, string assemblyPath, BaseAssemblyResolver resolver, string [] knownPaths, NativeTypeManifest manifest, bool verify)
        {
            string backupFile       = Path.ChangeExtension(assemblyPath, ".bak.dll");
            string pdbFile          = Path.ChangeExtension(assemblyPath, ".pdb");
            string backupPdbFile    = Path.ChangeExtension(pdbFile, ".bak.pdb");
            string metadataFileName = Path.ChangeExtension(assemblyPath, "json");

            // before we rewrite, copy the original assembly to a backup location
            // if we're debugging we might be using backup files directly, don't do the copy
            if (!assemblyPath.Contains(".bak"))
            {
                File.Copy(assemblyPath, backupFile, true);
                if (File.Exists(pdbFile))
                {
                    File.Copy(pdbFile, backupPdbFile, true);
                }
            }

            try {
                ProcessAssembly(bindingsAssembly, assemblyPath, assemblyPath, resolver, knownPaths, manifest, verify);

                // if we got this far without an exception, safe to delete the bak files
                if (File.Exists(backupFile))
                {
                    File.Delete(backupFile);
                }
                if (File.Exists(backupPdbFile))
                {
                    File.Delete(backupPdbFile);
                }
            } catch (MonoAssemblyProcessError error) {
                ErrorEmitter.Error(error);
                // if we're debugging, we may be operating on the backup files
                if (!assemblyPath.Contains(".bak"))
                {
                    // delete originals so UE4 won't think the assembly is valid
                    if (File.Exists(assemblyPath))
                    {
                        File.Delete(assemblyPath);
                    }
                    if (File.Exists(pdbFile))
                    {
                        File.Delete(pdbFile);
                    }
                    if (File.Exists(metadataFileName))
                    {
                        File.Delete(metadataFileName);
                    }
                }
                return(false);
            } catch (Exception e) {
                Console.Error.WriteLine("Exception processing {0}", assemblyPath);
                Console.Error.WriteLine(e.Message);
                Console.Error.WriteLine(e.StackTrace);
                // if we're debugging, we may be operating on the backup files
                if (!assemblyPath.Contains(".bak"))
                {
                    // delete originals so UE4 won't think the assembly is valid
                    if (File.Exists(assemblyPath))
                    {
                        File.Delete(assemblyPath);
                    }
                    if (File.Exists(pdbFile))
                    {
                        File.Delete(pdbFile);
                    }
                    if (File.Exists(metadataFileName))
                    {
                        File.Delete(metadataFileName);
                    }
                }
                return(false);
            }
            return(true);
        }
示例#16
0
        static int Main(string [] args)
        {
            var    assemblyPaths = new List <string> ();
            string baseUnrealBindingsNamespace = "UnrealEngine";
            bool   showHelp  = false;
            bool   verify    = false;
            string outputDir = null;
            var    options   = new OptionSet()
            {
                { "p|path=", "Additional search paths for assemblies", v => assemblyPaths.Add(StripQuotes(v)) },
                { "n|namespace=", "Base unreal bindings namespace", v => baseUnrealBindingsNamespace = v },
                { "o|output=", "Output directory", v => outputDir = v },
                { "h|help", "Show this message and exit", v => showHelp = v != null },
                { "verify", "Verify processed assemblies", v => verify = v != null }
            };

            List <string> extra;

            try {
                extra = options.Parse(args);
            } catch (OptionException e) {
                Console.Error.Write("MonoAssemblyProcess: ");
                Console.Error.WriteLine(e.Message);
                Console.Error.WriteLine("Try 'MonoAssemblyProcess --help' for more information");
                return(1);
            }

            if (showHelp)
            {
                ShowHelp(options);
                return(0);
            }

            if (extra.Count == 0)
            {
                Console.Error.WriteLine("Need at least one assembly to process!");
                Console.Error.WriteLine("Try 'MonoAssemblyProcess --help' for more information");
                return(2);
            }

            NativeTypeManifest      manifest = new NativeTypeManifest();
            DefaultAssemblyResolver resolver = new DefaultAssemblyResolver();

            foreach (var lookupPath in assemblyPaths)
            {
                if (Directory.Exists(lookupPath))
                {
                    string nativeClassManifest = Path.Combine(lookupPath, "AllNativeClasses.manifest");

                    if (File.Exists(nativeClassManifest))
                    {
                        manifest = new NativeTypeManifest(nativeClassManifest);
                    }
                    resolver.AddSearchDirectory(lookupPath);
                }
                else
                {
                    Console.Error.WriteLine("Warning: Assembly resolve path {0} does not exist, skipping", lookupPath);
                }
            }

            string [] knownPaths = assemblyPaths.ToArray();

            BaseUnrealNamespace = baseUnrealBindingsNamespace;
            BindingsNamespace   = baseUnrealBindingsNamespace + "." + BindingsSubnamespace;

            AssemblyDefinition bindingsAssembly = resolver.Resolve(new AssemblyNameReference(BindingsNamespace, new Version(0, 0, 0, 0)));

            if (null == bindingsAssembly)
            {
                Console.Error.WriteLine("Could not find bindings assembly: " + BindingsNamespace);
                return(3);
            }

            foreach (var quotedAssemblyPath in extra)
            {
                var assemblyPath = StripQuotes(quotedAssemblyPath);
                if (outputDir == null)
                {
                    if (!ProcessAssemblyInPlace(bindingsAssembly, assemblyPath, resolver, knownPaths, manifest, verify))
                    {
                        return(4);
                    }
                }
                else
                {
                    var    outputPath          = Path.Combine(outputDir, Path.GetFileName(assemblyPath));
                    string nativeClassManifest = Path.Combine(outputPath, "AllNativeClasses.manifest");

                    if (File.Exists(nativeClassManifest))
                    {
                        manifest = new NativeTypeManifest(nativeClassManifest);
                    }

                    Directory.CreateDirectory(outputDir);
                    try {
                        ProcessAssembly(bindingsAssembly, assemblyPath, outputPath, resolver, knownPaths, manifest, verify);
                    } catch (MonoAssemblyProcessError error) {
                        ErrorEmitter.Error(error);
                    } catch (Exception ex) {
                        Console.Error.WriteLine("Exception processing {0}", assemblyPath);
                        Console.Error.WriteLine(ex.Message);
                        Console.Error.WriteLine(ex.StackTrace);
                        return(4);
                    }
                }
            }

            return(0);
        }