qapi-types.py 10 KB

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