From 778402af3a544ef40e2a008c2e10ec1036c2815a Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Sat, 20 Feb 2021 02:35:39 +0100 Subject: [PATCH] Port most of the Mono module build to Meson Missing: - Test platform: macOS (Should work but I've not tested yet.) - Finish and test: Windows (Mostly done. Should require a few fixes, but I'm too lazy to reboot right now.) - Finish and test: All non-desktop platforms (Blocked until implemented for the rest of Godot.) - NOTE: For android we were copying shared libs to `#platform/android/java/lib/libs`. How will this work with Meson (out-of-source builds)? !!! Check TODOs and FIXMEs in 'modules/mono/meson.build'. --- meson_options.txt | 14 +- modules/mono/Directory.Build.targets | 15 + .../mono/build_scripts/api_solution_build.py | 80 -- modules/mono/build_scripts/copy_file.py | 40 + modules/mono/build_scripts/cs_glue_version.py | 44 + ...no_reg_utils.py => find_mono_in_winreg.py} | 58 +- modules/mono/build_scripts/find_msbuild.py | 159 ++++ .../mono/build_scripts/gen_cs_glue_version.py | 20 - .../mono/build_scripts/godot_net_sdk_build.py | 45 - .../mono/build_scripts/godot_tools_build.py | 38 - .../mono/build_scripts/list_dir_assemblies.py | 17 + modules/mono/build_scripts/meson.build | 8 + modules/mono/build_scripts/mono_configure.py | 580 ------------ modules/mono/build_scripts/print_env_var.py | 14 + modules/mono/build_scripts/print_file.py | 16 + modules/mono/build_scripts/run_msbuild.py | 161 ++++ .../mono/build_scripts/solution_builder.py | 145 --- modules/mono/config.py | 48 - .../Godot.NET.Sdk/Godot.NET.Sdk.csproj | 29 +- .../GodotTools.BuildLogger.csproj | 4 + .../GodotTools.Core/GodotTools.Core.csproj | 6 + .../GodotTools.IdeMessaging.CLI.csproj | 5 + .../GodotTools.IdeMessaging.csproj | 17 + .../GodotTools.OpenVisualStudio.csproj | 4 + .../GodotTools.ProjectEditor.csproj | 8 + .../GenerateGodotNupkgsVersions.targets | 4 + .../GodotTools.Shared.csproj | 4 + .../GodotTools/GodotTools/GodotTools.csproj | 54 +- modules/mono/editor/bindings_generator.cpp | 2 +- modules/mono/editor/editor_internal_calls.cpp | 2 +- .../GodotSharp/GodotSharp/GodotSharp.csproj | 14 +- .../GodotSharpEditor/GodotSharpEditor.csproj | 14 +- modules/mono/meson.build | 875 ++++++++++++++++++ modules/mono/mono_gd/gd_mono.cpp | 2 + 34 files changed, 1512 insertions(+), 1034 deletions(-) create mode 100644 modules/mono/Directory.Build.targets delete mode 100644 modules/mono/build_scripts/api_solution_build.py create mode 100644 modules/mono/build_scripts/copy_file.py create mode 100644 modules/mono/build_scripts/cs_glue_version.py rename modules/mono/build_scripts/{mono_reg_utils.py => find_mono_in_winreg.py} (51%) create mode 100644 modules/mono/build_scripts/find_msbuild.py delete mode 100644 modules/mono/build_scripts/gen_cs_glue_version.py delete mode 100644 modules/mono/build_scripts/godot_net_sdk_build.py delete mode 100644 modules/mono/build_scripts/godot_tools_build.py create mode 100755 modules/mono/build_scripts/list_dir_assemblies.py create mode 100644 modules/mono/build_scripts/meson.build delete mode 100644 modules/mono/build_scripts/mono_configure.py create mode 100644 modules/mono/build_scripts/print_env_var.py create mode 100644 modules/mono/build_scripts/print_file.py create mode 100644 modules/mono/build_scripts/run_msbuild.py delete mode 100644 modules/mono/build_scripts/solution_builder.py create mode 100644 modules/mono/meson.build diff --git a/meson_options.txt b/meson_options.txt index 66ab49651e34..0d2ec5d36af1 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -11,7 +11,7 @@ option('xaudio2', type: 'boolean', value: false, description: 'Enable the XAudio option('android_neon', type: 'boolean', value: true, description: 'Enable NEON support (armv7 only)') option('custom_modules', type: 'array', value: [], description: 'A list of comma-separated directory paths containing custom modules to build') # add text_server_fb to disabled modules -option('disabled_modules', type: 'array', value: ['mono', 'text_server_fb'], description: 'A list of modules that are to be disabled') +option('disabled_modules', type: 'array', value: ['text_server_fb'], description: 'A list of modules that are to be disabled') option('disable_all_modules', type: 'boolean', value: false, description: 'A boolean that disables ALL modules.') # Advanced options @@ -54,7 +54,15 @@ option('builtin_graphite', type: 'boolean', value: true, description: 'Use the b option('builtin_icu', type: 'boolean', value: true, description: 'Use the built-in icu library') # Mono options -option('mono_glue', type: 'boolean', value: true, description: 'Enable mono glue') + +option('mono_prefix', type: 'string', value: '', description: 'Path to the Mono installation directory for the target platform and architecture') +option('mono_bcl', type: 'string', value: '', description: 'Path to a custom Mono BCL (Base Class Library) directory for the target platform') +option('mono_static', type: 'combo', choices: ['auto', 'true', 'false'], value: 'auto', description: 'Statically link Mono') +option('mono_glue', type: 'boolean', value: true, description: 'Build with the Mono glue sources') +option('build_cil', type: 'boolean', value: true, description: 'Build C# solutions') +option('copy_mono_root', type: 'boolean', value: true, description: 'Make a copy of the Mono installation directory to bundle with the editor') +# TODO: It would be great if this could be detected automatically instead +option('mono_bundles_zlib', type: 'combo', choices: ['auto', 'true', 'false'], value: 'auto', description: 'Specify if the Mono runtime was built with bundled zlib') # Javascript Options option('initial_wasm_memory', type: 'integer', value: 16, description: 'Initial WASM memory (in MiB)') @@ -68,4 +76,4 @@ option('use_safe_heap', type: 'boolean', value: false, description: 'Use Emscrip option('javascript_eval', type: 'boolean', value: true, description: 'Enable JavaScript eval interface') option('threads_enabled', type: 'boolean', value: false, description: 'Enable WebAssembly Threads support (limited browser support)') option('gdnative_enabled', type: 'boolean', value: false, description: 'Enable WebAssembly GDNative support (produces bigger binaries)') -option('use_closure_compiler', type: 'boolean', value: false, description: 'Use closure compiler to minimize JavaScript code') \ No newline at end of file +option('use_closure_compiler', type: 'boolean', value: false, description: 'Use closure compiler to minimize JavaScript code') diff --git a/modules/mono/Directory.Build.targets b/modules/mono/Directory.Build.targets new file mode 100644 index 000000000000..eeecf5650200 --- /dev/null +++ b/modules/mono/Directory.Build.targets @@ -0,0 +1,15 @@ + + + + + + + diff --git a/modules/mono/build_scripts/api_solution_build.py b/modules/mono/build_scripts/api_solution_build.py deleted file mode 100644 index 9abac22df608..000000000000 --- a/modules/mono/build_scripts/api_solution_build.py +++ /dev/null @@ -1,80 +0,0 @@ -# Build the Godot API solution - -import os - -from SCons.Script import Dir - - -def build_api_solution(source, target, env): - # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str - - module_dir = env["module_dir"] - - solution_path = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln") - - build_config = env["solution_build_config"] - - extra_msbuild_args = ["/p:NoWarn=1591"] # Ignore missing documentation warnings - - from .solution_builder import build_solution - - build_solution(env, solution_path, build_config, extra_msbuild_args=extra_msbuild_args) - - # Copy targets - - core_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, "GodotSharp", "bin", build_config)) - editor_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, "GodotSharpEditor", "bin", build_config)) - - dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir)) - - if not os.path.isdir(dst_dir): - assert not os.path.isfile(dst_dir) - os.makedirs(dst_dir) - - def copy_target(target_path): - from shutil import copy - - filename = os.path.basename(target_path) - - src_path = os.path.join(core_src_dir, filename) - if not os.path.isfile(src_path): - src_path = os.path.join(editor_src_dir, filename) - - copy(src_path, target_path) - - for scons_target in target: - copy_target(str(scons_target)) - - -def build(env_mono): - assert env_mono["tools"] - - target_filenames = [ - "GodotSharp.dll", - "GodotSharp.pdb", - "GodotSharp.xml", - "GodotSharpEditor.dll", - "GodotSharpEditor.pdb", - "GodotSharpEditor.xml", - ] - - depend_cmd = [] - - for build_config in ["Debug", "Release"]: - output_dir = Dir("#bin").abspath - editor_api_dir = os.path.join(output_dir, "GodotSharp", "Api", build_config) - - targets = [os.path.join(editor_api_dir, filename) for filename in target_filenames] - - cmd = env_mono.CommandNoCache( - targets, depend_cmd, build_api_solution, module_dir=os.getcwd(), solution_build_config=build_config - ) - env_mono.AlwaysBuild(cmd) - - # Make the Release build of the API solution depend on the Debug build. - # We do this in order to prevent SCons from building them in parallel, - # which can freak out MSBuild. In many cases, one of the builds would - # hang indefinitely requiring a key to be pressed for it to continue. - depend_cmd = cmd - - return depend_cmd diff --git a/modules/mono/build_scripts/copy_file.py b/modules/mono/build_scripts/copy_file.py new file mode 100644 index 000000000000..2bc6ab5d4f80 --- /dev/null +++ b/modules/mono/build_scripts/copy_file.py @@ -0,0 +1,40 @@ +#!/usr/bin/python3 + +import argparse +from shutil import copy2 + + +# Only needed for the stamp file +def touch(path): + import os + with open(path, 'a'): + os.utime(path, None) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='Prints the specified environment variable') + parser.add_argument('src', type=str) + parser.add_argument('dst', type=str) + parser.add_argument('--stamp', type=str) + + args = parser.parse_args() + + # Only check if directory exists if copy fails + + try: + copy2(args.src, args.dst) + except (IOError, FileNotFoundError) as e: + import errno + if isinstance(e, IOError) and e.errno != errno.ENOENT: + raise + import os.path + dst_dir = os.path.dirname(args.dst) + if os.path.isdir(dst_dir): + raise + import os + os.makedirs(dst_dir, exist_ok=True) + copy2(args.src, args.dst) + + if args.stamp: + touch(args.stamp) diff --git a/modules/mono/build_scripts/cs_glue_version.py b/modules/mono/build_scripts/cs_glue_version.py new file mode 100644 index 000000000000..3bdeeb525840 --- /dev/null +++ b/modules/mono/build_scripts/cs_glue_version.py @@ -0,0 +1,44 @@ +#!/usr/bin/python3 + +import argparse +import sys + +# Whatever... +try: + import run_msbuild +except: + from . import run_msbuild + + +def generate_header(version_header_dst: str, deplist: [str]): + import os + + latest_mtime = 0 + for filepath in deplist: + mtime = os.path.getmtime(filepath) + latest_mtime = mtime if mtime > latest_mtime else latest_mtime + + glue_version = int(latest_mtime) # The latest modified time will do for now + + with open(version_header_dst, "w") as version_header: + version_header.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + version_header.write("#ifndef CS_GLUE_VERSION_H\n") + version_header.write("#define CS_GLUE_VERSION_H\n\n") + version_header.write("#define CS_GLUE_VERSION UINT32_C(" + str(glue_version) + ")\n") + version_header.write("\n#endif // CS_GLUE_VERSION_H\n") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='Generate C# glue version header') + + run_msbuild.add_arguments_to_parser(parser) + + args = parser.parse_args() + + result = run_msbuild.run_msbuild_with_args(args) + + if result.exit_code != 0: + sys.exit(result.exit_code) + + generate_header(args.stamp, result.deplist) diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/find_mono_in_winreg.py similarity index 51% rename from modules/mono/build_scripts/mono_reg_utils.py rename to modules/mono/build_scripts/find_mono_in_winreg.py index 0ec7e2f433da..f9764d5c02e6 100644 --- a/modules/mono/build_scripts/mono_reg_utils.py +++ b/modules/mono/build_scripts/find_mono_in_winreg.py @@ -1,3 +1,5 @@ +#!/usr/bin/python3 + import os import platform @@ -62,52 +64,14 @@ def find_mono_root_dir(bits): return "" -def find_msbuild_tools_path_reg(): - import subprocess - - vswhere = os.getenv("PROGRAMFILES(X86)") - if not vswhere: - vswhere = os.getenv("PROGRAMFILES") - vswhere += r"\Microsoft Visual Studio\Installer\vswhere.exe" - - vswhere_args = ["-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"] - - try: - lines = subprocess.check_output([vswhere] + vswhere_args).splitlines() - - for line in lines: - parts = line.decode("utf-8").split(":", 1) - - if len(parts) < 2 or parts[0] != "installationPath": - continue - - val = parts[1].strip() +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser( + description='Attempts to find the Mono install directory in the Windows Registry') + parser.add_argument('cpu_family', choices=['x86', 'x86_64'], type=str) - if not val: - raise ValueError("Value of `installationPath` entry is empty") + args = parser.parse_args() - # Since VS2019, the directory is simply named "Current" - msbuild_dir = os.path.join(val, "MSBuild\\Current\\Bin") - if os.path.isdir(msbuild_dir): - return msbuild_dir - - # Directory name "15.0" is used in VS 2017 - return os.path.join(val, "MSBuild\\15.0\\Bin") - - raise ValueError("Cannot find `installationPath` entry") - except ValueError as e: - print("Error reading output from vswhere: " + e.message) - except OSError: - pass # Fine, vswhere not found - except (subprocess.CalledProcessError, OSError): - pass - - # Try to find 14.0 in the Registry - - try: - subkey = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" - with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey: - value = winreg.QueryValueEx(hKey, "MSBuildToolsPath")[0] - return value - except OSError: - return "" + res = find_mono_root_dir(bits='32' if args.cpu_family == 'x86' else '64') + if res: + print(res) diff --git a/modules/mono/build_scripts/find_msbuild.py b/modules/mono/build_scripts/find_msbuild.py new file mode 100644 index 000000000000..f1ea45a72745 --- /dev/null +++ b/modules/mono/build_scripts/find_msbuild.py @@ -0,0 +1,159 @@ +#!/usr/bin/python3 + +import os +import os.path + + +def find_dotnet_cli(): + import os.path + + if os.name == "nt": + for hint_dir in os.environ["PATH"].split(os.pathsep): + hint_dir = hint_dir.strip('"') + hint_path = os.path.join(hint_dir, "dotnet") + if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK): + return hint_path + if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK): + return hint_path + ".exe" + else: + for hint_dir in os.environ["PATH"].split(os.pathsep): + hint_dir = hint_dir.strip('"') + hint_path = os.path.join(hint_dir, "dotnet") + if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK): + return hint_path + + +def find_msbuild_standalone_windows(): + msbuild_tools_path = find_msbuild_tools_path_reg() + + if msbuild_tools_path: + return os.path.join(msbuild_tools_path, "MSBuild.exe") + + return None + + +def find_msbuild_mono_windows(mono_prefix): + assert(mono_prefix is not None) + + mono_bin_dir = os.path.join(mono_prefix, "bin") + msbuild_mono = os.path.join(mono_bin_dir, "msbuild.bat") + + if os.path.isfile(msbuild_mono): + return msbuild_mono + + return None + + +def find_msbuild_mono_unix(): + import os.path + import sys + + hint_dirs = [] + if sys.platform == "darwin": + hint_dirs[:0] = [ + "/Library/Frameworks/Mono.framework/Versions/Current/bin", + "/usr/local/var/homebrew/linked/mono/bin", + ] + + for hint_dir in hint_dirs: + hint_path = os.path.join(hint_dir, "msbuild") + if os.path.isfile(hint_path): + return hint_path + elif os.path.isfile(hint_path + ".exe"): + return hint_path + ".exe" + + for hint_dir in os.environ["PATH"].split(os.pathsep): + hint_dir = hint_dir.strip('"') + hint_path = os.path.join(hint_dir, "msbuild") + if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK): + return hint_path + if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK): + return hint_path + ".exe" + + return None + + +def find_msbuild_tools_path_reg(): + import subprocess + + vswhere = os.getenv("PROGRAMFILES(X86)") + if not vswhere: + vswhere = os.getenv("PROGRAMFILES") + vswhere += r"\Microsoft Visual Studio\Installer\vswhere.exe" + + vswhere_args = ["-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"] + + try: + lines = subprocess.check_output([vswhere] + vswhere_args).splitlines() + + for line in lines: + parts = line.decode("utf-8").split(":", 1) + + if len(parts) < 2 or parts[0] != "installationPath": + continue + + val = parts[1].strip() + + if not val: + raise ValueError("Value of `installationPath` entry is empty") + + # Since VS2019, the directory is simply named "Current" + msbuild_dir = os.path.join(val, "MSBuild\\Current\\Bin") + if os.path.isdir(msbuild_dir): + return msbuild_dir + + # Directory name "15.0" is used in VS 2017 + return os.path.join(val, "MSBuild\\15.0\\Bin") + + raise ValueError("Cannot find `installationPath` entry") + except ValueError as e: + print("Error reading output from vswhere: " + e.message) + except OSError: + pass # Fine, vswhere not found + except (subprocess.CalledProcessError, OSError): + pass + + +if __name__ == "__main__": + import argparse + import sys + + parser = argparse.ArgumentParser( + description='Prints the specified environment variable') + parser.add_argument('tool', choices=['dotnet_cli', 'msbuild_standalone', 'msbuild_mono'], type=str) + parser.add_argument('--mono-prefix', type=str) + + args = parser.parse_args() + + if args.tool == 'dotnet_cli': + # Find dotnet CLI + dotnet_cli = find_dotnet_cli() + if dotnet_cli: + print(dotnet_cli) + sys.exit(0) + elif args.tool == 'msbuild_standalone': + # Find standalone MSBuild + if os.name == "nt": + msbuild_standalone = find_msbuild_standalone_windows() + if msbuild_standalone: + print(msbuild_standalone) + sys.exit(0) + else: + assert(args.tool == 'msbuild_mono') + + if not args.mono_prefix: + parser.error('\'--mono-prefix\' is required with \'--tool=msbuild_mono\'.') + + # Find Mono's MSBuild + if os.name == "nt": + msbuild_mono = find_msbuild_mono_windows(args.mono_prefix) + if msbuild_mono: + print(msbuild_mono) + sys.exit(0) + else: + msbuild_mono = find_msbuild_mono_unix() + if msbuild_mono: + print(msbuild_mono) + sys.exit(0) + + sys.exit(1) diff --git a/modules/mono/build_scripts/gen_cs_glue_version.py b/modules/mono/build_scripts/gen_cs_glue_version.py deleted file mode 100644 index 98bbb4d9be39..000000000000 --- a/modules/mono/build_scripts/gen_cs_glue_version.py +++ /dev/null @@ -1,20 +0,0 @@ -def generate_header(solution_dir, version_header_dst): - import os - - latest_mtime = 0 - for root, dirs, files in os.walk(solution_dir, topdown=True): - dirs[:] = [d for d in dirs if d not in ["Generated"]] # Ignored generated files - files = [f for f in files if f.endswith(".cs")] - for file in files: - filepath = os.path.join(root, file) - mtime = os.path.getmtime(filepath) - latest_mtime = mtime if mtime > latest_mtime else latest_mtime - - glue_version = int(latest_mtime) # The latest modified time will do for now - - with open(version_header_dst, "w") as version_header: - version_header.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - version_header.write("#ifndef CS_GLUE_VERSION_H\n") - version_header.write("#define CS_GLUE_VERSION_H\n\n") - version_header.write("#define CS_GLUE_VERSION UINT32_C(" + str(glue_version) + ")\n") - version_header.write("\n#endif // CS_GLUE_VERSION_H\n") diff --git a/modules/mono/build_scripts/godot_net_sdk_build.py b/modules/mono/build_scripts/godot_net_sdk_build.py deleted file mode 100644 index 3bfba0f0f67f..000000000000 --- a/modules/mono/build_scripts/godot_net_sdk_build.py +++ /dev/null @@ -1,45 +0,0 @@ -# Build Godot.NET.Sdk solution - -import os - -from SCons.Script import Dir - - -def build_godot_net_sdk(source, target, env): - # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str - - module_dir = env["module_dir"] - - solution_path = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln") - build_config = "Release" - - from .solution_builder import build_solution - - extra_msbuild_args = ["/p:GodotPlatform=" + env["platform"]] - - build_solution(env, solution_path, build_config, extra_msbuild_args) - # No need to copy targets. The Godot.NET.Sdk csproj takes care of copying them. - - -def build(env_mono): - assert env_mono["tools"] - - output_dir = Dir("#bin").abspath - editor_tools_dir = os.path.join(output_dir, "GodotSharp", "Tools") - nupkgs_dir = os.path.join(editor_tools_dir, "nupkgs") - - module_dir = os.getcwd() - - package_version_file = os.path.join( - module_dir, "editor", "Godot.NET.Sdk", "Godot.NET.Sdk", "Godot.NET.Sdk_PackageVersion.txt" - ) - - with open(package_version_file, mode="r") as f: - version = f.read().strip() - - target_filenames = ["Godot.NET.Sdk.%s.nupkg" % version] - - targets = [os.path.join(nupkgs_dir, filename) for filename in target_filenames] - - cmd = env_mono.CommandNoCache(targets, [], build_godot_net_sdk, module_dir=module_dir) - env_mono.AlwaysBuild(cmd) diff --git a/modules/mono/build_scripts/godot_tools_build.py b/modules/mono/build_scripts/godot_tools_build.py deleted file mode 100644 index 3bbbf29d3bd3..000000000000 --- a/modules/mono/build_scripts/godot_tools_build.py +++ /dev/null @@ -1,38 +0,0 @@ -# Build GodotTools solution - -import os - -from SCons.Script import Dir - - -def build_godot_tools(source, target, env): - # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str - - module_dir = env["module_dir"] - - solution_path = os.path.join(module_dir, "editor/GodotTools/GodotTools.sln") - build_config = "Debug" if env["target"] == "debug" else "Release" - - from .solution_builder import build_solution - - extra_msbuild_args = ["/p:GodotPlatform=" + env["platform"]] - - build_solution(env, solution_path, build_config, extra_msbuild_args) - # No need to copy targets. The GodotTools csproj takes care of copying them. - - -def build(env_mono, api_sln_cmd): - assert env_mono["tools"] - - output_dir = Dir("#bin").abspath - editor_tools_dir = os.path.join(output_dir, "GodotSharp", "Tools") - - target_filenames = ["GodotTools.dll"] - - if env_mono["target"] == "debug": - target_filenames += ["GodotTools.pdb"] - - targets = [os.path.join(editor_tools_dir, filename) for filename in target_filenames] - - cmd = env_mono.CommandNoCache(targets, api_sln_cmd, build_godot_tools, module_dir=os.getcwd()) - env_mono.AlwaysBuild(cmd) diff --git a/modules/mono/build_scripts/list_dir_assemblies.py b/modules/mono/build_scripts/list_dir_assemblies.py new file mode 100755 index 000000000000..a35eab2fde6d --- /dev/null +++ b/modules/mono/build_scripts/list_dir_assemblies.py @@ -0,0 +1,17 @@ +#!/usr/bin/python3 + +import argparse +import os.path +from glob import glob + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='List all the assemblies in the specified directory (not recursive)') + parser.add_argument('directory', type=str) + + args = parser.parse_args() + + for assembly in glob(os.path.join(args.directory, "*.dll")): + # Print file base name with extension + print(os.path.basename(assembly)) diff --git a/modules/mono/build_scripts/meson.build b/modules/mono/build_scripts/meson.build new file mode 100644 index 000000000000..eabfdcd1a799 --- /dev/null +++ b/modules/mono/build_scripts/meson.build @@ -0,0 +1,8 @@ +SCRIPT_CS_GLUE_VERSION = find_program('cs_glue_version.py') +SCRIPT_PRINT_ENV_VAR = find_program('print_env_var.py') +SCRIPT_COPY_FILE = find_program('copy_file.py') +SCRIPT_PRINT_FILE = find_program('print_file.py') +SCRIPT_RUN_MSBUILD = find_program('run_msbuild.py') +SCRIPT_LIST_DIR_ASSEMBLIES = find_program('list_dir_assemblies.py') +SCRIPT_FIND_MONO_IN_WINREG = find_program('find_mono_in_winreg.py') +SCRIPT_FIND_MSBUILD = find_program('find_msbuild.py') diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py deleted file mode 100644 index 309abfbff78f..000000000000 --- a/modules/mono/build_scripts/mono_configure.py +++ /dev/null @@ -1,580 +0,0 @@ -import os -import os.path -import subprocess - -from SCons.Script import Dir, Environment - -if os.name == "nt": - from . import mono_reg_utils as monoreg - - -android_arch_dirs = { - "armv7": "armeabi-v7a", - "arm64v8": "arm64-v8a", - "x86": "x86", - "x86_64": "x86_64", -} - - -def get_android_out_dir(env): - return os.path.join( - Dir("#platform/android/java/lib/libs").abspath, - "release" if env["target"] == "release" else "debug", - android_arch_dirs[env["android_arch"]], - ) - - -def find_name_in_dir_files(directory, names, prefixes=[""], extensions=[""]): - for extension in extensions: - if extension and not extension.startswith("."): - extension = "." + extension - for prefix in prefixes: - for curname in names: - if os.path.isfile(os.path.join(directory, prefix + curname + extension)): - return curname - return "" - - -def find_file_in_dir(directory, names, prefixes=[""], extensions=[""]): - for extension in extensions: - if extension and not extension.startswith("."): - extension = "." + extension - for prefix in prefixes: - for curname in names: - filename = prefix + curname + extension - if os.path.isfile(os.path.join(directory, filename)): - return filename - return "" - - -def copy_file(src_dir, dst_dir, src_name, dst_name=""): - from shutil import copy - - src_path = os.path.join(Dir(src_dir).abspath, src_name) - dst_dir = Dir(dst_dir).abspath - - if not os.path.isdir(dst_dir): - os.makedirs(dst_dir) - - if dst_name: - copy(src_path, os.path.join(dst_dir, dst_name)) - else: - copy(src_path, dst_dir) - - -def is_desktop(platform): - return platform in ["windows", "osx", "linuxbsd", "server", "uwp", "haiku"] - - -def is_unix_like(platform): - return platform in ["osx", "linuxbsd", "server", "android", "haiku", "iphone"] - - -def module_supports_tools_on(platform): - return platform not in ["android", "javascript", "iphone"] - - -def find_wasm_src_dir(mono_root): - hint_dirs = [ - os.path.join(mono_root, "src"), - os.path.join(mono_root, "../src"), - ] - for hint_dir in hint_dirs: - if os.path.isfile(os.path.join(hint_dir, "driver.c")): - return hint_dir - return "" - - -def configure(env, env_mono): - bits = env["bits"] - is_android = env["platform"] == "android" - is_javascript = env["platform"] == "javascript" - is_ios = env["platform"] == "iphone" - is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"] - - tools_enabled = env["tools"] - mono_static = env["mono_static"] - copy_mono_root = env["copy_mono_root"] - - mono_prefix = env["mono_prefix"] - mono_bcl = env["mono_bcl"] - - mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"] - - is_travis = os.environ.get("TRAVIS") == "true" - - if is_travis: - # Travis CI may have a Mono version lower than 5.12 - env_mono.Append(CPPDEFINES=["NO_PENDING_EXCEPTIONS"]) - - if is_android and not env["android_arch"] in android_arch_dirs: - raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"]) - - if tools_enabled and not module_supports_tools_on(env["platform"]): - # TODO: - # Android: We have to add the data directory to the apk, concretely the Api and Tools folders. - raise RuntimeError("This module does not currently support building for this platform with tools enabled") - - if is_android and mono_static: - # FIXME: When static linking and doing something that requires libmono-native, we get a dlopen error as 'libmono-native' - # seems to depend on 'libmonosgen-2.0'. Could be fixed by re-directing to '__Internal' with a dllmap or in the dlopen hook. - raise RuntimeError("Statically linking Mono is not currently supported for this platform") - - if not mono_static and (is_javascript or is_ios): - raise RuntimeError("Dynamically linking Mono is not currently supported for this platform") - - if not mono_prefix and (os.getenv("MONO32_PREFIX") or os.getenv("MONO64_PREFIX")): - print( - "WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the" - " 'mono_prefix' SCons parameter instead" - ) - - # Although we don't support building with tools for any platform where we currently use static AOT, - # if these are supported in the future, we won't be using static AOT for them as that would be - # too restrictive for the editor. These builds would probably be made to only use the interpreter. - mono_aot_static = (is_ios and not is_ios_sim) and not env["tools"] - - # Static AOT is only supported on the root domain - mono_single_appdomain = mono_aot_static - - if mono_single_appdomain: - env_mono.Append(CPPDEFINES=["GD_MONO_SINGLE_APPDOMAIN"]) - - if (env["tools"] or env["target"] != "release") and not mono_single_appdomain: - env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"]) - - if env["platform"] == "windows": - mono_root = mono_prefix - - if not mono_root and os.name == "nt": - mono_root = monoreg.find_mono_root_dir(bits) - - if not mono_root: - raise RuntimeError( - "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter" - ) - - print("Found Mono root directory: " + mono_root) - - mono_lib_path = os.path.join(mono_root, "lib") - - env.Append(LIBPATH=mono_lib_path) - env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0")) - - lib_suffixes = [".lib"] - - if not env.msvc: - # MingW supports both '.a' and '.lib' - lib_suffixes.insert(0, ".a") - - if mono_static: - if env.msvc: - mono_static_lib_name = "libmono-static-sgen" - else: - mono_static_lib_name = "libmonosgen-2.0" - - mono_static_lib_file = find_file_in_dir(mono_lib_path, [mono_static_lib_name], extensions=lib_suffixes) - - if not mono_static_lib_file: - raise RuntimeError("Could not find static mono library in: " + mono_lib_path) - - if env.msvc: - env.Append(LINKFLAGS=mono_static_lib_file) - - env.Append(LINKFLAGS="Mincore.lib") - env.Append(LINKFLAGS="msvcrt.lib") - env.Append(LINKFLAGS="LIBCMT.lib") - env.Append(LINKFLAGS="Psapi.lib") - else: - mono_static_lib_file_path = os.path.join(mono_lib_path, mono_static_lib_file) - env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_static_lib_file_path, "-Wl,-no-whole-archive"]) - - env.Append(LIBS=["psapi"]) - env.Append(LIBS=["version"]) - else: - mono_lib_file = find_file_in_dir(mono_lib_path, mono_lib_names, extensions=lib_suffixes) - - if not mono_lib_file: - raise RuntimeError("Could not find mono library in: " + mono_lib_path) - - if env.msvc: - env.Append(LINKFLAGS=mono_lib_file) - else: - mono_lib_file_path = os.path.join(mono_lib_path, mono_lib_file) - env.Append(LINKFLAGS=mono_lib_file_path) - - mono_bin_path = os.path.join(mono_root, "bin") - - mono_dll_file = find_file_in_dir(mono_bin_path, mono_lib_names, prefixes=["", "lib"], extensions=[".dll"]) - - if not mono_dll_file: - raise RuntimeError("Could not find mono shared library in: " + mono_bin_path) - - copy_file(mono_bin_path, "#bin", mono_dll_file) - else: - is_apple = env["platform"] in ["osx", "iphone"] - is_macos = is_apple and not is_ios - - sharedlib_ext = ".dylib" if is_apple else ".so" - - mono_root = mono_prefix - mono_lib_path = "" - mono_so_file = "" - - if not mono_root and (is_android or is_javascript or is_ios): - raise RuntimeError( - "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter" - ) - - if not mono_root and is_macos: - # Try with some known directories under OSX - hint_dirs = ["/Library/Frameworks/Mono.framework/Versions/Current", "/usr/local/var/homebrew/linked/mono"] - for hint_dir in hint_dirs: - if os.path.isdir(hint_dir): - mono_root = hint_dir - break - - # We can't use pkg-config to link mono statically, - # but we can still use it to find the mono root directory - if not mono_root and mono_static: - mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext) - if not mono_root: - raise RuntimeError( - "Building with mono_static=yes, but failed to find the mono prefix with pkg-config; " - + "specify one manually with the 'mono_prefix' SCons parameter" - ) - - if is_ios and not is_ios_sim: - env_mono.Append(CPPDEFINES=["IOS_DEVICE"]) - - if mono_root: - print("Found Mono root directory: " + mono_root) - - mono_lib_path = os.path.join(mono_root, "lib") - - env.Append(LIBPATH=[mono_lib_path]) - env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0")) - - mono_lib = find_name_in_dir_files(mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[".a"]) - - if not mono_lib: - raise RuntimeError("Could not find mono library in: " + mono_lib_path) - - env_mono.Append(CPPDEFINES=["_REENTRANT"]) - - if mono_static: - if not is_javascript: - env.Append(LINKFLAGS=["-rdynamic"]) - - mono_lib_file = os.path.join(mono_lib_path, "lib" + mono_lib + ".a") - - if is_apple: - if is_macos: - env.Append(LINKFLAGS=["-Wl,-force_load," + mono_lib_file]) - else: - arch = env["arch"] - - def copy_mono_lib(libname_wo_ext): - copy_file( - mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.iphone.%s.a" % (libname_wo_ext, arch) - ) - - # Copy Mono libraries to the output folder. These are meant to be bundled with - # the export templates and added to the Xcode project when exporting a game. - copy_mono_lib("lib" + mono_lib) - copy_mono_lib("libmono-native") - copy_mono_lib("libmono-profiler-log") - - if not is_ios_sim: - copy_mono_lib("libmono-ee-interp") - copy_mono_lib("libmono-icall-table") - copy_mono_lib("libmono-ilgen") - else: - assert is_desktop(env["platform"]) or is_android or is_javascript - env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_lib_file, "-Wl,-no-whole-archive"]) - - if is_javascript: - env.Append(LIBS=["mono-icall-table", "mono-native", "mono-ilgen", "mono-ee-interp"]) - - wasm_src_dir = os.path.join(mono_root, "src") - if not os.path.isdir(wasm_src_dir): - raise RuntimeError("Could not find mono wasm src directory") - - # Ideally this should be defined only for 'driver.c', but I can't fight scons for another 2 hours - env_mono.Append(CPPDEFINES=["CORE_BINDINGS"]) - - env_mono.add_source_files( - env.modules_sources, - [ - os.path.join(wasm_src_dir, "driver.c"), - os.path.join(wasm_src_dir, "zlib-helper.c"), - os.path.join(wasm_src_dir, "corebindings.c"), - ], - ) - - env.Append( - LINKFLAGS=[ - "--js-library", - os.path.join(wasm_src_dir, "library_mono.js"), - "--js-library", - os.path.join(wasm_src_dir, "binding_support.js"), - "--js-library", - os.path.join(wasm_src_dir, "dotnet_support.js"), - ] - ) - else: - env.Append(LIBS=[mono_lib]) - - if is_macos: - env.Append(LIBS=["iconv", "pthread"]) - elif is_android: - pass # Nothing - elif is_ios: - pass # Nothing, linking is delegated to the exported Xcode project - elif is_javascript: - env.Append(LIBS=["m", "rt", "dl", "pthread"]) - else: - env.Append(LIBS=["m", "rt", "dl", "pthread"]) - - if not mono_static: - mono_so_file = find_file_in_dir( - mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext] - ) - - if not mono_so_file: - raise RuntimeError("Could not find mono shared library in: " + mono_lib_path) - else: - assert not mono_static - - # TODO: Add option to force using pkg-config - print("Mono root directory not found. Using pkg-config instead") - - env.ParseConfig("pkg-config monosgen-2 --libs") - env_mono.ParseConfig("pkg-config monosgen-2 --cflags") - - tmpenv = Environment() - tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH")) - tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L") - - for hint_dir in tmpenv["LIBPATH"]: - file_found = find_file_in_dir(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext]) - if file_found: - mono_lib_path = hint_dir - mono_so_file = file_found - break - - if not mono_so_file: - raise RuntimeError("Could not find mono shared library in: " + str(tmpenv["LIBPATH"])) - - if not mono_static: - libs_output_dir = get_android_out_dir(env) if is_android else "#bin" - copy_file(mono_lib_path, libs_output_dir, mono_so_file) - - if not tools_enabled: - if is_desktop(env["platform"]): - if not mono_root: - mono_root = ( - subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip() - ) - - make_template_dir(env, mono_root) - elif is_android: - # Compress Android Mono Config - from . import make_android_mono_config - - module_dir = os.getcwd() - config_file_path = os.path.join(module_dir, "build_scripts", "mono_android_config.xml") - make_android_mono_config.generate_compressed_config(config_file_path, "mono_gd/") - - # Copy the required shared libraries - copy_mono_shared_libs(env, mono_root, None) - elif is_javascript: - pass # No data directory for this platform - elif is_ios: - pass # No data directory for this platform - - 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: - # Only supported for editor builds. - copy_mono_root_files(env, mono_root, mono_bcl) - - -def make_template_dir(env, mono_root): - from shutil import rmtree - - platform = env["platform"] - target = env["target"] - - template_dir_name = "" - - assert is_desktop(platform) - - template_dir_name = "data.mono.%s.%s.%s" % (platform, env["bits"], target) - - output_dir = Dir("#bin").abspath - template_dir = os.path.join(output_dir, template_dir_name) - - template_mono_root_dir = os.path.join(template_dir, "Mono") - - if os.path.isdir(template_mono_root_dir): - rmtree(template_mono_root_dir) # Clean first - - # Copy etc/mono/ - - template_mono_config_dir = os.path.join(template_mono_root_dir, "etc", "mono") - copy_mono_etc_dir(mono_root, template_mono_config_dir, platform) - - # Copy the required shared libraries - - copy_mono_shared_libs(env, mono_root, template_mono_root_dir) - - -def copy_mono_root_files(env, mono_root, mono_bcl): - from glob import glob - from shutil import copy - from shutil import rmtree - - if not mono_root: - raise RuntimeError("Mono installation directory not found") - - output_dir = Dir("#bin").abspath - editor_mono_root_dir = os.path.join(output_dir, "GodotSharp", "Mono") - - if os.path.isdir(editor_mono_root_dir): - rmtree(editor_mono_root_dir) # Clean first - - # Copy etc/mono/ - - editor_mono_config_dir = os.path.join(editor_mono_root_dir, "etc", "mono") - copy_mono_etc_dir(mono_root, editor_mono_config_dir, env["platform"]) - - # Copy the required shared libraries - - copy_mono_shared_libs(env, mono_root, editor_mono_root_dir) - - # Copy framework assemblies - - mono_framework_dir = mono_bcl or os.path.join(mono_root, "lib", "mono", "4.5") - mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades") - - 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")) - if os.path.isdir(os.path.join(mono_etc_dir, "mconfig")): - copy_tree(os.path.join(mono_etc_dir, "mconfig"), os.path.join(target_mono_config_dir, "mconfig")) - - for file in glob(os.path.join(mono_etc_dir, "*")): - if os.path.isfile(file): - copy(file, target_mono_config_dir) - - -def copy_mono_shared_libs(env, mono_root, target_mono_root_dir): - from shutil import copy - - def copy_if_exists(src, dst): - if os.path.isfile(src): - copy(src, dst) - - platform = env["platform"] - - if platform == "windows": - src_mono_bin_dir = os.path.join(mono_root, "bin") - target_mono_bin_dir = os.path.join(target_mono_root_dir, "bin") - - if not os.path.isdir(target_mono_bin_dir): - os.makedirs(target_mono_bin_dir) - - mono_posix_helper_file = find_file_in_dir( - src_mono_bin_dir, ["MonoPosixHelper"], prefixes=["", "lib"], extensions=[".dll"] - ) - copy( - os.path.join(src_mono_bin_dir, mono_posix_helper_file), - os.path.join(target_mono_bin_dir, "MonoPosixHelper.dll"), - ) - - # For newer versions - btls_dll_path = os.path.join(src_mono_bin_dir, "libmono-btls-shared.dll") - if os.path.isfile(btls_dll_path): - copy(btls_dll_path, target_mono_bin_dir) - else: - target_mono_lib_dir = ( - get_android_out_dir(env) if platform == "android" else os.path.join(target_mono_root_dir, "lib") - ) - - if not os.path.isdir(target_mono_lib_dir): - os.makedirs(target_mono_lib_dir) - - lib_file_names = [] - if platform == "osx": - lib_file_names = [ - lib_name + ".dylib" - for lib_name in ["libmono-btls-shared", "libmono-native-compat", "libMonoPosixHelper"] - ] - elif is_unix_like(platform): - lib_file_names = [ - lib_name + ".so" - for lib_name in [ - "libmono-btls-shared", - "libmono-ee-interp", - "libmono-native", - "libMonoPosixHelper", - "libmono-profiler-aot", - "libmono-profiler-coverage", - "libmono-profiler-log", - "libMonoSupportW", - ] - ] - - for lib_file_name in lib_file_names: - copy_if_exists(os.path.join(mono_root, "lib", lib_file_name), target_mono_lib_dir) - - -def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext): - tmpenv = Environment() - tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH")) - tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L") - for hint_dir in tmpenv["LIBPATH"]: - name_found = find_name_in_dir_files(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext]) - if name_found and os.path.isdir(os.path.join(hint_dir, "..", "include", "mono-2.0")): - return os.path.join(hint_dir, "..") - return "" diff --git a/modules/mono/build_scripts/print_env_var.py b/modules/mono/build_scripts/print_env_var.py new file mode 100644 index 000000000000..6dbe1139c535 --- /dev/null +++ b/modules/mono/build_scripts/print_env_var.py @@ -0,0 +1,14 @@ +#!/usr/bin/python3 + +import argparse +from os import environ + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='Prints the specified environment variable') + parser.add_argument('var_name', type=str) + + args = parser.parse_args() + + print(environ[args.var_name]) diff --git a/modules/mono/build_scripts/print_file.py b/modules/mono/build_scripts/print_file.py new file mode 100644 index 000000000000..47b47e4788e7 --- /dev/null +++ b/modules/mono/build_scripts/print_file.py @@ -0,0 +1,16 @@ +#!/usr/bin/python3 + +import argparse +import shutil +import sys + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description='Prints the file contents') + parser.add_argument('file', type=str) + + args = parser.parse_args() + + with open(args.file, 'r') as file: + shutil.copyfileobj(file, sys.stdout) diff --git a/modules/mono/build_scripts/run_msbuild.py b/modules/mono/build_scripts/run_msbuild.py new file mode 100644 index 000000000000..03ca05ae667c --- /dev/null +++ b/modules/mono/build_scripts/run_msbuild.py @@ -0,0 +1,161 @@ +#!/usr/bin/python3 + +import argparse +import subprocess +import sys +import os +import os.path +import shlex +from dataclasses import dataclass + + +@dataclass +class MSBuildResult: + exit_code: int = 0 + deplist: [str] = None + + +@dataclass +class ToolsLocation: + dotnet_cli: str = '' + msbuild_standalone: str = '' + msbuild_mono: str = '' + mono_bin_dir: str = '' + + +def read_file_to_deplist(file: str) -> [str]: + with open(file, 'r', encoding='utf-8-sig') as f: + files = f.readlines() + + # Strip entries + files = [f.strip() for f in files] + # Remove empty entries + files = filter(None, files) + # Remove duplicate entries + files = list(dict.fromkeys(files)) + + return files + + +def deplist_to_rules(output: str, deplist: [str]) -> str: + quoted_deplist = [f.replace(' ', r'\ ') for f in deplist] + return '%s: %s\n' % (output, ' '.join(quoted_deplist)) + + +def run_msbuild(tools: ToolsLocation, sln: str, depfile: str, + stamp: str, targets: [str], msbuild_args: [str] = []) -> MSBuildResult: + using_msbuild_mono = False + + # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild + if tools.dotnet_cli: + args = [tools.dotnet_cli, 'msbuild'] + elif tools.msbuild_standalone: + args = [tools.msbuild_standalone] + elif tools.msbuild_mono: + args = [tools.msbuild_mono] + using_msbuild_mono = True + else: + raise RuntimeError('Path to MSBuild or dotnet CLI not provided.') + + args += [sln] + + if depfile: + deplist_file = os.path.abspath(depfile) + '.list.txt' + targets += ['WriteMesonDepList'] + msbuild_args += ['/p:MesonDepListPath=' + deplist_file] + + if os.path.exists(deplist_file): + os.remove(deplist_file) # Raises IsADirectoryError if depfile is a directory + + if len(targets) > 0: + args += ['/t:' + ','.join(targets)] + + if len(msbuild_args) > 0: + args += msbuild_args + + print('Running MSBuild: ', ' '.join(shlex.quote(arg) for arg in args), flush=True) + + result = MSBuildResult() + + msbuild_env = os.environ.copy() + + # Needed when running from Developer Command Prompt for VS + if "PLATFORM" in msbuild_env: + del msbuild_env["PLATFORM"] + + if using_msbuild_mono: + # The (Csc/Vbc/Fsc)ToolExe environment variables are required when + # building with Mono's MSBuild. They must point to the batch files + # in Mono's bin directory to make sure they are executed with Mono. + msbuild_env.update({ + "CscToolExe": os.path.join(tools.mono_bin_dir, "csc.bat"), + "VbcToolExe": os.path.join(tools.mono_bin_dir, "vbc.bat"), + "FscToolExe": os.path.join(tools.mono_bin_dir, "fsharpc.bat"), + }) + + result.exit_code = subprocess.call(args, env=msbuild_env) + + if depfile and result.exit_code == 0: + result.deplist = read_file_to_deplist(deplist_file) + + deprules = deplist_to_rules(stamp, result.deplist) + save = True + + if os.path.exists(depfile): + with open(depfile, 'r') as f: + prev_deprules = f.read() + save = deprules.strip() != prev_deprules.strip() + + if save: + with open(depfile, 'w') as f: + f.write(deprules) + + return result + + +def run_msbuild_with_args(args) -> MSBuildResult: + msbuild_args = args.msbuild_args or [] + targets = args.targets or [] + + tools = ToolsLocation( + dotnet_cli=args.tool_dotnet_cli or '', + msbuild_standalone=args.tool_msbuild_standalone or '', + msbuild_mono=args.tool_msbuild_mono or '', + mono_bin_dir=args.mono_bin_dir or '') + + return run_msbuild(tools, args.solution, args.depfile, args.stamp, targets, msbuild_args) + + +# Only needed for the stamp file +def touch(path): + with open(path, 'a'): + os.utime(path, None) + + +def add_arguments_to_parser(parser: argparse.ArgumentParser): + parser.add_argument('solution', type=str) + parser.add_argument('--tool-dotnet-cli', type=str) + parser.add_argument('--tool-msbuild-standalone', type=str) + parser.add_argument('--tool-msbuild-mono', type=str) + parser.add_argument('--mono-bin-dir', type=str) + parser.add_argument('--depfile', type=str, required=True) + # TODO: stamp is only a thing while we're stuck with https://github.com/mesonbuild/meson/issues/2320 + parser.add_argument('--stamp', type=str, required=True) + parser.add_argument('--targets', nargs='+') + parser.add_argument('msbuild_args', nargs=argparse.REMAINDER) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='Run MSBuild') + + add_arguments_to_parser(parser) + + args = parser.parse_args() + + result = run_msbuild_with_args(args) + + if result.exit_code == 0: + touch(args.stamp) + + sys.exit(result.exit_code) diff --git a/modules/mono/build_scripts/solution_builder.py b/modules/mono/build_scripts/solution_builder.py deleted file mode 100644 index 6a621c3c8b4b..000000000000 --- a/modules/mono/build_scripts/solution_builder.py +++ /dev/null @@ -1,145 +0,0 @@ -import os - - -verbose = False - - -def find_dotnet_cli(): - import os.path - - if os.name == "nt": - for hint_dir in os.environ["PATH"].split(os.pathsep): - hint_dir = hint_dir.strip('"') - hint_path = os.path.join(hint_dir, "dotnet") - if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK): - return hint_path - if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK): - return hint_path + ".exe" - else: - for hint_dir in os.environ["PATH"].split(os.pathsep): - hint_dir = hint_dir.strip('"') - hint_path = os.path.join(hint_dir, "dotnet") - if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK): - return hint_path - - -def find_msbuild_unix(): - import os.path - import sys - - hint_dirs = [] - if sys.platform == "darwin": - hint_dirs[:0] = [ - "/Library/Frameworks/Mono.framework/Versions/Current/bin", - "/usr/local/var/homebrew/linked/mono/bin", - ] - - for hint_dir in hint_dirs: - hint_path = os.path.join(hint_dir, "msbuild") - if os.path.isfile(hint_path): - return hint_path - elif os.path.isfile(hint_path + ".exe"): - return hint_path + ".exe" - - for hint_dir in os.environ["PATH"].split(os.pathsep): - hint_dir = hint_dir.strip('"') - hint_path = os.path.join(hint_dir, "msbuild") - if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK): - return hint_path - if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK): - return hint_path + ".exe" - - return None - - -def find_msbuild_windows(env): - from .mono_reg_utils import find_mono_root_dir, find_msbuild_tools_path_reg - - mono_root = env["mono_prefix"] or find_mono_root_dir(env["bits"]) - - if not mono_root: - raise RuntimeError("Cannot find mono root directory") - - mono_bin_dir = os.path.join(mono_root, "bin") - msbuild_mono = os.path.join(mono_bin_dir, "msbuild.bat") - - msbuild_tools_path = find_msbuild_tools_path_reg() - - if msbuild_tools_path: - return (os.path.join(msbuild_tools_path, "MSBuild.exe"), {}) - - if os.path.isfile(msbuild_mono): - # The (Csc/Vbc/Fsc)ToolExe environment variables are required when - # building with Mono's MSBuild. They must point to the batch files - # in Mono's bin directory to make sure they are executed with Mono. - mono_msbuild_env = { - "CscToolExe": os.path.join(mono_bin_dir, "csc.bat"), - "VbcToolExe": os.path.join(mono_bin_dir, "vbc.bat"), - "FscToolExe": os.path.join(mono_bin_dir, "fsharpc.bat"), - } - return (msbuild_mono, mono_msbuild_env) - - return None - - -def run_command(command, args, env_override=None, name=None): - def cmd_args_to_str(cmd_args): - return " ".join([arg if not " " in arg else '"%s"' % arg for arg in cmd_args]) - - args = [command] + args - - if name is None: - name = os.path.basename(command) - - if verbose: - print("Running '%s': %s" % (name, cmd_args_to_str(args))) - - import subprocess - - try: - if env_override is None: - subprocess.check_call(args) - else: - subprocess.check_call(args, env=env_override) - except subprocess.CalledProcessError as e: - raise RuntimeError("'%s' exited with error code: %s" % (name, e.returncode)) - - -def build_solution(env, solution_path, build_config, extra_msbuild_args=[]): - global verbose - verbose = env["verbose"] - - msbuild_env = os.environ.copy() - - # Needed when running from Developer Command Prompt for VS - if "PLATFORM" in msbuild_env: - del msbuild_env["PLATFORM"] - - msbuild_args = [] - - dotnet_cli = find_dotnet_cli() - - if dotnet_cli: - msbuild_path = dotnet_cli - msbuild_args += ["msbuild"] # `dotnet msbuild` command - else: - # Find MSBuild - if os.name == "nt": - msbuild_info = find_msbuild_windows(env) - if msbuild_info is None: - raise RuntimeError("Cannot find MSBuild executable") - msbuild_path = msbuild_info[0] - msbuild_env.update(msbuild_info[1]) - else: - msbuild_path = find_msbuild_unix() - if msbuild_path is None: - raise RuntimeError("Cannot find MSBuild executable") - - print("MSBuild path: " + msbuild_path) - - # Build solution - - msbuild_args += [solution_path, "/restore", "/t:Build", "/p:Configuration=" + build_config] - msbuild_args += extra_msbuild_args - - run_command(msbuild_path, msbuild_args, env_override=msbuild_env, name="msbuild") diff --git a/modules/mono/config.py b/modules/mono/config.py index 4bce6f363ae3..7a545df4850c 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -7,54 +7,6 @@ def can_build(env: dict) -> bool: return env.platform in supported_platforms -# def configure(env): -# platform = env["platform"] - -# if platform not in supported_platforms: -# raise RuntimeError("This module does not currently support building for this platform") - -# env.use_ptrcall = True -# env.add_module_version_string("mono") - -# from SCons.Script import BoolVariable, PathVariable, Variables, Help - -# default_mono_static = platform in ["iphone", "javascript"] -# default_mono_bundles_zlib = platform in ["javascript"] - -# envvars = Variables() -# envvars.Add( -# PathVariable( -# "mono_prefix", -# "Path to the Mono installation directory for the target platform and architecture", -# "", -# PathVariable.PathAccept, -# ) -# ) -# envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static)) -# envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True)) -# envvars.Add(BoolVariable("build_cil", "Build C# solutions", True)) -# envvars.Add( -# BoolVariable("copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True) -# ) - -# # TODO: It would be great if this could be detected automatically instead -# envvars.Add( -# BoolVariable( -# "mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib -# ) -# ) - -# envvars.Update(env) -# Help(envvars.GenerateHelpText(env)) - -# if env["mono_bundles_zlib"]: -# # Mono may come with zlib bundled for WASM or on newer version when built with MinGW. -# print("This Mono runtime comes with zlib bundled. Disabling 'builtin_zlib'...") -# env["builtin_zlib"] = False -# thirdparty_zlib_dir = "#thirdparty/zlib/" -# env.Prepend(CPPPATH=[thirdparty_zlib_dir]) - - def get_doc_classes() -> [str]: return [ "CSharpScript", diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj index 8304d9e3212f..b0bd2399c802 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj @@ -12,6 +12,7 @@ MSBuildSdk MSBuildSdk true + $(ProjectDir)Godot.NET.Sdk_PackageVersion.txt @@ -19,12 +20,27 @@ $(GenerateNuspecDependsOn);SetNuSpecProperties - + + + + + - $([System.IO.File]::ReadAllText('$(ProjectDir)Godot.NET.Sdk_PackageVersion.txt').Trim()) + $([System.IO.File]::ReadAllText('$(GodotNETSdkPackageVersionFile)').Trim()) + + + + $(MesonBuildDir)\GodotSharp\Tools\nupkgs\ + + False + False + + @@ -38,13 +54,4 @@ - - - - $(SolutionDir)\..\..\..\..\ - $(GodotSourceRootPath)\bin\GodotSharp\ - - - diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj index 0afec970c648..1d5fae5d8d48 100644 --- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj @@ -3,8 +3,12 @@ {6CE9A984-37B1-4F8A-8FE9-609F05F071B3} netstandard2.0 7.2 + false + + + diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj index d6d8962f90e5..66513914f9fd 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj @@ -3,5 +3,11 @@ {639E48BD-44E5-4091-8EDD-22D36DC0768D} netstandard2.0 7.2 + false + + + + + diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj index ae78da27bcb9..23678d07f689 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj @@ -4,6 +4,7 @@ Exe net472 7.2 + false @@ -14,4 +15,8 @@ + + + + diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj index dad6b9ae7a2b..a657da03011a 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj @@ -2,6 +2,7 @@ {92600954-25F0-4291-8E11-1FEE9FC4BE20} netstandard2.0 + false 7.2 GodotTools.IdeMessaging 1.1.1 @@ -21,4 +22,20 @@ A client using this library is only compatible with servers of the same major ve + + + + + + + + + + + + + + + + diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj index 5b3ed0b1b7a8..0a168be07c38 100644 --- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj @@ -4,9 +4,13 @@ Exe net472 7.2 + false + + + diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj index 37123ba2b220..066300e49746 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj @@ -3,6 +3,7 @@ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984} net472 7.2 + false @@ -29,4 +30,11 @@ + + + + + + + diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets index 1d382dcb4375..a4d7bb49540d 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets +++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets @@ -1,6 +1,10 @@ + + + + $(SolutionDir)..\Godot.NET.Sdk\Godot.NET.Sdk\Godot.NET.Sdk_PackageVersion.txt diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj index 3bc1698c153d..8fb27a53436b 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj @@ -1,6 +1,10 @@ netstandard2.0 + false + + + diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index 3f14629b112d..b2fe5e7eff02 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -4,14 +4,12 @@ net472 7.2 Debug - $(SolutionDir)/../../../../ - $(GodotSourceRootPath)/bin/GodotSharp - $(GodotOutputDataDir)/Api/$(GodotApiConfiguration) + false - + - $(GodotOutputDataDir)/Tools + $(MesonBuildDir)\GodotSharp\Tools False @@ -19,14 +17,12 @@ - - $(GodotApiAssembliesDir)/GodotSharp.dll + False - - - $(GodotApiAssembliesDir)/GodotSharpEditor.dll + + False - + @@ -36,4 +32,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 59ce617990c4..a67ab89e15b8 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -40,7 +40,7 @@ #include "core/os/os.h" #include "core/string/ucaps.h" -#include "../glue/cs_glue_version.gen.h" +#include "../cs_glue_version.gen.h" #include "../godotsharp_defs.h" #include "../mono_gd/gd_mono_marshal.h" #include "../utils/path_utils.h" diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index 667e4a38795c..2d20c45969f6 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -43,7 +43,7 @@ #include "main/main.h" #include "../csharp_script.h" -#include "../glue/cs_glue_version.gen.h" +#include "../cs_glue_version.gen.h" #include "../godotsharp_dirs.h" #include "../mono_gd/gd_mono_marshal.h" #include "../utils/osx_utils.h" diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 86a16c17f1c9..d741ba38bb3e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -4,10 +4,17 @@ bin/$(Configuration) false Godot - netstandard2.1 + netstandard2.0 $(OutputPath)/$(AssemblyName).xml false + + + + $(MesonBuildDir)\GodotSharp\Api\$(Configuration)\ + + False + $(DefineConstants);GODOT @@ -67,5 +74,8 @@ We can't use wildcards as there may be undesired old files still hanging around. Fortunately code completion, go to definition and such still work. --> - + + + + diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj index a8c4ba96b539..6c9f753e7726 100644 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj @@ -4,10 +4,17 @@ bin/$(Configuration) false Godot - netstandard2.1 + netstandard2.0 $(OutputPath)/$(AssemblyName).xml false + + + + $(MesonBuildDir)\GodotSharp\Api\$(Configuration)\ + + False + $(DefineConstants);GODOT @@ -22,5 +29,8 @@ We can't use wildcards as there may be undesired old files still hanging around. Fortunately code completion, go to definition and such still work. --> - + + + + diff --git a/modules/mono/meson.build b/modules/mono/meson.build new file mode 100644 index 000000000000..2c28b17210b2 --- /dev/null +++ b/modules/mono/meson.build @@ -0,0 +1,875 @@ + +subdir('build_scripts') + +_module_mono_srcs = files() +_module_mono_cpp_args = [] + +################################################################################ +# General sources +################################################################################ + +_module_mono_srcs += files([ + 'class_db_api_json.cpp', + 'csharp_script.cpp', + 'godotsharp_dirs.cpp', + 'managed_callable.cpp', + 'mono_gc_handle.cpp', + 'register_types.cpp', + 'signal_awaiter_utils.cpp', + 'mono_gd/gd_mono_assembly.cpp', + 'mono_gd/gd_mono_cache.cpp', + 'mono_gd/gd_mono_class.cpp', + 'mono_gd/gd_mono_field.cpp', + 'mono_gd/gd_mono_internals.cpp', + 'mono_gd/gd_mono_log.cpp', + 'mono_gd/gd_mono_marshal.cpp', + 'mono_gd/gd_mono_method.cpp', + 'mono_gd/gd_mono_property.cpp', + 'mono_gd/gd_mono_utils.cpp', + 'mono_gd/gd_mono_wasm_m2n.cpp', + 'mono_gd/gd_mono.cpp', + 'mono_gd/managed_type.cpp', + 'utils/mono_reg_utils.cpp', + 'utils/osx_utils.cpp', + 'utils/path_utils.cpp', + 'utils/string_utils.cpp', + 'glue/base_object_glue.cpp', + 'glue/collections_glue.cpp', + 'glue/gd_glue.cpp', + 'glue/nodepath_glue.cpp', + 'glue/rid_glue.cpp', + 'glue/scene_tree_glue.cpp', + 'glue/string_glue.cpp', + 'glue/string_name_glue.cpp', +]) + +################################################################################ +# Platform-specific sources +################################################################################ + +if PLATFORM == 'android' + _module_mono_srcs += files([ + 'mono_gd/support/android_support.cpp', + ]) +elif PLATFORM in ['osx', 'iphone'] + _module_mono_srcs += files([ + 'mono_gd/support/ios_support.mm', + ]) +endif + +################################################################################ +# Tools sources +################################################################################ + +if get_option('tools') + _module_mono_srcs += files([ + 'editor/bindings_generator.cpp', + 'editor/code_completion.cpp', + 'editor/editor_internal_calls.cpp', + 'editor/godotsharp_export.cpp', + 'editor/script_class_parser.cpp', + ]) +endif + +################################################################################ +# Conditionally define GD_MONO_HOT_RELOAD +################################################################################ + +if get_option('tools') or IS_DEBUG_BUILD + _module_mono_cpp_args += ['-DGD_MONO_HOT_RELOAD'] +endif + +################################################################################ +# Variables +################################################################################ + +fs = import('fs') + +_desktop_platforms = ['windows', 'osx', 'linuxbsd', 'server', 'uwp', 'haiku'] +_unix_like_platforms = ['osx', 'linuxbsd', 'server', 'android', 'haiku', 'iphone'] + +_module_tools_unsupported_platforms = ['android', 'javascript', 'iphone'] + +################################################################################ +# Find Mono +################################################################################ + +mono_prefix = get_option('mono_prefix') + +if mono_prefix != '' + mono_bin_dir = mono_prefix / 'bin' + mono_etc_dir = mono_prefix / 'etc' + mono_include_dir = mono_prefix / 'include/mono-2.0' + mono_lib_dir = mono_prefix / 'lib' + + if not fs.is_dir(mono_etc_dir / 'mono') + # Support specifying the '/usr' mono prefix manually. + if fs.is_dir(mono_prefix / '../etc/mono') + mono_etc_dir = mono_prefix / '../etc' + elif fs.is_dir(mono_prefix / 'local/etc/mono') + mono_etc_dir = mono_prefix / 'local/etc' + else + error('Cannot find \'etc\' directory for the specified mono prefix.') + endif + endif +endif + +# Auto-detect Mono location +if mono_prefix == '' + message('The \'mono_prefix\' Meson option was not specified. Attempting to auto-detect Mono\'s location...') + + if PLATFORM == 'windows' + if build_machine.system() == 'windows' + mono_prefix = run_command(SCRIPT_FIND_MONO_IN_WINREG, host_machine.cpu_family()).stdout().strip() + if mono_prefix == '' + error('Could not find Mono in the Windows Registry.') + endif + + mono_bin_dir = mono_prefix / 'bin' + mono_etc_dir = mono_prefix / 'etc' + mono_include_dir = mono_prefix / 'include/mono-2.0' + mono_lib_dir = mono_prefix / 'lib' + + message('Found Mono prefix in the Windows Registry: ' + mono_prefix) + else + error('The \'mono_prefix\' Meson option was not specified.') + endif + else + mono_pkgconfig_dep = dependency('mono-2', method: 'pkg-config', required: false) + if not mono_pkgconfig_dep.found() + error('Could not find Mono via pkg-config.') + endif + + mono_prefix = zdep.get_variable(pkgconfig: 'prefix', '') + if mono_prefix == '' + error('Could not find pkg-config \'prefix\' variable.') + endif + + mono_pkgconfig_sysconfdir = zdep.get_variable(pkgconfig: 'sysconfdir', '') + mono_pkgconfig_includedir = zdep.get_variable(pkgconfig: 'includedir', '') + mono_pkgconfig_libdir = zdep.get_variable(pkgconfig: 'libdir', '') + + mono_bin_dir = mono_prefix / 'bin' + mono_etc_dir = mono_pkgconfig_sysconfdir != '' ? mono_pkgconfig_sysconfdir : mono_prefix / 'etc' + mono_include_dir = mono_pkgconfig_includedir != '' ? mono_pkgconfig_includedir : mono_prefix / 'include' + mono_lib_dir = mono_pkgconfig_libdir != '' ? mono_pkgconfig_libdir : mono_prefix / 'lib' + + message('Found Mono prefix via pkg-config: ' + mono_prefix) + endif +endif + +################################################################################ +# Find Mono BCL +################################################################################ + +mono_bcl = get_option('mono_bcl') +if mono_bcl == '' + mono_bcl = mono_lib_dir / 'mono/4.5' +endif + +################################################################################ +# Find MSBuild or dotnet CLI +################################################################################ + +dotnet_cli = '' +msbuild_standalone = '' +msbuild_mono = '' + +msbuild_tool_args = ['--mono-bin-dir', mono_bin_dir] + +_find_msbuild_res = run_command(SCRIPT_FIND_MSBUILD, 'dotnet_cli') +if _find_msbuild_res.returncode() == 0 + dotnet_cli = _find_msbuild_res.stdout().strip() + msbuild_tool_args += ['--tool-dotnet-cli', dotnet_cli] +endif + +_find_msbuild_res = run_command(SCRIPT_FIND_MSBUILD, 'msbuild_standalone') +if _find_msbuild_res.returncode() == 0 + msbuild_standalone = _find_msbuild_res.stdout().strip() + msbuild_tool_args += ['--tool-msbuild-standalone', msbuild_standalone] +endif + +_find_msbuild_res = run_command(SCRIPT_FIND_MSBUILD, 'msbuild_mono', '--mono-prefix', mono_prefix) +if _find_msbuild_res.returncode() == 0 + msbuild_mono = _find_msbuild_res.stdout().strip() + msbuild_tool_args += ['--tool-msbuild-mono', msbuild_mono] +endif + +if dotnet_cli == '' and msbuild_standalone == '' and msbuild_mono == '' + error('One of these tools is required but none could be found: dotnet CLI, standalone MSBuild, Mono\'s MSBuild.') +endif + +################################################################################ +# Generate C# glue version header +################################################################################ + +if get_option('tools') + custom_target('cs_glue_version', + output: ['cs_glue_version.gen.h'], + input: 'glue/GodotSharp/GodotSharp.sln', + depfile: 'cs_glue_version.depfile', + command: [SCRIPT_CS_GLUE_VERSION] + msbuild_tool_args + + ['--stamp', '@OUTPUT@', '--depfile', '@DEPFILE@', '--', + '@INPUT@', '/p:ExcludeGeneratedSources=true'], + build_by_default: true) +endif + +################################################################################ +# Conditionally define MONO_GLUE_ENABLED and ensure glue is generated +################################################################################ + +glue_gen_exists = fs.is_file('glue/mono_glue.gen.cpp') + +if get_option('mono_glue') + _module_mono_cpp_args += ['-DMONO_GLUE_ENABLED'] + + if not glue_gen_exists + error('Mono glue sources not found. Did you forget to run \'--generate-mono-glue\'?') + endif +endif + +if glue_gen_exists + _module_mono_srcs += files('glue/mono_glue.gen.cpp') +endif + +################################################################################ +# TODO: Can this be removed now that we migrated to GitHub Actions? Or maybe Travis CI already updated Mono? +# Travis CI may have a Mono version lower than 5.12 +# Disable use of Mono pending exceptions API for Travis builds +################################################################################ + +travis = run_command(SCRIPT_PRINT_ENV_VAR, 'TRAVIS').stdout().strip() +if travis == 'true' + _module_mono_cpp_args += ['-DNO_PENDING_EXCEPTIONS'] +endif + +################################################################################ +# Configure Mono +################################################################################ + +default_mono_static = PLATFORM in ['iphone', 'javascript'] +default_mono_bundles_zlib = PLATFORM in ['javascript'] + +is_android = PLATFORM == 'android' +is_javascript = PLATFORM == 'javascript' +is_ios = PLATFORM == 'iphone' +is_ios_sim = is_ios and host_machine.cpu_family() in ['x86', 'x86_64'] + +mono_static = get_option('mono_static') +mono_static = mono_static == 'auto' ? default_mono_static : mono_static != 'false' + +# TODO: Implement mono_bundles_zlib (how to disable builtin_zlib in Meson) +mono_bundles_zlib = get_option('mono_bundles_zlib') +mono_bundles_zlib = mono_bundles_zlib == 'auto' ? default_mono_bundles_zlib : mono_bundles_zlib != 'false' + +# TODO: +# if is_android and not env["android_arch"] in android_arch_dirs: +# raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"]) + +if get_option('tools') and PLATFORM in _module_tools_unsupported_platforms + # TODO: + # Android: We have to add the data directory to the apk, concretely the Api and Tools folders. + error('This module does not currently support building for this platform with tools enabled') +endif + +if is_android and mono_static + # FIXME: When static linking and doing something that requires libmono-native, we get a dlopen error as 'libmono-native' + # seems to depend on 'libmonosgen-2.0'. Could be fixed by re-directing to '__Internal' with a dllmap or in the dlopen hook. + error('Statically linking Mono is not currently supported for this platform') +endif + +if not mono_static and (is_javascript or is_ios) + error('Dynamically linking Mono is not currently supported for this platform') +endif + +# Although we don't support building with tools for any platform where we currently use static AOT, +# if these are supported in the future, we won't be using static AOT for them as that would be +# too restrictive for the editor. These builds would probably be made to only use the interpreter. +mono_aot_static = (is_ios and not is_ios_sim) and not get_option('tools') + +# Static AOT is only supported on the root domain +mono_single_appdomain = mono_aot_static + +if mono_single_appdomain + _module_mono_cpp_args += ['-DGD_MONO_SINGLE_APPDOMAIN'] +endif + +if (get_option('tools') or IS_DEBUG_BUILD) and not mono_single_appdomain + _module_mono_cpp_args += ['-DGD_MONO_HOT_RELOAD'] +endif + +_cpp = meson.get_compiler('cpp') + +if PLATFORM == 'windows' + is_msvc = meson.get_compiler('cpp').get_id() == 'msvc' + + if mono_static + # Static Linking + + if is_msvc + _mono_lib_dep = _cpp.find_library('mono-static-sgen', # libmono-static-sgen.lib + dirs: mono_lib_dir, static: true, required: false) + else + # MinGW supports both '.a' and '.lib' + _mono_lib_dep = _cpp.find_library('monosgen-2.0', # libmonosgen-2.0.a + dirs: mono_lib_dir, static: true, required: false) + + if not _mono_lib_dep.found() + # TODO: does linking this one work with MinGW? + _mono_lib_dep = _cpp.find_library('mono-static-sgen', # libmono-static-sgen.lib + dirs: mono_lib_dir, static: true, required: false) + endif + endif + + if not _mono_lib_dep.found() + error('Could not find static mono library in: ' + mono_lib_dir) + endif + + if is_msvc + _mono_other_lib_deps = [ + _cpp.find_library('Mincore', static: true, required: true), + _cpp.find_library('msvcrt', static: true, required: true), + _cpp.find_library('LIBCMT', static: true, required: true), + _cpp.find_library('Psapi', static: true, required: true) + ] + else + _mono_other_lib_deps = [ + _cpp.find_library('psapi', required: true), + _cpp.find_library('version', required: true) + ] + endif + + link_whole = not is_msvc + + if link_whole + _mono_dep = declare_dependency(link_whole: _mono_lib_dep) + endif + + _mono_dep = declare_dependency( + dependencies: [_mono_dep] + _mono_other_lib_deps + ) + else + # Dynamic Linking + + # dll file has same base name as lib file + + if is_msvc + _mono_lib_dep = _cpp.find_library('mono-2.0-sgen', # mono-2.0-sgen.lib + dirs: mono_lib_dir, static: true, required: false) + mono_dll_file_name = 'mono-2.0-sgen.dll' + else + # MinGW supports both '.a' and '.lib' + _mono_lib_dep = _cpp.find_library('monosgen-2.0', # libmonosgen-2.0.a + dirs: mono_lib_dir, static: true, required: false) + mono_dll_file_name = 'libmonosgen-2.0.dll' + + if not _mono_lib_dep.found() + _mono_lib_dep = _cpp.find_library('mono-2.0-sgen', # mono-2.0-sgen.lib + dirs: mono_lib_dir, static: true, required: false) + mono_dll_file_name = 'mono-2.0-sgen.dll' + endif + endif + + if not _mono_lib_dep.found() + error('Could not find mono library in: ' + mono_lib_dir) + endif + + _mono_dep = declare_dependency( + dependencies: _mono_lib_dep + ) + + mono_dll_file_path = mono_bin_dir / mono_dll_file_name + + if not fs.is_file(mono_dll_file_path) + error('Could not find mono dll in: ' + mono_bin_dir) + endif + + custom_target(mono_dll_file_name, + input: mono_dll_file_path, + output: mono_dll_file_name, + command: [SCRIPT_COPY_FILE, '@INPUT@', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) + endif +else + is_apple = PLATFORM in ['osx', 'iphone'] + is_macos = is_apple and not is_ios + + sharedlib_ext = is_apple ? '.dylib' : '.so' + + mono_so_file_name = '' + + if is_ios and not is_ios_sim + _module_mono_cpp_args += ['-DIOS_DEVICE'] + endif + + _mono_lib_dep = _cpp.find_library('monosgen-2.0', # libmonosgen-2.0.a + dirs: mono_lib_dir, static: mono_static, required: false) + + if not _mono_lib_dep.found() + error('Could not find mono library in: ' + mono_lib_dir) + endif + + _module_mono_cpp_args += ['-D_REENTRANT'] + + if is_macos + _mono_other_lib_deps = [ + _cpp.find_library('iconv', required: true), + _cpp.find_library('pthread', required: true) + ] + elif is_android + _mono_other_lib_deps = [] # Nothing + elif is_ios + _mono_other_lib_deps = [] # Nothing, linking is delegated to the exported Xcode project + elif is_javascript + _mono_other_lib_deps = [ + _cpp.find_library('m', required: true), + _cpp.find_library('rt', required: true), + _cpp.find_library('dl', required: true), + _cpp.find_library('pthread', required: true) + ] + else + _mono_other_lib_deps = [ + _cpp.find_library('m', required: true), + _cpp.find_library('rt', required: true), + _cpp.find_library('dl', required: true), + _cpp.find_library('pthread', required: true) + ] + endif + + if mono_static + _mono_dep_link_flags = [] + + if not is_javascript + _mono_dep_link_flags += '-rdynamic' + endif + + # link_whole doesn't work with ExternalLibrary (find_library) because of reasons, so we need to do this manually... + mono_lib_file_path = mono_lib_dir / 'libmonosgen-2.0.a' + if is_apple + if is_macos + _mono_dep_link_flags += ['-Wl,-force_load,' + mono_lib_file_path] + endif + else + _mono_dep_link_flags += ['-Wl,-whole-archive', mono_lib_file_path, '-Wl,-no-whole-archive'] + endif + + if is_apple + if is_ios + _mono_ios_arch = host_machine.cpu_family() + + # TODO: Fix old code that depends on this that's using the old arm64 naming instead of aarch64. + assert(_mono_ios_arch in ['x86', 'x86_64', 'arm', 'aarch64']) + + _mono_libs_to_cp = [] + + # Copy Mono libraries to the output folder. These are meant to be bundled with + # the export templates and added to the Xcode project when exporting a game. + _mono_libs_to_cp += 'libmonosgen-2.0.a' + _mono_libs_to_cp += 'libmono-native' + _mono_libs_to_cp += 'libmono-profiler-log' + + if not is_ios_sim + _mono_libs_to_cp += 'libmono-ee-interp' + _mono_libs_to_cp += 'libmono-icall-table' + _mono_libs_to_cp += 'libmono-ilgen' + endif + + foreach mono_lib_to_cp : _mono_libs_to_cp + custom_target(mono_lib_to_cp, + input: mono_lib_dir / mono_lib_to_cp + '.a', + # FIXME: copies to builddir/modules/mono/ ... + output: mono_lib_to_cp + '.a.stamp', + command: [SCRIPT_COPY_FILE, '@INPUT@', + meson.project_build_root() / mono_lib_to_cp + '.iphone.' + _mono_ios_arch + '.a', + '--stamp', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) + endforeach + endif + else + assert(PLATFORM in _desktop_platforms or is_android or is_javascript) + endif + + if is_javascript + _mono_other_lib_deps += [ + _cpp.find_library('mono-icall-table', dirs: mono_lib_dir, static: true, required: true), + _cpp.find_library('mono-native', dirs: mono_lib_dir, static: true, required: true), + _cpp.find_library('mono-ilgen', dirs: mono_lib_dir, static: true, required: true), + _cpp.find_library('mono-ee-interp', dirs: mono_lib_dir, static: true, required: true) + ] + + wasm_src_dir = mono_prefix / 'src' + if not fs.is_dir(wasm_src_dir) + error('Could not find mono wasm src directory') + endif + + _mono_dep_link_flags += [ + '--js-library', wasm_src_dir / 'library_mono.js', + '--js-library', wasm_src_dir / 'binding_support.js', + '--js-library', wasm_src_dir / 'dotnet_support.js', + ] + + _mono_dep = declare_dependency( + include_directories: include_directories(mono_include_dir), + #link_whole: _mono_lib_dep, + dependencies: _mono_other_lib_deps, + link_args: _mono_dep_link_flags, + # Ideally this should be defined only for 'driver.c', but I can't fight scons for another 2 hours (TODO: is this comment still true with Meson?) + compile_args: ['-DCORE_BINDINGS'], + sources: [ + wasm_src_dir / 'driver.c', + wasm_src_dir / 'zlib-helper.c', + wasm_src_dir / 'corebindings.c' + ] + ) + else + _mono_dep = declare_dependency( + #link_whole: _mono_lib_dep, + dependencies: _mono_other_lib_deps, + link_args: _mono_dep_link_flags + ) + endif + else + _mono_dep = declare_dependency( + dependencies: [_mono_lib_dep] + _mono_other_lib_deps + ) + endif + + if not mono_static + mono_so_file_name = 'libmonosgen-2.0' + sharedlib_ext + + if not fs.is_file(mono_lib_dir / mono_so_file_name) + error('Could not find mono shared library in: ' + mono_lib_dir) + endif + endif + + if not mono_static + if is_android + mono_so_output = meson.project_build_root() / mono_so_file_name + # TODO + # android_output_dir = Dir('#platform/android/java/lib/libs').abspath / + # 'release' if env['target'] == 'release' else 'debug' / + # android_arch_dirs[env['android_arch']] + # mono_so_output = android_output_dir / mono_so_file_name + endif + + custom_target(mono_so_file_name, + input: mono_lib_dir / mono_so_file_name, + # FIXME: copies to builddir/modules/mono/ ... + output: mono_so_file_name + '.stamp', + command: [SCRIPT_COPY_FILE, '@INPUT@', mono_so_output, '--stamp', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) + endif +endif + +_mono_shared_libs_output_dir = '' +_mono_etc_files_output_dir = '' +_mono_bcl_output_dir = '' + +if not get_option('tools') + if PLATFORM in _desktop_platforms + # Only desktop export templates have a data directory + assert(PLATFORM in _desktop_platforms) + + # TODO: Fix old code that depends on this that's using bits (32/64) instead of arch. + # TODO: Fix target? Where is release_debug? How to check this in Meson? + _mono_template_dir_name = 'data.mono.' + PLATFORM + '.' + host_machine.cpu_family() + '.' + (IS_DEBUG_BUILD ? 'debug' : 'release') + + _target_mono_prefix = meson.project_build_root() / _mono_template_dir_name / 'Mono' + _mono_shared_libs_output_dir = _target_mono_prefix / (PLATFORM == 'windows' ? 'bin' : 'lib') + _mono_etc_files_output_dir = _target_mono_prefix / 'etc' + elif is_android + # TODO: + # # Compress Android Mono Config + # from . import make_android_mono_config + + # module_dir = os.getcwd() + # config_file_path = os.path.join(module_dir, "build_scripts", "mono_android_config.xml") + # make_android_mono_config.generate_compressed_config(config_file_path, "mono_gd/") + + # target_mono_lib_dir = get_android_out_dir(env) + # # Copy the required shared libraries + # copy_mono_shared_libs(env, mono_prefix, None) + elif is_javascript or is_ios + # No data directory for these platform + endif +endif + +if get_option('copy_mono_root') + if get_option('tools') + _target_mono_prefix = meson.project_build_root() / 'GodotSharp/Mono' + _mono_shared_libs_output_dir = _target_mono_prefix / (PLATFORM == 'windows' ? 'bin' : 'lib') + _mono_etc_files_output_dir = _target_mono_prefix / 'etc' + _mono_bcl_output_dir = _target_mono_prefix / 'lib/mono/4.5' + else + error('The Meson option \'copy_mono_root\' can only be enabled together with \'tools\'.') + endif +endif + +################################################################################ +# Copy Mono Etc Files +################################################################################ + +if _mono_etc_files_output_dir != '' + _mono_etc_config_output = _mono_etc_files_output_dir / 'mono/config' + custom_target('mono_etc_mono_config', + input: mono_etc_dir / 'mono/config', + # FIXME: copies to builddir/modules/mono/ ... + output: 'mono_etc_mono_config.stamp', + command: [SCRIPT_COPY_FILE, '@INPUT@', _mono_etc_config_output, '--stamp', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) +endif + +################################################################################ +# Copy Mono Shared Libraries +################################################################################ + +if _mono_shared_libs_output_dir != '' + if PLATFORM == 'windows' + _mono_output_bin_dir = _mono_shared_libs_output_dir + + if fs.is_file(mono_bin_dir / 'libMonoPosixHelper.dll') + # Naming for Mono built with MinGW + mono_posix_helper_file = 'libMonoPosixHelper.dll' + else + mono_posix_helper_file = 'MonoPosixHelper.dll' + endif + + custom_target('MonoPosixHelper', + input: mono_bin_dir / mono_posix_helper_file, + # FIXME: copies to builddir/modules/mono/ ... + output: 'MonoPosixHelper.dll.stamp', + command: [SCRIPT_COPY_FILE, '@INPUT@', _mono_shared_libs_output_dir / 'MonoPosixHelper.dll', '--stamp', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) + + # For newer versions + btls_dll_path = mono_bin_dir / 'libmono-btls-shared.dll' + if fs.is_file(btls_dll_path) + custom_target('libmono-btls-shared', + input: btls_dll_path, + # FIXME: copies to builddir/modules/mono/ ... + output: 'libmono-btls-shared.dll.stamp', + command: [SCRIPT_COPY_FILE, '@INPUT@', _mono_shared_libs_output_dir / 'libmono-btls-shared.dll', '--stamp', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) + endif + else + if PLATFORM == 'osx' + lib_file_names = ['libmono-btls-shared.dylib', 'libmono-native-compat.dylib', 'libMonoPosixHelper.dylib'] + elif PLATFORM in _unix_like_platforms + lib_file_names = [ + 'libmono-btls-shared.so', + 'libmono-ee-interp.so', + 'libmono-native.so', + 'libMonoPosixHelper.so', + 'libmono-profiler-aot.so', + 'libmono-profiler-coverage.so', + 'libmono-profiler-log.so', + 'libMonoSupportW.so', + ] + endif + + foreach lib_file_name : lib_file_names + if fs.is_file(mono_lib_dir / lib_file_name) + custom_target(fs.replace_suffix(lib_file_name, ''), + input: mono_lib_dir / lib_file_name, + # FIXME: copies to builddir/modules/mono/ ... + output: lib_file_name + '.stamp', + command: [SCRIPT_COPY_FILE, '@INPUT@', _mono_shared_libs_output_dir / lib_file_name, '--stamp', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) + endif + endforeach + endif +endif + +################################################################################ +# Copy Mono BCL Assemblies +################################################################################ + +if _mono_bcl_output_dir != '' + mono_bcl_facades_dir = mono_bcl / 'Facades' + + _mono_bcl_facades_output_dir = _mono_bcl_output_dir / 'Facades' + + _mono_bcl_assemblies = run_command(SCRIPT_LIST_DIR_ASSEMBLIES, mono_bcl) \ + .stdout().strip().split('\n') + _mono_bcl_facade_assemblies = run_command(SCRIPT_LIST_DIR_ASSEMBLIES, mono_bcl_facades_dir) \ + .stdout().strip().split('\n') + + foreach assembly : _mono_bcl_assemblies + custom_target(fs.replace_suffix(assembly, ''), + input: mono_bcl / assembly, + # FIXME: copies to builddir/modules/mono/ ... + output: assembly + '.stamp', + command: [SCRIPT_COPY_FILE, '@INPUT@', _mono_bcl_output_dir / assembly, '--stamp', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) + endforeach + foreach assembly : _mono_bcl_facade_assemblies + custom_target(fs.replace_suffix(assembly, ''), + input: mono_bcl_facades_dir / assembly, + # FIXME: copies to builddir/modules/mono/ ... + output: assembly + '.stamp', + command: [SCRIPT_COPY_FILE, '@INPUT@', _mono_bcl_facades_output_dir / assembly, '--stamp', '@OUTPUT@'], + install: true, + install_dir: '@OUTDIR@', + build_by_default: true) + endforeach +endif + +################################################################################ +# Build MSBuild solutions: GodotSharp, GodotTools and Godot.NET.Sdk +################################################################################ + +if get_option('tools') and get_option('mono_glue') and get_option('build_cil') + # GodotSharp target + custom_target('sln_godotsharp_debug', + # FIXME: https://github.com/mesonbuild/meson/issues/2320 + output: 'sln_godotsharp_debug.stamp', + # output: [ + # 'GodotSharp/Api/Debug/GodotSharp.dll', + # 'GodotSharp/Api/Debug/GodotSharp.pdb', + # 'GodotSharp/Api/Debug/GodotSharp.xml', + # 'GodotSharp/Api/Debug/GodotSharpEditor.dll', + # 'GodotSharp/Api/Debug/GodotSharpEditor.pdb', + # 'GodotSharp/Api/Debug/GodotSharpEditor.xml', + # ], + input: 'glue/GodotSharp/GodotSharp.sln', + depfile: 'sln_godotsharp_debug.depfile', + command: [SCRIPT_RUN_MSBUILD] + msbuild_tool_args + + ['--depfile', '@DEPFILE@', '--stamp', '@OUTPUT@', '--targets', 'Build', '--', + '@INPUT@', '/restore', '/p:Configuration=Debug', '/p:NoWarn=1591', + '/p:MesonBuildDir=' + meson.project_build_root()], + build_by_default: true) + + custom_target('sln_godotsharp_release', + # FIXME: https://github.com/mesonbuild/meson/issues/2320 + output: 'sln_godotsharp_release.stamp', + # output: [ + # 'GodotSharp/Api/Release/GodotSharp.dll', + # 'GodotSharp/Api/Release/GodotSharp.pdb', + # 'GodotSharp/Api/Release/GodotSharp.xml', + # 'GodotSharp/Api/Release/GodotSharpEditor.dll', + # 'GodotSharp/Api/Release/GodotSharpEditor.pdb', + # 'GodotSharp/Api/Release/GodotSharpEditor.xml', + # ], + input: 'glue/GodotSharp/GodotSharp.sln', + depfile: 'sln_godotsharp_release.depfile', + command: [SCRIPT_RUN_MSBUILD] + msbuild_tool_args + + ['--depfile', '@DEPFILE@', '--stamp', '@OUTPUT@', '--targets', 'Build', '--', + '@INPUT@', '/restore', '/p:Configuration=Release', '/p:NoWarn=1591', + '/p:MesonBuildDir=' + meson.project_build_root()], + build_by_default: true) + + _godottools_output_names = [ + 'GodotTools.BuildLogger.dll', + 'GodotTools.Core.dll', + 'GodotTools.dll', + 'GodotTools.IdeMessaging.dll', + 'GodotTools.ProjectEditor.dll', + 'GodotTools.Shared.dll', + 'Microsoft.Build.dll', + 'Microsoft.Build.Framework.dll', + 'Microsoft.VisualStudio.Setup.Configuration.Interop.dll', + 'MSBuild.exe', + 'Newtonsoft.Json.dll', + 'System.Buffers.dll', + 'System.Collections.Immutable.dll', + 'System.Memory.dll', + 'System.Numerics.Vectors.dll', + 'System.Runtime.CompilerServices.Unsafe.dll', + 'System.Threading.Tasks.Dataflow.dll', + ] + + _godottools_output_names_debug = [ + 'GodotTools.BuildLogger.pdb', + 'GodotTools.Core.pdb', + 'GodotTools.IdeMessaging.pdb', + 'GodotTools.pdb', + 'GodotTools.ProjectEditor.pdb', + 'GodotTools.Shared.pdb', + ] + + if PLATFORM == 'windows' + _godottools_output_names += [ + 'EnvDTE.dll', + 'GodotTools.OpenVisualStudio.exe', + 'GodotTools.OpenVisualStudio.exe.config', + 'GodotTools.OpenVisualStudio.pdb', + 'stdole.dll', + ] + + _godottools_output_names_debug += [ + 'GodotTools.OpenVisualStudio.pdb', + ] + endif + + _sln_godottools_output = [] + + foreach f : _godottools_output_names + _sln_godottools_output += 'GodotSharp/Tools' / f + endforeach + + if IS_DEBUG_BUILD + foreach f : _godottools_output_names_debug + _sln_godottools_output += 'GodotSharp/Tools' / f + endforeach + endif + + # GodotTools target + custom_target('sln_godottools', + # FIXME: https://github.com/mesonbuild/meson/issues/2320 + output: 'sln_godottools.stamp', + # output: _sln_godottools_output, + input: 'editor/GodotTools/GodotTools.sln', + depfile: 'sln_godottools.depfile', + command: [SCRIPT_RUN_MSBUILD] + msbuild_tool_args + + ['--depfile', '@DEPFILE@', '--stamp', '@OUTPUT@', '--targets', 'Build', '--', + '@INPUT@', '/restore', '/p:Configuration=' + (IS_DEBUG_BUILD ? 'Debug' : 'Release'), + '/p:GodotPlatform=' + PLATFORM, '/p:MesonBuildDir=' + meson.project_build_root()], + build_by_default: true) + + _godot_net_sdk_version_file = 'editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk_PackageVersion.txt' + _godot_net_sdk_version = run_command(SCRIPT_PRINT_FILE, _godot_net_sdk_version_file).stdout().strip() + + # Godot.NET.Sdk target + custom_target('sln_godot_net_sdk', + # FIXME: https://github.com/mesonbuild/meson/issues/2320 + output: 'sln_godot_net_sdk.stamp', + # # FIXME: If the version changes, the target is rebuilt but 'output' is still named after the old version... What can be done about this? + # output: ['GodotSharp/Tools/nupkgs/Godot.NET.Sdk.' + _godot_net_sdk_version + '.nupkg'], + input: 'editor/Godot.NET.Sdk/Godot.NET.Sdk.sln', + depfile: 'sln_godot_net_sdk.depfile', + command: [SCRIPT_RUN_MSBUILD] + msbuild_tool_args + + ['--depfile', '@DEPFILE@', '--stamp', '@OUTPUT@', '--targets', 'Build', '--', + '@INPUT@', '/restore', '/p:Configuration=Release', '/p:GodotPlatform=' + PLATFORM, + '/p:MesonBuildDir=' + meson.project_build_root()], + build_by_default: true) +endif + +################################################################################ +# Declare Mono module library +################################################################################ + +lib_module_mono = library('module_mono', _module_mono_srcs, + dependencies: [DEP_GODOT_ALL], + cpp_args: _module_mono_cpp_args, + include_directories: include_directories(mono_include_dir) +) + +DEP_MODULE_MONO = declare_dependency(link_with: lib_module_mono, dependencies: _mono_dep) + +MODULE_DEPENDENCIES += DEP_MODULE_MONO diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 875d20ebe47e..ce49e4e33614 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -892,6 +892,7 @@ bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, Lo } if (r_editor_api_assembly.out_of_sync) { + print_verbose("Mono: Editor API assembly is out of sync"); return false; } #endif @@ -900,6 +901,7 @@ bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, Lo // editor API assembly. Otherwise, if both assemblies are out of sync, we would // only update the former as we won't know the latter also needs to be updated. if (r_core_api_assembly.out_of_sync) { + print_verbose("Mono: Core API assembly is out of sync"); return false; }