gen_odin.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. #-------------------------------------------------------------------------------
  2. # gen_odin.py
  3. #
  4. # Generate Odin bindings.
  5. #-------------------------------------------------------------------------------
  6. import textwrap
  7. import gen_ir
  8. import gen_util as util
  9. import os, shutil, sys
  10. bindings_root = 'sokol-odin'
  11. c_root = f'{bindings_root}/sokol/c'
  12. module_root = f'{bindings_root}/sokol'
  13. module_names = {
  14. 'slog_': 'log',
  15. 'sg_': 'gfx',
  16. 'sapp_': 'app',
  17. 'stm_': 'time',
  18. 'saudio_': 'audio',
  19. 'sgl_': 'gl',
  20. 'sdtx_': 'debugtext',
  21. 'sshape_': 'shape',
  22. 'sglue_': 'glue',
  23. 'simgui_': 'imgui',
  24. }
  25. system_libs = {
  26. 'sg_': {
  27. 'windows': {
  28. 'd3d11': "",
  29. 'gl': "",
  30. },
  31. 'macos': {
  32. 'metal': '"system:Cocoa.framework","system:QuartzCore.framework","system:Metal.framework","system:MetalKit.framework"',
  33. 'gl': '"system:Cocoa.framework","system:QuartzCore.framework","system:OpenGL.framework"'
  34. },
  35. 'linux': {
  36. 'gl': '"system:GL", "system:dl", "system:pthread"'
  37. }
  38. },
  39. 'sapp_': {
  40. 'windows': {
  41. 'd3d11': '',
  42. 'gl': '',
  43. },
  44. 'macos': {
  45. 'metal': '"system:Cocoa.framework","system:QuartzCore.framework","system:Metal.framework","system:MetalKit.framework"',
  46. 'gl': '"system:Cocoa.framework","system:QuartzCore.framework","system:OpenGL.framework"',
  47. },
  48. 'linux': {
  49. 'gl': '"system:X11", "system:Xi", "system:Xcursor", "system:GL", "system:dl", "system:pthread"'
  50. }
  51. },
  52. 'saudio_': {
  53. 'windows': {
  54. 'd3d11': '',
  55. 'gl': '',
  56. },
  57. 'macos': {
  58. 'metal': '"system:AudioToolbox.framework"',
  59. 'gl': '"system:AudioToolbox.framework"',
  60. },
  61. 'linux': {
  62. 'gl': '"system:asound", "system:dl", "system:pthread"',
  63. }
  64. }
  65. }
  66. c_source_names = {
  67. 'slog_': 'sokol_log.c',
  68. 'sg_': 'sokol_gfx.c',
  69. 'sapp_': 'sokol_app.c',
  70. 'sapp_sg': 'sokol_glue.c',
  71. 'stm_': 'sokol_time.c',
  72. 'saudio_': 'sokol_audio.c',
  73. 'sgl_': 'sokol_gl.c',
  74. 'sdtx_': 'sokol_debugtext.c',
  75. 'sshape_': 'sokol_shape.c',
  76. 'sglue_': 'sokol_glue.c',
  77. 'simgui_': 'sokol_imgui.c',
  78. }
  79. ignores = [
  80. 'sdtx_printf',
  81. 'sdtx_vprintf',
  82. 'sg_install_trace_hooks',
  83. 'sg_trace_hooks',
  84. ]
  85. # NOTE: syntax for function results: "func_name.RESULT"
  86. overrides = {
  87. 'context': 'ctx', # reserved keyword
  88. 'SGL_NO_ERROR': 'SGL_ERROR_NO_ERROR',
  89. }
  90. prim_types = {
  91. 'int': 'c.int',
  92. 'bool': 'bool',
  93. 'char': 'u8',
  94. 'int8_t': 'i8',
  95. 'uint8_t': 'u8',
  96. 'int16_t': 'i16',
  97. 'uint16_t': 'u16',
  98. 'int32_t': 'i32',
  99. 'uint32_t': 'u32',
  100. 'int64_t': 'i64',
  101. 'uint64_t': 'u64',
  102. 'float': 'f32',
  103. 'double': 'f64',
  104. 'uintptr_t': 'c.uintptr_t',
  105. 'intptr_t': 'c.intptr_t',
  106. 'size_t': 'c.size_t'
  107. }
  108. prim_defaults = {
  109. 'int': '0',
  110. 'bool': 'false',
  111. 'int8_t': '0',
  112. 'uint8_t': '0',
  113. 'int16_t': '0',
  114. 'uint16_t': '0',
  115. 'int32_t': '0',
  116. 'uint32_t': '0',
  117. 'int64_t': '0',
  118. 'uint64_t': '0',
  119. 'float': '0.0',
  120. 'double': '0.0',
  121. 'uintptr_t': '0',
  122. 'intptr_t': '0',
  123. 'size_t': '0'
  124. }
  125. struct_types = []
  126. enum_types = []
  127. enum_items = {}
  128. out_lines = ''
  129. def reset_globals():
  130. global struct_types
  131. global enum_types
  132. global enum_items
  133. global out_lines
  134. struct_types = []
  135. enum_types = []
  136. enum_items = {}
  137. out_lines = ''
  138. def l(s):
  139. global out_lines
  140. out_lines += s + '\n'
  141. def c(s, indent=""):
  142. if not s:
  143. return
  144. if '\n' in s:
  145. l(f'{indent}/*')
  146. l(textwrap.indent(textwrap.dedent(s), prefix=f" {indent}"))
  147. l(f'{indent}*/')
  148. else:
  149. l(f'{indent}// {s.strip()}')
  150. def check_override(name, default=None):
  151. if name in overrides:
  152. return overrides[name]
  153. elif default is None:
  154. return name
  155. else:
  156. return default
  157. def check_ignore(name):
  158. return name in ignores
  159. # PREFIX_BLA_BLUB to BLA_BLUB, prefix_bla_blub to bla_blub
  160. def as_snake_case(s, prefix):
  161. outp = s
  162. if outp.lower().startswith(prefix):
  163. outp = outp[len(prefix):]
  164. return outp
  165. def get_odin_module_path(c_prefix):
  166. return f'{module_root}/{module_names[c_prefix]}'
  167. def get_csource_path(c_prefix):
  168. return f'{c_root}/{c_source_names[c_prefix]}'
  169. def make_odin_module_directory(c_prefix):
  170. path = get_odin_module_path(c_prefix)
  171. if not os.path.isdir(path):
  172. os.makedirs(path)
  173. def as_prim_type(s):
  174. return prim_types[s]
  175. # prefix_bla_blub(_t) => (dep.)Bla_Blub
  176. def as_struct_or_enum_type(s, prefix):
  177. parts = s.lower().split('_')
  178. outp = '' if s.startswith(prefix) else f'{parts[0]}.'
  179. for part in parts[1:]:
  180. # ignore '_t' type postfix
  181. if (part != 't'):
  182. outp += part.capitalize()
  183. outp += '_'
  184. outp = outp[:-1]
  185. return outp
  186. # PREFIX_ENUM_BLA_BLUB => BLA_BLUB, _PREFIX_ENUM_BLA_BLUB => BLA_BLUB
  187. def as_enum_item_name(s):
  188. outp = s.lstrip('_')
  189. parts = outp.split('_')[2:]
  190. outp = '_'.join(parts)
  191. if outp[0].isdigit():
  192. outp = '_' + outp
  193. return outp
  194. def enum_default_item(enum_name):
  195. return enum_items[enum_name][0]
  196. def is_prim_type(s):
  197. return s in prim_types
  198. def is_int_type(s):
  199. return s == "int"
  200. def is_struct_type(s):
  201. return s in struct_types
  202. def is_enum_type(s):
  203. return s in enum_types
  204. def is_const_prim_ptr(s):
  205. for prim_type in prim_types:
  206. if s == f"const {prim_type} *":
  207. return True
  208. return False
  209. def is_prim_ptr(s):
  210. for prim_type in prim_types:
  211. if s == f"{prim_type} *":
  212. return True
  213. return False
  214. def is_const_struct_ptr(s):
  215. for struct_type in struct_types:
  216. if s == f"const {struct_type} *":
  217. return True
  218. return False
  219. def type_default_value(s):
  220. return prim_defaults[s]
  221. def map_type(type, prefix, sub_type):
  222. if sub_type not in ['c_arg', 'odin_arg', 'struct_field']:
  223. sys.exit(f"Error: map_type(): unknown sub_type '{sub_type}")
  224. if type == "void":
  225. return ""
  226. elif is_prim_type(type):
  227. if sub_type == 'odin_arg':
  228. # for Odin args, maps C int (32-bit) to Odin int (pointer-sized),
  229. # and the C bool type to Odin's bool type
  230. if type == 'int' or type == 'uint32_t':
  231. return 'int'
  232. elif type == 'bool':
  233. return 'bool'
  234. return as_prim_type(type)
  235. elif is_struct_type(type):
  236. return as_struct_or_enum_type(type, prefix)
  237. elif is_enum_type(type):
  238. return as_struct_or_enum_type(type, prefix)
  239. elif util.is_void_ptr(type):
  240. return "rawptr"
  241. elif util.is_const_void_ptr(type):
  242. return "rawptr"
  243. elif util.is_string_ptr(type):
  244. return "cstring"
  245. elif is_const_struct_ptr(type):
  246. # pass Odin struct args by value, not by pointer
  247. if sub_type == 'odin_arg':
  248. return f"{as_struct_or_enum_type(util.extract_ptr_type(type), prefix)}"
  249. else:
  250. return f"^{as_struct_or_enum_type(util.extract_ptr_type(type), prefix)}"
  251. elif is_prim_ptr(type):
  252. return f"^{as_prim_type(util.extract_ptr_type(type))}"
  253. elif is_const_prim_ptr(type):
  254. return f"^{as_prim_type(util.extract_ptr_type(type))}"
  255. elif util.is_1d_array_type(type):
  256. array_type = util.extract_array_type(type)
  257. array_sizes = util.extract_array_sizes(type)
  258. return f"[{array_sizes[0]}]{map_type(array_type, prefix, sub_type)}"
  259. elif util.is_2d_array_type(type):
  260. array_type = util.extract_array_type(type)
  261. array_sizes = util.extract_array_sizes(type)
  262. return f"[{array_sizes[0]}][{array_sizes[1]}]{map_type(array_type, prefix, sub_type)}"
  263. elif util.is_func_ptr(type):
  264. res_type = funcptr_result_c(type, prefix)
  265. res_str = '' if res_type == '' else f' -> {res_type}'
  266. return f'proc "c" ({funcptr_args_c(type, prefix)}){res_str}'
  267. else:
  268. sys.exit(f"Error map_type(): unknown type '{type}'")
  269. def funcdecl_args_c(decl, prefix):
  270. s = ''
  271. func_name = decl['name']
  272. for param_decl in decl['params']:
  273. if s != '':
  274. s += ', '
  275. param_name = param_decl['name']
  276. param_type = check_override(f'{func_name}.{param_name}', default=param_decl['type'])
  277. if is_const_struct_ptr(param_type):
  278. s += f"#by_ptr {param_name}: {map_type(param_type, prefix, 'odin_arg')}"
  279. elif is_int_type(param_type):
  280. s += f"#any_int {param_name}: {map_type(param_type, prefix, 'c_arg')}"
  281. else:
  282. s += f"{param_name}: {map_type(param_type, prefix, 'c_arg')}"
  283. return s
  284. def funcptr_args_c(field_type, prefix):
  285. tokens = field_type[field_type.index('(*)')+4:-1].split(',')
  286. s = ''
  287. arg_index = 0
  288. for token in tokens:
  289. arg_type = token.strip()
  290. if s != '':
  291. s += ', '
  292. c_arg = map_type(arg_type, prefix, 'c_arg')
  293. if c_arg == '':
  294. return ''
  295. else:
  296. s += f'a{arg_index}: {c_arg}'
  297. arg_index += 1
  298. return s
  299. def funcptr_result_c(field_type, prefix):
  300. res_type = field_type[:field_type.index('(*)')].strip()
  301. return map_type(res_type, prefix, 'c_arg')
  302. def funcdecl_result_c(decl, prefix):
  303. func_name = decl['name']
  304. decl_type = decl['type']
  305. res_c_type = decl_type[:decl_type.index('(')].strip()
  306. return map_type(check_override(f'{func_name}.RESULT', default=res_c_type), prefix, 'c_arg')
  307. def get_system_libs(module, platform, backend):
  308. if module in system_libs:
  309. if platform in system_libs[module]:
  310. if backend in system_libs[module][platform]:
  311. libs = system_libs[module][platform][backend]
  312. if libs != '':
  313. return f", {libs}"
  314. return ''
  315. def gen_c_imports(inp, c_prefix, prefix):
  316. module_name = inp["module"]
  317. clib_prefix = f'sokol_{module_name}'
  318. clib_import = f'{clib_prefix}_clib'
  319. windows_d3d11_libs = get_system_libs(prefix, 'windows', 'd3d11')
  320. windows_gl_libs = get_system_libs(prefix, 'windows', 'gl')
  321. macos_metal_libs = get_system_libs(prefix, 'macos', 'metal')
  322. macos_gl_libs = get_system_libs(prefix, 'macos', 'gl')
  323. linux_gl_libs = get_system_libs(prefix, 'linux', 'gl')
  324. l( 'import "core:c"')
  325. l( '')
  326. l( '_ :: c')
  327. l( '')
  328. l( 'SOKOL_DEBUG :: #config(SOKOL_DEBUG, ODIN_DEBUG)')
  329. l( '')
  330. l(f'DEBUG :: #config(SOKOL_{module_name.upper()}_DEBUG, SOKOL_DEBUG)')
  331. l( 'USE_GL :: #config(SOKOL_USE_GL, false)')
  332. l( 'USE_DLL :: #config(SOKOL_DLL, false)')
  333. l( '')
  334. l( 'when ODIN_OS == .Windows {')
  335. l( ' when USE_DLL {')
  336. l( ' when USE_GL {')
  337. l(f' when DEBUG {{ foreign import {clib_import} {{ "../sokol_dll_windows_x64_gl_debug.lib"{windows_gl_libs} }} }}')
  338. l(f' else {{ foreign import {clib_import} {{ "../sokol_dll_windows_x64_gl_release.lib"{windows_gl_libs} }} }}')
  339. l( ' } else {')
  340. l(f' when DEBUG {{ foreign import {clib_import} {{ "../sokol_dll_windows_x64_d3d11_debug.lib"{windows_d3d11_libs} }} }}')
  341. l(f' else {{ foreign import {clib_import} {{ "../sokol_dll_windows_x64_d3d11_release.lib"{windows_d3d11_libs} }} }}')
  342. l( ' }')
  343. l( ' } else {')
  344. l( ' when USE_GL {')
  345. l(f' when DEBUG {{ foreign import {clib_import} {{ "{clib_prefix}_windows_x64_gl_debug.lib"{windows_gl_libs} }} }}')
  346. l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_windows_x64_gl_release.lib"{windows_gl_libs} }} }}')
  347. l( ' } else {')
  348. l(f' when DEBUG {{ foreign import {clib_import} {{ "{clib_prefix}_windows_x64_d3d11_debug.lib"{windows_d3d11_libs} }} }}')
  349. l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_windows_x64_d3d11_release.lib"{windows_d3d11_libs} }} }}')
  350. l( ' }')
  351. l( ' }')
  352. l( '} else when ODIN_OS == .Darwin {')
  353. l( ' when USE_DLL {')
  354. l(f' when USE_GL && ODIN_ARCH == .arm64 && DEBUG {{ foreign import {clib_import} {{ "../dylib/sokol_dylib_macos_arm64_gl_debug.dylib" }} }}')
  355. l(f' else when USE_GL && ODIN_ARCH == .arm64 && !DEBUG {{ foreign import {clib_import} {{ "../dylib/sokol_dylib_macos_arm64_gl_release.dylib" }} }}')
  356. l(f' else when USE_GL && ODIN_ARCH == .amd64 && DEBUG {{ foreign import {clib_import} {{ "../dylib/sokol_dylib_macos_x64_gl_debug.dylib" }} }}')
  357. l(f' else when USE_GL && ODIN_ARCH == .amd64 && !DEBUG {{ foreign import {clib_import} {{ "../dylib/sokol_dylib_macos_x64_gl_release.dylib" }} }}')
  358. l(f' else when !USE_GL && ODIN_ARCH == .arm64 && DEBUG {{ foreign import {clib_import} {{ "../dylib/sokol_dylib_macos_arm64_metal_debug.dylib" }} }}')
  359. l(f' else when !USE_GL && ODIN_ARCH == .arm64 && !DEBUG {{ foreign import {clib_import} {{ "../dylib/sokol_dylib_macos_arm64_metal_release.dylib" }} }}')
  360. l(f' else when !USE_GL && ODIN_ARCH == .amd64 && DEBUG {{ foreign import {clib_import} {{ "../dylib/sokol_dylib_macos_x64_metal_debug.dylib" }} }}')
  361. l(f' else when !USE_GL && ODIN_ARCH == .amd64 && !DEBUG {{ foreign import {clib_import} {{ "../dylib/sokol_dylib_macos_x64_metal_release.dylib" }} }}')
  362. l( ' } else {')
  363. l( ' when USE_GL {')
  364. l( ' when ODIN_ARCH == .arm64 {')
  365. l(f' when DEBUG {{ foreign import {clib_import} {{ "{clib_prefix}_macos_arm64_gl_debug.a"{macos_gl_libs} }} }}')
  366. l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_macos_arm64_gl_release.a"{macos_gl_libs} }} }}')
  367. l( ' } else {')
  368. l(f' when DEBUG {{ foreign import {clib_import} {{ "{clib_prefix}_macos_x64_gl_debug.a"{macos_gl_libs} }} }}')
  369. l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_macos_x64_gl_release.a"{macos_gl_libs} }} }}')
  370. l( ' }')
  371. l( ' } else {')
  372. l( ' when ODIN_ARCH == .arm64 {')
  373. l(f' when DEBUG {{ foreign import {clib_import} {{ "{clib_prefix}_macos_arm64_metal_debug.a"{macos_metal_libs} }} }}')
  374. l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_macos_arm64_metal_release.a"{macos_metal_libs} }} }}')
  375. l( ' } else {')
  376. l(f' when DEBUG {{ foreign import {clib_import} {{ "{clib_prefix}_macos_x64_metal_debug.a"{macos_metal_libs} }} }}')
  377. l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_macos_x64_metal_release.a"{macos_metal_libs} }} }}')
  378. l( ' }')
  379. l( ' }')
  380. l( ' }')
  381. l( '} else when ODIN_OS == .Linux {')
  382. l( ' when USE_DLL {')
  383. l(f' when DEBUG {{ foreign import {clib_import} {{ "{clib_prefix}_linux_x64_gl_debug.so"{linux_gl_libs} }} }}')
  384. l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_linux_x64_gl_release.so"{linux_gl_libs} }} }}')
  385. l( ' } else {')
  386. l(f' when DEBUG {{ foreign import {clib_import} {{ "{clib_prefix}_linux_x64_gl_debug.a"{linux_gl_libs} }} }}')
  387. l(f' else {{ foreign import {clib_import} {{ "{clib_prefix}_linux_x64_gl_release.a"{linux_gl_libs} }} }}')
  388. l( ' }')
  389. l( '} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {')
  390. l(f' // Feed {clib_prefix}_wasm_gl_debug.a or {clib_prefix}_wasm_gl_release.a into emscripten compiler.')
  391. l(f' foreign import {clib_import} {{ "env.o" }}')
  392. l( '} else {')
  393. l( ' #panic("This OS is currently not supported")')
  394. l( '}')
  395. l( '')
  396. # Need to special case sapp_sg to avoid Odin's context keyword
  397. if c_prefix == "sapp_sg":
  398. l(f'@(default_calling_convention="c")')
  399. else:
  400. l(f'@(default_calling_convention="c", link_prefix="{c_prefix}")')
  401. l(f"foreign {clib_import} {{")
  402. prefix = inp['prefix']
  403. for decl in inp['decls']:
  404. if decl['kind'] == 'func' and not decl['is_dep'] and not check_ignore(decl['name']):
  405. args = funcdecl_args_c(decl, prefix)
  406. res_type = funcdecl_result_c(decl, prefix)
  407. res_str = '' if res_type == '' else f'-> {res_type}'
  408. if decl.get('comment'):
  409. c(decl['comment'], indent=" ")
  410. # Need to special case sapp_sg to avoid Odin's context keyword
  411. if c_prefix == "sapp_sg":
  412. l(f' @(link_name="{decl["name"]}")')
  413. l(f" {check_override(as_snake_case(decl['name'], c_prefix))} :: proc({args}) {res_str} ---")
  414. else:
  415. l(f" {as_snake_case(decl['name'], c_prefix)} :: proc({args}) {res_str} ---")
  416. l('}')
  417. l('')
  418. def gen_consts(decl, prefix):
  419. c(decl.get('comment'))
  420. for item in decl['items']:
  421. item_name = check_override(item['name'])
  422. c(item.get('comment'))
  423. l(f"{as_snake_case(item_name, prefix)} :: {item['value']}")
  424. l('')
  425. def gen_struct(decl, prefix):
  426. c_struct_name = check_override(decl['name'])
  427. struct_name = as_struct_or_enum_type(c_struct_name, prefix)
  428. if decl.get('comment'):
  429. c(decl['comment'])
  430. l(f'{struct_name} :: struct {{')
  431. for field in decl['fields']:
  432. field_name = check_override(field['name'])
  433. field_type = map_type(check_override(f'{c_struct_name}.{field_name}', default=field['type']), prefix, 'struct_field')
  434. # any field name starting with _ is considered private
  435. if field_name.startswith('_'):
  436. l(f' _ : {field_type},')
  437. else:
  438. l(f' {field_name} : {field_type},')
  439. l('}')
  440. l('')
  441. def gen_enum(decl, prefix):
  442. enum_name = check_override(decl['name'])
  443. if decl.get('comment'):
  444. c(decl['comment'])
  445. l(f'{as_struct_or_enum_type(enum_name, prefix)} :: enum i32 {{')
  446. for item in decl['items']:
  447. item_name = as_enum_item_name(check_override(item['name']))
  448. if item_name != 'FORCE_U32' and item_name != 'NUM':
  449. if 'value' in item:
  450. l(f" {item_name} = {item['value']},")
  451. else:
  452. l(f" {item_name},")
  453. l('}')
  454. l('')
  455. def gen_imports(dep_prefixes):
  456. for dep_prefix in dep_prefixes:
  457. dep_module_name = module_names[dep_prefix]
  458. l(f'import {dep_prefix[:-1]} "../{dep_module_name}"')
  459. l('')
  460. def gen_helpers(inp):
  461. if inp['prefix'] == 'sdtx_':
  462. l('import "core:fmt"')
  463. l('import "core:strings"')
  464. l('printf :: proc(s: string, args: ..any) {')
  465. l(' fstr := fmt.tprintf(s, ..args)')
  466. l(' putr(strings.unsafe_string_to_cstring(fstr), len(fstr))')
  467. l('}')
  468. def gen_module(inp, c_prefix, dep_prefixes):
  469. pre_parse(inp)
  470. l('// machine generated, do not edit')
  471. l('')
  472. l(f"package sokol_{inp['module']}")
  473. if inp.get('comment'):
  474. l('')
  475. c(inp['comment'])
  476. gen_imports(dep_prefixes)
  477. gen_helpers(inp)
  478. prefix = inp['prefix']
  479. gen_c_imports(inp, c_prefix, prefix)
  480. for decl in inp['decls']:
  481. if not decl['is_dep']:
  482. kind = decl['kind']
  483. if kind == 'consts':
  484. gen_consts(decl, prefix)
  485. elif not check_ignore(decl['name']):
  486. if kind == 'struct':
  487. gen_struct(decl, prefix)
  488. elif kind == 'enum':
  489. gen_enum(decl, prefix)
  490. def pre_parse(inp):
  491. global struct_types
  492. global enum_types
  493. for decl in inp['decls']:
  494. kind = decl['kind']
  495. if kind == 'struct':
  496. struct_types.append(decl['name'])
  497. elif kind == 'enum':
  498. enum_name = decl['name']
  499. enum_types.append(enum_name)
  500. enum_items[enum_name] = []
  501. for item in decl['items']:
  502. enum_items[enum_name].append(as_enum_item_name(item['name']))
  503. def prepare():
  504. print('=== Generating Odin bindings:')
  505. if not os.path.isdir(module_root):
  506. os.makedirs(module_root)
  507. if not os.path.isdir(c_root):
  508. os.makedirs(c_root)
  509. def gen(c_header_path, c_prefix, dep_c_prefixes):
  510. if not c_prefix in module_names:
  511. print(f' >> warning: skipping generation for {c_prefix} prefix...')
  512. return
  513. reset_globals()
  514. make_odin_module_directory(c_prefix)
  515. print(f' {c_header_path} => {module_names[c_prefix]}')
  516. shutil.copyfile(c_header_path, f'{c_root}/{os.path.basename(c_header_path)}')
  517. csource_path = get_csource_path(c_prefix)
  518. module_name = module_names[c_prefix]
  519. ir = gen_ir.gen(c_header_path, csource_path, module_name, c_prefix, dep_c_prefixes, with_comments=True)
  520. gen_module(ir, c_prefix, dep_c_prefixes)
  521. with open(f"{module_root}/{ir['module']}/{ir['module']}.odin", 'w', newline='\n') as f_outp:
  522. f_outp.write(out_lines)