Merge pull request #22688 from neikeq/lotsofgoodies

Mono: Editor and export template dependencies and fixes
This commit is contained in:
Rémi Verschelde 2018-10-05 16:24:21 +02:00 committed by GitHub
commit aa85b7ed62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 651 additions and 239 deletions

View File

@ -244,16 +244,13 @@ def mono_build_solution(source, target, env):
copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file))
output_dir = Dir('#bin').abspath
assemblies_output_dir = Dir(env['mono_assemblies_output_dir']).abspath
if env['tools']:
output_dir = Dir('#bin').abspath
editor_tools_dir = os.path.join(output_dir, 'GodotSharp', 'Tools')
mono_sln_builder = Builder(action=mono_build_solution)
env_mono.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder})
env_mono.MonoBuildSolution(
os.path.join(assemblies_output_dir, 'GodotSharpTools.dll'),
'editor/GodotSharpTools/GodotSharpTools.sln'
)
if os.path.normpath(output_dir) != os.path.normpath(assemblies_output_dir):
rel_assemblies_output_dir = os.path.relpath(assemblies_output_dir, output_dir)
env_mono.Append(CPPDEFINES={'GD_MONO_EDITOR_ASSEMBLIES_DIR': rel_assemblies_output_dir})
mono_sln_builder = Builder(action=mono_build_solution)
env_mono.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder})
env_mono.MonoBuildSolution(
os.path.join(editor_tools_dir, 'GodotSharpTools.dll'),
'editor/GodotSharpTools/GodotSharpTools.sln'
)

View File

@ -5,7 +5,7 @@ import sys
import subprocess
from distutils.version import LooseVersion
from SCons.Script import BoolVariable, Dir, Environment, File, PathVariable, SCons, Variables
from SCons.Script import BoolVariable, Dir, Environment, File, SCons, Variables
monoreg = imp.load_source('mono_reg_utils', 'modules/mono/mono_reg_utils.py')
@ -55,30 +55,20 @@ def copy_file(src_dir, dst_dir, name):
copyfile(src_path, dst_path)
def custom_path_is_dir_create(key, val, env):
"""Validator to check if Path is a directory, creating it if it does not exist.
Similar to PathIsDirCreate, except it uses SCons.Script.Dir() and
SCons.Script.File() in order to support the '#' top level directory token.
"""
# Dir constructor will throw an error if the path points to a file
fsDir = Dir(val)
if not fsDir.exists:
os.makedirs(fsDir.abspath)
def configure(env):
env.use_ptrcall = True
env.add_module_version_string('mono')
envvars = Variables()
envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
envvars.Add(PathVariable('mono_assemblies_output_dir', 'Path to the assemblies output directory', '#bin', custom_path_is_dir_create))
envvars.Add(BoolVariable('copy_mono_root', 'Make a copy of the mono installation directory to bundle with the editor', False))
envvars.Update(env)
bits = env['bits']
tools_enabled = env['tools']
mono_static = env['mono_static']
assemblies_output_dir = Dir(env['mono_assemblies_output_dir']).abspath
copy_mono_root = env['copy_mono_root']
mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
@ -151,8 +141,6 @@ def configure(env):
raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)
copy_file(mono_bin_path, 'bin', mono_dll_name + '.dll')
copy_file(os.path.join(mono_lib_path, 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll')
else:
sharedlib_ext = '.dylib' if sys.platform == 'darwin' else '.so'
@ -204,16 +192,14 @@ def configure(env):
if sys.platform == 'darwin':
env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file])
elif sys.platform == 'linux' or sys.platform == 'linux2':
env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
else:
raise RuntimeError('mono-static: Not supported on this platform')
env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
else:
env.Append(LIBS=[mono_lib])
if sys.platform == 'darwin':
env.Append(LIBS=['iconv', 'pthread'])
elif sys.platform == 'linux' or sys.platform == 'linux2':
else:
env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
if not mono_static:
@ -223,8 +209,6 @@ def configure(env):
raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path)
copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
copy_file(os.path.join(mono_lib_path, 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll')
else:
assert not mono_static
@ -238,7 +222,6 @@ def configure(env):
mono_lib_path = ''
mono_so_name = ''
mono_prefix = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
tmpenv = Environment()
tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
@ -255,16 +238,163 @@ def configure(env):
raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH']))
copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
copy_file(os.path.join(mono_prefix, 'lib', 'mono', '4.5'), assemblies_output_dir, 'mscorlib.dll')
env.Append(LINKFLAGS='-rdynamic')
if not tools_enabled:
if not mono_root:
mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
make_template_dir(env, mono_root)
if copy_mono_root:
if not mono_root:
mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
if tools_enabled:
copy_mono_root_files(env, mono_root)
else:
print("Ignoring option: 'copy_mono_root'. Only available for builds with 'tools' enabled.")
def make_template_dir(env, mono_root):
from shutil import rmtree
platform = env['platform']
target = env['target']
template_dir_name = ''
if platform == 'windows':
template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target)
elif platform == 'osx':
template_dir_name = 'data.mono.%s.%s' % (platform, target)
elif platform == 'x11':
template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target)
else:
assert False
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, env['platform'])
# Copy the required shared libraries
copy_mono_shared_libs(mono_root, template_mono_root_dir, env['platform'])
def copy_mono_root_files(env, mono_root):
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(mono_root, editor_mono_root_dir, env['platform'])
# Copy framework assemblies
mono_framework_dir = os.path.join(mono_root, 'lib', 'mono', '4.5')
mono_framework_facades_dir = os.path.join(mono_framework_dir, 'Facades')
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')
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 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)
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
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')
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'))
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 copy_mono_shared_libs(mono_root, target_mono_root_dir, platform):
from shutil import copy
if platform == 'windows':
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)
copy(os.path.join(mono_root, 'bin', 'MonoPosixHelper.dll'), os.path.join(target_mono_bin_dir, 'MonoPosixHelper.dll'))
else:
target_mono_lib_dir = os.path.join(target_mono_root_dir, 'lib')
if not os.path.isdir(target_mono_lib_dir):
os.makedirs(target_mono_lib_dir)
if platform == 'osx':
copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.dylib'), os.path.join(target_mono_lib_dir, 'libMonoPosixHelper.dylib'))
elif platform == 'x11':
copy(os.path.join(mono_root, 'lib', 'libmono-btls-shared.so'), os.path.join(target_mono_lib_dir, 'libmono-btls-shared.so'))
copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.so'), os.path.join(target_mono_lib_dir, 'libMonoPosixHelper.so'))
def configure_for_mono_version(env, mono_version):
if mono_version is None:
raise RuntimeError('Mono JIT compiler version not found')
print('Found Mono JIT compiler version: ' + str(mono_version))
if mono_version >= LooseVersion("5.12.0"):
if mono_version >= LooseVersion('5.12.0'):
env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS'])

