methods.py 26 KB

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