qapi-types.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. #
  2. # QAPI types generator
  3. #
  4. # Copyright IBM, Corp. 2011
  5. #
  6. # Authors:
  7. # Anthony Liguori <aliguori@us.ibm.com>
  8. #
  9. # This work is licensed under the terms of the GNU GPL, version 2.
  10. # See the COPYING file in the top-level directory.
  11. from ordereddict import OrderedDict
  12. from qapi import *
  13. def generate_fwd_struct(name, members, builtin_type=False):
  14. if builtin_type:
  15. return mcgen('''
  16. typedef struct %(name)sList
  17. {
  18. union {
  19. %(type)s value;
  20. uint64_t padding;
  21. };
  22. struct %(name)sList *next;
  23. } %(name)sList;
  24. ''',
  25. type=c_type(name),
  26. name=name)
  27. return mcgen('''
  28. typedef struct %(name)s %(name)s;
  29. typedef struct %(name)sList
  30. {
  31. union {
  32. %(name)s *value;
  33. uint64_t padding;
  34. };
  35. struct %(name)sList *next;
  36. } %(name)sList;
  37. ''',
  38. name=c_name(name))
  39. def generate_fwd_enum_struct(name, members):
  40. return mcgen('''
  41. typedef struct %(name)sList
  42. {
  43. union {
  44. %(name)s value;
  45. uint64_t padding;
  46. };
  47. struct %(name)sList *next;
  48. } %(name)sList;
  49. ''',
  50. name=c_name(name))
  51. def generate_struct_fields(members):
  52. ret = ''
  53. for argname, argentry, optional in parse_args(members):
  54. if optional:
  55. ret += mcgen('''
  56. bool has_%(c_name)s;
  57. ''',
  58. c_name=c_name(argname))
  59. ret += mcgen('''
  60. %(c_type)s %(c_name)s;
  61. ''',
  62. c_type=c_type(argentry), c_name=c_name(argname))
  63. return ret
  64. def generate_struct(expr):
  65. structname = expr.get('struct', "")
  66. fieldname = expr.get('field', "")
  67. members = expr['data']
  68. base = expr.get('base')
  69. ret = mcgen('''
  70. struct %(name)s
  71. {
  72. ''',
  73. name=c_name(structname))
  74. if base:
  75. ret += generate_struct_fields({'base': base})
  76. ret += generate_struct_fields(members)
  77. # Make sure that all structs have at least one field; this avoids
  78. # potential issues with attempting to malloc space for zero-length structs
  79. # in C, and also incompatibility with C++ (where an empty struct is size 1).
  80. if not base and not members:
  81. ret += mcgen('''
  82. char qapi_dummy_field_for_empty_struct;
  83. ''')
  84. if len(fieldname):
  85. fieldname = " " + fieldname
  86. ret += mcgen('''
  87. }%(field)s;
  88. ''',
  89. field=fieldname)
  90. return ret
  91. def generate_enum_lookup(name, values):
  92. ret = mcgen('''
  93. const char *%(name)s_lookup[] = {
  94. ''',
  95. name=c_name(name))
  96. i = 0
  97. for value in values:
  98. index = c_enum_const(name, value)
  99. ret += mcgen('''
  100. [%(index)s] = "%(value)s",
  101. ''',
  102. index = index, value = value)
  103. max_index = c_enum_const(name, 'MAX')
  104. ret += mcgen('''
  105. [%(max_index)s] = NULL,
  106. };
  107. ''',
  108. max_index=max_index)
  109. return ret
  110. def generate_enum(name, values):
  111. name = c_name(name)
  112. lookup_decl = mcgen('''
  113. extern const char *%(name)s_lookup[];
  114. ''',
  115. name=name)
  116. enum_decl = mcgen('''
  117. typedef enum %(name)s
  118. {
  119. ''',
  120. name=name)
  121. # append automatically generated _MAX value
  122. enum_values = values + [ 'MAX' ]
  123. i = 0
  124. for value in enum_values:
  125. enum_full_value = c_enum_const(name, value)
  126. enum_decl += mcgen('''
  127. %(enum_full_value)s = %(i)d,
  128. ''',
  129. enum_full_value = enum_full_value,
  130. i=i)
  131. i += 1
  132. enum_decl += mcgen('''
  133. } %(name)s;
  134. ''',
  135. name=name)
  136. return lookup_decl + enum_decl
  137. def generate_alternate_qtypes(expr):
  138. name = expr['alternate']
  139. members = expr['data']
  140. ret = mcgen('''
  141. const int %(name)s_qtypes[QTYPE_MAX] = {
  142. ''',
  143. name=c_name(name))
  144. for key in members:
  145. qtype = find_alternate_member_qtype(members[key])
  146. assert qtype, "Invalid alternate member"
  147. ret += mcgen('''
  148. [%(qtype)s] = %(enum_const)s,
  149. ''',
  150. qtype = qtype,
  151. enum_const = c_enum_const(name + 'Kind', key))
  152. ret += mcgen('''
  153. };
  154. ''')
  155. return ret
  156. def generate_union(expr, meta):
  157. name = c_name(expr[meta])
  158. typeinfo = expr['data']
  159. base = expr.get('base')
  160. discriminator = expr.get('discriminator')
  161. enum_define = discriminator_find_enum_define(expr)
  162. if enum_define:
  163. discriminator_type_name = enum_define['enum_name']
  164. else:
  165. discriminator_type_name = '%sKind' % (name)
  166. ret = mcgen('''
  167. struct %(name)s
  168. {
  169. %(discriminator_type_name)s kind;
  170. union {
  171. void *data;
  172. ''',
  173. name=name,
  174. discriminator_type_name=c_name(discriminator_type_name))
  175. for key in typeinfo:
  176. ret += mcgen('''
  177. %(c_type)s %(c_name)s;
  178. ''',
  179. c_type=c_type(typeinfo[key]),
  180. c_name=c_name(key))
  181. ret += mcgen('''
  182. };
  183. ''')
  184. if base:
  185. assert discriminator
  186. base_fields = find_struct(base)['data'].copy()
  187. del base_fields[discriminator]
  188. ret += generate_struct_fields(base_fields)
  189. else:
  190. assert not discriminator
  191. ret += mcgen('''
  192. };
  193. ''')
  194. if meta == 'alternate':
  195. ret += mcgen('''
  196. extern const int %(name)s_qtypes[];
  197. ''',
  198. name=name)
  199. return ret
  200. def generate_type_cleanup_decl(name):
  201. ret = mcgen('''
  202. void qapi_free_%(name)s(%(c_type)s obj);
  203. ''',
  204. c_type=c_type(name), name=c_name(name))
  205. return ret
  206. def generate_type_cleanup(name):
  207. ret = mcgen('''
  208. void qapi_free_%(name)s(%(c_type)s obj)
  209. {
  210. QapiDeallocVisitor *md;
  211. Visitor *v;
  212. if (!obj) {
  213. return;
  214. }
  215. md = qapi_dealloc_visitor_new();
  216. v = qapi_dealloc_get_visitor(md);
  217. visit_type_%(name)s(v, &obj, NULL, NULL);
  218. qapi_dealloc_visitor_cleanup(md);
  219. }
  220. ''',
  221. c_type=c_type(name), name=c_name(name))
  222. return ret
  223. do_builtins = False
  224. (input_file, output_dir, do_c, do_h, prefix, opts) = \
  225. parse_command_line("b", ["builtins"])
  226. for o, a in opts:
  227. if o in ("-b", "--builtins"):
  228. do_builtins = True
  229. c_comment = '''
  230. /*
  231. * deallocation functions for schema-defined QAPI types
  232. *
  233. * Copyright IBM, Corp. 2011
  234. *
  235. * Authors:
  236. * Anthony Liguori <aliguori@us.ibm.com>
  237. * Michael Roth <mdroth@linux.vnet.ibm.com>
  238. *
  239. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  240. * See the COPYING.LIB file in the top-level directory.
  241. *
  242. */
  243. '''
  244. h_comment = '''
  245. /*
  246. * schema-defined QAPI types
  247. *
  248. * Copyright IBM, Corp. 2011
  249. *
  250. * Authors:
  251. * Anthony Liguori <aliguori@us.ibm.com>
  252. *
  253. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  254. * See the COPYING.LIB file in the top-level directory.
  255. *
  256. */
  257. '''
  258. (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
  259. 'qapi-types.c', 'qapi-types.h',
  260. c_comment, h_comment)
  261. fdef.write(mcgen('''
  262. #include "qapi/dealloc-visitor.h"
  263. #include "%(prefix)sqapi-types.h"
  264. #include "%(prefix)sqapi-visit.h"
  265. ''',
  266. prefix=prefix))
  267. fdecl.write(mcgen('''
  268. #include <stdbool.h>
  269. #include <stdint.h>
  270. '''))
  271. exprs = parse_schema(input_file)
  272. exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
  273. fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
  274. for typename in builtin_types.keys():
  275. fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
  276. fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
  277. for expr in exprs:
  278. ret = "\n"
  279. if expr.has_key('struct'):
  280. ret += generate_fwd_struct(expr['struct'], expr['data'])
  281. elif expr.has_key('enum'):
  282. ret += generate_enum(expr['enum'], expr['data']) + "\n"
  283. ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
  284. fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
  285. elif expr.has_key('union'):
  286. ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
  287. enum_define = discriminator_find_enum_define(expr)
  288. if not enum_define:
  289. ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
  290. fdef.write(generate_enum_lookup('%sKind' % expr['union'],
  291. expr['data'].keys()))
  292. elif expr.has_key('alternate'):
  293. ret += generate_fwd_struct(expr['alternate'], expr['data']) + "\n"
  294. ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
  295. fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
  296. expr['data'].keys()))
  297. fdef.write(generate_alternate_qtypes(expr))
  298. else:
  299. continue
  300. fdecl.write(ret)
  301. # to avoid header dependency hell, we always generate declarations
  302. # for built-in types in our header files and simply guard them
  303. fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
  304. for typename in builtin_types.keys():
  305. fdecl.write(generate_type_cleanup_decl(typename + "List"))
  306. fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
  307. # ...this doesn't work for cases where we link in multiple objects that
  308. # have the functions defined, so we use -b option to provide control
  309. # over these cases
  310. if do_builtins:
  311. fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
  312. for typename in builtin_types.keys():
  313. fdef.write(generate_type_cleanup(typename + "List"))
  314. fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
  315. for expr in exprs:
  316. ret = "\n"
  317. if expr.has_key('struct'):
  318. ret += generate_struct(expr) + "\n"
  319. ret += generate_type_cleanup_decl(expr['struct'] + "List")
  320. fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n")
  321. ret += generate_type_cleanup_decl(expr['struct'])
  322. fdef.write(generate_type_cleanup(expr['struct']) + "\n")
  323. elif expr.has_key('union'):
  324. ret += generate_union(expr, 'union')
  325. ret += generate_type_cleanup_decl(expr['union'] + "List")
  326. fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
  327. ret += generate_type_cleanup_decl(expr['union'])
  328. fdef.write(generate_type_cleanup(expr['union']) + "\n")
  329. elif expr.has_key('alternate'):
  330. ret += generate_union(expr, 'alternate')
  331. ret += generate_type_cleanup_decl(expr['alternate'] + "List")
  332. fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n")
  333. ret += generate_type_cleanup_decl(expr['alternate'])
  334. fdef.write(generate_type_cleanup(expr['alternate']) + "\n")
  335. elif expr.has_key('enum'):
  336. ret += generate_type_cleanup_decl(expr['enum'] + "List")
  337. fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
  338. else:
  339. continue
  340. fdecl.write(ret)
  341. close_output(fdef, fdecl)