Refactor generated bindings P/Invoke to support name mangling for symbols

This commit is contained in:
Wojciech Figat
2023-01-23 18:41:12 +01:00
parent f3366178ea
commit 405ae519dd
13 changed files with 187 additions and 136 deletions

View File

@@ -176,7 +176,6 @@ bool ScriptsBuilder::IsReady()
void ScriptsBuilder::MarkWorkspaceDirty()
{
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_MarkWorkspaceDirty")
ScopeLock scopeLock(_locker);
_lastSourceCodeEdited = DateTime::Now();
_wasProjectStructureChanged = true;
@@ -184,7 +183,6 @@ void ScriptsBuilder::MarkWorkspaceDirty()
void ScriptsBuilder::CheckForCompile()
{
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_CheckForCompile")
ScopeLock scopeLock(_locker);
if (IsSourceDirty())
Compile();
@@ -207,7 +205,6 @@ void ScriptsBuilderImpl::onScriptsReloadEnd()
void ScriptsBuilder::Compile()
{
SCRIPTING_EXPORT("FlaxEditor.ScriptsBuilder::Internal_Compile")
ScopeLock scopeLock(_locker);
// Request compile job

View File

@@ -260,15 +260,15 @@ namespace FlaxEngine
#region Internal Calls
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_HasConnection")]
[LibraryImport("FlaxEngine", EntryPoint = "AnimGraphInternal_HasConnection")]
[return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_HasConnection(ref AnimationGraph.CustomNode.Context context, int boxId);
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetInputValue")]
[LibraryImport("FlaxEngine", EntryPoint = "AnimGraphInternal_GetInputValue")]
[return: MarshalUsing(typeof(FlaxEngine.ManagedHandleMarshaller))]
internal static partial object Internal_GetInputValue(ref AnimationGraph.CustomNode.Context context, int boxId);
[LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.AnimationGraph::Internal_GetOutputImpulseData")]
[LibraryImport("FlaxEngine", EntryPoint = "AnimGraphInternal_GetOutputImpulseData")]
internal static partial IntPtr Internal_GetOutputImpulseData(ref AnimationGraph.CustomNode.Context context);
#endregion

View File

@@ -32,8 +32,6 @@
#pragma clang diagnostic ignored "-Wnull-dereference"
#pragma clang diagnostic ignored "-Winvalid-noreturn"
#define SCRIPTING_EXPORT(name)
#elif defined(__GNUC__)
#define DLLEXPORT __attribute__ ((__visibility__ ("default")))
@@ -88,8 +86,6 @@
#pragma warning(disable: 4251)
#define SCRIPTING_EXPORT(name) __pragma(comment(linker, "/EXPORT:" #name "=" __FUNCDNAME__))
#else
#pragma error "Unknown compiler."

View File

@@ -1323,7 +1323,6 @@ bool Level::SaveAllScenes()
void Level::SaveAllScenesAsync()
{
SCRIPTING_EXPORT("FlaxEngine.Level::Internal_SaveAllScenesAsync")
ScopeLock lock(_sceneActionsLocker);
for (int32 i = 0; i < Scenes.Count(); i++)
_sceneActions.Enqueue(New<SaveSceneAction>(Scenes[i]));
@@ -1428,7 +1427,6 @@ bool Level::UnloadAllScenes()
void Level::UnloadAllScenesAsync()
{
SCRIPTING_EXPORT("FlaxEngine.Level::Internal_UnloadAllScenesAsync")
ScopeLock lock(_sceneActionsLocker);
_sceneActions.Enqueue(New<UnloadScenesAction>());
}

View File

@@ -304,7 +304,6 @@ bool NetworkManager::StartHost()
void NetworkManager::Stop()
{
SCRIPTING_EXPORT("FlaxEngine.Networking.NetworkManager::Internal_Stop");
if (Mode == NetworkManagerMode::Offline && State == NetworkConnectionState::Offline)
return;
PROFILE_CPU();

View File

@@ -16,7 +16,6 @@ typedef struct _DROPFILES
void WindowsClipboard::Clear()
{
SCRIPTING_EXPORT("FlaxEngine.Clipboard::Internal_Clear");
OpenClipboard(nullptr);
EmptyClipboard();
CloseClipboard();

View File

@@ -700,7 +700,6 @@ void Render2D::Begin(GPUContext* context, GPUTextureView* output, GPUTextureView
void Render2D::End()
{
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_End")
RENDER2D_CHECK_RENDERING_STATE;
ASSERT(Context != nullptr && Output != nullptr);
ASSERT(GUIShader != nullptr);
@@ -816,7 +815,6 @@ void Render2D::PeekTransform(Matrix3x3& transform)
void Render2D::PopTransform()
{
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopTransform")
RENDER2D_CHECK_RENDERING_STATE;
ASSERT(TransformLayersStack.HasItems());
@@ -858,7 +856,6 @@ void Render2D::PeekClip(Rectangle& clipRect)
void Render2D::PopClip()
{
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopClip")
RENDER2D_CHECK_RENDERING_STATE;
ClipLayersStack.Pop();
@@ -880,7 +877,6 @@ void Render2D::PeekTint(Color& tint)
void Render2D::PopTint()
{
SCRIPTING_EXPORT("FlaxEngine.Render2D::Internal_PopTint")
RENDER2D_CHECK_RENDERING_STATE;
TintLayersStack.Pop();

View File

@@ -1,6 +1,5 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "Engine/Platform/FileSystem.h"
#include "Engine/Animations/Graph/AnimGraph.h"
#include "Engine/Scripting/InternalCalls.h"
#include "Engine/Scripting/MException.h"
@@ -8,82 +7,69 @@
#if !COMPILE_WITHOUT_CSHARP
namespace UtilsInternal
#if USE_MONO && !USE_NETCORE
DEFINE_INTERNAL_CALL(MonoObject*) UtilsInternal_ExtractArrayFromList(MonoObject* obj)
{
MonoObject* ExtractArrayFromList(MonoObject* obj)
{
#if USE_MONO
auto klass = mono_object_get_class(obj);
auto field = mono_class_get_field_from_name(klass, "_items");
MonoObject* o;
mono_field_get_value(obj, field, &o);
return o;
#else
SCRIPTING_EXPORT("FlaxEngine.Utils::Internal_ExtractArrayFromList")
return nullptr;
auto klass = mono_object_get_class(obj);
auto field = mono_class_get_field_from_name(klass, "_items");
MonoObject* o;
mono_field_get_value(obj, field, &o);
return o;
}
#endif
}
DEFINE_INTERNAL_CALL(void) PlatformInternal_MemoryCopy(void* dst, const void* src, uint64 size)
{
Platform::MemoryCopy(dst, src, size);
}
namespace DebugLogHandlerInternal
DEFINE_INTERNAL_CALL(void) PlatformInternal_MemoryClear(void* dst, uint64 size)
{
void LogWrite(LogType level, MonoString* msgObj)
{
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_LogWrite")
StringView msg;
MUtils::ToString(msgObj, msg);
Log::Logger::Write(level, msg);
}
void Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace)
{
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_Log")
if (msgObj == nullptr)
return;
// Get info
StringView msg;
MUtils::ToString(msgObj, msg);
//const String objName = obj ? obj->ToString() : String::Empty;
// Send event
// TODO: maybe option for build to threat warnings and errors as fatal errors?
//const String logMessage = String::Format(TEXT("Debug:{1} {2}"), objName, *msg);
Log::Logger::Write(level, msg);
}
void LogException(MonoException* exception, ScriptingObject* obj)
{
SCRIPTING_EXPORT("FlaxEngine.DebugLogHandler::Internal_LogException")
#if USE_MONO
if (exception == nullptr)
return;
// Get info
MException ex(exception);
const String objName = obj ? obj->ToString() : String::Empty;
// Print exception including inner exceptions
// TODO: maybe option for build to threat warnings and errors as fatal errors?
ex.Log(LogType::Warning, objName.GetText());
#endif
}
Platform::MemoryClear(dst, size);
}
namespace FlaxLogWriterInternal
DEFINE_INTERNAL_CALL(int32) PlatformInternal_MemoryCompare(const void* buf1, const void* buf2, uint64 size)
{
void WriteStringToLog(MonoString* msgObj)
{
SCRIPTING_EXPORT("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog")
if (msgObj == nullptr)
return;
StringView msg;
MUtils::ToString(msgObj, msg);
LOG_STR(Info, msg);
}
return Platform::MemoryCompare(buf1, buf2, size);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogWrite(LogType level, MonoString* msgObj)
{
StringView msg;
MUtils::ToString(msgObj, msg);
Log::Logger::Write(level, msg);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_Log(LogType level, MonoString* msgObj, ScriptingObject* obj, MonoString* stackTrace)
{
if (msgObj == nullptr)
return;
// Get info
StringView msg;
MUtils::ToString(msgObj, msg);
//const String objName = obj ? obj->ToString() : String::Empty;
// Send event
// TODO: maybe option for build to threat warnings and errors as fatal errors?
//const String logMessage = String::Format(TEXT("Debug:{1} {2}"), objName, *msg);
Log::Logger::Write(level, msg);
}
DEFINE_INTERNAL_CALL(void) DebugLogHandlerInternal_LogException(MonoException* exception, ScriptingObject* obj)
{
#if USE_MONO
if (exception == nullptr)
return;
// Get info
MException ex(exception);
const String objName = obj ? obj->ToString() : String::Empty;
// Print exception including inner exceptions
// TODO: maybe option for build to threat warnings and errors as fatal errors?
ex.Log(LogType::Warning, objName.GetText());
#endif
}
#endif
@@ -92,13 +78,14 @@ void registerFlaxEngineInternalCalls()
{
AnimGraphExecutor::initRuntime();
#if USE_MONO
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCopy", &Platform::MemoryCopy);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryClear", &Platform::MemoryClear);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCompare", &Platform::MemoryCompare);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCopy", &PlatformInternal_MemoryCopy);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryClear", &PlatformInternal_MemoryClear);
ADD_INTERNAL_CALL("FlaxEngine.Utils::MemoryCompare", &PlatformInternal_MemoryCompare);
#if USE_MONO && !USE_NETCORE
ADD_INTERNAL_CALL("FlaxEngine.Utils::Internal_ExtractArrayFromList", &UtilsInternal::ExtractArrayFromList);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogWrite", &DebugLogHandlerInternal::LogWrite);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal::Log);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal::LogException);
ADD_INTERNAL_CALL("FlaxEngine.FlaxLogWriter::Internal_WriteStringToLog", &FlaxLogWriterInternal::WriteStringToLog);
#endif
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogWrite", &DebugLogHandlerInternal_LogWrite);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_Log", &DebugLogHandlerInternal_Log);
ADD_INTERNAL_CALL("FlaxEngine.DebugLogHandler::Internal_LogException", &DebugLogHandlerInternal_LogException);
#endif
}

View File

@@ -17,6 +17,9 @@ namespace Flax.Build.Bindings
private static readonly List<string> CSharpUsedNamespacesSorted = new List<string>();
private static readonly List<string> CSharpAdditionalCode = new List<string>();
private static readonly Dictionary<string, string> CSharpAdditionalCodeCache = new Dictionary<string, string>();
#if USE_NETCORE
private static readonly List<FunctionInfo.ParameterInfo> CSharpEventBindParams = new List<FunctionInfo.ParameterInfo>() { new FunctionInfo.ParameterInfo() { Name = "bind", Type = new TypeInfo("bool") } };
#endif
public static event Action<BuildData, ApiTypeInfo, StringBuilder, string> GenerateCSharpTypeInternals;
@@ -512,7 +515,9 @@ namespace Flax.Build.Bindings
contents.AppendLine().Append(indent).Append("[MethodImpl(MethodImplOptions.InternalCall)]");
contents.AppendLine().Append(indent).Append("internal static partial ");
#else
contents.AppendLine().Append(indent).Append($"[LibraryImport(\"{caller.ParentModule.Module.BinaryModuleName}\", EntryPoint = \"{caller.FullNameManaged}::Internal_{functionInfo.UniqueName}\", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]");
if (string.IsNullOrEmpty(functionInfo.Glue.LibraryEntryPoint))
throw new Exception($"Function {caller.FullNameNative}::{functionInfo.Name} has missing entry point for library import.");
contents.AppendLine().Append(indent).Append($"[LibraryImport(\"{caller.ParentModule.Module.BinaryModuleName}\", EntryPoint = \"{functionInfo.Glue.LibraryEntryPoint}\", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]");
if (!string.IsNullOrEmpty(returnMarshalType))
contents.AppendLine().Append(indent).Append($"[return: {returnMarshalType}]");
contents.AppendLine().Append(indent).Append("internal static partial ");
@@ -1000,7 +1005,12 @@ namespace Flax.Build.Bindings
contents.Append("IntPtr obj, ");
contents.Append("bool bind);");
#else
contents.Append(indent).Append($"[LibraryImport(\"{classInfo.ParentModule.Module.BinaryModuleName}\", EntryPoint = \"{classInfo.FullNameManaged}::Internal_{eventInfo.Name}_Bind\", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))]").AppendLine();
string libraryEntryPoint;
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);
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)
contents.Append("IntPtr obj, ");

View File

@@ -871,7 +871,6 @@ namespace Flax.Build.Bindings
return true;
if (typeInfo.IsPtr || typeInfo.IsRef || typeInfo.IsArray || typeInfo.IsBitField || (typeInfo.GenericArgs != null && typeInfo.GenericArgs.Count != 0))
return false;
#if !USE_NETCORE
if (CSharpNativeToManagedBasicTypes.ContainsKey(typeInfo.Type) || CSharpNativeToManagedBasicTypes.ContainsValue(typeInfo.Type))
return true;
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
@@ -880,7 +879,6 @@ namespace Flax.Build.Bindings
if (apiType.IsEnum)
return true;
}
#endif
return false;
}
@@ -899,8 +897,9 @@ namespace Flax.Build.Bindings
return true;
}
private static void GenerateCppWrapperFunction(BuildData buildData, StringBuilder contents, ApiTypeInfo caller, FunctionInfo functionInfo, string callFormat = "{0}({1})")
private static void GenerateCppWrapperFunction(BuildData buildData, StringBuilder contents, ApiTypeInfo caller, string callerName, FunctionInfo functionInfo, string callFormat = "{0}({1})")
{
#if !USE_NETCORE
// Optimize static function wrappers that match C# internal call ABI exactly
// Use it for Engine-internally only because in games this makes it problematic to use the same function name but with different signature that is not visible to scripting
if (CurrentModule.Module is EngineModule && callFormat == "{0}({1})" && GenerateCppWrapperFunctionImplicitBinding(buildData, functionInfo, caller))
@@ -913,6 +912,7 @@ namespace Flax.Build.Bindings
return;
}
}
#endif
// Setup function binding glue to ensure that wrapper method signature matches for C++ and C#
functionInfo.Glue = new FunctionInfo.GlueInfo
@@ -954,9 +954,22 @@ namespace Flax.Build.Bindings
});
}
#endif
var prevIndent = " ";
var indent = " ";
contents.Append(prevIndent);
#if USE_NETCORE
contents.AppendFormat("DLLEXPORT static {0} {1}(", returnValueType, functionInfo.UniqueName);
string libraryEntryPoint;
if (buildData.Toolchain.Compiler == TargetCompiler.MSVC)
libraryEntryPoint = $"{caller.FullNameManaged}::Internal_{functionInfo.UniqueName}"; // MSVC allows to override exported symbol name
else
libraryEntryPoint = CppNameMangling.MangleFunctionName(buildData, functionInfo.Name, callerName + "Internal", functionInfo.Parameters, functionInfo.Glue.CustomParameters);
functionInfo.Glue.LibraryEntryPoint = libraryEntryPoint;
#else
contents.AppendFormat("static {0} {1}(", returnValueType, functionInfo.UniqueName);
#endif
CppInternalCalls.Add(new KeyValuePair<string, string>(functionInfo.UniqueName, functionInfo.UniqueName));
contents.AppendFormat(" static {0} {1}(", returnValueType, functionInfo.UniqueName);
var separator = false;
if (!functionInfo.IsStatic)
@@ -1054,14 +1067,15 @@ namespace Flax.Build.Bindings
contents.Append(')');
contents.AppendLine();
contents.AppendLine(" {");
contents.Append(prevIndent).AppendLine("{");
#if USE_NETCORE
contents.AppendLine(string.Format(" SCRIPTING_EXPORT(\"{0}\")", caller.FullNameManaged + "::Internal_" + functionInfo.UniqueName));
if (buildData.Toolchain.Compiler == TargetCompiler.MSVC)
contents.Append(indent).AppendLine($"MSVC_FUNC_EXPORT(\"{libraryEntryPoint}\")"); // Export generated function binding under the C# name
#endif
if (!functionInfo.IsStatic)
contents.AppendLine(" if (obj == nullptr) DebugLog::ThrowNullReference();");
contents.Append(indent).AppendLine("if (obj == nullptr) DebugLog::ThrowNullReference();");
string callBegin = " ";
string callBegin = indent;
if (functionInfo.Glue.UseReferenceForResult)
{
callBegin += "*__resultAsRef = ";
@@ -1078,7 +1092,7 @@ namespace Flax.Build.Bindings
string callReturnCount = "";
if (returnTypeIsContainer)
{
callReturnCount = " ";
callReturnCount = indent;
if (functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "BytesContainer")
callReturnCount += "*__returnCount = {0}.Length();";
else
@@ -1132,9 +1146,9 @@ namespace Flax.Build.Bindings
if (apiType != null)
{
if (parameterInfo.IsOut)
contents.AppendFormat(" {1} {0}Temp;", parameterInfo.Name, new TypeInfo(parameterInfo.Type) { IsRef = false }.GetFullNameNative(buildData, caller)).AppendLine();
contents.Append(indent).AppendFormat("{1} {0}Temp;", parameterInfo.Name, new TypeInfo(parameterInfo.Type) { IsRef = false }.GetFullNameNative(buildData, caller)).AppendLine();
else
contents.AppendFormat(" auto {0}Temp = {1};", parameterInfo.Name, param).AppendLine();
contents.Append(indent).AppendFormat("auto {0}Temp = {1};", parameterInfo.Name, param).AppendLine();
if (parameterInfo.Type.IsPtr && !parameterInfo.Type.IsRef)
callParams += "&";
callParams += parameterInfo.Name;
@@ -1143,7 +1157,7 @@ namespace Flax.Build.Bindings
// BytesContainer
else if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null)
{
contents.AppendFormat(" BytesContainer {0}Temp;", parameterInfo.Name).AppendLine();
contents.Append(indent).AppendFormat("BytesContainer {0}Temp;", parameterInfo.Name).AppendLine();
callParams += parameterInfo.Name;
callParams += "Temp";
}
@@ -1151,7 +1165,7 @@ namespace Flax.Build.Bindings
// Special case for parameter that cannot be passed directly to the function from the wrapper method input parameter (eg. MonoArray* converted into BytesContainer uses as BytesContainer&)
else if (CppParamsThatNeedLocalVariable[i])
{
contents.AppendFormat(" auto {0}Temp = {1};", parameterInfo.Name, param).AppendLine();
contents.Append(indent).AppendFormat("auto {0}Temp = {1};", parameterInfo.Name, param).AppendLine();
if (parameterInfo.Type.IsPtr)
callParams += "&";
callParams += parameterInfo.Name;
@@ -1166,7 +1180,7 @@ namespace Flax.Build.Bindings
#if USE_NETCORE
if (!string.IsNullOrEmpty(callReturnCount))
{
contents.Append(" ").Append("const auto& __callTemp = ").Append(string.Format(callFormat, call, callParams)).Append(";").AppendLine();
contents.Append(indent).Append("const auto& __callTemp = ").Append(string.Format(callFormat, call, callParams)).Append(";").AppendLine();
call = "__callTemp";
contents.Append(string.Format(callReturnCount, call));
contents.AppendLine();
@@ -1210,11 +1224,11 @@ namespace Flax.Build.Bindings
{
if (apiType.IsClass)
{
contents.AppendFormat(" mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine();
contents.Append(indent).AppendFormat("mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine();
#if USE_NETCORE
if (parameterInfo.Type.Type == "Array")
{
contents.AppendFormat(" *__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
}
#endif
continue;
@@ -1222,7 +1236,7 @@ namespace Flax.Build.Bindings
if (apiType.IsStruct && !apiType.IsPod)
{
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
contents.AppendFormat(" {{ auto __temp = {1}; mono_gc_wbarrier_value_copy({0}, &__temp, 1, {2}::TypeInitializer.GetType().ManagedClass->GetNative()); }}", parameterInfo.Name, value, apiType.FullNameNative).AppendLine();
contents.Append(indent).AppendFormat("{{ auto __temp = {1}; mono_gc_wbarrier_value_copy({0}, &__temp, 1, {2}::TypeInitializer.GetType().ManagedClass->GetNative()); }}", parameterInfo.Name, value, apiType.FullNameNative).AppendLine();
continue;
}
}
@@ -1231,25 +1245,25 @@ namespace Flax.Build.Bindings
// BytesContainer
if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null)
{
contents.AppendFormat(" mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine();
contents.AppendFormat(" *__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
contents.Append(indent).AppendFormat("mono_gc_wbarrier_generic_store({0}, (MonoObject*){1});", parameterInfo.Name, value).AppendLine();
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
continue;
}
throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'");
}
}
contents.AppendFormat(" *{0} = {1};", parameterInfo.Name, value).AppendLine();
contents.Append(indent).AppendFormat("*{0} = {1};", parameterInfo.Name, value).AppendLine();
}
}
}
if (!useInlinedReturn && !functionInfo.Glue.UseReferenceForResult && !functionInfo.ReturnType.IsVoid)
{
contents.Append(" return __result;").AppendLine();
contents.Append(indent).Append("return __result;").AppendLine();
}
contents.AppendLine(" }");
contents.Append(prevIndent).AppendLine("}");
contents.AppendLine();
}
@@ -1901,14 +1915,13 @@ namespace Flax.Build.Bindings
// C# event wrapper binding method (binds/unbinds C# wrapper to C++ delegate)
CppInternalCalls.Add(new KeyValuePair<string, string>(eventInfo.Name + "_Bind", eventInfo.Name + "_ManagedBind"));
contents.AppendFormat(" static void {0}_ManagedBind(", eventInfo.Name);
contents.AppendFormat(" DLLEXPORT static void {0}_ManagedBind(", eventInfo.Name);
if (!eventInfo.IsStatic)
contents.AppendFormat("{0}* obj, ", classTypeNameNative);
contents.Append("bool bind)").AppendLine();
contents.Append(" {").AppendLine();
#if USE_NETCORE
contents.AppendLine(string.Format(" SCRIPTING_EXPORT(\"{0}\")", classTypeNameManagedInternalCall + "::Internal_" + eventInfo.Name + "_Bind"));
#endif
if (buildData.Toolchain.Compiler == TargetCompiler.MSVC)
contents.AppendLine($" MSVC_FUNC_EXPORT(\"{classTypeNameManaged}::Internal_{eventInfo.Name}_Bind\")"); // Export generated function binding under the C# name
contents.Append(" Function<void(");
for (var i = 0; i < paramsCount; i++)
{
@@ -1985,14 +1998,14 @@ namespace Flax.Build.Bindings
if (!useScripting || !useCSharp || fieldInfo.IsHidden || fieldInfo.IsConstexpr)
continue;
if (fieldInfo.Getter != null)
GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Getter, "{0}");
GenerateCppWrapperFunction(buildData, contents, classInfo, classTypeNameInternal, fieldInfo.Getter, "{0}");
if (fieldInfo.Setter != null)
{
var callFormat = "{0} = {1}";
var type = fieldInfo.Setter.Parameters[0].Type;
if (type.IsArray)
callFormat = $"auto __tmp = {{1}}; for (int32 i = 0; i < {type.ArraySize}; i++) {{0}}[i] = __tmp[i]";
GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Setter, callFormat);
GenerateCppWrapperFunction(buildData, contents, classInfo, classTypeNameInternal, fieldInfo.Setter, callFormat);
}
}
@@ -2002,9 +2015,9 @@ namespace Flax.Build.Bindings
if (!useScripting || !useCSharp || propertyInfo.IsHidden)
continue;
if (propertyInfo.Getter != null)
GenerateCppWrapperFunction(buildData, contents, classInfo, propertyInfo.Getter);
GenerateCppWrapperFunction(buildData, contents, classInfo, classTypeNameInternal, propertyInfo.Getter);
if (propertyInfo.Setter != null)
GenerateCppWrapperFunction(buildData, contents, classInfo, propertyInfo.Setter);
GenerateCppWrapperFunction(buildData, contents, classInfo, classTypeNameInternal, propertyInfo.Setter);
}
// Functions
@@ -2014,7 +2027,7 @@ namespace Flax.Build.Bindings
continue;
if (!useScripting)
throw new Exception($"Not supported function {functionInfo.Name} inside non-static and non-scripting class type {classInfo.Name}.");
GenerateCppWrapperFunction(buildData, contents, classInfo, functionInfo);
GenerateCppWrapperFunction(buildData, contents, classInfo, classTypeNameInternal, functionInfo);
}
// Interface implementation
@@ -2028,7 +2041,7 @@ namespace Flax.Build.Bindings
{
if (!classInfo.IsScriptingObject)
throw new Exception($"Class {classInfo.Name} cannot implement interface {interfaceInfo.Name} because it requires ScriptingObject as a base class.");
GenerateCppWrapperFunction(buildData, contents, classInfo, functionInfo);
GenerateCppWrapperFunction(buildData, contents, classInfo, classTypeNameInternal, functionInfo);
}
}
}
@@ -2184,9 +2197,9 @@ namespace Flax.Build.Bindings
}
if (fieldInfo.Getter != null)
GenerateCppWrapperFunction(buildData, contents, structureInfo, fieldInfo.Getter, "{0}");
GenerateCppWrapperFunction(buildData, contents, structureInfo, structureTypeNameInternal, fieldInfo.Getter, "{0}");
if (fieldInfo.Setter != null)
GenerateCppWrapperFunction(buildData, contents, structureInfo, fieldInfo.Setter, "{0} = {1}");
GenerateCppWrapperFunction(buildData, contents, structureInfo, structureTypeNameInternal, fieldInfo.Setter, "{0} = {1}");
}
// Functions
@@ -2194,7 +2207,7 @@ namespace Flax.Build.Bindings
{
// TODO: add support for API functions in structures
throw new NotImplementedException($"TODO: add support for API functions in structures (function {functionInfo} in structure {structureInfo.Name})");
//GenerateCppWrapperFunction(buildData, contents, structureInfo, functionInfo);
//GenerateCppWrapperFunction(buildData, contents, structureInfo, structureTypeNameInternal, functionInfo);
}
GenerateCppTypeInternals?.Invoke(buildData, structureInfo, contents);
@@ -2677,8 +2690,6 @@ namespace Flax.Build.Bindings
header.Append(" return result;").AppendLine();
header.Append('}').AppendLine();
header.AppendLine("}");
PutStringBuilder(header);
}
// Non-POD types
@@ -2968,6 +2979,8 @@ namespace Flax.Build.Bindings
foreach (var path in CppIncludeFilesList)
header.AppendFormat("#include \"{0}\"", path).AppendLine();
contents.Insert(headerPos, header.ToString());
PutStringBuilder(header);
}
contents.AppendLine("PRAGMA_ENABLE_DEPRECATION_WARNINGS");

