mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-03 23:21:15 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			265 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import os
 | 
						|
import os.path
 | 
						|
 | 
						|
 | 
						|
def is_desktop(platform):
 | 
						|
    return platform in ["windows", "macos", "linuxbsd", "server", "uwp", "haiku"]
 | 
						|
 | 
						|
 | 
						|
def is_unix_like(platform):
 | 
						|
    return platform in ["macos", "linuxbsd", "server", "android", "haiku", "ios"]
 | 
						|
 | 
						|
 | 
						|
def module_supports_tools_on(platform):
 | 
						|
    return is_desktop(platform)
 | 
						|
 | 
						|
 | 
						|
def configure(env, env_mono):
 | 
						|
    # is_android = env["platform"] == "android"
 | 
						|
    # is_javascript = env["platform"] == "javascript"
 | 
						|
    # is_ios = env["platform"] == "ios"
 | 
						|
    # is_ios_sim = is_ios and env["arch"] in ["x86", "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"] or env["target"] != "release":
 | 
						|
        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.Append(LIBPATH=[app_host_dir])
 | 
						|
    env_mono.Prepend(CPPPATH=app_host_dir)
 | 
						|
 | 
						|
    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 = "5.0"
 | 
						|
 | 
						|
    dotnet_root = env["dotnet_root"]
 | 
						|
 | 
						|
    if not dotnet_root:
 | 
						|
        dotnet_cmd = find_executable("dotnet")
 | 
						|
        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):
 | 
						|
    names_map = {
 | 
						|
        "windows": "win",
 | 
						|
        "macos": "osx",
 | 
						|
        "linuxbsd": "linux",
 | 
						|
        "server": "linux",  # FIXME: Is server linux only, or also macos?
 | 
						|
    }
 | 
						|
 | 
						|
    # .NET RID architectures: x86, x64, arm, or arm64
 | 
						|
 | 
						|
    platform = env["platform"]
 | 
						|
 | 
						|
    if is_desktop(platform):
 | 
						|
        if env["arch"] in ["arm", "arm32"]:
 | 
						|
            rid = "arm"
 | 
						|
        elif env["arch"] == "arm64":
 | 
						|
            rid = "arm64"
 | 
						|
        else:
 | 
						|
            bits = env["bits"]
 | 
						|
            bit_arch_map = {"64": "x64", "32": "x86"}
 | 
						|
            rid = bit_arch_map[bits]
 | 
						|
        return "%s-%s" % (names_map[platform], rid)
 | 
						|
    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)
 | 
						|
 | 
						|
    try:
 | 
						|
        lines = subprocess.check_output([dotnet_cmd, "--list-runtimes"]).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:
 | 
						|
                return version_str
 | 
						|
    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:
 | 
						|
        lines = subprocess.check_output([dotnet_cmd, "--list-sdks"]).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_executable(name):
 | 
						|
    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 search_dirs:
 | 
						|
        path = os.path.join(dir, name)
 | 
						|
 | 
						|
        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):
 | 
						|
                    return path_with_ext
 | 
						|
        else:
 | 
						|
            if os.path.isfile(path) and os.access(path, os.X_OK):
 | 
						|
                return path
 | 
						|
 | 
						|
    return ""
 |