View File

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
namespace GodotSharpTools.Editor
{
public static class GodotSharpExport
{
public static void _ExportBegin(string[] features, bool debug, string path, int flags)
{
var featureSet = new HashSet<string>(features);
if (PlatformHasTemplateDir(featureSet))
{
string templateDirName = "data.mono";
if (featureSet.Contains("Windows"))
{
templateDirName += ".windows";
templateDirName += featureSet.Contains("64") ? ".64" : ".32";
}
else if (featureSet.Contains("X11"))
{
templateDirName += ".x11";
templateDirName += featureSet.Contains("64") ? ".64" : ".32";
}
else
{
throw new NotSupportedException("Target platform not supported");
}
templateDirName += debug ? ".debug" : ".release";
string templateDirPath = Path.Combine(GetTemplatesDir(), templateDirName);
if (!Directory.Exists(templateDirPath))
throw new FileNotFoundException("Data template directory not found");
string outputDir = new FileInfo(path).Directory.FullName;
string outputDataDir = Path.Combine(outputDir, GetDataDirName());
Directory.Delete(outputDataDir, recursive: true); // Clean first
Directory.CreateDirectory(outputDataDir);
foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1)));
}
foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories))
{
File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1)));
}
}
}
public static bool PlatformHasTemplateDir(HashSet<string> featureSet)
{
// OSX export templates are contained in a zip, so we place
// our custom template inside it and let Godot do the rest.
return !featureSet.Contains("OSX");
}
[MethodImpl(MethodImplOptions.InternalCall)]
extern static string GetTemplatesDir();
[MethodImpl(MethodImplOptions.InternalCall)]
extern static string GetDataDirName();
}
}

View File

@ -41,6 +41,7 @@
<Compile Include="Project\ProjectUtils.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\OS.cs" />
<Compile Include="Editor\GodotSharpExport.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -51,7 +51,7 @@ String generate_core_api_project(const String &p_dir, const Vector<String> &p_fi
MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
GDMonoUtils::debug_print_unhandled_exception(exc);
ERR_FAIL_V(String());
}
@ -72,7 +72,7 @@ String generate_editor_api_project(const String &p_dir, const String &p_core_dll
MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
GDMonoUtils::debug_print_unhandled_exception(exc);
ERR_FAIL_V(String());
}
@ -93,7 +93,7 @@ String generate_game_project(const String &p_dir, const String &p_name, const Ve
MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
GDMonoUtils::debug_print_unhandled_exception(exc);
ERR_FAIL_V(String());
}
@ -114,7 +114,7 @@ void add_item(const String &p_project_path, const String &p_item_type, const Str
klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
GDMonoUtils::debug_print_unhandled_exception(exc);
ERR_FAIL();
}
}

