qapi: New classes QAPIGenC, QAPIGenH, QAPIGenDoc

These classes encapsulate accumulating and writing output.

Convert C code generation to QAPIGenC and QAPIGenH.  The conversion is
rather shallow: most of the output accumulation is not converted.
Left for later.

The indentation machinery uses a single global variable indent_level,
even though we generally interleave creation of a .c and its .h.  It
should become instance variable of QAPIGenC.  Also left for later.

Documentation generation isn't converted, and QAPIGenDoc isn't used.
This will change shortly.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20180211093607.27351-6-armbru@redhat.com>
Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com>
[eblake: fix nits spotted by Michael]
Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Markus Armbruster 2018-02-26 13:19:40 -06:00 committed by Eric Blake
parent d46eec4260
commit 47a6ea9aab
6 changed files with 117 additions and 98 deletions

View File

@ -258,12 +258,10 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
blurb = ' * Schema-defined QAPI/QMP commands'
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
'qmp-marshal.c', 'qmp-commands.h',
blurb, __doc__)
fdef.write(mcgen('''
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/module.h"
@ -278,20 +276,23 @@ fdef.write(mcgen('''
#include "%(prefix)sqmp-commands.h"
''',
prefix=prefix))
prefix=prefix))
fdecl.write(mcgen('''
genh.add(mcgen('''
#include "%(prefix)sqapi-types.h"
#include "qapi/qmp/dispatch.h"
void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
''',
prefix=prefix, c_prefix=c_name(prefix, protect=False)))
prefix=prefix, c_prefix=c_name(prefix, protect=False)))
schema = QAPISchema(input_file)
vis = QAPISchemaGenCommandVisitor()
schema.visit(vis)
fdef.write(vis.defn)
fdecl.write(vis.decl)
genc.add(vis.defn)
genh.add(vis.decl)
close_output(fdef, fdecl)
if do_c:
genc.write(output_dir, prefix + 'qmp-marshal.c')
if do_h:
genh.write(output_dir, prefix + 'qmp-commands.h')

View File

@ -174,11 +174,10 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
blurb = ' * Schema-defined QAPI/QMP events'
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
'qapi-event.c', 'qapi-event.h',
blurb, __doc__)
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
fdef.write(mcgen('''
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "%(prefix)sqapi-event.h"
@ -189,21 +188,24 @@ fdef.write(mcgen('''
#include "qapi/qmp-event.h"
''',
prefix=prefix))
prefix=prefix))
fdecl.write(mcgen('''
genh.add(mcgen('''
#include "qapi/util.h"
#include "%(prefix)sqapi-types.h"
''',
prefix=prefix))
prefix=prefix))
event_enum_name = c_name(prefix + 'QAPIEvent', protect=False)
schema = QAPISchema(input_file)
vis = QAPISchemaGenEventVisitor()
schema.visit(vis)
fdef.write(vis.defn)
fdecl.write(vis.decl)
genc.add(vis.defn)
genh.add(vis.decl)
close_output(fdef, fdecl)
if do_c:
genc.write(output_dir, prefix + 'qapi-event.c')
if do_h:
genh.write(output_dir, prefix + 'qapi-event.h')

View File

@ -179,21 +179,23 @@ for o, a in opts:
blurb = ' * QAPI/QMP schema introspection'
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
'qmp-introspect.c', 'qmp-introspect.h',
blurb, __doc__)
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
fdef.write(mcgen('''
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "%(prefix)sqmp-introspect.h"
''',
prefix=prefix))
prefix=prefix))
schema = QAPISchema(input_file)
vis = QAPISchemaGenIntrospectVisitor(opt_unmask)
schema.visit(vis)
fdef.write(vis.defn)
fdecl.write(vis.decl)
genc.add(vis.defn)
genh.add(vis.decl)
close_output(fdef, fdecl)
if do_c:
genc.write(output_dir, prefix + 'qmp-introspect.c')
if do_h:
genh.write(output_dir, prefix + 'qmp-introspect.h')

View File

