qapi: Generate separate .h, .c for each module

Our qapi-schema.json is composed of modules connected by include
directives, but the generated code is monolithic all the same: one
qapi-types.h with all the types, one qapi-visit.h with all the
visitors, and so forth. These monolithic headers get included all
over the place. In my "build everything" tree, adding a QAPI type
recompiles about 4800 out of 5100 objects.

We wouldn't write such monolithic headers by hand. It stands to
reason that we shouldn't generate them, either.

Split up generated qapi-types.h to mirror the schema's modular
structure: one header per module. Name the main module's header
qapi-types.h, and sub-module D/B.json's header D/qapi-types-B.h.

Mirror the schema's includes in the headers, so that qapi-types.h gets
you everything exactly as before. If you need less, you can include
one or more of the sub-module headers. To be exploited shortly.

Split up qapi-types.c, qapi-visit.h, qapi-visit.c, qmp-commands.h,
qmp-commands.c, qapi-event.h, qapi-event.c the same way.
qmp-introspect.h, qmp-introspect.c and qapi.texi remain monolithic.

The split of qmp-commands.c duplicates static helper function
qmp_marshal_output_str() in qapi-commands-char.c and
qapi-commands-misc.c. This happens when commands returning the same
type occur in multiple modules. Not worth avoiding.

Since I'm going to rename qapi-event.[ch] to qapi-events.[ch], and
qmp-commands.[ch] to qapi-commands.[ch], name the shards that way
already, to reduce churn. This requires temporary hacks in
commands.py and events.py. Similarly, c_name() must temporarily
be taught to munge '/' in common.py. They'll go away with the rename.

Backports commit 252dc3105fc494182e236e97fe20f2d6b1d652cb from qemu
This commit is contained in:
Markus Armbruster 2018-03-09 09:38:13 -05:00 committed by Lioncash
parent c18d107804
commit fe90858609
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
11 changed files with 184 additions and 12 deletions

View file

@ -0,0 +1,28 @@
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
/*
* Schema-defined QAPI types
*
* Copyright IBM, Corp. 2011
* Copyright (c) 2013-2018 Red Hat Inc.
*
* 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.
*/
#include "qemu/osdep.h"
#include "qapi/dealloc-visitor.h"
#include "qapi-types.h"
#include "qapi-visit.h"
const char *const QapiErrorClass_lookup[] = {
"GenericError",
"CommandNotFound",
"DeviceEncrypted",
"DeviceNotActive",
"DeviceNotFound",
"KVMMissingCap",
NULL,
};
/* Dummy declaration to prevent empty .o file */
char dummy_qapi_qapi_types_common_c;

View file

@ -0,0 +1,30 @@
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
/*
* Schema-defined QAPI types
*
* Copyright IBM, Corp. 2011
* Copyright (c) 2013-2018 Red Hat Inc.
*
* 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.
*/
#ifndef QAPI_QAPI_TYPES_COMMON_H
#define QAPI_QAPI_TYPES_COMMON_H
#include "qapi-builtin-types.h"
typedef enum QapiErrorClass {
QAPI_ERROR_CLASS_GENERICERROR = 0,
QAPI_ERROR_CLASS_COMMANDNOTFOUND = 1,
QAPI_ERROR_CLASS_DEVICEENCRYPTED = 2,
QAPI_ERROR_CLASS_DEVICENOTACTIVE = 3,
QAPI_ERROR_CLASS_DEVICENOTFOUND = 4,
QAPI_ERROR_CLASS_KVMMISSINGCAP = 5,
QAPI_ERROR_CLASS__MAX = 6,
} QapiErrorClass;
extern const char *const QapiErrorClass_lookup[];
#endif /* QAPI_QAPI_TYPES_COMMON_H */

View file

@ -0,0 +1,26 @@
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
/*
* Schema-defined QAPI visitors
*
* Copyright IBM, Corp. 2011
* Copyright (C) 2014-2018 Red Hat, Inc.
*
* 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.
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "qapi-visit.h"
void visit_type_QapiErrorClass(Visitor *v, const char *name, QapiErrorClass *obj, Error **errp)
{
int value = *obj;
visit_type_enum(v, name, &value, QapiErrorClass_lookup, errp);
*obj = value;
}
/* Dummy declaration to prevent empty .o file */
char dummy_qapi_qapi_visit_common_c;

View file