View File

@ -249,6 +249,18 @@ bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_s
bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) {
// Create destination directory if needed
if (!DirAccess::exists(p_dst_dir)) {
DirAccess *da = DirAccess::create_for_path(p_dst_dir);
Error err = da->make_dir_recursive(p_dst_dir);
memdelete(da);
if (err != OK) {
show_build_error_dialog("Failed to create destination directory for the API assemblies. Error: " + itos(err));
return false;
}
}
String assembly_file = p_assembly_name + ".dll";
String assembly_src = p_src_dir.plus_file(assembly_file);
String assembly_dst = p_dst_dir.plus_file(assembly_file);
@ -296,9 +308,9 @@ bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) {
String api_name = p_api_type == APIAssembly::API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
String api_build_config = "Release";
EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 4);
EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 3);
pr.step("Generating " + api_name + " solution");
pr.step("Generating " + api_name + " solution", 0);
String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
.plus_file(_api_folder_name(APIAssembly::API_CORE))
@ -336,34 +348,19 @@ bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) {
}
}
pr.step("Building " + api_name + " solution");
pr.step("Building " + api_name + " solution", 1);
if (!GodotSharpBuilds::build_api_sln(api_name, api_sln_dir, api_build_config))
return false;
pr.step("Copying " + api_name + " assembly");
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
// Create assemblies directory if needed
if (!DirAccess::exists(res_assemblies_dir)) {
DirAccess *da = DirAccess::create_for_path(res_assemblies_dir);
Error err = da->make_dir_recursive(res_assemblies_dir);
memdelete(da);
if (err != OK) {
show_build_error_dialog("Failed to create assemblies directory. Error: " + itos(err));
return false;
}
}
pr.step("Copying " + api_name + " assembly", 2);
// Copy the built assembly to the assemblies directory
String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config);
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type))
return false;
pr.step("Done");
return true;
}
@ -372,15 +369,39 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
return false;
String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir();
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
return false;
if (FileAccess::exists(editor_prebuilt_api_dir.plus_file(API_ASSEMBLY_NAME ".dll"))) {
EditorProgress pr("mono_copy_prebuilt_api_assemblies",
"Copying prebuilt " API_ASSEMBLY_NAME " assemblies...", 1);
pr.step("Copying " API_ASSEMBLY_NAME " assembly", 0);
EditorProgress pr("mono_project_debug_build", "Building project solution...", 2);
if (!GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir,
API_ASSEMBLY_NAME, APIAssembly::API_CORE)) {
return false;
}
} else {
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
return false;
}
pr.step("Building project solution");
if (DirAccess::exists(editor_prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"))) {
EditorProgress pr("mono_copy_prebuilt_api_assemblies",
"Copying prebuilt " EDITOR_API_ASSEMBLY_NAME " assemblies...", 1);
pr.step("Copying " EDITOR_API_ASSEMBLY_NAME " assembly", 0);
if (!GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir,
EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) {
return false;
}
} else {
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
return false;
}
EditorProgress pr("mono_project_debug_build", "Building project solution...", 1);
pr.step("Building project solution", 0);
MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), p_config);
if (!GodotSharpBuilds::get_singleton()->build(build_info)) {
@ -388,8 +409,6 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
return false;
}
pr.step("Done");
return true;
}

View File

