qapi-types.py 8.1 KB

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