Optimize scripting API bindings generation if loaded API from valid cache

This commit is contained in:
Wojtek Figat
2021-02-16 10:42:56 +01:00
parent f11686a7b7
commit fa332a3785
5 changed files with 63 additions and 39 deletions

View File

@@ -1028,9 +1028,6 @@ namespace Flax.Build.Bindings
private static void GenerateCSharp(BuildData buildData, ModuleInfo moduleInfo, ref BindingsResult bindings)
{
if (!bindings.UseBindings)
return;
var contents = new StringBuilder();
buildData.Modules.TryGetValue(moduleInfo.Module, out var moduleBuildInfo);
@@ -1081,12 +1078,6 @@ namespace Flax.Build.Bindings
// Save generated file
contents.AppendLine("#endif");
Utilities.WriteFileIfChanged(bindings.GeneratedCSharpFilePath, contents.ToString());
// Ensure that generated file is included into build
if (!moduleBuildInfo.SourceFiles.Contains(bindings.GeneratedCSharpFilePath))
{
moduleBuildInfo.SourceFiles.Add(bindings.GeneratedCSharpFilePath);
}
}
internal struct GuidInterop

View File

@@ -245,7 +245,7 @@ namespace Flax.Build.Bindings
Module = moduleInfo.Module,
Name = moduleInfo.Name,
Namespace = moduleInfo.Namespace,
Children = new List<ApiTypeInfo>(),
IsFromCache = true,
};
try
{

View File

@@ -1656,10 +1656,10 @@ namespace Flax.Build.Bindings
}
}
private static bool GenerateCppType(BuildData buildData, StringBuilder contents, ModuleInfo moduleInfo, object type)
private static void GenerateCppType(BuildData buildData, StringBuilder contents, ModuleInfo moduleInfo, object type)
{
if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.IsInBuild)
return false;
return;
try
{
@@ -1671,16 +1671,12 @@ namespace Flax.Build.Bindings
GenerateCppInterface(buildData, contents, moduleInfo, interfaceInfo);
else if (type is InjectCppCodeInfo injectCppCodeInfo)
contents.AppendLine(injectCppCodeInfo.Code);
else
return false;
}
catch
{
Log.Error($"Failed to generate C++ bindings for {type}.");
throw;
}
return true;
}
private static void GenerateCppCppUsedNonPodTypes(BuildData buildData, ApiTypeInfo apiType)
@@ -1728,21 +1724,16 @@ namespace Flax.Build.Bindings
CppReferencesFiles.Add(fileInfo);
}
}
var headerPos = contents.Length;
foreach (var child in moduleInfo.Children)
{
foreach (var apiTypeInfo in child.Children)
{
if (GenerateCppType(buildData, contents, moduleInfo, apiTypeInfo))
bindings.UseBindings = true;
GenerateCppType(buildData, contents, moduleInfo, apiTypeInfo);
}
}
if (!bindings.UseBindings)
return;
GenerateCppModuleSource?.Invoke(buildData, moduleInfo, contents);
{
@@ -2036,7 +2027,7 @@ namespace Flax.Build.Bindings
var binaryModuleSourcePath = Path.Combine(project.ProjectFolderPath, "Source", binaryModuleName + ".Gen.cpp");
contents.AppendLine("// This code was auto-generated. Do not modify it.");
contents.AppendLine();
contents.AppendLine($"#include \"Engine/Scripting/BinaryModule.h\"");
contents.AppendLine("#include \"Engine/Scripting/BinaryModule.h\"");
contents.AppendLine($"#include \"{binaryModuleName}.Gen.h\"");
contents.AppendLine();
contents.AppendLine($"StaticallyLinkedBinaryModuleInitializer StaticallyLinkedBinaryModule{binaryModuleName}(GetBinaryModule{binaryModuleName});");

View File

@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flax.Build.NativeCpp;
@@ -65,7 +66,6 @@ namespace Flax.Build.Bindings
Module = module,
Name = module.BinaryModuleName,
Namespace = string.Empty,
Children = new List<ApiTypeInfo>(),
};
if (string.IsNullOrEmpty(moduleInfo.Name))
throw new Exception("Module name cannot be empty.");
@@ -479,41 +479,82 @@ namespace Flax.Build.Bindings
throw new Exception($"Invalid #if/endif pairing in file '{fileInfo.Name}'. Failed to generate API bindings for it.");
}
private static bool UseBindings(object type)
{
var apiTypeInfo = type as ApiTypeInfo;
if (apiTypeInfo != null && apiTypeInfo.IsInBuild)
return false;
if ((type is ModuleInfo || type is FileInfo) && apiTypeInfo != null)
{
foreach (var child in apiTypeInfo.Children)
{
if (UseBindings(child))
return true;
}
}
return type is ClassInfo ||
type is StructureInfo ||
type is InterfaceInfo ||
type is InjectCppCodeInfo;
}
/// <summary>
/// The API bindings generation utility that can produce scripting bindings for another languages to the native code.
/// </summary>
public static void GenerateBindings(BuildData buildData, Module module, ref BuildOptions moduleOptions, out BindingsResult bindings)
{
// Parse module (or load from cache)
var moduleInfo = ParseModule(buildData, module, moduleOptions);
bindings = new BindingsResult
{
UseBindings = UseBindings(moduleInfo),
GeneratedCppFilePath = Path.Combine(moduleOptions.IntermediateFolder, module.Name + ".Bindings.Gen.cpp"),
GeneratedCSharpFilePath = Path.Combine(moduleOptions.IntermediateFolder, module.Name + ".Bindings.Gen.cs"),
};
var moduleInfo = ParseModule(buildData, module, moduleOptions);
if (bindings.UseBindings)
{
buildData.Modules.TryGetValue(moduleInfo.Module, out var moduleBuildInfo);
// Ensure that generated files are included into build
if (!moduleBuildInfo.SourceFiles.Contains(bindings.GeneratedCSharpFilePath))
moduleBuildInfo.SourceFiles.Add(bindings.GeneratedCSharpFilePath);
}
// Skip if module is cached (no scripting API changed)
if (moduleInfo.IsFromCache)
return;
// Process parsed API
foreach (var child in moduleInfo.Children)
using (new ProfileEventScope("Process"))
{
try
foreach (var child in moduleInfo.Children)
{
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;
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;
}
}
}
// Generate bindings for scripting
Log.Verbose($"Generating API bindings for {module.Name} ({moduleInfo.Name})");
GenerateCpp(buildData, moduleInfo, ref bindings);
GenerateCSharp(buildData, moduleInfo, ref bindings);
if (bindings.UseBindings)
{
Log.Verbose($"Generating API bindings for {module.Name} ({moduleInfo.Name})");
using (new ProfileEventScope("Cpp"))
GenerateCpp(buildData, moduleInfo, ref bindings);
using (new ProfileEventScope("CSharp"))
GenerateCSharp(buildData, moduleInfo, ref bindings);
// TODO: add support for extending this code and support generating bindings for other scripting languages
// TODO: add support for extending this code and support generating bindings for other scripting languages
}
}
/// <summary>

View File

@@ -11,6 +11,7 @@ namespace Flax.Build.Bindings
public class ModuleInfo : ApiTypeInfo
{
public Module Module;
public bool IsFromCache;
public override string ToString()
{