diff options
author | Eric Blake <eblake@redhat.com> | 2016-03-17 16:48:30 -0600 |
---|---|---|
committer | Markus Armbruster <armbru@redhat.com> | 2016-03-18 10:29:25 +0100 |
commit | 7ce106a96feee4d46bfcdb47127b0935804c9357 (patch) | |
tree | f2ec21603adc4d3c7019bcf6f8b5c1bfca8c1d83 /scripts/qapi-visit.py | |
parent | 7599697c66d22ff4c859ba6ccea30e6a9aae6b9b (diff) |
qapi: Emit implicit structs in generated C
We already have several places that want to visit all the members
of an implicit object within a larger context (simple union variant,
event with anonymous data, command with anonymous arguments struct);
and will be adding another one soon (the ability to declare an
anonymous base for a flat union). Having a C struct declared for
these implicit types, along with a visit_type_FOO_members() helper
function, will make for fewer special cases in our generator.
We do not, however, need qapi_free_FOO() or visit_type_FOO()
functions for implicit types, because they should not be used
directly outside of the generated code. This is done by adding a
conditional in visit_object_type() for both qapi-types.py and
qapi-visit.py based on the object name. The comparison of
"name.startswith('q_')" is a bit hacky (it's basically duplicating
what .is_implicit() already uses), but beats changing the signature
of the visit_object_type() callback to pass a new 'implicit' flag.
The hack should be temporary: we are considering adding a future
patch that consolidates the narrow visit_object_type(..., base,
local_members, variants) and visit_object_type_flat(...,
all_members, variants) [where different sets of information are
already broken out, and the QAPISchemaObjectType is no longer
available] into a broader visit_object_type(obj_type) [where the
visitor can query the needed fields from obj_type directly].
Also, now that we WANT to output C code for implicits, we no longer
need the visit_needed() filter, leaving 'q_empty' as the only object
still needing a special case. Remember, 'q_empty' is the only
built-in generated object, which means that without a special case
it would be emitted in multiple files (the main qapi-types.h and in
qga-qapi-types.h) causing compilation failure due to redefinition.
But since it has no members, it's easier to just avoid an attempt to
visit that particular type; since gen_object() is called recursively,
we also prime the objects_seen set to cover any recursion into the
empty type.
The patch relies on the changed naming of implicit types in the
previous patch. It is a bit unfortunate that the generated struct
names and visit_type_FOO_members() don't match normal naming
conventions, but it's not too bad, since they will only be used in
generated code.
The generated code grows substantially in size: the implicit
'-wrapper' types must be emitted in qapi-types.h before any union
can include an unboxed member of that type. Arguably, the '-args'
types could be emitted in a private header for just qapi-visit.c
and qmp-marshal.c, rather than polluting qapi-types.h; but adding
complexity to the generator to split the output location according
to role doesn't seem worth the maintenance costs.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-6-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Diffstat (limited to 'scripts/qapi-visit.py')
-rw-r--r-- | scripts/qapi-visit.py | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index a712e9af8a..4923b2e9dd 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -215,13 +215,11 @@ out: def gen_visit_object(name, base, members, variants): - ret = gen_visit_object_members(name, base, members, variants) - # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to # *obj, but then visit_type_FOO_members() fails, we should clean up *obj # rather than leaving it non-NULL. As currently written, the caller must # call qapi_free_FOO() to avoid a memory leak of the partial FOO. - ret += mcgen(''' + return mcgen(''' void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { @@ -245,8 +243,6 @@ out: ''', c_name=c_name(name)) - return ret - class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): def __init__(self): @@ -268,11 +264,6 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.decl = self._btin + self.decl self._btin = None - def visit_needed(self, entity): - # Visit everything except implicit objects - return not (entity.is_implicit() and - isinstance(entity, QAPISchemaObjectType)) - def visit_enum_type(self, name, info, values, prefix): # Special case for our lone builtin enum type # TODO use something cleaner than existence of info @@ -296,9 +287,17 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.defn += defn def visit_object_type(self, name, info, base, members, variants): + # Nothing to do for the special empty builtin + if name == 'q_empty': + return self.decl += gen_visit_members_decl(name) - self.decl += gen_visit_decl(name) - self.defn += gen_visit_object(name, base, members, variants) + self.defn += gen_visit_object_members(name, base, members, variants) + # TODO Worth changing the visitor signature, so we could + # directly use rather than repeat type.is_implicit()? + if not name.startswith('q_'): + # only explicit types need an allocating visit + self.decl += gen_visit_decl(name) + self.defn += gen_visit_object(name, base, members, variants) def visit_alternate_type(self, name, info, variants): self.decl += gen_visit_decl(name) |