From f9a67ee9da1d6cc3562fa5a7443a2a66a673bd8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etcheverry?= Date: Sun, 12 Sep 2021 20:23:05 +0200 Subject: C#: Begin move to .NET Core We're targeting .NET 5 for now to make development easier while .NET 6 is not yet released. TEMPORARY REGRESSIONS --------------------- Assembly unloading is not implemented yet. As such, many Godot resources are leaked at exit. This will be re-implemented later together with assembly hot-reloading. --- doc/classes/ProjectSettings.xml | 14 - main/main.cpp | 12 - methods.py | 17 +- modules/mono/build_scripts/build_assemblies.py | 6 + .../mono/build_scripts/make_android_mono_config.py | 55 -- modules/mono/build_scripts/mono_android_config.xml | 28 - modules/mono/build_scripts/mono_configure.py | 624 ++++------------- modules/mono/build_scripts/mono_reg_utils.py | 112 --- modules/mono/config.py | 30 +- modules/mono/csharp_script.cpp | 397 +++-------- modules/mono/csharp_script.h | 8 +- modules/mono/doc_classes/GodotSharp.xml | 47 +- .../mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln | 2 +- .../Godot.SourceGenerators.Sample.csproj | 2 +- .../GodotTools.BuildLogger/GodotBuildLogger.cs | 2 - .../GodotTools.BuildLogger.csproj | 2 +- .../GodotTools.Core/GodotTools.Core.csproj | 2 +- .../GodotTools.IdeMessaging.CLI.csproj | 2 +- .../GodotTools.OpenVisualStudio.csproj | 2 +- .../GodotTools.ProjectEditor.csproj | 24 +- .../GodotTools.ProjectEditor/MSBuild.exe | 0 .../GodotTools.ProjectEditor/ProjectGenerator.cs | 3 +- .../GodotTools.ProjectEditor/ProjectUtils.cs | 6 +- .../GodotTools.Shared/GodotTools.Shared.csproj | 2 +- modules/mono/editor/GodotTools/GodotTools.sln | 2 +- .../GodotTools/GodotTools/Build/BuildManager.cs | 4 +- .../GodotTools/GodotTools/Build/BuildOutputView.cs | 2 +- .../GodotTools/GodotTools/Build/BuildSystem.cs | 10 +- .../GodotTools/GodotTools/Build/MSBuildPanel.cs | 4 - .../GodotTools/GodotTools/Export/ExportPlugin.cs | 14 +- .../GodotTools/GodotTools/GodotSharpEditor.cs | 19 +- .../editor/GodotTools/GodotTools/GodotTools.csproj | 5 +- .../GodotTools/HotReloadAssemblyWatcher.cs | 2 + .../GodotTools/Ides/Rider/RiderPathLocator.cs | 12 +- .../GodotTools/Internals/EditorProgress.cs | 19 +- .../GodotTools/GodotTools/Internals/Globals.cs | 29 +- .../GodotTools/Internals/GodotSharpDirs.cs | 39 +- .../GodotTools/GodotTools/Internals/Internal.cs | 155 ++-- .../GodotTools/GodotTools/Utils/FsPathUtils.cs | 4 +- .../mono/editor/GodotTools/GodotTools/Utils/OS.cs | 23 +- modules/mono/editor/bindings_generator.cpp | 30 +- modules/mono/editor/editor_internal_calls.cpp | 175 +++-- modules/mono/editor/godotsharp_export.cpp | 144 ---- modules/mono/editor/godotsharp_export.h | 44 -- .../GodotSharp/GodotPlugins/GodotPlugins.csproj | 17 + modules/mono/glue/GodotSharp/GodotPlugins/Main.cs | 197 ++++++ .../GodotSharp/GodotPlugins/PluginLoadContext.cs | 61 ++ modules/mono/glue/GodotSharp/GodotSharp.sln | 6 + .../mono/glue/GodotSharp/GodotSharp/Core/Array.cs | 2 +- .../GodotSharp/Core/Bridge/CSharpInstanceBridge.cs | 205 +++--- .../GodotSharp/Core/Bridge/GCHandleBridge.cs | 15 +- .../GodotSharp/Core/Bridge/ManagedCallbacks.cs | 72 ++ .../GodotSharp/Core/Bridge/ScriptManagerBridge.cs | 653 ++++++++++------- .../GodotSharp/GodotSharp/Core/DebuggingUtils.cs | 20 +- .../GodotSharp/GodotSharp/Core/DelegateUtils.cs | 62 +- .../glue/GodotSharp/GodotSharp/Core/Dictionary.cs | 27 +- .../glue/GodotSharp/GodotSharp/Core/Dispatcher.cs | 16 +- .../Core/Extensions/SceneTreeExtensions.cs | 18 +- modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs | 4 +- .../Core/NativeInterop/ExceptionUtils.cs | 74 ++ .../Core/NativeInterop/InteropStructs.cs | 34 +- .../GodotSharp/Core/NativeInterop/InteropUtils.cs | 51 +- .../GodotSharp/Core/NativeInterop/Marshaling.cs | 72 +- .../GodotSharp/Core/NativeInterop/NativeFuncs.cs | 63 +- .../GodotSharp/Core/NativeInterop/VariantUtils.cs | 134 ++-- .../glue/GodotSharp/GodotSharp/Core/NodePath.cs | 2 +- .../glue/GodotSharp/GodotSharp/Core/Object.base.cs | 39 +- .../GodotSharp/GodotSharp/Core/SignalAwaiter.cs | 47 +- .../glue/GodotSharp/GodotSharp/GodotSharp.csproj | 4 +- .../GodotSharp/Properties/AssemblyInfo.cs | 1 + .../GodotSharpEditor/GodotSharpEditor.csproj | 2 +- modules/mono/glue/base_object_glue.cpp | 137 ---- modules/mono/glue/placeholder_glue.cpp | 201 ------ modules/mono/glue/runtime_interop.cpp | 245 ++++++- modules/mono/managed_callable.cpp | 29 +- modules/mono/managed_callable.h | 2 - modules/mono/mono_gc_handle.cpp | 10 +- modules/mono/mono_gc_handle.h | 6 +- modules/mono/mono_gd/gd_mono.cpp | 779 ++++----------------- modules/mono/mono_gd/gd_mono.h | 163 +---- modules/mono/mono_gd/gd_mono_assembly.cpp | 388 ---------- modules/mono/mono_gd/gd_mono_assembly.h | 97 --- modules/mono/mono_gd/gd_mono_cache.cpp | 113 ++- modules/mono/mono_gd/gd_mono_cache.h | 112 +-- modules/mono/mono_gd/gd_mono_internals.cpp | 71 -- modules/mono/mono_gd/gd_mono_internals.h | 52 -- modules/mono/mono_gd/gd_mono_log.cpp | 209 ------ modules/mono/mono_gd/gd_mono_log.h | 71 -- modules/mono/mono_gd/gd_mono_method_thunk.h | 126 ---- modules/mono/mono_gd/gd_mono_utils.cpp | 253 ------- modules/mono/mono_gd/gd_mono_utils.h | 144 ---- modules/mono/mono_gd/gd_mono_wasm_m2n.cpp | 79 --- modules/mono/mono_gd/gd_mono_wasm_m2n.h | 263 ------- modules/mono/signal_awaiter_utils.cpp | 19 +- modules/mono/utils/mono_reg_utils.cpp | 242 ------- modules/mono/utils/mono_reg_utils.h | 54 -- 96 files changed, 2379 insertions(+), 5519 deletions(-) delete mode 100644 modules/mono/build_scripts/make_android_mono_config.py delete mode 100644 modules/mono/build_scripts/mono_android_config.xml delete mode 100644 modules/mono/build_scripts/mono_reg_utils.py delete mode 100644 modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe delete mode 100644 modules/mono/editor/godotsharp_export.cpp delete mode 100644 modules/mono/editor/godotsharp_export.h create mode 100644 modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj create mode 100644 modules/mono/glue/GodotSharp/GodotPlugins/Main.cs create mode 100644 modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs create mode 100644 modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs create mode 100644 modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs delete mode 100644 modules/mono/glue/base_object_glue.cpp delete mode 100644 modules/mono/glue/placeholder_glue.cpp delete mode 100644 modules/mono/mono_gd/gd_mono_assembly.cpp delete mode 100644 modules/mono/mono_gd/gd_mono_assembly.h delete mode 100644 modules/mono/mono_gd/gd_mono_internals.cpp delete mode 100644 modules/mono/mono_gd/gd_mono_internals.h delete mode 100644 modules/mono/mono_gd/gd_mono_log.cpp delete mode 100644 modules/mono/mono_gd/gd_mono_log.h delete mode 100644 modules/mono/mono_gd/gd_mono_method_thunk.h delete mode 100644 modules/mono/mono_gd/gd_mono_utils.cpp delete mode 100644 modules/mono/mono_gd/gd_mono_utils.h delete mode 100644 modules/mono/mono_gd/gd_mono_wasm_m2n.cpp delete mode 100644 modules/mono/mono_gd/gd_mono_wasm_m2n.h delete mode 100644 modules/mono/utils/mono_reg_utils.cpp delete mode 100644 modules/mono/utils/mono_reg_utils.h diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index f72aeff469..9e2c3440c7 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1433,20 +1433,6 @@ This is used by servers when used in multi-threading mode (servers and visual). RIDs are preallocated to avoid stalling the server requesting them on threads. If servers get stalled too often when loading resources in a thread, increase this number. - - - - - - - - - - - - The policy to use for unhandled Mono (C#) exceptions. The default "Terminate Application" exits the project as soon as an unhandled exception is thrown. "Log Error" logs an error message to the console instead, and will not interrupt the project execution when an unhandled exception is thrown. - [b]Note:[/b] The unhandled exception policy is always set to "Log Error" in the editor, which also includes C# [code]tool[/code] scripts running within the editor as well as editor plugin code. - Default cell size for 2D navigation maps. See [method NavigationServer2D.map_set_cell_size]. diff --git a/main/main.cpp b/main/main.cpp index 6559b69f2e..740e3cc69d 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2255,18 +2255,6 @@ bool Main::start() { ERR_FAIL_COND_V_MSG(da.is_null(), false, "Argument supplied to --doctool must be a valid directory path."); } -#ifndef MODULE_MONO_ENABLED - // Hack to define Mono-specific project settings even on non-Mono builds, - // so that we don't lose their descriptions and default values in DocData. - // Default values should be synced with mono_gd/gd_mono.cpp. - GLOBAL_DEF("mono/debugger_agent/port", 23685); - GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false); - GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000); - GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd"); - GLOBAL_DEF("mono/profiler/enabled", false); - GLOBAL_DEF("mono/runtime/unhandled_exception_policy", 0); -#endif - Error err; DocTools doc; doc.generate(doc_base); diff --git a/methods.py b/methods.py index ba7474ea02..c02517d137 100644 --- a/methods.py +++ b/methods.py @@ -818,18 +818,21 @@ def generate_vs_project(env, num_jobs): module_configs = ModuleConfigs() if env.get("module_mono_enabled"): - import modules.mono.build_scripts.mono_reg_utils as mono_reg + import modules.mono.build_scripts.mono_configure as mono_configure - mono_root = env.get("mono_prefix") or mono_reg.find_mono_root_dir(env["bits"]) - if mono_root: + app_host_dir = mono_configure.find_dotnet_app_host_dir(env) + if app_host_dir and os.path.isdir(app_host_dir): + mono_defines = [("NETHOST_USE_AS_STATIC",)] + if env["tools"]: + mono_defines += [("GD_MONO_HOT_RELOAD",)] module_configs.add_mode( "mono", - includes=os.path.join(mono_root, "include", "mono-2.0"), - cli_args="module_mono_enabled=yes mono_glue=yes", - defines=[("MONO_GLUE_ENABLED",)], + includes=app_host_dir, + cli_args="module_mono_enabled=yes", + defines=mono_defines, ) else: - print("Mono installation directory not found. Generated project will not have build variants for Mono.") + print(".NET App Host directory not found. Generated project will not have build variants for .NET.") env["MSVSBUILDCOM"] = module_configs.build_commandline("scons") env["MSVSREBUILDCOM"] = module_configs.build_commandline("scons vsproj=yes") diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py index dd96f40f6b..67c2f7f70e 100755 --- a/modules/mono/build_scripts/build_assemblies.py +++ b/modules/mono/build_scripts/build_assemblies.py @@ -203,6 +203,9 @@ def build_godot_api(msbuild_tool, module_dir, output_dir): "GodotSharpEditor.dll", "GodotSharpEditor.pdb", "GodotSharpEditor.xml", + "GodotPlugins.dll", + "GodotPlugins.pdb", + "GodotPlugins.runtimeconfig.json", ] for build_config in ["Debug", "Release"]: @@ -223,6 +226,7 @@ def build_godot_api(msbuild_tool, module_dir, output_dir): core_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotSharp", "bin", build_config)) editor_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotSharpEditor", "bin", build_config)) + plugins_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotPlugins", "bin", build_config, "net5.0")) if not os.path.isdir(editor_api_dir): assert not os.path.isfile(editor_api_dir) @@ -236,6 +240,8 @@ def build_godot_api(msbuild_tool, module_dir, output_dir): src_path = os.path.join(core_src_dir, filename) if not os.path.isfile(src_path): src_path = os.path.join(editor_src_dir, filename) + if not os.path.isfile(src_path): + src_path = os.path.join(plugins_src_dir, filename) print(f"Copying assembly to {target_path}...") copy(src_path, target_path) diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py deleted file mode 100644 index 3459244bc2..0000000000 --- a/modules/mono/build_scripts/make_android_mono_config.py +++ /dev/null @@ -1,55 +0,0 @@ -def generate_compressed_config(config_src, output_dir): - import os.path - - # Source file - with open(os.path.join(output_dir, "android_mono_config.gen.cpp"), "w") as cpp: - with open(config_src, "rb") as f: - buf = f.read() - decompr_size = len(buf) - import zlib - - # Use maximum zlib compression level to further reduce file size - # (at the cost of initial build times). - buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION) - compr_size = len(buf) - - bytes_seq_str = "" - for i, buf_idx in enumerate(range(compr_size)): - if i > 0: - bytes_seq_str += ", " - bytes_seq_str += str(buf[buf_idx]) - - cpp.write( - """/* THIS FILE IS GENERATED DO NOT EDIT */ -#include "android_mono_config.h" - -#ifdef ANDROID_ENABLED - -#include "core/io/compression.h" - - -namespace { - -// config -static const int config_compressed_size = %d; -static const int config_uncompressed_size = %d; -static const unsigned char config_compressed_data[] = { %s }; -} // namespace - -String get_godot_android_mono_config() { - Vector data; - data.resize(config_uncompressed_size); - uint8_t* w = data.ptrw(); - Compression::decompress(w, config_uncompressed_size, config_compressed_data, - config_compressed_size, Compression::MODE_DEFLATE); - String s; - if (s.parse_utf8((const char *)w, data.size()) != OK) { - ERR_FAIL_V(String()); - } - return s; -} - -#endif // ANDROID_ENABLED -""" - % (compr_size, decompr_size, bytes_seq_str) - ) diff --git a/modules/mono/build_scripts/mono_android_config.xml b/modules/mono/build_scripts/mono_android_config.xml deleted file mode 100644 index e79670afd2..0000000000 --- a/modules/mono/build_scripts/mono_android_config.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index e69904c54b..071693d758 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -1,65 +1,5 @@ import os import os.path -import subprocess - -from SCons.Script import Dir, Environment - -if os.name == "nt": - from . import mono_reg_utils as monoreg - - -android_arch_dirs = { - "armv7": "armeabi-v7a", - "arm64v8": "arm64-v8a", - "x86": "x86", - "x86_64": "x86_64", -} - - -def get_android_out_dir(env): - return os.path.join( - Dir("#platform/android/java/lib/libs").abspath, - "release" if env["target"] == "release" else "debug", - android_arch_dirs[env["android_arch"]], - ) - - -def find_name_in_dir_files(directory, names, prefixes=[""], extensions=[""]): - for extension in extensions: - if extension and not extension.startswith("."): - extension = "." + extension - for prefix in prefixes: - for curname in names: - if os.path.isfile(os.path.join(directory, prefix + curname + extension)): - return curname - return "" - - -def find_file_in_dir(directory, names, prefixes=[""], extensions=[""]): - for extension in extensions: - if extension and not extension.startswith("."): - extension = "." + extension - for prefix in prefixes: - for curname in names: - filename = prefix + curname + extension - if os.path.isfile(os.path.join(directory, filename)): - return filename - return "" - - -def copy_file(src_dir, dst_dir, src_name, dst_name=""): - from shutil import copy - - src_path = os.path.join(Dir(src_dir).abspath, src_name) - dst_dir = Dir(dst_dir).abspath - - if not os.path.isdir(dst_dir): - os.makedirs(dst_dir) - - if dst_name: - copy(src_path, os.path.join(dst_dir, dst_name)) - else: - copy(src_path, dst_dir) def is_desktop(platform): @@ -71,504 +11,176 @@ def is_unix_like(platform): def module_supports_tools_on(platform): - return platform not in ["android", "javascript", "ios"] - - -def find_wasm_src_dir(mono_root): - hint_dirs = [ - os.path.join(mono_root, "src"), - os.path.join(mono_root, "../src"), - ] - for hint_dir in hint_dirs: - if os.path.isfile(os.path.join(hint_dir, "driver.c")): - return hint_dir - return "" + return is_desktop(platform) def configure(env, env_mono): - bits = env["bits"] - is_android = env["platform"] == "android" - is_javascript = env["platform"] == "javascript" - is_ios = env["platform"] == "ios" - is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"] + # is_android = env["platform"] == "android" + # is_javascript = env["platform"] == "javascript" + # is_ios = env["platform"] == "ios" + # is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"] tools_enabled = env["tools"] - mono_static = env["mono_static"] - copy_mono_root = env["copy_mono_root"] - - mono_prefix = env["mono_prefix"] - mono_bcl = env["mono_bcl"] - - mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"] - - if is_android and not env["android_arch"] in android_arch_dirs: - raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"]) if tools_enabled and not module_supports_tools_on(env["platform"]): - # TODO: - # Android: We have to add the data directory to the apk, concretely the Api and Tools folders. raise RuntimeError("This module does not currently support building for this platform with tools enabled") - if is_android and mono_static: - # FIXME: When static linking and doing something that requires libmono-native, we get a dlopen error as 'libmono-native' - # seems to depend on 'libmonosgen-2.0'. Could be fixed by re-directing to '__Internal' with a dllmap or in the dlopen hook. - raise RuntimeError("Statically linking Mono is not currently supported for this platform") - - if not mono_static and (is_javascript or is_ios): - raise RuntimeError("Dynamically linking Mono is not currently supported for this platform") - - if not mono_prefix and (os.getenv("MONO32_PREFIX") or os.getenv("MONO64_PREFIX")): - print( - "WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the" - " 'mono_prefix' SCons parameter instead" - ) - - # Although we don't support building with tools for any platform where we currently use static AOT, - # if these are supported in the future, we won't be using static AOT for them as that would be - # too restrictive for the editor. These builds would probably be made to only use the interpreter. - mono_aot_static = (is_ios and not is_ios_sim) and not env["tools"] - - # Static AOT is only supported on the root domain - mono_single_appdomain = mono_aot_static - - if mono_single_appdomain: - env_mono.Append(CPPDEFINES=["GD_MONO_SINGLE_APPDOMAIN"]) - - if (env["tools"] or env["target"] != "release") and not mono_single_appdomain: + if env["tools"] or env["target"] != "release": env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"]) - if env["platform"] == "windows": - mono_root = mono_prefix - - if not mono_root and os.name == "nt": - mono_root = monoreg.find_mono_root_dir(bits) - - if not mono_root: - raise RuntimeError( - "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter" - ) - - print("Found Mono root directory: " + mono_root) - - mono_lib_path = os.path.join(mono_root, "lib") - - env.Append(LIBPATH=mono_lib_path) - env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0")) + app_host_dir = find_dotnet_app_host_dir(env) - lib_suffixes = [".lib"] + def check_app_host_file_exists(file): + file_path = os.path.join(app_host_dir, file) + if not os.path.isfile(file_path): + raise RuntimeError("File not found: " + file_path) - if not env.msvc: - # MingW supports both '.a' and '.lib' - lib_suffixes.insert(0, ".a") + # TODO: + # All libnethost does for us is provide a function to find hostfxr. + # If we could handle that logic ourselves we could void linking it. - if mono_static: - if env.msvc: - mono_static_lib_name = "libmono-static-sgen" - else: - mono_static_lib_name = "libmonosgen-2.0" + # nethost file names: + # static: libnethost.a/lib + # shared: libnethost.a/dylib and nethost.dll + check_app_host_file_exists("libnethost.lib" if os.name == "nt" else "libnethost.a") + check_app_host_file_exists("nethost.h") + check_app_host_file_exists("hostfxr.h") + check_app_host_file_exists("coreclr_delegates.h") - mono_static_lib_file = find_file_in_dir(mono_lib_path, [mono_static_lib_name], extensions=lib_suffixes) + env.Append(LIBPATH=[app_host_dir]) + env_mono.Prepend(CPPPATH=app_host_dir) - if not mono_static_lib_file: - raise RuntimeError("Could not find static mono library in: " + mono_lib_path) + libnethost_path = os.path.join(app_host_dir, "libnethost.lib" if os.name == "nt" else "libnethost.a") - if env.msvc: - env.Append(LINKFLAGS=mono_static_lib_file) - - env.Append(LINKFLAGS="Mincore.lib") - env.Append(LINKFLAGS="msvcrt.lib") - env.Append(LINKFLAGS="LIBCMT.lib") - env.Append(LINKFLAGS="Psapi.lib") - else: - mono_static_lib_file_path = os.path.join(mono_lib_path, mono_static_lib_file) - env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_static_lib_file_path, "-Wl,-no-whole-archive"]) + if env["platform"] == "windows": + env_mono.Append(CPPDEFINES=["NETHOST_USE_AS_STATIC"]) - env.Append(LIBS=["psapi"]) - env.Append(LIBS=["version"]) + if env.msvc: + env.Append(LINKFLAGS="libnethost.lib") else: - mono_lib_file = find_file_in_dir(mono_lib_path, mono_lib_names, extensions=lib_suffixes) - - if not mono_lib_file: - raise RuntimeError("Could not find mono library in: " + mono_lib_path) - - if env.msvc: - env.Append(LINKFLAGS=mono_lib_file) - else: - mono_lib_file_path = os.path.join(mono_lib_path, mono_lib_file) - env.Append(LINKFLAGS=mono_lib_file_path) - - mono_bin_path = os.path.join(mono_root, "bin") - - mono_dll_file = find_file_in_dir(mono_bin_path, mono_lib_names, prefixes=["", "lib"], extensions=[".dll"]) - - if not mono_dll_file: - raise RuntimeError("Could not find mono shared library in: " + mono_bin_path) - - copy_file(mono_bin_path, "#bin", mono_dll_file) + env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"]) else: is_apple = env["platform"] in ["macos", "ios"] - is_macos = is_apple and not is_ios - - sharedlib_ext = ".dylib" if is_apple else ".so" - - mono_root = mono_prefix - mono_lib_path = "" - mono_so_file = "" - - if not mono_root and (is_android or is_javascript or is_ios): - raise RuntimeError( - "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter" - ) - - if not mono_root and is_macos: - # Try with some known directories under macOS - hint_dirs = ["/Library/Frameworks/Mono.framework/Versions/Current", "/usr/local/var/homebrew/linked/mono"] - for hint_dir in hint_dirs: - if os.path.isdir(hint_dir): - mono_root = hint_dir - break - - # We can't use pkg-config to link mono statically, - # but we can still use it to find the mono root directory - if not mono_root and mono_static: - mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext) - if not mono_root: - raise RuntimeError( - "Building with mono_static=yes, but failed to find the mono prefix with pkg-config; " - + "specify one manually with the 'mono_prefix' SCons parameter" - ) - - if is_ios and not is_ios_sim: - env_mono.Append(CPPDEFINES=["IOS_DEVICE"]) - - if mono_root: - print("Found Mono root directory: " + mono_root) - - mono_lib_path = os.path.join(mono_root, "lib") - - env.Append(LIBPATH=[mono_lib_path]) - env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0")) - - mono_lib = find_name_in_dir_files(mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[".a"]) - - if not mono_lib: - raise RuntimeError("Could not find mono library in: " + mono_lib_path) - - env_mono.Append(CPPDEFINES=["_REENTRANT"]) - - if mono_static: - if not is_javascript: - env.Append(LINKFLAGS=["-rdynamic"]) - - mono_lib_file = os.path.join(mono_lib_path, "lib" + mono_lib + ".a") - - if is_apple: - if is_macos: - env.Append(LINKFLAGS=["-Wl,-force_load," + mono_lib_file]) - else: - arch = env["arch"] - - def copy_mono_lib(libname_wo_ext): - copy_file( - mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.ios.%s.a" % (libname_wo_ext, arch) - ) - - # Copy Mono libraries to the output folder. These are meant to be bundled with - # the export templates and added to the Xcode project when exporting a game. - copy_mono_lib("lib" + mono_lib) - copy_mono_lib("libmono-native") - copy_mono_lib("libmono-profiler-log") - - if not is_ios_sim: - copy_mono_lib("libmono-ee-interp") - copy_mono_lib("libmono-icall-table") - copy_mono_lib("libmono-ilgen") - else: - assert is_desktop(env["platform"]) or is_android or is_javascript - env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_lib_file, "-Wl,-no-whole-archive"]) - - if is_javascript: - env.Append(LIBS=["mono-icall-table", "mono-native", "mono-ilgen", "mono-ee-interp"]) - - wasm_src_dir = os.path.join(mono_root, "src") - if not os.path.isdir(wasm_src_dir): - raise RuntimeError("Could not find mono wasm src directory") - - # Ideally this should be defined only for 'driver.c', but I can't fight scons for another 2 hours - env_mono.Append(CPPDEFINES=["CORE_BINDINGS"]) - - env_mono.add_source_files( - env.modules_sources, - [ - os.path.join(wasm_src_dir, "driver.c"), - os.path.join(wasm_src_dir, "zlib-helper.c"), - os.path.join(wasm_src_dir, "corebindings.c"), - ], - ) - - env.Append( - LINKFLAGS=[ - "--js-library", - os.path.join(wasm_src_dir, "library_mono.js"), - "--js-library", - os.path.join(wasm_src_dir, "binding_support.js"), - "--js-library", - os.path.join(wasm_src_dir, "dotnet_support.js"), - ] - ) - else: - env.Append(LIBS=[mono_lib]) - - if is_macos: - env.Append(LIBS=["iconv", "pthread"]) - elif is_android: - pass # Nothing - elif is_ios: - pass # Nothing, linking is delegated to the exported Xcode project - elif is_javascript: - env.Append(LIBS=["m", "rt", "dl", "pthread"]) - else: - env.Append(LIBS=["m", "rt", "dl", "pthread"]) - - if not mono_static: - mono_so_file = find_file_in_dir( - mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext] - ) - - if not mono_so_file: - raise RuntimeError("Could not find mono shared library in: " + mono_lib_path) - else: - assert not mono_static + # is_macos = is_apple and not is_ios - # TODO: Add option to force using pkg-config - print("Mono root directory not found. Using pkg-config instead") + # if is_ios and not is_ios_sim: + # env_mono.Append(CPPDEFINES=["IOS_DEVICE"]) - env.ParseConfig("pkg-config monosgen-2 --libs") - env_mono.ParseConfig("pkg-config monosgen-2 --cflags") + if is_apple: + env.Append(LINKFLAGS=["-Wl,-force_load," + libnethost_path]) + else: + env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"]) - tmpenv = Environment() - tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH")) - tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L") - for hint_dir in tmpenv["LIBPATH"]: - file_found = find_file_in_dir(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext]) - if file_found: - mono_lib_path = hint_dir - mono_so_file = file_found - break +def find_dotnet_app_host_dir(env): + dotnet_root = env["dotnet_root"] - if not mono_so_file: - raise RuntimeError("Could not find mono shared library in: " + str(tmpenv["LIBPATH"])) + if not dotnet_root: + dotnet_exe = find_executable("dotnet") + if dotnet_exe: + dotnet_exe_realpath = os.path.realpath(dotnet_exe) # Eliminate symbolic links + dotnet_root = os.path.abspath(os.path.join(dotnet_exe_realpath, os.pardir)) + else: + raise RuntimeError("Cannot find .NET Core Sdk") - if not mono_static: - libs_output_dir = get_android_out_dir(env) if is_android else "#bin" - copy_file(mono_lib_path, libs_output_dir, mono_so_file) + print("Found .NET Core Sdk root directory: " + dotnet_root) - if not tools_enabled: - if is_desktop(env["platform"]): - if not mono_root: - mono_root = ( - subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip() - ) + dotnet_cmd = os.path.join(dotnet_root, "dotnet.exe" if os.name == "nt" else "dotnet") - make_template_dir(env, mono_root) - elif is_android: - # Compress Android Mono Config - from . import make_android_mono_config + runtime_identifier = determine_runtime_identifier(env) - module_dir = os.getcwd() - config_file_path = os.path.join(module_dir, "build_scripts", "mono_android_config.xml") - make_android_mono_config.generate_compressed_config(config_file_path, "mono_gd/") + # TODO: In the future, if it can't be found this way, we want to obtain it + # from the runtime.{runtime_identifier}.Microsoft.NETCore.DotNetAppHost NuGet package. + app_host_search_version = "5.0" + app_host_version = find_app_host_version(dotnet_cmd, app_host_search_version) + if not app_host_version: + raise RuntimeError("Cannot find .NET app host for version: " + app_host_search_version) - # Copy the required shared libraries - copy_mono_shared_libs(env, mono_root, None) - elif is_javascript: - pass # No data directory for this platform - elif is_ios: - pass # No data directory for this platform + app_host_dir = os.path.join( + dotnet_root, + "packs", + "Microsoft.NETCore.App.Host." + runtime_identifier, + app_host_version, + "runtimes", + runtime_identifier, + "native", + ) - if copy_mono_root: - if not mono_root: - mono_root = subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip() + return app_host_dir - if tools_enabled: - # Only supported for editor builds. - copy_mono_root_files(env, mono_root, mono_bcl) +def determine_runtime_identifier(env): + names_map = { + "windows": "win", + "macos": "osx", + "linuxbsd": "linux", + "server": "linux", # FIXME: Is server linux only, or also macos? + } -def make_template_dir(env, mono_root): - from shutil import rmtree + # .NET RID architectures: x86, x64, arm, or arm64 platform = env["platform"] - target = env["target"] - - template_dir_name = "" - - assert is_desktop(platform) - - template_dir_name = "data.mono.%s.%s.%s" % (platform, env["bits"], target) - - output_dir = Dir("#bin").abspath - template_dir = os.path.join(output_dir, template_dir_name) - - template_mono_root_dir = os.path.join(template_dir, "Mono") - - if os.path.isdir(template_mono_root_dir): - rmtree(template_mono_root_dir) # Clean first - # Copy etc/mono/ - - template_mono_config_dir = os.path.join(template_mono_root_dir, "etc", "mono") - copy_mono_etc_dir(mono_root, template_mono_config_dir, platform) - - # Copy the required shared libraries - - copy_mono_shared_libs(env, mono_root, template_mono_root_dir) - - -def copy_mono_root_files(env, mono_root, mono_bcl): - from glob import glob - from shutil import copy - from shutil import rmtree - - if not mono_root: - raise RuntimeError("Mono installation directory not found") - - output_dir = Dir("#bin").abspath - editor_mono_root_dir = os.path.join(output_dir, "GodotSharp", "Mono") - - if os.path.isdir(editor_mono_root_dir): - rmtree(editor_mono_root_dir) # Clean first - - # Copy etc/mono/ - - editor_mono_config_dir = os.path.join(editor_mono_root_dir, "etc", "mono") - copy_mono_etc_dir(mono_root, editor_mono_config_dir, env["platform"]) - - # Copy the required shared libraries - - copy_mono_shared_libs(env, mono_root, editor_mono_root_dir) + if is_desktop(platform): + if env["arch"] in ["arm", "arm32"]: + rid = "arm" + elif env["arch"] == "arm64": + rid = "arm64" + else: + bits = env["bits"] + bit_arch_map = {"64": "x64", "32": "x86"} + rid = bit_arch_map[bits] + return "%s-%s" % (names_map[platform], rid) + else: + raise NotImplementedError() - # Copy framework assemblies - mono_framework_dir = mono_bcl or os.path.join(mono_root, "lib", "mono", "4.5") - mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades") +def find_app_host_version(dotnet_cmd, search_version): + import subprocess - editor_mono_framework_dir = os.path.join(editor_mono_root_dir, "lib", "mono", "4.5") - editor_mono_framework_facades_dir = os.path.join(editor_mono_framework_dir, "Facades") + try: + lines = subprocess.check_output([dotnet_cmd, "--list-runtimes"]).splitlines() - if not os.path.isdir(editor_mono_framework_dir): - os.makedirs(editor_mono_framework_dir) - if not os.path.isdir(editor_mono_framework_facades_dir): - os.makedirs(editor_mono_framework_facades_dir) + for line_bytes in lines: + line = line_bytes.decode("utf-8") + if not line.startswith("Microsoft.NETCore.App "): + continue - for assembly in glob(os.path.join(mono_framework_dir, "*.dll")): - copy(assembly, editor_mono_framework_dir) - for assembly in glob(os.path.join(mono_framework_facades_dir, "*.dll")): - copy(assembly, editor_mono_framework_facades_dir) + parts = line.split(" ") + if len(parts) < 2: + continue + version = parts[1] -def copy_mono_etc_dir(mono_root, target_mono_config_dir, platform): - from distutils.dir_util import copy_tree - from glob import glob - from shutil import copy + # Look for 6.0.0 or 6.0.0-* + if version.startswith(search_version + "."): + return version + except (subprocess.CalledProcessError, OSError): + pass + return "" - if not os.path.isdir(target_mono_config_dir): - os.makedirs(target_mono_config_dir) - mono_etc_dir = os.path.join(mono_root, "etc", "mono") - if not os.path.isdir(mono_etc_dir): - mono_etc_dir = "" - etc_hint_dirs = [] - if platform != "windows": - etc_hint_dirs += ["/etc/mono", "/usr/local/etc/mono"] - if "MONO_CFG_DIR" in os.environ: - etc_hint_dirs += [os.path.join(os.environ["MONO_CFG_DIR"], "mono")] - for etc_hint_dir in etc_hint_dirs: - if os.path.isdir(etc_hint_dir): - mono_etc_dir = etc_hint_dir - break - if not mono_etc_dir: - raise RuntimeError("Mono installation etc directory not found") +ENV_PATH_SEP = ";" if os.name == "nt" else ":" - copy_tree(os.path.join(mono_etc_dir, "2.0"), os.path.join(target_mono_config_dir, "2.0")) - copy_tree(os.path.join(mono_etc_dir, "4.0"), os.path.join(target_mono_config_dir, "4.0")) - copy_tree(os.path.join(mono_etc_dir, "4.5"), os.path.join(target_mono_config_dir, "4.5")) - if os.path.isdir(os.path.join(mono_etc_dir, "mconfig")): - copy_tree(os.path.join(mono_etc_dir, "mconfig"), os.path.join(target_mono_config_dir, "mconfig")) - for file in glob(os.path.join(mono_etc_dir, "*")): - if os.path.isfile(file): - copy(file, target_mono_config_dir) +def find_executable(name): + is_windows = os.name == "nt" + windows_exts = os.environ["PATHEXT"].split(ENV_PATH_SEP) if is_windows else None + path_dirs = os.environ["PATH"].split(ENV_PATH_SEP) + search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list -def copy_mono_shared_libs(env, mono_root, target_mono_root_dir): - from shutil import copy + for dir in search_dirs: + path = os.path.join(dir, name) - def copy_if_exists(src, dst): - if os.path.isfile(src): - copy(src, dst) + if is_windows: + for extension in windows_exts: + path_with_ext = path + extension - platform = env["platform"] + if os.path.isfile(path_with_ext) and os.access(path_with_ext, os.X_OK): + return path_with_ext + else: + if os.path.isfile(path) and os.access(path, os.X_OK): + return path - if platform == "windows": - src_mono_bin_dir = os.path.join(mono_root, "bin") - target_mono_bin_dir = os.path.join(target_mono_root_dir, "bin") - - if not os.path.isdir(target_mono_bin_dir): - os.makedirs(target_mono_bin_dir) - - mono_posix_helper_file = find_file_in_dir( - src_mono_bin_dir, ["MonoPosixHelper"], prefixes=["", "lib"], extensions=[".dll"] - ) - copy( - os.path.join(src_mono_bin_dir, mono_posix_helper_file), - os.path.join(target_mono_bin_dir, "MonoPosixHelper.dll"), - ) - - # For newer versions - btls_dll_path = os.path.join(src_mono_bin_dir, "libmono-btls-shared.dll") - if os.path.isfile(btls_dll_path): - copy(btls_dll_path, target_mono_bin_dir) - else: - target_mono_lib_dir = ( - get_android_out_dir(env) if platform == "android" else os.path.join(target_mono_root_dir, "lib") - ) - - if not os.path.isdir(target_mono_lib_dir): - os.makedirs(target_mono_lib_dir) - - lib_file_names = [] - if platform == "macos": - lib_file_names = [ - lib_name + ".dylib" - for lib_name in ["libmono-btls-shared", "libmono-native-compat", "libMonoPosixHelper"] - ] - elif is_unix_like(platform): - lib_file_names = [ - lib_name + ".so" - for lib_name in [ - "libmono-btls-shared", - "libmono-ee-interp", - "libmono-native", - "libMonoPosixHelper", - "libmono-profiler-aot", - "libmono-profiler-coverage", - "libmono-profiler-log", - "libMonoSupportW", - ] - ] - - for lib_file_name in lib_file_names: - copy_if_exists(os.path.join(mono_root, "lib", lib_file_name), target_mono_lib_dir) - - -def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext): - tmpenv = Environment() - tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH")) - tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L") - for hint_dir in tmpenv["LIBPATH"]: - name_found = find_name_in_dir_files(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext]) - if name_found and os.path.isdir(os.path.join(hint_dir, "..", "include", "mono-2.0")): - return os.path.join(hint_dir, "..") return "" diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py deleted file mode 100644 index 43c1ec8f8a..0000000000 --- a/modules/mono/build_scripts/mono_reg_utils.py +++ /dev/null @@ -1,112 +0,0 @@ -import os -import platform - -if os.name == "nt": - import winreg - - -def _reg_open_key(key, subkey): - try: - return winreg.OpenKey(key, subkey) - except OSError: - if platform.architecture()[0] == "32bit": - bitness_sam = winreg.KEY_WOW64_64KEY - else: - bitness_sam = winreg.KEY_WOW64_32KEY - return winreg.OpenKey(key, subkey, 0, winreg.KEY_READ | bitness_sam) - - -def _reg_open_key_bits(key, subkey, bits): - sam = winreg.KEY_READ - - if platform.architecture()[0] == "32bit": - if bits == "64": - # Force 32bit process to search in 64bit registry - sam |= winreg.KEY_WOW64_64KEY - else: - if bits == "32": - # Force 64bit process to search in 32bit registry - sam |= winreg.KEY_WOW64_32KEY - - return winreg.OpenKey(key, subkey, 0, sam) - - -def _find_mono_in_reg(subkey, bits): - try: - with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey: - value = winreg.QueryValueEx(hKey, "SdkInstallRoot")[0] - return value - except OSError: - return None - - -def _find_mono_in_reg_old(subkey, bits): - try: - with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey: - default_clr = winreg.QueryValueEx(hKey, "DefaultCLR")[0] - if default_clr: - return _find_mono_in_reg(subkey + "\\" + default_clr, bits) - return None - except OSError: - return None - - -def find_mono_root_dir(bits): - root_dir = _find_mono_in_reg(r"SOFTWARE\Mono", bits) - if root_dir is not None: - return str(root_dir) - root_dir = _find_mono_in_reg_old(r"SOFTWARE\Novell\Mono", bits) - if root_dir is not None: - return str(root_dir) - return "" - - -def find_msbuild_tools_path_reg(): - import subprocess - - vswhere = os.getenv("PROGRAMFILES(X86)") - if not vswhere: - vswhere = os.getenv("PROGRAMFILES") - vswhere += r"\Microsoft Visual Studio\Installer\vswhere.exe" - - vswhere_args = ["-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"] - - try: - lines = subprocess.check_output([vswhere] + vswhere_args).splitlines() - - for line in lines: - parts = line.decode("utf-8").split(":", 1) - - if len(parts) < 2 or parts[0] != "installationPath": - continue - - val = parts[1].strip() - - if not val: - raise ValueError("Value of `installationPath` entry is empty") - - # Since VS2019, the directory is simply named "Current" - msbuild_dir = os.path.join(val, "MSBuild\\Current\\Bin") - if os.path.isdir(msbuild_dir): - return msbuild_dir - - # Directory name "15.0" is used in VS 2017 - return os.path.join(val, "MSBuild\\15.0\\Bin") - - raise ValueError("Cannot find `installationPath` entry") - except ValueError as e: - print("Error reading output from vswhere: " + e.message) - except subprocess.CalledProcessError as e: - print(e.output) - except OSError as e: - print(e) - - # Try to find 14.0 in the Registry - - try: - subkey = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" - with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey: - value = winreg.QueryValueEx(hKey, "MSBuildToolsPath")[0] - return value - except OSError: - return "" diff --git a/modules/mono/config.py b/modules/mono/config.py index 010f1ef1e5..d156877929 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -1,4 +1,6 @@ -supported_platforms = ["windows", "macos", "linuxbsd", "server", "android", "haiku", "javascript", "ios"] +# Prior to .NET Core, we supported these: ["windows", "macos", "linuxbsd", "server", "android", "haiku", "javascript", "ios"] +# Eventually support for each them should be added back (except Haiku if not supported by .NET Core) +supported_platforms = ["windows", "macos", "linuxbsd", "server"] def can_build(env, platform): @@ -13,26 +15,11 @@ def get_opts(platform): return [ PathVariable( - "mono_prefix", - "Path to the Mono installation directory for the target platform and architecture", + "dotnet_root", + "Path to the .NET Sdk installation directory for the target platform and architecture", "", PathVariable.PathAccept, ), - PathVariable( - "mono_bcl", - "Path to a custom Mono BCL (Base Class Library) directory for the target platform", - "", - PathVariable.PathAccept, - ), - BoolVariable("mono_static", "Statically link Mono", default_mono_static), - BoolVariable("build_cil", "Build C# solutions", True), - BoolVariable( - "copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True - ), - # TODO: It would be great if this could be detected automatically instead - BoolVariable( - "mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib - ), ] @@ -44,13 +31,6 @@ def configure(env): env.add_module_version_string("mono") - if env["mono_bundles_zlib"]: - # Mono may come with zlib bundled for WASM or on newer version when built with MinGW. - print("This Mono runtime comes with zlib bundled. Disabling 'builtin_zlib'...") - env["builtin_zlib"] = False - thirdparty_zlib_dir = "#thirdparty/zlib/" - env.Prepend(CPPPATH=[thirdparty_zlib_dir]) - def get_doc_classes(): return [ diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b088271b18..772c705981 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -30,8 +30,6 @@ #include "csharp_script.h" -#include -#include #include #include "core/config/project_settings.h" @@ -59,7 +57,6 @@ #include "godotsharp_dirs.h" #include "managed_callable.h" #include "mono_gd/gd_mono_cache.h" -#include "mono_gd/gd_mono_utils.h" #include "signal_awaiter_utils.h" #include "utils/macros.h" #include "utils/string_utils.h" @@ -107,8 +104,12 @@ Error CSharpLanguage::execute_file(const String &p_path) { return OK; } -extern void *godotsharp_pinvoke_funcs[164]; +extern void *godotsharp_pinvoke_funcs[176]; [[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs; +#ifdef TOOLS_ENABLED +extern void *godotsharp_editor_pinvoke_funcs[32]; +[[maybe_unused]] volatile void **do_not_strip_godotsharp_editor_pinvoke_funcs; +#endif void CSharpLanguage::init() { #ifdef DEBUG_METHODS_ENABLED @@ -122,6 +123,9 @@ void CSharpLanguage::init() { // Hopefully this will be enough for all compilers. Otherwise we could use the printf on fake getenv trick. do_not_strip_godotsharp_pinvoke_funcs = (volatile void **)godotsharp_pinvoke_funcs; +#ifdef TOOLS_ENABLED + do_not_strip_godotsharp_editor_pinvoke_funcs = (volatile void **)godotsharp_editor_pinvoke_funcs; +#endif #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) // Generate the bindings here, before loading assemblies. The Godot assemblies @@ -709,19 +713,14 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) { } void CSharpLanguage::frame() { - if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != nullptr) { - MonoException *exc = nullptr; - GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_FrameCallback.invoke(&exc); - if (exc) { - GDMonoUtils::debug_unhandled_exception(exc); - } + if (gdmono && gdmono->is_runtime_initialized() && GDMonoCache::godot_api_cache_updated) { + GDMonoCache::managed_callbacks.ScriptManagerBridge_FrameCallback(); } } void CSharpLanguage::reload_all_scripts() { #ifdef GD_MONO_HOT_RELOAD if (is_assembly_reloading_needed()) { - GD_MONO_SCOPE_THREAD_ATTACH; reload_assemblies(false); } #endif @@ -738,7 +737,6 @@ void CSharpLanguage::reload_tool_script(const Ref