@ -0,0 +1,21 @@
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
/*
* Schema-defined QAPI visitors
*
* Copyright IBM, Corp. 2011
* Copyright (C) 2014-2018 Red Hat, Inc.
*
* 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.
*/
#ifndef QAPI_QAPI_VISIT_COMMON_H
#define QAPI_QAPI_VISIT_COMMON_H
#include "qapi-builtin-visit.h"
#include "qapi-types.h"
void visit_type_QapiErrorClass(Visitor *v, const char *name, QapiErrorClass *obj, Error **errp);
#endif /* QAPI_QAPI_VISIT_COMMON_H */

View file

@ -238,6 +238,8 @@ copy $(SolutionDir)..\include\unicorn\*.h $(SolutionDir)distro\include\unicorn\
<ClCompile Include="..\..\..\uc.c" />
<ClCompile Include="..\qapi-builtin-types.c" />
<ClCompile Include="..\qapi-builtin-visit.c" />
<ClCompile Include="..\qapi-types-common.c" />
<ClCompile Include="..\qapi-visit-common.c" />
<ClCompile Include="..\qapi-types.c" />
<ClCompile Include="..\qapi-visit.c" />
<ClCompile Include="dllmain.cpp">
@ -366,6 +368,8 @@ copy $(SolutionDir)..\include\unicorn\*.h $(SolutionDir)distro\include\unicorn\
<ClInclude Include="..\config-host.h" />
<ClInclude Include="..\qapi-builtin-types.h" />
<ClInclude Include="..\qapi-builtin-visit.h" />
<ClInclude Include="..\qapi-types-common.h" />
<ClInclude Include="..\qapi-visit-common.h" />
<ClInclude Include="..\qapi-types.h" />
<ClInclude Include="..\qapi-visit.h" />
</ItemGroup>

View file

@ -138,6 +138,12 @@
<ClCompile Include="..\qapi-builtin-visit.c">
<Filter>qemu</Filter>
</ClCompile>
<ClCompile Include="..\qapi-types-common.c">
<Filter>qemu</Filter>
</ClCompile>
<ClCompile Include="..\qapi-visit-common.c">
<Filter>qemu</Filter>
</ClCompile>
<ClCompile Include="..\qapi-visit.c">
<Filter>qemu</Filter>
</ClCompile>
@ -238,6 +244,12 @@
<ClInclude Include="..\qapi-builtin-visit.h">
<Filter>qemu</Filter>
</ClInclude>
<ClInclude Include="..\qapi-types-common.h">
<Filter>qemu</Filter>
</ClInclude>
<ClInclude Include="..\qapi-visit-common.h">
<Filter>qemu</Filter>
</ClInclude>
<ClInclude Include="..\qapi-visit.h">
<Filter>qemu</Filter>
</ClInclude>

View file

@ -179,8 +179,10 @@
<ClInclude Include="..\..\..\qemu\include\sysemu\sysemu.h" />
<ClInclude Include="..\..\..\qemu\vl.h" />
<ClInclude Include="..\config-host.h" />
<ClCompile Include="..\qapi-builtin-types.h" />
<ClCompile Include="..\qapi-builtin-visit.h" />
<ClInclude Include="..\qapi-builtin-types.h" />
<ClInclude Include="..\qapi-builtin-visit.h" />
<ClInclude Include="..\qapi-types-common.h" />
<ClInclude Include="..\qapi-visit-common.h" />
<ClInclude Include="..\qapi-types.h" />
<ClInclude Include="..\qapi-visit.h" />
</ItemGroup>

View file

@ -211,6 +211,12 @@
<ClCompile Include="..\qapi-builtin-visit.c">
<Filter>qemu</Filter>
</ClCompile>
<ClCompile Include="..\qapi-types-common.c">
<Filter>qemu</Filter>
</ClCompile>
<ClCompile Include="..\qapi-visit-common.c">
<Filter>qemu</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\include\list.h">
@ -530,5 +536,11 @@
<ClInclude Include="..\qapi-builtin-visit.h">
<Filter>qemu</Filter>
</ClInclude>
<ClInclude Include="..\qapi-types-common.h">
<Filter>qemu</Filter>
</ClInclude>
<ClInclude Include="..\qapi-visit-common.h">
<Filter>qemu</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -49,8 +49,10 @@ include $(SRC_PATH)/rules.mak
GENERATED_FILES = config-host.h
GENERATED_FILES += qapi-builtin-types.h qapi-builtin-types.c
GENERATED_FILES += qapi-types.h qapi-types.c
GENERATED_FILES += qapi/qapi-types-common.h qapi/qapi-types-common.c
GENERATED_FILES += qapi-builtin-visit.h qapi-builtin-visit.c
GENERATED_FILES += qapi-visit.h qapi-visit.c
GENERATED_FILES += qapi/qapi-visit-common.h qapi/qapi-visit-common.c
# Don't try to regenerate Makefile or configure
# We don't generate any of them
@ -155,8 +157,10 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json
qapi-builtin-types.c qapi-builtin-types.h \
qapi-types.c qapi-types.h \
qapi/qapi-types-common.c qapi/qapi-types-common.h \
qapi-builtin-visit.c qapi-builtin-visit.h \
qapi-visit.c qapi-visit.h \
qapi/qapi-visit-common.c qapi/qapi-visit-common.h \
qapi-doc.texi: \
qapi-gen-timestamp ;
qapi-gen-timestamp: $(qapi-modules) $(qapi-py)

