public void GenerateDLL(string folderPath, bool generateLinkXML = true)
        {
            var generateForTypes = this.supportSerializedTypes.Where(n => n.Emit && n.Type != null).Select(n => n.Type).ToList();

            FixUnityAboutWindowBeforeEmit.Fix();
            AOTSupportUtilities.GenerateDLL(folderPath, FormatterEmitter.PRE_EMITTED_ASSEMBLY_NAME, generateForTypes, generateLinkXML);
        }
Пример #2
0
        public void GenerateDLL()
        {
            FixUnityAboutWindowBeforeEmit.Fix();

            const string NAME = FormatterEmitter.PRE_EMITTED_ASSEMBLY_NAME;

            var dirPath         = this.AOTFolderPath;
            var newDllPath      = dirPath + NAME;
            var fullDllPath     = newDllPath + ".dll";
            var fullLinkXmlPath = dirPath + "link.xml";

            var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName()
            {
                Name = NAME
            }, AssemblyBuilderAccess.Save, dirPath);
            var module = assembly.DefineDynamicModule(NAME);

            // The following is a fix for Unity's crappy Mono runtime that doesn't know how to do this sort
            //  of stuff properly
            //
            // We must manually remove the "Default Dynamic Assembly" module that is automatically defined,
            //  otherwise a reference to that non-existent module will be saved into the assembly's IL, and
            //  that will cause a multitude of issues.
            //
            // We do this by forcing there to be only one module - the one we just defined, and we set the
            //   manifest module to be that module as well.
            {
                var modulesField        = assembly.GetType().GetField("modules", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                var manifestModuleField = assembly.GetType().GetField("manifest_module", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                if (modulesField != null)
                {
                    modulesField.SetValue(assembly, new ModuleBuilder[] { module });
                }

                if (manifestModuleField != null)
                {
                    manifestModuleField.SetValue(assembly, module);
                }
            }

            var type = module.DefineType(NAME + ".PreventCodeStrippingViaReferences", TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic);

            CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(typeof(PreserveAttribute).GetConstructor(Type.EmptyTypes), new object[0]);

            type.SetCustomAttribute(attributeBuilder);

            var staticConstructor = type.DefineTypeInitializer();
            var il = staticConstructor.GetILGenerator();

            HashSet <Type> seenTypes = new HashSet <Type>();

            //var endPoint = il.DefineLabel();
            //il.Emit(OpCodes.Br, endPoint);

            foreach (var typeEntry in this.supportSerializedTypes)
            {
                if (typeEntry.Type == null || !typeEntry.Emit)
                {
                    continue;
                }

                if (typeEntry.Type.IsAbstract || typeEntry.Type.IsInterface)
                {
                    Debug.LogError("Skipping type '" + typeEntry.Type.GetNiceFullName() + "'! Type is abstract or an interface.");
                    continue;
                }

                if (typeEntry.Type.IsGenericType && (typeEntry.Type.IsGenericTypeDefinition || !typeEntry.Type.IsFullyConstructedGenericType()))
                {
                    Debug.LogError("Skipping type '" + typeEntry.Type.GetNiceFullName() + "'! Type is a generic type definition, or its arguments contain generic parameters; type must be a fully constructed generic type.");
                    continue;
                }

                var serializedType = typeEntry.Type;

                if (seenTypes.Contains(serializedType))
                {
                    continue;
                }

                seenTypes.Add(serializedType);

                // Reference serialized type
                {
                    if (serializedType.IsValueType)
                    {
                        var local = il.DeclareLocal(serializedType);

                        il.Emit(OpCodes.Ldloca, local);
                        il.Emit(OpCodes.Initobj, serializedType);
                    }
                    else
                    {
                        var constructor = serializedType.GetConstructor(Type.EmptyTypes);

                        if (constructor != null)
                        {
                            il.Emit(OpCodes.Newobj, constructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }
                }

                // Reference and/or create formatter type
                if (!FormatterUtilities.IsPrimitiveType(serializedType))
                {
                    var formatter = FormatterLocator.GetFormatter(serializedType, SerializationPolicies.Unity);

                    if (formatter.GetType().IsDefined <EmittedFormatterAttribute>())
                    {
                        //// Emit an actual AOT formatter into the generated assembly

                        //if (this.emitAOTFormatters)
                        //{
                        //    var emittedFormatter = FormatterEmitter.EmitAOTFormatter(typeEntry.Type, module, SerializationPolicies.Unity);
                        //    var emittedFormatterConstructor = emittedFormatter.GetConstructor(Type.EmptyTypes);

                        //    il.Emit(OpCodes.Newobj, emittedFormatterConstructor);
                        //    il.Emit(OpCodes.Pop);
                        //}
                    }
                    else
                    {
                        // Just reference the pre-existing formatter

                        var formatterConstructor = formatter.GetType().GetConstructor(Type.EmptyTypes);

                        if (formatterConstructor != null)
                        {
                            il.Emit(OpCodes.Newobj, formatterConstructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }

                    // Make sure we have a proper reflection formatter variant if all else goes wrong
                    il.Emit(OpCodes.Newobj, typeof(ReflectionFormatter <>).MakeGenericType(typeEntry.Type).GetConstructor(Type.EmptyTypes));
                    il.Emit(OpCodes.Pop);
                }

                ConstructorInfo serializerConstructor;

                // Reference serializer variant
                if (serializedType.IsEnum)
                {
                    serializerConstructor = typeof(EnumSerializer <>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes);
                }
                else
                {
                    serializerConstructor = typeof(ComplexTypeSerializer <>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes);
                }

                il.Emit(OpCodes.Newobj, serializerConstructor);
                il.Emit(OpCodes.Pop);
            }

            //il.MarkLabel(endPoint);
            il.Emit(OpCodes.Ret);

            type.CreateType();

            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            if (File.Exists(fullDllPath))
            {
                File.Delete(fullDllPath);
            }

            if (File.Exists(fullDllPath + ".meta"))
            {
                File.Delete(fullDllPath + ".meta");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            assembly.Save(NAME);

            File.Move(newDllPath, fullDllPath);
            File.WriteAllText(fullLinkXmlPath, LINK_XML_CONTENTS);

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            var pluginImporter = PluginImporter.GetAtPath(fullDllPath) as PluginImporter;

            if (pluginImporter != null)
            {
                //pluginImporter.ClearSettings();

                pluginImporter.SetCompatibleWithEditor(false);
                pluginImporter.SetCompatibleWithAnyPlatform(true);

                // Disable for all standalones
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux64, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinuxUniversal, false);

                // StandaloneOSXUniversal (<= 2017.2) / StandaloneOSX (>= 2017.3)
                pluginImporter.SetCompatibleWithPlatform((BuildTarget)2, false);

                if (!UnityVersion.IsVersionOrGreater(2017, 3))
                {
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)4, false);        // StandaloneOSXIntel
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)27, false);       // StandaloneOSXIntel64
                }

                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false);

                //pluginImporter.SetCompatibleWithPlatform(BuildTarget.Android, false);

                pluginImporter.SaveAndReimport();
            }

            AssetDatabase.SaveAssets();
        }