methods.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. import os
  2. import os.path
  3. import sys
  4. import re
  5. import glob
  6. import string
  7. import datetime
  8. import subprocess
  9. from compat import iteritems, isbasestring
  10. def add_source_files(self, sources, filetype, lib_env=None, shared=False):
  11. if isbasestring(filetype):
  12. dir_path = self.Dir('.').abspath
  13. filetype = glob.glob(dir_path + "/" + filetype)
  14. for path in filetype:
  15. sources.append(self.Object(path))
  16. def add_module_version_string(self,s):
  17. self.module_version_string += "." + s
  18. def update_version(module_version_string=""):
  19. build_name = "custom_build"
  20. if os.getenv("BUILD_NAME") != None:
  21. build_name = os.getenv("BUILD_NAME")
  22. print("Using custom build name: " + build_name)
  23. import version
  24. # NOTE: It is safe to generate this file here, since this is still executed serially
  25. f = open("core/version_generated.gen.h", "w")
  26. f.write("#define VERSION_SHORT_NAME \"" + str(version.short_name) + "\"\n")
  27. f.write("#define VERSION_NAME \"" + str(version.name) + "\"\n")
  28. f.write("#define VERSION_MAJOR " + str(version.major) + "\n")
  29. f.write("#define VERSION_MINOR " + str(version.minor) + "\n")
  30. if hasattr(version, 'patch'):
  31. f.write("#define VERSION_PATCH " + str(version.patch) + "\n")
  32. f.write("#define VERSION_STATUS \"" + str(version.status) + "\"\n")
  33. f.write("#define VERSION_BUILD \"" + str(build_name) + "\"\n")
  34. f.write("#define VERSION_MODULE_CONFIG \"" + str(version.module_config) + module_version_string + "\"\n")
  35. f.write("#define VERSION_YEAR " + str(2018) + "\n")
  36. f.close()
  37. # NOTE: It is safe to generate this file here, since this is still executed serially
  38. fhash = open("core/version_hash.gen.h", "w")
  39. githash = ""
  40. if os.path.isfile(".git/HEAD"):
  41. head = open(".git/HEAD", "r").readline().strip()
  42. if head.startswith("ref: "):
  43. head = ".git/" + head[5:]
  44. if os.path.isfile(head):
  45. githash = open(head, "r").readline().strip()
  46. else:
  47. githash = head
  48. fhash.write("#define VERSION_HASH \"" + githash + "\"")
  49. fhash.close()
  50. def parse_cg_file(fname, uniforms, sizes, conditionals):
  51. fs = open(fname, "r")
  52. line = fs.readline()
  53. while line:
  54. if re.match(r"^\s*uniform", line):
  55. res = re.match(r"uniform ([\d\w]*) ([\d\w]*)")
  56. type = res.groups(1)
  57. name = res.groups(2)
  58. uniforms.append(name)
  59. if type.find("texobj") != -1:
  60. sizes.append(1)
  61. else:
  62. t = re.match(r"float(\d)x(\d)", type)
  63. if t:
  64. sizes.append(int(t.groups(1)) * int(t.groups(2)))
  65. else:
  66. t = re.match(r"float(\d)", type)
  67. sizes.append(int(t.groups(1)))
  68. if line.find("[branch]") != -1:
  69. conditionals.append(name)
  70. line = fs.readline()
  71. fs.close()
  72. def detect_modules():
  73. module_list = []
  74. includes_cpp = ""
  75. register_cpp = ""
  76. unregister_cpp = ""
  77. files = glob.glob("modules/*")
  78. files.sort() # so register_module_types does not change that often, and also plugins are registered in alphabetic order
  79. for x in files:
  80. if not os.path.isdir(x):
  81. continue
  82. if not os.path.exists(x + "/config.py"):
  83. continue
  84. x = x.replace("modules/", "") # rest of world
  85. x = x.replace("modules\\", "") # win32
  86. module_list.append(x)
  87. try:
  88. with open("modules/" + x + "/register_types.h"):
  89. includes_cpp += '#include "modules/' + x + '/register_types.h"\n'
  90. register_cpp += '#ifdef MODULE_' + x.upper() + '_ENABLED\n'
  91. register_cpp += '\tregister_' + x + '_types();\n'
  92. register_cpp += '#endif\n'
  93. unregister_cpp += '#ifdef MODULE_' + x.upper() + '_ENABLED\n'
  94. unregister_cpp += '\tunregister_' + x + '_types();\n'
  95. unregister_cpp += '#endif\n'
  96. except IOError:
  97. pass
  98. modules_cpp = """
  99. // modules.cpp - THIS FILE IS GENERATED, DO NOT EDIT!!!!!!!
  100. #include "register_module_types.h"
  101. """ + includes_cpp + """
  102. void register_module_types() {
  103. """ + register_cpp + """
  104. }
  105. void unregister_module_types() {
  106. """ + unregister_cpp + """
  107. }
  108. """
  109. # NOTE: It is safe to generate this file here, since this is still executed serially
  110. with open("modules/register_module_types.gen.cpp", "w") as f:
  111. f.write(modules_cpp)
  112. return module_list
  113. def win32_spawn(sh, escape, cmd, args, env):
  114. import subprocess
  115. newargs = ' '.join(args[1:])
  116. cmdline = cmd + " " + newargs
  117. startupinfo = subprocess.STARTUPINFO()
  118. for e in env:
  119. if type(env[e]) != type(""):
  120. env[e] = str(env[e])
  121. proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
  122. stderr=subprocess.PIPE, startupinfo=startupinfo, shell=False, env=env)
  123. data, err = proc.communicate()
  124. rv = proc.wait()
  125. if rv:
  126. print("=====")
  127. print(err)
  128. print("=====")
  129. return rv
  130. """
  131. def win32_spawn(sh, escape, cmd, args, spawnenv):
  132. import win32file
  133. import win32event
  134. import win32process
  135. import win32security
  136. for var in spawnenv:
  137. spawnenv[var] = spawnenv[var].encode('ascii', 'replace')
  138. sAttrs = win32security.SECURITY_ATTRIBUTES()
  139. StartupInfo = win32process.STARTUPINFO()
  140. newargs = ' '.join(map(escape, args[1:]))
  141. cmdline = cmd + " " + newargs
  142. # check for any special operating system commands
  143. if cmd == 'del':
  144. for arg in args[1:]:
  145. win32file.DeleteFile(arg)
  146. exit_code = 0
  147. else:
  148. # otherwise execute the command.
  149. hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo)
  150. win32event.WaitForSingleObject(hProcess, win32event.INFINITE)
  151. exit_code = win32process.GetExitCodeProcess(hProcess)
  152. win32file.CloseHandle(hProcess);
  153. win32file.CloseHandle(hThread);
  154. return exit_code
  155. """
  156. def android_add_flat_dir(self, dir):
  157. if (dir not in self.android_flat_dirs):
  158. self.android_flat_dirs.append(dir)
  159. def android_add_maven_repository(self, url):
  160. if (url not in self.android_maven_repos):
  161. self.android_maven_repos.append(url)
  162. def android_add_dependency(self, depline):
  163. if (depline not in self.android_dependencies):
  164. self.android_dependencies.append(depline)
  165. def android_add_java_dir(self, subpath):
  166. base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + subpath
  167. if (base_path not in self.android_java_dirs):
  168. self.android_java_dirs.append(base_path)
  169. def android_add_res_dir(self, subpath):
  170. base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + subpath
  171. if (base_path not in self.android_res_dirs):
  172. self.android_res_dirs.append(base_path)
  173. def android_add_asset_dir(self, subpath):
  174. base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + subpath
  175. if (base_path not in self.android_asset_dirs):
  176. self.android_asset_dirs.append(base_path)
  177. def android_add_aidl_dir(self, subpath):
  178. base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + subpath
  179. if (base_path not in self.android_aidl_dirs):
  180. self.android_aidl_dirs.append(base_path)
  181. def android_add_jni_dir(self, subpath):
  182. base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + subpath
  183. if (base_path not in self.android_jni_dirs):
  184. self.android_jni_dirs.append(base_path)
  185. def android_add_gradle_plugin(self, plugin):
  186. if (plugin not in self.android_gradle_plugins):
  187. self.android_gradle_plugins.append(plugin)
  188. def android_add_gradle_classpath(self, classpath):
  189. if (classpath not in self.android_gradle_classpath):
  190. self.android_gradle_classpath.append(classpath)
  191. def android_add_default_config(self, config):
  192. if (config not in self.android_default_config):
  193. self.android_default_config.append(config)
  194. def android_add_to_manifest(self, file):
  195. base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + file
  196. with open(base_path, "r") as f:
  197. self.android_manifest_chunk += f.read()
  198. def android_add_to_permissions(self, file):
  199. base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + file
  200. with open(base_path, "r") as f:
  201. self.android_permission_chunk += f.read()
  202. def android_add_to_attributes(self, file):
  203. base_path = self.Dir(".").abspath + "/modules/" + self.current_module + "/" + file
  204. with open(base_path, "r") as f:
  205. self.android_appattributes_chunk += f.read()
  206. def disable_module(self):
  207. self.disabled_modules.append(self.current_module)
  208. def use_windows_spawn_fix(self, platform=None):
  209. if (os.name != "nt"):
  210. return # not needed, only for windows
  211. # On Windows, due to the limited command line length, when creating a static library
  212. # from a very high number of objects SCons will invoke "ar" once per object file;
  213. # that makes object files with same names to be overwritten so the last wins and
  214. # the library looses symbols defined by overwritten objects.
  215. # By enabling quick append instead of the default mode (replacing), libraries will
  216. # got built correctly regardless the invocation strategy.
  217. # Furthermore, since SCons will rebuild the library from scratch when an object file
  218. # changes, no multiple versions of the same object file will be present.
  219. self.Replace(ARFLAGS='q')
  220. def mySubProcess(cmdline, env):
  221. startupinfo = subprocess.STARTUPINFO()
  222. startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
  223. proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
  224. stderr=subprocess.PIPE, startupinfo=startupinfo, shell=False, env=env)
  225. data, err = proc.communicate()
  226. rv = proc.wait()
  227. if rv:
  228. print("=====")
  229. print(err)
  230. print("=====")
  231. return rv
  232. def mySpawn(sh, escape, cmd, args, env):
  233. newargs = ' '.join(args[1:])
  234. cmdline = cmd + " " + newargs
  235. rv = 0
  236. env = {str(key): str(value) for key, value in iteritems(env)}
  237. if len(cmdline) > 32000 and cmd.endswith("ar"):
  238. cmdline = cmd + " " + args[1] + " " + args[2] + " "
  239. for i in range(3, len(args)):
  240. rv = mySubProcess(cmdline + args[i], env)
  241. if rv:
  242. break
  243. else:
  244. rv = mySubProcess(cmdline, env)
  245. return rv
  246. self['SPAWN'] = mySpawn
  247. def split_lib(self, libname, src_list = None, env_lib = None):
  248. env = self
  249. num = 0
  250. cur_base = ""
  251. max_src = 64
  252. list = []
  253. lib_list = []
  254. if src_list == None:
  255. src_list = getattr(env, libname + "_sources")
  256. if type(env_lib) == type(None):
  257. env_lib = env
  258. for f in src_list:
  259. fname = ""
  260. if type(f) == type(""):
  261. fname = env.File(f).path
  262. else:
  263. fname = env.File(f)[0].path
  264. fname = fname.replace("\\", "/")
  265. base = string.join(fname.split("/")[:2], "/")
  266. if base != cur_base and len(list) > max_src:
  267. if num > 0:
  268. lib = env_lib.add_library(libname + str(num), list)
  269. lib_list.append(lib)
  270. list = []
  271. num = num + 1
  272. cur_base = base
  273. list.append(f)
  274. lib = env_lib.add_library(libname + str(num), list)
  275. lib_list.append(lib)
  276. if len(lib_list) > 0:
  277. if os.name == 'posix' and sys.platform == 'msys':
  278. env.Replace(ARFLAGS=['rcsT'])
  279. lib = env_lib.add_library(libname + "_collated", lib_list)
  280. lib_list = [lib]
  281. lib_base = []
  282. env_lib.add_source_files(lib_base, "*.cpp")
  283. lib = env_lib.add_library(libname, lib_base)
  284. lib_list.insert(0, lib)
  285. env.Prepend(LIBS=lib_list)
  286. def save_active_platforms(apnames, ap):
  287. for x in ap:
  288. names = ['logo']
  289. if os.path.isfile(x + "/run_icon.png"):
  290. names.append('run_icon')
  291. for name in names:
  292. pngf = open(x + "/" + name + ".png", "rb")
  293. b = pngf.read(1)
  294. str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n"
  295. str += " static const unsigned char _" + x[9:] + "_" + name + "[]={"
  296. while len(b) == 1:
  297. str += hex(ord(b))
  298. b = pngf.read(1)
  299. if (len(b) == 1):
  300. str += ","
  301. str += "};\n"
  302. pngf.close()
  303. # NOTE: It is safe to generate this file here, since this is still executed serially
  304. wf = x + "/" + name + ".gen.h"
  305. with open(wf, "w") as pngw:
  306. pngw.write(str)
  307. def no_verbose(sys, env):
  308. colors = {}
  309. # Colors are disabled in non-TTY environments such as pipes. This means
  310. # that if output is redirected to a file, it will not contain color codes
  311. if sys.stdout.isatty():
  312. colors['cyan'] = '\033[96m'
  313. colors['purple'] = '\033[95m'
  314. colors['blue'] = '\033[94m'
  315. colors['green'] = '\033[92m'
  316. colors['yellow'] = '\033[93m'
  317. colors['red'] = '\033[91m'
  318. colors['end'] = '\033[0m'
  319. else:
  320. colors['cyan'] = ''
  321. colors['purple'] = ''
  322. colors['blue'] = ''
  323. colors['green'] = ''
  324. colors['yellow'] = ''
  325. colors['red'] = ''
  326. colors['end'] = ''
  327. compile_source_message = '%sCompiling %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
  328. java_compile_source_message = '%sCompiling %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
  329. compile_shared_source_message = '%sCompiling shared %s==> %s$SOURCE%s' % (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
  330. link_program_message = '%sLinking Program %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
  331. link_library_message = '%sLinking Static Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
  332. ranlib_library_message = '%sRanlib Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
  333. link_shared_library_message = '%sLinking Shared Library %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
  334. java_library_message = '%sCreating Java Archive %s==> %s$TARGET%s' % (colors['red'], colors['purple'], colors['yellow'], colors['end'])
  335. env.Append(CXXCOMSTR=[compile_source_message])
  336. env.Append(CCCOMSTR=[compile_source_message])
  337. env.Append(SHCCCOMSTR=[compile_shared_source_message])
  338. env.Append(SHCXXCOMSTR=[compile_shared_source_message])
  339. env.Append(ARCOMSTR=[link_library_message])
  340. env.Append(RANLIBCOMSTR=[ranlib_library_message])
  341. env.Append(SHLINKCOMSTR=[link_shared_library_message])
  342. env.Append(LINKCOMSTR=[link_program_message])
  343. env.Append(JARCOMSTR=[java_library_message])
  344. env.Append(JAVACCOMSTR=[java_compile_source_message])
  345. def detect_visual_c_compiler_version(tools_env):
  346. # tools_env is the variable scons uses to call tools that execute tasks, SCons's env['ENV'] that executes tasks...
  347. # (see the SCons documentation for more information on what it does)...
  348. # in order for this function to be well encapsulated i choose to force it to receive SCons's TOOLS env (env['ENV']
  349. # and not scons setup environment (env)... so make sure you call the right environment on it or it will fail to detect
  350. # the proper vc version that will be called
  351. # There is no flag to give to visual c compilers to set the architecture, ie scons bits argument (32,64,ARM etc)
  352. # There are many different cl.exe files that are run, and each one compiles & links to a different architecture
  353. # As far as I know, the only way to figure out what compiler will be run when Scons calls cl.exe via Program()
  354. # is to check the PATH variable and figure out which one will be called first. Code below does that and returns:
  355. # the following string values:
  356. # "" Compiler not detected
  357. # "amd64" Native 64 bit compiler
  358. # "amd64_x86" 64 bit Cross Compiler for 32 bit
  359. # "x86" Native 32 bit compiler
  360. # "x86_amd64" 32 bit Cross Compiler for 64 bit
  361. # There are other architectures, but Godot does not support them currently, so this function does not detect arm/amd64_arm
  362. # and similar architectures/compilers
  363. # Set chosen compiler to "not detected"
  364. vc_chosen_compiler_index = -1
  365. vc_chosen_compiler_str = ""
  366. # Start with Pre VS 2017 checks which uses VCINSTALLDIR:
  367. if 'VCINSTALLDIR' in tools_env:
  368. # print("Checking VCINSTALLDIR")
  369. # find() works with -1 so big ifs below are needed... the simplest solution, in fact
  370. # First test if amd64 and amd64_x86 compilers are present in the path
  371. vc_amd64_compiler_detection_index = tools_env["PATH"].find(tools_env["VCINSTALLDIR"] + "BIN\\amd64;")
  372. if(vc_amd64_compiler_detection_index > -1):
  373. vc_chosen_compiler_index = vc_amd64_compiler_detection_index
  374. vc_chosen_compiler_str = "amd64"
  375. vc_amd64_x86_compiler_detection_index = tools_env["PATH"].find(tools_env["VCINSTALLDIR"] + "BIN\\amd64_x86;")
  376. if(vc_amd64_x86_compiler_detection_index > -1
  377. and (vc_chosen_compiler_index == -1
  378. or vc_chosen_compiler_index > vc_amd64_x86_compiler_detection_index)):
  379. vc_chosen_compiler_index = vc_amd64_x86_compiler_detection_index
  380. vc_chosen_compiler_str = "amd64_x86"
  381. # Now check the 32 bit compilers
  382. vc_x86_compiler_detection_index = tools_env["PATH"].find(tools_env["VCINSTALLDIR"] + "BIN;")
  383. if(vc_x86_compiler_detection_index > -1
  384. and (vc_chosen_compiler_index == -1
  385. or vc_chosen_compiler_index > vc_x86_compiler_detection_index)):
  386. vc_chosen_compiler_index = vc_x86_compiler_detection_index
  387. vc_chosen_compiler_str = "x86"
  388. vc_x86_amd64_compiler_detection_index = tools_env["PATH"].find(tools_env['VCINSTALLDIR'] + "BIN\\x86_amd64;")
  389. if(vc_x86_amd64_compiler_detection_index > -1
  390. and (vc_chosen_compiler_index == -1
  391. or vc_chosen_compiler_index > vc_x86_amd64_compiler_detection_index)):
  392. vc_chosen_compiler_index = vc_x86_amd64_compiler_detection_index
  393. vc_chosen_compiler_str = "x86_amd64"
  394. # and for VS 2017 and newer we check VCTOOLSINSTALLDIR:
  395. if 'VCTOOLSINSTALLDIR' in tools_env:
  396. # Newer versions have a different path available
  397. vc_amd64_compiler_detection_index = tools_env["PATH"].upper().find(tools_env['VCTOOLSINSTALLDIR'].upper() + "BIN\\HOSTX64\\X64;")
  398. if(vc_amd64_compiler_detection_index > -1):
  399. vc_chosen_compiler_index = vc_amd64_compiler_detection_index
  400. vc_chosen_compiler_str = "amd64"
  401. vc_amd64_x86_compiler_detection_index = tools_env["PATH"].upper().find(tools_env['VCTOOLSINSTALLDIR'].upper() + "BIN\\HOSTX64\\X86;")
  402. if(vc_amd64_x86_compiler_detection_index > -1
  403. and (vc_chosen_compiler_index == -1
  404. or vc_chosen_compiler_index > vc_amd64_x86_compiler_detection_index)):
  405. vc_chosen_compiler_index = vc_amd64_x86_compiler_detection_index
  406. vc_chosen_compiler_str = "amd64_x86"
  407. vc_x86_compiler_detection_index = tools_env["PATH"].upper().find(tools_env['VCTOOLSINSTALLDIR'].upper() + "BIN\\HOSTX86\\X86;")
  408. if(vc_x86_compiler_detection_index > -1
  409. and (vc_chosen_compiler_index == -1
  410. or vc_chosen_compiler_index > vc_x86_compiler_detection_index)):
  411. vc_chosen_compiler_index = vc_x86_compiler_detection_index
  412. vc_chosen_compiler_str = "x86"
  413. vc_x86_amd64_compiler_detection_index = tools_env["PATH"].upper().find(tools_env['VCTOOLSINSTALLDIR'].upper() + "BIN\\HOSTX86\\X64;")
  414. if(vc_x86_amd64_compiler_detection_index > -1
  415. and (vc_chosen_compiler_index == -1
  416. or vc_chosen_compiler_index > vc_x86_amd64_compiler_detection_index)):
  417. vc_chosen_compiler_index = vc_x86_amd64_compiler_detection_index
  418. vc_chosen_compiler_str = "x86_amd64"
  419. return vc_chosen_compiler_str
  420. def find_visual_c_batch_file(env):
  421. from SCons.Tool.MSCommon.vc import get_default_version, get_host_target, find_batch_file
  422. version = get_default_version(env)
  423. (host_platform, target_platform,req_target_platform) = get_host_target(env)
  424. return find_batch_file(env, version, host_platform, target_platform)[0]
  425. def generate_cpp_hint_file(filename):
  426. if os.path.isfile(filename):
  427. # Don't overwrite an existing hint file since the user may have customized it.
  428. pass
  429. else:
  430. try:
  431. with open(filename, "w") as fd:
  432. fd.write("#define GDCLASS(m_class, m_inherits)\n")
  433. except IOError:
  434. print("Could not write cpp.hint file.")
  435. def generate_vs_project(env, num_jobs):
  436. batch_file = find_visual_c_batch_file(env)
  437. if batch_file:
  438. def build_commandline(commands):
  439. common_build_prefix = ['cmd /V /C set "plat=$(PlatformTarget)"',
  440. '(if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))',
  441. 'set "tools=yes"',
  442. '(if "$(Configuration)"=="release" (set "tools=no"))',
  443. 'call "' + batch_file + '" !plat!']
  444. result = " ^& ".join(common_build_prefix + [commands])
  445. return result
  446. env.AddToVSProject(env.core_sources)
  447. env.AddToVSProject(env.main_sources)
  448. env.AddToVSProject(env.modules_sources)
  449. env.AddToVSProject(env.scene_sources)
  450. env.AddToVSProject(env.servers_sources)
  451. env.AddToVSProject(env.editor_sources)
  452. # windows allows us to have spaces in paths, so we need
  453. # to double quote off the directory. However, the path ends
  454. # in a backslash, so we need to remove this, lest it escape the
  455. # last double quote off, confusing MSBuild
  456. env['MSVSBUILDCOM'] = build_commandline('scons --directory="$(ProjectDir.TrimEnd(\'\\\'))" platform=windows progress=no target=$(Configuration) tools=!tools! -j' + str(num_jobs))
  457. env['MSVSREBUILDCOM'] = build_commandline('scons --directory="$(ProjectDir.TrimEnd(\'\\\'))" platform=windows progress=no target=$(Configuration) tools=!tools! vsproj=yes -j' + str(num_jobs))
  458. env['MSVSCLEANCOM'] = build_commandline('scons --directory="$(ProjectDir.TrimEnd(\'\\\'))" --clean platform=windows progress=no target=$(Configuration) tools=!tools! -j' + str(num_jobs))
  459. # This version information (Win32, x64, Debug, Release, Release_Debug seems to be
  460. # required for Visual Studio to understand that it needs to generate an NMAKE
  461. # project. Do not modify without knowing what you are doing.
  462. debug_variants = ['debug|Win32'] + ['debug|x64']
  463. release_variants = ['release|Win32'] + ['release|x64']
  464. release_debug_variants = ['release_debug|Win32'] + ['release_debug|x64']
  465. variants = debug_variants + release_variants + release_debug_variants
  466. debug_targets = ['bin\\godot.windows.tools.32.exe'] + ['bin\\godot.windows.tools.64.exe']
  467. release_targets = ['bin\\godot.windows.opt.32.exe'] + ['bin\\godot.windows.opt.64.exe']
  468. release_debug_targets = ['bin\\godot.windows.opt.tools.32.exe'] + ['bin\\godot.windows.opt.tools.64.exe']
  469. targets = debug_targets + release_targets + release_debug_targets
  470. env.MSVSProject(
  471. target=['#godot' + env['MSVSPROJECTSUFFIX']],
  472. incs=env.vs_incs,
  473. srcs=env.vs_srcs,
  474. runfile=targets,
  475. buildtarget=targets,
  476. auto_build_solution=1,
  477. variant=variants)
  478. else:
  479. print("Could not locate Visual Studio batch file for setting up the build environment. Not generating VS project.")
  480. def precious_program(env, program, sources, **args):
  481. program = env.ProgramOriginal(program, sources, **args)
  482. env.Precious(program)
  483. return program
  484. def add_shared_library(env, name, sources, **args):
  485. library = env.SharedLibrary(name, sources, **args)
  486. env.NoCache(library)
  487. return library
  488. def add_library(env, name, sources, **args):
  489. library = env.Library(name, sources, **args)
  490. env.NoCache(library)
  491. return library
  492. def add_program(env, name, sources, **args):
  493. program = env.Program(name, sources, **args)
  494. env.NoCache(program)
  495. return program
  496. def CommandNoCache(env, target, sources, command, **args):
  497. result = env.Command(target, sources, command, **args)
  498. env.NoCache(result)
  499. return result