diff --git a/CHANGELOG.md b/CHANGELOG.md index ab7b1435..5d52d712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## v0.5.1 - 2026-06-05 + +Hotfix for Windows IL2CPP builds in the Unity package. + +### Magic.Unity +- IL2CPP workaround generation selects signature assemblies from the player compilation reference set (`CompilationPipeline`) instead of a Unity name-prefix check, so editor-only desktop assemblies (`Mono.WebBrowser`, reached through a `csc.rsp` `System.Web` reference on Windows) no longer leak into emitted signatures and break the build. Keep and skip decisions are logged, and a degenerate reference set fails the build instead of silently emitting no workarounds - [#23](https://github.com/flybot-sg/magic/issues/23). + ## v0.5.0 - 2026-06-04 Consumer quality-of-life fixes from the 0.4.0 rollout. diff --git a/magic-unity/Editor/GenerateGenericWorkaroundMethods.cs b/magic-unity/Editor/GenerateGenericWorkaroundMethods.cs index 3bc258d1..6fae0abf 100644 --- a/magic-unity/Editor/GenerateGenericWorkaroundMethods.cs +++ b/magic-unity/Editor/GenerateGenericWorkaroundMethods.cs @@ -5,6 +5,7 @@ using Mono.Cecil; using Mono.Cecil.Rocks; using Mono.Cecil.Cil; +using UnityEditor.Compilation; namespace Magic.Unity { @@ -21,10 +22,35 @@ struct DynamicCallSiteInfo static List AllMethods = new List(); static TypeDefinition MagicRuntimeDelegateHelpers = null; - static bool ShouldCollectReferencedAssembly(AssemblyDefinition assy) + static HashSet PlayerReferenceNames = null; + + // The collected assemblies feed AllMethods, the pool of candidate dynamic + // dispatch targets whose GetMethodDelegateFast instantiations get emitted + // into the shipped .clj.dlls. A signature referencing an assembly absent + // from the player build breaks the IL2CPP build; the type-reference + // closure resolves against the editor's full desktop BCL, which on + // Windows reaches editor-only assemblies like Mono.WebBrowser. So collect + // an assembly only if player scripts compile against it. Desktop-only BCL + // assemblies are never player compilation references, while UnityEngine + // modules, the player BCL profile, plugins (including .clj.dlls), and + // user script assemblies all are. + static HashSet CollectPlayerReferenceNames() { - return !assy.FullName.StartsWith("Unity") || assy.FullName.StartsWith("UnityEngine"); + var names = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var assembly in CompilationPipeline.GetAssemblies(AssembliesType.PlayerWithoutTestAssemblies)) + { + names.Add(assembly.name); + foreach (var reference in assembly.allReferences) + { + names.Add(System.IO.Path.GetFileNameWithoutExtension(reference)); + } + } + return names; + } + static bool ShouldCollectReferencedAssembly(AssemblyDefinition assy) + { + return PlayerReferenceNames.Contains(assy.Name.Name); } static HashSet CollectAllReferencedAssemblies(AssemblyDefinition assydef, HashSet seen = null) @@ -51,7 +77,7 @@ static HashSet CollectAllReferencedAssemblies(AssemblyDefini } else { - UnityEngine.Debug.Log($"[CollectAllReferencedAssemblies] Skip {resolved.Module.Assembly}"); + UnityEngine.Debug.Log($"[CollectAllReferencedAssemblies] Skip {resolved.Module.Assembly} (not a player compilation reference)"); } } } @@ -66,6 +92,18 @@ static HashSet CollectAllReferencedAssemblies(AssemblyDefini public static void Init() { + PlayerReferenceNames = CollectPlayerReferenceNames(); + // A degenerate reference set would silently turn workaround + // generation into a no-op: the build stays green and devices throw + // ExecutionEngineException at runtime. Fail the build instead. Any + // sane player reference set contains a core library and at least + // one UnityEngine module. + if (!(PlayerReferenceNames.Contains("mscorlib") || PlayerReferenceNames.Contains("netstandard")) + || !PlayerReferenceNames.Any(n => n.StartsWith("UnityEngine"))) + { + throw new InvalidOperationException($"[Magic.Unity] player compilation reference set looks degenerate ({PlayerReferenceNames.Count} entries), refusing to generate IL2CPP workarounds from it"); + } + UnityEngine.Debug.Log($"[CollectAllReferencedAssemblies] player compilation references: {string.Join(",", PlayerReferenceNames.OrderBy(n => n))}"); var assemblyCSharp = AssemblyDefinition.ReadAssembly("Library/ScriptAssemblies/Assembly-CSharp.dll"); var referencedAssemblies = CollectAllReferencedAssemblies(assemblyCSharp); UnityEngine.Debug.Log($"[CollectAllReferencedAssemblies] {string.Join(",", referencedAssemblies)}"); diff --git a/magic-unity/package.json b/magic-unity/package.json index 25423779..15682bb6 100644 --- a/magic-unity/package.json +++ b/magic-unity/package.json @@ -1,6 +1,6 @@ { "name": "sg.flybot.magic.unity", - "version": "0.5.0", + "version": "0.5.1", "displayName": "MAGIC Unity Integration", "description": "The integration of the MAGIC Clojure compiler into Unity", "unity": "2021.2", diff --git a/version.edn b/version.edn index 879b88c2..03443473 100644 --- a/version.edn +++ b/version.edn @@ -1 +1 @@ -{:version "0.5.0"} +{:version "0.5.1"}