qapi-types.py 9.5 KB
Newer Older
1 2 3 4
#
# QAPI types generator
#
# Copyright IBM, Corp. 2011
5
# Copyright (c) 2013-2015 Red Hat Inc.
6 7 8
#
# Authors:
#  Anthony Liguori <aliguori@us.ibm.com>
9
#  Markus Armbruster <armbru@redhat.com>
10
#
11 12
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
13 14 15

from qapi import *

16

17
def gen_fwd_object_or_array(name):
18
    return mcgen('''
19

20
typedef struct %(c_name)s %(c_name)s;
21
''',
22 23
                 c_name=c_name(name))

24

25
def gen_array(name, element_type):
26
    return mcgen('''
M
Markus Armbruster 已提交
27

28
struct %(c_name)s {
29
    union {
30
        %(c_type)s value;
31 32
        uint64_t padding;
    };
33
    %(c_name)s *next;
34
};
35
''',
36 37
                 c_name=c_name(name), c_type=element_type.c_type())

38

39
def gen_struct_field(name, typ, optional):
40
    ret = ''
41

42 43
    if optional:
        ret += mcgen('''
44 45
    bool has_%(c_name)s;
''',
46 47
                     c_name=c_name(name))
    ret += mcgen('''
48 49
    %(c_type)s %(c_name)s;
''',
50
                 c_type=typ.c_type(), c_name=c_name(name))
51 52
    return ret

53

54
def gen_struct_fields(local_members, base=None):
55
    ret = ''
56

57 58 59 60 61 62 63 64 65 66 67 68
    if base:
        ret += mcgen('''
    /* Members inherited from %(c_name)s: */
''',
                     c_name=base.c_name())
        for memb in base.members:
            ret += gen_struct_field(memb.name, memb.type, memb.optional)
        ret += mcgen('''
    /* Own members: */
''')

    for memb in local_members:
69 70
        ret += gen_struct_field(memb.name, memb.type, memb.optional)
    return ret
71

72

73
def gen_struct(name, base, members):
74
    ret = mcgen('''
M
Markus Armbruster 已提交
75

76
struct %(c_name)s {
77
''',
78
                c_name=c_name(name))
79

80
    if base:
81
        ret += gen_struct_field('base', base, False)
82

83
    ret += gen_struct_fields(members)
84

85
    # Make sure that all structs have at least one field; this avoids
86 87 88
    # potential issues with attempting to malloc space for zero-length
    # structs in C, and also incompatibility with C++ (where an empty
    # struct is size 1).
89
    if not base and not members:
90
        ret += mcgen('''
91 92 93
    char qapi_dummy_field_for_empty_struct;
''')

94
    ret += mcgen('''
95 96
};
''')
97 98 99

    return ret

100

101 102 103 104 105 106 107 108 109 110 111 112 113
def gen_upcast(name, base):
    # C makes const-correctness ugly.  We have to cast away const to let
    # this function work for both const and non-const obj.
    return mcgen('''

static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
{
    return (%(base)s *)obj;
}
''',
                 c_name=c_name(name), base=base.c_name())


114 115
def gen_alternate_qtypes_decl(name):
    return mcgen('''
K
Kevin Wolf 已提交
116

117 118 119
extern const int %(c_name)s_qtypes[];
''',
                 c_name=c_name(name))
K
Kevin Wolf 已提交
120

121

122
def gen_alternate_qtypes(name, variants):
K
Kevin Wolf 已提交
123
    ret = mcgen('''
M
Markus Armbruster 已提交
124

125
const int %(c_name)s_qtypes[QTYPE_MAX] = {
K
Kevin Wolf 已提交
126
''',
127
                c_name=c_name(name))
K
Kevin Wolf 已提交
128

129 130 131
    for var in variants.variants:
        qtype = var.type.alternate_qtype()
        assert qtype
K
Kevin Wolf 已提交
132 133

        ret += mcgen('''
E
Eric Blake 已提交
134
    [%(qtype)s] = %(enum_const)s,
K
Kevin Wolf 已提交
135
''',
136
                     qtype=qtype,
137 138
                     enum_const=c_enum_const(variants.tag_member.type.name,
                                             var.name))
K
Kevin Wolf 已提交
139 140 141 142 143 144

    ret += mcgen('''
};
''')
    return ret

145

146
def gen_union(name, base, variants):
147
    ret = mcgen('''
M
Markus Armbruster 已提交
148

149
struct %(c_name)s {
150
''',
151
                c_name=c_name(name))
152
    if base:
153
        ret += gen_struct_fields([], base)
154 155
    else:
        ret += mcgen('''
156
    %(c_type)s kind;
157
''',
158
                     c_type=c_name(variants.tag_member.type.name))
159

160 161 162 163 164 165 166 167
    # FIXME: What purpose does data serve, besides preventing a union that
    # has a branch named 'data'? We use it in qapi-visit.py to decide
    # whether to bypass the switch statement if visiting the discriminator
    # failed; but since we 0-initialize structs, and cannot tell what
    # branch of the union is in use if the discriminator is invalid, there
    # should not be any data leaks even without a data pointer.  Or, if
    # 'data' is merely added to guarantee we don't have an empty union,
    # shouldn't we enforce that at .json parse time?
168 169
    ret += mcgen('''
    union { /* union tag is @%(c_name)s */
170
        void *data;
171
''',
172 173 174 175 176 177 178 179
                 # TODO ugly special case for simple union
                 # Use same tag name in C as on the wire to get rid of
                 # it, then: c_name=c_name(variants.tag_member.name)
                 c_name=c_name(variants.tag_name or 'kind'))

    for var in variants.variants:
        # Ugly special case for simple union TODO get rid of it
        typ = var.simple_union_type() or var.type