@ -197,6 +197,7 @@ void GodotSharpEditor::register_internal_calls() {
mono_add_internal_call("GodotSharpTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName);
GodotSharpBuilds::register_internal_calls();
GodotSharpExport::register_internal_calls();
}
void GodotSharpEditor::show_error_dialog(const String &p_message, const String &p_title) {

View File

@ -30,12 +30,37 @@
#include "godotsharp_export.h"
#include "core/version.h"
#include "../csharp_script.h"
#include "../godotsharp_defs.h"
#include "../godotsharp_dirs.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "godotsharp_builds.h"
void GodotSharpExport::_export_file(const String &p_path, const String &p_type, const Set<String> &p_features) {
static MonoString *godot_icall_GodotSharpExport_GetTemplatesDir() {
String current_version = VERSION_FULL_CONFIG;
String templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(current_version);
return GDMonoMarshal::mono_string_from_godot(ProjectSettings::get_singleton()->globalize_path(templates_dir));
}
static MonoString *godot_icall_GodotSharpExport_GetDataDirName() {
String appname = ProjectSettings::get_singleton()->get("application/config/name");
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
return GDMonoMarshal::mono_string_from_godot("data_" + appname_safe);
}
void GodotSharpExport::register_internal_calls() {
static bool registered = false;
ERR_FAIL_COND(registered);
registered = true;
mono_add_internal_call("GodotSharpTools.Editor.GodotSharpExport::GetTemplatesDir", (void *)godot_icall_GodotSharpExport_GetTemplatesDir);
mono_add_internal_call("GodotSharpTools.Editor.GodotSharpExport::GetDataDirName", (void *)godot_icall_GodotSharpExport_GetDataDirName);
}
void GodotSharpExport::_export_file(const String &p_path, const String &p_type, const Set<String> &) {
if (p_type != CSharpLanguage::get_singleton()->get_type())
return;
@ -56,59 +81,78 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
// TODO right now there is no way to stop the export process with an error
ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
ERR_FAIL_NULL(GDMono::get_singleton()->get_tools_domain());
ERR_FAIL_NULL(TOOLS_DOMAIN);
ERR_FAIL_NULL(GDMono::get_singleton()->get_editor_tools_assembly());
String build_config = p_debug ? "Debug" : "Release";
ERR_FAIL_COND(!GodotSharpBuilds::build_project_blocking(build_config));
// Add API assemblies
// Add dependency assemblies
String core_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(API_ASSEMBLY_NAME ".dll");
ERR_FAIL_COND(!_add_assembly(core_api_dll_path, core_api_dll_path));
String editor_api_dll_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
ERR_FAIL_COND(!_add_assembly(editor_api_dll_path, editor_api_dll_path));
// Add project assembly
Map<String, String> dependencies;
String project_dll_name = ProjectSettings::get_singleton()->get("application/config/name");
if (project_dll_name.empty()) {
project_dll_name = "UnnamedProject";
}
String project_dll_src_path = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config).plus_file(project_dll_name + ".dll");
String project_dll_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(project_dll_name + ".dll");
ERR_FAIL_COND(!_add_assembly(project_dll_src_path, project_dll_dst_path));
String project_dll_src_dir = GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(build_config);
String project_dll_src_path = project_dll_src_dir.plus_file(project_dll_name + ".dll");
dependencies.insert(project_dll_name, project_dll_src_path);
// Add dependencies
{
MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
ERR_FAIL_NULL(export_domain);
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
MonoDomain *prev_domain = mono_domain_get();
MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
_GDMONO_SCOPE_DOMAIN_(export_domain);
ERR_FAIL_COND(!export_domain);
ERR_FAIL_COND(!mono_domain_set(export_domain, false));
GDMonoAssembly *scripts_assembly = NULL;
bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name,
project_dll_src_dir, &scripts_assembly, /* refonly: */ true);
Map<String, String> dependencies;
dependencies.insert("mscorlib", GDMono::get_singleton()->get_corlib_assembly()->get_path());
ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name);
ERR_FAIL_COND(!load_success);
GDMonoAssembly *scripts_assembly = GDMonoAssembly::load_from(project_dll_name, project_dll_src_path, /* refonly: */ true);
ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name);
ERR_FAIL_COND(!scripts_assembly);
Error depend_error = _get_assembly_dependencies(scripts_assembly, dependencies);
GDMono::get_singleton()->finalize_and_unload_domain(export_domain);
mono_domain_set(prev_domain, false);
ERR_FAIL_COND(depend_error != OK);
Vector<String> search_dirs;
GDMonoAssembly::fill_search_dirs(search_dirs);
Error depend_error = _get_assembly_dependencies(scripts_assembly, search_dirs, dependencies);
ERR_FAIL_COND(depend_error != OK);
}
for (Map<String, String>::Element *E = dependencies.front(); E; E = E->next()) {
String depend_src_path = E->value();
String depend_dst_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(depend_src_path.get_file());
ERR_FAIL_COND(!_add_assembly(depend_src_path, depend_dst_path));
}
// Mono specific export template extras (data dir)
GDMonoClass *export_class = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Editor", "GodotSharpExport");
ERR_FAIL_NULL(export_class);
GDMonoMethod *export_begin_method = export_class->get_method("_ExportBegin", 4);
ERR_FAIL_NULL(export_begin_method);
MonoArray *features = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_features.size());
int i = 0;
for (const Set<String>::Element *E = p_features.front(); E; E = E->next()) {
MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get());
mono_array_set(features, MonoString *, i, boxed);
i++;
}
MonoBoolean debug = p_debug;
MonoString *path = GDMonoMarshal::mono_string_from_godot(p_path);
uint32_t flags = p_flags;
void *args[4] = { features, &debug, path, &flags };
MonoException *exc = NULL;
export_begin_method->invoke_raw(NULL, args, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
ERR_FAIL();
}
}
bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_dst_path) {
@ -125,7 +169,7 @@ bool GodotSharpExport::_add_assembly(const String &p_src_path, const String &p_d
return true;
}
Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies) {
Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Map<String, String> &r_dependencies) {
MonoImage *image = p_assembly->get_image();
@ -134,18 +178,48 @@ Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, M
mono_assembly_get_assemblyref(image, i, ref_aname);
String ref_name = mono_assembly_name_get_name(ref_aname);
if (ref_name == "mscorlib" || r_dependencies.find(ref_name))
if (r_dependencies.find(ref_name))
continue;
GDMonoAssembly *ref_assembly = NULL;
if (!GDMono::get_singleton()->load_assembly(ref_name, ref_aname, &ref_assembly, /* refonly: */ true)) {
ERR_EXPLAIN("Cannot load refonly assembly: " + ref_name);
String path;
bool has_extension = ref_name.ends_with(".dll") || ref_name.ends_with(".exe");
for (int i = 0; i < p_search_dirs.size(); i++) {
const String &search_dir = p_search_dirs[i];
if (has_extension) {
path = search_dir.plus_file(ref_name);
if (FileAccess::exists(path)) {
GDMono::get_singleton()->load_assembly_from(ref_name.get_basename(), search_dir, ref_aname, &ref_assembly, true);
if (ref_assembly != NULL)
break;
}
} else {
path = search_dir.plus_file(ref_name + ".dll");
if (FileAccess::exists(path)) {
GDMono::get_singleton()->load_assembly_from(ref_name, search_dir, ref_aname, &ref_assembly, true);
if (ref_assembly != NULL)
break;
}
path = search_dir.plus_file(ref_name + ".exe");
if (FileAccess::exists(path)) {
GDMono::get_singleton()->load_assembly_from(ref_name, search_dir, ref_aname, &ref_assembly, true);
if (ref_assembly != NULL)
break;
}
}
}
if (!ref_assembly) {
ERR_EXPLAIN("Cannot load assembly (refonly): " + ref_name);
ERR_FAIL_V(ERR_CANT_RESOLVE);
}
r_dependencies.insert(ref_name, ref_assembly->get_path());
Error err = _get_assembly_dependencies(ref_assembly, r_dependencies);
Error err = _get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies);
if (err != OK)
return err;
}

