From 75130fcca37a5b1e6e2a203579d07718015c0957 Mon Sep 17 00:00:00 2001 From: Wojciech Figat Date: Thu, 22 Dec 2022 11:50:29 +0100 Subject: [PATCH] Fix using `Function` in scripting api to pass function pointer to native code when running in dotnet7 --- .../Bindings/BindingsGenerator.CSharp.cs | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index 71c5d7eaa..9103f82a4 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -15,6 +15,8 @@ namespace Flax.Build.Bindings { private static readonly HashSet CSharpUsedNamespaces = new HashSet(); private static readonly List CSharpUsedNamespacesSorted = new List(); + private static readonly List CSharpAdditionalCode = new List(); + private static readonly Dictionary CSharpAdditionalCodeCache = new Dictionary(); public static event Action GenerateCSharpTypeInternals; @@ -310,6 +312,33 @@ namespace Flax.Build.Bindings { if (typeInfo.GenericArgs.Count == 0) throw new Exception("Missing function return type."); +#if USE_NETCORE + // NetCore doesn't allow using Marshal.GetDelegateForFunctionPointer on generic delegate type (eg. Action) thus generate explicit delegate type for function parameter + // https://github.com/dotnet/runtime/issues/36110 + if (typeInfo.GenericArgs.Count == 1 && typeInfo.GenericArgs[0].Type == "void") + return "Action"; + // TODO: generate delegates globally in the module namespace to share more code (smaller binary size) + var key = string.Empty; + for (int i = 0; i < typeInfo.GenericArgs.Count; i++) + key += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller); + if (!CSharpAdditionalCodeCache.TryGetValue(key, out var delegateName)) + { + delegateName = "Delegate" + CSharpAdditionalCodeCache.Count; + var signature = $"public delegate {GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller)} {delegateName}("; + for (int i = 1; i < typeInfo.GenericArgs.Count; i++) + { + if (i != 1) + signature += ", "; + signature += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller); + signature += $" arg{(i - 1)}"; + } + signature += ");"; + CSharpAdditionalCode.Add("/// Function delegate."); + CSharpAdditionalCode.Add(signature); + CSharpAdditionalCodeCache.Add(key, delegateName); + } + return delegateName; +#else if (typeInfo.GenericArgs.Count > 1) { var args = string.Empty; @@ -323,6 +352,7 @@ namespace Flax.Build.Bindings if (typeInfo.GenericArgs[0].Type == "void") return "Action"; return string.Format("Func<{0}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller)); +#endif } // Find API type info @@ -422,6 +452,19 @@ namespace Flax.Build.Bindings return string.Empty; } } + + private static void GenerateCSharpManagedTypeInternals(BuildData buildData, ApiTypeInfo apiTypeInfo, StringBuilder contents, string indent) + { + if (CSharpAdditionalCode.Count != 0) + { + contents.AppendLine(); + foreach(var e in CSharpAdditionalCode) + contents.Append(indent).AppendLine(e); + CSharpAdditionalCode.Clear(); + CSharpAdditionalCodeCache.Clear(); + } + GenerateCSharpTypeInternals?.Invoke(buildData, apiTypeInfo, contents, indent); + } private static void GenerateCSharpWrapperFunction(BuildData buildData, StringBuilder contents, string indent, ApiTypeInfo caller, FunctionInfo functionInfo) { @@ -1180,7 +1223,7 @@ namespace Flax.Build.Bindings } } - GenerateCSharpTypeInternals?.Invoke(buildData, classInfo, contents, indent); + GenerateCSharpManagedTypeInternals(buildData, classInfo, contents, indent); // Nested types foreach (var apiTypeInfo in classInfo.Children) @@ -1723,7 +1766,7 @@ namespace Flax.Build.Bindings contents.Append(indent).AppendLine("}"); } - GenerateCSharpTypeInternals?.Invoke(buildData, structureInfo, contents, indent); + GenerateCSharpManagedTypeInternals(buildData, structureInfo, contents, indent); // Nested types foreach (var apiTypeInfo in structureInfo.Children) @@ -1856,7 +1899,7 @@ namespace Flax.Build.Bindings contents.Append(");").AppendLine(); } - GenerateCSharpTypeInternals?.Invoke(buildData, interfaceInfo, contents, indent); + GenerateCSharpManagedTypeInternals(buildData, interfaceInfo, contents, indent); // End indent = indent.Substring(0, indent.Length - 4);