detect.py 22 KB

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