Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -71,6 +71,13 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
|
||||
public void EnsureInited(Builder.BuildData buildData)
|
||||
{
|
||||
if (IsInited)
|
||||
return;
|
||||
Init(buildData);
|
||||
}
|
||||
|
||||
public virtual void Init(Builder.BuildData buildData)
|
||||
{
|
||||
IsInited = true;
|
||||
|
||||
@@ -261,7 +261,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
if (typeInfo == null)
|
||||
return null;
|
||||
var result = FindApiTypeInfoInner(typeInfo, caller);
|
||||
var result = FindApiTypeInfoInner(buildData, typeInfo, caller);
|
||||
if (result != null)
|
||||
return result;
|
||||
if (buildData.TypeCache.TryGetValue(typeInfo, out result))
|
||||
@@ -274,7 +274,7 @@ namespace Flax.Build.Bindings
|
||||
// Find across all loaded modules for this build
|
||||
foreach (var e in buildData.ModulesInfo)
|
||||
{
|
||||
result = FindApiTypeInfoInner(typeInfo, e.Value);
|
||||
result = FindApiTypeInfoInner(buildData, typeInfo, e.Value);
|
||||
if (result != null)
|
||||
{
|
||||
buildData.TypeCache.Add(typeInfo, result);
|
||||
@@ -291,7 +291,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
if (result == null)
|
||||
return null;
|
||||
result = FindApiTypeInfoInner(new TypeInfo { Type = nesting[i], }, result);
|
||||
result = FindApiTypeInfoInner(buildData, new TypeInfo { Type = nesting[i], }, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -301,14 +301,17 @@ namespace Flax.Build.Bindings
|
||||
return null;
|
||||
}
|
||||
|
||||
private static ApiTypeInfo FindApiTypeInfoInner(TypeInfo typeInfo, ApiTypeInfo parent)
|
||||
private static ApiTypeInfo FindApiTypeInfoInner(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo parent)
|
||||
{
|
||||
foreach (var child in parent.Children)
|
||||
{
|
||||
if (child.Name == typeInfo.Type)
|
||||
{
|
||||
child.EnsureInited(buildData);
|
||||
return child;
|
||||
}
|
||||
|
||||
var result = FindApiTypeInfoInner(typeInfo, child);
|
||||
var result = FindApiTypeInfoInner(buildData, typeInfo, child);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Flax.Build.Bindings
|
||||
private static readonly HashSet<string> CSharpUsedNamespaces = new HashSet<string>();
|
||||
private static readonly List<string> CSharpUsedNamespacesSorted = new List<string>();
|
||||
|
||||
private static readonly Dictionary<string, string> CSharpNativeToManagedBasicTypes = new Dictionary<string, string>()
|
||||
internal static readonly Dictionary<string, string> CSharpNativeToManagedBasicTypes = new Dictionary<string, string>()
|
||||
{
|
||||
// Language types
|
||||
{ "int8", "sbyte" },
|
||||
@@ -32,7 +32,7 @@ namespace Flax.Build.Bindings
|
||||
{ "double", "double" },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, string> CSharpNativeToManagedDefault = new Dictionary<string, string>()
|
||||
internal static readonly Dictionary<string, string> CSharpNativeToManagedDefault = new Dictionary<string, string>()
|
||||
{
|
||||
// Engine types
|
||||
{ "String", "string" },
|
||||
@@ -201,6 +201,8 @@ namespace Flax.Build.Bindings
|
||||
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
||||
if (apiType != null)
|
||||
{
|
||||
CSharpUsedNamespaces.Add(apiType.Namespace);
|
||||
|
||||
if (apiType.IsScriptingObject)
|
||||
return typeInfo.Type.Replace("::", ".");
|
||||
|
||||
@@ -527,7 +529,7 @@ namespace Flax.Build.Bindings
|
||||
contents.Append("abstract ");
|
||||
contents.Append("unsafe partial class ").Append(classInfo.Name);
|
||||
if (classInfo.BaseType != null && !classInfo.IsBaseTypeHidden)
|
||||
contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, classInfo.BaseType, classInfo));
|
||||
contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, new TypeInfo { Type = classInfo.BaseType.Name }, classInfo));
|
||||
contents.AppendLine();
|
||||
contents.Append(indent + "{");
|
||||
indent += " ";
|
||||
@@ -861,7 +863,7 @@ namespace Flax.Build.Bindings
|
||||
contents.Append("private ");
|
||||
contents.Append("unsafe partial struct ").Append(structureInfo.Name);
|
||||
if (structureInfo.BaseType != null && structureInfo.IsPod)
|
||||
contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, structureInfo.BaseType, structureInfo));
|
||||
contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, new TypeInfo { Type = structureInfo.BaseType.Name }, structureInfo));
|
||||
contents.AppendLine();
|
||||
contents.Append(indent + "{");
|
||||
indent += " ";
|
||||
@@ -1048,30 +1050,6 @@ namespace Flax.Build.Bindings
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void GenerateCSharpCollectNamespaces(BuildData buildData, ApiTypeInfo apiType, HashSet<string> usedNamespaces)
|
||||
{
|
||||
if (apiType is ClassInfo classInfo)
|
||||
{
|
||||
foreach (var field in classInfo.Fields)
|
||||
{
|
||||
var fieldInfo = FindApiTypeInfo(buildData, field.Type, classInfo);
|
||||
if (fieldInfo != null && !string.IsNullOrWhiteSpace(fieldInfo.Namespace) && fieldInfo.Namespace != apiType.Namespace)
|
||||
usedNamespaces.Add(fieldInfo.Namespace);
|
||||
}
|
||||
}
|
||||
else if (apiType is StructureInfo structureInfo)
|
||||
{
|
||||
foreach (var field in structureInfo.Fields)
|
||||
{
|
||||
var fieldInfo = FindApiTypeInfo(buildData, field.Type, structureInfo);
|
||||
if (fieldInfo != null && !string.IsNullOrWhiteSpace(fieldInfo.Namespace) && fieldInfo.Namespace != apiType.Namespace)
|
||||
usedNamespaces.Add(fieldInfo.Namespace);
|
||||
}
|
||||
}
|
||||
foreach (var child in apiType.Children)
|
||||
GenerateCSharpCollectNamespaces(buildData, child, usedNamespaces);
|
||||
}
|
||||
|
||||
private static void GenerateCSharp(BuildData buildData, ModuleInfo moduleInfo, ref BindingsResult bindings)
|
||||
{
|
||||
var contents = new StringBuilder();
|
||||
@@ -1084,29 +1062,17 @@ namespace Flax.Build.Bindings
|
||||
contents.Append("true").AppendLine();
|
||||
contents.AppendLine("// This code was auto-generated. Do not modify it.");
|
||||
contents.AppendLine();
|
||||
var headerPos = contents.Length;
|
||||
|
||||
// Using declarations
|
||||
CSharpUsedNamespaces.Clear();
|
||||
CSharpUsedNamespaces.Add(null);
|
||||
CSharpUsedNamespaces.Add(string.Empty);
|
||||
CSharpUsedNamespaces.Add("System");
|
||||
CSharpUsedNamespaces.Add("System.ComponentModel");
|
||||
CSharpUsedNamespaces.Add("System.Globalization");
|
||||
CSharpUsedNamespaces.Add("System.Runtime.CompilerServices");
|
||||
CSharpUsedNamespaces.Add("System.Runtime.InteropServices");
|
||||
CSharpUsedNamespaces.Add("FlaxEngine");
|
||||
foreach (var e in moduleInfo.Children)
|
||||
{
|
||||
foreach (var apiTypeInfo in e.Children)
|
||||
{
|
||||
GenerateCSharpCollectNamespaces(buildData, apiTypeInfo, CSharpUsedNamespaces);
|
||||
}
|
||||
}
|
||||
CSharpUsedNamespacesSorted.Clear();
|
||||
CSharpUsedNamespacesSorted.AddRange(CSharpUsedNamespaces);
|
||||
CSharpUsedNamespacesSorted.Sort();
|
||||
foreach (var e in CSharpUsedNamespacesSorted)
|
||||
contents.AppendLine($"using {e};");
|
||||
// TODO: custom using declarations support
|
||||
// TODO: generate using declarations based on references modules (eg. using FlaxEngine, using Plugin1 in game API)
|
||||
|
||||
// Process all API types from the file
|
||||
var useBindings = false;
|
||||
@@ -1121,7 +1087,21 @@ namespace Flax.Build.Bindings
|
||||
if (!useBindings)
|
||||
return;
|
||||
|
||||
{
|
||||
var header = new StringBuilder();
|
||||
|
||||
// Using declarations
|
||||
CSharpUsedNamespacesSorted.Clear();
|
||||
CSharpUsedNamespacesSorted.AddRange(CSharpUsedNamespaces);
|
||||
CSharpUsedNamespacesSorted.Sort();
|
||||
for (var i = 2; i < CSharpUsedNamespacesSorted.Count; i++)
|
||||
header.AppendLine($"using {CSharpUsedNamespacesSorted[i]};");
|
||||
|
||||
contents.Insert(headerPos, header.ToString());
|
||||
}
|
||||
|
||||
// Save generated file
|
||||
contents.AppendLine();
|
||||
contents.AppendLine("#endif");
|
||||
Utilities.WriteFileIfChanged(bindings.GeneratedCSharpFilePath, contents.ToString());
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Flax.Build.Bindings
|
||||
partial class BindingsGenerator
|
||||
{
|
||||
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
|
||||
private const int CacheVersion = 7;
|
||||
private const int CacheVersion = 8;
|
||||
|
||||
internal static void Write(BinaryWriter writer, string e)
|
||||
{
|
||||
|
||||
@@ -1095,7 +1095,7 @@ namespace Flax.Build.Bindings
|
||||
var baseType = classInfo?.BaseType ?? structureInfo?.BaseType;
|
||||
if (classInfo != null && classInfo.IsBaseTypeHidden)
|
||||
baseType = null;
|
||||
if (baseType != null && (baseType.Type == "PersistentScriptingObject" || baseType.Type == "ScriptingObject"))
|
||||
if (baseType != null && (baseType.Name == "PersistentScriptingObject" || baseType.Name == "ScriptingObject"))
|
||||
baseType = null;
|
||||
CppAutoSerializeFields.Clear();
|
||||
CppAutoSerializeProperties.Clear();
|
||||
@@ -1105,7 +1105,7 @@ namespace Flax.Build.Bindings
|
||||
contents.Append($"void {typeNameNative}::Serialize(SerializeStream& stream, const void* otherObj)").AppendLine();
|
||||
contents.Append('{').AppendLine();
|
||||
if (baseType != null)
|
||||
contents.Append($" {baseType}::Serialize(stream, otherObj);").AppendLine();
|
||||
contents.Append($" {baseType.FullNameNative}::Serialize(stream, otherObj);").AppendLine();
|
||||
contents.Append($" SERIALIZE_GET_OTHER_OBJ({typeNameNative});").AppendLine();
|
||||
|
||||
if (classInfo != null)
|
||||
@@ -1161,7 +1161,7 @@ namespace Flax.Build.Bindings
|
||||
contents.Append($"void {typeNameNative}::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)").AppendLine();
|
||||
contents.Append('{').AppendLine();
|
||||
if (baseType != null)
|
||||
contents.Append($" {baseType}::Deserialize(stream, modifier);").AppendLine();
|
||||
contents.Append($" {baseType.FullNameNative}::Deserialize(stream, modifier);").AppendLine();
|
||||
|
||||
foreach (var fieldInfo in CppAutoSerializeFields)
|
||||
{
|
||||
@@ -1554,7 +1554,7 @@ namespace Flax.Build.Bindings
|
||||
else
|
||||
contents.Append($"(ScriptingType::SpawnHandler)&{classTypeNameNative}::Spawn, ");
|
||||
if (classInfo.BaseType != null && useScripting)
|
||||
contents.Append($"&{classInfo.BaseType}::TypeInitializer, ");
|
||||
contents.Append($"&{classInfo.BaseType.FullNameNative}::TypeInitializer, ");
|
||||
else
|
||||
contents.Append("nullptr, ");
|
||||
contents.Append(setupScriptVTable);
|
||||
@@ -1566,7 +1566,7 @@ namespace Flax.Build.Bindings
|
||||
else
|
||||
contents.Append($"&{classTypeNameInternal}Internal::Ctor, &{classTypeNameInternal}Internal::Dtor, ");
|
||||
if (classInfo.BaseType != null)
|
||||
contents.Append($"&{classInfo.BaseType}::TypeInitializer");
|
||||
contents.Append($"&{classInfo.BaseType.FullNameNative}::TypeInitializer");
|
||||
else
|
||||
contents.Append("nullptr");
|
||||
}
|
||||
|
||||
@@ -416,38 +416,38 @@ namespace Flax.Build.Bindings
|
||||
token = accessToken;
|
||||
break;
|
||||
}
|
||||
|
||||
var baseTypeInfo = new TypeInfo
|
||||
var inheritType = new TypeInfo
|
||||
{
|
||||
Type = token.Value,
|
||||
};
|
||||
if (token.Value.Length > 2 && token.Value[0] == 'I' && char.IsUpper(token.Value[1]))
|
||||
{
|
||||
// Interface
|
||||
if (desc.InterfaceNames == null)
|
||||
desc.InterfaceNames = new List<TypeInfo>();
|
||||
desc.InterfaceNames.Add(baseTypeInfo);
|
||||
token = context.Tokenizer.NextToken();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desc.BaseType != null)
|
||||
{
|
||||
// Allow for multiple base classes, just the first one needs to be a valid base type
|
||||
break;
|
||||
throw new Exception($"Invalid '{desc.Name}' inheritance (only single base class is allowed for scripting types, excluding interfaces).");
|
||||
}
|
||||
desc.BaseType = baseTypeInfo;
|
||||
if (desc.Inheritance == null)
|
||||
desc.Inheritance = new List<TypeInfo>();
|
||||
desc.Inheritance.Add(inheritType);
|
||||
token = context.Tokenizer.NextToken();
|
||||
if (token.Type == TokenType.LeftCurlyBrace)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (token.Type == TokenType.Colon)
|
||||
{
|
||||
token = context.Tokenizer.ExpectToken(TokenType.Colon);
|
||||
token = context.Tokenizer.NextToken();
|
||||
inheritType.Type = token.Value;
|
||||
token = context.Tokenizer.NextToken();
|
||||
continue;
|
||||
}
|
||||
if (token.Type == TokenType.DoubleColon)
|
||||
{
|
||||
token = context.Tokenizer.NextToken();
|
||||
inheritType.Type += token.Value;
|
||||
token = context.Tokenizer.NextToken();
|
||||
continue;
|
||||
}
|
||||
if (token.Type == TokenType.LeftAngleBracket)
|
||||
{
|
||||
var genericType = context.Tokenizer.ExpectToken(TokenType.Identifier);
|
||||
token = context.Tokenizer.ExpectToken(TokenType.RightAngleBracket);
|
||||
desc.BaseType.GenericArgs = new List<TypeInfo>
|
||||
inheritType.GenericArgs = new List<TypeInfo>
|
||||
{
|
||||
new TypeInfo
|
||||
{
|
||||
@@ -456,9 +456,9 @@ namespace Flax.Build.Bindings
|
||||
};
|
||||
|
||||
// TODO: find better way to resolve this (custom base type attribute?)
|
||||
if (desc.BaseType.Type == "ShaderAssetTypeBase")
|
||||
if (inheritType.Type == "ShaderAssetTypeBase")
|
||||
{
|
||||
desc.BaseType = desc.BaseType.GenericArgs[0];
|
||||
desc.Inheritance[desc.Inheritance.Count - 1] = inheritType.GenericArgs[0];
|
||||
}
|
||||
|
||||
token = context.Tokenizer.NextToken();
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Flax.Build.NativeCpp;
|
||||
@@ -109,13 +108,6 @@ namespace Flax.Build.Bindings
|
||||
if (LoadCache(ref moduleInfo, moduleOptions, headerFiles))
|
||||
{
|
||||
buildData.ModulesInfo[module] = moduleInfo;
|
||||
|
||||
// Initialize API
|
||||
using (new ProfileEventScope("Init"))
|
||||
{
|
||||
moduleInfo.Init(buildData);
|
||||
}
|
||||
|
||||
return moduleInfo;
|
||||
}
|
||||
}
|
||||
@@ -164,12 +156,6 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize API
|
||||
using (new ProfileEventScope("Init"))
|
||||
{
|
||||
moduleInfo.Init(buildData);
|
||||
}
|
||||
|
||||
return moduleInfo;
|
||||
}
|
||||
|
||||
@@ -533,23 +519,10 @@ namespace Flax.Build.Bindings
|
||||
if (moduleInfo.IsFromCache)
|
||||
return;
|
||||
|
||||
// Process parsed API
|
||||
using (new ProfileEventScope("Process"))
|
||||
// Initialize parsed API
|
||||
using (new ProfileEventScope("Init"))
|
||||
{
|
||||
foreach (var child in moduleInfo.Children)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var apiTypeInfo in child.Children)
|
||||
ProcessAndValidate(buildData, apiTypeInfo);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (child is FileInfo fileInfo)
|
||||
Log.Error($"Failed to validate '{fileInfo.Name}' file to generate bindings.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
moduleInfo.Init(buildData);
|
||||
}
|
||||
|
||||
// Generate bindings for scripting
|
||||
@@ -583,122 +556,5 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessAndValidate(BuildData buildData, ApiTypeInfo apiTypeInfo)
|
||||
{
|
||||
if (apiTypeInfo is ClassInfo classInfo)
|
||||
ProcessAndValidate(buildData, classInfo);
|
||||
else if (apiTypeInfo is StructureInfo structureInfo)
|
||||
ProcessAndValidate(buildData, structureInfo);
|
||||
|
||||
foreach (var child in apiTypeInfo.Children)
|
||||
ProcessAndValidate(buildData, child);
|
||||
}
|
||||
|
||||
private static void ProcessAndValidate(BuildData buildData, ClassInfo classInfo)
|
||||
{
|
||||
if (classInfo.UniqueFunctionNames == null)
|
||||
classInfo.UniqueFunctionNames = new HashSet<string>();
|
||||
|
||||
foreach (var fieldInfo in classInfo.Fields)
|
||||
{
|
||||
if (fieldInfo.Access == AccessLevel.Private)
|
||||
continue;
|
||||
|
||||
fieldInfo.Getter = new FunctionInfo
|
||||
{
|
||||
Name = "Get" + fieldInfo.Name,
|
||||
Comment = fieldInfo.Comment,
|
||||
IsStatic = fieldInfo.IsStatic,
|
||||
Access = fieldInfo.Access,
|
||||
Attributes = fieldInfo.Attributes,
|
||||
ReturnType = fieldInfo.Type,
|
||||
Parameters = new List<FunctionInfo.ParameterInfo>(),
|
||||
IsVirtual = false,
|
||||
IsConst = true,
|
||||
Glue = new FunctionInfo.GlueInfo()
|
||||
};
|
||||
ProcessAndValidate(classInfo, fieldInfo.Getter);
|
||||
fieldInfo.Getter.Name = fieldInfo.Name;
|
||||
|
||||
if (!fieldInfo.IsReadOnly)
|
||||
{
|
||||
fieldInfo.Setter = new FunctionInfo
|
||||
{
|
||||
Name = "Set" + fieldInfo.Name,
|
||||
Comment = fieldInfo.Comment,
|
||||
IsStatic = fieldInfo.IsStatic,
|
||||
Access = fieldInfo.Access,
|
||||
Attributes = fieldInfo.Attributes,
|
||||
ReturnType = new TypeInfo
|
||||
{
|
||||
Type = "void",
|
||||
},
|
||||
Parameters = new List<FunctionInfo.ParameterInfo>
|
||||
{
|
||||
new FunctionInfo.ParameterInfo
|
||||
{
|
||||
Name = "value",
|
||||
Type = fieldInfo.Type,
|
||||
},
|
||||
},
|
||||
IsVirtual = false,
|
||||
IsConst = true,
|
||||
Glue = new FunctionInfo.GlueInfo()
|
||||
};
|
||||
ProcessAndValidate(classInfo, fieldInfo.Setter);
|
||||
fieldInfo.Setter.Name = fieldInfo.Name;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var propertyInfo in classInfo.Properties)
|
||||
{
|
||||
if (propertyInfo.Getter != null)
|
||||
ProcessAndValidate(classInfo, propertyInfo.Getter);
|
||||
if (propertyInfo.Setter != null)
|
||||
ProcessAndValidate(classInfo, propertyInfo.Setter);
|
||||
}
|
||||
|
||||
foreach (var functionInfo in classInfo.Functions)
|
||||
ProcessAndValidate(classInfo, functionInfo);
|
||||
}
|
||||
|
||||
private static void ProcessAndValidate(BuildData buildData, StructureInfo structureInfo)
|
||||
{
|
||||
foreach (var fieldInfo in structureInfo.Fields)
|
||||
{
|
||||
if (fieldInfo.Type.IsBitField)
|
||||
throw new NotImplementedException($"TODO: support bit-fields in structure fields (found field {fieldInfo} in structure {structureInfo.Name})");
|
||||
|
||||
// Pointers are fine
|
||||
if (fieldInfo.Type.IsPtr)
|
||||
continue;
|
||||
|
||||
// In-build types
|
||||
if (CSharpNativeToManagedBasicTypes.ContainsKey(fieldInfo.Type.Type))
|
||||
continue;
|
||||
if (CSharpNativeToManagedDefault.ContainsKey(fieldInfo.Type.Type))
|
||||
continue;
|
||||
|
||||
// Find API type info for this field type
|
||||
var apiType = FindApiTypeInfo(buildData, fieldInfo.Type, structureInfo);
|
||||
if (apiType != null)
|
||||
continue;
|
||||
|
||||
throw new Exception($"Unknown field type '{fieldInfo.Type} {fieldInfo.Name}' in structure '{structureInfo.Name}'.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessAndValidate(ClassInfo classInfo, FunctionInfo functionInfo)
|
||||
{
|
||||
// Ensure that methods have unique names for bindings
|
||||
if (classInfo.UniqueFunctionNames == null)
|
||||
classInfo.UniqueFunctionNames = new HashSet<string>();
|
||||
int idx = 1;
|
||||
functionInfo.UniqueName = functionInfo.Name;
|
||||
while (classInfo.UniqueFunctionNames.Contains(functionInfo.UniqueName))
|
||||
functionInfo.UniqueName = functionInfo.Name + idx++;
|
||||
classInfo.UniqueFunctionNames.Add(functionInfo.UniqueName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,22 +57,87 @@ namespace Flax.Build.Bindings
|
||||
_isScriptingObject = true;
|
||||
else if (BaseType == null)
|
||||
_isScriptingObject = false;
|
||||
else if (InBuildScriptingObjectTypes.Contains(BaseType.Type))
|
||||
else if (InBuildScriptingObjectTypes.Contains(BaseType.Name))
|
||||
_isScriptingObject = true;
|
||||
else
|
||||
_isScriptingObject = BaseType != null && BaseType.IsScriptingObject;
|
||||
|
||||
if (UniqueFunctionNames == null)
|
||||
UniqueFunctionNames = new HashSet<string>();
|
||||
|
||||
foreach (var fieldInfo in Fields)
|
||||
{
|
||||
var baseApiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, BaseType, this);
|
||||
if (baseApiTypeInfo != null)
|
||||
if (fieldInfo.Access == AccessLevel.Private)
|
||||
continue;
|
||||
|
||||
fieldInfo.Getter = new FunctionInfo
|
||||
{
|
||||
if (!baseApiTypeInfo.IsInited)
|
||||
baseApiTypeInfo.Init(buildData);
|
||||
_isScriptingObject = baseApiTypeInfo.IsScriptingObject;
|
||||
}
|
||||
else
|
||||
Name = "Get" + fieldInfo.Name,
|
||||
Comment = fieldInfo.Comment,
|
||||
IsStatic = fieldInfo.IsStatic,
|
||||
Access = fieldInfo.Access,
|
||||
Attributes = fieldInfo.Attributes,
|
||||
ReturnType = fieldInfo.Type,
|
||||
Parameters = new List<FunctionInfo.ParameterInfo>(),
|
||||
IsVirtual = false,
|
||||
IsConst = true,
|
||||
Glue = new FunctionInfo.GlueInfo()
|
||||
};
|
||||
ProcessAndValidate(fieldInfo.Getter);
|
||||
fieldInfo.Getter.Name = fieldInfo.Name;
|
||||
|
||||
if (!fieldInfo.IsReadOnly)
|
||||
{
|
||||
_isScriptingObject = false;
|
||||
fieldInfo.Setter = new FunctionInfo
|
||||
{
|
||||
Name = "Set" + fieldInfo.Name,
|
||||
Comment = fieldInfo.Comment,
|
||||
IsStatic = fieldInfo.IsStatic,
|
||||
Access = fieldInfo.Access,
|
||||
Attributes = fieldInfo.Attributes,
|
||||
ReturnType = new TypeInfo
|
||||
{
|
||||
Type = "void",
|
||||
},
|
||||
Parameters = new List<FunctionInfo.ParameterInfo>
|
||||
{
|
||||
new FunctionInfo.ParameterInfo
|
||||
{
|
||||
Name = "value",
|
||||
Type = fieldInfo.Type,
|
||||
},
|
||||
},
|
||||
IsVirtual = false,
|
||||
IsConst = true,
|
||||
Glue = new FunctionInfo.GlueInfo()
|
||||
};
|
||||
ProcessAndValidate(fieldInfo.Setter);
|
||||
fieldInfo.Setter.Name = fieldInfo.Name;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var propertyInfo in Properties)
|
||||
{
|
||||
if (propertyInfo.Getter != null)
|
||||
ProcessAndValidate(propertyInfo.Getter);
|
||||
if (propertyInfo.Setter != null)
|
||||
ProcessAndValidate(propertyInfo.Setter);
|
||||
}
|
||||
|
||||
foreach (var functionInfo in Functions)
|
||||
ProcessAndValidate(functionInfo);
|
||||
}
|
||||
|
||||
private void ProcessAndValidate(FunctionInfo functionInfo)
|
||||
{
|
||||
// Ensure that methods have unique names for bindings
|
||||
if (UniqueFunctionNames == null)
|
||||
UniqueFunctionNames = new HashSet<string>();
|
||||
int idx = 1;
|
||||
functionInfo.UniqueName = functionInfo.Name;
|
||||
while (UniqueFunctionNames.Contains(functionInfo.UniqueName))
|
||||
functionInfo.UniqueName = functionInfo.Name + idx++;
|
||||
UniqueFunctionNames.Add(functionInfo.UniqueName);
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
@@ -113,7 +178,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
if (_scriptVTableSize == -1)
|
||||
{
|
||||
if (BindingsGenerator.FindApiTypeInfo(buildData, BaseType, this) is ClassInfo baseApiTypeInfo)
|
||||
if (BaseType is ClassInfo baseApiTypeInfo)
|
||||
{
|
||||
_scriptVTableOffset = baseApiTypeInfo.GetScriptVTableSize(buildData, out _);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
@@ -12,29 +13,37 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
public AccessLevel Access;
|
||||
public AccessLevel BaseTypeInheritance;
|
||||
public TypeInfo BaseType;
|
||||
public List<InterfaceInfo> Interfaces; // Optional
|
||||
public List<TypeInfo> InterfaceNames; // Optional
|
||||
public ClassStructInfo BaseType;
|
||||
public List<InterfaceInfo> Interfaces;
|
||||
public List<TypeInfo> Inheritance; // Data from parsing, used to interfaces and base type construct in Init
|
||||
|
||||
public override void Init(Builder.BuildData buildData)
|
||||
{
|
||||
base.Init(buildData);
|
||||
|
||||
if (Interfaces == null && InterfaceNames != null && InterfaceNames.Count != 0)
|
||||
if (BaseType == null && Interfaces == null && Inheritance != null)
|
||||
{
|
||||
Interfaces = new List<InterfaceInfo>();
|
||||
for (var i = 0; i < InterfaceNames.Count; i++)
|
||||
// Extract base class and interfaces from inheritance info
|
||||
for (int i = 0; i < Inheritance.Count; i++)
|
||||
{
|
||||
var interfaceName = InterfaceNames[i];
|
||||
var apiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, interfaceName, this);
|
||||
var apiTypeInfo = BindingsGenerator.FindApiTypeInfo(buildData, Inheritance[i], Parent);
|
||||
if (apiTypeInfo is InterfaceInfo interfaceInfo)
|
||||
{
|
||||
if (Interfaces == null)
|
||||
Interfaces = new List<InterfaceInfo>();
|
||||
Interfaces.Add(interfaceInfo);
|
||||
}
|
||||
else if (apiTypeInfo is ClassStructInfo otherInfo)
|
||||
{
|
||||
if (otherInfo == this)
|
||||
throw new Exception($"Type '{Name}' inherits from itself.");
|
||||
if (BaseType != null)
|
||||
throw new Exception($"Invalid '{Name}' inheritance (only single base class is allowed for scripting types, excluding interfaces).");
|
||||
BaseType = otherInfo;
|
||||
}
|
||||
}
|
||||
if (Interfaces.Count == 0)
|
||||
Interfaces = null;
|
||||
}
|
||||
BaseType?.EnsureInited(buildData);
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
@@ -42,7 +51,7 @@ namespace Flax.Build.Bindings
|
||||
writer.Write((byte)Access);
|
||||
writer.Write((byte)BaseTypeInheritance);
|
||||
BindingsGenerator.Write(writer, BaseType);
|
||||
BindingsGenerator.Write(writer, InterfaceNames);
|
||||
BindingsGenerator.Write(writer, Inheritance);
|
||||
|
||||
base.Write(writer);
|
||||
}
|
||||
@@ -52,7 +61,7 @@ namespace Flax.Build.Bindings
|
||||
Access = (AccessLevel)reader.ReadByte();
|
||||
BaseTypeInheritance = (AccessLevel)reader.ReadByte();
|
||||
BaseType = BindingsGenerator.Read(reader, BaseType);
|
||||
InterfaceNames = BindingsGenerator.Read(reader, InterfaceNames);
|
||||
Inheritance = BindingsGenerator.Read(reader, Inheritance);
|
||||
|
||||
base.Read(reader);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,19 @@ namespace Flax.Build.Bindings
|
||||
base.AddChild(apiTypeInfo);
|
||||
}
|
||||
|
||||
public override void Init(Builder.BuildData buildData)
|
||||
{
|
||||
try
|
||||
{
|
||||
base.Init(buildData);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Log.Error($"Failed to init '{Name}' file scripting API.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(FileInfo other)
|
||||
{
|
||||
return Name.CompareTo(other.Name);
|
||||
|
||||
@@ -26,14 +26,14 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
base.Init(buildData);
|
||||
|
||||
if (ForceNoPod || (InterfaceNames != null && InterfaceNames.Count != 0))
|
||||
if (ForceNoPod || (Interfaces != null && Interfaces.Count != 0))
|
||||
{
|
||||
_isPod = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Structure is POD (plain old data) only if all of it's fields are (and has no base type ro base type is also POD)
|
||||
_isPod = BaseType == null || (BindingsGenerator.FindApiTypeInfo(buildData, BaseType, Parent)?.IsPod ?? false);
|
||||
_isPod = BaseType == null || (BaseType?.IsPod ?? false);
|
||||
for (int i = 0; _isPod && i < Fields.Count; i++)
|
||||
{
|
||||
var field = Fields[i];
|
||||
@@ -42,6 +42,29 @@ namespace Flax.Build.Bindings
|
||||
_isPod = false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var fieldInfo in Fields)
|
||||
{
|
||||
if (fieldInfo.Type.IsBitField)
|
||||
throw new NotImplementedException($"TODO: support bit-fields in structure fields (found field {fieldInfo} in structure {Name})");
|
||||
|
||||
// Pointers are fine
|
||||
if (fieldInfo.Type.IsPtr)
|
||||
continue;
|
||||
|
||||
// In-build types
|
||||
if (BindingsGenerator.CSharpNativeToManagedBasicTypes.ContainsKey(fieldInfo.Type.Type))
|
||||
continue;
|
||||
if (BindingsGenerator.CSharpNativeToManagedDefault.ContainsKey(fieldInfo.Type.Type))
|
||||
continue;
|
||||
|
||||
// Find API type info for this field type
|
||||
var apiType = BindingsGenerator.FindApiTypeInfo(buildData, fieldInfo.Type, this);
|
||||
if (apiType != null)
|
||||
continue;
|
||||
|
||||
throw new Exception($"Unknown field type '{fieldInfo.Type} {fieldInfo.Name}' in structure '{Name}'.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
|
||||
@@ -36,8 +36,7 @@ namespace Flax.Build.Bindings
|
||||
var apiType = BindingsGenerator.FindApiTypeInfo(buildData, this, caller);
|
||||
if (apiType != null)
|
||||
{
|
||||
if (!apiType.IsInited)
|
||||
apiType.Init(buildData);
|
||||
apiType.EnsureInited(buildData);
|
||||
return apiType.IsPod;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,22 +46,35 @@ namespace Flax.Build
|
||||
var outputPath = Path.GetDirectoryName(buildData.Target.GetOutputFilePath(buildOptions));
|
||||
var outputFile = Path.Combine(outputPath, binaryModuleName + ".CSharp.dll");
|
||||
var outputDocFile = Path.Combine(outputPath, binaryModuleName + ".CSharp.xml");
|
||||
string monoRoot, exePath;
|
||||
string monoRoot, monoPath, cscPath;
|
||||
switch (buildPlatform)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
{
|
||||
monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Windows", "Mono");
|
||||
exePath = Path.Combine(monoRoot, "bin", "mono.exe");
|
||||
|
||||
// Prefer installed Roslyn C# compiler over Mono one
|
||||
monoPath = null;
|
||||
cscPath = Path.Combine(Path.GetDirectoryName(Deploy.VCEnvironment.MSBuildPath), "Roslyn", "csc.exe");
|
||||
|
||||
if (!File.Exists(cscPath))
|
||||
{
|
||||
// Fallback to Mono binaries
|
||||
monoPath = Path.Combine(monoRoot, "bin", "mono.exe");
|
||||
cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TargetPlatform.Linux:
|
||||
monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Linux", "Mono");
|
||||
exePath = Path.Combine(monoRoot, "bin", "mono");
|
||||
monoPath = Path.Combine(monoRoot, "bin", "mono");
|
||||
cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
|
||||
break;
|
||||
default: throw new InvalidPlatformException(buildPlatform);
|
||||
}
|
||||
var cscPath = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
|
||||
var referenceAssemblies = Path.Combine(monoRoot, "lib", "mono", "4.5-api");
|
||||
var references = new HashSet<string>(buildOptions.ScriptingAPI.FileReferences);
|
||||
|
||||
foreach (var module in binaryModule)
|
||||
{
|
||||
if (!buildData.Modules.TryGetValue(module, out var moduleBuildOptions))
|
||||
@@ -147,11 +160,23 @@ namespace Flax.Build
|
||||
task.PrerequisiteFiles.AddRange(references);
|
||||
task.ProducedFiles.Add(outputFile);
|
||||
task.WorkingDirectory = workspaceRoot;
|
||||
task.CommandPath = exePath;
|
||||
task.CommandArguments = $"\"{cscPath}\" /noconfig @\"{responseFile}\"";
|
||||
task.InfoMessage = "Compiling " + outputFile;
|
||||
task.Cost = task.PrerequisiteFiles.Count;
|
||||
|
||||
if (monoPath != null)
|
||||
{
|
||||
task.CommandPath = monoPath;
|
||||
task.CommandArguments = $"\"{cscPath}\" /noconfig @\"{responseFile}\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
// The "/shared" flag enables the compiler server support:
|
||||
// https://github.com/dotnet/roslyn/blob/main/docs/compilers/Compiler%20Server.md
|
||||
|
||||
task.CommandPath = cscPath;
|
||||
task.CommandArguments = $"/noconfig /shared @\"{responseFile}\"";
|
||||
}
|
||||
|
||||
// Copy referenced assemblies
|
||||
foreach (var reference in buildOptions.ScriptingAPI.FileReferences)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,12 @@ namespace Flax.Build
|
||||
{
|
||||
public static partial class Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Package deployment output path.
|
||||
/// </summary>
|
||||
[CommandLine("deployOutput", "Package deployment output path.")]
|
||||
public static string DeployOutput;
|
||||
|
||||
/// <summary>
|
||||
/// Builds and packages the editor.
|
||||
/// </summary>
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Flax.Deploy
|
||||
public static int VersionMajor;
|
||||
public static int VersionMinor;
|
||||
public static int VersionBuild;
|
||||
public static TargetConfiguration[] Configurations;
|
||||
|
||||
public static bool Run()
|
||||
{
|
||||
@@ -64,6 +65,8 @@ namespace Flax.Deploy
|
||||
|
||||
static void Initialize()
|
||||
{
|
||||
Configurations = Configuration.BuildConfigurations != null ? Configuration.BuildConfigurations : new[] { TargetConfiguration.Debug, TargetConfiguration.Development, TargetConfiguration.Release };
|
||||
|
||||
// Read the current engine version
|
||||
var engineVersion = EngineTarget.EngineVersion;
|
||||
VersionMajor = engineVersion.Major;
|
||||
@@ -81,9 +84,12 @@ namespace Flax.Deploy
|
||||
Utilities.WriteFileIfChanged(Path.Combine(Globals.EngineRoot, "Source/Engine/Core/Config.Gen.h"), buildConfigHeader.ToString());
|
||||
|
||||
// Prepare the package output
|
||||
PackageOutputPath = Path.Combine(Globals.EngineRoot, string.Format("Package_{0}_{1:00}_{2:00000}", VersionMajor, VersionMinor, VersionBuild));
|
||||
Utilities.DirectoryDelete(PackageOutputPath);
|
||||
Directory.CreateDirectory(PackageOutputPath);
|
||||
if (string.IsNullOrEmpty(Configuration.DeployOutput))
|
||||
PackageOutputPath = Path.Combine(Globals.EngineRoot, string.Format("Package_{0}_{1:00}_{2:00000}", VersionMajor, VersionMinor, VersionBuild));
|
||||
else
|
||||
PackageOutputPath = Configuration.DeployOutput;
|
||||
if (!Directory.Exists(PackageOutputPath))
|
||||
Directory.CreateDirectory(PackageOutputPath);
|
||||
|
||||
Log.Info(string.Empty);
|
||||
Log.Info(string.Empty);
|
||||
@@ -104,9 +110,10 @@ namespace Flax.Deploy
|
||||
private static void BuildEditor()
|
||||
{
|
||||
var targetPlatform = Platform.BuildPlatform.Target;
|
||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Debug);
|
||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Development);
|
||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Release);
|
||||
foreach (var configuration in Configurations)
|
||||
{
|
||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, configuration);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CannotBuildPlatform(TargetPlatform platform)
|
||||
@@ -129,9 +136,10 @@ namespace Flax.Deploy
|
||||
{
|
||||
if (Platform.IsPlatformSupported(platform, architecture))
|
||||
{
|
||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, TargetConfiguration.Debug);
|
||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, TargetConfiguration.Development);
|
||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, TargetConfiguration.Release);
|
||||
foreach (var configuration in Configurations)
|
||||
{
|
||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,15 +34,15 @@ namespace Flax.Deploy
|
||||
// Prepare
|
||||
RootPath = Globals.EngineRoot;
|
||||
OutputPath = Path.Combine(Deployer.PackageOutputPath, "Editor");
|
||||
Utilities.DirectoryDelete(OutputPath);
|
||||
Directory.CreateDirectory(OutputPath);
|
||||
Log.Info(string.Empty);
|
||||
Log.Info("Deploy editor files");
|
||||
Log.Info(string.Empty);
|
||||
|
||||
// Deploy binaries
|
||||
DeployEditorBinaries(TargetConfiguration.Debug);
|
||||
DeployEditorBinaries(TargetConfiguration.Development);
|
||||
DeployEditorBinaries(TargetConfiguration.Release);
|
||||
foreach (var configuration in Deployer.Configurations)
|
||||
DeployEditorBinaries(configuration);
|
||||
{
|
||||
var binariesSubDir = "Binaries/Tools";
|
||||
var src = Path.Combine(RootPath, binariesSubDir);
|
||||
@@ -130,12 +130,14 @@ namespace Flax.Deploy
|
||||
{
|
||||
// Use system tool (preserves executable file attributes and link files)
|
||||
editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "FlaxEditorLinux.zip");
|
||||
Utilities.FileDelete(editorPackageZipPath);
|
||||
Utilities.Run("zip", "Editor.zip -r .", null, OutputPath, Utilities.RunOptions.None);
|
||||
File.Move(Path.Combine(OutputPath, "Editor.zip"), editorPackageZipPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "Editor.zip");
|
||||
Utilities.FileDelete(editorPackageZipPath);
|
||||
using (ZipFile zip = new ZipFile())
|
||||
{
|
||||
zip.AddDirectory(OutputPath);
|
||||
@@ -152,6 +154,7 @@ namespace Flax.Deploy
|
||||
{
|
||||
Log.Info("Compressing editor debug symbols files...");
|
||||
editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols.zip");
|
||||
Utilities.FileDelete(editorPackageZipPath);
|
||||
using (ZipFile zip = new ZipFile())
|
||||
{
|
||||
zip.AddDirectory(Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols"));
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace Flax.Deploy
|
||||
string platformName = platform.ToString();
|
||||
string src = Path.Combine(platformsRoot, platformName);
|
||||
string dst = Path.Combine(Deployer.PackageOutputPath, platformName);
|
||||
Utilities.DirectoryDelete(dst);
|
||||
|
||||
// Deploy files
|
||||
{
|
||||
@@ -69,6 +70,7 @@ namespace Flax.Deploy
|
||||
Log.Info("Compressing platform files...");
|
||||
|
||||
var packageZipPath = Path.Combine(Deployer.PackageOutputPath, platformName + ".zip");
|
||||
Utilities.FileDelete(packageZipPath);
|
||||
using (ZipFile zip = new ZipFile())
|
||||
{
|
||||
zip.AddDirectory(dst);
|
||||
|
||||
Reference in New Issue
Block a user