Exemple #1
0
        // Automatically generates the link.xml file to prevent stripping.
        // Currently only used for plugin assemblies, because blanket preserving
        // all setting assemblies sometimes causes the IL2CPP process to fail.
        // For settings assemblies, the AOT stubs are good enough to fool
        // the static code analysis without needing this full coverage.
        // https://docs.unity3d.com/Manual/iphone-playerSizeOptimization.html
        // However, for FullSerializer, we need to preserve our custom assemblies.
        // This is mostly because IL2CPP will attempt to transform non-public
        // property setters used in deserialization into read-only accessors
        // that return false on PropertyInfo.CanWrite, but only in stripped builds.
        // Therefore, in stripped builds, FS will skip properties that should be
        // deserialized without any error (and that took hours of debugging to figure out).
        private void GenerateLinker()
        {
            var linker = new XDocument();

            var linkerNode = new XElement("linker");

            if (!PluginContainer.initialized)
            {
                PluginContainer.Initialize();
            }

            foreach (var pluginAssembly in PluginContainer.plugins
                     .SelectMany(plugin => plugin.GetType()
                                 .GetAttributes <PluginRuntimeAssemblyAttribute>()
                                 .Select(a => a.assemblyName))
                     .Distinct())
            {
                var assemblyNode      = new XElement("assembly");
                var fullnameAttribute = new XAttribute("fullname", pluginAssembly);
                var preserveAttribute = new XAttribute("preserve", "all");
                assemblyNode.Add(fullnameAttribute);
                assemblyNode.Add(preserveAttribute);
                linkerNode.Add(assemblyNode);
            }

            linker.Add(linkerNode);

            PathUtility.CreateDirectoryIfNeeded(BoltCore.Paths.transientGenerated);

            PathUtility.DeleteProjectFileIfExists(linkerPath, true);

            // Using ToString instead of Save to omit the <?xml> declaration,
            // which doesn't appear in the Unity documentation page for the linker.
            File.WriteAllText(linkerPath, linker.ToString());
        }
Exemple #2
0
        private void GenerateStubScript(string scriptFilePath)
        {
            var scriptDirectory = Path.GetDirectoryName(scriptFilePath);

            PathUtility.CreateDirectoryIfNeeded(scriptDirectory);
            PathUtility.DeleteProjectFileIfExists(scriptFilePath, true);

            using (var scriptWriter = new StreamWriter(scriptFilePath))
            {
                FindAndWriteAotStubs(scriptWriter);
            }

            AssetDatabase.Refresh();
        }
Exemple #3
0
 private void DeleteAotStubs()
 {
     PathUtility.DeleteProjectFileIfExists(linkerPath, true);
     PathUtility.DeleteProjectFileIfExists(aotStubsPath, true);
 }
Exemple #4
0
        private void GenerateStubScript(string scriptPath, IEnumerable <AotStubWriter> stubWriters)
        {
            Ensure.That(nameof(stubWriters)).IsNotNull(stubWriters);

            var unit = new CodeCompileUnit();

            var @namespace = new CodeNamespace("Unity.VisualScripting.Generated.Aot");

            unit.Namespaces.Add(@namespace);

            var @class = new CodeTypeDeclaration("AotStubs")
            {
                IsClass = true
            };

            @class.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(PreserveAttribute))));

            @namespace.Types.Add(@class);

            var usedMethodNames = new HashSet <string>();

            foreach (var stubWriter in stubWriters.OrderBy(sw => sw.stubMethodComment))
            {
                if (stubWriter.skip)
                {
                    continue;
                }

                var methodName = stubWriter.stubMethodName;

                var i = 0;

                while (usedMethodNames.Contains(methodName))
                {
                    methodName = stubWriter.stubMethodName + "_" + i++;
                }

                usedMethodNames.Add(methodName);

                @class.Comments.Add(new CodeCommentStatement(stubWriter.stubMethodComment));

                var @method = new CodeMemberMethod
                {
                    Name       = methodName,
                    ReturnType = new CodeTypeReference(typeof(void)),
                    Attributes = MemberAttributes.Public | MemberAttributes.Static
                };

                @method.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(PreserveAttribute), CodeTypeReferenceOptions.GlobalReference)));

                @method.Comments.Add(new CodeCommentStatement(stubWriter.stubMethodComment));

                @method.Statements.AddRange(stubWriter.GetStubStatements().ToArray());

                @class.Members.Add(@method);
            }

            PathUtility.CreateDirectoryIfNeeded(BoltCore.Paths.transientGenerated);

            PathUtility.DeleteProjectFileIfExists(aotStubsPath, true);

            using (var provider = CodeDomProvider.CreateProvider("CSharp"))
            {
                var options = new CodeGeneratorOptions
                {
                    BracingStyle             = "C",
                    IndentString             = "\t",
                    BlankLinesBetweenMembers = true,
                    ElseOnClosing            = false,
                    VerbatimOrder            = true
                };

                using (var scriptWriter = new StreamWriter(scriptPath))
                {
                    provider.GenerateCodeFromCompileUnit(new CodeSnippetCompileUnit("#pragma warning disable 219"), scriptWriter, options); // Disable unused variable warning
                    provider.GenerateCodeFromCompileUnit(unit, scriptWriter, options);
                }
            }

            AssetDatabase.Refresh();
        }