Merge pull request #22688 from neikeq/lotsofgoodies
Mono: Editor and export template dependencies and fixes
This commit is contained in:
commit
aa85b7ed62
15 changed files with 651 additions and 239 deletions
|
@ -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'
|
||||
)
|
||||
|
|
|
@ -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'])
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue