From 20c32ea6ed76dcbf2e5f5796075915f451685457 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 24 Jan 2023 17:31:09 +0100 Subject: [PATCH] Impl progress on c++ name mangling on Clang for proper P/Invokes binding --- .../Bindings/BindingsGenerator.CSharp.cs | 3 +- .../Bindings/BindingsGenerator.Cpp.cs | 7 +- .../Flax.Build/Utilities/CppNameMangling.cs | 104 ++++++++++++++++-- 3 files changed, 97 insertions(+), 17 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index a3d083bd2..356651b01 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -18,6 +18,7 @@ namespace Flax.Build.Bindings private static readonly List CSharpAdditionalCode = new List(); private static readonly Dictionary CSharpAdditionalCodeCache = new Dictionary(); #if USE_NETCORE + private static readonly TypeInfo CSharpEventBindReturn = new TypeInfo("void"); private static readonly List CSharpEventBindParams = new List() { new FunctionInfo.ParameterInfo() { Name = "bind", Type = new TypeInfo("bool") } }; #endif @@ -1009,7 +1010,7 @@ namespace Flax.Build.Bindings if (buildData.Toolchain.Compiler == TargetCompiler.MSVC) libraryEntryPoint = $"{classInfo.FullNameManaged}::Internal_{eventInfo.Name}_Bind"; // MSVC allows to override exported symbol name else - libraryEntryPoint = CppNameMangling.MangleFunctionName(buildData, eventInfo.Name + "_ManagedBind", classInfo.FullNameNativeInternal + "Internal", CSharpEventBindParams); + libraryEntryPoint = CppNameMangling.MangleFunctionName(buildData, eventInfo.Name + "_ManagedBind", classInfo.FullNameNativeInternal + "Internal", CSharpEventBindReturn, CSharpEventBindParams); contents.Append(indent).Append($"[LibraryImport(\"{classInfo.ParentModule.Module.BinaryModuleName}\", EntryPoint = \"{libraryEntryPoint}\", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]").AppendLine(); contents.Append(indent).Append($"internal static partial void Internal_{eventInfo.Name}_Bind("); if (!eventInfo.IsStatic) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 53aa615b2..5161dc321 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -947,10 +947,7 @@ namespace Flax.Build.Bindings { Name = "__returnCount", DefaultValue = "var __returnCount", - Type = new TypeInfo - { - Type = "int" - }, + Type = new TypeInfo("int"), IsOut = true, }); } @@ -969,7 +966,7 @@ namespace Flax.Build.Bindings } else { - libraryEntryPoint = CppNameMangling.MangleFunctionName(buildData, functionInfo.Name, callerName, functionInfo.Parameters, functionInfo.Glue.CustomParameters); + libraryEntryPoint = CppNameMangling.MangleFunctionName(buildData, functionInfo.Name, callerName, functionInfo.ReturnType, functionInfo.IsStatic ? null : new TypeInfo(caller.Name) { IsPtr = true }, functionInfo.Parameters, functionInfo.Glue.CustomParameters); useSeparateImpl = true; // DLLEXPORT doesn't properly export function thus separate implementation from declaration } functionInfo.Glue.LibraryEntryPoint = libraryEntryPoint; diff --git a/Source/Tools/Flax.Build/Utilities/CppNameMangling.cs b/Source/Tools/Flax.Build/Utilities/CppNameMangling.cs index 772d392ef..2311c27a0 100644 --- a/Source/Tools/Flax.Build/Utilities/CppNameMangling.cs +++ b/Source/Tools/Flax.Build/Utilities/CppNameMangling.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; +using System.Text; using System.Collections.Generic; using Flax.Build.Bindings; @@ -11,19 +12,30 @@ namespace Flax.Build /// internal static class CppNameMangling { - public static string MangleFunctionName(Builder.BuildData buildData, string name, string outerName, List parameters1, List parameters2) + public static string MangleFunctionName(Builder.BuildData buildData, string name, string outerName, TypeInfo returnType, TypeInfo parameter0, List parameters1, List parameters2) { - if (parameters1 == null || parameters1.Count == 0) - return MangleFunctionName(buildData, name, outerName, parameters2); - if (parameters2 == null || parameters2.Count == 0) - return MangleFunctionName(buildData, name, outerName, parameters1); - var parameters = new List(); - parameters.AddRange(parameters1); - parameters.AddRange(parameters2); - return MangleFunctionName(buildData, name, outerName, parameters); + List parameters = null; + if (parameter0 == null) + { + if (parameters1 == null || parameters1.Count == 0) + parameters = parameters2; + else if (parameters2 == null || parameters2.Count == 0) + parameters = parameters1; + } + if (parameters == null) + { + parameters = new List(); + if (parameter0 != null) + parameters.Add(new FunctionInfo.ParameterInfo() { Type = parameter0 }); + if (parameters1 != null) + parameters.AddRange(parameters1); + if (parameters2 != null) + parameters.AddRange(parameters2); + } + return MangleFunctionName(buildData, name, outerName, returnType, parameters); } - public static string MangleFunctionName(Builder.BuildData buildData, string name, string outerName, List parameters) + public static string MangleFunctionName(Builder.BuildData buildData, string name, string outerName, TypeInfo returnType, List parameters) { if (name.Contains(":")) throw new NotImplementedException("No nested types mangling support."); @@ -42,7 +54,28 @@ namespace Flax.Build // TODO: mangle parameters break; case TargetCompiler.Clang: - sb.Append("todo"); + // References: + // http://web.mit.edu/tibbetts/Public/inside-c/www/mangling.html + // https://en.wikipedia.org/wiki/Name_mangling + sb.Append("_ZN"); + //if (!returnType.IsVoid) + // MangleTypeClang(sb, returnType); + sb.Append(outerName.Length); + sb.Append(outerName); + sb.Append(name.Length); + sb.Append(name); + sb.Append('E'); + if (parameters == null || parameters.Count == 0) + { + sb.Append('v'); + } + else + { + foreach (var e in parameters) + { + MangleTypeClang(sb, e.Type); + } + } break; default: throw new InvalidPlatformException(buildData.Platform.Target); @@ -51,5 +84,54 @@ namespace Flax.Build BindingsGenerator.PutStringBuilder(sb); return result; } + + private static void MangleTypeClang(StringBuilder sb, TypeInfo type) + { + if (type.IsPtr) + sb.Append('P'); + if (type.IsRef) + sb.Append('R'); + if (type.IsConst) + sb.Append('K'); + switch (type.Type) + { + // TODO: use proper typedef extraction from TypedefInfo + case "Float2": + sb.Append("11Vector2BaseIfE"); + break; + case "Float3": + sb.Append("11Vector3BaseIfE"); + break; + case "Float4": + sb.Append("11Vector4BaseIfE"); + break; + + case "bool": + sb.Append('b'); + break; + case "char": + case "int8": + sb.Append('c'); + break; + case "int": + case "int32": + sb.Append('i'); + break; + case "float": + sb.Append('f'); + break; + default: + sb.Append(type.Type.Length); + sb.Append(type.Type); + if (type.GenericArgs != null) + { + sb.Append('I'); + foreach (var e in type.GenericArgs) + MangleTypeClang(sb, e); + sb.Append('E'); + } + break; + } + } } }