View File

@@ -62,7 +62,7 @@ namespace Flax.Build.Bindings
private static List<StringBuilder> _strignBuilderCache;
private static StringBuilder GetStringBuilder()
public static StringBuilder GetStringBuilder()
{
if (_strignBuilderCache == null || _strignBuilderCache.Count == 0)
return new StringBuilder();
@@ -73,7 +73,7 @@ namespace Flax.Build.Bindings
return result;
}
private static void PutStringBuilder(StringBuilder value)
public static void PutStringBuilder(StringBuilder value)
{
if (_strignBuilderCache == null)
_strignBuilderCache = new List<StringBuilder>();

View File

@@ -60,6 +60,7 @@ namespace Flax.Build.Bindings
public struct GlueInfo
{
public bool UseReferenceForResult;
public string LibraryEntryPoint;
public List<ParameterInfo> CustomParameters;
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using Flax.Build.Bindings;
namespace Flax.Build
{
/// <summary>
/// The utilities for C++ typename mangling.
/// </summary>
internal static class CppNameMangling
{
public static string MangleFunctionName(Builder.BuildData buildData, string name, string outerName, List<FunctionInfo.ParameterInfo> parameters1, List<FunctionInfo.ParameterInfo> 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<FunctionInfo.ParameterInfo>();
parameters.AddRange(parameters1);
parameters.AddRange(parameters2);
return MangleFunctionName(buildData, name, outerName, parameters);
}
public static string MangleFunctionName(Builder.BuildData buildData, string name, string outerName, List<FunctionInfo.ParameterInfo> parameters)
{
if (name.Contains(":"))
throw new NotImplementedException("No nested types mangling support.");
var sb = BindingsGenerator.GetStringBuilder();
switch (buildData.Toolchain.Compiler)
{
case TargetCompiler.MSVC:
// References:
// https://learn.microsoft.com/en-us/cpp/build/reference/decorated-names
// https://mearie.org/documents/mscmangle/
sb.Append('?');
sb.Append(name);
sb.Append('@');
sb.Append(outerName);
sb.Append('@');
// TODO: mangle parameters
break;
case TargetCompiler.Clang:
sb.Append("todo");
break;
default:
throw new InvalidPlatformException(buildData.Platform.Target);
}
var result = sb.ToString();
BindingsGenerator.PutStringBuilder(sb);
return result;
}
}
}