diff options
Diffstat (limited to 'platform/windows/detect.py')
-rw-r--r-- | platform/windows/detect.py | 230 |
1 files changed, 185 insertions, 45 deletions
diff --git a/platform/windows/detect.py b/platform/windows/detect.py index bdacdbb9ba..93eb34001e 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -2,12 +2,13 @@ import methods import os import subprocess import sys +from methods import print_warning, print_error from platform_methods import detect_arch from typing import TYPE_CHECKING if TYPE_CHECKING: - from SCons import Environment + from SCons.Script.SConscript import SConsEnvironment # To match other platforms STACK_SIZE = 8388608 @@ -164,6 +165,22 @@ def get_opts(): mingw = os.getenv("MINGW_PREFIX", "") + # Direct3D 12 SDK dependencies folder. + d3d12_deps_folder = os.getenv("LOCALAPPDATA") + if d3d12_deps_folder: + d3d12_deps_folder = os.path.join(d3d12_deps_folder, "Godot", "build_deps") + else: + # Cross-compiling, the deps install script puts things in `bin`. + # Getting an absolute path to it is a bit hacky in Python. + try: + import inspect + + caller_frame = inspect.stack()[1] + caller_script_dir = os.path.dirname(os.path.abspath(caller_frame[1])) + d3d12_deps_folder = os.path.join(caller_script_dir, "bin", "build_deps") + except: # Give up. + d3d12_deps_folder = "" + return [ ("mingw_prefix", "MinGW prefix", mingw), # Targeted Windows version: 7 (and later), minimum supported version @@ -186,7 +203,35 @@ def get_opts(): BoolVariable("use_asan", "Use address sanitizer (ASAN)", False), BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False), BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False), + BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting any errors to stderr.", True), ("angle_libs", "Path to the ANGLE static libraries", ""), + # Direct3D 12 support. + ( + "mesa_libs", + "Path to the MESA/NIR static libraries (required for D3D12)", + os.path.join(d3d12_deps_folder, "mesa"), + ), + ( + "dxc_path", + "Path to the DirectX Shader Compiler distribution (required for D3D12)", + os.path.join(d3d12_deps_folder, "dxc"), + ), + ( + "agility_sdk_path", + "Path to the Agility SDK distribution (optional for D3D12)", + os.path.join(d3d12_deps_folder, "agility_sdk"), + ), + BoolVariable( + "agility_sdk_multiarch", + "Whether the Agility SDK DLLs will be stored in arch-specific subdirectories", + False, + ), + BoolVariable("use_pix", "Use PIX (Performance tuning and debugging for DirectX 12) runtime", False), + ( + "pix_path", + "Path to the PIX runtime distribution (optional for D3D12)", + os.path.join(d3d12_deps_folder, "pix"), + ), ] @@ -205,10 +250,11 @@ def get_flags(): return [ ("arch", arch), + ("supported", ["mono"]), ] -def build_res_file(target, source, env): +def build_res_file(target, source, env: "SConsEnvironment"): arch_aliases = { "x86_32": "pe-i386", "x86_64": "pe-x86-64", @@ -243,24 +289,22 @@ def build_res_file(target, source, env): return 0 -def setup_msvc_manual(env): +def setup_msvc_manual(env: "SConsEnvironment"): """Running from VCVARS environment""" env_arch = detect_build_env_arch() if env["arch"] != env_arch: - print( - """ - Arch argument (%s) is not matching Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings) that is being used to run SCons (%s). - Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you. - """ + print_error( + "Arch argument (%s) is not matching Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings) that is being used to run SCons (%s).\n" + "Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you." % (env["arch"], env_arch) ) - sys.exit(200) + sys.exit(255) - print("Found MSVC, arch %s" % (env_arch)) + print("Using VCVARS-determined MSVC, arch %s" % (env_arch)) -def setup_msvc_auto(env): +def setup_msvc_auto(env: "SConsEnvironment"): """Set up MSVC using SCons's auto-detection logic""" # If MSVC_VERSION is set by SCons, we know MSVC is installed. @@ -293,45 +337,37 @@ def setup_msvc_auto(env): env.Tool("mssdk") # we want the MS SDK # Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015 - print("Found MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["arch"])) + print("Using SCons-detected MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["arch"])) -def setup_mingw(env): +def setup_mingw(env: "SConsEnvironment"): """Set up env for use with mingw""" env_arch = detect_build_env_arch() if os.getenv("MSYSTEM") == "MSYS": - print( - """ - Running from base MSYS2 console/environment, use target specific environment instead (e.g., mingw32, mingw64, clang32, clang64). - """ + print_error( + "Running from base MSYS2 console/environment, use target specific environment instead (e.g., mingw32, mingw64, clang32, clang64)." ) - sys.exit(201) + sys.exit(255) if env_arch != "" and env["arch"] != env_arch: - print( - """ - Arch argument (%s) is not matching MSYS2 console/environment that is being used to run SCons (%s). - Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSYS2 compiler will be executed and inform you. - """ + print_error( + "Arch argument (%s) is not matching MSYS2 console/environment that is being used to run SCons (%s).\n" + "Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSYS2 compiler will be executed and inform you." % (env["arch"], env_arch) ) - sys.exit(202) + sys.exit(255) if not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]) and not try_cmd( "clang --version", env["mingw_prefix"], env["arch"] ): - print( - """ - No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path. - """ - ) - sys.exit(202) + print_error("No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.") + sys.exit(255) print("Using MinGW, arch %s" % (env["arch"])) -def configure_msvc(env, vcvars_msvc_config): +def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): """Configure env to work with MSVC""" ## Build type @@ -348,6 +384,39 @@ def configure_msvc(env, vcvars_msvc_config): ## Compile/link flags + env["MAXLINELENGTH"] = 8192 # Windows Vista and beyond, so always applicable. + + if env["silence_msvc"]: + from tempfile import mkstemp + + old_spawn = env["SPAWN"] + + def spawn_capture(sh, escape, cmd, args, env): + # We only care about cl/link, process everything else as normal. + if args[0] not in ["cl", "link"]: + return old_spawn(sh, escape, cmd, args, env) + + tmp_stdout, tmp_stdout_name = mkstemp() + os.close(tmp_stdout) + args.append(f">{tmp_stdout_name}") + ret = old_spawn(sh, escape, cmd, args, env) + + try: + with open(tmp_stdout_name, "rb") as tmp_stdout: + # First line is always bloat, subsequent lines are always errors. If content + # exists after discarding the first line, safely decode & send to stderr. + tmp_stdout.readline() + content = tmp_stdout.read() + if content: + sys.stderr.write(content.decode(sys.stdout.encoding, "replace")) + os.remove(tmp_stdout_name) + except OSError: + pass + + return ret + + env["SPAWN"] = spawn_capture + if env["debug_crt"]: # Always use dynamic runtime, static debug CRT breaks thread_local. env.AppendUnique(CCFLAGS=["/MDd"]) @@ -374,9 +443,13 @@ def configure_msvc(env, vcvars_msvc_config): if vcvars_msvc_config: # should be automatic if SCons found it if os.getenv("WindowsSdkDir") is not None: - env.Prepend(CPPPATH=[os.getenv("WindowsSdkDir") + "/Include"]) + env.Prepend(CPPPATH=[str(os.getenv("WindowsSdkDir")) + "/Include"]) else: - print("Missing environment variable: WindowsSdkDir") + print_warning("Missing environment variable: WindowsSdkDir") + + if int(env["target_win_version"], 16) < 0x0601: + print_error("`target_win_version` should be 0x0601 or higher (Windows 7).") + sys.exit(255) env.AppendUnique( CPPDEFINES=[ @@ -426,10 +499,42 @@ def configure_msvc(env, vcvars_msvc_config): LIBS += ["psapi", "dbghelp"] if env["vulkan"]: - env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"]) + env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) if not env["use_volk"]: LIBS += ["vulkan"] + if env["d3d12"]: + # Check whether we have d3d12 dependencies installed. + if not os.path.exists(env["mesa_libs"]): + print_error( + "The Direct3D 12 rendering driver requires dependencies to be installed.\n" + "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n" + "See the documentation for more information:\n\t" + "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html" + ) + sys.exit(255) + + env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) + LIBS += ["dxgi", "dxguid"] + LIBS += ["version"] # Mesa dependency. + + # Needed for avoiding C1128. + if env["target"] == "release_debug": + env.Append(CXXFLAGS=["/bigobj"]) + + # PIX + if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]): + env["use_pix"] = False + + if env["use_pix"]: + arch_subdir = "arm64" if env["arch"] == "arm64" else "x64" + + env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir]) + LIBS += ["WinPixEventRuntime"] + + env.Append(LIBPATH=[env["mesa_libs"] + "/bin"]) + LIBS += ["libNIR.windows." + env["arch"]] + if env["opengl3"]: env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"]) if env["angle_libs"] != "": @@ -443,13 +548,16 @@ def configure_msvc(env, vcvars_msvc_config): LIBS += ["dxgi", "d3d9", "d3d11"] env.Prepend(CPPPATH=["#thirdparty/angle/include"]) + if env["target"] in ["editor", "template_debug"]: + LIBS += ["psapi", "dbghelp"] + env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) if vcvars_msvc_config: if os.getenv("WindowsSdkDir") is not None: - env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"]) + env.Append(LIBPATH=[str(os.getenv("WindowsSdkDir")) + "/Lib"]) else: - print("Missing environment variable: WindowsSdkDir") + print_warning("Missing environment variable: WindowsSdkDir") ## LTO @@ -458,7 +566,7 @@ def configure_msvc(env, vcvars_msvc_config): if env["lto"] != "none": if env["lto"] == "thin": - print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.") + print_error("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.") sys.exit(255) env.AppendUnique(CCFLAGS=["/GL"]) env.AppendUnique(ARFLAGS=["/LTCG"]) @@ -468,8 +576,8 @@ def configure_msvc(env, vcvars_msvc_config): env.AppendUnique(LINKFLAGS=["/LTCG"]) if vcvars_msvc_config: - env.Prepend(CPPPATH=[p for p in os.getenv("INCLUDE").split(";")]) - env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) + env.Prepend(CPPPATH=[p for p in str(os.getenv("INCLUDE")).split(";")]) + env.Append(LIBPATH=[p for p in str(os.getenv("LIB")).split(";")]) # Sanitizers if env["use_asan"]: @@ -481,11 +589,11 @@ def configure_msvc(env, vcvars_msvc_config): env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"] env["BUILDERS"]["Program"] = methods.precious_program - env.Append(LINKFLAGS=["/NATVIS:platform\windows\godot.natvis"]) + env.Append(LINKFLAGS=["/NATVIS:platform\\windows\\godot.natvis"]) env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE)]) -def configure_mingw(env): +def configure_mingw(env: "SConsEnvironment"): # Workaround for MinGW. See: # https://www.scons.org/wiki/LongCmdLinesOnWin32 env.use_windows_spawn_fix() @@ -575,6 +683,10 @@ def configure_mingw(env): ## Compile flags + if int(env["target_win_version"], 16) < 0x0601: + print_error("`target_win_version` should be 0x0601 or higher (Windows 7).") + sys.exit(255) + if not env["use_llvm"]: env.Append(CCFLAGS=["-mwindows"]) @@ -619,10 +731,38 @@ def configure_mingw(env): env.Append(LIBS=["psapi", "dbghelp"]) if env["vulkan"]: - env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"]) if not env["use_volk"]: env.Append(LIBS=["vulkan"]) + if env["d3d12"]: + # Check whether we have d3d12 dependencies installed. + if not os.path.exists(env["mesa_libs"]): + print_error( + "The Direct3D 12 rendering driver requires dependencies to be installed.\n" + "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n" + "See the documentation for more information:\n\t" + "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html" + ) + sys.exit(255) + + env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) + env.Append(LIBS=["dxgi", "dxguid"]) + + # PIX + if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]): + env["use_pix"] = False + + if env["use_pix"]: + arch_subdir = "arm64" if env["arch"] == "arm64" else "x64" + + env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir]) + env.Append(LIBS=["WinPixEventRuntime"]) + + env.Append(LIBPATH=[env["mesa_libs"] + "/bin"]) + env.Append(LIBS=["libNIR.windows." + env["arch"]]) + env.Append(LIBS=["version"]) # Mesa dependency. + if env["opengl3"]: env.Append(CPPDEFINES=["GLES3_ENABLED"]) if env["angle_libs"] != "": @@ -644,15 +784,15 @@ def configure_mingw(env): env.Append(BUILDERS={"RES": env.Builder(action=build_res_file, suffix=".o", src_suffix=".rc")}) -def configure(env: "Environment"): +def configure(env: "SConsEnvironment"): # Validate arch. supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] if env["arch"] not in supported_arches: - print( + print_error( 'Unsupported CPU architecture "%s" for Windows. Supported architectures are: %s.' % (env["arch"], ", ".join(supported_arches)) ) - sys.exit() + sys.exit(255) # At this point the env has been set up with basic tools/compilers. env.Prepend(CPPPATH=["#platform/windows"]) |