summaryrefslogtreecommitdiff
path: root/modules/mono/mono_gd
diff options
context:
space:
mode:
authorIgnacio Etcheverry <ignalfonsore@gmail.com>2019-11-28 23:42:37 +0100
committerIgnacio Etcheverry <ignalfonsore@gmail.com>2019-11-29 00:36:05 +0100
commit66de28eda8239e006c5d53debdea75f131b32f77 (patch)
tree2a2049727d84c173e7e0a924350ce2cdd15e01ee /modules/mono/mono_gd
parent7735af7e768e16efb4b3b6de1c72c3dfb50c9412 (diff)
Mono/C#: Add option to export assemblies outside of PCK
When using this options, assemblies will be saved in the Assemblies folder of the data directory: 'data_AppName/Assemblies/'.
Diffstat (limited to 'modules/mono/mono_gd')
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp107
-rw-r--r--modules/mono/mono_gd/gd_mono.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp40
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h2
4 files changed, 96 insertions, 57 deletions
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 384ef08cd0..a43311d281 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -239,35 +239,22 @@ void GDMono::add_mono_shared_libs_dir_to_path() {
#endif // WINDOWS_ENABLED || UNIX_ENABLED
}
-void GDMono::initialize() {
-
- ERR_FAIL_NULL(Engine::get_singleton());
-
- print_verbose("Mono: Initializing module...");
-
- char *runtime_build_info = mono_get_runtime_build_info();
- print_verbose("Mono JIT compiler version " + String(runtime_build_info));
- mono_free(runtime_build_info);
-
-#ifdef DEBUG_METHODS_ENABLED
- _initialize_and_check_api_hashes();
-#endif
+void GDMono::determine_mono_dirs(String &r_assembly_rootdir, String &r_config_dir) {
- GDMonoLog::get_singleton()->initialize();
-
- String assembly_rootdir;
- String config_dir;
+ String bundled_assembly_rootdir = GodotSharpDirs::get_data_mono_lib_dir();
+ String bundled_config_dir = GodotSharpDirs::get_data_mono_etc_dir();
#ifdef TOOLS_ENABLED
+
#if defined(WINDOWS_ENABLED)
mono_reg_info = MonoRegUtils::find_mono();
if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) {
- assembly_rootdir = mono_reg_info.assembly_dir;
+ r_assembly_rootdir = mono_reg_info.assembly_dir;
}
if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
- config_dir = mono_reg_info.config_dir;
+ r_config_dir = mono_reg_info.config_dir;
}
#elif defined(OSX_ENABLED)
const char *c_assembly_rootdir = mono_assembly_getrootdir();
@@ -284,29 +271,24 @@ void GDMono::initialize() {
String hint_config_dir = path::join(locations[i], "etc");
if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
- assembly_rootdir = hint_assembly_rootdir;
- config_dir = hint_config_dir;
+ r_assembly_rootdir = hint_assembly_rootdir;
+ r_config_dir = hint_config_dir;
break;
}
}
}
#endif
-#endif // TOOLS_ENABLED
- String bundled_assembly_rootdir = GodotSharpDirs::get_data_mono_lib_dir();
- String bundled_config_dir = GodotSharpDirs::get_data_mono_etc_dir();
-
-#ifdef TOOLS_ENABLED
if (DirAccess::exists(bundled_assembly_rootdir)) {
- assembly_rootdir = bundled_assembly_rootdir;
+ r_assembly_rootdir = bundled_assembly_rootdir;
}
if (DirAccess::exists(bundled_config_dir)) {
- config_dir = bundled_config_dir;
+ r_config_dir = bundled_config_dir;
}
#ifdef WINDOWS_ENABLED
- if (assembly_rootdir.empty() || config_dir.empty()) {
+ if (r_assembly_rootdir.empty() || r_config_dir.empty()) {
ERR_PRINT("Cannot find Mono in the registry.");
// Assertion: if they are not set, then they weren't found in the registry
CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0);
@@ -314,12 +296,32 @@ void GDMono::initialize() {
#endif // WINDOWS_ENABLED
#else
- // These are always the directories in export templates
- assembly_rootdir = bundled_assembly_rootdir;
- config_dir = bundled_config_dir;
-#endif // TOOLS_ENABLED
+ // Export templates always use the bundled directories
+ r_assembly_rootdir = bundled_assembly_rootdir;
+ r_config_dir = bundled_config_dir;
+#endif
+}
+
+void GDMono::initialize() {
+
+ ERR_FAIL_NULL(Engine::get_singleton());
+
+ print_verbose("Mono: Initializing module...");
+
+ char *runtime_build_info = mono_get_runtime_build_info();
+ print_verbose("Mono JIT compiler version " + String(runtime_build_info));
+ mono_free(runtime_build_info);
+
+ _init_godot_api_hashes();
+ _init_exception_policy();
+
+ GDMonoLog::get_singleton()->initialize();
#if !defined(JAVASCRIPT_ENABLED)
+ String assembly_rootdir;
+ String config_dir;
+ determine_mono_dirs(assembly_rootdir, config_dir);
+
// Leak if we call mono_set_dirs more than once
mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL,
config_dir.length() ? config_dir.utf8().get_data() : NULL);
@@ -331,18 +333,6 @@ void GDMono::initialize() {
GDMonoAndroid::register_android_dl_fallback();
#endif
- {
- PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/unhandled_exception_policy", PROPERTY_HINT_ENUM,
- vformat("Terminate Application:%s,Log Error:%s", (int)POLICY_TERMINATE_APP, (int)POLICY_LOG_ERROR));
- unhandled_exception_policy = (UnhandledExceptionPolicy)(int)GLOBAL_DEF(exc_policy_prop.name, (int)POLICY_TERMINATE_APP);
- ProjectSettings::get_singleton()->set_custom_property_info(exc_policy_prop.name, exc_policy_prop);
-
- if (Engine::get_singleton()->is_editor_hint()) {
- // Unhandled exceptions should not terminate the editor
- unhandled_exception_policy = POLICY_LOG_ERROR;
- }
- }
-
GDMonoAssembly::initialize();
#if !defined(JAVASCRIPT_ENABLED)
@@ -358,9 +348,12 @@ void GDMono::initialize() {
mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
#ifndef TOOLS_ENABLED
- // Export templates only load the Mono runtime if the project uses it
- if (!DirAccess::exists("res://.mono"))
+ // Exported games that don't use C# must still work. They likely don't ship with mscorlib.
+ // We only initialize the Mono runtime if we can find mscorlib. Otherwise it would crash.
+ if (GDMonoAssembly::find_assembly("mscorlib.dll").empty()) {
+ print_verbose("Mono: Skipping runtime initialization because 'mscorlib.dll' could not be found");
return;
+ }
#endif
#if !defined(WINDOWS_ENABLED) && !defined(NO_MONO_THREADS_SUSPEND_WORKAROUND)
@@ -475,9 +468,8 @@ void GDMono::_register_internal_calls() {
GodotSharpBindings::register_generated_icalls();
}
-void GDMono::_initialize_and_check_api_hashes() {
-#ifdef MONO_GLUE_ENABLED
-#ifdef DEBUG_METHODS_ENABLED
+void GDMono::_init_godot_api_hashes() {
+#if defined(MONO_GLUE_ENABLED) && defined(DEBUG_METHODS_ENABLED)
if (get_api_core_hash() != GodotSharpBindings::get_core_api_hash()) {
ERR_PRINT("Mono: Core API hash mismatch.");
}
@@ -487,8 +479,19 @@ void GDMono::_initialize_and_check_api_hashes() {
ERR_PRINT("Mono: Editor API hash mismatch.");
}
#endif // TOOLS_ENABLED
-#endif // DEBUG_METHODS_ENABLED
-#endif // MONO_GLUE_ENABLED
+#endif // MONO_GLUE_ENABLED && DEBUG_METHODS_ENABLED
+}
+
+void GDMono::_init_exception_policy() {
+ PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/unhandled_exception_policy", PROPERTY_HINT_ENUM,
+ vformat("Terminate Application:%s,Log Error:%s", (int)POLICY_TERMINATE_APP, (int)POLICY_LOG_ERROR));
+ unhandled_exception_policy = (UnhandledExceptionPolicy)(int)GLOBAL_DEF(exc_policy_prop.name, (int)POLICY_TERMINATE_APP);
+ ProjectSettings::get_singleton()->set_custom_property_info(exc_policy_prop.name, exc_policy_prop);
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // Unhandled exceptions should not terminate the editor
+ unhandled_exception_policy = POLICY_LOG_ERROR;
+ }
}
void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index e14a0d8409..7fb03b82ad 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -153,7 +153,8 @@ private:
#ifdef TOOLS_ENABLED
uint64_t api_editor_hash;
#endif
- void _initialize_and_check_api_hashes();
+ void _init_godot_api_hashes();
+ void _init_exception_policy();
GDMonoLog *gdmono_log;
@@ -162,6 +163,7 @@ private:
#endif
void add_mono_shared_libs_dir_to_path();
+ void determine_mono_dirs(String &r_assembly_rootdir, String &r_config_dir);
protected:
static GDMono *singleton;
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 91842420b7..105560fe9a 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -62,6 +62,13 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin
r_search_dirs.push_back(framework_dir.plus_file("Facades"));
}
+#if !defined(TOOLS_ENABLED)
+ String data_game_assemblies_dir = GodotSharpDirs::get_data_game_assemblies_dir();
+ if (!data_game_assemblies_dir.empty()) {
+ r_search_dirs.push_back(data_game_assemblies_dir);
+ }
+#endif
+
if (p_custom_config.length()) {
r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(p_custom_config));
} else {
@@ -147,10 +154,6 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, vo
(void)user_data; // UNUSED
- if (search_dirs.empty()) {
- fill_search_dirs(search_dirs);
- }
-
{
// If we find the assembly here, we load it with 'mono_assembly_load_from_full',
// which in turn invokes load hooks before returning the MonoAssembly to us.
@@ -228,6 +231,33 @@ GDMonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, cons
return NULL;
}
+String GDMonoAssembly::find_assembly(const String &p_name) {
+
+ String path;
+
+ bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe");
+
+ for (int i = 0; i < search_dirs.size(); i++) {
+ const String &search_dir = search_dirs[i];
+
+ if (has_extension) {
+ path = search_dir.plus_file(p_name);
+ if (FileAccess::exists(path))
+ return path;
+ } else {
+ path = search_dir.plus_file(p_name + ".dll");
+ if (FileAccess::exists(path))
+ return path;
+
+ path = search_dir.plus_file(p_name + ".exe");
+ if (FileAccess::exists(path))
+ return path;
+ }
+ }
+
+ return String();
+}
+
GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) {
GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
@@ -264,6 +294,8 @@ void GDMonoAssembly::_wrap_mono_assembly(MonoAssembly *assembly) {
void GDMonoAssembly::initialize() {
+ fill_search_dirs(search_dirs);
+
mono_install_assembly_search_hook(&assembly_search_hook, NULL);
mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, NULL);
mono_install_assembly_preload_hook(&assembly_preload_hook, NULL);
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 39749dfc1d..04a219f742 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -122,6 +122,8 @@ public:
GDMonoClass *get_object_derived_class(const StringName &p_class);
+ static String find_assembly(const String &p_name);
+
static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String(), const String &p_custom_bcl_dir = String());
static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly);