C#: Initial NativeAOT support
This commit adds initial support for games exported as NativeAOT shared libraries. At this moment, the NativeAOT runtime is experimental. Additionally, Godot is not trim-safe as it still makes some use of reflection. For the time being, a rd.xml file is needed to prevent code triming: ``` <Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata"> <Application> <Assembly Name="GodotSharp" Dynamic="Required All" /> <Assembly Name="GAME_ASSEMBLY" Dynamic="Required All" /> </Application> </Directives> ``` These are the csproj changes for publishing: ``` <PropertyGroup> <NativeLib>Shared</NativeLib> </PropertyGroup> <ItemGroup> <RdXmlFile Include="rd.xml" /> <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="7.0.0-*" /> </ItemGroup> ``` More info: - https://github.com/dotnet/runtimelab/blob/feature/NativeAOT/docs/using-nativeaot/compiling.md - https://github.com/dotnet/runtimelab/tree/feature/NativeAOT/samples/NativeLibrary - https://github.com/dotnet/runtimelab/blob/feature/NativeAOT/docs/using-nativeaot/rd-xml-format.md
This commit is contained in:
parent
18f805b3aa
commit
4b90d16250
|
@ -2179,7 +2179,9 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
|
||||||
if (exports_invalidated)
|
if (exports_invalidated)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
exports_invalidated = false;
|
exports_invalidated = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|
||||||
|
@ -2222,6 +2224,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
GDMonoCache::managed_callbacks.ScriptManagerBridge_GetPropertyDefaultValues(this,
|
GDMonoCache::managed_callbacks.ScriptManagerBridge_GetPropertyDefaultValues(this,
|
||||||
[](CSharpScript *p_script, GDMonoCache::godotsharp_property_def_val_pair *p_def_vals, int32_t p_count) {
|
[](CSharpScript *p_script, GDMonoCache::godotsharp_property_def_val_pair *p_def_vals, int32_t p_count) {
|
||||||
for (int i = 0; i < p_count; i++) {
|
for (int i = 0; i < p_count; i++) {
|
||||||
|
@ -2233,6 +2236,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
|
||||||
p_script->exported_members_defval_cache[name] = value;
|
p_script->exported_members_defval_cache[name] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,14 +26,16 @@ namespace GodotPlugins.Game
|
||||||
{
|
{
|
||||||
internal static partial class Main
|
internal static partial class Main
|
||||||
{
|
{
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly(EntryPoint = ""godotsharp_game_main_init"")]
|
||||||
private static godot_bool InitializeFromGameProject(IntPtr outManagedCallbacks)
|
private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
DllImportResolver dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport;
|
||||||
|
|
||||||
var coreApiAssembly = typeof(Godot.Object).Assembly;
|
var coreApiAssembly = typeof(Godot.Object).Assembly;
|
||||||
|
|
||||||
NativeLibrary.SetDllImportResolver(coreApiAssembly, GodotDllImportResolver.OnResolveDllImport);
|
NativeLibrary.SetDllImportResolver(coreApiAssembly, dllImportResolver);
|
||||||
|
|
||||||
ManagedCallbacks.Create(outManagedCallbacks);
|
ManagedCallbacks.Create(outManagedCallbacks);
|
||||||
|
|
||||||
|
|
|
@ -197,10 +197,6 @@ namespace GodotTools.Build
|
||||||
// Logger
|
// Logger
|
||||||
AddLoggerArgument(buildInfo, arguments);
|
AddLoggerArgument(buildInfo, arguments);
|
||||||
|
|
||||||
// Trimming is not supported for dynamically loaded assemblies, as is our case with self hosting:
|
|
||||||
// https://github.com/dotnet/runtime/blob/main/docs/design/features/native-hosting.md#incompatible-with-trimming
|
|
||||||
arguments.Add("-p:PublishTrimmed=false");
|
|
||||||
|
|
||||||
// Custom properties
|
// Custom properties
|
||||||
foreach (string customProperty in buildInfo.CustomProperties)
|
foreach (string customProperty in buildInfo.CustomProperties)
|
||||||
{
|
{
|
||||||
|
|
|
@ -134,7 +134,16 @@ namespace GodotTools.Export
|
||||||
throw new Exception("Failed to build project");
|
throw new Exception("Failed to build project");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpEditor.ProjectAssemblyName}.dll")))
|
string soExt = ridOS switch
|
||||||
|
{
|
||||||
|
OS.DotNetOS.Win or OS.DotNetOS.Win10 => "dll",
|
||||||
|
OS.DotNetOS.OSX or OS.DotNetOS.iOS => "dylib",
|
||||||
|
_ => "so"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpEditor.ProjectAssemblyName}.dll"))
|
||||||
|
// NativeAOT shared library output
|
||||||
|
&& !File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpEditor.ProjectAssemblyName}.{soExt}")))
|
||||||
{
|
{
|
||||||
throw new NotSupportedException(
|
throw new NotSupportedException(
|
||||||
"Publish succeeded but project assembly not found in the output directory");
|
"Publish succeeded but project assembly not found in the output directory");
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace GodotTools.Utils
|
||||||
public const string HTML5 = "javascript";
|
public const string HTML5 = "javascript";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DotNetOS
|
public static class DotNetOS
|
||||||
{
|
{
|
||||||
public const string Win = "win";
|
public const string Win = "win";
|
||||||
public const string OSX = "osx";
|
public const string OSX = "osx";
|
||||||
|
|
|
@ -20,22 +20,26 @@ namespace GodotPlugins
|
||||||
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
|
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
|
||||||
AssemblyLoadContext.Default;
|
AssemblyLoadContext.Default;
|
||||||
|
|
||||||
|
private static DllImportResolver? _dllImportResolver;
|
||||||
|
|
||||||
// Right now we do it this way for simplicity as hot-reload is disabled. It will need to be changed later.
|
// Right now we do it this way for simplicity as hot-reload is disabled. It will need to be changed later.
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
// ReSharper disable once UnusedMember.Local
|
// ReSharper disable once UnusedMember.Local
|
||||||
private static unsafe godot_bool InitializeFromEngine(godot_bool editorHint,
|
private static unsafe godot_bool InitializeFromEngine(IntPtr godotDllHandle, godot_bool editorHint,
|
||||||
PluginsCallbacks* pluginsCallbacks, ManagedCallbacks* managedCallbacks)
|
PluginsCallbacks* pluginsCallbacks, ManagedCallbacks* managedCallbacks)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport;
|
||||||
|
|
||||||
SharedAssemblies.Add(CoreApiAssembly.GetName());
|
SharedAssemblies.Add(CoreApiAssembly.GetName());
|
||||||
NativeLibrary.SetDllImportResolver(CoreApiAssembly, GodotDllImportResolver.OnResolveDllImport);
|
NativeLibrary.SetDllImportResolver(CoreApiAssembly, _dllImportResolver);
|
||||||
|
|
||||||
if (editorHint.ToBool())
|
if (editorHint.ToBool())
|
||||||
{
|
{
|
||||||
_editorApiAssembly = Assembly.Load("GodotSharpEditor");
|
_editorApiAssembly = Assembly.Load("GodotSharpEditor");
|
||||||
SharedAssemblies.Add(_editorApiAssembly.GetName());
|
SharedAssemblies.Add(_editorApiAssembly.GetName());
|
||||||
NativeLibrary.SetDllImportResolver(_editorApiAssembly, GodotDllImportResolver.OnResolveDllImport);
|
NativeLibrary.SetDllImportResolver(_editorApiAssembly, _dllImportResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
*pluginsCallbacks = new()
|
*pluginsCallbacks = new()
|
||||||
|
@ -97,7 +101,7 @@ namespace GodotPlugins
|
||||||
|
|
||||||
var assembly = LoadPlugin(assemblyPath);
|
var assembly = LoadPlugin(assemblyPath);
|
||||||
|
|
||||||
NativeLibrary.SetDllImportResolver(assembly, GodotDllImportResolver.OnResolveDllImport);
|
NativeLibrary.SetDllImportResolver(assembly, _dllImportResolver!);
|
||||||
|
|
||||||
var method = assembly.GetType("GodotTools.GodotSharpEditor")?
|
var method = assembly.GetType("GodotTools.GodotSharpEditor")?
|
||||||
.GetMethod("InternalCreateInstance",
|
.GetMethod("InternalCreateInstance",
|
||||||
|
|
|
@ -39,7 +39,12 @@ namespace Godot.Bridge
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Type nativeType = TypeGetProxyClass(nativeTypeName);
|
using var stringName = StringName.CreateTakingOwnershipOfDisposableValue(
|
||||||
|
NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(nativeTypeName)));
|
||||||
|
string nativeTypeNameStr = stringName.ToString();
|
||||||
|
|
||||||
|
Type nativeType = TypeGetProxyClass(nativeTypeNameStr) ?? throw new InvalidOperationException(
|
||||||
|
"Wrapper class not found for type: " + nativeTypeNameStr);
|
||||||
var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
|
var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
|
||||||
|
|
||||||
var ctor = nativeType.GetConstructor(
|
var ctor = nativeType.GetConstructor(
|
||||||
|
@ -171,12 +176,9 @@ namespace Godot.Bridge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe Type TypeGetProxyClass(godot_string_name* nativeTypeName)
|
private static Type TypeGetProxyClass(string nativeTypeNameStr)
|
||||||
{
|
{
|
||||||
// Performance is not critical here as this will be replaced with a generated dictionary.
|
// Performance is not critical here as this will be replaced with a generated dictionary.
|
||||||
using var stringName = StringName.CreateTakingOwnershipOfDisposableValue(
|
|
||||||
NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(nativeTypeName)));
|
|
||||||
string nativeTypeNameStr = stringName.ToString();
|
|
||||||
|
|
||||||
if (nativeTypeNameStr[0] == '_')
|
if (nativeTypeNameStr[0] == '_')
|
||||||
nativeTypeNameStr = nativeTypeNameStr.Substring(1);
|
nativeTypeNameStr = nativeTypeNameStr.Substring(1);
|
||||||
|
@ -186,7 +188,7 @@ namespace Godot.Bridge
|
||||||
if (wrapperType == null)
|
if (wrapperType == null)
|
||||||
{
|
{
|
||||||
wrapperType = AppDomain.CurrentDomain.GetAssemblies()
|
wrapperType = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
.First(a => a.GetName().Name == "GodotSharpEditor")
|
.FirstOrDefault(a => a.GetName().Name == "GodotSharpEditor")?
|
||||||
.GetType("Godot." + nativeTypeNameStr);
|
.GetType("Godot." + nativeTypeNameStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,16 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Godot.NativeInterop
|
namespace Godot.NativeInterop
|
||||||
{
|
{
|
||||||
public static class GodotDllImportResolver
|
public class GodotDllImportResolver
|
||||||
{
|
{
|
||||||
public static IntPtr OnResolveDllImport(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
private IntPtr _internalHandle;
|
||||||
|
|
||||||
|
public GodotDllImportResolver(IntPtr internalHandle)
|
||||||
|
{
|
||||||
|
_internalHandle = internalHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr OnResolveDllImport(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
||||||
{
|
{
|
||||||
if (libraryName == "__Internal")
|
if (libraryName == "__Internal")
|
||||||
{
|
{
|
||||||
|
@ -18,7 +25,7 @@ namespace Godot.NativeInterop
|
||||||
}
|
}
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
{
|
{
|
||||||
return Linux.dlopen(IntPtr.Zero, Linux.RTLD_LAZY);
|
return _internalHandle;
|
||||||
}
|
}
|
||||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||||
{
|
{
|
||||||
|
@ -40,18 +47,6 @@ namespace Godot.NativeInterop
|
||||||
public static extern IntPtr dlopen(IntPtr path, int mode);
|
public static extern IntPtr dlopen(IntPtr path, int mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Linux
|
|
||||||
{
|
|
||||||
// libdl.so was resulting in DllNotFoundException, for some reason...
|
|
||||||
// libcoreclr.so should work with both CoreCLR and the .NET Core version of Mono.
|
|
||||||
private const string SystemLibrary = "libcoreclr.so";
|
|
||||||
|
|
||||||
public const int RTLD_LAZY = 1;
|
|
||||||
|
|
||||||
[DllImport(SystemLibrary)]
|
|
||||||
public static extern IntPtr dlopen(IntPtr path, int mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Win32
|
private static class Win32
|
||||||
{
|
{
|
||||||
private const string SystemLibrary = "Kernel32.dll";
|
private const string SystemLibrary = "Kernel32.dll";
|
||||||
|
|
|
@ -48,6 +48,9 @@
|
||||||
|
|
||||||
#include <coreclr_delegates.h>
|
#include <coreclr_delegates.h>
|
||||||
#include <hostfxr.h>
|
#include <hostfxr.h>
|
||||||
|
#ifdef UNIX_ENABLED
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO mobile
|
// TODO mobile
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -168,18 +171,24 @@ String find_hostfxr() {
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#if defined(WINDOWS_ENABLED)
|
#if defined(WINDOWS_ENABLED)
|
||||||
return GodotSharpDirs::get_api_assemblies_dir()
|
String probe_path = GodotSharpDirs::get_api_assemblies_dir()
|
||||||
.plus_file("hostfxr.dll");
|
.plus_file("hostfxr.dll");
|
||||||
#elif defined(MACOS_ENABLED)
|
#elif defined(MACOS_ENABLED)
|
||||||
return GodotSharpDirs::get_api_assemblies_dir()
|
String probe_path = GodotSharpDirs::get_api_assemblies_dir()
|
||||||
.plus_file("libhostfxr.dylib");
|
.plus_file("libhostfxr.dylib");
|
||||||
#elif defined(UNIX_ENABLED)
|
#elif defined(UNIX_ENABLED)
|
||||||
return GodotSharpDirs::get_api_assemblies_dir()
|
String probe_path = GodotSharpDirs::get_api_assemblies_dir()
|
||||||
.plus_file("libhostfxr.so");
|
.plus_file("libhostfxr.so");
|
||||||
#else
|
#else
|
||||||
#error "Platform not supported (yet?)"
|
#error "Platform not supported (yet?)"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (FileAccess::exists(probe_path)) {
|
||||||
|
return probe_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,11 +294,21 @@ load_assembly_and_get_function_pointer_fn initialize_hostfxr_self_contained(
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
using godot_plugins_initialize_fn = bool (*)(bool, gdmono::PluginCallbacks *, GDMonoCache::ManagedCallbacks *);
|
using godot_plugins_initialize_fn = bool (*)(void *, bool, gdmono::PluginCallbacks *, GDMonoCache::ManagedCallbacks *);
|
||||||
#else
|
#else
|
||||||
using godot_plugins_initialize_fn = bool (*)(GDMonoCache::ManagedCallbacks *);
|
using godot_plugins_initialize_fn = bool (*)(void *, GDMonoCache::ManagedCallbacks *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static String get_assembly_name() {
|
||||||
|
String appname = ProjectSettings::get_singleton()->get("application/config/name");
|
||||||
|
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
|
||||||
|
if (appname_safe.is_empty()) {
|
||||||
|
appname_safe = "UnnamedProject";
|
||||||
|
}
|
||||||
|
|
||||||
|
return appname_safe;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
|
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
|
||||||
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
||||||
|
@ -320,15 +339,9 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
|
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
|
||||||
String appname = ProjectSettings::get_singleton()->get("application/config/name");
|
|
||||||
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
|
|
||||||
if (appname_safe.is_empty()) {
|
|
||||||
appname_safe = "UnnamedProject";
|
|
||||||
}
|
|
||||||
|
|
||||||
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
||||||
|
|
||||||
String assembly_name = appname_safe;
|
String assembly_name = get_assembly_name();
|
||||||
|
|
||||||
HostFxrCharString assembly_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir()
|
HostFxrCharString assembly_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir()
|
||||||
.plus_file(assembly_name + ".dll"));
|
.plus_file(assembly_name + ".dll"));
|
||||||
|
@ -351,6 +364,38 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
|
||||||
|
|
||||||
return godot_plugins_initialize;
|
return godot_plugins_initialize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle) {
|
||||||
|
String assembly_name = get_assembly_name();
|
||||||
|
|
||||||
|
#if defined(WINDOWS_ENABLED)
|
||||||
|
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".dll");
|
||||||
|
#elif defined(MACOS_ENABLED)
|
||||||
|
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".dylib");
|
||||||
|
#elif defined(UNIX_ENABLED)
|
||||||
|
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".so");
|
||||||
|
#else
|
||||||
|
#error "Platform not supported (yet?)"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (FileAccess::exists(native_aot_so_path)) {
|
||||||
|
Error err = OS::get_singleton()->open_dynamic_library(native_aot_so_path, r_aot_dll_handle);
|
||||||
|
|
||||||
|
if (err != OK) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *lib = r_aot_dll_handle;
|
||||||
|
|
||||||
|
void *symbol = nullptr;
|
||||||
|
|
||||||
|
err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "godotsharp_game_main_init", symbol);
|
||||||
|
ERR_FAIL_COND_V(err != OK, nullptr);
|
||||||
|
return (godot_plugins_initialize_fn)symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -377,25 +422,46 @@ void GDMono::initialize() {
|
||||||
|
|
||||||
_init_godot_api_hashes();
|
_init_godot_api_hashes();
|
||||||
|
|
||||||
|
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
||||||
|
|
||||||
if (!load_hostfxr(hostfxr_dll_handle)) {
|
if (!load_hostfxr(hostfxr_dll_handle)) {
|
||||||
|
#if !defined(TOOLS_ENABLED)
|
||||||
|
godot_plugins_initialize = try_load_native_aot_library(hostfxr_dll_handle);
|
||||||
|
|
||||||
|
if (godot_plugins_initialize != nullptr) {
|
||||||
|
is_native_aot = true;
|
||||||
|
} else {
|
||||||
|
ERR_FAIL_MSG(".NET: Failed to load hostfxr");
|
||||||
|
}
|
||||||
|
#else
|
||||||
ERR_FAIL_MSG(".NET: Failed to load hostfxr");
|
ERR_FAIL_MSG(".NET: Failed to load hostfxr");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
godot_plugins_initialize_fn godot_plugins_initialize =
|
if (!is_native_aot) {
|
||||||
initialize_hostfxr_and_godot_plugins(runtime_initialized);
|
godot_plugins_initialize = initialize_hostfxr_and_godot_plugins(runtime_initialized);
|
||||||
ERR_FAIL_NULL(godot_plugins_initialize);
|
ERR_FAIL_NULL(godot_plugins_initialize);
|
||||||
|
}
|
||||||
|
|
||||||
GDMonoCache::ManagedCallbacks managed_callbacks;
|
GDMonoCache::ManagedCallbacks managed_callbacks;
|
||||||
|
|
||||||
|
void *godot_dll_handle = nullptr;
|
||||||
|
|
||||||
|
#if defined(UNIX_ENABLED) && !defined(MACOS_ENABLED) && !defined(IOS_ENABLED)
|
||||||
|
// Managed code can access it on its own on other platforms
|
||||||
|
godot_dll_handle = dlopen(nullptr, RTLD_NOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
gdmono::PluginCallbacks plugin_callbacks_res;
|
gdmono::PluginCallbacks plugin_callbacks_res;
|
||||||
bool init_ok = godot_plugins_initialize(Engine::get_singleton()->is_editor_hint(),
|
bool init_ok = godot_plugins_initialize(godot_dll_handle,
|
||||||
|
Engine::get_singleton()->is_editor_hint(),
|
||||||
&plugin_callbacks_res, &managed_callbacks);
|
&plugin_callbacks_res, &managed_callbacks);
|
||||||
ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed");
|
ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed");
|
||||||
|
|
||||||
plugin_callbacks = plugin_callbacks_res;
|
plugin_callbacks = plugin_callbacks_res;
|
||||||
#else
|
#else
|
||||||
bool init_ok = godot_plugins_initialize(&managed_callbacks);
|
bool init_ok = godot_plugins_initialize(godot_dll_handle, &managed_callbacks);
|
||||||
ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed");
|
ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ class GDMono {
|
||||||
bool finalizing_scripts_domain;
|
bool finalizing_scripts_domain;
|
||||||
|
|
||||||
void *hostfxr_dll_handle = nullptr;
|
void *hostfxr_dll_handle = nullptr;
|
||||||
|
bool is_native_aot = false;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
bool _load_project_assembly();
|
bool _load_project_assembly();
|
||||||
|
|
Loading…
Reference in New Issue