detect.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. import methods
  2. import os
  3. import subprocess
  4. import sys
  5. from methods import print_warning, print_error
  6. from platform_methods import detect_arch
  7. from typing import TYPE_CHECKING
  8. if TYPE_CHECKING:
  9. from SCons.Script.SConscript import SConsEnvironment
  10. # To match other platforms
  11. STACK_SIZE = 8388608
  12. def get_name():
  13. return "Windows"
  14. def get_mingw_tool(tool, prefix="", arch="", test="--version"):
  15. if not prefix:
  16. prefix = os.getenv("MINGW_PREFIX", "")
  17. supported_arches = ["x86_64", "x86_32", "arm64", "arm32"]
  18. if arch in supported_arches:
  19. arches = [arch, ""]
  20. else:
  21. arches = ["x86_64", "x86_32", "arm64", "arm32", ""]
  22. for a in arches:
  23. try:
  24. path = f"{get_mingw_bin_prefix(prefix, a)}{tool}"
  25. out = subprocess.Popen(
  26. f"{path} {test}",
  27. shell=True,
  28. stderr=subprocess.PIPE,
  29. stdout=subprocess.PIPE,
  30. )
  31. out.communicate()
  32. if out.returncode == 0:
  33. return path
  34. except Exception:
  35. pass
  36. return ""
  37. def can_build():
  38. if os.name == "nt":
  39. # Building natively on Windows
  40. # If VCINSTALLDIR is set in the OS environ, use traditional Godot logic to set up MSVC
  41. if os.getenv("VCINSTALLDIR"): # MSVC, manual setup
  42. return True
  43. # Otherwise, let SCons find MSVC if installed, or else MinGW.
  44. # Since we're just returning True here, if there's no compiler
  45. # installed, we'll get errors when it tries to build with the
  46. # null compiler.
  47. return True
  48. if os.name == "posix":
  49. # Cross-compiling with MinGW-w64 (old MinGW32 is not supported)
  50. if get_mingw_tool("gcc") or get_mingw_tool("clang"):
  51. return True
  52. return False
  53. def get_mingw_bin_prefix(prefix, arch):
  54. if not prefix:
  55. mingw_bin_prefix = ""
  56. elif prefix[-1] != "/":
  57. mingw_bin_prefix = prefix + "/bin/"
  58. else:
  59. mingw_bin_prefix = prefix + "bin/"
  60. if arch == "x86_64":
  61. mingw_bin_prefix += "x86_64-w64-mingw32-"
  62. elif arch == "x86_32":
  63. mingw_bin_prefix += "i686-w64-mingw32-"
  64. elif arch == "arm32":
  65. mingw_bin_prefix += "armv7-w64-mingw32-"
  66. elif arch == "arm64":
  67. mingw_bin_prefix += "aarch64-w64-mingw32-"
  68. return mingw_bin_prefix
  69. def detect_build_env_arch():
  70. msvc_target_aliases = {
  71. "amd64": "x86_64",
  72. "i386": "x86_32",
  73. "i486": "x86_32",
  74. "i586": "x86_32",
  75. "i686": "x86_32",
  76. "x86": "x86_32",
  77. "x64": "x86_64",
  78. "x86_64": "x86_64",
  79. "arm": "arm32",
  80. "arm64": "arm64",
  81. "aarch64": "arm64",
  82. }
  83. if os.getenv("VCINSTALLDIR") or os.getenv("VCTOOLSINSTALLDIR"):
  84. if os.getenv("Platform"):
  85. msvc_arch = os.getenv("Platform").lower()
  86. if msvc_arch in msvc_target_aliases.keys():
  87. return msvc_target_aliases[msvc_arch]
  88. if os.getenv("VSCMD_ARG_TGT_ARCH"):
  89. msvc_arch = os.getenv("VSCMD_ARG_TGT_ARCH").lower()
  90. if msvc_arch in msvc_target_aliases.keys():
  91. return msvc_target_aliases[msvc_arch]
  92. # Pre VS 2017 checks.
  93. if os.getenv("VCINSTALLDIR"):
  94. PATH = os.getenv("PATH").upper()
  95. VCINSTALLDIR = os.getenv("VCINSTALLDIR").upper()
  96. path_arch = {
  97. "BIN\\x86_ARM;": "arm32",
  98. "BIN\\amd64_ARM;": "arm32",
  99. "BIN\\x86_ARM64;": "arm64",
  100. "BIN\\amd64_ARM64;": "arm64",
  101. "BIN\\x86_amd64;": "a86_64",
  102. "BIN\\amd64;": "x86_64",
  103. "BIN\\amd64_x86;": "x86_32",
  104. "BIN;": "x86_32",
  105. }
  106. for path, arch in path_arch.items():
  107. final_path = VCINSTALLDIR + path
  108. if final_path in PATH:
  109. return arch
  110. # VS 2017 and newer.
  111. if os.getenv("VCTOOLSINSTALLDIR"):
  112. host_path_index = os.getenv("PATH").upper().find(os.getenv("VCTOOLSINSTALLDIR").upper() + "BIN\\HOST")
  113. if host_path_index > -1:
  114. first_path_arch = os.getenv("PATH").split(";")[0].rsplit("\\", 1)[-1].lower()
  115. return msvc_target_aliases[first_path_arch]
  116. msys_target_aliases = {
  117. "mingw32": "x86_32",
  118. "mingw64": "x86_64",
  119. "ucrt64": "x86_64",
  120. "clang64": "x86_64",
  121. "clang32": "x86_32",
  122. "clangarm64": "arm64",
  123. }
  124. if os.getenv("MSYSTEM"):
  125. msys_arch = os.getenv("MSYSTEM").lower()
  126. if msys_arch in msys_target_aliases.keys():
  127. return msys_target_aliases[msys_arch]
  128. return ""
  129. def get_opts():
  130. from SCons.Variables import BoolVariable, EnumVariable
  131. mingw = os.getenv("MINGW_PREFIX", "")
  132. # Direct3D 12 SDK dependencies folder.
  133. d3d12_deps_folder = os.getenv("LOCALAPPDATA")
  134. if d3d12_deps_folder:
  135. d3d12_deps_folder = os.path.join(d3d12_deps_folder, "Godot", "build_deps")
  136. else:
  137. # Cross-compiling, the deps install script puts things in `bin`.
  138. # Getting an absolute path to it is a bit hacky in Python.
  139. try:
  140. import inspect
  141. caller_frame = inspect.stack()[1]
  142. caller_script_dir = os.path.dirname(os.path.abspath(caller_frame[1]))
  143. d3d12_deps_folder = os.path.join(caller_script_dir, "bin", "build_deps")
  144. except: # Give up.
  145. d3d12_deps_folder = ""
  146. return [
  147. ("mingw_prefix", "MinGW prefix", mingw),
  148. # Targeted Windows version: 7 (and later), minimum supported version
  149. # XP support dropped after EOL due to missing API for IPv6 and other issues
  150. # Vista support dropped after EOL due to GH-10243
  151. (
  152. "target_win_version",
  153. "Targeted Windows version, >= 0x0601 (Windows 7)",
  154. "0x0601",
  155. ),
  156. EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("gui", "console")),
  157. (
  158. "msvc_version",
  159. "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.",
  160. None,
  161. ),
  162. BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed.", False),
  163. BoolVariable("use_llvm", "Use the LLVM compiler", False),
  164. BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True),
  165. BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
  166. BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False),
  167. BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False),
  168. BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting any errors to stderr.", True),
  169. ("angle_libs", "Path to the ANGLE static libraries", ""),
  170. # Direct3D 12 support.
  171. (
  172. "mesa_libs",
  173. "Path to the MESA/NIR static libraries (required for D3D12)",
  174. os.path.join(d3d12_deps_folder, "mesa"),
  175. ),
  176. (
  177. "dxc_path",
  178. "Path to the DirectX Shader Compiler distribution (required for D3D12)",
  179. os.path.join(d3d12_deps_folder, "dxc"),
  180. ),
  181. (
  182. "agility_sdk_path",
  183. "Path to the Agility SDK distribution (optional for D3D12)",
  184. os.path.join(d3d12_deps_folder, "agility_sdk"),
  185. ),
  186. BoolVariable(
  187. "agility_sdk_multiarch",
  188. "Whether the Agility SDK DLLs will be stored in arch-specific subdirectories",
  189. False,
  190. ),
  191. BoolVariable("use_pix", "Use PIX (Performance tuning and debugging for DirectX 12) runtime", False),
  192. (
  193. "pix_path",
  194. "Path to the PIX runtime distribution (optional for D3D12)",
  195. os.path.join(d3d12_deps_folder, "pix"),
  196. ),
  197. ]
  198. def get_doc_classes():
  199. return [
  200. "EditorExportPlatformWindows",
  201. ]
  202. def get_doc_path():
  203. return "doc_classes"
  204. def get_flags():
  205. arch = detect_build_env_arch() or detect_arch()
  206. return [
  207. ("arch", arch),
  208. ("supported", ["mono"]),
  209. ]
  210. def build_res_file(target, source, env: "SConsEnvironment"):
  211. cmdbase = get_mingw_tool("windres", env["mingw_prefix"], env["arch"])
  212. if not cmdbase:
  213. return -1
  214. arch_aliases = {
  215. "x86_32": "pe-i386",
  216. "x86_64": "pe-x86-64",
  217. "arm32": "armv7-w64-mingw32",
  218. "arm64": "aarch64-w64-mingw32",
  219. }
  220. cmdbase += " --include-dir . --target=" + arch_aliases[env["arch"]]
  221. for x in range(len(source)):
  222. cmd = f"{cmdbase} -i {source[x]} -o {target[x]}"
  223. try:
  224. out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
  225. if len(out[1]):
  226. return -1
  227. except Exception:
  228. return -1
  229. return 0
  230. def setup_msvc_manual(env: "SConsEnvironment"):
  231. """Running from VCVARS environment"""
  232. env_arch = detect_build_env_arch()
  233. if env["arch"] != env_arch:
  234. print_error(
  235. "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"
  236. "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."
  237. % (env["arch"], env_arch)
  238. )
  239. sys.exit(255)
  240. print("Using VCVARS-determined MSVC, arch %s" % (env_arch))
  241. def setup_msvc_auto(env: "SConsEnvironment"):
  242. """Set up MSVC using SCons's auto-detection logic"""
  243. # If MSVC_VERSION is set by SCons, we know MSVC is installed.
  244. # But we may want a different version or target arch.
  245. # Valid architectures for MSVC's TARGET_ARCH:
  246. # ['amd64', 'emt64', 'i386', 'i486', 'i586', 'i686', 'ia64', 'itanium', 'x86', 'x86_64', 'arm', 'arm64', 'aarch64']
  247. # Our x86_64 and arm64 are the same, and we need to map the 32-bit
  248. # architectures to other names since MSVC isn't as explicit.
  249. # The rest we don't need to worry about because they are
  250. # aliases or aren't supported by Godot (itanium & ia64).
  251. msvc_arch_aliases = {"x86_32": "x86", "arm32": "arm"}
  252. if env["arch"] in msvc_arch_aliases.keys():
  253. env["TARGET_ARCH"] = msvc_arch_aliases[env["arch"]]
  254. else:
  255. env["TARGET_ARCH"] = env["arch"]
  256. # The env may have already been set up with default MSVC tools, so
  257. # reset a few things so we can set it up with the tools we want.
  258. # (Ideally we'd decide on the tool config before configuring any
  259. # environment, and just set the env up once, but this function runs
  260. # on an existing env so this is the simplest way.)
  261. env["MSVC_SETUP_RUN"] = False # Need to set this to re-run the tool
  262. env["MSVS_VERSION"] = None
  263. env["MSVC_VERSION"] = None
  264. if "msvc_version" in env:
  265. env["MSVC_VERSION"] = env["msvc_version"]
  266. env.Tool("msvc")
  267. env.Tool("mssdk") # we want the MS SDK
  268. # Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015
  269. print("Using SCons-detected MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["arch"]))
  270. def setup_mingw(env: "SConsEnvironment"):
  271. """Set up env for use with mingw"""
  272. env_arch = detect_build_env_arch()
  273. if os.getenv("MSYSTEM") == "MSYS":
  274. print_error(
  275. "Running from base MSYS2 console/environment, use target specific environment instead (e.g., mingw32, mingw64, clang32, clang64)."
  276. )
  277. sys.exit(255)
  278. if env_arch != "" and env["arch"] != env_arch:
  279. print_error(
  280. "Arch argument (%s) is not matching MSYS2 console/environment that is being used to run SCons (%s).\n"
  281. "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."
  282. % (env["arch"], env_arch)
  283. )
  284. sys.exit(255)
  285. if not get_mingw_tool("gcc", env["mingw_prefix"], env["arch"]) and not get_mingw_tool(
  286. "clang", env["mingw_prefix"], env["arch"]
  287. ):
  288. print_error("No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.")
  289. sys.exit(255)
  290. print("Using MinGW, arch %s" % (env["arch"]))
  291. def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
  292. """Configure env to work with MSVC"""
  293. ## Build type
  294. # TODO: Re-evaluate the need for this / streamline with common config.
  295. if env["target"] == "template_release":
  296. env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"])
  297. if env["windows_subsystem"] == "gui":
  298. env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
  299. else:
  300. env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
  301. env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"])
  302. ## Compile/link flags
  303. env["MAXLINELENGTH"] = 8192 # Windows Vista and beyond, so always applicable.
  304. if env["silence_msvc"]:
  305. from tempfile import mkstemp
  306. old_spawn = env["SPAWN"]
  307. def spawn_capture(sh, escape, cmd, args, env):
  308. # We only care about cl/link, process everything else as normal.
  309. if args[0] not in ["cl", "link"]:
  310. return old_spawn(sh, escape, cmd, args, env)
  311. tmp_stdout, tmp_stdout_name = mkstemp()
  312. os.close(tmp_stdout)
  313. args.append(f">{tmp_stdout_name}")
  314. ret = old_spawn(sh, escape, cmd, args, env)
  315. try:
  316. with open(tmp_stdout_name, "rb") as tmp_stdout:
  317. # First line is always bloat, subsequent lines are always errors. If content
  318. # exists after discarding the first line, safely decode & send to stderr.
  319. tmp_stdout.readline()
  320. content = tmp_stdout.read()
  321. if content:
  322. sys.stderr.write(content.decode(sys.stdout.encoding, "replace"))
  323. os.remove(tmp_stdout_name)
  324. except OSError:
  325. pass
  326. return ret
  327. env["SPAWN"] = spawn_capture
  328. if env["debug_crt"]:
  329. # Always use dynamic runtime, static debug CRT breaks thread_local.
  330. env.AppendUnique(CCFLAGS=["/MDd"])
  331. else:
  332. if env["use_static_cpp"]:
  333. env.AppendUnique(CCFLAGS=["/MT"])
  334. else:
  335. env.AppendUnique(CCFLAGS=["/MD"])
  336. # MSVC incremental linking is broken and may _increase_ link time (GH-77968).
  337. if not env["incremental_link"]:
  338. env.Append(LINKFLAGS=["/INCREMENTAL:NO"])
  339. if env["arch"] == "x86_32":
  340. env["x86_libtheora_opt_vc"] = True
  341. env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"])
  342. env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding.
  343. env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++
  344. # Once it was thought that only debug builds would be too large,
  345. # but this has recently stopped being true. See the mingw function
  346. # for notes on why this shouldn't be enabled for gcc
  347. env.AppendUnique(CCFLAGS=["/bigobj"])
  348. if vcvars_msvc_config: # should be automatic if SCons found it
  349. if os.getenv("WindowsSdkDir") is not None:
  350. env.Prepend(CPPPATH=[str(os.getenv("WindowsSdkDir")) + "/Include"])
  351. else:
  352. print_warning("Missing environment variable: WindowsSdkDir")
  353. if int(env["target_win_version"], 16) < 0x0601:
  354. print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
  355. sys.exit(255)
  356. env.AppendUnique(
  357. CPPDEFINES=[
  358. "WINDOWS_ENABLED",
  359. "WASAPI_ENABLED",
  360. "WINMIDI_ENABLED",
  361. "TYPED_METHOD_BIND",
  362. "WIN32",
  363. "WINVER=%s" % env["target_win_version"],
  364. "_WIN32_WINNT=%s" % env["target_win_version"],
  365. ]
  366. )
  367. env.AppendUnique(CPPDEFINES=["NOMINMAX"]) # disable bogus min/max WinDef.h macros
  368. if env["arch"] == "x86_64":
  369. env.AppendUnique(CPPDEFINES=["_WIN64"])
  370. ## Libs
  371. LIBS = [
  372. "winmm",
  373. "dsound",
  374. "kernel32",
  375. "ole32",
  376. "oleaut32",
  377. "sapi",
  378. "user32",
  379. "gdi32",
  380. "IPHLPAPI",
  381. "Shlwapi",
  382. "wsock32",
  383. "Ws2_32",
  384. "shell32",
  385. "advapi32",
  386. "dinput8",
  387. "dxguid",
  388. "imm32",
  389. "bcrypt",
  390. "Crypt32",
  391. "Avrt",
  392. "dwmapi",
  393. "dwrite",
  394. "wbemuuid",
  395. "ntdll",
  396. ]
  397. if env.debug_features:
  398. LIBS += ["psapi", "dbghelp"]
  399. if env["vulkan"]:
  400. env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"])
  401. if not env["use_volk"]:
  402. LIBS += ["vulkan"]
  403. if env["d3d12"]:
  404. # Check whether we have d3d12 dependencies installed.
  405. if not os.path.exists(env["mesa_libs"]):
  406. print_error(
  407. "The Direct3D 12 rendering driver requires dependencies to be installed.\n"
  408. "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
  409. "See the documentation for more information:\n\t"
  410. "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
  411. )
  412. sys.exit(255)
  413. env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
  414. LIBS += ["dxgi", "dxguid"]
  415. LIBS += ["version"] # Mesa dependency.
  416. # Needed for avoiding C1128.
  417. if env["target"] == "release_debug":
  418. env.Append(CXXFLAGS=["/bigobj"])
  419. # PIX
  420. if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]):
  421. env["use_pix"] = False
  422. if env["use_pix"]:
  423. arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
  424. env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir])
  425. LIBS += ["WinPixEventRuntime"]
  426. env.Append(LIBPATH=[env["mesa_libs"] + "/bin"])
  427. LIBS += ["libNIR.windows." + env["arch"]]
  428. if env["opengl3"]:
  429. env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
  430. if env["angle_libs"] != "":
  431. env.AppendUnique(CPPDEFINES=["EGL_STATIC"])
  432. env.Append(LIBPATH=[env["angle_libs"]])
  433. LIBS += [
  434. "libANGLE.windows." + env["arch"],
  435. "libEGL.windows." + env["arch"],
  436. "libGLES.windows." + env["arch"],
  437. ]
  438. LIBS += ["dxgi", "d3d9", "d3d11"]
  439. env.Prepend(CPPPATH=["#thirdparty/angle/include"])
  440. if env["target"] in ["editor", "template_debug"]:
  441. LIBS += ["psapi", "dbghelp"]
  442. env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
  443. if vcvars_msvc_config:
  444. if os.getenv("WindowsSdkDir") is not None:
  445. env.Append(LIBPATH=[str(os.getenv("WindowsSdkDir")) + "/Lib"])
  446. else:
  447. print_warning("Missing environment variable: WindowsSdkDir")
  448. ## LTO
  449. if env["lto"] == "auto": # No LTO by default for MSVC, doesn't help.
  450. env["lto"] = "none"
  451. if env["lto"] != "none":
  452. if env["lto"] == "thin":
  453. print_error("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
  454. sys.exit(255)
  455. env.AppendUnique(CCFLAGS=["/GL"])
  456. env.AppendUnique(ARFLAGS=["/LTCG"])
  457. if env["progress"]:
  458. env.AppendUnique(LINKFLAGS=["/LTCG:STATUS"])
  459. else:
  460. env.AppendUnique(LINKFLAGS=["/LTCG"])
  461. if vcvars_msvc_config:
  462. env.Prepend(CPPPATH=[p for p in str(os.getenv("INCLUDE")).split(";")])
  463. env.Append(LIBPATH=[p for p in str(os.getenv("LIB")).split(";")])
  464. # Sanitizers
  465. if env["use_asan"]:
  466. env.extra_suffix += ".san"
  467. env.Append(LINKFLAGS=["/INFERASANLIBS"])
  468. env.Append(CCFLAGS=["/fsanitize=address"])
  469. # Incremental linking fix
  470. env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"]
  471. env["BUILDERS"]["Program"] = methods.precious_program
  472. env.Append(LINKFLAGS=["/NATVIS:platform\\windows\\godot.natvis"])
  473. env.AppendUnique(LINKFLAGS=["/STACK:" + str(STACK_SIZE)])
  474. def configure_mingw(env: "SConsEnvironment"):
  475. # Workaround for MinGW. See:
  476. # https://www.scons.org/wiki/LongCmdLinesOnWin32
  477. env.use_windows_spawn_fix()
  478. ## Build type
  479. if not env["use_llvm"] and not get_mingw_tool("gcc", env["mingw_prefix"], env["arch"]):
  480. env["use_llvm"] = True
  481. if env["use_llvm"] and not get_mingw_tool("clang", env["mingw_prefix"], env["arch"]):
  482. env["use_llvm"] = False
  483. # TODO: Re-evaluate the need for this / streamline with common config.
  484. if env["target"] == "template_release":
  485. env.Append(CCFLAGS=["-msse2"])
  486. elif env.dev_build:
  487. # Allow big objects. It's supposed not to have drawbacks but seems to break
  488. # GCC LTO, so enabling for debug builds only (which are not built with LTO
  489. # and are the only ones with too big objects).
  490. env.Append(CCFLAGS=["-Wa,-mbig-obj"])
  491. if env["windows_subsystem"] == "gui":
  492. env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
  493. else:
  494. env.Append(LINKFLAGS=["-Wl,--subsystem,console"])
  495. env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"])
  496. ## Compiler configuration
  497. if os.name != "nt":
  498. env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation
  499. if env["arch"] == "x86_32":
  500. if env["use_static_cpp"]:
  501. env.Append(LINKFLAGS=["-static"])
  502. env.Append(LINKFLAGS=["-static-libgcc"])
  503. env.Append(LINKFLAGS=["-static-libstdc++"])
  504. else:
  505. if env["use_static_cpp"]:
  506. env.Append(LINKFLAGS=["-static"])
  507. if env["arch"] in ["x86_32", "x86_64"]:
  508. env["x86_libtheora_opt_gcc"] = True
  509. if env["use_llvm"]:
  510. env["CC"] = get_mingw_tool("clang", env["mingw_prefix"], env["arch"])
  511. env["CXX"] = get_mingw_tool("clang++", env["mingw_prefix"], env["arch"])
  512. tool_as = get_mingw_tool("as", env["mingw_prefix"], env["arch"])
  513. tool_ar = get_mingw_tool("ar", env["mingw_prefix"], env["arch"])
  514. tool_ranlib = get_mingw_tool("ranlib", env["mingw_prefix"], env["arch"])
  515. env.extra_suffix = ".llvm" + env.extra_suffix
  516. else:
  517. env["CC"] = get_mingw_tool("gcc", env["mingw_prefix"], env["arch"])
  518. env["CXX"] = get_mingw_tool("g++", env["mingw_prefix"], env["arch"])
  519. tool_as = get_mingw_tool("as", env["mingw_prefix"], env["arch"])
  520. tool_ar = get_mingw_tool("gcc-ar", env["mingw_prefix"], env["arch"])
  521. tool_ranlib = get_mingw_tool("gcc-ranlib", env["mingw_prefix"], env["arch"])
  522. if tool_as:
  523. env["AS"] = tool_as
  524. if tool_ar:
  525. env["AR"] = tool_ar
  526. if tool_ranlib:
  527. env["RANLIB"] = tool_ranlib
  528. ## LTO
  529. if env["lto"] == "auto": # Full LTO for production with MinGW.
  530. env["lto"] = "full"
  531. if env["lto"] != "none":
  532. if env["lto"] == "thin":
  533. if not env["use_llvm"]:
  534. print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
  535. sys.exit(255)
  536. env.Append(CCFLAGS=["-flto=thin"])
  537. env.Append(LINKFLAGS=["-flto=thin"])
  538. elif not env["use_llvm"] and env.GetOption("num_jobs") > 1:
  539. env.Append(CCFLAGS=["-flto"])
  540. env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))])
  541. else:
  542. env.Append(CCFLAGS=["-flto"])
  543. env.Append(LINKFLAGS=["-flto"])
  544. env.Append(LINKFLAGS=["-Wl,--stack," + str(STACK_SIZE)])
  545. ## Compile flags
  546. if int(env["target_win_version"], 16) < 0x0601:
  547. print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
  548. sys.exit(255)
  549. if not env["use_llvm"]:
  550. env.Append(CCFLAGS=["-mwindows"])
  551. env.Append(CPPDEFINES=["WINDOWS_ENABLED", "WASAPI_ENABLED", "WINMIDI_ENABLED"])
  552. env.Append(
  553. CPPDEFINES=[
  554. ("WINVER", env["target_win_version"]),
  555. ("_WIN32_WINNT", env["target_win_version"]),
  556. ]
  557. )
  558. env.Append(
  559. LIBS=[
  560. "mingw32",
  561. "dsound",
  562. "ole32",
  563. "d3d9",
  564. "winmm",
  565. "gdi32",
  566. "iphlpapi",
  567. "shlwapi",
  568. "wsock32",
  569. "ws2_32",
  570. "kernel32",
  571. "oleaut32",
  572. "sapi",
  573. "dinput8",
  574. "dxguid",
  575. "ksuser",
  576. "imm32",
  577. "bcrypt",
  578. "crypt32",
  579. "avrt",
  580. "uuid",
  581. "dwmapi",
  582. "dwrite",
  583. "wbemuuid",
  584. "ntdll",
  585. ]
  586. )
  587. if env.debug_features:
  588. env.Append(LIBS=["psapi", "dbghelp"])
  589. if env["vulkan"]:
  590. env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"])
  591. if not env["use_volk"]:
  592. env.Append(LIBS=["vulkan"])
  593. if env["d3d12"]:
  594. # Check whether we have d3d12 dependencies installed.
  595. if not os.path.exists(env["mesa_libs"]):
  596. print_error(
  597. "The Direct3D 12 rendering driver requires dependencies to be installed.\n"
  598. "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
  599. "See the documentation for more information:\n\t"
  600. "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
  601. )
  602. sys.exit(255)
  603. env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
  604. env.Append(LIBS=["dxgi", "dxguid"])
  605. # PIX
  606. if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]):
  607. env["use_pix"] = False
  608. if env["use_pix"]:
  609. arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
  610. env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir])
  611. env.Append(LIBS=["WinPixEventRuntime"])
  612. env.Append(LIBPATH=[env["mesa_libs"] + "/bin"])
  613. env.Append(LIBS=["libNIR.windows." + env["arch"]])
  614. env.Append(LIBS=["version"]) # Mesa dependency.
  615. if env["opengl3"]:
  616. env.Append(CPPDEFINES=["GLES3_ENABLED"])
  617. if env["angle_libs"] != "":
  618. env.AppendUnique(CPPDEFINES=["EGL_STATIC"])
  619. env.Append(LIBPATH=[env["angle_libs"]])
  620. env.Append(
  621. LIBS=[
  622. "EGL.windows." + env["arch"],
  623. "GLES.windows." + env["arch"],
  624. "ANGLE.windows." + env["arch"],
  625. ]
  626. )
  627. env.Append(LIBS=["dxgi", "d3d9", "d3d11"])
  628. env.Prepend(CPPPATH=["#thirdparty/angle/include"])
  629. env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)])
  630. # resrc
  631. env.Append(BUILDERS={"RES": env.Builder(action=build_res_file, suffix=".o", src_suffix=".rc")})
  632. def configure(env: "SConsEnvironment"):
  633. # Validate arch.
  634. supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
  635. if env["arch"] not in supported_arches:
  636. print_error(
  637. 'Unsupported CPU architecture "%s" for Windows. Supported architectures are: %s.'
  638. % (env["arch"], ", ".join(supported_arches))
  639. )
  640. sys.exit(255)
  641. # At this point the env has been set up with basic tools/compilers.
  642. env.Prepend(CPPPATH=["#platform/windows"])
  643. if os.name == "nt":
  644. env["ENV"] = os.environ # this makes build less repeatable, but simplifies some things
  645. env["ENV"]["TMP"] = os.environ["TMP"]
  646. # First figure out which compiler, version, and target arch we're using
  647. if os.getenv("VCINSTALLDIR") and detect_build_env_arch() and not env["use_mingw"]:
  648. setup_msvc_manual(env)
  649. env.msvc = True
  650. vcvars_msvc_config = True
  651. elif env.get("MSVC_VERSION", "") and not env["use_mingw"]:
  652. setup_msvc_auto(env)
  653. env.msvc = True
  654. vcvars_msvc_config = False
  655. else:
  656. setup_mingw(env)
  657. env.msvc = False
  658. # Now set compiler/linker flags
  659. if env.msvc:
  660. configure_msvc(env, vcvars_msvc_config)
  661. else: # MinGW
  662. configure_mingw(env)