qapi-types.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #
  2. # QAPI types generator
  3. #
  4. # Copyright IBM, Corp. 2011
  5. # Copyright (c) 2013-2016 Red Hat Inc.
  6. #
  7. # Authors:
  8. # Anthony Liguori <aliguori@us.ibm.com>
  9. # Markus Armbruster <armbru@redhat.com>
  10. #
  11. # This work is licensed under the terms of the GNU GPL, version 2.
  12. # See the COPYING file in the top-level directory.
  13. from qapi import *
  14. # variants must be emitted before their container; track what has already
  15. # been output
  16. objects_seen = set()
  17. def gen_fwd_object_or_array(name):
  18. return mcgen('''
  19. typedef struct %(c_name)s %(c_name)s;
  20. ''',
  21. c_name=c_name(name))
  22. def gen_array(name, element_type):
  23. return mcgen('''
  24. struct %(c_name)s {
  25. %(c_name)s *next;
  26. %(c_type)s value;
  27. };
  28. ''',
  29. c_name=c_name(name), c_type=element_type.c_type())
  30. def gen_struct_members(members):
  31. ret = ''
  32. for memb in members:
  33. if memb.optional:
  34. ret += mcgen('''
  35. bool has_%(c_name)s;
  36. ''',
  37. c_name=c_name(memb.name))
  38. ret += mcgen('''
  39. %(c_type)s %(c_name)s;
  40. ''',
  41. c_type=memb.type.c_type(), c_name=c_name(memb.name))
  42. return ret
  43. def gen_object(name, base, members, variants):
  44. if name in objects_seen:
  45. return ''
  46. objects_seen.add(name)
  47. ret = ''
  48. if variants:
  49. for v in variants.variants:
  50. if isinstance(v.type, QAPISchemaObjectType):
  51. ret += gen_object(v.type.name, v.type.base,
  52. v.type.local_members, v.type.variants)
  53. ret += mcgen('''
  54. struct %(c_name)s {
  55. ''',
  56. c_name=c_name(name))
  57. if base:
  58. ret += mcgen('''
  59. /* Members inherited from %(c_name)s: */
  60. ''',
  61. c_name=base.c_name())
  62. ret += gen_struct_members(base.members)
  63. ret += mcgen('''
  64. /* Own members: */
  65. ''')
  66. ret += gen_struct_members(members)
  67. if variants:
  68. ret += gen_variants(variants)
  69. # Make sure that all structs have at least one member; this avoids
  70. # potential issues with attempting to malloc space for zero-length
  71. # structs in C, and also incompatibility with C++ (where an empty
  72. # struct is size 1).
  73. if not (base and base.members) and not members and not variants:
  74. ret += mcgen('''
  75. char qapi_dummy_for_empty_struct;
  76. ''')
  77. ret += mcgen('''
  78. };
  79. ''')
  80. return ret
  81. def gen_upcast(name, base):
  82. # C makes const-correctness ugly. We have to cast away const to let
  83. # this function work for both const and non-const obj.
  84. return mcgen('''
  85. static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
  86. {
  87. return (%(base)s *)obj;
  88. }
  89. ''',
  90. c_name=c_name(name), base=base.c_name())
  91. def gen_variants(variants):
  92. ret = mcgen('''
  93. union { /* union tag is @%(c_name)s */
  94. ''',
  95. c_name=c_name(variants.tag_member.name))
  96. for var in variants.variants:
  97. # Ugly special case for simple union TODO get rid of it
  98. simple_union_type = var.simple_union_type()
  99. if simple_union_type:
  100. typ = simple_union_type.c_type()
  101. else:
  102. typ = var.type.c_unboxed_type()
  103. ret += mcgen('''
  104. %(c_type)s %(c_name)s;
  105. ''',
  106. c_type=typ,
  107. c_name=c_name(var.name))
  108. ret += mcgen('''
  109. } u;
  110. ''')
  111. return ret
  112. def gen_type_cleanup_decl(name):
  113. ret = mcgen('''
  114. void qapi_free_%(c_name)s(%(c_name)s *obj);
  115. ''',
  116. c_name=c_name(name))
  117. return ret
  118. def gen_type_cleanup(name):
  119. ret = mcgen('''
  120. void qapi_free_%(c_name)s(%(c_name)s *obj)
  121. {
  122. QapiDeallocVisitor *qdv;
  123. Visitor *v;
  124. if (!obj) {
  125. return;
  126. }
  127. qdv = qapi_dealloc_visitor_new();
  128. v = qapi_dealloc_get_visitor(qdv);
  129. visit_type_%(c_name)s(v, NULL, &obj, NULL);
  130. qapi_dealloc_visitor_cleanup(qdv);
  131. }
  132. ''',
  133. c_name=c_name(name))
  134. return ret
  135. class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
  136. def __init__(self):
  137. self.decl = None
  138. self.defn = None
  139. self._fwdecl = None
  140. self._btin = None
  141. def visit_begin(self, schema):
  142. # gen_object() is recursive, ensure it doesn't visit the empty type
  143. objects_seen.add(schema.the_empty_object_type.name)
  144. self.decl = ''
  145. self.defn = ''
  146. self._fwdecl = ''
  147. self._btin = guardstart('QAPI_TYPES_BUILTIN')
  148. def visit_end(self):
  149. self.decl = self._fwdecl + self.decl
  150. self._fwdecl = None
  151. # To avoid header dependency hell, we always generate
  152. # declarations for built-in types in our header files and
  153. # simply guard them. See also do_builtins (command line
  154. # option -b).
  155. self._btin += guardend('QAPI_TYPES_BUILTIN')
  156. self.decl = self._btin + self.decl
  157. self._btin = None
  158. def _gen_type_cleanup(self, name):
  159. self.decl += gen_type_cleanup_decl(name)
  160. self.defn += gen_type_cleanup(name)
  161. def visit_enum_type(self, name, info, values, prefix):
  162. # Special case for our lone builtin enum type
  163. # TODO use something cleaner than existence of info
  164. if not info:
  165. self._btin += gen_enum(name, values, prefix)
  166. if do_builtins:
  167. self.defn += gen_enum_lookup(name, values, prefix)
  168. else:
  169. self._fwdecl += gen_enum(name, values, prefix)
  170. self.defn += gen_enum_lookup(name, values, prefix)
  171. def visit_array_type(self, name, info, element_type):
  172. if isinstance(element_type, QAPISchemaBuiltinType):
  173. self._btin += gen_fwd_object_or_array(name)
  174. self._btin += gen_array(name, element_type)
  175. self._btin += gen_type_cleanup_decl(name)
  176. if do_builtins:
  177. self.defn += gen_type_cleanup(name)
  178. else:
  179. self._fwdecl += gen_fwd_object_or_array(name)
  180. self.decl += gen_array(name, element_type)
  181. self._gen_type_cleanup(name)
  182. def visit_object_type(self, name, info, base, members, variants):
  183. # Nothing to do for the special empty builtin
  184. if name == 'q_empty':
  185. return
  186. self._fwdecl += gen_fwd_object_or_array(name)
  187. self.decl += gen_object(name, base, members, variants)
  188. if base:
  189. self.decl += gen_upcast(name, base)
  190. # TODO Worth changing the visitor signature, so we could
  191. # directly use rather than repeat type.is_implicit()?
  192. if not name.startswith('q_'):
  193. # implicit types won't be directly allocated/freed
  194. self._gen_type_cleanup(name)
  195. def visit_alternate_type(self, name, info, variants):
  196. self._fwdecl += gen_fwd_object_or_array(name)
  197. self.decl += gen_object(name, None, [variants.tag_member], variants)
  198. self._gen_type_cleanup(name)
  199. # If you link code generated from multiple schemata, you want only one
  200. # instance of the code for built-in types. Generate it only when
  201. # do_builtins, enabled by command line option -b. See also
  202. # QAPISchemaGenTypeVisitor.visit_end().
  203. do_builtins = False
  204. (input_file, output_dir, do_c, do_h, prefix, opts) = \
  205. parse_command_line("b", ["builtins"])
  206. for o, a in opts:
  207. if o in ("-b", "--builtins"):
  208. do_builtins = True
  209. c_comment = '''
  210. /*
  211. * deallocation functions for schema-defined QAPI types
  212. *
  213. * Copyright IBM, Corp. 2011
  214. *
  215. * Authors:
  216. * Anthony Liguori <aliguori@us.ibm.com>
  217. * Michael Roth <mdroth@linux.vnet.ibm.com>
  218. *
  219. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  220. * See the COPYING.LIB file in the top-level directory.
  221. *
  222. */
  223. '''
  224. h_comment = '''
  225. /*
  226. * schema-defined QAPI types
  227. *
  228. * Copyright IBM, Corp. 2011
  229. *
  230. * Authors:
  231. * Anthony Liguori <aliguori@us.ibm.com>
  232. *
  233. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  234. * See the COPYING.LIB file in the top-level directory.
  235. *
  236. */
  237. '''
  238. (fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
  239. 'qapi-types.c', 'qapi-types.h',
  240. c_comment, h_comment)
  241. fdef.write(mcgen('''
  242. #include "qemu/osdep.h"
  243. #include "qapi/dealloc-visitor.h"
  244. #include "%(prefix)sqapi-types.h"
  245. #include "%(prefix)sqapi-visit.h"
  246. ''',
  247. prefix=prefix))
  248. # To avoid circular headers, use only typedefs.h here, not qobject.h
  249. fdecl.write(mcgen('''
  250. #include "qemu/typedefs.h"
  251. '''))
  252. schema = QAPISchema(input_file)
  253. gen = QAPISchemaGenTypeVisitor()
  254. schema.visit(gen)
  255. fdef.write(gen.defn)
  256. fdecl.write(gen.decl)
  257. close_output(fdef, fdecl)