detect.py 26 KB

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