diff --git a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs index 46447cf4c..14e03e188 100644 --- a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs @@ -28,6 +28,7 @@ namespace Flax.Build.Bindings public virtual bool IsValueType => false; public virtual bool IsScriptingObject => false; public virtual bool IsPod => false; + public virtual bool SkipGeneration => IsInBuild; public FileInfo File { diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index b28744a50..e8fc930af 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -235,10 +235,10 @@ namespace Flax.Build.Bindings } // Object reference property - if ((typeInfo.Type == "ScriptingObjectReference" || - typeInfo.Type == "AssetReference" || - typeInfo.Type == "WeakAssetReference" || - typeInfo.Type == "SoftAssetReference" || + if ((typeInfo.Type == "ScriptingObjectReference" || + typeInfo.Type == "AssetReference" || + typeInfo.Type == "WeakAssetReference" || + typeInfo.Type == "SoftAssetReference" || typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null) return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller); @@ -284,21 +284,23 @@ namespace Flax.Build.Bindings // Find API type info var apiType = FindApiTypeInfo(buildData, typeInfo, caller); + var typeName = typeInfo.Type.Replace("::", "."); if (apiType != null) { CSharpUsedNamespaces.Add(apiType.Namespace); - if (apiType.IsScriptingObject || apiType.IsInterface) - return typeInfo.Type.Replace("::", "."); + return typeName; if (typeInfo.IsPtr && apiType.IsPod) - return typeInfo.Type.Replace("::", ".") + '*'; + return typeName + '*'; + if (apiType is LangType && CSharpNativeToManagedBasicTypes.TryGetValue(apiType.Name, out result)) + return result; } // Pointer if (typeInfo.IsPtr) return "IntPtr"; - return typeInfo.Type.Replace("::", "."); + return typeName; } private static string GenerateCSharpManagedToNativeType(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller) @@ -316,10 +318,10 @@ namespace Flax.Build.Bindings } // Object reference property - if ((typeInfo.Type == "ScriptingObjectReference" || - typeInfo.Type == "AssetReference" || - typeInfo.Type == "WeakAssetReference" || - typeInfo.Type == "SoftAssetReference" || + if ((typeInfo.Type == "ScriptingObjectReference" || + typeInfo.Type == "AssetReference" || + typeInfo.Type == "WeakAssetReference" || + typeInfo.Type == "SoftAssetReference" || typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null) return "IntPtr"; @@ -374,10 +376,10 @@ namespace Flax.Build.Bindings } // Object reference property - if ((typeInfo.Type == "ScriptingObjectReference" || - typeInfo.Type == "AssetReference" || - typeInfo.Type == "WeakAssetReference" || - typeInfo.Type == "SoftAssetReference" || + if ((typeInfo.Type == "ScriptingObjectReference" || + typeInfo.Type == "AssetReference" || + typeInfo.Type == "WeakAssetReference" || + typeInfo.Type == "SoftAssetReference" || typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null) return "FlaxEngine.Object.GetUnmanagedPtr({0})"; @@ -1355,7 +1357,7 @@ namespace Flax.Build.Bindings private static bool GenerateCSharpType(BuildData buildData, StringBuilder contents, string indent, object type) { - if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.IsInBuild) + if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.SkipGeneration) return false; try diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs index e9d2076ed..8984d7e2a 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs @@ -19,7 +19,7 @@ namespace Flax.Build.Bindings partial class BindingsGenerator { private static readonly Dictionary TypeCache = new Dictionary(); - private const int CacheVersion = 12; + private const int CacheVersion = 13; internal static void Write(BinaryWriter writer, string e) { diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index cc101638e..bf925c3da 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -131,10 +131,10 @@ namespace Flax.Build.Bindings return value; if (typeInfo.Type == "String") return $"Variant(StringView({value}))"; - if (typeInfo.Type == "AssetReference" || - typeInfo.Type == "WeakAssetReference" || - typeInfo.Type == "SoftAssetReference" || - typeInfo.Type == "ScriptingObjectReference" || + if (typeInfo.Type == "AssetReference" || + typeInfo.Type == "WeakAssetReference" || + typeInfo.Type == "SoftAssetReference" || + typeInfo.Type == "ScriptingObjectReference" || typeInfo.Type == "SoftObjectReference") return $"Variant({value}.Get())"; if (typeInfo.IsArray) @@ -254,7 +254,7 @@ namespace Flax.Build.Bindings CppReferencesFiles.Add(apiType.File); if (apiType.IsStruct && !apiType.IsPod && !CppUsedNonPodTypes.Contains(apiType)) CppUsedNonPodTypes.Add(apiType); - if (!apiType.IsInBuild && !apiType.IsEnum) + if (!apiType.SkipGeneration && !apiType.IsEnum) { // Use declared type initializer CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h"); @@ -329,7 +329,7 @@ namespace Flax.Build.Bindings CppReferencesFiles.Add(apiType.File); if (apiType.IsStruct && !apiType.IsPod && !CppUsedNonPodTypes.Contains(apiType)) CppUsedNonPodTypes.Add(apiType); - if (!apiType.IsInBuild && !apiType.IsEnum) + if (!apiType.SkipGeneration && !apiType.IsEnum) { // Use declared type initializer CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h"); @@ -406,10 +406,10 @@ namespace Flax.Build.Bindings return "MUtils::ToManaged({0})"; default: // Object reference property - if ((typeInfo.Type == "ScriptingObjectReference" || - typeInfo.Type == "AssetReference" || - typeInfo.Type == "WeakAssetReference" || - typeInfo.Type == "SoftAssetReference" || + if ((typeInfo.Type == "ScriptingObjectReference" || + typeInfo.Type == "AssetReference" || + typeInfo.Type == "WeakAssetReference" || + typeInfo.Type == "SoftAssetReference" || typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null) { type = "MonoObject*"; @@ -578,10 +578,10 @@ namespace Flax.Build.Bindings return "MUtils::ToNative({0})"; default: // Object reference property - if ((typeInfo.Type == "ScriptingObjectReference" || - typeInfo.Type == "AssetReference" || - typeInfo.Type == "WeakAssetReference" || - typeInfo.Type == "SoftAssetReference" || + if ((typeInfo.Type == "ScriptingObjectReference" || + typeInfo.Type == "AssetReference" || + typeInfo.Type == "WeakAssetReference" || + typeInfo.Type == "SoftAssetReference" || typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null) { // For non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code) @@ -2156,7 +2156,7 @@ namespace Flax.Build.Bindings private static void GenerateCppType(BuildData buildData, StringBuilder contents, ModuleInfo moduleInfo, object type) { - if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.IsInBuild) + if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.SkipGeneration) return; try @@ -2197,6 +2197,11 @@ namespace Flax.Build.Bindings } } } + if (apiType is ClassStructInfo classStructInfo) + { + if (classStructInfo.IsTemplate) + throw new Exception($"Cannot use template type '{classStructInfo}' as non-POD type for cross-language bindings."); + } if (!CppUsedNonPodTypesList.Contains(apiType)) CppUsedNonPodTypesList.Add(apiType); } diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs index 235e87485..203a932fa 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs @@ -499,7 +499,7 @@ namespace Flax.Build.Bindings // Read 'class' keyword var token = context.Tokenizer.NextToken(); if (token.Value != "class") - throw new Exception($"Invalid API_CLASS usage (expected 'class' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}')."); + throw new Exception($"Invalid {ApiTokens.Class} usage (expected 'class' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}')."); // Read specifiers while (true) @@ -551,6 +551,9 @@ namespace Flax.Build.Bindings case "private": desc.Access = AccessLevel.Private; break; + case "template": + desc.IsTemplate = true; + break; case "inbuild": desc.IsInBuild = true; break; @@ -592,7 +595,7 @@ namespace Flax.Build.Bindings // Read 'class' keyword var token = context.Tokenizer.NextToken(); if (token.Value != "class") - throw new Exception($"Invalid API_INTERFACE usage (expected 'class' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}')."); + throw new Exception($"Invalid {ApiTokens.Interface} usage (expected 'class' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}')."); // Read specifiers while (true) @@ -629,6 +632,9 @@ namespace Flax.Build.Bindings case "private": desc.Access = AccessLevel.Private; break; + case "template": + desc.IsTemplate = true; + break; case "inbuild": desc.IsInBuild = true; break; @@ -876,7 +882,7 @@ namespace Flax.Build.Bindings // Read 'enum' or `enum class` keywords var token = context.Tokenizer.NextToken(); if (token.Value != "enum") - throw new Exception($"Invalid API_ENUM usage at line {context.Tokenizer.CurrentLine} (expected 'enum' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}')."); + throw new Exception($"Invalid {ApiTokens.Enum} usage at line {context.Tokenizer.CurrentLine} (expected 'enum' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}')."); token = context.Tokenizer.NextToken(); if (token.Value != "class") context.Tokenizer.PreviousToken(); @@ -1046,7 +1052,7 @@ namespace Flax.Build.Bindings // Read 'struct' keyword var token = context.Tokenizer.NextToken(); if (token.Value != "struct") - throw new Exception($"Invalid API_STRUCT usage (expected 'struct' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}')."); + throw new Exception($"Invalid {ApiTokens.Struct} usage (expected 'struct' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}')."); // Read name desc.Name = desc.NativeName = ParseName(ref context); @@ -1068,6 +1074,9 @@ namespace Flax.Build.Bindings case "private": desc.Access = AccessLevel.Private; break; + case "template": + desc.IsTemplate = true; + break; case "inbuild": desc.IsInBuild = true; break; @@ -1232,7 +1241,7 @@ namespace Flax.Build.Bindings if (desc.Type.Type == "Action") desc.Type = new TypeInfo { Type = "Delegate", GenericArgs = new List() }; else if (desc.Type.Type != "Delegate") - throw new Exception($"Invalid API_EVENT type. Only Action and Delegate<> types are supported. '{desc.Type}' used on event at line {context.Tokenizer.CurrentLine}."); + throw new Exception($"Invalid {ApiTokens.Event} type. Only Action and Delegate<> types are supported. '{desc.Type}' used on event at line {context.Tokenizer.CurrentLine}."); // Read name desc.Name = ParseName(ref context); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs index 292f07773..a00efacfe 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs @@ -541,7 +541,7 @@ namespace Flax.Build.Bindings private static bool UseBindings(object type) { var apiTypeInfo = type as ApiTypeInfo; - if (apiTypeInfo != null && apiTypeInfo.IsInBuild) + if (apiTypeInfo != null && apiTypeInfo.SkipGeneration) return false; if ((type is ModuleInfo || type is FileInfo) && apiTypeInfo != null) { diff --git a/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs b/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs index 3f212a3a5..bdf21b7f8 100644 --- a/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ClassStructInfo.cs @@ -13,11 +13,14 @@ namespace Flax.Build.Bindings { public AccessLevel Access; public AccessLevel BaseTypeInheritance; + public bool IsTemplate; public ClassStructInfo BaseType; public List Interfaces; public List Inheritance; // Data from parsing, used to interfaces and base type construct in Init public List Functions = new List(); + public override bool SkipGeneration => IsInBuild || IsTemplate; + public override void Init(Builder.BuildData buildData) { base.Init(buildData); @@ -51,6 +54,7 @@ namespace Flax.Build.Bindings { writer.Write((byte)Access); writer.Write((byte)BaseTypeInheritance); + writer.Write(IsTemplate); BindingsGenerator.Write(writer, BaseType); BindingsGenerator.Write(writer, Inheritance); BindingsGenerator.Write(writer, Functions); @@ -62,6 +66,7 @@ namespace Flax.Build.Bindings { Access = (AccessLevel)reader.ReadByte(); BaseTypeInheritance = (AccessLevel)reader.ReadByte(); + IsTemplate = reader.ReadBoolean(); BaseType = BindingsGenerator.Read(reader, BaseType); Inheritance = BindingsGenerator.Read(reader, Inheritance); Functions = BindingsGenerator.Read(reader, Functions); diff --git a/Source/Tools/Flax.Build/Bindings/StructureInfo.cs b/Source/Tools/Flax.Build/Bindings/StructureInfo.cs index 24c700c22..a3009d9aa 100644 --- a/Source/Tools/Flax.Build/Bindings/StructureInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/StructureInfo.cs @@ -25,7 +25,7 @@ namespace Flax.Build.Bindings { base.Init(buildData); - if (ForceNoPod || (Interfaces != null && Interfaces.Count != 0)) + if (ForceNoPod || (Interfaces != null && Interfaces.Count != 0) || IsTemplate) { _isPod = false; return; diff --git a/Source/Tools/Flax.Build/Platforms/Android/AndroidPlatform.cs b/Source/Tools/Flax.Build/Platforms/Android/AndroidPlatform.cs index 9cd0b12ea..bafaa4492 100644 --- a/Source/Tools/Flax.Build/Platforms/Android/AndroidPlatform.cs +++ b/Source/Tools/Flax.Build/Platforms/Android/AndroidPlatform.cs @@ -20,7 +20,7 @@ namespace Flax.Build.Platforms /// public override bool HasSharedLibrarySupport => true; - + /// public override bool HasExecutableFileReferenceSupport => true;