View File

@ -43,13 +43,15 @@ class GodotSharpExport : public EditorExportPlugin {
bool _add_assembly(const String &p_src_path, const String &p_dst_path);
Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, Map<String, String> &r_dependencies);
Error _get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Map<String, String> &r_dependencies);
protected:
virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features);
virtual void _export_begin(const Set<String> &p_features, bool p_debug, const String &p_path, int p_flags);
public:
static void register_internal_calls();
GodotSharpExport();
~GodotSharpExport();
};

View File

@ -30,11 +30,11 @@
#include "godotsharp_dirs.h"
#include "core/os/dir_access.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#ifdef TOOLS_ENABLED
#include "core/os/dir_access.h"
#include "core/project_settings.h"
#include "core/version.h"
#include "editor/editor_settings.h"
#endif
@ -95,10 +95,18 @@ public:
#ifdef TOOLS_ENABLED
String mono_solutions_dir;
String build_logs_dir;
String sln_filepath;
String csproj_filepath;
String data_mono_bin_dir;
String data_editor_tools_dir;
String data_editor_prebuilt_api_dir;
#endif
String data_mono_etc_dir;
String data_mono_lib_dir;
private:
_GodotSharpDirs() {
res_data_dir = "res://.mono";
@ -123,10 +131,60 @@ private:
name = "UnnamedProject";
}
String base_path = String("res://") + name;
String base_path = ProjectSettings::get_singleton()->globalize_path("res://");
sln_filepath = base_path.plus_file(name + ".sln");
csproj_filepath = base_path.plus_file(name + ".csproj");
#endif
String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
#ifdef TOOLS_ENABLED
String data_dir_root = exe_dir.plus_file("GodotSharp");
data_editor_tools_dir = data_dir_root.plus_file("Tools");
data_editor_prebuilt_api_dir = data_dir_root.plus_file("Api");
String data_mono_root_dir = data_dir_root.plus_file("Mono");
data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
#ifdef OSX_ENABLED
if (!DirAccess::exists(data_editor_tools_dir)) {
data_editor_tools_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Tools");
}
if (!DirAccess::exists(data_editor_prebuilt_api_dir)) {
data_editor_prebuilt_api_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Api");
}
if (!DirAccess::exists(data_mono_root_dir)) {
data_mono_bin_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Mono/bin");
data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
data_mono_lib_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Mono/lib");
}
#endif
#else
String appname = OS::get_singleton()->get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name"));
String data_dir_root = exe_dir.plus_file("data_" + appname);
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = exe_dir.plus_file("data_Godot");
}
String data_mono_root_dir = data_dir_root.plus_file("Mono");
data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
#ifdef OSX_ENABLED
if (!DirAccess::exists(data_mono_root_dir)) {
data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
data_mono_lib_dir = exe_dir.plus_file("../Frameworks/GodotSharp/Mono/lib");
}
#endif
sln_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".sln");
csproj_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".csproj");
#endif
}
@ -192,5 +250,26 @@ String get_project_sln_path() {
String get_project_csproj_path() {
return _GodotSharpDirs::get_singleton().csproj_filepath;
}
String get_data_mono_bin_dir() {
return _GodotSharpDirs::get_singleton().data_mono_bin_dir;
}
String get_data_editor_tools_dir() {
return _GodotSharpDirs::get_singleton().data_editor_tools_dir;
}
String get_data_editor_prebuilt_api_dir() {
return _GodotSharpDirs::get_singleton().data_editor_prebuilt_api_dir;
}
#endif
String get_data_mono_etc_dir() {
return _GodotSharpDirs::get_singleton().data_mono_etc_dir;
}
String get_data_mono_lib_dir() {
return _GodotSharpDirs::get_singleton().data_mono_lib_dir;
}
} // namespace GodotSharpDirs

