summaryrefslogtreecommitdiffstats
path: root/scripts/qapi/common.py
diff options
context:
space:
mode:
authorMarkus Armbruster2018-02-26 23:29:21 +0100
committerEric Blake2018-03-02 20:14:10 +0100
commitcdb6610ae4283720037bae2af1f78bd40eb5fe71 (patch)
treea32a7d2a3575d8438f3e88eccd6832ff55fdad0a /scripts/qapi/common.py
parentqapi: Make code-generating visitors use QAPIGen more (diff)
downloadqemu-cdb6610ae4283720037bae2af1f78bd40eb5fe71.tar.gz
qemu-cdb6610ae4283720037bae2af1f78bd40eb5fe71.tar.xz
qemu-cdb6610ae4283720037bae2af1f78bd40eb5fe71.zip
qapi/types qapi/visit: Generate built-in stuff into separate files
Linking code from multiple separate QAPI schemata into the same program is possible, but involves some weirdness around built-in types: * We generate code for built-in types into .c only with option --builtins. The user is responsible for generating code for exactly one QAPI schema per program with --builtins. * We generate code for built-in types into .h regardless of --builtins, but guarded by #ifndef QAPI_VISIT_BUILTIN. Because all copies of this code are exactly the same, including any combination of these headers works. Replace this contraption by something more conventional: generate code for built-in types into their very own files: qapi-builtin-types.c, qapi-builtin-visit.c, qapi-builtin-types.h, qapi-builtin-visit.h, but only with --builtins. Obey --output-dir, but ignore --prefix for them. Make qapi-types.h include qapi-builtin-types.h. With multiple schemata you now have multiple qapi-types.[ch], but only one qapi-builtin-types.[ch]. Same for qapi-visit.[ch] and qapi-builtin-visit.[ch]. Bonus: if all you need is built-in stuff, you can include a much smaller header. To be exploited shortly. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20180211093607.27351-21-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com> [eblake: fix octal constant for python 3] Signed-off-by: Eric Blake <eblake@redhat.com>
Diffstat (limited to 'scripts/qapi/common.py')
-rw-r--r--scripts/qapi/common.py60
1 files changed, 51 insertions, 9 deletions
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 23437b558f..547656c8b2 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -1531,11 +1531,10 @@ class QAPISchema(object):
def _def_builtin_type(self, name, json_type, c_type):
self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
- # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
- # qapi-types.h from a single .c, all arrays of builtins must be
- # declared in the first file whether or not they are used. Nicer
- # would be to use lazy instantiation, while figuring out how to
- # avoid compilation issues with multiple qapi-types.h.
+ # Instantiating only the arrays that are actually used would
+ # be nice, but we can't as long as their generated code
+ # (qapi-builtin-types.[ch]) may be shared by some other
+ # schema.
self._make_array_type(name, None)
def _def_predefineds(self):
@@ -1992,14 +1991,15 @@ class QAPIGen(object):
return ''
def write(self, output_dir, fname):
- if output_dir:
+ pathname = os.path.join(output_dir, fname)
+ dir = os.path.dirname(pathname)
+ if dir:
try:
- os.makedirs(output_dir)
+ os.makedirs(dir)
except os.error as e:
if e.errno != errno.EEXIST:
raise
- fd = os.open(os.path.join(output_dir, fname),
- os.O_RDWR | os.O_CREAT, 0o666)
+ fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666)
f = os.fdopen(fd, 'r+')
text = (self._top(fname) + self._preamble + self._body
+ self._bottom(fname))
@@ -2063,3 +2063,45 @@ class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor):
def write(self, output_dir):
self._genc.write(output_dir, self._prefix + self._what + '.c')
self._genh.write(output_dir, self._prefix + self._what + '.h')
+
+
+class QAPISchemaModularCVisitor(QAPISchemaVisitor):
+
+ def __init__(self, prefix, what, blurb, pydoc):
+ self._prefix = prefix
+ self._what = what
+ self._blurb = blurb
+ self._pydoc = pydoc
+ self._module = {}
+
+ def _module_basename(self, what, name):
+ if name is None:
+ return re.sub(r'-', '-builtin-', what)
+ return self._prefix + what
+
+ def _add_module(self, name, blurb):
+ genc = QAPIGenC(blurb, self._pydoc)
+ genh = QAPIGenH(blurb, self._pydoc)
+ self._module[name] = (genc, genh)
+ self._set_module(name)
+
+ def _set_module(self, name):
+ self._genc, self._genh = self._module[name]
+
+ def write(self, output_dir, opt_builtins):
+ for name in self._module:
+ if name is None and not opt_builtins:
+ continue
+ basename = self._module_basename(self._what, name)
+ (genc, genh) = self._module[name]
+ genc.write(output_dir, basename + '.c')
+ genh.write(output_dir, basename + '.h')
+
+ def _begin_module(self, name):
+ pass
+
+ def visit_module(self, name):
+ if len(self._module) != 1:
+ return
+ self._add_module(name, self._blurb)
+ self._begin_module(name)