core_builders.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. """Functions used to generate source files during build time
  2. All such functions are invoked in a subprocess on Windows to prevent build flakiness.
  3. """
  4. from platform_methods import subprocess_main
  5. def escape_string(s):
  6. def charcode_to_c_escapes(c):
  7. rev_result = []
  8. while c >= 256:
  9. c, low = (c // 256, c % 256)
  10. rev_result.append("\\%03o" % low)
  11. rev_result.append("\\%03o" % c)
  12. return "".join(reversed(rev_result))
  13. result = ""
  14. if isinstance(s, str):
  15. s = s.encode("utf-8")
  16. for c in s:
  17. if not (32 <= c < 127) or c in (ord("\\"), ord('"')):
  18. result += charcode_to_c_escapes(c)
  19. else:
  20. result += chr(c)
  21. return result
  22. def make_certs_header(target, source, env):
  23. src = source[0]
  24. dst = target[0]
  25. f = open(src, "rb")
  26. g = open(dst, "w", encoding="utf-8")
  27. buf = f.read()
  28. decomp_size = len(buf)
  29. import zlib
  30. buf = zlib.compress(buf)
  31. g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
  32. g.write("#ifndef CERTS_COMPRESSED_GEN_H\n")
  33. g.write("#define CERTS_COMPRESSED_GEN_H\n")
  34. # System certs path. Editor will use them if defined. (for package maintainers)
  35. path = env["system_certs_path"]
  36. g.write('#define _SYSTEM_CERTS_PATH "%s"\n' % str(path))
  37. if env["builtin_certs"]:
  38. # Defined here and not in env so changing it does not trigger a full rebuild.
  39. g.write("#define BUILTIN_CERTS_ENABLED\n")
  40. g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n")
  41. g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n")
  42. g.write("static const unsigned char _certs_compressed[] = {\n")
  43. for i in range(len(buf)):
  44. g.write("\t" + str(buf[i]) + ",\n")
  45. g.write("};\n")
  46. g.write("#endif // CERTS_COMPRESSED_GEN_H")
  47. g.close()
  48. f.close()
  49. def make_authors_header(target, source, env):
  50. sections = [
  51. "Project Founders",
  52. "Lead Developer",
  53. "Project Manager",
  54. "Developers",
  55. ]
  56. sections_id = [
  57. "AUTHORS_FOUNDERS",
  58. "AUTHORS_LEAD_DEVELOPERS",
  59. "AUTHORS_PROJECT_MANAGERS",
  60. "AUTHORS_DEVELOPERS",
  61. ]
  62. src = source[0]
  63. dst = target[0]
  64. f = open(src, "r", encoding="utf-8")
  65. g = open(dst, "w", encoding="utf-8")
  66. g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
  67. g.write("#ifndef AUTHORS_GEN_H\n")
  68. g.write("#define AUTHORS_GEN_H\n")
  69. reading = False
  70. def close_section():
  71. g.write("\t0\n")
  72. g.write("};\n")
  73. for line in f:
  74. if reading:
  75. if line.startswith(" "):
  76. g.write('\t"' + escape_string(line.strip()) + '",\n')
  77. continue
  78. if line.startswith("## "):
  79. if reading:
  80. close_section()
  81. reading = False
  82. for section, section_id in zip(sections, sections_id):
  83. if line.strip().endswith(section):
  84. current_section = escape_string(section_id)
  85. reading = True
  86. g.write("const char *const " + current_section + "[] = {\n")
  87. break
  88. if reading:
  89. close_section()
  90. g.write("#endif // AUTHORS_GEN_H\n")
  91. g.close()
  92. f.close()
  93. def make_donors_header(target, source, env):
  94. sections = [
  95. "Platinum sponsors",
  96. "Gold sponsors",
  97. "Mini sponsors",
  98. "Gold donors",
  99. "Silver donors",
  100. "Bronze donors",
  101. ]
  102. sections_id = [
  103. "DONORS_SPONSOR_PLAT",
  104. "DONORS_SPONSOR_GOLD",
  105. "DONORS_SPONSOR_MINI",
  106. "DONORS_GOLD",
  107. "DONORS_SILVER",
  108. "DONORS_BRONZE",
  109. ]
  110. src = source[0]
  111. dst = target[0]
  112. f = open(src, "r", encoding="utf-8")
  113. g = open(dst, "w", encoding="utf-8")
  114. g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
  115. g.write("#ifndef DONORS_GEN_H\n")
  116. g.write("#define DONORS_GEN_H\n")
  117. reading = False
  118. def close_section():
  119. g.write("\t0\n")
  120. g.write("};\n")
  121. for line in f:
  122. if reading >= 0:
  123. if line.startswith(" "):
  124. g.write('\t"' + escape_string(line.strip()) + '",\n')
  125. continue
  126. if line.startswith("## "):
  127. if reading:
  128. close_section()
  129. reading = False
  130. for section, section_id in zip(sections, sections_id):
  131. if line.strip().endswith(section):
  132. current_section = escape_string(section_id)
  133. reading = True
  134. g.write("const char *const " + current_section + "[] = {\n")
  135. break
  136. if reading:
  137. close_section()
  138. g.write("#endif // DONORS_GEN_H\n")
  139. g.close()
  140. f.close()
  141. def make_license_header(target, source, env):
  142. src_copyright = source[0]
  143. src_license = source[1]
  144. dst = target[0]
  145. class LicenseReader:
  146. def __init__(self, license_file):
  147. self._license_file = license_file
  148. self.line_num = 0
  149. self.current = self.next_line()
  150. def next_line(self):
  151. line = self._license_file.readline()
  152. self.line_num += 1
  153. while line.startswith("#"):
  154. line = self._license_file.readline()
  155. self.line_num += 1
  156. self.current = line
  157. return line
  158. def next_tag(self):
  159. if not ":" in self.current:
  160. return ("", [])
  161. tag, line = self.current.split(":", 1)
  162. lines = [line.strip()]
  163. while self.next_line() and self.current.startswith(" "):
  164. lines.append(self.current.strip())
  165. return (tag, lines)
  166. from collections import OrderedDict
  167. projects = OrderedDict()
  168. license_list = []
  169. with open(src_copyright, "r", encoding="utf-8") as copyright_file:
  170. reader = LicenseReader(copyright_file)
  171. part = {}
  172. while reader.current:
  173. tag, content = reader.next_tag()
  174. if tag in ("Files", "Copyright", "License"):
  175. part[tag] = content[:]
  176. elif tag == "Comment":
  177. # attach part to named project
  178. projects[content[0]] = projects.get(content[0], []) + [part]
  179. if not tag or not reader.current:
  180. # end of a paragraph start a new part
  181. if "License" in part and not "Files" in part:
  182. # no Files tag in this one, so assume standalone license
  183. license_list.append(part["License"])
  184. part = {}
  185. reader.next_line()
  186. data_list = []
  187. for project in iter(projects.values()):
  188. for part in project:
  189. part["file_index"] = len(data_list)
  190. data_list += part["Files"]
  191. part["copyright_index"] = len(data_list)
  192. data_list += part["Copyright"]
  193. with open(dst, "w", encoding="utf-8") as f:
  194. f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
  195. f.write("#ifndef LICENSE_GEN_H\n")
  196. f.write("#define LICENSE_GEN_H\n")
  197. f.write("const char *const GODOT_LICENSE_TEXT =")
  198. with open(src_license, "r", encoding="utf-8") as license_file:
  199. for line in license_file:
  200. escaped_string = escape_string(line.strip())
  201. f.write('\n\t\t"' + escaped_string + '\\n"')
  202. f.write(";\n\n")
  203. f.write(
  204. "struct ComponentCopyrightPart {\n"
  205. "\tconst char *license;\n"
  206. "\tconst char *const *files;\n"
  207. "\tconst char *const *copyright_statements;\n"
  208. "\tint file_count;\n"
  209. "\tint copyright_count;\n"
  210. "};\n\n"
  211. )
  212. f.write(
  213. "struct ComponentCopyright {\n"
  214. "\tconst char *name;\n"
  215. "\tconst ComponentCopyrightPart *parts;\n"
  216. "\tint part_count;\n"
  217. "};\n\n"
  218. )
  219. f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n")
  220. for line in data_list:
  221. f.write('\t"' + escape_string(line) + '",\n')
  222. f.write("};\n\n")
  223. f.write("const ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n")
  224. part_index = 0
  225. part_indexes = {}
  226. for project_name, project in iter(projects.items()):
  227. part_indexes[project_name] = part_index
  228. for part in project:
  229. f.write(
  230. '\t{ "'
  231. + escape_string(part["License"][0])
  232. + '", '
  233. + "&COPYRIGHT_INFO_DATA["
  234. + str(part["file_index"])
  235. + "], "
  236. + "&COPYRIGHT_INFO_DATA["
  237. + str(part["copyright_index"])
  238. + "], "
  239. + str(len(part["Files"]))
  240. + ", "
  241. + str(len(part["Copyright"]))
  242. + " },\n"
  243. )
  244. part_index += 1
  245. f.write("};\n\n")
  246. f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n")
  247. f.write("const ComponentCopyright COPYRIGHT_INFO[] = {\n")
  248. for project_name, project in iter(projects.items()):
  249. f.write(
  250. '\t{ "'
  251. + escape_string(project_name)
  252. + '", '
  253. + "&COPYRIGHT_PROJECT_PARTS["
  254. + str(part_indexes[project_name])
  255. + "], "
  256. + str(len(project))
  257. + " },\n"
  258. )
  259. f.write("};\n\n")
  260. f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n")
  261. f.write("const char *const LICENSE_NAMES[] = {\n")
  262. for l in license_list:
  263. f.write('\t"' + escape_string(l[0]) + '",\n')
  264. f.write("};\n\n")
  265. f.write("const char *const LICENSE_BODIES[] = {\n\n")
  266. for l in license_list:
  267. for line in l[1:]:
  268. if line == ".":
  269. f.write('\t"\\n"\n')
  270. else:
  271. f.write('\t"' + escape_string(line) + '\\n"\n')
  272. f.write('\t"",\n\n')
  273. f.write("};\n\n")
  274. f.write("#endif // LICENSE_GEN_H\n")
  275. if __name__ == "__main__":
  276. subprocess_main(globals())