View File

@ -49,11 +49,18 @@ String get_mono_logs_dir();
#ifdef TOOLS_ENABLED
String get_mono_solutions_dir();
String get_build_logs_dir();
String get_custom_project_settings_dir();
#endif
String get_project_sln_path();
String get_project_csproj_path();
String get_data_mono_bin_dir();
String get_data_editor_tools_dir();
String get_data_editor_prebuilt_api_dir();
#endif
String get_data_mono_etc_dir();
String get_data_mono_lib_dir();
} // namespace GodotSharpDirs
#endif // GODOTSHARP_DIRS_H

View File

@ -162,49 +162,62 @@ void GDMono::initialize() {
mono_trace_set_printerr_handler(gdmono_MonoPrintCallback);
#endif
String assembly_rootdir;
String config_dir;
#ifdef TOOLS_ENABLED
#ifdef WINDOWS_ENABLED
mono_reg_info = MonoRegUtils::find_mono();
CharString assembly_dir;
CharString config_dir;
if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) {
assembly_dir = mono_reg_info.assembly_dir.utf8();
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.utf8();
config_dir = mono_reg_info.config_dir;
}
mono_set_dirs(assembly_dir.length() ? assembly_dir.get_data() : NULL,
config_dir.length() ? config_dir.get_data() : NULL);
#elif OSX_ENABLED
mono_set_dirs(NULL, NULL);
const char *c_assembly_rootdir = mono_assembly_getrootdir();
const char *c_config_dir = mono_get_config_dir();
{
const char *assembly_rootdir = mono_assembly_getrootdir();
const char *config_dir = mono_get_config_dir();
if (!c_assembly_rootdir || !c_config_dir || !DirAccess::exists(c_assembly_rootdir) || !DirAccess::exists(c_config_dir)) {
Vector<const char *> locations;
locations.push_back("/Library/Frameworks/Mono.framework/Versions/Current/");
locations.push_back("/usr/local/var/homebrew/linked/mono/");
if (!assembly_rootdir || !config_dir || !DirAccess::exists(assembly_rootdir) || !DirAccess::exists(config_dir)) {
Vector<const char *> locations;
locations.push_back("/Library/Frameworks/Mono.framework/Versions/Current/");
locations.push_back("/usr/local/var/homebrew/linked/mono/");
for (int i = 0; i < locations.size(); i++) {
String hint_assembly_rootdir = path_join(locations[i], "lib");
String hint_mscorlib_path = path_join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
String hint_config_dir = path_join(locations[i], "etc");
for (int i = 0; i < locations.size(); i++) {
String hint_assembly_rootdir = path_join(locations[i], "lib");
String hint_mscorlib_path = path_join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
String hint_config_dir = path_join(locations[i], "etc");
if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
mono_set_dirs(hint_assembly_rootdir.utf8().get_data(), hint_config_dir.utf8().get_data());
break;
}
if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
need_set_mono_dirs = false;
assembly_rootdir = hint_assembly_rootdir;
config_dir = hint_config_dir;
break;
}
}
}
#else
mono_set_dirs(NULL, NULL);
#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) && DirAccess::exists(bundled_config_dir)) {
assembly_rootdir = bundled_assembly_rootdir;
config_dir = bundled_config_dir;
}
#else
// These are always the directories in export templates
assembly_rootdir = bundled_assembly_rootdir;
config_dir = bundled_config_dir;
#endif
// 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);
GDMonoAssembly::initialize();
@ -262,8 +275,11 @@ void GDMono::initialize() {
// Everything is fine with the api assemblies, load the project assembly
_load_project_assembly();
} else {
if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) ||
(editor_api_assembly && editor_api_assembly_out_of_sync)) {
if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated))
#ifdef TOOLS_ENABLED
|| (editor_api_assembly && editor_api_assembly_out_of_sync)
#endif
) {
#ifdef TOOLS_ENABLED
// The assembly was successfully loaded, but the full api could not be cached.
// This is most likely an outdated assembly loaded because of an invalid version in the
@ -362,24 +378,34 @@ GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {
bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) {
return load_assembly_from(p_name, String(), r_assembly, p_refonly);
}
bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
return load_assembly_from(p_name, String(), p_aname, r_assembly, p_refonly);
}
bool GDMono::load_assembly_from(const String &p_name, const String &p_basedir, GDMonoAssembly **r_assembly, bool p_refonly) {
CRASH_COND(!r_assembly);
MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
bool result = load_assembly(p_name, aname, r_assembly, p_refonly);
bool result = load_assembly_from(p_name, p_basedir, aname, r_assembly, p_refonly);
mono_assembly_name_free(aname);
mono_free(aname);
return result;
}
bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
bool GDMono::load_assembly_from(const String &p_name, const String &p_basedir, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
CRASH_COND(!r_assembly);
print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
MonoImageOpenStatus status = MONO_IMAGE_OK;
MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly);
MonoAssembly *assembly = mono_assembly_load_full(p_aname, p_basedir.length() ? p_basedir.utf8().get_data() : NULL, &status, p_refonly);
if (!assembly)
return false;
@ -480,12 +506,10 @@ bool GDMono::_load_editor_api_assembly() {
if (editor_api_assembly)
return true;
#ifdef TOOLS_ENABLED
if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) {
print_verbose("Mono: Skipping loading of Editor API assembly because it was invalidated");
return false;
}
#endif
bool success = load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
@ -772,7 +796,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
print_verbose("Mono: Unloading domain `" + domain_name + "`...");
if (mono_domain_get() != root_domain)
if (mono_domain_get() == p_domain)
mono_domain_set(root_domain, true);
mono_gc_collect(mono_gc_max_generation());

