diff options
Diffstat (limited to 'modules/mono/build_scripts')
-rwxr-xr-x | modules/mono/build_scripts/build_assemblies.py | 80 | ||||
-rw-r--r-- | modules/mono/build_scripts/mono_configure.py | 299 |
2 files changed, 69 insertions, 310 deletions
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py index 6f66ce9efa..0b91cda9b8 100755 --- a/modules/mono/build_scripts/build_assemblies.py +++ b/modules/mono/build_scripts/build_assemblies.py @@ -5,6 +5,7 @@ import os.path import shlex import subprocess from dataclasses import dataclass +from typing import Optional, List def find_dotnet_cli(): @@ -150,10 +151,7 @@ def find_any_msbuild_tool(mono_prefix): return None -def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None): - if msbuild_args is None: - msbuild_args = [] - +def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: Optional[List[str]] = None): using_msbuild_mono = False # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild @@ -169,7 +167,7 @@ def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None): args += [sln] - if len(msbuild_args) > 0: + if msbuild_args: args += msbuild_args print("Running MSBuild: ", " ".join(shlex.quote(arg) for arg in args), flush=True) @@ -195,7 +193,7 @@ def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None): return subprocess.call(args, env=msbuild_env) -def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size): +def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, precision): target_filenames = [ "GodotSharp.dll", "GodotSharp.pdb", @@ -216,7 +214,7 @@ def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, flo args = ["/restore", "/t:Build", "/p:Configuration=" + build_config, "/p:NoWarn=1591"] if push_nupkgs_local: args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local] - if float_size == "64": + if precision == "double": args += ["/p:GodotFloat64=true"] sln = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln") @@ -258,9 +256,59 @@ def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, flo return 0 -def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local, float_size): +def generate_sdk_package_versions(): + # I can't believe importing files in Python is so convoluted when not + # following the golden standard for packages/modules. + import os + import sys + from os.path import dirname + + # We want ../../../methods.py. + script_path = dirname(os.path.abspath(__file__)) + root_path = dirname(dirname(dirname(script_path))) + + sys.path.insert(0, root_path) + from methods import get_version_info + + version_info = get_version_info("") + sys.path.remove(root_path) + + version_str = "{major}.{minor}.{patch}".format(**version_info) + version_status = version_info["status"] + if version_status != "stable": # Pre-release + # If version was overridden to be e.g. "beta3", we insert a dot between + # "beta" and "3" to follow SemVer 2.0. + import re + + match = re.search(r"[\d]+$", version_status) + if match: + pos = match.start() + version_status = version_status[:pos] + "." + version_status[pos:] + version_str += "-" + version_status + + props = """<Project> + <PropertyGroup> + <PackageVersion_GodotSharp>{0}</PackageVersion_GodotSharp> + <PackageVersion_Godot_NET_Sdk>{0}</PackageVersion_Godot_NET_Sdk> + <PackageVersion_Godot_SourceGenerators>{0}</PackageVersion_Godot_SourceGenerators> + </PropertyGroup> +</Project> +""".format( + version_str + ) + + # We write in ../SdkPackageVersions.props. + with open(os.path.join(dirname(script_path), "SdkPackageVersions.props"), "w") as f: + f.write(props) + f.close() + + +def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local, precision): + # Generate SdkPackageVersions.props + generate_sdk_package_versions() + # Godot API - exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size) + exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, precision) if exit_code != 0: return exit_code @@ -271,7 +319,7 @@ def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, p ) if push_nupkgs_local: args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local] - if float_size == "64": + if precision == "double": args += ["/p:GodotFloat64=true"] exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args) if exit_code != 0: @@ -281,7 +329,7 @@ def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, p args = ["/restore", "/t:Build", "/p:Configuration=Release"] if push_nupkgs_local: args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local] - if float_size == "64": + if precision == "double": args += ["/p:GodotFloat64=true"] sln = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln") exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args) @@ -306,7 +354,9 @@ def main(): parser.add_argument("--godot-platform", type=str, default="") parser.add_argument("--mono-prefix", type=str, default="") parser.add_argument("--push-nupkgs-local", type=str, default="") - parser.add_argument("--float", type=str, default="32", choices=["32", "64"], help="Floating-point precision") + parser.add_argument( + "--precision", type=str, default="single", choices=["single", "double"], help="Floating-point precision level" + ) args = parser.parse_args() @@ -315,6 +365,8 @@ def main(): output_dir = os.path.abspath(args.godot_output_dir) + push_nupkgs_local = os.path.abspath(args.push_nupkgs_local) if args.push_nupkgs_local else None + msbuild_tool = find_any_msbuild_tool(args.mono_prefix) if msbuild_tool is None: @@ -327,8 +379,8 @@ def main(): output_dir, args.godot_platform, args.dev_debug, - args.push_nupkgs_local, - args.float, + push_nupkgs_local, + args.precision, ) sys.exit(exit_code) diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index c2d5452837..5cec8f41f5 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -20,300 +20,7 @@ def configure(env, env_mono): # is_ios = env["platform"] == "ios" # is_ios_sim = is_ios and env["arch"] in ["x86_32", "x86_64"] - tools_enabled = env["tools"] - - if tools_enabled and not module_supports_tools_on(env["platform"]): - raise RuntimeError("This module does not currently support building for this platform with tools enabled") - - if env["tools"]: + if env.editor_build: + if not module_supports_tools_on(env["platform"]): + raise RuntimeError("This module does not currently support building for this platform for editor builds.") env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"]) - - app_host_dir = find_dotnet_app_host_dir(env) - - def check_app_host_file_exists(file): - file_path = os.path.join(app_host_dir, file) - if not os.path.isfile(file_path): - raise RuntimeError("File not found: " + file_path) - - # TODO: - # All libnethost does for us is provide a function to find hostfxr. - # If we could handle that logic ourselves we could void linking it. - - # nethost file names: - # static: libnethost.a/lib - # shared: libnethost.a/dylib and nethost.dll - check_app_host_file_exists("libnethost.lib" if os.name == "nt" else "libnethost.a") - check_app_host_file_exists("nethost.h") - check_app_host_file_exists("hostfxr.h") - check_app_host_file_exists("coreclr_delegates.h") - - env_mono.Prepend(CPPPATH=app_host_dir) - - env.Append(LIBPATH=[app_host_dir]) - - # Only the editor build links nethost, which is needed to find hostfxr. - # Exported games don't need this logic as hostfxr is bundled with them. - if tools_enabled: - libnethost_path = os.path.join(app_host_dir, "libnethost.lib" if os.name == "nt" else "libnethost.a") - - if env["platform"] == "windows": - env_mono.Append(CPPDEFINES=["NETHOST_USE_AS_STATIC"]) - - if env.msvc: - env.Append(LINKFLAGS="libnethost.lib") - else: - env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"]) - else: - is_apple = env["platform"] in ["macos", "ios"] - # is_macos = is_apple and not is_ios - - # if is_ios and not is_ios_sim: - # env_mono.Append(CPPDEFINES=["IOS_DEVICE"]) - - if is_apple: - env.Append(LINKFLAGS=["-Wl,-force_load," + libnethost_path]) - else: - env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"]) - - -def find_dotnet_app_host_dir(env): - dotnet_version = "6.0" - - dotnet_root = env["dotnet_root"] - - if not dotnet_root: - dotnet_cmd = find_dotnet_executable(env["arch"]) - if dotnet_cmd: - sdk_path = find_dotnet_sdk(dotnet_cmd, dotnet_version) - if sdk_path: - dotnet_root = os.path.abspath(os.path.join(sdk_path, os.pardir)) - - if not dotnet_root: - raise RuntimeError("Cannot find .NET Core Sdk") - - print("Found .NET Core Sdk root directory: " + dotnet_root) - - dotnet_cmd = os.path.join(dotnet_root, "dotnet.exe" if os.name == "nt" else "dotnet") - - runtime_identifier = determine_runtime_identifier(env) - - # TODO: In the future, if it can't be found this way, we want to obtain it - # from the runtime.{runtime_identifier}.Microsoft.NETCore.DotNetAppHost NuGet package. - app_host_version = find_app_host_version(dotnet_cmd, dotnet_version) - if not app_host_version: - raise RuntimeError("Cannot find .NET app host for version: " + dotnet_version) - - def get_runtime_path(): - return os.path.join( - dotnet_root, - "packs", - "Microsoft.NETCore.App.Host." + runtime_identifier, - app_host_version, - "runtimes", - runtime_identifier, - "native", - ) - - app_host_dir = get_runtime_path() - - # Some Linux distros use their distro name as the RID in these paths. - # If the initial generic path doesn't exist, try to get the RID from `dotnet --info`. - # The generic RID should still be the first choice. Some platforms like Windows 10 - # define the RID as `win10-x64` but still use the generic `win-x64` for directory names. - if not app_host_dir or not os.path.isdir(app_host_dir): - runtime_identifier = find_dotnet_cli_rid(dotnet_cmd) - app_host_dir = get_runtime_path() - - return app_host_dir - - -def determine_runtime_identifier(env): - # The keys are Godot's names, the values are the Microsoft's names. - # List: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog - names_map = { - "windows": "win", - "macos": "osx", - "linuxbsd": "linux", - } - arch_map = { - "x86_64": "x64", - "x86_32": "x86", - "arm64": "arm64", - "arm32": "arm", - } - platform = env["platform"] - if is_desktop(platform): - return "%s-%s" % (names_map[platform], arch_map[env["arch"]]) - else: - raise NotImplementedError() - - -def find_app_host_version(dotnet_cmd, search_version_str): - import subprocess - from distutils.version import LooseVersion - - search_version = LooseVersion(search_version_str) - found_match = False - - try: - env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US") - lines = subprocess.check_output([dotnet_cmd, "--list-runtimes"], env=env).splitlines() - - for line_bytes in lines: - line = line_bytes.decode("utf-8") - if not line.startswith("Microsoft.NETCore.App "): - continue - - parts = line.split(" ", 2) - if len(parts) < 3: - continue - - version_str = parts[1] - - version = LooseVersion(version_str) - - if version >= search_version: - search_version = version - found_match = True - if found_match: - return str(search_version) - except (subprocess.CalledProcessError, OSError) as e: - import sys - - print(e, file=sys.stderr) - - return "" - - -def find_dotnet_arch(dotnet_cmd): - import subprocess - - try: - env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US") - lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines() - - for line_bytes in lines: - line = line_bytes.decode("utf-8") - - parts = line.split(":", 1) - if len(parts) < 2: - continue - - arch_str = parts[0].strip() - if arch_str != "Architecture": - continue - - arch_value = parts[1].strip() - arch_map = {"x64": "x86_64", "x86": "x86_32", "arm64": "arm64", "arm32": "arm32"} - return arch_map[arch_value] - except (subprocess.CalledProcessError, OSError) as e: - import sys - - print(e, file=sys.stderr) - - return "" - - -def find_dotnet_sdk(dotnet_cmd, search_version_str): - import subprocess - from distutils.version import LooseVersion - - search_version = LooseVersion(search_version_str) - - try: - env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US") - lines = subprocess.check_output([dotnet_cmd, "--list-sdks"], env=env).splitlines() - - for line_bytes in lines: - line = line_bytes.decode("utf-8") - - parts = line.split(" ", 1) - if len(parts) < 2: - continue - - version_str = parts[0] - - version = LooseVersion(version_str) - - if version < search_version: - continue - - path_part = parts[1] - return path_part[1 : path_part.find("]")] - except (subprocess.CalledProcessError, OSError) as e: - import sys - - print(e, file=sys.stderr) - - return "" - - -def find_dotnet_cli_rid(dotnet_cmd): - import subprocess - - try: - env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US") - lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines() - - for line_bytes in lines: - line = line_bytes.decode("utf-8") - if not line.startswith(" RID:"): - continue - - parts = line.split() - if len(parts) < 2: - continue - - return parts[1] - except (subprocess.CalledProcessError, OSError) as e: - import sys - - print(e, file=sys.stderr) - - return "" - - -ENV_PATH_SEP = ";" if os.name == "nt" else ":" - - -def find_dotnet_executable(arch): - is_windows = os.name == "nt" - windows_exts = os.environ["PATHEXT"].split(ENV_PATH_SEP) if is_windows else None - path_dirs = os.environ["PATH"].split(ENV_PATH_SEP) - - search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list - - for dir in path_dirs: - search_dirs += [ - os.path.join(dir, "x64"), - os.path.join(dir, "x86"), - os.path.join(dir, "arm64"), - os.path.join(dir, "arm32"), - ] # search subfolders for cross compiling - - # `dotnet --info` may not specify architecture. In such cases, - # we fallback to the first one we find without architecture. - sdk_path_unknown_arch = "" - - for dir in search_dirs: - path = os.path.join(dir, "dotnet") - - if is_windows: - for extension in windows_exts: - path_with_ext = path + extension - - if os.path.isfile(path_with_ext) and os.access(path_with_ext, os.X_OK): - sdk_arch = find_dotnet_arch(path_with_ext) - if sdk_arch == arch or arch == "": - return path_with_ext - elif sdk_arch == "": - sdk_path_unknown_arch = path_with_ext - else: - if os.path.isfile(path) and os.access(path, os.X_OK): - sdk_arch = find_dotnet_arch(path) - if sdk_arch == arch or arch == "": - return path - elif sdk_arch == "": - sdk_path_unknown_arch = path - - return sdk_path_unknown_arch |