View file

@ -1784,10 +1784,11 @@ def c_enum_const(type_name, const_name, prefix=None):
type_name = prefix
return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
# Temporary HACK for '/':
if hasattr(str, 'maketrans'):
c_name_trans = str.maketrans('.-', '__')
c_name_trans = str.maketrans('.-/', '___')
else:
c_name_trans = string.maketrans('.-', '__')
c_name_trans = string.maketrans('.-/', '___')
# Map @name to a valid C identifier.
@ -2040,6 +2041,13 @@ class QAPIGenC(QAPIGen):
''',
blurb=self._blurb, copyright=self._copyright)
def _bottom(self, fname):
return mcgen('''
/* Dummy declaration to prevent empty .o file */
char dummy_%(name)s;
''',
name=c_name(fname))
class QAPIGenH(QAPIGenC):
def _top(self, fname):
@ -2076,13 +2084,20 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
self._blurb = blurb
self._pydoc = pydoc
self._module = {}
self._main_module = None
def _module_basename(self, what, name):
if name is None:
return re.sub(r'-', '-builtin-', what)
return self._prefix + what
basename = os.path.join(os.path.dirname(name),
self._prefix + what)
if name == self._main_module:
return basename
return basename + '-' + os.path.splitext(os.path.basename(name))[0]
def _add_module(self, name, blurb):
if self._main_module is None and name is not None:
self._main_module = name
genc = QAPIGenC(blurb, self._pydoc)
genh = QAPIGenH(blurb, self._pydoc)
self._module[name] = (genc, genh)
@ -2091,7 +2106,7 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
def _set_module(self, name):
self._genc, self._genh = self._module[name]
def write(self, output_dir, opt_builtins):
def write(self, output_dir, opt_builtins=False):
for name in self._module:
if name is None and not opt_builtins:
continue
@ -2104,7 +2119,15 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor):
pass
def visit_module(self, name):
if len(self._module) != 1:
if name in self._module:
self._set_module(name)
return
self._add_module(name, self._blurb)
self._begin_module(name)
def visit_include(self, name, info):
basename = self._module_basename(self._what, name)
self._genh.preamble_add(mcgen('''
#include "%(basename)s.h"
''',
basename=basename))

View file

@ -148,13 +148,23 @@ out:
return ret
class QAPISchemaGenEventVisitor(QAPISchemaMonolithicCVisitor):
class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
def __init__(self, prefix):
QAPISchemaMonolithicCVisitor.__init__(
self, prefix, 'qapi-event',
QAPISchemaModularCVisitor.__init__(
self, prefix, 'qapi-events',
' * Schema-defined QAPI/QMP events', __doc__)
self._enum_name = c_name(prefix + 'QAPIEvent', protect=False)
self._event_names = []
# Temporary HACK:
def _module_basename(self, what, name):
basename = QAPISchemaModularCVisitor._module_basename(self, what, name)
if name == self._main_module:
return re.sub(r'qapi-events', 'qapi-event', basename)
return basename
def _begin_module(self, name):
self._genc.add(mcgen('''
#include "qemu-common.h"
#include "%(prefix)sqapi-event.h"
@ -165,13 +175,13 @@ class QAPISchemaGenEventVisitor(QAPISchemaMonolithicCVisitor):
#include "qapi/qmp-event.h"
''',
prefix=prefix))
prefix=self._prefix))
self._genh.add(mcgen('''
#include "%(prefix)sqapi-types.h"
''',
prefix=prefix))
prefix=self._prefix))
def visit_end(self):
self._genh.add(gen_enum(self._enum_name, self._event_names))