// 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()); }
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(); }
private void DeleteAotStubs() { PathUtility.DeleteProjectFileIfExists(linkerPath, true); PathUtility.DeleteProjectFileIfExists(aotStubsPath, true); }
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(); }