gen_zig.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. #-------------------------------------------------------------------------------
  2. # Generate Zig bindings.
  3. #
  4. # Zig coding style:
  5. # - types are PascalCase
  6. # - functions are camelCase
  7. # - otherwise snake_case
  8. #-------------------------------------------------------------------------------
  9. import gen_ir
  10. import os, shutil, sys
  11. import gen_util as util
  12. module_names = {
  13. 'slog_': 'log',
  14. 'sg_': 'gfx',
  15. 'sapp_': 'app',
  16. 'stm_': 'time',
  17. 'saudio_': 'audio',
  18. 'sgl_': 'gl',
  19. 'sdtx_': 'debugtext',
  20. 'sshape_': 'shape',
  21. 'sglue_': 'glue',
  22. 'sfetch_': 'fetch',
  23. 'simgui_': 'imgui',
  24. }
  25. c_source_paths = {
  26. 'slog_': 'sokol-zig/src/sokol/c/sokol_log.c',
  27. 'sg_': 'sokol-zig/src/sokol/c/sokol_gfx.c',
  28. 'sapp_': 'sokol-zig/src/sokol/c/sokol_app.c',
  29. 'stm_': 'sokol-zig/src/sokol/c/sokol_time.c',
  30. 'saudio_': 'sokol-zig/src/sokol/c/sokol_audio.c',
  31. 'sgl_': 'sokol-zig/src/sokol/c/sokol_gl.c',
  32. 'sdtx_': 'sokol-zig/src/sokol/c/sokol_debugtext.c',
  33. 'sshape_': 'sokol-zig/src/sokol/c/sokol_shape.c',
  34. 'sglue_': 'sokol-zig/src/sokol/c/sokol_glue.c',
  35. 'sfetch_': 'sokol-zig/src/sokol/c/sokol_fetch.c',
  36. 'simgui_': 'sokol-zig/src/sokol/c/sokol_imgui.c',
  37. }
  38. ignores = [
  39. 'sdtx_printf',
  40. 'sdtx_vprintf',
  41. 'sg_install_trace_hooks',
  42. 'sg_trace_hooks',
  43. ]
  44. # functions that need to be exposed as 'raw' C callbacks without a Zig wrapper function
  45. c_callbacks = [
  46. 'slog_func'
  47. ]
  48. # NOTE: syntax for function results: "func_name.RESULT"
  49. overrides = {
  50. 'sgl_error': 'sgl_get_error', # 'error' is reserved in Zig
  51. 'sgl_deg': 'sgl_as_degrees',
  52. 'sgl_rad': 'sgl_as_radians',
  53. 'sg_apply_uniforms.ub_slot': 'uint32_t',
  54. 'sg_draw.base_element': 'uint32_t',
  55. 'sg_draw.num_elements': 'uint32_t',
  56. 'sg_draw.num_instances': 'uint32_t',
  57. 'sshape_element_range_t.base_element': 'uint32_t',
  58. 'sshape_element_range_t.num_elements': 'uint32_t',
  59. 'sdtx_font.font_index': 'uint32_t',
  60. 'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR',
  61. 'sfetch_continue': 'continue_fetching', # 'continue' is reserved in Zig
  62. 'sfetch_desc': 'sfetch_get_desc' # 'desc' shadowed by earlier definition
  63. }
  64. prim_types = {
  65. 'int': 'i32',
  66. 'bool': 'bool',
  67. 'char': 'u8',
  68. 'int8_t': 'i8',
  69. 'uint8_t': 'u8',
  70. 'int16_t': 'i16',
  71. 'uint16_t': 'u16',
  72. 'int32_t': 'i32',
  73. 'uint32_t': 'u32',
  74. 'int64_t': 'i64',
  75. 'uint64_t': 'u64',
  76. 'float': 'f32',
  77. 'double': 'f64',
  78. 'uintptr_t': 'usize',
  79. 'intptr_t': 'isize',
  80. 'size_t': 'usize'
  81. }
  82. prim_defaults = {
  83. 'int': '0',
  84. 'bool': 'false',
  85. 'int8_t': '0',
  86. 'uint8_t': '0',
  87. 'int16_t': '0',
  88. 'uint16_t': '0',
  89. 'int32_t': '0',
  90. 'uint32_t': '0',
  91. 'int64_t': '0',
  92. 'uint64_t': '0',
  93. 'float': '0.0',
  94. 'double': '0.0',
  95. 'uintptr_t': '0',
  96. 'intptr_t': '0',
  97. 'size_t': '0'
  98. }
  99. struct_types = []
  100. enum_types = []
  101. enum_items = {}
  102. out_lines = ''
  103. def reset_globals():
  104. global struct_types
  105. global enum_types
  106. global enum_items
  107. global out_lines
  108. struct_types = []
  109. enum_types = []
  110. enum_items = {}
  111. out_lines = ''
  112. def l(s):
  113. global out_lines
  114. out_lines += s + '\n'
  115. def as_zig_prim_type(s):
  116. return prim_types[s]
  117. # prefix_bla_blub(_t) => (dep.)BlaBlub
  118. def as_zig_struct_type(s, prefix):
  119. parts = s.lower().split('_')
  120. outp = '' if s.startswith(prefix) else f'{parts[0]}.'
  121. for part in parts[1:]:
  122. # ignore '_t' type postfix
  123. if (part != 't'):
  124. outp += part.capitalize()
  125. return outp
  126. # prefix_bla_blub(_t) => (dep.)BlaBlub
  127. def as_zig_enum_type(s, prefix):
  128. parts = s.lower().split('_')
  129. outp = '' if s.startswith(prefix) else f'{parts[0]}.'
  130. for part in parts[1:]:
  131. if (part != 't'):
  132. outp += part.capitalize()
  133. return outp
  134. def check_override(name, default=None):
  135. if name in overrides:
  136. return overrides[name]
  137. elif default is None:
  138. return name
  139. else:
  140. return default
  141. def check_ignore(name):
  142. return name in ignores
  143. # PREFIX_ENUM_BLA => Bla, _PREFIX_ENUM_BLA => Bla
  144. def as_enum_item_name(s):
  145. outp = s.lstrip('_')
  146. parts = outp.split('_')[2:]
  147. outp = '_'.join(parts)
  148. if outp[0].isdigit():
  149. outp = '_' + outp
  150. return outp
  151. def enum_default_item(enum_name):
  152. return enum_items[enum_name][0]
  153. def is_prim_type(s):
  154. return s in prim_types
  155. def is_struct_type(s):
  156. return s in struct_types
  157. def is_enum_type(s):
  158. return s in enum_types
  159. def is_const_prim_ptr(s):
  160. for prim_type in prim_types:
  161. if s == f"const {prim_type} *":
  162. return True
  163. return False
  164. def is_prim_ptr(s):
  165. for prim_type in prim_types:
  166. if s == f"{prim_type} *":
  167. return True
  168. return False
  169. def is_const_struct_ptr(s):
  170. for struct_type in struct_types:
  171. if s == f"const {struct_type} *":
  172. return True
  173. return False
  174. def type_default_value(s):
  175. return prim_defaults[s]
  176. def as_c_arg_type(arg_type, prefix):
  177. if arg_type == "void":
  178. return "void"
  179. elif is_prim_type(arg_type):
  180. return as_zig_prim_type(arg_type)
  181. elif is_struct_type(arg_type):
  182. return as_zig_struct_type(arg_type, prefix)
  183. elif is_enum_type(arg_type):
  184. return as_zig_enum_type(arg_type, prefix)
  185. elif util.is_void_ptr(arg_type):
  186. return "?*anyopaque"
  187. elif util.is_const_void_ptr(arg_type):
  188. return "?*const anyopaque"
  189. elif util.is_string_ptr(arg_type):
  190. return "[*c]const u8"
  191. elif is_const_struct_ptr(arg_type):
  192. return f"[*c]const {as_zig_struct_type(util.extract_ptr_type(arg_type), prefix)}"
  193. elif is_prim_ptr(arg_type):
  194. return f"[*c]{as_zig_prim_type(util.extract_ptr_type(arg_type))}"
  195. elif is_const_prim_ptr(arg_type):
  196. return f"[*c]const {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
  197. else:
  198. sys.exit(f"Error as_c_arg_type(): {arg_type}")
  199. def as_zig_arg_type(arg_prefix, arg_type, prefix):
  200. # NOTE: if arg_prefix is None, the result is used as return value
  201. pre = "" if arg_prefix is None else arg_prefix
  202. if arg_type == "void":
  203. if arg_prefix is None:
  204. return "void"
  205. else:
  206. return ""
  207. elif is_prim_type(arg_type):
  208. return pre + as_zig_prim_type(arg_type)
  209. elif is_struct_type(arg_type):
  210. return pre + as_zig_struct_type(arg_type, prefix)
  211. elif is_enum_type(arg_type):
  212. return pre + as_zig_enum_type(arg_type, prefix)
  213. elif util.is_void_ptr(arg_type):
  214. return pre + "?*anyopaque"
  215. elif util.is_const_void_ptr(arg_type):
  216. return pre + "?*const anyopaque"
  217. elif util.is_string_ptr(arg_type):
  218. return pre + "[:0]const u8"
  219. elif is_const_struct_ptr(arg_type):
  220. # not a bug, pass const structs by value
  221. return pre + f"{as_zig_struct_type(util.extract_ptr_type(arg_type), prefix)}"
  222. elif is_prim_ptr(arg_type):
  223. return pre + f"*{as_zig_prim_type(util.extract_ptr_type(arg_type))}"
  224. elif is_const_prim_ptr(arg_type):
  225. return pre + f"*const {as_zig_prim_type(util.extract_ptr_type(arg_type))}"
  226. else:
  227. sys.exit(f"ERROR as_zig_arg_type(): {arg_type}")
  228. def is_zig_string(zig_type):
  229. return zig_type == "[:0]const u8"
  230. # get C-style arguments of a function pointer as string
  231. def funcptr_args_c(field_type, prefix):
  232. tokens = field_type[field_type.index('(*)')+4:-1].split(',')
  233. s = ""
  234. for token in tokens:
  235. arg_type = token.strip()
  236. if s != "":
  237. s += ", "
  238. c_arg = as_c_arg_type(arg_type, prefix)
  239. if c_arg == "void":
  240. return ""
  241. else:
  242. s += c_arg
  243. return s
  244. # get C-style result of a function pointer as string
  245. def funcptr_result_c(field_type):
  246. res_type = field_type[:field_type.index('(*)')].strip()
  247. if res_type == 'void':
  248. return 'void'
  249. elif is_prim_type(res_type):
  250. return as_zig_prim_type(res_type)
  251. elif util.is_const_void_ptr(res_type):
  252. return '?*const anyopaque'
  253. elif util.is_void_ptr(res_type):
  254. return '?*anyopaque'
  255. else:
  256. sys.exit(f"ERROR funcptr_result_c(): {field_type}")
  257. def funcdecl_args_c(decl, prefix):
  258. s = ""
  259. func_name = decl['name']
  260. for param_decl in decl['params']:
  261. if s != "":
  262. s += ", "
  263. param_name = param_decl['name']
  264. param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type'])
  265. s += as_c_arg_type(param_type, prefix)
  266. return s
  267. def funcdecl_args_zig(decl, prefix):
  268. s = ""
  269. func_name = decl['name']
  270. for param_decl in decl['params']:
  271. if s != "":
  272. s += ", "
  273. param_name = param_decl['name']
  274. param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type'])
  275. s += f"{as_zig_arg_type(f'{param_name}: ', param_type, prefix)}"
  276. return s
  277. def funcdecl_result_c(decl, prefix):
  278. func_name = decl['name']
  279. decl_type = decl['type']
  280. result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip())
  281. return as_c_arg_type(result_type, prefix)
  282. def funcdecl_result_zig(decl, prefix):
  283. func_name = decl['name']
  284. decl_type = decl['type']
  285. result_type = check_override(f'{func_name}.RESULT', default=decl_type[:decl_type.index('(')].strip())
  286. zig_res_type = as_zig_arg_type(None, result_type, prefix)
  287. return zig_res_type
  288. def gen_struct(decl, prefix):
  289. struct_name = check_override(decl['name'])
  290. zig_type = as_zig_struct_type(struct_name, prefix)
  291. l(f"pub const {zig_type} = extern struct {{")
  292. for field in decl['fields']:
  293. field_name = check_override(field['name'])
  294. field_type = check_override(f'{struct_name}.{field_name}', default=field['type'])
  295. if is_prim_type(field_type):
  296. l(f" {field_name}: {as_zig_prim_type(field_type)} = {type_default_value(field_type)},")
  297. elif is_struct_type(field_type):
  298. l(f" {field_name}: {as_zig_struct_type(field_type, prefix)} = .{{}},")
  299. elif is_enum_type(field_type):
  300. l(f" {field_name}: {as_zig_enum_type(field_type, prefix)} = .{enum_default_item(field_type)},")
  301. elif util.is_string_ptr(field_type):
  302. l(f" {field_name}: [*c]const u8 = null,")
  303. elif util.is_const_void_ptr(field_type):
  304. l(f" {field_name}: ?*const anyopaque = null,")
  305. elif util.is_void_ptr(field_type):
  306. l(f" {field_name}: ?*anyopaque = null,")
  307. elif is_const_prim_ptr(field_type):
  308. l(f" {field_name}: ?[*]const {as_zig_prim_type(util.extract_ptr_type(field_type))} = null,")
  309. elif util.is_func_ptr(field_type):
  310. l(f" {field_name}: ?*const fn ({funcptr_args_c(field_type, prefix)}) callconv(.C) {funcptr_result_c(field_type)} = null,")
  311. elif util.is_1d_array_type(field_type):
  312. array_type = util.extract_array_type(field_type)
  313. array_sizes = util.extract_array_sizes(field_type)
  314. if is_prim_type(array_type) or is_struct_type(array_type):
  315. if is_prim_type(array_type):
  316. zig_type = as_zig_prim_type(array_type)
  317. def_val = type_default_value(array_type)
  318. elif is_struct_type(array_type):
  319. zig_type = as_zig_struct_type(array_type, prefix)
  320. def_val = '.{}'
  321. elif is_enum_type(array_type):
  322. zig_type = as_zig_enum_type(array_type, prefix)
  323. def_val = '.{}'
  324. else:
  325. sys.exit(f"ERROR gen_struct is_1d_array_type: {array_type}")
  326. t0 = f"[{array_sizes[0]}]{zig_type}"
  327. t1 = f"[_]{zig_type}"
  328. l(f" {field_name}: {t0} = {t1}{{{def_val}}} ** {array_sizes[0]},")
  329. elif util.is_const_void_ptr(array_type):
  330. l(f" {field_name}: [{array_sizes[0]}]?*const anyopaque = [_]?*const anyopaque{{null}} ** {array_sizes[0]},")
  331. else:
  332. sys.exit(f"ERROR gen_struct: array {field_name}: {field_type} => {array_type} [{array_sizes[0]}]")
  333. elif util.is_2d_array_type(field_type):
  334. array_type = util.extract_array_type(field_type)
  335. array_sizes = util.extract_array_sizes(field_type)
  336. if is_prim_type(array_type):
  337. zig_type = as_zig_prim_type(array_type)
  338. def_val = type_default_value(array_type)
  339. elif is_struct_type(array_type):
  340. zig_type = as_zig_struct_type(array_type, prefix)
  341. def_val = ".{}"
  342. else:
  343. sys.exit(f"ERROR gen_struct is_2d_array_type: {array_type}")
  344. t0 = f"[{array_sizes[0]}][{array_sizes[1]}]{zig_type}"
  345. l(f" {field_name}: {t0} = [_][{array_sizes[1]}]{zig_type}{{[_]{zig_type}{{{def_val}}} ** {array_sizes[1]}}} ** {array_sizes[0]},")
  346. else:
  347. sys.exit(f"ERROR gen_struct: {field_name}: {field_type};")
  348. l("};")
  349. def gen_consts(decl, prefix):
  350. for item in decl['items']:
  351. item_name = check_override(item['name'])
  352. l(f"pub const {util.as_lower_snake_case(item_name, prefix)} = {item['value']};")
  353. def gen_enum(decl, prefix):
  354. enum_name = check_override(decl['name'])
  355. l(f"pub const {as_zig_enum_type(enum_name, prefix)} = enum(i32) {{")
  356. for item in decl['items']:
  357. item_name = as_enum_item_name(check_override(item['name']))
  358. if item_name != "FORCE_U32":
  359. if 'value' in item:
  360. l(f" {item_name} = {item['value']},")
  361. else:
  362. l(f" {item_name},")
  363. l("};")
  364. def gen_func_c(decl, prefix):
  365. l(f"pub extern fn {decl['name']}({funcdecl_args_c(decl, prefix)}) {funcdecl_result_c(decl, prefix)};")
  366. def gen_func_zig(decl, prefix):
  367. c_func_name = decl['name']
  368. zig_func_name = util.as_lower_camel_case(check_override(decl['name']), prefix)
  369. if c_func_name in c_callbacks:
  370. # a simple forwarded C callback function
  371. l(f"pub const {zig_func_name} = {c_func_name};")
  372. else:
  373. zig_res_type = funcdecl_result_zig(decl, prefix)
  374. l(f"pub fn {zig_func_name}({funcdecl_args_zig(decl, prefix)}) {zig_res_type} {{")
  375. if is_zig_string(zig_res_type):
  376. # special case: convert C string to Zig string slice
  377. s = f" return cStrToZig({c_func_name}("
  378. elif zig_res_type != 'void':
  379. s = f" return {c_func_name}("
  380. else:
  381. s = f" {c_func_name}("
  382. for i, param_decl in enumerate(decl['params']):
  383. if i > 0:
  384. s += ", "
  385. arg_name = param_decl['name']
  386. arg_type = param_decl['type']
  387. if is_const_struct_ptr(arg_type):
  388. s += f"&{arg_name}"
  389. elif util.is_string_ptr(arg_type):
  390. s += f"@ptrCast({arg_name})"
  391. else:
  392. s += arg_name
  393. if is_zig_string(zig_res_type):
  394. s += ")"
  395. s += ");"
  396. l(s)
  397. l("}")
  398. def pre_parse(inp):
  399. global struct_types
  400. global enum_types
  401. for decl in inp['decls']:
  402. kind = decl['kind']
  403. if kind == 'struct':
  404. struct_types.append(decl['name'])
  405. elif kind == 'enum':
  406. enum_name = decl['name']
  407. enum_types.append(enum_name)
  408. enum_items[enum_name] = []
  409. for item in decl['items']:
  410. enum_items[enum_name].append(as_enum_item_name(item['name']))
  411. def gen_imports(inp, dep_prefixes):
  412. l('const builtin = @import("builtin");')
  413. for dep_prefix in dep_prefixes:
  414. dep_module_name = module_names[dep_prefix]
  415. l(f'const {dep_prefix[:-1]} = @import("{dep_module_name}.zig");')
  416. l('')
  417. def gen_helpers(inp):
  418. l('// helper function to convert a C string to a Zig string slice')
  419. l('fn cStrToZig(c_str: [*c]const u8) [:0]const u8 {')
  420. l(' return @import("std").mem.span(c_str);')
  421. l('}')
  422. if inp['prefix'] in ['sg_', 'sdtx_', 'sshape_', 'sfetch_']:
  423. l('// helper function to convert "anything" to a Range struct')
  424. l('pub fn asRange(val: anytype) Range {')
  425. l(' const type_info = @typeInfo(@TypeOf(val));')
  426. l(' // FIXME: naming convention change between 0.13 and 0.14-dev')
  427. l(' if (@hasField(@TypeOf(type_info), "Pointer")) {')
  428. l(' switch (type_info) {')
  429. l(' .Pointer => {')
  430. l(' switch (type_info.Pointer.size) {')
  431. l(' .One => return .{ .ptr = val, .size = @sizeOf(type_info.Pointer.child) },')
  432. l(' .Slice => return .{ .ptr = val.ptr, .size = @sizeOf(type_info.Pointer.child) * val.len },')
  433. l(' else => @compileError("FIXME: Pointer type!"),')
  434. l(' }')
  435. l(' },')
  436. l(' .Struct, .Array => {')
  437. l(' @compileError("Structs and arrays must be passed as pointers to asRange");')
  438. l(' },')
  439. l(' else => {')
  440. l(' @compileError("Cannot convert to range!");')
  441. l(' },')
  442. l(' }')
  443. l(' } else {')
  444. l(' switch (type_info) {')
  445. l(' .pointer => {')
  446. l(' switch (type_info.pointer.size) {')
  447. l(' .One => return .{ .ptr = val, .size = @sizeOf(type_info.pointer.child) },')
  448. l(' .Slice => return .{ .ptr = val.ptr, .size = @sizeOf(type_info.pointer.child) * val.len },')
  449. l(' else => @compileError("FIXME: Pointer type!"),')
  450. l(' }')
  451. l(' },')
  452. l(' .@"struct", .array => {')
  453. l(' @compileError("Structs and arrays must be passed as pointers to asRange");')
  454. l(' },')
  455. l(' else => {')
  456. l(' @compileError("Cannot convert to range!");')
  457. l(' },')
  458. l(' }')
  459. l(' }')
  460. l('}')
  461. l('')
  462. if inp['prefix'] == 'sdtx_':
  463. l('// std.fmt compatible Writer')
  464. l('pub const Writer = struct {')
  465. l(' pub const Error = error{};')
  466. l(' pub fn writeAll(self: Writer, bytes: []const u8) Error!void {')
  467. l(' _ = self;')
  468. l(' for (bytes) |byte| {')
  469. l(' putc(byte);')
  470. l(' }')
  471. l(' }')
  472. l(' pub fn writeByteNTimes(self: Writer, byte: u8, n: usize) Error!void {')
  473. l(' _ = self;')
  474. l(' var i: u64 = 0;')
  475. l(' while (i < n) : (i += 1) {')
  476. l(' putc(byte);')
  477. l(' }')
  478. l(' }')
  479. l(' pub fn writeBytesNTimes(self: Writer, bytes: []const u8, n: usize) Error!void {')
  480. l(' var i: usize = 0;')
  481. l(' while (i < n) : (i += 1) {')
  482. l(' try self.writeAll(bytes);')
  483. l(' }')
  484. l(' }')
  485. l('};')
  486. l('// std.fmt-style formatted print')
  487. l('pub fn print(comptime fmt: anytype, args: anytype) void {')
  488. l(' const writer: Writer = .{};')
  489. l(' @import("std").fmt.format(writer, fmt, args) catch {};')
  490. l('}')
  491. l('')
  492. def gen_module(inp, dep_prefixes):
  493. l('// machine generated, do not edit')
  494. l('')
  495. gen_imports(inp, dep_prefixes)
  496. gen_helpers(inp)
  497. pre_parse(inp)
  498. prefix = inp['prefix']
  499. for decl in inp['decls']:
  500. if not decl['is_dep']:
  501. kind = decl['kind']
  502. if kind == 'consts':
  503. gen_consts(decl, prefix)
  504. elif not check_ignore(decl['name']):
  505. if kind == 'struct':
  506. gen_struct(decl, prefix)
  507. elif kind == 'enum':
  508. gen_enum(decl, prefix)
  509. elif kind == 'func':
  510. gen_func_c(decl, prefix)
  511. gen_func_zig(decl, prefix)
  512. def prepare():
  513. print('=== Generating Zig bindings:')
  514. if not os.path.isdir('sokol-zig/src/sokol'):
  515. os.makedirs('sokol-zig/src/sokol')
  516. if not os.path.isdir('sokol-zig/src/sokol/c'):
  517. os.makedirs('sokol-zig/src/sokol/c')
  518. def gen(c_header_path, c_prefix, dep_c_prefixes):
  519. if not c_prefix in module_names:
  520. print(f' >> warning: skipping generation for {c_prefix} prefix...')
  521. return
  522. module_name = module_names[c_prefix]
  523. c_source_path = c_source_paths[c_prefix]
  524. print(f' {c_header_path} => {module_name}')
  525. reset_globals()
  526. shutil.copyfile(c_header_path, f'sokol-zig/src/sokol/c/{os.path.basename(c_header_path)}')
  527. ir = gen_ir.gen(c_header_path, c_source_path, module_name, c_prefix, dep_c_prefixes)
  528. gen_module(ir, dep_c_prefixes)
  529. output_path = f"sokol-zig/src/sokol/{ir['module']}.zig"
  530. with open(output_path, 'w', newline='\n') as f_outp:
  531. f_outp.write(out_lines)