View File

@ -142,7 +142,7 @@ class GDMono {
GDMonoLog *gdmono_log;
#ifdef WINDOWS_ENABLED
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
MonoRegInfo mono_reg_info;
#endif
@ -197,6 +197,9 @@ public:
bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false);
bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false);
bool load_assembly_from(const String &p_name, const String &p_basedir, GDMonoAssembly **r_assembly, bool p_refonly = false);
bool load_assembly_from(const String &p_name, const String &p_basedir, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false);
Error finalize_and_unload_domain(MonoDomain *p_domain);
void initialize();
@ -205,12 +208,14 @@ public:
~GDMono();
};
class GDMonoScopeDomain {
namespace gdmono {
class ScopeDomain {
MonoDomain *prev_domain;
public:
GDMonoScopeDomain(MonoDomain *p_domain) {
ScopeDomain(MonoDomain *p_domain) {
MonoDomain *prev_domain = mono_domain_get();
if (prev_domain != p_domain) {
this->prev_domain = prev_domain;
@ -220,16 +225,36 @@ public:
}
}
~GDMonoScopeDomain() {
~ScopeDomain() {
if (prev_domain)
mono_domain_set(prev_domain, false);
}
};
#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \
GDMonoScopeDomain __gdmono__scope__domain__(m_mono_domain); \
class ScopeExitDomainUnload {
MonoDomain *domain;
public:
ScopeExitDomainUnload(MonoDomain *p_domain) :
domain(p_domain) {
}
~ScopeExitDomainUnload() {
if (domain)
GDMono::get_singleton()->finalize_and_unload_domain(domain);
}
};
} // namespace gdmono
#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \
gdmono::ScopeDomain __gdmono__scope__domain__(m_mono_domain); \
(void)__gdmono__scope__domain__;
#define _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(m_mono_domain) \
gdmono::ScopeExitDomainUnload __gdmono__scope__exit__domain__unload__(m_mono_domain); \
(void)__gdmono__scope__exit__domain__unload__;
class _GodotSharp : public Object {
GDCLASS(_GodotSharp, Object)

View File

@ -46,6 +46,29 @@ bool GDMonoAssembly::in_preload = false;
Vector<String> GDMonoAssembly::search_dirs;
void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config) {
const char *rootdir = mono_assembly_getrootdir();
if (rootdir) {
String framework_dir = String(rootdir).plus_file("mono").plus_file("4.5");
r_search_dirs.push_back(framework_dir);
r_search_dirs.push_back(framework_dir.plus_file("Facades"));
}
if (p_custom_config.length()) {
r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(p_custom_config));
} else {
r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
}
r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
r_search_dirs.push_back(OS::get_singleton()->get_resource_dir());
r_search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
#ifdef TOOLS_ENABLED
r_search_dirs.push_back(GodotSharpDirs::get_data_editor_tools_dir());
#endif
}
void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, void *user_data) {
if (no_search)
@ -93,35 +116,7 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
no_search = true; // Avoid the recursion madness
String path;
GDMonoAssembly *res = NULL;
for (int i = 0; i < search_dirs.size(); i++) {
const String &search_dir = search_dirs[i];
if (has_extension) {
path = search_dir.plus_file(name);
if (FileAccess::exists(path)) {
res = _load_assembly_from(name.get_basename(), path, refonly);
if (res != NULL)
break;
}
} else {
path = search_dir.plus_file(name + ".dll");
if (FileAccess::exists(path)) {
res = _load_assembly_from(name, path, refonly);
if (res != NULL)
break;
}
path = search_dir.plus_file(name + ".exe");
if (FileAccess::exists(path)) {
res = _load_assembly_from(name, path, refonly);
if (res != NULL)
break;
}
}
}
GDMonoAssembly *res = _load_assembly_search(name, search_dirs, refonly);
no_search = false;
@ -130,31 +125,12 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
static _THREAD_LOCAL_(MonoImage *) image_corlib_loading = NULL;
MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly) {
MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, void *user_data, bool refonly) {
(void)user_data; // UNUSED
if (search_dirs.empty()) {
search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
search_dirs.push_back(OS::get_singleton()->get_resource_dir());
search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
#ifdef GD_MONO_EDITOR_ASSEMBLIES_DIR
search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir().plus_file(_MKSTR(GD_MONO_EDITOR_ASSEMBLIES_DIR)).simplify_path());
#endif
const char *rootdir = mono_assembly_getrootdir();
if (rootdir) {
search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5"));
search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5").plus_file("Facades"));
}
if (assemblies_path) {
while (*assemblies_path) {
search_dirs.push_back(*assemblies_path);
++assemblies_path;
}
}
fill_search_dirs(search_dirs);
}
{
@ -188,27 +164,7 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
if (stored_assembly)
return (*stored_assembly)->get_assembly();
String path;
for (int i = 0; i < search_dirs.size(); i++) {
const String &search_dir = search_dirs[i];
if (has_extension) {
path = search_dir.plus_file(name);
if (FileAccess::exists(path)) {
res = _load_assembly_from(name.get_basename(), path, refonly);
if (res != NULL)
break;
}
} else {
path = search_dir.plus_file(name + ".dll");
if (FileAccess::exists(path)) {
res = _load_assembly_from(name, path, refonly);
if (res != NULL)
break;
}
}
}
res = _load_assembly_search("mscorlib.dll", search_dirs, refonly);
}
no_search = false;
@ -217,6 +173,43 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
return res ? res->get_assembly() : NULL;
}
GDMonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly) {
GDMonoAssembly *res = NULL;
String path;
bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe");
for (int i = 0; i < p_search_dirs.size(); i++) {
const String &search_dir = p_search_dirs[i];
if (has_extension) {
path = search_dir.plus_file(p_name);
if (FileAccess::exists(path)) {
res = _load_assembly_from(p_name.get_basename(), path, p_refonly);
if (res != NULL)
return res;
}
} else {
path = search_dir.plus_file(p_name + ".dll");
if (FileAccess::exists(path)) {
res = _load_assembly_from(p_name, path, p_refonly);
if (res != NULL)
return res;
}
path = search_dir.plus_file(p_name + ".exe");
if (FileAccess::exists(path)) {
res = _load_assembly_from(p_name, path, p_refonly);
if (res != NULL)
return res;
}
}
}
return NULL;
}
GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) {
GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
@ -464,19 +457,6 @@ GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class)
return match;
}
GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) {
GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
if (loaded_asm)
return *loaded_asm;
no_search = true;
GDMonoAssembly *res = _load_assembly_from(p_name, p_path, p_refonly);
no_search = false;
return res;
}
GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) {
loaded = false;

View File

@ -102,6 +102,7 @@ class GDMonoAssembly {
static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly);
static GDMonoAssembly *_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly);
static GDMonoAssembly *_load_assembly_search(const String &p_name, const Vector<String> &p_search_dirs, bool p_refonly);
static void _wrap_mono_assembly(MonoAssembly *assembly);
friend class GDMono;
@ -125,7 +126,7 @@ public:
GDMonoClass *get_object_derived_class(const StringName &p_class);
static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly);
static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String());
GDMonoAssembly(const String &p_name, const String &p_path = String());
~GDMonoAssembly();