Add support for binary modules with native-code only
This commit is contained in:
@@ -456,7 +456,7 @@ int32 GameCookerImpl::ThreadFunction()
|
||||
|
||||
bool GameCookerService::Init()
|
||||
{
|
||||
auto editorAssembly = GetBinaryModuleFlaxEngine()->Assembly;
|
||||
auto editorAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
editorAssembly->Unloading.Bind(OnEditorAssemblyUnloading);
|
||||
|
||||
return false;
|
||||
|
||||
@@ -73,7 +73,7 @@ MonoReflectionType* CustomEditorsUtil::GetCustomEditor(MonoReflectionType* refTy
|
||||
|
||||
bool CustomEditorsUtilService::Init()
|
||||
{
|
||||
TRACK_ASSEMBLY(GetBinaryModuleFlaxEngine()->Assembly);
|
||||
TRACK_ASSEMBLY(((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly);
|
||||
Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded);
|
||||
|
||||
return false;
|
||||
@@ -84,7 +84,7 @@ void OnAssemblyLoaded(MAssembly* assembly)
|
||||
const auto startTime = DateTime::NowUTC();
|
||||
|
||||
// Prepare FlaxEngine
|
||||
auto engineAssembly = GetBinaryModuleFlaxEngine()->Assembly;
|
||||
auto engineAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
if (!engineAssembly->IsLoaded())
|
||||
{
|
||||
LOG(Warning, "Cannot load custom editors meta for assembly {0} because FlaxEngine is not loaded.", assembly->ToString());
|
||||
@@ -173,7 +173,7 @@ void OnAssemblyLoaded(MAssembly* assembly)
|
||||
void OnAssemblyUnloading(MAssembly* assembly)
|
||||
{
|
||||
// Fast clear for editor unloading
|
||||
if (assembly == GetBinaryModuleFlaxEngine()->Assembly)
|
||||
if (assembly == ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly)
|
||||
{
|
||||
Cache.Clear();
|
||||
return;
|
||||
|
||||
@@ -900,7 +900,7 @@ public:
|
||||
if (stack && stack->Scope)
|
||||
{
|
||||
const int32 count = stack->Scope->Parameters.Length() + stack->Scope->ReturnedValues.Count();
|
||||
const auto mclass = GetBinaryModuleFlaxEngine()->Assembly->GetClass("FlaxEditor.Editor+VisualScriptLocal");
|
||||
const auto mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptLocal");
|
||||
ASSERT(mclass);
|
||||
result = mono_array_new(mono_domain_get(), mclass->GetNative(), count);
|
||||
VisualScriptLocalManaged local;
|
||||
@@ -954,7 +954,7 @@ public:
|
||||
s = s->PreviousFrame;
|
||||
count++;
|
||||
}
|
||||
const auto mclass = GetBinaryModuleFlaxEngine()->Assembly->GetClass("FlaxEditor.Editor+VisualScriptStackFrame");
|
||||
const auto mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptStackFrame");
|
||||
ASSERT(mclass);
|
||||
result = mono_array_new(mono_domain_get(), mclass->GetNative(), count);
|
||||
s = stack;
|
||||
|
||||
@@ -175,7 +175,7 @@ ManagedEditor::ManagedEditor()
|
||||
: PersistentScriptingObject(SpawnParams(ObjectID, ManagedEditor::TypeInitializer))
|
||||
{
|
||||
// Link events
|
||||
auto editor = GetBinaryModuleFlaxEngine()->Assembly;
|
||||
auto editor = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
editor->Loaded.Bind<ManagedEditor, &ManagedEditor::OnEditorAssemblyLoaded>(this);
|
||||
ProbesRenderer::OnRegisterBake.Bind<OnRegisterBake>();
|
||||
ProbesRenderer::OnFinishBake.Bind<OnFinishBake>();
|
||||
@@ -192,7 +192,7 @@ ManagedEditor::ManagedEditor()
|
||||
ManagedEditor::~ManagedEditor()
|
||||
{
|
||||
// Unlink events
|
||||
auto editor = GetBinaryModuleFlaxEngine()->Assembly;
|
||||
auto editor = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
editor->Loaded.Unbind<ManagedEditor, &ManagedEditor::OnEditorAssemblyLoaded>(this);
|
||||
ProbesRenderer::OnRegisterBake.Unbind<OnRegisterBake>();
|
||||
ProbesRenderer::OnFinishBake.Unbind<OnFinishBake>();
|
||||
|
||||
@@ -524,7 +524,7 @@ bool ScriptsBuilderService::Init()
|
||||
_isInited = true;
|
||||
|
||||
// Link for Editor assembly unload event to clear cached Internal_OnCompilationEnd to prevent errors
|
||||
auto editorAssembly = GetBinaryModuleFlaxEngine()->Assembly;
|
||||
auto editorAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
editorAssembly->Unloading.Bind(onEditorAssemblyUnloading);
|
||||
|
||||
// Listen to scripts reloading events and forward them to c#
|
||||
|
||||
@@ -104,7 +104,7 @@ bool CacheMethods()
|
||||
if (Internal_SendLog && Internal_SendLogException && Internal_GetStackTrace)
|
||||
return false;
|
||||
|
||||
auto engine = GetBinaryModuleFlaxEngine()->Assembly;
|
||||
auto engine = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
if (engine == nullptr || !engine->IsLoaded())
|
||||
return true;
|
||||
auto debugLogHandlerClass = engine->GetClass("FlaxEngine.DebugLogHandler");
|
||||
|
||||
@@ -163,7 +163,7 @@ void ManagedPostProcessEffect::FetchInfo()
|
||||
static MMethod* FetchInfoManaged = nullptr;
|
||||
if (FetchInfoManaged == nullptr)
|
||||
{
|
||||
auto klass = GetBinaryModuleFlaxEngine()->Assembly->GetClass("FlaxEngine.PostProcessEffect");
|
||||
auto klass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEngine.PostProcessEffect");
|
||||
ASSERT(klass);
|
||||
FetchInfoManaged = klass->GetMethod("FetchInfo", 3);
|
||||
ASSERT(FetchInfoManaged);
|
||||
|
||||
@@ -633,7 +633,7 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
|
||||
|
||||
// Cache types for managed-only types that can be used in the engine
|
||||
_firstManagedTypeIndex = Types.Count();
|
||||
NativeBinaryModule* flaxEngine = GetBinaryModuleFlaxEngine();
|
||||
NativeBinaryModule* flaxEngine = (NativeBinaryModule*)GetBinaryModuleFlaxEngine();
|
||||
if (flaxEngine->Assembly->IsLoaded())
|
||||
{
|
||||
// TODO: check only assemblies that references FlaxEngine.CSharp.dll
|
||||
@@ -1039,6 +1039,37 @@ void NativeBinaryModule::Destroy(bool isReloading)
|
||||
}
|
||||
}
|
||||
|
||||
NativeOnlyBinaryModule::NativeOnlyBinaryModule(const StringAnsiView& name)
|
||||
: BinaryModule()
|
||||
, _name(name)
|
||||
, Library(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
const StringAnsi& NativeOnlyBinaryModule::GetName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
bool NativeOnlyBinaryModule::IsLoaded() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeOnlyBinaryModule::Destroy(bool isReloading)
|
||||
{
|
||||
BinaryModule::Destroy(isReloading);
|
||||
|
||||
// Release native library
|
||||
const auto library = Library;
|
||||
if (library)
|
||||
{
|
||||
Library = nullptr;
|
||||
Platform::FreeLibrary(library);
|
||||
// Don't do anything after FreeLibrary (this pointer might be invalid)
|
||||
}
|
||||
}
|
||||
|
||||
Array<GetBinaryModuleFunc>& StaticallyLinkedBinaryModuleInitializer::GetStaticallyLinkedBinaryModules()
|
||||
{
|
||||
static Array<GetBinaryModuleFunc> modules;
|
||||
|
||||
@@ -355,7 +355,39 @@ public:
|
||||
void Destroy(bool isReloading) override;
|
||||
};
|
||||
|
||||
typedef NativeBinaryModule* (*GetBinaryModuleFunc)();
|
||||
/// <summary>
|
||||
/// The C++ scripting assembly container.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API NativeOnlyBinaryModule : public BinaryModule
|
||||
{
|
||||
private:
|
||||
|
||||
StringAnsi _name;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NativeOnlyBinaryModule" /> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The module name.</param>
|
||||
NativeOnlyBinaryModule(const StringAnsiView& name);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// The native library (C++ DLL).
|
||||
/// </summary>
|
||||
void* Library;
|
||||
|
||||
public:
|
||||
|
||||
// [BinaryModule]
|
||||
const StringAnsi& GetName() const override;
|
||||
bool IsLoaded() const override;
|
||||
void Destroy(bool isReloading) override;
|
||||
};
|
||||
|
||||
typedef BinaryModule* (*GetBinaryModuleFunc)();
|
||||
|
||||
// Helper utility for registering native binary modules that are statically linked.
|
||||
class FLAXENGINE_API StaticallyLinkedBinaryModuleInitializer
|
||||
|
||||
@@ -66,7 +66,7 @@ void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly)
|
||||
PROFILE_CPU_NAMED("Load Assembly Plugins");
|
||||
|
||||
// Prepare FlaxEngine
|
||||
auto engineAssembly = GetBinaryModuleFlaxEngine()->Assembly;
|
||||
auto engineAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
if (!engineAssembly->IsLoaded())
|
||||
{
|
||||
LOG(Warning, "Cannot find plugin class types for assembly {0} because FlaxEngine is not loaded.", assembly->ToString());
|
||||
|
||||
@@ -124,7 +124,7 @@ bool ScriptingService::Init()
|
||||
const auto startTime = DateTime::NowUTC();
|
||||
|
||||
// Link for assemblies events
|
||||
auto engineAssembly = GetBinaryModuleFlaxEngine()->Assembly;
|
||||
auto engineAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
engineAssembly->Loaded.Bind(onEngineLoaded);
|
||||
engineAssembly->Unloading.Bind(onEngineUnloading);
|
||||
|
||||
@@ -424,7 +424,7 @@ bool Scripting::Load()
|
||||
|
||||
// Load FlaxEngine
|
||||
const String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll");
|
||||
if (GetBinaryModuleFlaxEngine()->Assembly->Load(flaxEnginePath))
|
||||
if (((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->Load(flaxEnginePath))
|
||||
{
|
||||
LOG(Error, "Failed to load FlaxEngine C# assembly.");
|
||||
return true;
|
||||
|
||||
@@ -48,7 +48,7 @@ void StdTypesContainer::Clear()
|
||||
bool StdTypesContainer::Gather()
|
||||
{
|
||||
#define GET_CLASS(assembly, type, typeName) \
|
||||
type = CONCAT_MACROS(GetBinaryModule, assembly)()->Assembly->GetClass(typeName); \
|
||||
type = ((ManagedBinaryModule*)CONCAT_MACROS(GetBinaryModule, assembly)())->Assembly->GetClass(typeName); \
|
||||
if (type == nullptr) \
|
||||
{ \
|
||||
LOG(Error, "Missing managed type: \'{0}\'", String(typeName)); \
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
StaticallyLinkedBinaryModuleInitializer StaticallyLinkedBinaryModuleFlaxEngine(GetBinaryModuleFlaxEngine);
|
||||
|
||||
extern "C" NativeBinaryModule* GetBinaryModuleFlaxEngine()
|
||||
extern "C" BinaryModule* GetBinaryModuleFlaxEngine()
|
||||
{
|
||||
static NativeBinaryModule module("FlaxEngine", MAssemblyOptions());
|
||||
return &module;
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
#define FLAXENGINE_COMPANY "Flax"
|
||||
#define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved."
|
||||
|
||||
class NativeBinaryModule;
|
||||
extern "C" FLAXENGINE_API NativeBinaryModule* GetBinaryModuleFlaxEngine();
|
||||
class BinaryModule;
|
||||
extern "C" FLAXENGINE_API BinaryModule* GetBinaryModuleFlaxEngine();
|
||||
|
||||
@@ -1091,6 +1091,10 @@ namespace Flax.Build.Bindings
|
||||
|
||||
private static unsafe void GenerateCSharp(BuildData buildData, IGrouping<string, Module> binaryModule)
|
||||
{
|
||||
// Skip generating C# bindings code for native-only modules
|
||||
if (binaryModule.Any(x => !x.BuildCSharp))
|
||||
return;
|
||||
|
||||
var contents = new StringBuilder();
|
||||
var binaryModuleName = binaryModule.Key;
|
||||
var project = Builder.GetModuleProject(binaryModule.First(), buildData);
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace Flax.Build.Bindings
|
||||
using (var writer = new BinaryWriter(stream, Encoding.UTF8))
|
||||
{
|
||||
// Version
|
||||
writer.Write(4);
|
||||
writer.Write(5);
|
||||
writer.Write(File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks);
|
||||
|
||||
// Build options
|
||||
@@ -254,7 +254,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
// Version
|
||||
var version = reader.ReadInt32();
|
||||
if (version != 4)
|
||||
if (version != 5)
|
||||
return false;
|
||||
if (File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks != reader.ReadInt64())
|
||||
return false;
|
||||
|
||||
@@ -1991,6 +1991,7 @@ namespace Flax.Build.Bindings
|
||||
// Skip generating C++ bindings code for C#-only modules
|
||||
if (binaryModule.Any(x => !x.BuildNativeCode))
|
||||
return;
|
||||
var useCSharp = binaryModule.Any(x => x.BuildCSharp);
|
||||
|
||||
var contents = new StringBuilder();
|
||||
var binaryModuleName = binaryModule.Key;
|
||||
@@ -2018,8 +2019,8 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine($"#define {binaryModuleNameUpper}_COMPANY \"{project.Company}\"");
|
||||
contents.AppendLine($"#define {binaryModuleNameUpper}_COPYRIGHT \"{project.Copyright}\"");
|
||||
contents.AppendLine();
|
||||
contents.AppendLine("class NativeBinaryModule;");
|
||||
contents.AppendLine($"extern \"C\" {binaryModuleNameUpper}_API NativeBinaryModule* GetBinaryModule{binaryModuleName}();");
|
||||
contents.AppendLine("class BinaryModule;");
|
||||
contents.AppendLine($"extern \"C\" {binaryModuleNameUpper}_API BinaryModule* GetBinaryModule{binaryModuleName}();");
|
||||
GenerateCppBinaryModuleHeader?.Invoke(buildData, binaryModule, contents);
|
||||
Utilities.WriteFileIfChanged(binaryModuleHeaderPath, contents.ToString());
|
||||
|
||||
@@ -2033,9 +2034,16 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine();
|
||||
contents.AppendLine($"StaticallyLinkedBinaryModuleInitializer StaticallyLinkedBinaryModule{binaryModuleName}(GetBinaryModule{binaryModuleName});");
|
||||
contents.AppendLine();
|
||||
contents.AppendLine($"extern \"C\" NativeBinaryModule* GetBinaryModule{binaryModuleName}()");
|
||||
contents.AppendLine($"extern \"C\" BinaryModule* GetBinaryModule{binaryModuleName}()");
|
||||
contents.AppendLine("{");
|
||||
contents.AppendLine($" static NativeBinaryModule module(\"{binaryModuleName}\", MAssemblyOptions());");
|
||||
if (useCSharp)
|
||||
{
|
||||
contents.AppendLine($" static NativeBinaryModule module(\"{binaryModuleName}\", MAssemblyOptions());");
|
||||
}
|
||||
else
|
||||
{
|
||||
contents.AppendLine($" static NativeOnlyBinaryModule module(\"{binaryModuleName}\");");
|
||||
}
|
||||
contents.AppendLine(" return &module;");
|
||||
contents.AppendLine("}");
|
||||
GenerateCppBinaryModuleSource?.Invoke(buildData, binaryModule, contents);
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace Flax.Build.Bindings
|
||||
writer.Write(Module.FilePath);
|
||||
BindingsGenerator.Write(writer, Module.BinaryModuleName);
|
||||
writer.Write(Module.BuildNativeCode);
|
||||
writer.Write(Module.BuildCSharp);
|
||||
|
||||
base.Write(writer);
|
||||
}
|
||||
@@ -42,7 +43,9 @@ namespace Flax.Build.Bindings
|
||||
if (reader.ReadString() != Module.Name ||
|
||||
reader.ReadString() != Module.FilePath ||
|
||||
BindingsGenerator.Read(reader, Module.BinaryModuleName) != Module.BinaryModuleName ||
|
||||
reader.ReadBoolean() != Module.BuildNativeCode)
|
||||
reader.ReadBoolean() != Module.BuildNativeCode ||
|
||||
reader.ReadBoolean() != Module.BuildCSharp
|
||||
)
|
||||
throw new Exception();
|
||||
|
||||
base.Read(reader);
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace Flax.Build
|
||||
var buildOptions = buildData.TargetOptions;
|
||||
foreach (var binaryModule in buildData.BinaryModules)
|
||||
{
|
||||
if (binaryModule.All(x => !x.BuildCSharp))
|
||||
continue;
|
||||
var binaryModuleName = binaryModule.Key;
|
||||
using (new ProfileEventScope(binaryModuleName))
|
||||
{
|
||||
@@ -71,6 +73,7 @@ namespace Flax.Build
|
||||
var dependencyModule = buildData.Rules.GetModule(dependencyName);
|
||||
if (dependencyModule != null &&
|
||||
!string.IsNullOrEmpty(dependencyModule.BinaryModuleName) &&
|
||||
dependencyModule.BuildCSharp &&
|
||||
dependencyModule.BinaryModuleName != binaryModuleName &&
|
||||
buildData.Modules.TryGetValue(dependencyModule, out var dependencyModuleOptions))
|
||||
{
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace Flax.Build
|
||||
/// </summary>
|
||||
public bool BuildNativeCode = true;
|
||||
|
||||
/// <summary>
|
||||
/// True if module has C# code to build. Can be used for native modules without C# bindings nor code.
|
||||
/// </summary>
|
||||
public bool BuildCSharp = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Module"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -831,6 +831,11 @@ namespace Flax.Build
|
||||
// C#-only binary module
|
||||
binaryModuleInfo.NativePath = string.Empty;
|
||||
}
|
||||
if (!binaryModule.Any(x => x.BuildCSharp))
|
||||
{
|
||||
// Skip C#
|
||||
binaryModuleInfo.ManagedPath = string.Empty;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TargetLinkType.Modular:
|
||||
@@ -850,6 +855,11 @@ namespace Flax.Build
|
||||
// C#-only binary module
|
||||
binaryModuleInfo.NativePath = string.Empty;
|
||||
}
|
||||
if (!module.BuildCSharp)
|
||||
{
|
||||
// Skip C#
|
||||
binaryModuleInfo.ManagedPath = string.Empty;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
|
||||
Reference in New Issue
Block a user