180 181 182
        ret += mcgen('''
        %(c_type)s %(c_name)s;
''',
183 184
                     c_type=typ.c_type(),
                     c_name=c_name(var.name))
185 186 187 188 189 190 191 192

    ret += mcgen('''
    };
};
''')

    return ret

193 194

def gen_type_cleanup_decl(name):
195
    ret = mcgen('''
196

197
void qapi_free_%(c_name)s(%(c_name)s *obj);
198
''',
199
                c_name=c_name(name))
200 201
    return ret

202 203

def gen_type_cleanup(name):
204
    ret = mcgen('''
205

206
void qapi_free_%(c_name)s(%(c_name)s *obj)
207
{
208
    QapiDeallocVisitor *qdv;
209 210 211 212 213 214
    Visitor *v;

    if (!obj) {
        return;
    }

215 216
    qdv = qapi_dealloc_visitor_new();
    v = qapi_dealloc_get_visitor(qdv);
217
    visit_type_%(c_name)s(v, &obj, NULL, NULL);
218
    qapi_dealloc_visitor_cleanup(qdv);
219 220
}
''',
221
                c_name=c_name(name))
222 223
    return ret

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
    def __init__(self):
        self.decl = None
        self.defn = None
        self._fwdecl = None
        self._fwdefn = None
        self._btin = None

    def visit_begin(self, schema):
        self.decl = ''
        self.defn = ''
        self._fwdecl = ''
        self._fwdefn = ''
        self._btin = guardstart('QAPI_TYPES_BUILTIN')

    def visit_end(self):
        self.decl = self._fwdecl + self.decl
        self._fwdecl = None
        self.defn = self._fwdefn + self.defn
        self._fwdefn = None
        # To avoid header dependency hell, we always generate
        # declarations for built-in types in our header files and
        # simply guard them.  See also do_builtins (command line
        # option -b).
        self._btin += guardend('QAPI_TYPES_BUILTIN')
        self.decl = self._btin + self.decl
        self._btin = None

253 254
    def visit_needed(self, entity):
        # Visit everything except implicit objects
255 256
        return not (entity.is_implicit() and
                    isinstance(entity, QAPISchemaObjectType))
257

258
    def _gen_type_cleanup(self, name):
259 260
        self.decl += gen_type_cleanup_decl(name)
        self.defn += gen_type_cleanup(name)
261 262

    def visit_enum_type(self, name, info, values, prefix):
263 264
        self._fwdecl += gen_enum(name, values, prefix)
        self._fwdefn += gen_enum_lookup(name, values, prefix)
265 266 267 268 269

    def visit_array_type(self, name, info, element_type):
        if isinstance(element_type, QAPISchemaBuiltinType):
            self._btin += gen_fwd_object_or_array(name)
            self._btin += gen_array(name, element_type)
270
            self._btin += gen_type_cleanup_decl(name)
271
            if do_builtins:
272
                self.defn += gen_type_cleanup(name)
273 274 275 276 277 278
        else:
            self._fwdecl += gen_fwd_object_or_array(name)
            self.decl += gen_array(name, element_type)
            self._gen_type_cleanup(name)

    def visit_object_type(self, name, info, base, members, variants):
279 280 281 282
        self._fwdecl += gen_fwd_object_or_array(name)
        if variants:
            assert not members      # not implemented
            self.decl += gen_union(name, base, variants)
283 284 285
            # TODO Use gen_upcast on structs too, once they have sane layout
            if base:
                self.decl += gen_upcast(name, base)
286 287 288
        else:
            self.decl += gen_struct(name, base, members)
        self._gen_type_cleanup(name)
289 290 291 292 293 294 295 296 297 298 299 300

    def visit_alternate_type(self, name, info, variants):
        self._fwdecl += gen_fwd_object_or_array(name)
        self._fwdefn += gen_alternate_qtypes(name, variants)
        self.decl += gen_union(name, None, variants)
        self.decl += gen_alternate_qtypes_decl(name)
        self._gen_type_cleanup(name)

# If you link code generated from multiple schemata, you want only one
# instance of the code for built-in types.  Generate it only when
# do_builtins, enabled by command line option -b.  See also
# QAPISchemaGenTypeVisitor.visit_end().
301
do_builtins = False
302

303 304 305
(input_file, output_dir, do_c, do_h, prefix, opts) = \
    parse_command_line("b", ["builtins"])

306
for o, a in opts:
307
    if o in ("-b", "--builtins"):
308
        do_builtins = True
309

310
c_comment = '''
311 312 313 314 315 316 317 318 319 320 321 322 323
/*
 * deallocation functions for schema-defined QAPI types
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *  Michael Roth      <mdroth@linux.vnet.ibm.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */
324 325
'''
h_comment = '''
326 327 328 329 330 331 332 333 334 335 336 337
/*
 * schema-defined QAPI types
 *
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */
338
'''
339

340 341 342
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
                            'qapi-types.c', 'qapi-types.h',
                            c_comment, h_comment)
343

344 345 346 347 348 349 350 351
fdef.write(mcgen('''
#include "qapi/dealloc-visitor.h"
#include "%(prefix)sqapi-types.h"
#include "%(prefix)sqapi-visit.h"
''',
                 prefix=prefix))

fdecl.write(mcgen('''
352 353
#include <stdbool.h>
#include <stdint.h>
354
#include "qapi/qmp/qobject.h"
355
'''))
356

357 358 359 360 361
schema = QAPISchema(input_file)
gen = QAPISchemaGenTypeVisitor()
schema.visit(gen)
fdef.write(gen.defn)
fdecl.write(gen.decl)
362

363
close_output(fdef, fdecl)