@ -180,7 +180,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
self.decl = ''
self.defn = ''
self._fwdecl = ''
self._btin = guardstart('QAPI_TYPES_BUILTIN')
self._btin = '\n' + guardstart('QAPI_TYPES_BUILTIN')
def visit_end(self):
self.decl = self._fwdecl + self.decl
@ -254,26 +254,28 @@ for o, a in opts:
blurb = ' * Schema-defined QAPI types'
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
'qapi-types.c', 'qapi-types.h',
blurb, __doc__)
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
fdef.write(mcgen('''
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qapi/dealloc-visitor.h"
#include "%(prefix)sqapi-types.h"
#include "%(prefix)sqapi-visit.h"
''',
prefix=prefix))
prefix=prefix))
fdecl.write(mcgen('''
genh.add(mcgen('''
#include "qapi/util.h"
'''))
schema = QAPISchema(input_file)
vis = QAPISchemaGenTypeVisitor()
schema.visit(vis)
fdef.write(vis.defn)
fdecl.write(vis.decl)
genc.add(vis.defn)
genh.add(vis.decl)
close_output(fdef, fdecl)
if do_c:
genc.write(output_dir, prefix + 'qapi-types.c')
if do_h:
genh.write(output_dir, prefix + 'qapi-types.h')

View File

@ -272,7 +272,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
def visit_begin(self, schema):
self.decl = ''
self.defn = ''
self._btin = guardstart('QAPI_VISIT_BUILTIN')
self._btin = '\n' + guardstart('QAPI_VISIT_BUILTIN')
def visit_end(self):
# To avoid header dependency hell, we always generate
@ -337,30 +337,32 @@ for o, a in opts:
blurb = ' * Schema-defined QAPI visitors'
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
'qapi-visit.c', 'qapi-visit.h',
blurb, __doc__)
genc = QAPIGenC(blurb, __doc__)
genh = QAPIGenH(blurb, __doc__)
fdef.write(mcgen('''
genc.add(mcgen('''
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "%(prefix)sqapi-visit.h"
''',
prefix=prefix))
prefix=prefix))
fdecl.write(mcgen('''
genh.add(mcgen('''
#include "qapi/visitor.h"
#include "%(prefix)sqapi-types.h"
''',
prefix=prefix))
prefix=prefix))
schema = QAPISchema(input_file)
vis = QAPISchemaGenVisitVisitor()
schema.visit(vis)
fdef.write(vis.defn)
fdecl.write(vis.decl)
genc.add(vis.defn)
genh.add(vis.decl)
close_output(fdef, fdecl)
if do_c:
genc.write(output_dir, prefix + 'qapi-visit.c')
if do_h:
genh.write(output_dir, prefix + 'qapi-visit.h')

View File

@ -2,7 +2,7 @@
# QAPI helper library
#
# Copyright IBM, Corp. 2011
# Copyright (c) 2013-2016 Red Hat Inc.
# Copyright (c) 2013-2018 Red Hat Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
@ -22,10 +22,6 @@ try:
from collections import OrderedDict
except:
from ordereddict import OrderedDict
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
builtin_types = {
'null': 'QTYPE_QNULL',
@ -1831,7 +1827,6 @@ def guardname(filename):
def guardstart(name):
return mcgen('''
#ifndef %(name)s
#define %(name)s
@ -1843,7 +1838,6 @@ def guardend(name):
return mcgen('''
#endif /* %(name)s */
''',
name=guardname(name))
@ -1980,17 +1974,53 @@ def parse_command_line(extra_options='', extra_long_options=[]):
return (fname, output_dir, do_c, do_h, prefix, extra_opts)
#
# Generate output files with boilerplate
# Accumulate and write output
#
class QAPIGen(object):
def open_output(output_dir, do_c, do_h, prefix, c_file, h_file, blurb, doc):
guard = guardname(prefix + h_file)
c_file = output_dir + prefix + c_file
h_file = output_dir + prefix + h_file
copyright = '\n * '.join(re.findall(r'^Copyright .*', doc, re.MULTILINE))
comment = mcgen('''/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
def __init__(self):
self._preamble = ''
self._body = ''
def preamble_add(self, text):
self._preamble += text
def add(self, text):
self._body += text
def _top(self, fname):
return ''
def _bottom(self, fname):
return ''
def write(self, output_dir, fname):
if output_dir:
try:
os.makedirs(output_dir)
except os.error as e:
if e.errno != errno.EEXIST:
raise
f = open(os.path.join(output_dir, fname), 'w')
f.write(self._top(fname) + self._preamble + self._body
+ self._bottom(fname))
f.close()
class QAPIGenC(QAPIGen):
def __init__(self, blurb, pydoc):
QAPIGen.__init__(self)
self._blurb = blurb
self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc,
re.MULTILINE))
def _top(self, fname):
return mcgen('''
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
/*
%(blurb)s
@ -2002,40 +2032,20 @@ def open_output(output_dir, do_c, do_h, prefix, c_file, h_file, blurb, doc):
*/
''',
blurb=blurb, copyright=copyright)
if output_dir:
try:
os.makedirs(output_dir)
except os.error as e:
if e.errno != errno.EEXIST:
raise
def maybe_open(really, name, opt):
if really:
return open(name, opt)
else:
return StringIO()
fdef = maybe_open(do_c, c_file, 'w')
fdecl = maybe_open(do_h, h_file, 'w')
fdef.write(comment)
fdecl.write(comment)
fdecl.write(mcgen('''
#ifndef %(guard)s
#define %(guard)s
''',
guard=guard))
return (fdef, fdecl)
blurb=self._blurb, copyright=self._copyright)
def close_output(fdef, fdecl):
fdecl.write(mcgen('''
class QAPIGenH(QAPIGenC):
#endif
'''))
fdecl.close()
fdef.close()
def _top(self, fname):
return QAPIGenC._top(self, fname) + guardstart(fname)
def _bottom(self, fname):
return guardend(fname)
class QAPIGenDoc(QAPIGen):
def _top(self, fname):
return (QAPIGen._top(self, fname)
+ '@c AUTOMATICALLY GENERATED, DO NOT MODIFY\n\n')