All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/50] Hi,
@ 2017-09-11 11:05 Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit() Marc-André Lureau
                   ` (51 more replies)
  0 siblings, 52 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau

In order to clean-up some hacks in qapi (having to unregister commands
at runtime), I proposed a "[PATCH v5 02/20] qapi.py: add a simple #ifdef condition"

(see http://lists.gnu.org/archive/html/qemu-devel/2016-08/msg03106.html).

However, we decided to drop that patch from the series and solve the
problem later. The main issues were:
- the syntax was awkward to the JSON schema and documentation
- the evaluation of the condition was done in the qapi scripts, with
  very limited capability
- each target/config would need different generated files.

Instead, it could defer the #if evaluation to the C-preprocessor.

With this series, top-level qapi JSON entity can take 'if' keys:

{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
  'if': 'defined(TEST_IF_STRUCT)' }

Members can be exploded as dictionnary with 'type'/'if' keys:

{ 'struct': 'TestIfStruct', 'data':
  { 'foo': 'int',
    'bar': { 'type': 'int', 'if': 'defined(TEST_IF_STRUCT_BAR)'} } }

Enum values can be exploded as dictionnary with 'type'/'if' keys:

{ 'enum': 'TestIfEnum', 'data':
  [ 'foo',
    { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ] }

A good benefit from having conditional schema is that introspection
will reflect more accurately the capability of the server. Another
benefit is that it may help to remove some dead code when disabling a
functionality.

Starting from patch "qapi: add conditions to VNC type/commands/events
on the schema", the series demonstrate adding conditions, in order to
remove qmp_unregister_commands_hack(). The main difference with v2, is
the addition of a per-target schema in "build-sys: add a target
schema". This removes the NEED_CPU_H hack, and keep most of the qapi
files in common build.

There are a lot more things we could make conditional in the QAPI
schema, like pci/kvm/xen/numa/vde/slirp/posix/win32/vsock/lzo etc etc,
however I am still evaluating the implication of such changes both
externally and internally, for those interested, I can share my wip
branch.

Comments welcome,

v3:
- rebased (qlit is now merged upstream)
- solve the per-target #ifdef problem by using a target.json
  and new qapi generated target files
- update some commit messages based on Markus review
- more schema error reporting
- move the ifcond argument closer to info/doc
- use mcgen() in gen_if()/gen_endif()
- simplify "modify to_qlit() to take an optional suffix"
- fix generated qlit indentation
- fix temporary build break by merging #if types & visitors patch
- fix some redundant condtionals generation
- change enum visitor to take QAPISchemaMember
- reject unknown dictionnary keys in { .., 'if': ..}
- split qapi test visitor print() with trailing ',' trick

Marc-André Lureau (50):
  qlit: add qobject_from_qlit()
  qapi: generate a literal qobject for introspection
  qapi2texi: minor python code simplification
  qapi: add 'if' to top-level expressions
  qapi: add tests for invalid 'if'
  qapi: pass 'if' condition into QAPISchemaEntity objects
  qapi: add 'ifcond' to visitor methods
  qapi: mcgen() shouldn't indent # lines
  qapi: add #if/#endif helpers
  qapi-introspect: modify to_qlit() to append ',' on level > 0
  qapi-introspect: modify to_qlit() to generate #if code
  qapi-introspect: add preprocessor conditions to generated QLit
  qapi-commands: add #if conditions to commands
  qapi-event: add #if conditions to events
  qapi-types: refactor variants handling
  qapi-types: add #if conditions to types & visitors
  qapi: do not define enumeration value explicitely
  qapi: change enum visitor to take QAPISchemaMember
  qapi: add 'if' to enum members
  qapi-event: add 'if' condition to generated enum
  qapi: add #if conditions on generated enum members
  tests: add some enum members tests
  qapi: add 'if' to struct members and implicit objects members
  qapi: add some struct member tests
  qapi: add #if conditions to generated struct members
  qapi: add 'if' on union variants
  qapi: add #if conditions to generated variants
  qapi: add 'if' to alternate variant
  qapi: add tests for invalid alternate
  qapi: add #if conditions to generated alternate variants
  docs: document schema configuration
  qapi2texi: add 'If:' section to generated documentation
  qapi2texi: add 'If:' condition to enum values
  qapi2texi: add 'If:' condition to struct members
  qapi2texi: add condition to variants
  qapi: add conditions to VNC type/commands/events on the schema
  qapi: add conditions to SPICE type/commands/events on the schema
  qapi: add conditions to REPLICATION type/commands on the schema
  qapi-commands: don't initialize command list in qmp_init_marshall()
  qapi: add -i/--include filename.h
  qapi: add a 'unit' pragma
  qapi: add a -u/--unit option to specify which unit to visit
  build-sys: move qmp-introspect per target
  build-sys: add a target schema
  qapi: make rtc-reset-reinjection depend on TARGET_I386
  qapi: make s390 commands depend on TARGET_S390X
  target.json: add a note about query-cpu* not being s390x-specific
  qapi: make query-gic-capabilities depend on TARGET_ARM
  qapi: make query-cpu-model-expansion depend on s390 or x86
  qapi: make query-cpu-definitions depend on specific targets

 qapi-schema.json                                   | 212 +-----------
 qapi/block-core.json                               |  15 +-
 qapi/char.json                                     |  10 +-
 qapi/crypto.json                                   |   3 +-
 qapi/migration.json                                |  12 +-
 qapi/target.json                                   | 228 +++++++++++++
 qapi/ui.json                                       |  75 +++--
 scripts/qapi.py                                    | 372 +++++++++++++++------
 scripts/qapi-commands.py                           |  13 +-
 scripts/qapi-event.py                              |  12 +-
 scripts/qapi-introspect.py                         | 121 ++++---
 scripts/qapi-types.py                              |  71 ++--
 scripts/qapi-visit.py                              |  24 +-
 scripts/qapi2texi.py                               |  52 +--
 include/qapi/qmp/qlit.h                            |   2 +
 include/sysemu/arch_init.h                         |  11 -
 ui/vnc.h                                           |   2 +
 crypto/cipher-builtin.c                            |   9 +
 crypto/cipher-gcrypt.c                             |  10 +-
 crypto/cipher-nettle.c                             |  14 +-
 crypto/cipher.c                                    |  13 +-
 hmp.c                                              |   9 +-
 hw/s390x/s390-skeys.c                              |   2 +-
 hw/timer/mc146818rtc.c                             |   2 +-
 migration/colo.c                                   |  16 +-
 monitor.c                                          |  73 +---
 qga/main.c                                         |   1 +
 qmp.c                                              |  72 +---
 qobject/qlit.c                                     |  36 ++
 stubs/arch-query-cpu-def.c                         |  10 -
 stubs/arch-query-cpu-model-baseline.c              |  12 -
 stubs/arch-query-cpu-model-comparison.c            |  12 -
 stubs/arch-query-cpu-model-expansion.c             |  12 -
 target/arm/helper.c                                |   3 +-
 target/arm/monitor.c                               |   2 +-
 target/i386/cpu.c                                  |   5 +-
 target/ppc/translate_init.c                        |   3 +-
 target/s390x/cpu_models.c                          |   9 +-
 tests/check-qlit.c                                 |  26 ++
 tests/test-crypto-cipher.c                         |   2 +
 tests/test-qmp-commands.c                          |   7 +
 tests/test-qobject-input-visitor.c                 |  10 +-
 Makefile                                           |  29 +-
 Makefile.objs                                      |   3 +-
 Makefile.target                                    |   4 +
 docs/devel/qapi-code-gen.txt                       |  69 +++-
 hmp-commands-info.hx                               |   2 +
 stubs/Makefile.objs                                |   4 -
 tests/Makefile.include                             |  10 +-
 tests/qapi-schema/alternate-dict-invalid.err       |   1 +
 ...ict-member.exit => alternate-dict-invalid.exit} |   0
 tests/qapi-schema/alternate-dict-invalid.json      |   4 +
 ...-dict-member.out => alternate-dict-invalid.out} |   0
 tests/qapi-schema/bad-if-empty-list.err            |   1 +
 tests/qapi-schema/bad-if-empty-list.exit           |   1 +
 tests/qapi-schema/bad-if-empty-list.json           |   3 +
 tests/qapi-schema/bad-if-empty-list.out            |   0
 tests/qapi-schema/bad-if-empty.err                 |   1 +
 tests/qapi-schema/bad-if-empty.exit                |   1 +
 tests/qapi-schema/bad-if-empty.json                |   3 +
 tests/qapi-schema/bad-if-empty.out                 |   0
 tests/qapi-schema/bad-if.err                       |   1 +
 tests/qapi-schema/bad-if.exit                      |   1 +
 tests/qapi-schema/bad-if.json                      |   3 +
 tests/qapi-schema/bad-if.out                       |   0
 tests/qapi-schema/comments.out                     |  14 +-
 tests/qapi-schema/doc-good.out                     |  17 +-
 tests/qapi-schema/empty.out                        |   9 +-
 tests/qapi-schema/enum-dict-member-invalid.err     |   1 +
 tests/qapi-schema/enum-dict-member-invalid.exit    |   1 +
 tests/qapi-schema/enum-dict-member-invalid.json    |   2 +
 tests/qapi-schema/enum-dict-member-invalid.out     |   0
 tests/qapi-schema/enum-dict-member-invalid2.err    |   1 +
 tests/qapi-schema/enum-dict-member-invalid2.exit   |   1 +
 tests/qapi-schema/enum-dict-member-invalid2.json   |   2 +
 tests/qapi-schema/enum-dict-member-invalid2.out    |   0
 tests/qapi-schema/enum-dict-member.err             |   1 -
 tests/qapi-schema/enum-dict-member.json            |   2 -
 tests/qapi-schema/enum-if-invalid.err              |   1 +
 tests/qapi-schema/enum-if-invalid.exit             |   1 +
 tests/qapi-schema/enum-if-invalid.json             |   3 +
 tests/qapi-schema/enum-if-invalid.out              |   0
 tests/qapi-schema/event-case.out                   |   9 +-
 tests/qapi-schema/ident-with-escape.out            |   9 +-
 tests/qapi-schema/include-relpath.out              |  14 +-
 tests/qapi-schema/include-repetition.out           |  14 +-
 tests/qapi-schema/include-simple.out               |  14 +-
 tests/qapi-schema/indented-expr.out                |   9 +-
 tests/qapi-schema/qapi-schema-test.json            |  36 ++
 tests/qapi-schema/qapi-schema-test.out             |  93 +++++-
 tests/qapi-schema/struct-if-invalid.err            |   1 +
 tests/qapi-schema/struct-if-invalid.exit           |   1 +
 tests/qapi-schema/struct-if-invalid.json           |   3 +
 tests/qapi-schema/struct-if-invalid.out            |   0
 tests/qapi-schema/struct-member-type.err           |   0
 tests/qapi-schema/struct-member-type.exit          |   1 +
 tests/qapi-schema/struct-member-type.json          |   2 +
 tests/qapi-schema/struct-member-type.out           |  12 +
 tests/qapi-schema/test-qapi.py                     |  43 ++-
 99 files changed, 1328 insertions(+), 735 deletions(-)
 create mode 100644 qapi/target.json
 delete mode 100644 stubs/arch-query-cpu-def.c
 delete mode 100644 stubs/arch-query-cpu-model-baseline.c
 delete mode 100644 stubs/arch-query-cpu-model-comparison.c
 delete mode 100644 stubs/arch-query-cpu-model-expansion.c
 create mode 100644 tests/qapi-schema/alternate-dict-invalid.err
 rename tests/qapi-schema/{enum-dict-member.exit => alternate-dict-invalid.exit} (100%)
 create mode 100644 tests/qapi-schema/alternate-dict-invalid.json
 rename tests/qapi-schema/{enum-dict-member.out => alternate-dict-invalid.out} (100%)
 create mode 100644 tests/qapi-schema/bad-if-empty-list.err
 create mode 100644 tests/qapi-schema/bad-if-empty-list.exit
 create mode 100644 tests/qapi-schema/bad-if-empty-list.json
 create mode 100644 tests/qapi-schema/bad-if-empty-list.out
 create mode 100644 tests/qapi-schema/bad-if-empty.err
 create mode 100644 tests/qapi-schema/bad-if-empty.exit
 create mode 100644 tests/qapi-schema/bad-if-empty.json
 create mode 100644 tests/qapi-schema/bad-if-empty.out
 create mode 100644 tests/qapi-schema/bad-if.err
 create mode 100644 tests/qapi-schema/bad-if.exit
 create mode 100644 tests/qapi-schema/bad-if.json
 create mode 100644 tests/qapi-schema/bad-if.out
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.err
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.exit
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.json
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.out
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.err
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.exit
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.json
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.out
 delete mode 100644 tests/qapi-schema/enum-dict-member.err
 delete mode 100644 tests/qapi-schema/enum-dict-member.json
 create mode 100644 tests/qapi-schema/enum-if-invalid.err
 create mode 100644 tests/qapi-schema/enum-if-invalid.exit
 create mode 100644 tests/qapi-schema/enum-if-invalid.json
 create mode 100644 tests/qapi-schema/enum-if-invalid.out
 create mode 100644 tests/qapi-schema/struct-if-invalid.err
 create mode 100644 tests/qapi-schema/struct-if-invalid.exit
 create mode 100644 tests/qapi-schema/struct-if-invalid.json
 create mode 100644 tests/qapi-schema/struct-if-invalid.out
 create mode 100644 tests/qapi-schema/struct-member-type.err
 create mode 100644 tests/qapi-schema/struct-member-type.exit
 create mode 100644 tests/qapi-schema/struct-member-type.json
 create mode 100644 tests/qapi-schema/struct-member-type.out

-- 
2.14.1.146.gd35faa819

^ permalink raw reply	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit()
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-09-13 13:51   ` Eric Blake
  2017-12-06 14:37   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 02/50] qapi: generate a literal qobject for introspection Marc-André Lureau
                   ` (50 subsequent siblings)
  51 siblings, 2 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau

Instanciate a QObject* form a literal QLitObject.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/qlit.h |  2 ++
 qobject/qlit.c          | 36 ++++++++++++++++++++++++++++++++++++
 tests/check-qlit.c      | 26 ++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)

diff --git a/include/qapi/qmp/qlit.h b/include/qapi/qmp/qlit.h
index b18406bce9..56feb25e04 100644
--- a/include/qapi/qmp/qlit.h
+++ b/include/qapi/qmp/qlit.h
@@ -51,4 +51,6 @@ struct QLitDictEntry {
 
 bool qlit_equal_qobject(const QLitObject *lhs, const QObject *rhs);
 
+QObject *qobject_from_qlit(const QLitObject *qlit);
+
 #endif /* QLIT_H */
diff --git a/qobject/qlit.c b/qobject/qlit.c
index 3c4882c784..df2ad97d33 100644
--- a/qobject/qlit.c
+++ b/qobject/qlit.c
@@ -82,3 +82,39 @@ bool qlit_equal_qobject(const QLitObject *lhs, const QObject *rhs)
 
     return false;
 }
+
+QObject *qobject_from_qlit(const QLitObject *qlit)
+{
+    switch (qlit->type) {
+    case QTYPE_QNULL:
+        return QOBJECT(qnull());
+    case QTYPE_QNUM:
+        return QOBJECT(qnum_from_int(qlit->value.qnum));
+    case QTYPE_QSTRING:
+        return QOBJECT(qstring_from_str(qlit->value.qstr));
+    case QTYPE_QDICT: {
+        QDict *qdict = qdict_new();
+        QLitDictEntry *e;
+
+        for (e = qlit->value.qdict; e->key; e++) {
+            qdict_put_obj(qdict, e->key, qobject_from_qlit(&e->value));
+        }
+        return QOBJECT(qdict);
+    }
+    case QTYPE_QLIST: {
+        QList *qlist = qlist_new();
+        QLitObject *e;
+
+        for (e = qlit->value.qlist; e->type != QTYPE_NONE; e++) {
+            qlist_append_obj(qlist, qobject_from_qlit(e));
+        }
+        return QOBJECT(qlist);
+    }
+    case QTYPE_QBOOL:
+        return QOBJECT(qbool_from_bool(qlit->value.qbool));
+    case QTYPE_NONE:
+        assert(0);
+    }
+
+    return NULL;
+}
diff --git a/tests/check-qlit.c b/tests/check-qlit.c
index c59ec1ab88..acd6e02e96 100644
--- a/tests/check-qlit.c
+++ b/tests/check-qlit.c
@@ -64,11 +64,37 @@ static void qlit_equal_qobject_test(void)
     qobject_decref(qobj);
 }
 
+static void qobject_from_qlit_test(void)
+{
+    QObject *obj, *qobj = qobject_from_qlit(&qlit);
+    QDict *qdict;
+    QList *bee;
+
+    qdict = qobject_to_qdict(qobj);
+    g_assert_cmpint(qdict_get_int(qdict, "foo"), ==, 42);
+    g_assert_cmpstr(qdict_get_str(qdict, "bar"), ==, "hello world");
+    g_assert(qobject_type(qdict_get(qdict, "baz")) == QTYPE_QNULL);
+
+    bee = qdict_get_qlist(qdict, "bee");
+    obj = qlist_pop(bee);
+    g_assert_cmpint(qnum_get_int(qobject_to_qnum(obj)), ==, 43);
+    qobject_decref(obj);
+    obj = qlist_pop(bee);
+    g_assert_cmpint(qnum_get_int(qobject_to_qnum(obj)), ==, 44);
+    qobject_decref(obj);
+    obj = qlist_pop(bee);
+    g_assert(qbool_get_bool(qobject_to_qbool(obj)));
+    qobject_decref(obj);
+
+    qobject_decref(qobj);
+}
+
 int main(int argc, char **argv)
 {
     g_test_init(&argc, &argv, NULL);
 
     g_test_add_func("/qlit/equal_qobject", qlit_equal_qobject_test);
+    g_test_add_func("/qlit/qobject_from_qlit", qobject_from_qlit_test);
 
     return g_test_run();
 }
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 02/50] qapi: generate a literal qobject for introspection
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit() Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-06 15:17   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 03/50] qapi2texi: minor python code simplification Marc-André Lureau
                   ` (49 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Dr. David Alan Gilbert, Michael Roth

Replace the generated json string with a literal qobject. The later is
easier to deal with, at run time as well as compile time: adding #if
conditionals will be easier than in a json string.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-introspect.py         | 83 ++++++++++++++++++++++----------------
 monitor.c                          |  2 +-
 tests/test-qobject-input-visitor.c | 11 +++--
 docs/devel/qapi-code-gen.txt       | 29 ++++++++-----
 4 files changed, 76 insertions(+), 49 deletions(-)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 032bcea491..0002bc1a68 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -12,26 +12,36 @@
 from qapi import *
 
 
-# Caveman's json.dumps() replacement (we're stuck at Python 2.4)
-# TODO try to use json.dumps() once we get unstuck
-def to_json(obj, level=0):
+def to_qlit(obj, level=0, suppress_first_indent=False):
+
+    def indent(level):
+        return level * 4 * ' '
+
+    ret = ''
+    if not suppress_first_indent:
+        ret += indent(level)
     if obj is None:
-        ret = 'null'
+        ret += 'QLIT_QNULL'
     elif isinstance(obj, str):
-        ret = '"' + obj.replace('"', r'\"') + '"'
+        ret += 'QLIT_QSTR(' + to_c_string(obj) + ')'
     elif isinstance(obj, list):
-        elts = [to_json(elt, level + 1)
+        elts = [to_qlit(elt, level + 1)
                 for elt in obj]
-        ret = '[' + ', '.join(elts) + ']'
+        elts.append(indent(level + 1) + "{}")
+        ret += 'QLIT_QLIST(((QLitObject[]) {\n'
+        ret += ',\n'.join(elts) + '\n'
+        ret += indent(level) + '}))'
     elif isinstance(obj, dict):
-        elts = ['"%s": %s' % (key.replace('"', r'\"'),
-                              to_json(obj[key], level + 1))
-                for key in sorted(obj.keys())]
-        ret = '{' + ', '.join(elts) + '}'
+        elts = []
+        for key, value in sorted(obj.iteritems()):
+            elts.append(indent(level + 1) + '{ %s, %s }' %
+                        (to_c_string(key), to_qlit(value, level + 1, True)))
+        elts.append(indent(level + 1) + '{}')
+        ret += 'QLIT_QDICT(((QLitDictEntry[]) {\n'
+        ret += ',\n'.join(elts) + '\n'
+        ret += indent(level) + '}))'
     else:
         assert False                # not implemented
-    if level == 1:
-        ret = '\n' + ret
     return ret
 
 
@@ -45,39 +55,37 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
         self.defn = None
         self.decl = None
         self._schema = None
-        self._jsons = None
+        self._qlits = None
         self._used_types = None
         self._name_map = None
 
     def visit_begin(self, schema):
         self._schema = schema
-        self._jsons = []
+        self._qlits = []
         self._used_types = []
         self._name_map = {}
 
     def visit_end(self):
         # visit the types that are actually used
-        jsons = self._jsons
-        self._jsons = []
+        qlits = self._qlits
+        self._qlits = []
         for typ in self._used_types:
             typ.visit(self)
         # generate C
         # TODO can generate awfully long lines
-        jsons.extend(self._jsons)
-        name = c_name(prefix, protect=False) + 'qmp_schema_json'
+        qlits.extend(self._qlits)
+        name = c_name(prefix, protect=False) + 'qmp_schema_qlit'
         self.decl = mcgen('''
-extern const char %(c_name)s[];
+extern const QLitObject %(c_name)s;
 ''',
                           c_name=c_name(name))
-        lines = to_json(jsons).split('\n')
-        c_string = '\n    '.join([to_c_string(line) for line in lines])
         self.defn = mcgen('''
-const char %(c_name)s[] = %(c_string)s;
+const QLitObject %(c_name)s = %(c_string)s;
 ''',
                           c_name=c_name(name),
-                          c_string=c_string)
+                          c_string=to_qlit(qlits))
         self._schema = None
-        self._jsons = None
+        self._qlits = None
         self._used_types = None
         self._name_map = None
 
@@ -111,12 +119,12 @@ const char %(c_name)s[] = %(c_string)s;
             return '[' + self._use_type(typ.element_type) + ']'
         return self._name(typ.name)
 
-    def _gen_json(self, name, mtype, obj):
+    def _gen_qlit(self, name, mtype, obj):
         if mtype not in ('command', 'event', 'builtin', 'array'):
             name = self._name(name)
         obj['name'] = name
         obj['meta-type'] = mtype
-        self._jsons.append(obj)
+        self._qlits.append(obj)
 
     def _gen_member(self, member):
         ret = {'name': member.name, 'type': self._use_type(member.type)}
@@ -132,24 +140,24 @@ const char %(c_name)s[] = %(c_string)s;
         return {'case': variant.name, 'type': self._use_type(variant.type)}
 
     def visit_builtin_type(self, name, info, json_type):
-        self._gen_json(name, 'builtin', {'json-type': json_type})
+        self._gen_qlit(name, 'builtin', {'json-type': json_type})
 
     def visit_enum_type(self, name, info, values, prefix):
-        self._gen_json(name, 'enum', {'values': values})
+        self._gen_qlit(name, 'enum', {'values': values})
 
     def visit_array_type(self, name, info, element_type):
         element = self._use_type(element_type)
-        self._gen_json('[' + element + ']', 'array', {'element-type': element})
+        self._gen_qlit('[' + element + ']', 'array', {'element-type': element})
 
     def visit_object_type_flat(self, name, info, members, variants):
         obj = {'members': [self._gen_member(m) for m in members]}
         if variants:
             obj.update(self._gen_variants(variants.tag_member.name,
                                           variants.variants))
-        self._gen_json(name, 'object', obj)
+        self._gen_qlit(name, 'object', obj)
 
     def visit_alternate_type(self, name, info, variants):
-        self._gen_json(name, 'alternate',
+        self._gen_qlit(name, 'alternate',
                        {'members': [{'type': self._use_type(m.type)}
                                     for m in variants.variants]})
 
@@ -157,13 +165,13 @@ const char %(c_name)s[] = %(c_string)s;
                       gen, success_response, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
-        self._gen_json(name, 'command',
+        self._gen_qlit(name, 'command',
                        {'arg-type': self._use_type(arg_type),
                         'ret-type': self._use_type(ret_type)})
 
     def visit_event(self, name, info, arg_type, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
-        self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
+        self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)})
 
 # Debugging aid: unmask QAPI schema's type names
 # We normally mask them, because they're not QMP wire ABI
@@ -205,11 +213,18 @@ h_comment = '''
 
 fdef.write(mcgen('''
 #include "qemu/osdep.h"
+#include "qapi/qmp/qlit.h"
 #include "%(prefix)sqmp-introspect.h"
 
 ''',
                  prefix=prefix))
 
+fdecl.write(mcgen('''
+#include "qemu/osdep.h"
+#include "qapi/qmp/qlit.h"
+
+'''))
+
 schema = QAPISchema(input_file)
 gen = QAPISchemaGenIntrospectVisitor(opt_unmask)
 schema.visit(gen)
diff --git a/monitor.c b/monitor.c
index 9239f7adde..5685697f59 100644
--- a/monitor.c
+++ b/monitor.c
@@ -953,7 +953,7 @@ EventInfoList *qmp_query_events(Error **errp)
 static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
                                  Error **errp)
 {
-    *ret_data = qobject_from_json(qmp_schema_json, &error_abort);
+    *ret_data = qobject_from_qlit(&qmp_schema_qlit);
 }
 
 /*
diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c
index fe591814e4..7c1d10e274 100644
--- a/tests/test-qobject-input-visitor.c
+++ b/tests/test-qobject-input-visitor.c
@@ -1247,24 +1247,27 @@ static void test_visitor_in_fail_alternate(TestInputVisitorData *data,
 }
 
 static void do_test_visitor_in_qmp_introspect(TestInputVisitorData *data,
-                                              const char *schema_json)
+                                              const QLitObject *qlit)
 {
     SchemaInfoList *schema = NULL;
+    QObject *obj = qobject_from_qlit(qlit);
     Visitor *v;
 
-    v = visitor_input_test_init_raw(data, schema_json);
+    v = qobject_input_visitor_new(obj);
 
     visit_type_SchemaInfoList(v, NULL, &schema, &error_abort);
     g_assert(schema);
 
     qapi_free_SchemaInfoList(schema);
+    qobject_decref(obj);
+    visit_free(v);
 }
 
 static void test_visitor_in_qmp_introspect(TestInputVisitorData *data,
                                            const void *unused)
 {
-    do_test_visitor_in_qmp_introspect(data, test_qmp_schema_json);
-    do_test_visitor_in_qmp_introspect(data, qmp_schema_json);
+    do_test_visitor_in_qmp_introspect(data, &test_qmp_schema_qlit);
+    do_test_visitor_in_qmp_introspect(data, &qmp_schema_qlit);
 }
 
 int main(int argc, char **argv)
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index f04c63fe82..0a90f2278a 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -1327,18 +1327,27 @@ Example:
     #ifndef EXAMPLE_QMP_INTROSPECT_H
     #define EXAMPLE_QMP_INTROSPECT_H
 
-    extern const char example_qmp_schema_json[];
+    extern const QLitObject qmp_schema_qlit;
 
     #endif
     $ cat qapi-generated/example-qmp-introspect.c
 [Uninteresting stuff omitted...]
 
-    const char example_qmp_schema_json[] = "["
-        "{\"arg-type\": \"0\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
-        "{\"arg-type\": \"1\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"2\"}, "
-        "{\"members\": [], \"meta-type\": \"object\", \"name\": \"0\"}, "
-        "{\"members\": [{\"name\": \"arg1\", \"type\": \"[2]\"}], \"meta-type\": \"object\", \"name\": \"1\"}, "
-        "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"default\": null, \"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, "
-        "{\"element-type\": \"2\", \"meta-type\": \"array\", \"name\": \"[2]\"}, "
-        "{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, "
-        "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]";
+    const QLitObject example_qmp_schema_qlit = QLIT_QLIST(((QLitObject[]) {
+        QLIT_QDICT(((QLitDictEntry[]) {
+            { "arg-type", QLIT_QSTR("0") },
+            { "meta-type", QLIT_QSTR("event") },
+            { "name", QLIT_QSTR("Event") },
+            { }
+        })),
+        QLIT_QDICT(((QLitDictEntry[]) {
+            { "members", QLIT_QLIST(((QLitObject[]) {
+                { }
+            })) },
+            { "meta-type", QLIT_QSTR("object") },
+            { "name", QLIT_QSTR("0") },
+            { }
+        })),
+        ...
+        { }
+    }));
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 03/50] qapi2texi: minor python code simplification
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit() Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 02/50] qapi: generate a literal qobject for introspection Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-06 15:19   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions Marc-André Lureau
                   ` (48 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi2texi.py | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index a317526e51..73cfb01727 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -136,10 +136,9 @@ def texi_enum_value(value):
 def texi_member(member, suffix=''):
     """Format a table of members item for an object type member"""
     typ = member.type.doc_type()
-    return '@item @code{%s%s%s}%s%s\n' % (
-        member.name,
-        ': ' if typ else '',
-        typ if typ else '',
+    membertype = ': ' + typ if typ else ''
+    return '@item @code{%s%s}%s%s\n' % (
+        member.name, membertype,
         ' (optional)' if member.optional else '',
         suffix)
 
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (2 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 03/50] qapi2texi: minor python code simplification Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-06 15:46   ` Markus Armbruster
  2017-12-06 16:23   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 05/50] qapi: add tests for invalid 'if' Marc-André Lureau
                   ` (47 subsequent siblings)
  51 siblings, 2 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Accept 'if' key in top-level elements, accepted as string or list of
string type. The following patches will modify the test visitor to
check the value is correctly saved, and generate #if/#endif code (as a
single #if/endif line or a series for a list).

Example of 'if' key:
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
  'if': 'defined(TEST_IF_STRUCT)' }

The generated code is for now *unconditional*. Later patches generate
the conditionals.

A following patch for qapi-code-gen.txt will provide more complete
documentation for 'if' usage.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                         | 35 +++++++++++++++++++++++++++------
 tests/test-qmp-commands.c               |  6 ++++++
 tests/qapi-schema/qapi-schema-test.json | 20 +++++++++++++++++++
 tests/qapi-schema/qapi-schema-test.out  | 22 +++++++++++++++++++++
 4 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 62dc52ed6e..20c1abf915 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -639,6 +639,26 @@ def add_name(name, info, meta, implicit=False):
     all_names[name] = meta
 
 
+def check_if(expr, info):
+
+    def check_if_str(ifcond, info):
+        if ifcond == '':
+            raise QAPISemError(info, "'if' condition '' makes no sense")
+
+    ifcond = expr['if']
+    if isinstance(ifcond, str):
+        check_if_str(ifcond, info)
+    elif (isinstance(ifcond, list)
+          and all(isinstance(elt, str) for elt in ifcond)):
+        if ifcond == []:
+            raise QAPISemError(info, "'if' condition [] is useless")
+        for elt in ifcond:
+            check_if_str(elt, info)
+    else:
+        raise QAPISemError(
+            info, "'if' condition must be a string or a list of strings")
+
+
 def check_type(info, source, value, allow_array=False,
                allow_dict=False, allow_optional=False,
                allow_metas=[]):
@@ -878,6 +898,8 @@ def check_keys(expr_elem, meta, required, optional=[]):
             raise QAPISemError(info,
                                "'%s' of %s '%s' should only use true value"
                                % (key, meta, name))
+        if key == 'if':
+            check_if(expr, info)
     for key in required:
         if key not in expr:
             raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
@@ -903,27 +925,28 @@ def check_exprs(exprs):
 
         if 'enum' in expr:
             meta = 'enum'
-            check_keys(expr_elem, 'enum', ['data'], ['prefix'])
+            check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix'])
             enum_types[expr[meta]] = expr
         elif 'union' in expr:
             meta = 'union'
             check_keys(expr_elem, 'union', ['data'],
-                       ['base', 'discriminator'])
+                       ['base', 'discriminator', 'if'])
             union_types[expr[meta]] = expr
         elif 'alternate' in expr:
             meta = 'alternate'
-            check_keys(expr_elem, 'alternate', ['data'])
+            check_keys(expr_elem, 'alternate', ['data'], ['if'])
         elif 'struct' in expr:
             meta = 'struct'
-            check_keys(expr_elem, 'struct', ['data'], ['base'])
+            check_keys(expr_elem, 'struct', ['data'], ['base', 'if'])
             struct_types[expr[meta]] = expr
         elif 'command' in expr:
             meta = 'command'
             check_keys(expr_elem, 'command', [],
-                       ['data', 'returns', 'gen', 'success-response', 'boxed'])
+                       ['data', 'returns', 'gen', 'success-response', 'boxed',
+                        'if'])
         elif 'event' in expr:
             meta = 'event'
-            check_keys(expr_elem, 'event', [], ['data', 'boxed'])
+            check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
         else:
             raise QAPISemError(expr_elem['info'],
                                "Expression is missing metatype")
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 904c89d4d4..9b9a7ffee7 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -10,6 +10,12 @@
 
 static QmpCommandList qmp_commands;
 
+/* #if defined(TEST_IF_CMD) */
+void qmp_TestIfCmd(TestIfStruct *foo, Error **errp)
+{
+}
+/* #endif */
+
 void qmp_user_def_cmd(Error **errp)
 {
 }
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index c72dbd8050..dc2c444fc1 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -188,3 +188,23 @@
   'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
             'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
   'returns': '__org.qemu_x-Union1' }
+
+# test 'if' condition handling
+
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+  'if': 'defined(TEST_IF_STRUCT)' }
+
+{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
+  'if': 'defined(TEST_IF_ENUM)' }
+
+{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
+  'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
+
+{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
+  'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
+
+{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
+  'if': 'defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)' }
+
+{ 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
+  'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 3b1e9082d3..7fbaea19bc 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -52,6 +52,22 @@ enum QEnumTwo ['value1', 'value2']
     prefix QENUM_TWO
 enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
     prefix QTYPE
+alternate TestIfAlternate
+    tag type
+    case foo: int
+    case bar: TestStruct
+command TestIfCmd q_obj_TestIfCmd-arg -> None
+   gen=True success_response=True boxed=False
+enum TestIfEnum ['foo', 'bar']
+event TestIfEvent q_obj_TestIfEvent-arg
+   boxed=False
+object TestIfStruct
+    member foo: int optional=False
+object TestIfUnion
+    member type: TestIfUnionKind optional=False
+    tag type
+    case foo: q_obj_TestStruct-wrapper
+enum TestIfUnionKind ['foo']
 object TestStruct
     member integer: int optional=False
     member boolean: bool optional=False
@@ -172,6 +188,12 @@ object q_obj_EVENT_D-arg
     member b: str optional=False
     member c: str optional=True
     member enum3: EnumOne optional=True
+object q_obj_TestIfCmd-arg
+    member foo: TestIfStruct optional=False
+object q_obj_TestIfEvent-arg
+    member foo: TestIfStruct optional=False
+object q_obj_TestStruct-wrapper
+    member data: TestStruct optional=False
 object q_obj_UserDefFlatUnion2-base
     member integer: int optional=True
     member string: str optional=False
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 05/50] qapi: add tests for invalid 'if'
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (3 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-06 16:34   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 06/50] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
                   ` (46 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/Makefile.include                   | 3 +++
 tests/qapi-schema/bad-if-empty-list.err  | 1 +
 tests/qapi-schema/bad-if-empty-list.exit | 1 +
 tests/qapi-schema/bad-if-empty-list.json | 3 +++
 tests/qapi-schema/bad-if-empty-list.out  | 0
 tests/qapi-schema/bad-if-empty.err       | 1 +
 tests/qapi-schema/bad-if-empty.exit      | 1 +
 tests/qapi-schema/bad-if-empty.json      | 3 +++
 tests/qapi-schema/bad-if-empty.out       | 0
 tests/qapi-schema/bad-if.err             | 1 +
 tests/qapi-schema/bad-if.exit            | 1 +
 tests/qapi-schema/bad-if.json            | 3 +++
 tests/qapi-schema/bad-if.out             | 0
 13 files changed, 18 insertions(+)
 create mode 100644 tests/qapi-schema/bad-if-empty-list.err
 create mode 100644 tests/qapi-schema/bad-if-empty-list.exit
 create mode 100644 tests/qapi-schema/bad-if-empty-list.json
 create mode 100644 tests/qapi-schema/bad-if-empty-list.out
 create mode 100644 tests/qapi-schema/bad-if-empty.err
 create mode 100644 tests/qapi-schema/bad-if-empty.exit
 create mode 100644 tests/qapi-schema/bad-if-empty.json
 create mode 100644 tests/qapi-schema/bad-if-empty.out
 create mode 100644 tests/qapi-schema/bad-if.err
 create mode 100644 tests/qapi-schema/bad-if.exit
 create mode 100644 tests/qapi-schema/bad-if.json
 create mode 100644 tests/qapi-schema/bad-if.out

diff --git a/tests/Makefile.include b/tests/Makefile.include
index fae5715e9c..8dac7c9083 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -402,6 +402,9 @@ qapi-schema += args-unknown.json
 qapi-schema += bad-base.json
 qapi-schema += bad-data.json
 qapi-schema += bad-ident.json
+qapi-schema += bad-if.json
+qapi-schema += bad-if-empty.json
+qapi-schema += bad-if-empty-list.json
 qapi-schema += bad-type-bool.json
 qapi-schema += bad-type-dict.json
 qapi-schema += bad-type-int.json
diff --git a/tests/qapi-schema/bad-if-empty-list.err b/tests/qapi-schema/bad-if-empty-list.err
new file mode 100644
index 0000000000..75fe6497bc
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
diff --git a/tests/qapi-schema/bad-if-empty-list.exit b/tests/qapi-schema/bad-if-empty-list.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-empty-list.json b/tests/qapi-schema/bad-if-empty-list.json
new file mode 100644
index 0000000000..94f2eb8670
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty-list.json
@@ -0,0 +1,3 @@
+# check empty 'if' list
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+  'if': [] }
diff --git a/tests/qapi-schema/bad-if-empty-list.out b/tests/qapi-schema/bad-if-empty-list.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/bad-if-empty.err b/tests/qapi-schema/bad-if-empty.err
new file mode 100644
index 0000000000..358bdc3e51
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense
diff --git a/tests/qapi-schema/bad-if-empty.exit b/tests/qapi-schema/bad-if-empty.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-empty.json b/tests/qapi-schema/bad-if-empty.json
new file mode 100644
index 0000000000..fe1dd4eca6
--- /dev/null
+++ b/tests/qapi-schema/bad-if-empty.json
@@ -0,0 +1,3 @@
+# check empty 'if'
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+  'if': '' }
diff --git a/tests/qapi-schema/bad-if-empty.out b/tests/qapi-schema/bad-if-empty.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/bad-if.err b/tests/qapi-schema/bad-if.err
new file mode 100644
index 0000000000..c2e3f5f44c
--- /dev/null
+++ b/tests/qapi-schema/bad-if.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if.json:2: 'if' condition must be a string or a list of strings
diff --git a/tests/qapi-schema/bad-if.exit b/tests/qapi-schema/bad-if.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if.json b/tests/qapi-schema/bad-if.json
new file mode 100644
index 0000000000..3edd1a0bf2
--- /dev/null
+++ b/tests/qapi-schema/bad-if.json
@@ -0,0 +1,3 @@
+# check invalid 'if' type
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+  'if': { 'value': 'defined(TEST_IF_STRUCT)' } }
diff --git a/tests/qapi-schema/bad-if.out b/tests/qapi-schema/bad-if.out
new file mode 100644
index 0000000000..e69de29bb2
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 06/50] qapi: pass 'if' condition into QAPISchemaEntity objects
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (4 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 05/50] qapi: add tests for invalid 'if' Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-06 17:13   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 07/50] qapi: add 'ifcond' to visitor methods Marc-André Lureau
                   ` (45 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Built-in objects remain unconditional.  Explicitly defined objects
use the condition specified in the schema.  Implicitly defined
objects inherit their condition from their users.  For most of them,
there is exactly one user, so the condition to use is obvious.  The
exception is the wrapper types generated for simple union variants,
which can be shared by any number of simple unions.  The tight
condition would be the disjunction of the conditions of these simple
unions.  For now, use wrapped type's condition instead.  Much
simpler and good enough for now.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py | 89 ++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 57 insertions(+), 32 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 20c1abf915..0f55caa18d 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1000,7 +1000,7 @@ def check_exprs(exprs):
 #
 
 class QAPISchemaEntity(object):
-    def __init__(self, name, info, doc):
+    def __init__(self, name, info, doc, ifcond=None):
         assert isinstance(name, str)
         self.name = name
         # For explicitly defined entities, info points to the (explicit)
@@ -1010,6 +1010,7 @@ class QAPISchemaEntity(object):
         # such place).
         self.info = info
         self.doc = doc
+        self.ifcond = ifcond
 
     def c_name(self):
         return c_name(self.name)
@@ -1126,8 +1127,8 @@ class QAPISchemaBuiltinType(QAPISchemaType):
 
 
 class QAPISchemaEnumType(QAPISchemaType):
-    def __init__(self, name, info, doc, values, prefix):
-        QAPISchemaType.__init__(self, name, info, doc)
+    def __init__(self, name, info, doc, ifcond, values, prefix):
+        QAPISchemaType.__init__(self, name, info, doc, ifcond)
         for v in values:
             assert isinstance(v, QAPISchemaMember)
             v.set_owner(name)
@@ -1162,7 +1163,7 @@ class QAPISchemaEnumType(QAPISchemaType):
 
 class QAPISchemaArrayType(QAPISchemaType):
     def __init__(self, name, info, element_type):
-        QAPISchemaType.__init__(self, name, info, None)
+        QAPISchemaType.__init__(self, name, info, None, None)
         assert isinstance(element_type, str)
         self._element_type_name = element_type
         self.element_type = None
@@ -1170,6 +1171,7 @@ class QAPISchemaArrayType(QAPISchemaType):
     def check(self, schema):
         self.element_type = schema.lookup_type(self._element_type_name)
         assert self.element_type
+        self.ifcond = self.element_type.ifcond
 
     def is_implicit(self):
         return True
@@ -1191,11 +1193,12 @@ class QAPISchemaArrayType(QAPISchemaType):
 
 
 class QAPISchemaObjectType(QAPISchemaType):
-    def __init__(self, name, info, doc, base, local_members, variants):
+    def __init__(self, name, info, doc, ifcond,
+                 base, local_members, variants):
         # struct has local_members, optional base, and no variants
         # flat union has base, variants, and no local_members
         # simple union has local_members, variants, and no base
-        QAPISchemaType.__init__(self, name, info, doc)
+        QAPISchemaType.__init__(self, name, info, doc, ifcond)
         assert base is None or isinstance(base, str)
         for m in local_members:
             assert isinstance(m, QAPISchemaObjectTypeMember)
@@ -1383,8 +1386,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
 
 
 class QAPISchemaAlternateType(QAPISchemaType):
-    def __init__(self, name, info, doc, variants):
-        QAPISchemaType.__init__(self, name, info, doc)
+    def __init__(self, name, info, doc, ifcond, variants):
+        QAPISchemaType.__init__(self, name, info, doc, ifcond)
         assert isinstance(variants, QAPISchemaObjectTypeVariants)
         assert variants.tag_member
         variants.set_owner(name)
@@ -1420,9 +1423,9 @@ class QAPISchemaAlternateType(QAPISchemaType):
 
 
 class QAPISchemaCommand(QAPISchemaEntity):
-    def __init__(self, name, info, doc, arg_type, ret_type,
+    def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
                  gen, success_response, boxed):
-        QAPISchemaEntity.__init__(self, name, info, doc)
+        QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
         self._arg_type_name = arg_type
@@ -1459,8 +1462,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
 
 
 class QAPISchemaEvent(QAPISchemaEntity):
-    def __init__(self, name, info, doc, arg_type, boxed):
-        QAPISchemaEntity.__init__(self, name, info, doc)
+    def __init__(self, name, info, doc, ifcond, arg_type, boxed):
+        QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
         assert not arg_type or isinstance(arg_type, str)
         self._arg_type_name = arg_type
         self.arg_type = None
@@ -1544,22 +1547,22 @@ class QAPISchema(object):
                   ('null',   'null',    'QNull' + pointer_suffix)]:
             self._def_builtin_type(*t)
         self.the_empty_object_type = QAPISchemaObjectType(
-            'q_empty', None, None, None, [], None)
+            'q_empty', None, None, None, None, [], None)
         self._def_entity(self.the_empty_object_type)
         qtype_values = self._make_enum_members(['none', 'qnull', 'qnum',
                                                 'qstring', 'qdict', 'qlist',
                                                 'qbool'])
-        self._def_entity(QAPISchemaEnumType('QType', None, None,
+        self._def_entity(QAPISchemaEnumType('QType', None, None, None,
                                             qtype_values, 'QTYPE'))
 
     def _make_enum_members(self, values):
         return [QAPISchemaMember(v) for v in values]
 
-    def _make_implicit_enum_type(self, name, info, values):
+    def _make_implicit_enum_type(self, name, info, ifcond, values):
         # See also QAPISchemaObjectTypeMember._pretty_owner()
         name = name + 'Kind'   # Use namespace reserved by add_name()
         self._def_entity(QAPISchemaEnumType(
-            name, info, None, self._make_enum_members(values), None))
+            name, info, None, ifcond, self._make_enum_members(values), None))
         return name
 
     def _make_array_type(self, element_type, info):
@@ -1568,22 +1571,37 @@ class QAPISchema(object):
             self._def_entity(QAPISchemaArrayType(name, info, element_type))
         return name
 
-    def _make_implicit_object_type(self, name, info, doc, role, members):
+    def _make_implicit_object_type(self, name, info, doc, ifcond,
+                                   role, members):
         if not members:
             return None
         # See also QAPISchemaObjectTypeMember._pretty_owner()
         name = 'q_obj_%s-%s' % (name, role)
-        if not self.lookup_entity(name, QAPISchemaObjectType):
-            self._def_entity(QAPISchemaObjectType(name, info, doc, None,
-                                                  members, None))
+        typ = self.lookup_entity(name, QAPISchemaObjectType)
+        if typ:
+            # The implicit object type has multiple users.  This can
+            # happen only for simple unions' implicit wrapper types.
+            # Its ifcond should be the disjunction of its user's
+            # ifconds.  Not implemented.  Instead, we always pass the
+            # wrapped type's ifcond, which is trivially the same for all
+            # users.  It's also necessary for the wrapper to compile.
+            # But it's not tight: the disjunction need not imply it.  We
+            # may end up compiling useless wrapper types.
+            # TODO kill simple unions or implement the disjunction
+            assert ifcond == typ.ifcond
+        else:
+            self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
+                                                  None, members, None))
         return name
 
     def _def_enum_type(self, expr, info, doc):
         name = expr['enum']
         data = expr['data']
         prefix = expr.get('prefix')
+        ifcond = expr.get('if')
         self._def_entity(QAPISchemaEnumType(
-            name, info, doc, self._make_enum_members(data), prefix))
+            name, info, doc, ifcond,
+            self._make_enum_members(data), prefix))
 
     def _make_member(self, name, typ, info):
         optional = False
@@ -1603,7 +1621,8 @@ class QAPISchema(object):
         name = expr['struct']
         base = expr.get('base')
         data = expr['data']
-        self._def_entity(QAPISchemaObjectType(name, info, doc, base,
+        ifcond = expr.get('if')
+        self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, base,
                                               self._make_members(data, info),
                                               None))
 
@@ -1615,18 +1634,21 @@ class QAPISchema(object):
             assert len(typ) == 1
             typ = self._make_array_type(typ[0], info)
         typ = self._make_implicit_object_type(
-            typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
+            typ, info, None, self.lookup_type(typ).ifcond,
+            'wrapper', [self._make_member('data', typ, info)])
         return QAPISchemaObjectTypeVariant(case, typ)
 
     def _def_union_type(self, expr, info, doc):
         name = expr['union']
         data = expr['data']
         base = expr.get('base')
+        ifcond = expr.get('if')
         tag_name = expr.get('discriminator')
         tag_member = None
         if isinstance(base, dict):
-            base = (self._make_implicit_object_type(
-                name, info, doc, 'base', self._make_members(base, info)))
+            base = self._make_implicit_object_type(
+                name, info, doc, ifcond,
+                'base', self._make_members(base, info))
         if tag_name:
             variants = [self._make_variant(key, value)
                         for (key, value) in data.iteritems()]
@@ -1634,12 +1656,12 @@ class QAPISchema(object):
         else:
             variants = [self._make_simple_variant(key, value, info)
                         for (key, value) in data.iteritems()]
-            typ = self._make_implicit_enum_type(name, info,
+            typ = self._make_implicit_enum_type(name, info, ifcond,
                                                 [v.name for v in variants])
             tag_member = QAPISchemaObjectTypeMember('type', typ, False)
             members = [tag_member]
         self._def_entity(
-            QAPISchemaObjectType(name, info, doc, base, members,
+            QAPISchemaObjectType(name, info, doc, ifcond, base, members,
                                  QAPISchemaObjectTypeVariants(tag_name,
                                                               tag_member,
                                                               variants)))
@@ -1647,11 +1669,12 @@ class QAPISchema(object):
     def _def_alternate_type(self, expr, info, doc):
         name = expr['alternate']
         data = expr['data']
+        ifcond = expr.get('if')
         variants = [self._make_variant(key, value)
                     for (key, value) in data.iteritems()]
         tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
         self._def_entity(
-            QAPISchemaAlternateType(name, info, doc,
+            QAPISchemaAlternateType(name, info, doc, ifcond,
                                     QAPISchemaObjectTypeVariants(None,
                                                                  tag_member,
                                                                  variants)))
@@ -1663,23 +1686,25 @@ class QAPISchema(object):
         gen = expr.get('gen', True)
         success_response = expr.get('success-response', True)
         boxed = expr.get('boxed', False)
+        ifcond = expr.get('if')
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
-                name, info, doc, 'arg', self._make_members(data, info))
+                name, info, doc, ifcond, 'arg', self._make_members(data, info))
         if isinstance(rets, list):
             assert len(rets) == 1
             rets = self._make_array_type(rets[0], info)
-        self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
+        self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets,
                                            gen, success_response, boxed))
 
     def _def_event(self, expr, info, doc):
         name = expr['event']
         data = expr.get('data')
         boxed = expr.get('boxed', False)
+        ifcond = expr.get('if')
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
-                name, info, doc, 'arg', self._make_members(data, info))
-        self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
+                name, info, doc, ifcond, 'arg', self._make_members(data, info))
+        self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed))
 
     def _def_exprs(self):
         for expr_elem in self.exprs:
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 07/50] qapi: add 'ifcond' to visitor methods
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (5 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 06/50] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-06 17:23   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 08/50] qapi: mcgen() shouldn't indent # lines Marc-André Lureau
                   ` (44 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Modify the test visitor to check correct passing of values.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                        | 31 +++++++++++++++++--------------
 scripts/qapi-commands.py               |  2 +-
 scripts/qapi-event.py                  |  2 +-
 scripts/qapi-introspect.py             | 12 ++++++------
 scripts/qapi-types.py                  |  8 ++++----
 scripts/qapi-visit.py                  |  8 ++++----
 scripts/qapi2texi.py                   | 10 +++++-----
 tests/qapi-schema/qapi-schema-test.out |  9 +++++++++
 tests/qapi-schema/test-qapi.py         | 21 ++++++++++++++++-----
 9 files changed, 63 insertions(+), 40 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 0f55caa18d..f2b5a7e131 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1039,26 +1039,26 @@ class QAPISchemaVisitor(object):
     def visit_builtin_type(self, name, info, json_type):
         pass
 
-    def visit_enum_type(self, name, info, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, values, prefix):
         pass
 
-    def visit_array_type(self, name, info, element_type):
+    def visit_array_type(self, name, info, ifcond, element_type):
         pass
 
-    def visit_object_type(self, name, info, base, members, variants):
+    def visit_object_type(self, name, info, ifcond, base, members, variants):
         pass
 
-    def visit_object_type_flat(self, name, info, members, variants):
+    def visit_object_type_flat(self, name, info, ifcond, members, variants):
         pass
 
-    def visit_alternate_type(self, name, info, variants):
+    def visit_alternate_type(self, name, info, ifcond, variants):
         pass
 
-    def visit_command(self, name, info, arg_type, ret_type,
+    def visit_command(self, name, info, ifcond, arg_type, ret_type,
                       gen, success_response, boxed):
         pass
 
-    def visit_event(self, name, info, arg_type, boxed):
+    def visit_event(self, name, info, ifcond, arg_type, boxed):
         pass
 
 
@@ -1157,7 +1157,7 @@ class QAPISchemaEnumType(QAPISchemaType):
         return 'string'
 
     def visit(self, visitor):
-        visitor.visit_enum_type(self.name, self.info,
+        visitor.visit_enum_type(self.name, self.info, self.ifcond,
                                 self.member_names(), self.prefix)
 
 
@@ -1189,7 +1189,8 @@ class QAPISchemaArrayType(QAPISchemaType):
         return 'array of ' + elt_doc_type
 
     def visit(self, visitor):
-        visitor.visit_array_type(self.name, self.info, self.element_type)
+        visitor.visit_array_type(self.name, self.info, self.ifcond,
+                                 self.element_type)
 
 
 class QAPISchemaObjectType(QAPISchemaType):
@@ -1270,9 +1271,9 @@ class QAPISchemaObjectType(QAPISchemaType):
         return 'object'
 
     def visit(self, visitor):
-        visitor.visit_object_type(self.name, self.info,
+        visitor.visit_object_type(self.name, self.info, self.ifcond,
                                   self.base, self.local_members, self.variants)
-        visitor.visit_object_type_flat(self.name, self.info,
+        visitor.visit_object_type_flat(self.name, self.info, self.ifcond,
                                        self.members, self.variants)
 
 
@@ -1416,7 +1417,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
         return 'value'
 
     def visit(self, visitor):
-        visitor.visit_alternate_type(self.name, self.info, self.variants)
+        visitor.visit_alternate_type(self.name, self.info, self.ifcond,
+                                     self.variants)
 
     def is_empty(self):
         return False
@@ -1456,7 +1458,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
             assert isinstance(self.ret_type, QAPISchemaType)
 
     def visit(self, visitor):
-        visitor.visit_command(self.name, self.info,
+        visitor.visit_command(self.name, self.info, self.ifcond,
                               self.arg_type, self.ret_type,
                               self.gen, self.success_response, self.boxed)
 
@@ -1486,7 +1488,8 @@ class QAPISchemaEvent(QAPISchemaEntity):
             raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
 
     def visit(self, visitor):
-        visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
+        visitor.visit_event(self.name, self.info, self.ifcond,
+                            self.arg_type, self.boxed)
 
 
 class QAPISchema(object):
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 974d0a4a80..669aef1eb7 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -240,7 +240,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self._regy = None
         self._visited_ret_types = None
 
-    def visit_command(self, name, info, arg_type, ret_type,
+    def visit_command(self, name, info, ifcond, arg_type, ret_type,
                       gen, success_response, boxed):
         if not gen:
             return
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 07b4b70199..dda496e824 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -163,7 +163,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
         self.defn += gen_enum_lookup(event_enum_name, self._event_names)
         self._event_names = None
 
-    def visit_event(self, name, info, arg_type, boxed):
+    def visit_event(self, name, info, ifcond, arg_type, boxed):
         self.decl += gen_event_send_decl(name, arg_type, boxed)
         self.defn += gen_event_send(name, arg_type, boxed)
         self._event_names.append(name)
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 0002bc1a68..56c1f9d548 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -142,26 +142,26 @@ const QLitObject %(c_name)s = %(c_string)s;
     def visit_builtin_type(self, name, info, json_type):
         self._gen_qlit(name, 'builtin', {'json-type': json_type})
 
-    def visit_enum_type(self, name, info, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, values, prefix):
         self._gen_qlit(name, 'enum', {'values': values})
 
-    def visit_array_type(self, name, info, element_type):
+    def visit_array_type(self, name, info, ifcond, element_type):
         element = self._use_type(element_type)
         self._gen_qlit('[' + element + ']', 'array', {'element-type': element})
 
-    def visit_object_type_flat(self, name, info, members, variants):
+    def visit_object_type_flat(self, name, info, ifcond, members, variants):
         obj = {'members': [self._gen_member(m) for m in members]}
         if variants:
             obj.update(self._gen_variants(variants.tag_member.name,
                                           variants.variants))
         self._gen_qlit(name, 'object', obj)
 
-    def visit_alternate_type(self, name, info, variants):
+    def visit_alternate_type(self, name, info, ifcond, variants):
         self._gen_qlit(name, 'alternate',
                        {'members': [{'type': self._use_type(m.type)}
                                     for m in variants.variants]})
 
-    def visit_command(self, name, info, arg_type, ret_type,
+    def visit_command(self, name, info, ifcond, arg_type, ret_type,
                       gen, success_response, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
@@ -169,7 +169,7 @@ const QLitObject %(c_name)s = %(c_string)s;
                        {'arg-type': self._use_type(arg_type),
                         'ret-type': self._use_type(ret_type)})
 
-    def visit_event(self, name, info, arg_type, boxed):
+    def visit_event(self, name, info, ifcond, arg_type, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
         self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)})
 
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 7e3051dbb9..915786c463 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -195,7 +195,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
         self.decl += gen_type_cleanup_decl(name)
         self.defn += gen_type_cleanup(name)
 
-    def visit_enum_type(self, name, info, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, values, prefix):
         # Special case for our lone builtin enum type
         # TODO use something cleaner than existence of info
         if not info:
@@ -206,7 +206,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             self._fwdecl += gen_enum(name, values, prefix)
             self.defn += gen_enum_lookup(name, values, prefix)
 
-    def visit_array_type(self, name, info, element_type):
+    def visit_array_type(self, name, info, ifcond, element_type):
         if isinstance(element_type, QAPISchemaBuiltinType):
             self._btin += gen_fwd_object_or_array(name)
             self._btin += gen_array(name, element_type)
@@ -218,7 +218,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             self.decl += gen_array(name, element_type)
             self._gen_type_cleanup(name)
 
-    def visit_object_type(self, name, info, base, members, variants):
+    def visit_object_type(self, name, info, ifcond, base, members, variants):
         # Nothing to do for the special empty builtin
         if name == 'q_empty':
             return
@@ -232,7 +232,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             # implicit types won't be directly allocated/freed
             self._gen_type_cleanup(name)
 
-    def visit_alternate_type(self, name, info, variants):
+    def visit_alternate_type(self, name, info, ifcond, variants):
         self._fwdecl += gen_fwd_object_or_array(name)
         self.decl += gen_object(name, None, [variants.tag_member], variants)
         self._gen_type_cleanup(name)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 7e1cfc13f0..aceea2a9f9 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -282,7 +282,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
         self.decl = self._btin + self.decl
         self._btin = None
 
-    def visit_enum_type(self, name, info, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, values, prefix):
         # Special case for our lone builtin enum type
         # TODO use something cleaner than existence of info
         if not info:
@@ -293,7 +293,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
             self.decl += gen_visit_decl(name, scalar=True)
             self.defn += gen_visit_enum(name)
 
-    def visit_array_type(self, name, info, element_type):
+    def visit_array_type(self, name, info, ifcond, element_type):
         decl = gen_visit_decl(name)
         defn = gen_visit_list(name, element_type)
         if isinstance(element_type, QAPISchemaBuiltinType):
@@ -304,7 +304,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
             self.decl += decl
             self.defn += defn
 
-    def visit_object_type(self, name, info, base, members, variants):
+    def visit_object_type(self, name, info, ifcond, base, members, variants):
         # Nothing to do for the special empty builtin
         if name == 'q_empty':
             return
@@ -317,7 +317,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
             self.decl += gen_visit_decl(name)
             self.defn += gen_visit_object(name, base, members, variants)
 
-    def visit_alternate_type(self, name, info, variants):
+    def visit_alternate_type(self, name, info, ifcond, variants):
         self.decl += gen_visit_decl(name)
         self.defn += gen_visit_alternate(name, variants)
 
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 73cfb01727..cf63cb0006 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -207,7 +207,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
     def visit_begin(self, schema):
         self.out = ''
 
-    def visit_enum_type(self, name, info, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, values, prefix):
         doc = self.cur_doc
         if self.out:
             self.out += '\n'
@@ -216,7 +216,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
                              body=texi_entity(doc, 'Values',
                                               member_func=texi_enum_value))
 
-    def visit_object_type(self, name, info, base, members, variants):
+    def visit_object_type(self, name, info, ifcond, base, members, variants):
         doc = self.cur_doc
         if base and base.is_implicit():
             base = None
@@ -226,7 +226,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
                              name=doc.symbol,
                              body=texi_entity(doc, 'Members', base, variants))
 
-    def visit_alternate_type(self, name, info, variants):
+    def visit_alternate_type(self, name, info, ifcond, variants):
         doc = self.cur_doc
         if self.out:
             self.out += '\n'
@@ -234,7 +234,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
                              name=doc.symbol,
                              body=texi_entity(doc, 'Members'))
 
-    def visit_command(self, name, info, arg_type, ret_type,
+    def visit_command(self, name, info, ifcond, arg_type, ret_type,
                       gen, success_response, boxed):
         doc = self.cur_doc
         if self.out:
@@ -249,7 +249,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
                             name=doc.symbol,
                             body=body)
 
-    def visit_event(self, name, info, arg_type, boxed):
+    def visit_event(self, name, info, ifcond, arg_type, boxed):
         doc = self.cur_doc
         if self.out:
             self.out += '\n'
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 7fbaea19bc..fc5fd25f1b 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -56,18 +56,25 @@ alternate TestIfAlternate
     tag type
     case foo: int
     case bar: TestStruct
+    if defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)
 command TestIfCmd q_obj_TestIfCmd-arg -> None
    gen=True success_response=True boxed=False
+    if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
 enum TestIfEnum ['foo', 'bar']
+    if defined(TEST_IF_ENUM)
 event TestIfEvent q_obj_TestIfEvent-arg
    boxed=False
+    if defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)
 object TestIfStruct
     member foo: int optional=False
+    if defined(TEST_IF_STRUCT)
 object TestIfUnion
     member type: TestIfUnionKind optional=False
     tag type
     case foo: q_obj_TestStruct-wrapper
+    if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
 enum TestIfUnionKind ['foo']
+    if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
 object TestStruct
     member integer: int optional=False
     member boolean: bool optional=False
@@ -190,8 +197,10 @@ object q_obj_EVENT_D-arg
     member enum3: EnumOne optional=True
 object q_obj_TestIfCmd-arg
     member foo: TestIfStruct optional=False
+    if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
 object q_obj_TestIfEvent-arg
     member foo: TestIfStruct optional=False
+    if defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)
 object q_obj_TestStruct-wrapper
     member data: TestStruct optional=False
 object q_obj_UserDefFlatUnion2-base
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index c7724d3437..8627f978af 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -17,12 +17,13 @@ import sys
 
 
 class QAPISchemaTestVisitor(QAPISchemaVisitor):
-    def visit_enum_type(self, name, info, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, values, prefix):
         print 'enum %s %s' % (name, values)
         if prefix:
             print '    prefix %s' % prefix
+        self._print_if(ifcond)
 
-    def visit_object_type(self, name, info, base, members, variants):
+    def visit_object_type(self, name, info, ifcond, base, members, variants):
         print 'object %s' % name
         if base:
             print '    base %s' % base.name
@@ -30,21 +31,25 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
             print '    member %s: %s optional=%s' % \
                 (m.name, m.type.name, m.optional)
         self._print_variants(variants)
+        self._print_if(ifcond)
 
-    def visit_alternate_type(self, name, info, variants):
+    def visit_alternate_type(self, name, info, ifcond, variants):
         print 'alternate %s' % name
         self._print_variants(variants)
+        self._print_if(ifcond)
 
-    def visit_command(self, name, info, arg_type, ret_type,
+    def visit_command(self, name, info, ifcond, arg_type, ret_type,
                       gen, success_response, boxed):
         print 'command %s %s -> %s' % \
             (name, arg_type and arg_type.name, ret_type and ret_type.name)
         print '   gen=%s success_response=%s boxed=%s' % \
             (gen, success_response, boxed)
+        self._print_if(ifcond)
 
-    def visit_event(self, name, info, arg_type, boxed):
+    def visit_event(self, name, info, ifcond, arg_type, boxed):
         print 'event %s %s' % (name, arg_type and arg_type.name)
         print '   boxed=%s' % boxed
+        self._print_if(ifcond)
 
     @staticmethod
     def _print_variants(variants):
@@ -53,6 +58,12 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
             for v in variants.variants:
                 print '    case %s: %s' % (v.name, v.type.name)
 
+    @staticmethod
+    def _print_if(ifcond):
+        if ifcond:
+            print '    if %s' % ifcond
+
+
 schema = QAPISchema(sys.argv[1])
 schema.visit(QAPISchemaTestVisitor())
 
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 08/50] qapi: mcgen() shouldn't indent # lines
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (6 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 07/50] qapi: add 'ifcond' to visitor methods Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-06 17:41   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 09/50] qapi: add #if/#endif helpers Marc-André Lureau
                   ` (43 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Skip preprocessor lines when adding indentation, since that would
likely result in invalid code.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index f2b5a7e131..2a8e60e975 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1862,7 +1862,7 @@ def cgen(code, **kwds):
     if indent_level:
         indent = genindent(indent_level)
         # re.subn() lacks flags support before Python 2.7, use re.compile()
-        raw = re.subn(re.compile(r'^.', re.MULTILINE),
+        raw = re.subn(re.compile(r'^[^#\n].', re.MULTILINE),
                       indent + r'\g<0>', raw)
         raw = raw[0]
     return re.sub(re.escape(eatspace) + r' *', '', raw)
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 09/50] qapi: add #if/#endif helpers
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (7 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 08/50] qapi: mcgen() shouldn't indent # lines Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-07 14:10   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 10/50] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Marc-André Lureau
                   ` (42 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Add helpers to wrap generated code with #if/#endif lines.

Add a function decorator that will be used to wrap visitor methods.
The decorator will check if code was generated before adding #if/#endif
lines. Used in the following patches.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 2a8e60e975..94b735d8d6 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1897,6 +1897,61 @@ def guardend(name):
                  name=guardname(name))
 
 
+def gen_if(ifcond):
+    if not ifcond:
+        return ''
+    if isinstance(ifcond, str):
+        ifcond = [ifcond]
+    ret = ''
+    for ifc in ifcond:
+        ret += mcgen('''
+#if %(cond)s
+''', cond=ifc)
+    return ret
+
+
+def gen_endif(ifcond):
+    if not ifcond:
+        return ''
+    if isinstance(ifcond, str):
+        ifcond = [ifcond]
+    ret = ''
+    for ifc in reversed(ifcond):
+        ret += mcgen('''
+#endif /* %(cond)s */
+''', cond=ifc)
+    return ret
+
+
+# Wrap a method to add #if / #endif to generated code, only if some
+# code was generated. The method must have an 'ifcond' argument.
+# self must have 'if_members' listing the attributes to wrap.
+def ifcond_decorator(func):
+
+    def func_wrapper(self, *args, **kwargs):
+        import inspect
+        idx = inspect.getargspec(func).args.index('ifcond')
+        ifcond = args[idx - 1]
+        save = {}
+        for mem in self.if_members:
+            save[mem] = getattr(self, mem)
+        func(self, *args, **kwargs)
+        for mem, val in save.items():
+            newval = getattr(self, mem)
+            if newval != val:
+                assert newval.startswith(val)
+                newval = newval[len(val):]
+                if newval[0] == '\n':
+                    val += '\n'
+                    newval = newval[1:]
+                val += gen_if(ifcond)
+                val += newval
+                val += gen_endif(ifcond)
+            setattr(self, mem, val)
+
+    return func_wrapper
+
+
 def gen_enum_lookup(name, values, prefix=None):
     ret = mcgen('''
 
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 10/50] qapi-introspect: modify to_qlit() to append ', ' on level > 0
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (8 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 09/50] qapi: add #if/#endif helpers Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-07 14:47   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 11/50] qapi-introspect: modify to_qlit() to generate #if code Marc-André Lureau
                   ` (41 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

The following patch is going to break list entries with #if/#endif, so
they should have the trailing ',' as suffix.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-introspect.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 56c1f9d548..b1d08ec97b 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -29,7 +29,7 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
                 for elt in obj]
         elts.append(indent(level + 1) + "{}")
         ret += 'QLIT_QLIST(((QLitObject[]) {\n'
-        ret += ',\n'.join(elts) + '\n'
+        ret += '\n'.join(elts) + '\n'
         ret += indent(level) + '}))'
     elif isinstance(obj, dict):
         elts = []
@@ -42,6 +42,8 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
         ret += indent(level) + '}))'
     else:
         assert False                # not implemented
+    if level > 0:
+        ret += ','
     return ret
 
 
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 11/50] qapi-introspect: modify to_qlit() to generate #if code
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (9 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 10/50] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-07 14:50   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 12/50] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
                   ` (40 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

The generator now accepts (obj, condition) tuples to wrap generated
QLit objects for 'obj' with #if/#endif conditions.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-introspect.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index b1d08ec97b..dc70954e8a 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -17,6 +17,13 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
     def indent(level):
         return level * 4 * ' '
 
+    if isinstance(obj, tuple):
+        ifobj, ifcond = obj
+        ret = gen_if(ifcond)
+        ret += to_qlit(ifobj, level)
+        ret += '\n' + gen_endif(ifcond)
+        return ret
+
     ret = ''
     if not suppress_first_indent:
         ret += indent(level)
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 12/50] qapi-introspect: add preprocessor conditions to generated QLit
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (10 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 11/50] qapi-introspect: modify to_qlit() to generate #if code Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-07 15:41   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 13/50] qapi-commands: add #if conditions to commands Marc-André Lureau
                   ` (39 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Add 'ifcond' condition to top-level QLit objects.

to_qlit() handles the (obj, ifcond) tuples in previous patch.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-introspect.py | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index dc70954e8a..69d9afc792 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -128,12 +128,12 @@ const QLitObject %(c_name)s = %(c_string)s;
             return '[' + self._use_type(typ.element_type) + ']'
         return self._name(typ.name)
 
-    def _gen_qlit(self, name, mtype, obj):
+    def _gen_qlit(self, name, mtype, obj, ifcond):
         if mtype not in ('command', 'event', 'builtin', 'array'):
             name = self._name(name)
         obj['name'] = name
         obj['meta-type'] = mtype
-        self._qlits.append(obj)
+        self._qlits.append((obj, ifcond))
 
     def _gen_member(self, member):
         ret = {'name': member.name, 'type': self._use_type(member.type)}
@@ -149,26 +149,27 @@ const QLitObject %(c_name)s = %(c_string)s;
         return {'case': variant.name, 'type': self._use_type(variant.type)}
 
     def visit_builtin_type(self, name, info, json_type):
-        self._gen_qlit(name, 'builtin', {'json-type': json_type})
+        self._gen_qlit(name, 'builtin', {'json-type': json_type}, None)
 
     def visit_enum_type(self, name, info, ifcond, values, prefix):
-        self._gen_qlit(name, 'enum', {'values': values})
+        self._gen_qlit(name, 'enum', {'values': values}, ifcond)
 
     def visit_array_type(self, name, info, ifcond, element_type):
         element = self._use_type(element_type)
-        self._gen_qlit('[' + element + ']', 'array', {'element-type': element})
+        self._gen_qlit('[' + element + ']', 'array', {'element-type': element},
+                       ifcond)
 
     def visit_object_type_flat(self, name, info, ifcond, members, variants):
         obj = {'members': [self._gen_member(m) for m in members]}
         if variants:
             obj.update(self._gen_variants(variants.tag_member.name,
                                           variants.variants))
-        self._gen_qlit(name, 'object', obj)
+        self._gen_qlit(name, 'object', obj, ifcond)
 
     def visit_alternate_type(self, name, info, ifcond, variants):
         self._gen_qlit(name, 'alternate',
                        {'members': [{'type': self._use_type(m.type)}
-                                    for m in variants.variants]})
+                                    for m in variants.variants]}, ifcond)
 
     def visit_command(self, name, info, ifcond, arg_type, ret_type,
                       gen, success_response, boxed):
@@ -176,11 +177,12 @@ const QLitObject %(c_name)s = %(c_string)s;
         ret_type = ret_type or self._schema.the_empty_object_type
         self._gen_qlit(name, 'command',
                        {'arg-type': self._use_type(arg_type),
-                        'ret-type': self._use_type(ret_type)})
+                        'ret-type': self._use_type(ret_type)}, ifcond)
 
     def visit_event(self, name, info, ifcond, arg_type, boxed):
         arg_type = arg_type or self._schema.the_empty_object_type
-        self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)})
+        self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)},
+                       ifcond)
 
 # Debugging aid: unmask QAPI schema's type names
 # We normally mask them, because they're not QMP wire ABI
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 13/50] qapi-commands: add #if conditions to commands
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (11 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 12/50] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 14/50] qapi-event: add #if conditions to events Marc-André Lureau
                   ` (38 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Wrap generated code with #if/#endif using the ifcond_decorator.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-commands.py  | 2 ++
 tests/test-qmp-commands.c | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 669aef1eb7..8af8d913b9 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -228,6 +228,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self.defn = None
         self._regy = None
         self._visited_ret_types = None
+        self.if_members = ['decl', 'defn', '_regy']
 
     def visit_begin(self, schema):
         self.decl = ''
@@ -240,6 +241,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self._regy = None
         self._visited_ret_types = None
 
+    @ifcond_decorator
     def visit_command(self, name, info, ifcond, arg_type, ret_type,
                       gen, success_response, boxed):
         if not gen:
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 9b9a7ffee7..ad7b6e4e1d 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -10,11 +10,11 @@
 
 static QmpCommandList qmp_commands;
 
-/* #if defined(TEST_IF_CMD) */
+#if defined(TEST_IF_CMD)
 void qmp_TestIfCmd(TestIfStruct *foo, Error **errp)
 {
 }
-/* #endif */
+#endif
 
 void qmp_user_def_cmd(Error **errp)
 {
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 14/50] qapi-event: add #if conditions to events
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (12 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 13/50] qapi-commands: add #if conditions to commands Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 15/50] qapi-types: refactor variants handling Marc-André Lureau
                   ` (37 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Wrap generated code with #if/#endif using the ifcond_decorator.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-event.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index dda496e824..bef301dfe9 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -152,6 +152,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
         self.decl = None
         self.defn = None
         self._event_names = None
+        self.if_members = ['decl', 'defn']
 
     def visit_begin(self, schema):
         self.decl = ''
@@ -163,6 +164,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
         self.defn += gen_enum_lookup(event_enum_name, self._event_names)
         self._event_names = None
 
+    @ifcond_decorator
     def visit_event(self, name, info, ifcond, arg_type, boxed):
         self.decl += gen_event_send_decl(name, arg_type, boxed)
         self.defn += gen_event_send(name, arg_type, boxed)
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 15/50] qapi-types: refactor variants handling
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (13 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 14/50] qapi-event: add #if conditions to events Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-07 15:57   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 16/50] qapi-types: add #if conditions to types & visitors Marc-André Lureau
                   ` (36 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Generate variants objects outside gen_object(). This will allow to
easily wrap gen_object() with ifcond_decorator in the following patch.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-types.py | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 915786c463..2b3588267b 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -53,23 +53,27 @@ def gen_struct_members(members):
     return ret
 
 
-def gen_object(name, base, members, variants):
-    if name in objects_seen:
-        return ''
-    objects_seen.add(name)
-
+def gen_variants_objects(variants):
     ret = ''
     if variants:
         for v in variants.variants:
             if isinstance(v.type, QAPISchemaObjectType):
+                ret += gen_variants_objects(v.type.variants)
                 ret += gen_object(v.type.name, v.type.base,
                                   v.type.local_members, v.type.variants)
+    return ret
 
-    ret += mcgen('''
+
+def gen_object(name, base, members, variants):
+    if name in objects_seen:
+        return ''
+    objects_seen.add(name)
+
+    ret = mcgen('''
 
 struct %(c_name)s {
 ''',
-                 c_name=c_name(name))
+                c_name=c_name(name))
 
     if base:
         if not base.is_implicit():
@@ -218,11 +222,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             self.decl += gen_array(name, element_type)
             self._gen_type_cleanup(name)
 
-    def visit_object_type(self, name, info, ifcond, base, members, variants):
-        # Nothing to do for the special empty builtin
-        if name == 'q_empty':
-            return
-        self._fwdecl += gen_fwd_object_or_array(name)
+    def _gen_object(self, name, info, ifcond, base, members, variants):
         self.decl += gen_object(name, base, members, variants)
         if base and not base.is_implicit():
             self.decl += gen_upcast(name, base)
@@ -232,10 +232,19 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             # implicit types won't be directly allocated/freed
             self._gen_type_cleanup(name)
 
+    def visit_object_type(self, name, info, ifcond, base, members, variants):
+        # Nothing to do for the special empty builtin
+        if name == 'q_empty':
+            return
+        self._fwdecl += gen_fwd_object_or_array(name)
+        self.decl += gen_variants_objects(variants)
+        self._gen_object(name, info, None, base, members, variants)
+
     def visit_alternate_type(self, name, info, ifcond, variants):
         self._fwdecl += gen_fwd_object_or_array(name)
-        self.decl += gen_object(name, None, [variants.tag_member], variants)
-        self._gen_type_cleanup(name)
+        self.decl += gen_variants_objects(variants)
+        self._gen_object(name, info, None, None,
+                         [variants.tag_member], variants)
 
 # If you link code generated from multiple schemata, you want only one
 # instance of the code for built-in types.  Generate it only when
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 16/50] qapi-types: add #if conditions to types & visitors
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (14 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 15/50] qapi-types: refactor variants handling Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely Marc-André Lureau
                   ` (35 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Types & visitors are coupled and must be handled together to avoid
temporary build regression.

Wrap generated types/visitor code with #if/#endif using the
ifcond_decorator & helpers.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-types.py | 18 ++++++++++++++----
 scripts/qapi-visit.py |  5 +++++
 2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 2b3588267b..789e89ff59 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -59,8 +59,10 @@ def gen_variants_objects(variants):
         for v in variants.variants:
             if isinstance(v.type, QAPISchemaObjectType):
                 ret += gen_variants_objects(v.type.variants)
+                ret += gen_if(v.type.ifcond)
                 ret += gen_object(v.type.name, v.type.base,
                                   v.type.local_members, v.type.variants)
+                ret += gen_endif(v.type.ifcond)
     return ret
 
 
@@ -175,6 +177,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
         self.defn = None
         self._fwdecl = None
         self._btin = None
+        self.if_members = ['decl', 'defn', '_fwdecl', '_btin']
 
     def visit_begin(self, schema):
         # gen_object() is recursive, ensure it doesn't visit the empty type
@@ -199,6 +202,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
         self.decl += gen_type_cleanup_decl(name)
         self.defn += gen_type_cleanup(name)
 
+    @ifcond_decorator
     def visit_enum_type(self, name, info, ifcond, values, prefix):
         # Special case for our lone builtin enum type
         # TODO use something cleaner than existence of info
@@ -210,6 +214,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             self._fwdecl += gen_enum(name, values, prefix)
             self.defn += gen_enum_lookup(name, values, prefix)
 
+    @ifcond_decorator
     def visit_array_type(self, name, info, ifcond, element_type):
         if isinstance(element_type, QAPISchemaBuiltinType):
             self._btin += gen_fwd_object_or_array(name)
@@ -222,6 +227,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             self.decl += gen_array(name, element_type)
             self._gen_type_cleanup(name)
 
+    @ifcond_decorator
     def _gen_object(self, name, info, ifcond, base, members, variants):
         self.decl += gen_object(name, base, members, variants)
         if base and not base.is_implicit():
@@ -232,18 +238,22 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
             # implicit types won't be directly allocated/freed
             self._gen_type_cleanup(name)
 
+    @ifcond_decorator
+    def _gen_fwd_object_or_array(self, name, ifcond):
+        self._fwdecl += gen_fwd_object_or_array(name)
+
     def visit_object_type(self, name, info, ifcond, base, members, variants):
         # Nothing to do for the special empty builtin
         if name == 'q_empty':
             return
-        self._fwdecl += gen_fwd_object_or_array(name)
+        self._gen_fwd_object_or_array(name, ifcond)
         self.decl += gen_variants_objects(variants)
-        self._gen_object(name, info, None, base, members, variants)
+        self._gen_object(name, info, ifcond, base, members, variants)
 
     def visit_alternate_type(self, name, info, ifcond, variants):
-        self._fwdecl += gen_fwd_object_or_array(name)
+        self._gen_fwd_object_or_array(name, ifcond)
         self.decl += gen_variants_objects(variants)
-        self._gen_object(name, info, None, None,
+        self._gen_object(name, info, ifcond, None,
                          [variants.tag_member], variants)
 
 # If you link code generated from multiple schemata, you want only one
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index aceea2a9f9..4b0e005437 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -267,6 +267,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
         self.decl = None
         self.defn = None
         self._btin = None
+        self.if_members = ['decl', 'defn', '_btin']
 
     def visit_begin(self, schema):
         self.decl = ''
@@ -282,6 +283,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
         self.decl = self._btin + self.decl
         self._btin = None
 
+    @ifcond_decorator
     def visit_enum_type(self, name, info, ifcond, values, prefix):
         # Special case for our lone builtin enum type
         # TODO use something cleaner than existence of info
@@ -293,6 +295,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
             self.decl += gen_visit_decl(name, scalar=True)
             self.defn += gen_visit_enum(name)
 
+    @ifcond_decorator
     def visit_array_type(self, name, info, ifcond, element_type):
         decl = gen_visit_decl(name)
         defn = gen_visit_list(name, element_type)
@@ -304,6 +307,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
             self.decl += decl
             self.defn += defn
 
+    @ifcond_decorator
     def visit_object_type(self, name, info, ifcond, base, members, variants):
         # Nothing to do for the special empty builtin
         if name == 'q_empty':
@@ -317,6 +321,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
             self.decl += gen_visit_decl(name)
             self.defn += gen_visit_object(name, base, members, variants)
 
+    @ifcond_decorator
     def visit_alternate_type(self, name, info, ifcond, variants):
         self.decl += gen_visit_decl(name)
         self.defn += gen_visit_alternate(name, variants)
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (15 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 16/50] qapi-types: add #if conditions to types & visitors Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-07 16:23   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 18/50] qapi: change enum visitor to take QAPISchemaMember Marc-André Lureau
                   ` (34 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

The C standard has the initial value at 0 and the subsequent values
incremented by 1. No need to set this explicitely.

This will prevent from artificial "gaps" when compiling out some enum
values and having unnecessarily large MAX values & enums arrays.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 94b735d8d6..074ee221a1 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1985,14 +1985,11 @@ typedef enum %(c_name)s {
 ''',
                 c_name=c_name(name))
 
-    i = 0
     for value in enum_values:
         ret += mcgen('''
-    %(c_enum)s = %(i)d,
+    %(c_enum)s,
 ''',
-                     c_enum=c_enum_const(name, value, prefix),
-                     i=i)
-        i += 1
+                     c_enum=c_enum_const(name, value, prefix))
 
     ret += mcgen('''
 } %(c_name)s;
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 18/50] qapi: change enum visitor to take QAPISchemaMember
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (16 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-07 17:34   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 19/50] qapi: add 'if' to enum members Marc-André Lureau
                   ` (33 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

This will allow to add and access more properties associated with enum
values/members, like the associated 'if' condition. We may want to
have a specialized type QAPISchemaEnumMember, for now this will do.

Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                          | 40 +++++++++++++-------------
 scripts/qapi-event.py                    |  2 +-
 scripts/qapi-introspect.py               |  5 ++--
 scripts/qapi-types.py                    | 10 +++----
 scripts/qapi-visit.py                    |  2 +-
 scripts/qapi2texi.py                     |  2 +-
 tests/qapi-schema/comments.out           | 14 +++++++--
 tests/qapi-schema/doc-good.out           | 17 +++++++++--
 tests/qapi-schema/empty.out              |  9 +++++-
 tests/qapi-schema/event-case.out         |  9 +++++-
 tests/qapi-schema/ident-with-escape.out  |  9 +++++-
 tests/qapi-schema/include-relpath.out    | 14 +++++++--
 tests/qapi-schema/include-repetition.out | 14 +++++++--
 tests/qapi-schema/include-simple.out     | 14 +++++++--
 tests/qapi-schema/indented-expr.out      |  9 +++++-
 tests/qapi-schema/qapi-schema-test.out   | 49 ++++++++++++++++++++++++++------
 tests/qapi-schema/test-qapi.py           | 17 +++++++----
 17 files changed, 177 insertions(+), 59 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 074ee221a1..386a577a59 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1039,7 +1039,7 @@ class QAPISchemaVisitor(object):
     def visit_builtin_type(self, name, info, json_type):
         pass
 
-    def visit_enum_type(self, name, info, ifcond, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, members, prefix):
         pass
 
     def visit_array_type(self, name, info, ifcond, element_type):
@@ -1127,21 +1127,21 @@ class QAPISchemaBuiltinType(QAPISchemaType):
 
 
 class QAPISchemaEnumType(QAPISchemaType):
-    def __init__(self, name, info, doc, ifcond, values, prefix):
+    def __init__(self, name, info, doc, ifcond, members, prefix):
         QAPISchemaType.__init__(self, name, info, doc, ifcond)
-        for v in values:
-            assert isinstance(v, QAPISchemaMember)
-            v.set_owner(name)
+        for m in members:
+            assert isinstance(m, QAPISchemaMember)
+            m.set_owner(name)
         assert prefix is None or isinstance(prefix, str)
-        self.values = values
+        self.members = members
         self.prefix = prefix
 
     def check(self, schema):
         seen = {}
-        for v in self.values:
-            v.check_clash(self.info, seen)
+        for m in self.members:
+            m.check_clash(self.info, seen)
             if self.doc:
-                self.doc.connect_member(v)
+                self.doc.connect_member(m)
 
     def is_implicit(self):
         # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
@@ -1151,14 +1151,14 @@ class QAPISchemaEnumType(QAPISchemaType):
         return c_name(self.name)
 
     def member_names(self):
-        return [v.name for v in self.values]
+        return [m.name for m in self.members]
 
     def json_type(self):
         return 'string'
 
     def visit(self, visitor):
         visitor.visit_enum_type(self.name, self.info, self.ifcond,
-                                self.member_names(), self.prefix)
+                                self.members, self.prefix)
 
 
 class QAPISchemaArrayType(QAPISchemaType):
@@ -1952,19 +1952,19 @@ def ifcond_decorator(func):
     return func_wrapper
 
 
-def gen_enum_lookup(name, values, prefix=None):
+def gen_enum_lookup(name, members, prefix=None):
     ret = mcgen('''
 
 const QEnumLookup %(c_name)s_lookup = {
     .array = (const char *const[]) {
 ''',
                 c_name=c_name(name))
-    for value in values:
-        index = c_enum_const(name, value, prefix)
+    for m in members:
+        index = c_enum_const(name, m.name, prefix)
         ret += mcgen('''
-        [%(index)s] = "%(value)s",
+        [%(index)s] = "%(name)s",
 ''',
-                     index=index, value=value)
+                     index=index, name=m.name)
 
     ret += mcgen('''
     },
@@ -1975,9 +1975,9 @@ const QEnumLookup %(c_name)s_lookup = {
     return ret
 
 
-def gen_enum(name, values, prefix=None):
+def gen_enum(name, members, prefix=None):
     # append automatically generated _MAX value
-    enum_values = values + ['_MAX']
+    enum_members = members + [QAPISchemaMember('_MAX')]
 
     ret = mcgen('''
 
@@ -1985,11 +1985,11 @@ typedef enum %(c_name)s {
 ''',
                 c_name=c_name(name))
 
-    for value in enum_values:
+    for m in enum_members:
         ret += mcgen('''
     %(c_enum)s,
 ''',
-                     c_enum=c_enum_const(name, value, prefix))
+                     c_enum=c_enum_const(name, m.name, prefix))
 
     ret += mcgen('''
 } %(c_name)s;
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index bef301dfe9..38f4264817 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -168,7 +168,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
     def visit_event(self, name, info, ifcond, arg_type, boxed):
         self.decl += gen_event_send_decl(name, arg_type, boxed)
         self.defn += gen_event_send(name, arg_type, boxed)
-        self._event_names.append(name)
+        self._event_names.append(QAPISchemaMember(name))
 
 
 (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 69d9afc792..32a58cf879 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -151,8 +151,9 @@ const QLitObject %(c_name)s = %(c_string)s;
     def visit_builtin_type(self, name, info, json_type):
         self._gen_qlit(name, 'builtin', {'json-type': json_type}, None)
 
-    def visit_enum_type(self, name, info, ifcond, values, prefix):
-        self._gen_qlit(name, 'enum', {'values': values}, ifcond)
+    def visit_enum_type(self, name, info, ifcond, members, prefix):
+        self._gen_qlit(name, 'enum',
+                       {'values': [m.name for m in members]}, ifcond)
 
     def visit_array_type(self, name, info, ifcond, element_type):
         element = self._use_type(element_type)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 789e89ff59..75c1823e44 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -203,16 +203,16 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
         self.defn += gen_type_cleanup(name)
 
     @ifcond_decorator
-    def visit_enum_type(self, name, info, ifcond, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, members, prefix):
         # Special case for our lone builtin enum type
         # TODO use something cleaner than existence of info
         if not info:
-            self._btin += gen_enum(name, values, prefix)
+            self._btin += gen_enum(name, members, prefix)
             if do_builtins:
-                self.defn += gen_enum_lookup(name, values, prefix)
+                self.defn += gen_enum_lookup(name, members, prefix)
         else:
-            self._fwdecl += gen_enum(name, values, prefix)
-            self.defn += gen_enum_lookup(name, values, prefix)
+            self._fwdecl += gen_enum(name, members, prefix)
+            self.defn += gen_enum_lookup(name, members, prefix)
 
     @ifcond_decorator
     def visit_array_type(self, name, info, ifcond, element_type):
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 4b0e005437..7e816ae98e 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -284,7 +284,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
         self._btin = None
 
     @ifcond_decorator
-    def visit_enum_type(self, name, info, ifcond, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, members, prefix):
         # Special case for our lone builtin enum type
         # TODO use something cleaner than existence of info
         if not info:
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index cf63cb0006..e72e7cfe0b 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -207,7 +207,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
     def visit_begin(self, schema):
         self.out = ''
 
-    def visit_enum_type(self, name, info, ifcond, values, prefix):
+    def visit_enum_type(self, name, info, ifcond, members, prefix):
         doc = self.cur_doc
         if self.out:
             self.out += '\n'
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 17e652535c..17b493ec24 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,4 +1,14 @@
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
-enum Status ['good', 'bad', 'ugly']
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
+enum Status
+    member good:
+    member bad:
+    member ugly:
 object q_empty
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 63ca25a8b9..0de06ce345 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -1,19 +1,30 @@
 object Base
     member base1: Enum optional=False
-enum Enum ['one', 'two']
+enum Enum
+    member one:
+    member two:
 object Object
     base Base
     tag base1
     case one: Variant1
     case two: Variant2
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
 object SugaredUnion
     member type: SugaredUnionKind optional=False
     tag type
     case one: q_obj_Variant1-wrapper
     case two: q_obj_Variant2-wrapper
-enum SugaredUnionKind ['one', 'two']
+enum SugaredUnionKind
+    member one:
+    member two:
 object Variant1
     member var1: str optional=False
 object Variant2
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index 40b886ddae..9859251087 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -1,3 +1,10 @@
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
 object q_empty
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index 313c0fe7be..4dccc8f61e 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -1,5 +1,12 @@
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
 event oops None
    boxed=False
 object q_empty
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index b5637cb2e0..4d17bc6783 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -1,5 +1,12 @@
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
 command fooA q_obj_fooA-arg -> None
    gen=True success_response=True boxed=False
 object q_empty
diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out
index 17e652535c..17b493ec24 100644
--- a/tests/qapi-schema/include-relpath.out
+++ b/tests/qapi-schema/include-relpath.out
@@ -1,4 +1,14 @@
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
-enum Status ['good', 'bad', 'ugly']
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
+enum Status
+    member good:
+    member bad:
+    member ugly:
 object q_empty
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 17e652535c..17b493ec24 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1,4 +1,14 @@
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
-enum Status ['good', 'bad', 'ugly']
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
+enum Status
+    member good:
+    member bad:
+    member ugly:
 object q_empty
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 17e652535c..17b493ec24 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1,4 +1,14 @@
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
-enum Status ['good', 'bad', 'ugly']
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
+enum Status
+    member good:
+    member bad:
+    member ugly:
 object q_empty
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 586795f44d..8bdc016e55 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,5 +1,12 @@
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
     prefix QTYPE
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
 command eins None -> None
    gen=True success_response=True boxed=False
 object q_empty
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index fc5fd25f1b..9a7cafc269 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -33,7 +33,10 @@ event EVENT_F UserDefAlternate
 object Empty1
 object Empty2
     base Empty1
-enum EnumOne ['value1', 'value2', 'value3']
+enum EnumOne
+    member value1:
+    member value2:
+    member value3:
 object EventStructOne
     member struct1: UserDefOne optional=False
     member string: str optional=False
@@ -42,16 +45,25 @@ object ForceArrays
     member unused1: UserDefOneList optional=False
     member unused2: UserDefTwoList optional=False
     member unused3: TestStructList optional=False
-enum MyEnum []
+enum MyEnum
 object NestedEnumsOne
     member enum1: EnumOne optional=False
     member enum2: EnumOne optional=True
     member enum3: EnumOne optional=False
     member enum4: EnumOne optional=True
-enum QEnumTwo ['value1', 'value2']
+enum QEnumTwo
     prefix QENUM_TWO
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+    member value1:
+    member value2:
+enum QType
     prefix QTYPE
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
 alternate TestIfAlternate
     tag type
     case foo: int
@@ -60,7 +72,9 @@ alternate TestIfAlternate
 command TestIfCmd q_obj_TestIfCmd-arg -> None
    gen=True success_response=True boxed=False
     if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
-enum TestIfEnum ['foo', 'bar']
+enum TestIfEnum
+    member foo:
+    member bar:
     if defined(TEST_IF_ENUM)
 event TestIfEvent q_obj_TestIfEvent-arg
    boxed=False
@@ -73,7 +87,8 @@ object TestIfUnion
     tag type
     case foo: q_obj_TestStruct-wrapper
     if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
-enum TestIfUnionKind ['foo']
+enum TestIfUnionKind
+    member foo:
     if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
 object TestStruct
     member integer: int optional=False
@@ -122,7 +137,21 @@ object UserDefNativeListUnion
     case string: q_obj_strList-wrapper
     case sizes: q_obj_sizeList-wrapper
     case any: q_obj_anyList-wrapper
-enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any']
+enum UserDefNativeListUnionKind
+    member integer:
+    member s8:
+    member s16:
+    member s32:
+    member s64:
+    member u8:
+    member u16:
+    member u32:
+    member u64:
+    member number:
+    member boolean:
+    member string:
+    member sizes:
+    member any:
 object UserDefOne
     base UserDefZero
     member string: str optional=False
@@ -159,7 +188,8 @@ alternate __org.qemu_x-Alt
     case b: __org.qemu_x-Base
 object __org.qemu_x-Base
     member __org.qemu_x-member1: __org.qemu_x-Enum optional=False
-enum __org.qemu_x-Enum ['__org.qemu_x-value']
+enum __org.qemu_x-Enum
+    member __org.qemu_x-value:
 object __org.qemu_x-Struct
     base __org.qemu_x-Base
     member __org.qemu_x-member2: str optional=False
@@ -170,7 +200,8 @@ object __org.qemu_x-Union1
     member type: __org.qemu_x-Union1Kind optional=False
     tag type
     case __org.qemu_x-branch: q_obj_str-wrapper
-enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch']
+enum __org.qemu_x-Union1Kind
+    member __org.qemu_x-branch:
 object __org.qemu_x-Union2
     base __org.qemu_x-Base
     tag __org.qemu_x-member1
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 8627f978af..67c6c1ecef 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -17,19 +17,18 @@ import sys
 
 
 class QAPISchemaTestVisitor(QAPISchemaVisitor):
-    def visit_enum_type(self, name, info, ifcond, values, prefix):
-        print 'enum %s %s' % (name, values)
+    def visit_enum_type(self, name, info, ifcond, members, prefix):
+        print 'enum %s' % name
         if prefix:
             print '    prefix %s' % prefix
+        self._print_members(members)
         self._print_if(ifcond)
 
     def visit_object_type(self, name, info, ifcond, base, members, variants):
         print 'object %s' % name
         if base:
             print '    base %s' % base.name
-        for m in members:
-            print '    member %s: %s optional=%s' % \
-                (m.name, m.type.name, m.optional)
+        self._print_members(members)
         self._print_variants(variants)
         self._print_if(ifcond)
 
@@ -51,6 +50,14 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         print '   boxed=%s' % boxed
         self._print_if(ifcond)
 
+    @staticmethod
+    def _print_members(members):
+        for m in members:
+            print '    member %s:' % m.name,
+            if isinstance(m, QAPISchemaObjectTypeMember):
+                print '%s optional=%s' % (m.type.name, m.optional),
+            print
+
     @staticmethod
     def _print_variants(variants):
         if variants:
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 19/50] qapi: add 'if' to enum members
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (17 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 18/50] qapi: change enum visitor to take QAPISchemaMember Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-08  8:38   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 20/50] qapi-event: add 'if' condition to generated enum Marc-André Lureau
                   ` (32 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                         | 39 ++++++++++++++++++++++++++++-----
 tests/Makefile.include                  |  1 -
 tests/qapi-schema/enum-dict-member.err  |  1 -
 tests/qapi-schema/enum-dict-member.exit |  1 -
 tests/qapi-schema/enum-dict-member.json |  2 --
 tests/qapi-schema/enum-dict-member.out  |  0
 tests/qapi-schema/qapi-schema-test.json |  5 +++--
 tests/qapi-schema/qapi-schema-test.out  |  3 ++-
 tests/qapi-schema/test-qapi.py          |  2 ++
 9 files changed, 41 insertions(+), 13 deletions(-)
 delete mode 100644 tests/qapi-schema/enum-dict-member.err
 delete mode 100644 tests/qapi-schema/enum-dict-member.exit
 delete mode 100644 tests/qapi-schema/enum-dict-member.json
 delete mode 100644 tests/qapi-schema/enum-dict-member.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 386a577a59..1535de9ce7 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -659,6 +659,14 @@ def check_if(expr, info):
             info, "'if' condition must be a string or a list of strings")
 
 
+def check_unknown_keys(info, dict, allowed_keys):
+    diff = set(dict) - allowed_keys
+    if not diff:
+        return
+    raise QAPISemError(info, "Dictionnary has unknown keys: %s (allowed: %s)" %
+        (', '.join(diff), ', '.join(allowed_keys)))
+
+
 def check_type(info, source, value, allow_array=False,
                allow_dict=False, allow_optional=False,
                allow_metas=[]):
@@ -739,6 +747,10 @@ def check_event(expr, info):
                allow_metas=meta)
 
 
+def enum_get_values(expr):
+    return [e if isinstance(e, str) else e['name'] for e in expr['data']]
+
+
 def check_union(expr, info):
     name = expr['union']
     base = expr.get('base')
@@ -798,7 +810,7 @@ def check_union(expr, info):
         # If the discriminator names an enum type, then all members
         # of 'data' must also be members of the enum type.
         if enum_define:
-            if key not in enum_define['data']:
+            if key not in enum_get_values(enum_define):
                 raise QAPISemError(info,
                                    "Discriminator value '%s' is not found in "
                                    "enum '%s'"
@@ -806,7 +818,7 @@ def check_union(expr, info):
 
     # If discriminator is user-defined, ensure all values are covered
     if enum_define:
-        for value in enum_define['data']:
+        for value in enum_get_values(enum_define):
             if value not in members.keys():
                 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
                                    % (name, value))
@@ -837,7 +849,7 @@ def check_alternate(expr, info):
         if qtype == 'QTYPE_QSTRING':
             enum_expr = enum_types.get(value)
             if enum_expr:
-                for v in enum_expr['data']:
+                for v in enum_get_values(enum_expr):
                     if v in ['on', 'off']:
                         conflicting.add('QTYPE_QBOOL')
                     if re.match(r'[-+0-9.]', v): # lazy, could be tightened
@@ -865,6 +877,14 @@ def check_enum(expr, info):
         raise QAPISemError(info,
                            "Enum '%s' requires a string for 'prefix'" % name)
     for member in members:
+        if isinstance(member, dict):
+            if 'name' not in member:
+                raise QAPISemError(info, "Dictionary member of enum '%s' must "
+                                   "have a 'name' key" % name)
+            if 'if' in member:
+                check_if(member, info)
+            check_unknown_keys(info, member, {'name', 'if'})
+            member = member['name']
         check_name(info, "Member of enum '%s'" % name, member,
                    enum_member=True)
 
@@ -1280,9 +1300,11 @@ class QAPISchemaObjectType(QAPISchemaType):
 class QAPISchemaMember(object):
     role = 'member'
 
-    def __init__(self, name):
+    def __init__(self, name, ifcond=None):
         assert isinstance(name, str)
+        assert ifcond is None or isinstance(ifcond, str)
         self.name = name
+        self.ifcond = ifcond
         self.owner = None
 
     def set_owner(self, name):
@@ -1559,7 +1581,14 @@ class QAPISchema(object):
                                             qtype_values, 'QTYPE'))
 
     def _make_enum_members(self, values):
-        return [QAPISchemaMember(v) for v in values]
+        enum = []
+        for v in values:
+            ifcond = None
+            if isinstance(v, dict):
+                ifcond = v.get('if')
+                v = v['name']
+            enum.append(QAPISchemaMember(v, ifcond))
+        return enum
 
     def _make_implicit_enum_type(self, name, info, ifcond, values):
         # See also QAPISchemaObjectTypeMember._pretty_owner()
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8dac7c9083..a9f0ddbe01 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -443,7 +443,6 @@ qapi-schema += empty.json
 qapi-schema += enum-bad-name.json
 qapi-schema += enum-bad-prefix.json
 qapi-schema += enum-clash-member.json
-qapi-schema += enum-dict-member.json
 qapi-schema += enum-int-member.json
 qapi-schema += enum-member-case.json
 qapi-schema += enum-missing-data.json
diff --git a/tests/qapi-schema/enum-dict-member.err b/tests/qapi-schema/enum-dict-member.err
deleted file mode 100644
index 8ca146ea59..0000000000
--- a/tests/qapi-schema/enum-dict-member.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum' requires a string name
diff --git a/tests/qapi-schema/enum-dict-member.exit b/tests/qapi-schema/enum-dict-member.exit
deleted file mode 100644
index d00491fd7e..0000000000
--- a/tests/qapi-schema/enum-dict-member.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/enum-dict-member.json b/tests/qapi-schema/enum-dict-member.json
deleted file mode 100644
index 79672e0f09..0000000000
--- a/tests/qapi-schema/enum-dict-member.json
+++ /dev/null
@@ -1,2 +0,0 @@
-# we reject any enum member that is not a string
-{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
diff --git a/tests/qapi-schema/enum-dict-member.out b/tests/qapi-schema/enum-dict-member.out
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index dc2c444fc1..ad2b405d83 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -194,7 +194,8 @@
 { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
   'if': 'defined(TEST_IF_STRUCT)' }
 
-{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
+{ 'enum': 'TestIfEnum', 'data':
+  [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
   'if': 'defined(TEST_IF_ENUM)' }
 
 { 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
@@ -203,7 +204,7 @@
 { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
   'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
 
-{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
+{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': 'TestIfEnum' },
   'if': 'defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)' }
 
 { 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 9a7cafc269..8a0cf1a551 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -74,7 +74,7 @@ command TestIfCmd q_obj_TestIfCmd-arg -> None
     if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
 enum TestIfEnum
     member foo:
-    member bar:
+    member bar: if=defined(TEST_IF_ENUM_BAR)
     if defined(TEST_IF_ENUM)
 event TestIfEvent q_obj_TestIfEvent-arg
    boxed=False
@@ -228,6 +228,7 @@ object q_obj_EVENT_D-arg
     member enum3: EnumOne optional=True
 object q_obj_TestIfCmd-arg
     member foo: TestIfStruct optional=False
+    member bar: TestIfEnum optional=False
     if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
 object q_obj_TestIfEvent-arg
     member foo: TestIfStruct optional=False
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 67c6c1ecef..a86c3b5ee1 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -56,6 +56,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
             print '    member %s:' % m.name,
             if isinstance(m, QAPISchemaObjectTypeMember):
                 print '%s optional=%s' % (m.type.name, m.optional),
+            if m.ifcond:
+                print 'if=%s' % m.ifcond,
             print
 
     @staticmethod
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 20/50] qapi-event: add 'if' condition to generated enum
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (18 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 19/50] qapi: add 'if' to enum members Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-08 13:58   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 21/50] qapi: add #if conditions on generated enum members Marc-André Lureau
                   ` (31 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Add condition to QAPIEvent enum members based on the event 'if'.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-event.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 38f4264817..60c6f7030d 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -168,7 +168,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
     def visit_event(self, name, info, ifcond, arg_type, boxed):
         self.decl += gen_event_send_decl(name, arg_type, boxed)
         self.defn += gen_event_send(name, arg_type, boxed)
-        self._event_names.append(QAPISchemaMember(name))
+        self._event_names.append(QAPISchemaMember(name, ifcond))
 
 
 (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 21/50] qapi: add #if conditions on generated enum members
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (19 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 20/50] qapi-event: add 'if' condition to generated enum Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 22/50] tests: add some enum members tests Marc-André Lureau
                   ` (30 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 1535de9ce7..df2a304e8f 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1989,11 +1989,13 @@ const QEnumLookup %(c_name)s_lookup = {
 ''',
                 c_name=c_name(name))
     for m in members:
+        ret += gen_if(m.ifcond)
         index = c_enum_const(name, m.name, prefix)
         ret += mcgen('''
         [%(index)s] = "%(name)s",
 ''',
                      index=index, name=m.name)
+        ret += gen_endif(m.ifcond)
 
     ret += mcgen('''
     },
@@ -2015,10 +2017,12 @@ typedef enum %(c_name)s {
                 c_name=c_name(name))
 
     for m in enum_members:
+        ret += gen_if(m.ifcond)
         ret += mcgen('''
     %(c_enum)s,
 ''',
                      c_enum=c_enum_const(name, m.name, prefix))
+        ret += gen_endif(m.ifcond)
 
     ret += mcgen('''
 } %(c_name)s;
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 22/50] tests: add some enum members tests
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (20 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 21/50] qapi: add #if conditions on generated enum members Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-08 17:58   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 23/50] qapi: add 'if' to struct members and implicit objects members Marc-André Lureau
                   ` (29 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/Makefile.include                           | 3 +++
 tests/qapi-schema/enum-dict-member-invalid.err   | 1 +
 tests/qapi-schema/enum-dict-member-invalid.exit  | 1 +
 tests/qapi-schema/enum-dict-member-invalid.json  | 2 ++
 tests/qapi-schema/enum-dict-member-invalid.out   | 0
 tests/qapi-schema/enum-dict-member-invalid2.err  | 1 +
 tests/qapi-schema/enum-dict-member-invalid2.exit | 1 +
 tests/qapi-schema/enum-dict-member-invalid2.json | 2 ++
 tests/qapi-schema/enum-dict-member-invalid2.out  | 0
 tests/qapi-schema/enum-if-invalid.err            | 1 +
 tests/qapi-schema/enum-if-invalid.exit           | 1 +
 tests/qapi-schema/enum-if-invalid.json           | 3 +++
 tests/qapi-schema/enum-if-invalid.out            | 0
 13 files changed, 16 insertions(+)
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.err
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.exit
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.json
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid.out
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.err
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.exit
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.json
 create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.out
 create mode 100644 tests/qapi-schema/enum-if-invalid.err
 create mode 100644 tests/qapi-schema/enum-if-invalid.exit
 create mode 100644 tests/qapi-schema/enum-if-invalid.json
 create mode 100644 tests/qapi-schema/enum-if-invalid.out

diff --git a/tests/Makefile.include b/tests/Makefile.include
index a9f0ddbe01..0aa532f029 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -443,6 +443,9 @@ qapi-schema += empty.json
 qapi-schema += enum-bad-name.json
 qapi-schema += enum-bad-prefix.json
 qapi-schema += enum-clash-member.json
+qapi-schema += enum-dict-member-invalid.json
+qapi-schema += enum-dict-member-invalid2.json
+qapi-schema += enum-if-invalid.json
 qapi-schema += enum-int-member.json
 qapi-schema += enum-member-case.json
 qapi-schema += enum-missing-data.json
diff --git a/tests/qapi-schema/enum-dict-member-invalid.err b/tests/qapi-schema/enum-dict-member-invalid.err
new file mode 100644
index 0000000000..d12cca0df3
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-dict-member-invalid.json:2: Dictionary member of enum 'MyEnum' must have a 'name' key
diff --git a/tests/qapi-schema/enum-dict-member-invalid.exit b/tests/qapi-schema/enum-dict-member-invalid.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-dict-member-invalid.json b/tests/qapi-schema/enum-dict-member-invalid.json
new file mode 100644
index 0000000000..9cf8406867
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid.json
@@ -0,0 +1,2 @@
+# we reject any enum member that is not a string or a dict with 'name'
+{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
diff --git a/tests/qapi-schema/enum-dict-member-invalid.out b/tests/qapi-schema/enum-dict-member-invalid.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/enum-dict-member-invalid2.err b/tests/qapi-schema/enum-dict-member-invalid2.err
new file mode 100644
index 0000000000..f7dc1a2b33
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid2.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-dict-member-invalid2.json:2: Dictionnary has unknown keys: bad-key (allowed: name, if)
diff --git a/tests/qapi-schema/enum-dict-member-invalid2.exit b/tests/qapi-schema/enum-dict-member-invalid2.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid2.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-dict-member-invalid2.json b/tests/qapi-schema/enum-dict-member-invalid2.json
new file mode 100644
index 0000000000..6664c59201
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-invalid2.json
@@ -0,0 +1,2 @@
+# we reject any enum member that is not a string or a dict with 'name'
+{ 'enum': 'MyEnum', 'data': [ { 'name': 'foo', 'bad-key': 'str' } ] }
diff --git a/tests/qapi-schema/enum-dict-member-invalid2.out b/tests/qapi-schema/enum-dict-member-invalid2.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/enum-if-invalid.err b/tests/qapi-schema/enum-if-invalid.err
new file mode 100644
index 0000000000..54c3cf887b
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-if-invalid.json:2: 'if' condition must be a string or a list of strings
diff --git a/tests/qapi-schema/enum-if-invalid.exit b/tests/qapi-schema/enum-if-invalid.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-if-invalid.json b/tests/qapi-schema/enum-if-invalid.json
new file mode 100644
index 0000000000..60bd0ef1d7
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.json
@@ -0,0 +1,3 @@
+# check invalid 'if' type
+{ 'enum': 'TestIfEnum', 'data':
+  [ 'foo', { 'name' : 'bar', 'if': { 'val': 'foo' } } ] }
diff --git a/tests/qapi-schema/enum-if-invalid.out b/tests/qapi-schema/enum-if-invalid.out
new file mode 100644
index 0000000000..e69de29bb2
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 23/50] qapi: add 'if' to struct members and implicit objects members
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (21 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 22/50] tests: add some enum members tests Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-09  8:18   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 24/50] qapi: add some struct member tests Marc-André Lureau
                   ` (28 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

check_type() will now accept a DICT { 'type': TYPENAME, 'if': ... }
instead of a TYPENAME. This is the case in various situations where
implicit object types are allowed such as commands/events arguments
and return type, base and branches of union & alternate.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                         | 20 ++++++++++++++++----
 tests/qapi-schema/qapi-schema-test.json | 12 +++++++++---
 tests/qapi-schema/qapi-schema-test.out  |  4 +++-
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index df2a304e8f..15711f96fa 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -696,7 +696,15 @@ def check_type(info, source, value, allow_array=False,
         return
 
     if not allow_dict:
-        raise QAPISemError(info, "%s should be a type name" % source)
+        if isinstance(value, dict) and 'type' in value:
+            check_type(info, source, value['type'], allow_array,
+                       allow_dict, allow_optional, allow_metas)
+            if 'if' in value:
+                check_if(value, info)
+            check_unknown_keys(info, value, {'type', 'if'})
+            return
+        else:
+            raise QAPISemError(info, "%s should be a type name" % source)
 
     if not isinstance(value, OrderedDict):
         raise QAPISemError(info,
@@ -1345,8 +1353,8 @@ class QAPISchemaMember(object):
 
 
 class QAPISchemaObjectTypeMember(QAPISchemaMember):
-    def __init__(self, name, typ, optional):
-        QAPISchemaMember.__init__(self, name)
+    def __init__(self, name, typ, optional, ifcond=None):
+        QAPISchemaMember.__init__(self, name, ifcond)
         assert isinstance(typ, str)
         assert isinstance(optional, bool)
         self._type_name = typ
@@ -1637,13 +1645,17 @@ class QAPISchema(object):
 
     def _make_member(self, name, typ, info):
         optional = False
+        ifcond = None
         if name.startswith('*'):
             name = name[1:]
             optional = True
+        if isinstance(typ, dict):
+            ifcond = typ.get('if')
+            typ = typ['type']
         if isinstance(typ, list):
             assert len(typ) == 1
             typ = self._make_array_type(typ[0], info)
-        return QAPISchemaObjectTypeMember(name, typ, optional)
+        return QAPISchemaObjectTypeMember(name, typ, optional, ifcond)
 
     def _make_members(self, data, info):
         return [self._make_member(key, value, info)
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index ad2b405d83..5cfccabb3d 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -191,7 +191,9 @@
 
 # test 'if' condition handling
 
-{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+{ 'struct': 'TestIfStruct', 'data':
+  { 'foo': 'int',
+    'bar': { 'type': 'int', 'if': 'defined(TEST_IF_STRUCT_BAR)'} },
   'if': 'defined(TEST_IF_STRUCT)' }
 
 { 'enum': 'TestIfEnum', 'data':
@@ -204,8 +206,12 @@
 { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
   'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
 
-{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': 'TestIfEnum' },
+{ 'command': 'TestIfCmd', 'data':
+  { 'foo': 'TestIfStruct',
+    'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } },
   'if': 'defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)' }
 
-{ 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
+{ 'event': 'TestIfEvent', 'data':
+  { 'foo': 'TestIfStruct',
+    'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_EVT_BAR)' } },
   'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 8a0cf1a551..6df4e49c69 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -81,6 +81,7 @@ event TestIfEvent q_obj_TestIfEvent-arg
     if defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)
 object TestIfStruct
     member foo: int optional=False
+    member bar: int optional=False if=defined(TEST_IF_STRUCT_BAR)
     if defined(TEST_IF_STRUCT)
 object TestIfUnion
     member type: TestIfUnionKind optional=False
@@ -228,10 +229,11 @@ object q_obj_EVENT_D-arg
     member enum3: EnumOne optional=True
 object q_obj_TestIfCmd-arg
     member foo: TestIfStruct optional=False
-    member bar: TestIfEnum optional=False
+    member bar: TestIfEnum optional=False if=defined(TEST_IF_CMD_BAR)
     if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
 object q_obj_TestIfEvent-arg
     member foo: TestIfStruct optional=False
+    member bar: TestIfEnum optional=False if=defined(TEST_IF_EVT_BAR)
     if defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)
 object q_obj_TestStruct-wrapper
     member data: TestStruct optional=False
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 24/50] qapi: add some struct member tests
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (22 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 23/50] qapi: add 'if' to struct members and implicit objects members Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-09  9:07   ` Markus Armbruster
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 25/50] qapi: add #if conditions to generated struct members Marc-André Lureau
                   ` (27 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/Makefile.include                    |  2 ++
 tests/qapi-schema/struct-if-invalid.err   |  1 +
 tests/qapi-schema/struct-if-invalid.exit  |  1 +
 tests/qapi-schema/struct-if-invalid.json  |  3 +++
 tests/qapi-schema/struct-if-invalid.out   |  0
 tests/qapi-schema/struct-member-type.err  |  0
 tests/qapi-schema/struct-member-type.exit |  1 +
 tests/qapi-schema/struct-member-type.json |  2 ++
 tests/qapi-schema/struct-member-type.out  | 12 ++++++++++++
 9 files changed, 22 insertions(+)
 create mode 100644 tests/qapi-schema/struct-if-invalid.err
 create mode 100644 tests/qapi-schema/struct-if-invalid.exit
 create mode 100644 tests/qapi-schema/struct-if-invalid.json
 create mode 100644 tests/qapi-schema/struct-if-invalid.out
 create mode 100644 tests/qapi-schema/struct-member-type.err
 create mode 100644 tests/qapi-schema/struct-member-type.exit
 create mode 100644 tests/qapi-schema/struct-member-type.json
 create mode 100644 tests/qapi-schema/struct-member-type.out

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 0aa532f029..44a3d8895e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -520,7 +520,9 @@ qapi-schema += returns-whitelist.json
 qapi-schema += struct-base-clash-deep.json
 qapi-schema += struct-base-clash.json
 qapi-schema += struct-data-invalid.json
+qapi-schema += struct-if-invalid.json
 qapi-schema += struct-member-invalid.json
+qapi-schema += struct-member-type.json
 qapi-schema += trailing-comma-list.json
 qapi-schema += trailing-comma-object.json
 qapi-schema += type-bypass-bad-gen.json
diff --git a/tests/qapi-schema/struct-if-invalid.err b/tests/qapi-schema/struct-if-invalid.err
new file mode 100644
index 0000000000..42245262a9
--- /dev/null
+++ b/tests/qapi-schema/struct-if-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-if-invalid.json:2: Member 'bar' of 'data' for struct 'TestIfStruct' should be a type name
diff --git a/tests/qapi-schema/struct-if-invalid.exit b/tests/qapi-schema/struct-if-invalid.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/struct-if-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/struct-if-invalid.json b/tests/qapi-schema/struct-if-invalid.json
new file mode 100644
index 0000000000..466cdb61e1
--- /dev/null
+++ b/tests/qapi-schema/struct-if-invalid.json
@@ -0,0 +1,3 @@
+# check missing 'type'
+{ 'struct': 'TestIfStruct', 'data':
+  { 'foo': 'int', 'bar': { 'if': 'defined(TEST_IF_STRUCT_BAR)' } } }
diff --git a/tests/qapi-schema/struct-if-invalid.out b/tests/qapi-schema/struct-if-invalid.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/struct-member-type.err b/tests/qapi-schema/struct-member-type.err
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/struct-member-type.exit b/tests/qapi-schema/struct-member-type.exit
new file mode 100644
index 0000000000..573541ac97
--- /dev/null
+++ b/tests/qapi-schema/struct-member-type.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/struct-member-type.json b/tests/qapi-schema/struct-member-type.json
new file mode 100644
index 0000000000..8b33027817
--- /dev/null
+++ b/tests/qapi-schema/struct-member-type.json
@@ -0,0 +1,2 @@
+# check member 'a' with 'type' key only
+{ 'struct': 'foo', 'data': { 'a': { 'type': 'str' } } }
diff --git a/tests/qapi-schema/struct-member-type.out b/tests/qapi-schema/struct-member-type.out
new file mode 100644
index 0000000000..04b969d2e3
--- /dev/null
+++ b/tests/qapi-schema/struct-member-type.out
@@ -0,0 +1,12 @@
+enum QType
+    prefix QTYPE
+    member none:
+    member qnull:
+    member qnum:
+    member qstring:
+    member qdict:
+    member qlist:
+    member qbool:
+object foo
+    member a: str optional=False
+object q_empty
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 25/50] qapi: add #if conditions to generated struct members
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (23 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 24/50] qapi: add some struct member tests Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 26/50] qapi: add 'if' on union variants Marc-André Lureau
                   ` (26 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-introspect.py | 2 ++
 scripts/qapi-types.py      | 2 ++
 scripts/qapi-visit.py      | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 32a58cf879..0e43e470bb 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -139,6 +139,8 @@ const QLitObject %(c_name)s = %(c_string)s;
         ret = {'name': member.name, 'type': self._use_type(member.type)}
         if member.optional:
             ret['default'] = None
+        if member.ifcond:
+            ret = (ret, member.ifcond)
         return ret
 
     def _gen_variants(self, tag_name, variants):
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 75c1823e44..7e6df21f53 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -41,6 +41,7 @@ struct %(c_name)s {
 def gen_struct_members(members):
     ret = ''
     for memb in members:
+        ret += gen_if(memb.ifcond)
         if memb.optional:
             ret += mcgen('''
     bool has_%(c_name)s;
@@ -50,6 +51,7 @@ def gen_struct_members(members):
     %(c_type)s %(c_name)s;
 ''',
                      c_type=memb.type.c_type(), c_name=c_name(memb.name))
+        ret += gen_endif(memb.ifcond)
     return ret
 
 
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 7e816ae98e..6a3a52e39d 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -53,6 +53,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
                      c_type=base.c_name())
 
     for memb in members:
+        ret += gen_if(memb.ifcond)
         if memb.optional:
             ret += mcgen('''
     if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
@@ -72,6 +73,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
             ret += mcgen('''
     }
 ''')
+        ret += gen_endif(memb.ifcond)
 
     if variants:
         ret += mcgen('''
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 26/50] qapi: add 'if' on union variants
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (24 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 25/50] qapi: add #if conditions to generated struct members Marc-André Lureau
@ 2017-09-11 11:05 ` Marc-André Lureau
  2017-12-11 10:36   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 27/50] qapi: add #if conditions to generated variants Marc-André Lureau
                   ` (25 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:05 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                         | 15 ++++++++++-----
 tests/qapi-schema/qapi-schema-test.json |  7 ++++++-
 tests/qapi-schema/qapi-schema-test.out  |  8 ++++++++
 tests/qapi-schema/test-qapi.py          |  5 ++++-
 4 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 15711f96fa..2f14edfa1f 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1412,8 +1412,8 @@ class QAPISchemaObjectTypeVariants(object):
 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
     role = 'branch'
 
-    def __init__(self, name, typ):
-        QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
+    def __init__(self, name, typ, ifcond=None):
+        QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond)
 
 
 class QAPISchemaAlternateType(QAPISchemaType):
@@ -1674,13 +1674,18 @@ class QAPISchema(object):
         return QAPISchemaObjectTypeVariant(case, typ)
 
     def _make_simple_variant(self, case, typ, info):
+        ifcond = None
+        if isinstance(typ, dict):
+            check_unknown_keys(info, typ, {'type', 'if'})
+            ifcond = typ.get('if')
+            typ = typ['type']
         if isinstance(typ, list):
             assert len(typ) == 1
             typ = self._make_array_type(typ[0], info)
         typ = self._make_implicit_object_type(
             typ, info, None, self.lookup_type(typ).ifcond,
             'wrapper', [self._make_member('data', typ, info)])
-        return QAPISchemaObjectTypeVariant(case, typ)
+        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
 
     def _def_union_type(self, expr, info, doc):
         name = expr['union']
@@ -1700,8 +1705,8 @@ class QAPISchema(object):
         else:
             variants = [self._make_simple_variant(key, value, info)
                         for (key, value) in data.iteritems()]
-            typ = self._make_implicit_enum_type(name, info, ifcond,
-                                                [v.name for v in variants])
+            values = [{'name': v.name, 'if': v.ifcond} for v in variants]
+            typ = self._make_implicit_enum_type(name, info, ifcond, values)
             tag_member = QAPISchemaObjectTypeMember('type', typ, False)
             members = [tag_member]
         self._def_entity(
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 5cfccabb3d..895e80a978 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -200,9 +200,14 @@
   [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
   'if': 'defined(TEST_IF_ENUM)' }
 
-{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
+{ 'union': 'TestIfUnion', 'data':
+  { 'foo': 'TestStruct',
+    'union_bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
   'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
 
+{ 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' },
+  'if': 'defined(TEST_IF_UNION)' }
+
 { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
   'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
 
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 6df4e49c69..ee009c5626 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -87,9 +87,14 @@ object TestIfUnion
     member type: TestIfUnionKind optional=False
     tag type
     case foo: q_obj_TestStruct-wrapper
+    case union_bar: q_obj_str-wrapper if=defined(TEST_IF_UNION_BAR)
     if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
+command TestIfUnionCmd q_obj_TestIfUnionCmd-arg -> None
+   gen=True success_response=True boxed=False
+    if defined(TEST_IF_UNION)
 enum TestIfUnionKind
     member foo:
+    member union_bar: if=defined(TEST_IF_UNION_BAR)
     if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
 object TestStruct
     member integer: int optional=False
@@ -235,6 +240,9 @@ object q_obj_TestIfEvent-arg
     member foo: TestIfStruct optional=False
     member bar: TestIfEnum optional=False if=defined(TEST_IF_EVT_BAR)
     if defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)
+object q_obj_TestIfUnionCmd-arg
+    member union_cmd_arg: TestIfUnion optional=False
+    if defined(TEST_IF_UNION)
 object q_obj_TestStruct-wrapper
     member data: TestStruct optional=False
 object q_obj_UserDefFlatUnion2-base
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index a86c3b5ee1..87a8efff78 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -65,7 +65,10 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         if variants:
             print '    tag %s' % variants.tag_member.name
             for v in variants.variants:
-                print '    case %s: %s' % (v.name, v.type.name)
+                print '    case %s: %s' % (v.name, v.type.name),
+                if v.ifcond:
+                    print 'if=%s' % v.ifcond,
+                print
 
     @staticmethod
     def _print_if(ifcond):
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 27/50] qapi: add #if conditions to generated variants
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (25 preceding siblings ...)
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 26/50] qapi: add 'if' on union variants Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-13 12:37   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 28/50] qapi: add 'if' to alternate variant Marc-André Lureau
                   ` (24 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-introspect.py | 3 ++-
 scripts/qapi-types.py      | 2 ++
 scripts/qapi-visit.py      | 4 ++++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 0e43e470bb..ef2d5577db 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -148,7 +148,8 @@ const QLitObject %(c_name)s = %(c_string)s;
                 'variants': [self._gen_variant(v) for v in variants]}
 
     def _gen_variant(self, variant):
-        return {'case': variant.name, 'type': self._use_type(variant.type)}
+        return ({'case': variant.name, 'type': self._use_type(variant.type)},
+                variant.ifcond)
 
     def visit_builtin_type(self, name, info, json_type):
         self._gen_qlit(name, 'builtin', {'json-type': json_type}, None)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 7e6df21f53..312685c295 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -131,11 +131,13 @@ def gen_variants(variants):
                 c_name=c_name(variants.tag_member.name))
 
     for var in variants.variants:
+        ret += gen_if(var.ifcond)
         ret += mcgen('''
         %(c_type)s %(c_name)s;
 ''',
                      c_type=var.type.c_unboxed_type(),
                      c_name=c_name(var.name))
+        ret += gen_endif(var.ifcond)
 
     ret += mcgen('''
     } u;
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 6a3a52e39d..369e1f927d 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -82,6 +82,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
                      c_name=c_name(variants.tag_member.name))
 
         for var in variants.variants:
+            ret += gen_if(var.ifcond)
             ret += mcgen('''
     case %(case)s:
         visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err);
@@ -92,6 +93,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
                                            variants.tag_member.type.prefix),
                          c_type=var.type.c_name(), c_name=c_name(var.name))
 
+            ret += gen_endif(var.ifcond)
         ret += mcgen('''
     default:
         abort();
@@ -182,6 +184,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
                  c_name=c_name(name))
 
     for var in variants.variants:
+        ret += gen_if(var.ifcond)
         ret += mcgen('''
     case %(case)s:
 ''',
@@ -209,6 +212,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
         ret += mcgen('''
         break;
 ''')
+        ret += gen_endif(var.ifcond)
 
     ret += mcgen('''
     case QTYPE_NONE:
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 28/50] qapi: add 'if' to alternate variant
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (26 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 27/50] qapi: add #if conditions to generated variants Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-12 14:51   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 29/50] qapi: add tests for invalid alternate Marc-André Lureau
                   ` (23 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                         | 9 ++++++++-
 tests/qapi-schema/qapi-schema-test.json | 6 +++++-
 tests/qapi-schema/qapi-schema-test.out  | 8 +++++++-
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 2f14edfa1f..19e48bd4d2 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -849,6 +849,9 @@ def check_alternate(expr, info):
         check_type(info, "Member '%s' of alternate '%s'" % (key, name),
                    value,
                    allow_metas=['built-in', 'union', 'struct', 'enum'])
+        if isinstance(value, dict):
+            check_unknown_keys(info, value, {'type', 'if'})
+            value = value['type']
         qtype = find_alternate_member_qtype(value)
         if not qtype:
             raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
@@ -1671,7 +1674,11 @@ class QAPISchema(object):
                                               None))
 
     def _make_variant(self, case, typ):
-        return QAPISchemaObjectTypeVariant(case, typ)
+        ifcond = None
+        if isinstance(typ, dict):
+            ifcond = typ.get('if')
+            typ = typ['type']
+        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
 
     def _make_simple_variant(self, case, typ, info):
         ifcond = None
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 895e80a978..f7a62b24d1 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -208,9 +208,13 @@
 { 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' },
   'if': 'defined(TEST_IF_UNION)' }
 
-{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
+{ 'alternate': 'TestIfAlternate', 'data':
+  { 'foo': 'int', 'alt_bar': { 'type': 'TestStruct', 'if': 'defined(TEST_IF_ALT_BAR)'} },
   'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
 
+{ 'command': 'TestIfAlternateCmd', 'data': { 'alt_cmd_arg': 'TestIfAlternate' },
+  'if': 'defined(TEST_IF_ALT)' }
+
 { 'command': 'TestIfCmd', 'data':
   { 'foo': 'TestIfStruct',
     'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } },
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index ee009c5626..6887e49c9b 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -67,8 +67,11 @@ enum QType
 alternate TestIfAlternate
     tag type
     case foo: int
-    case bar: TestStruct
+    case alt_bar: TestStruct if=defined(TEST_IF_ALT_BAR)
     if defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)
+command TestIfAlternateCmd q_obj_TestIfAlternateCmd-arg -> None
+   gen=True success_response=True boxed=False
+    if defined(TEST_IF_ALT)
 command TestIfCmd q_obj_TestIfCmd-arg -> None
    gen=True success_response=True boxed=False
     if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
@@ -232,6 +235,9 @@ object q_obj_EVENT_D-arg
     member b: str optional=False
     member c: str optional=True
     member enum3: EnumOne optional=True
+object q_obj_TestIfAlternateCmd-arg
+    member alt_cmd_arg: TestIfAlternate optional=False
+    if defined(TEST_IF_ALT)
 object q_obj_TestIfCmd-arg
     member foo: TestIfStruct optional=False
     member bar: TestIfEnum optional=False if=defined(TEST_IF_CMD_BAR)
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 29/50] qapi: add tests for invalid alternate
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (27 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 28/50] qapi: add 'if' to alternate variant Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 30/50] qapi: add #if conditions to generated alternate variants Marc-André Lureau
                   ` (22 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/Makefile.include                        | 1 +
 tests/qapi-schema/alternate-dict-invalid.err  | 1 +
 tests/qapi-schema/alternate-dict-invalid.exit | 1 +
 tests/qapi-schema/alternate-dict-invalid.json | 4 ++++
 tests/qapi-schema/alternate-dict-invalid.out  | 0
 5 files changed, 7 insertions(+)
 create mode 100644 tests/qapi-schema/alternate-dict-invalid.err
 create mode 100644 tests/qapi-schema/alternate-dict-invalid.exit
 create mode 100644 tests/qapi-schema/alternate-dict-invalid.json
 create mode 100644 tests/qapi-schema/alternate-dict-invalid.out

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 44a3d8895e..4af0b0c2eb 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -380,6 +380,7 @@ qapi-schema += alternate-conflict-enum-int.json
 qapi-schema += alternate-conflict-string.json
 qapi-schema += alternate-conflict-bool-string.json
 qapi-schema += alternate-conflict-num-string.json
+qapi-schema += alternate-dict-invalid.json
 qapi-schema += alternate-empty.json
 qapi-schema += alternate-nested.json
 qapi-schema += alternate-unknown.json
diff --git a/tests/qapi-schema/alternate-dict-invalid.err b/tests/qapi-schema/alternate-dict-invalid.err
new file mode 100644
index 0000000000..707c40f0f6
--- /dev/null
+++ b/tests/qapi-schema/alternate-dict-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-dict-invalid.json:2: Member 'two' of alternate 'Alt' should be a type name
diff --git a/tests/qapi-schema/alternate-dict-invalid.exit b/tests/qapi-schema/alternate-dict-invalid.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/alternate-dict-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/alternate-dict-invalid.json b/tests/qapi-schema/alternate-dict-invalid.json
new file mode 100644
index 0000000000..45f2c8ebef
--- /dev/null
+++ b/tests/qapi-schema/alternate-dict-invalid.json
@@ -0,0 +1,4 @@
+# invalid field dictionnary, missing type
+{ 'alternate': 'Alt',
+  'data': { 'one': 'str',
+            'two': { 'if': 'foo' } } }
diff --git a/tests/qapi-schema/alternate-dict-invalid.out b/tests/qapi-schema/alternate-dict-invalid.out
new file mode 100644
index 0000000000..e69de29bb2
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 30/50] qapi: add #if conditions to generated alternate variants
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (28 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 29/50] qapi: add tests for invalid alternate Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-12 19:25   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 31/50] docs: document schema configuration Marc-André Lureau
                   ` (21 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Mostly covered by previous patches already.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-introspect.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index ef2d5577db..d6194ff702 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -172,7 +172,7 @@ const QLitObject %(c_name)s = %(c_string)s;
 
     def visit_alternate_type(self, name, info, ifcond, variants):
         self._gen_qlit(name, 'alternate',
-                       {'members': [{'type': self._use_type(m.type)}
+                       {'members': [({'type': self._use_type(m.type)}, m.ifcond)
                                     for m in variants.variants]}, ifcond)
 
     def visit_command(self, name, info, ifcond, arg_type, ret_type,
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 31/50] docs: document schema configuration
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (29 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 30/50] qapi: add #if conditions to generated alternate variants Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-13 10:41   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 32/50] qapi2texi: add 'If:' section to generated documentation Marc-André Lureau
                   ` (20 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 docs/devel/qapi-code-gen.txt | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 0a90f2278a..24fc6f74ee 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -682,6 +682,43 @@ Example: Red Hat, Inc. controls redhat.com, and may therefore add a
 downstream command __com.redhat_drive-mirror.
 
 
+=== Configuring the schema ===
+
+'struct', 'enum', 'union', 'alternate', 'command' and 'event'
+top-level QAPI expressions can take a 'if' keyword like:
+
+{ 'struct': 'IfStruct', 'data': { 'foo': 'int' },
+  'if': 'defined(IF_STRUCT) && defined(FOO)' }
+
+Members can be exploded as dictionnary with 'type' & 'if' keys:
+
+{ 'struct': 'IfStruct', 'data':
+  { 'foo': 'int',
+    'bar': { 'type': 'int', 'if': 'defined(IF_STRUCT_BAR)'} } }
+
+Enum values can be exploded as dictionnary with 'name' & 'if' keys:
+
+{ 'enum': 'IfEnum', 'data':
+  [ 'foo',
+    { 'name' : 'bar', 'if': 'defined(IF_ENUM_BAR)' } ] }
+
+The C code generators will wrap the corresponding lines with #if / #endif
+pre-processor conditions for a given 'if' value.
+
+Example for enum values:
+
+enum IfEnum {
+     IF_ENUM_FOO,
+#if defined(IF_ENUM_BAR)
+     IF_ENUM_BAR,
+#endif /* defined(IF_ENUM_BAR) */
+     IF_ENUM__MAX
+}
+
+Please note that you are responsbile to ensure that the C code will
+compile with an arbitrary combination of conditions, since the
+generators are unable to check it at this point.
+
 == Client JSON Protocol introspection ==
 
 Clients of a Client JSON Protocol commonly need to figure out what
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 32/50] qapi2texi: add 'If:' section to generated documentation
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (30 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 31/50] docs: document schema configuration Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-13 12:35   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 33/50] qapi2texi: add 'If:' condition to enum values Marc-André Lureau
                   ` (19 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

The documentation is generated only once, and doesn't know C
pre-conditions. Add 'If:' sections for top-level entities.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi2texi.py | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index e72e7cfe0b..150e7045d2 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -132,7 +132,6 @@ def texi_enum_value(value):
     """Format a table of members item for an enumeration value"""
     return '@item @code{%s}\n' % value.name
 
-
 def texi_member(member, suffix=''):
     """Format a table of members item for an object type member"""
     typ = member.type.doc_type()
@@ -175,7 +174,7 @@ def texi_members(doc, what, base, variants, member_func):
     return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items)
 
 
-def texi_sections(doc):
+def texi_sections(doc, ifcond):
     """Format additional sections following arguments"""
     body = ''
     for section in doc.sections:
@@ -189,14 +188,16 @@ def texi_sections(doc):
             body += '\n\n@b{%s:}\n' % name
 
         body += func(doc)
+    if ifcond:
+        body += '\n\n@b{If:} @code{%s}' % ifcond
     return body
 
 
-def texi_entity(doc, what, base=None, variants=None,
+def texi_entity(doc, what, ifcond, base=None, variants=None,
                 member_func=texi_member):
     return (texi_body(doc)
             + texi_members(doc, what, base, variants, member_func)
-            + texi_sections(doc))
+            + texi_sections(doc, ifcond))
 
 
 class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
@@ -213,7 +214,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += TYPE_FMT(type='Enum',
                              name=doc.symbol,
-                             body=texi_entity(doc, 'Values',
+                             body=texi_entity(doc, 'Values', ifcond,
                                               member_func=texi_enum_value))
 
     def visit_object_type(self, name, info, ifcond, base, members, variants):
@@ -224,7 +225,8 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += TYPE_FMT(type='Object',
                              name=doc.symbol,
-                             body=texi_entity(doc, 'Members', base, variants))
+                             body=texi_entity(doc, 'Members', ifcond,
+                                              base, variants))
 
     def visit_alternate_type(self, name, info, ifcond, variants):
         doc = self.cur_doc
@@ -232,7 +234,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += TYPE_FMT(type='Alternate',
                              name=doc.symbol,
-                             body=texi_entity(doc, 'Members'))
+                             body=texi_entity(doc, 'Members', ifcond))
 
     def visit_command(self, name, info, ifcond, arg_type, ret_type,
                       gen, success_response, boxed):
@@ -242,9 +244,9 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
         if boxed:
             body = texi_body(doc)
             body += '\n@b{Arguments:} the members of @code{%s}' % arg_type.name
-            body += texi_sections(doc)
+            body += texi_sections(doc, ifcond)
         else:
-            body = texi_entity(doc, 'Arguments')
+            body = texi_entity(doc, 'Arguments', ifcond)
         self.out += MSG_FMT(type='Command',
                             name=doc.symbol,
                             body=body)
@@ -255,7 +257,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += MSG_FMT(type='Event',
                             name=doc.symbol,
-                            body=texi_entity(doc, 'Arguments'))
+                            body=texi_entity(doc, 'Arguments', ifcond))
 
     def symbol(self, doc, entity):
         self.cur_doc = doc
@@ -266,7 +268,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
         assert not doc.args
         if self.out:
             self.out += '\n'
-        self.out += texi_body(doc) + texi_sections(doc)
+        self.out += texi_body(doc) + texi_sections(doc, None)
 
 
 def texi_schema(schema):
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 33/50] qapi2texi: add 'If:' condition to enum values
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (31 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 32/50] qapi2texi: add 'If:' section to generated documentation Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 34/50] qapi2texi: add 'If:' condition to struct members Marc-André Lureau
                   ` (18 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi2texi.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 150e7045d2..7327245a60 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -130,7 +130,9 @@ def texi_body(doc):
 
 def texi_enum_value(value):
     """Format a table of members item for an enumeration value"""
-    return '@item @code{%s}\n' % value.name
+    return '@item @code{%s}%s\n' % (
+        value.name,
+        '\n@b{If:} @code{%s}\n' % value.ifcond if value.ifcond else '')
 
 def texi_member(member, suffix=''):
     """Format a table of members item for an object type member"""
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 34/50] qapi2texi: add 'If:' condition to struct members
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (32 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 33/50] qapi2texi: add 'If:' condition to enum values Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 35/50] qapi2texi: add condition to variants Marc-André Lureau
                   ` (17 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi2texi.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 7327245a60..bb819856ef 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -138,9 +138,10 @@ def texi_member(member, suffix=''):
     """Format a table of members item for an object type member"""
     typ = member.type.doc_type()
     membertype = ': ' + typ if typ else ''
-    return '@item @code{%s%s}%s%s\n' % (
+    return '@item @code{%s%s}%s%s%s\n' % (
         member.name, membertype,
         ' (optional)' if member.optional else '',
+        '\n@b{If:} @code{%s}\n' % member.ifcond if member.ifcond else '',
         suffix)
 
 
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 35/50] qapi2texi: add condition to variants
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (33 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 34/50] qapi2texi: add 'If:' condition to struct members Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 36/50] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
                   ` (16 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi2texi.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index bb819856ef..4e7b1cda87 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -163,8 +163,9 @@ def texi_members(doc, what, base, variants, member_func):
         items += '@item The members of @code{%s}\n' % base.doc_type()
     if variants:
         for v in variants.variants:
-            when = ' when @code{%s} is @t{"%s"}' % (
-                variants.tag_member.name, v.name)
+            when = ' when @code{%s} is @t{"%s"}%s' % (
+                variants.tag_member.name, v.name,
+                ' (and @code{%s})' % v.ifcond if v.ifcond else '')
             if v.type.is_implicit():
                 assert not v.type.base and not v.type.variants
                 for m in v.type.local_members:
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 36/50] qapi: add conditions to VNC type/commands/events on the schema
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (34 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 35/50] qapi2texi: add condition to variants Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-13 14:12   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 37/50] qapi: add conditions to SPICE " Marc-André Lureau
                   ` (15 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Daniel P. Berrange,
	Dr. David Alan Gilbert, Eric Blake, Gerd Hoffmann

Add #if defined(CONFIG_VNC) in generated code, and adjust the
qmp/hmp code accordingly.

Commands made conditional:

* query-vnc, query-vnc-servers, change-vnc-password

  Before the patch, the commands for !CONFIG_VNC are stubs that fail
  like this:

    {"error": {"class": "GenericError",
               "desc": "The feature 'vnc' is not enabled"}}

  Afterwards, they fail like this:

    {"error": {"class": "CommandNotFound",
               "desc": "The command FOO has not been found"}}

  I call that an improvement, because it lets clients distinguish
  between command unavailable (class CommandNotFound) and command failed
  (class GenericError).

Events made conditional:

* VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED

Enum made conditional:

* QCryptoCipherAlgorithm

    # @des-rfb: RFB specific variant of single DES. Do not use except in VNC.

Occurrences of VNC (case insensitive) in the schema that aren't
covered by this change:

* add_client

  Command has other uses, including "socket bases character devices".
  These are unconditional as far as I can tell.

* set_password, expire_password

  In theory, these commands could be used for managing any service's
  password.  In practice, they're used for VNC and SPICE services.
  They're documented for "remote display session" / "remote display
  server".

  The service is selected by argument @protocol.  The code special-cases
  protocol-specific argument checking, then calls a protocol-specific
  function to do the work.  If it fails, the command fails with "Could
  not set password".  It does when the service isn't compiled in (it's a
  stub then).

  We could make these commands conditional on the conjunction of all
  services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)],
  but I doubt it's worthwhile.

* change

  Command has other uses, namely changing media.
  This patch inlines a stub; no functional change.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/crypto.json           |  3 ++-
 qapi/ui.json               | 45 ++++++++++++++++++++++++++++-----------------
 ui/vnc.h                   |  2 ++
 crypto/cipher-builtin.c    |  9 +++++++++
 crypto/cipher-gcrypt.c     | 10 ++++++++--
 crypto/cipher-nettle.c     | 14 +++++++++++---
 crypto/cipher.c            | 13 +++++++++++--
 hmp.c                      |  9 ++++++++-
 qmp.c                      | 30 ++++--------------------------
 tests/test-crypto-cipher.c |  2 ++
 hmp-commands-info.hx       |  2 ++
 11 files changed, 87 insertions(+), 52 deletions(-)

diff --git a/qapi/crypto.json b/qapi/crypto.json
index 288bc056ef..09535b7be2 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -79,7 +79,8 @@
 { 'enum': 'QCryptoCipherAlgorithm',
   'prefix': 'QCRYPTO_CIPHER_ALG',
   'data': ['aes-128', 'aes-192', 'aes-256',
-           'des-rfb', '3des',
+           { 'name': 'des-rfb', 'if': 'defined(CONFIG_VNC)' },
+           '3des',
            'cast5-128',
            'serpent-128', 'serpent-192', 'serpent-256',
            'twofish-128', 'twofish-192', 'twofish-256']}
diff --git a/qapi/ui.json b/qapi/ui.json
index e5d6610b4a..4b573d214b 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -369,7 +369,8 @@
   'data': { 'host': 'str',
             'service': 'str',
             'family': 'NetworkAddressFamily',
-            'websocket': 'bool' } }
+            'websocket': 'bool' },
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VncServerInfo:
@@ -383,7 +384,8 @@
 ##
 { 'struct': 'VncServerInfo',
   'base': 'VncBasicInfo',
-  'data': { '*auth': 'str' } }
+  'data': { '*auth': 'str' },
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VncClientInfo:
@@ -400,7 +402,8 @@
 ##
 { 'struct': 'VncClientInfo',
   'base': 'VncBasicInfo',
-  'data': { '*x509_dname': 'str', '*sasl_username': 'str' } }
+  'data': { '*x509_dname': 'str', '*sasl_username': 'str' },
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VncInfo:
@@ -441,7 +444,8 @@
 { 'struct': 'VncInfo',
   'data': {'enabled': 'bool', '*host': 'str',
            '*family': 'NetworkAddressFamily',
-           '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
+           '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']},
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VncPrimaryAuth:
@@ -452,7 +456,8 @@
 ##
 { 'enum': 'VncPrimaryAuth',
   'data': [ 'none', 'vnc', 'ra2', 'ra2ne', 'tight', 'ultra',
-            'tls', 'vencrypt', 'sasl' ] }
+            'tls', 'vencrypt', 'sasl' ],
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VncVencryptSubAuth:
@@ -466,8 +471,8 @@
             'tls-none',  'x509-none',
             'tls-vnc',   'x509-vnc',
             'tls-plain', 'x509-plain',
-            'tls-sasl',  'x509-sasl' ] }
-
+            'tls-sasl',  'x509-sasl' ],
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VncServerInfo2:
@@ -484,8 +489,8 @@
 { 'struct': 'VncServerInfo2',
   'base': 'VncBasicInfo',
   'data': { 'auth'      : 'VncPrimaryAuth',
-            '*vencrypt' : 'VncVencryptSubAuth' } }
-
+            '*vencrypt' : 'VncVencryptSubAuth' },
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VncInfo2:
@@ -517,7 +522,8 @@
             'clients'   : ['VncClientInfo'],
             'auth'      : 'VncPrimaryAuth',
             '*vencrypt' : 'VncVencryptSubAuth',
-            '*display'  : 'str' } }
+            '*display'  : 'str' },
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @query-vnc:
@@ -548,8 +554,8 @@
 #    }
 #
 ##
-{ 'command': 'query-vnc', 'returns': 'VncInfo' }
-
+{ 'command': 'query-vnc', 'returns': 'VncInfo',
+  'if': 'defined(CONFIG_VNC)' }
 ##
 # @query-vnc-servers:
 #
@@ -559,7 +565,8 @@
 #
 # Since: 2.3
 ##
-{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'] }
+{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'],
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @change-vnc-password:
@@ -573,7 +580,8 @@
 # Notes:  An empty password in this command will set the password to the empty
 #         string.  Existing clients are unaffected by executing this command.
 ##
-{ 'command': 'change-vnc-password', 'data': {'password': 'str'} }
+{ 'command': 'change-vnc-password', 'data': {'password': 'str'},
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VNC_CONNECTED:
@@ -602,7 +610,8 @@
 ##
 { 'event': 'VNC_CONNECTED',
   'data': { 'server': 'VncServerInfo',
-            'client': 'VncBasicInfo' } }
+            'client': 'VncBasicInfo' },
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VNC_INITIALIZED:
@@ -629,7 +638,8 @@
 ##
 { 'event': 'VNC_INITIALIZED',
   'data': { 'server': 'VncServerInfo',
-            'client': 'VncClientInfo' } }
+            'client': 'VncClientInfo' },
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # @VNC_DISCONNECTED:
@@ -655,7 +665,8 @@
 ##
 { 'event': 'VNC_DISCONNECTED',
   'data': { 'server': 'VncServerInfo',
-            'client': 'VncClientInfo' } }
+            'client': 'VncClientInfo' },
+  'if': 'defined(CONFIG_VNC)' }
 
 ##
 # = Input
diff --git a/ui/vnc.h b/ui/vnc.h
index 694cf32ca9..5572bfdc9e 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -291,7 +291,9 @@ struct VncState
     bool encode_ws;
     bool websocket;
 
+#ifdef CONFIG_VNC
     VncClientInfo *info;
+#endif
 
     Buffer output;
     Buffer input;
diff --git a/crypto/cipher-builtin.c b/crypto/cipher-builtin.c
index d8c811fd33..647850843e 100644
--- a/crypto/cipher-builtin.c
+++ b/crypto/cipher-builtin.c
@@ -35,17 +35,22 @@ struct QCryptoCipherBuiltinAES {
     QCryptoCipherBuiltinAESContext key_tweak;
     uint8_t iv[AES_BLOCK_SIZE];
 };
+
+#ifdef CONFIG_VNC
 typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
 struct QCryptoCipherBuiltinDESRFB {
     uint8_t *key;
     size_t nkey;
 };
+#endif
 
 typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin;
 struct QCryptoCipherBuiltin {
     union {
         QCryptoCipherBuiltinAES aes;
+#ifdef CONFIG_VNC
         QCryptoCipherBuiltinDESRFB desrfb;
+#endif
     } state;
     size_t blocksize;
     void (*free)(QCryptoCipher *cipher);
@@ -403,7 +408,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
                              QCryptoCipherMode mode)
 {
     switch (alg) {
+#ifdef CONFIG_VNC
     case QCRYPTO_CIPHER_ALG_DES_RFB:
+#endif
     case QCRYPTO_CIPHER_ALG_AES_128:
     case QCRYPTO_CIPHER_ALG_AES_192:
     case QCRYPTO_CIPHER_ALG_AES_256:
@@ -449,9 +456,11 @@ static QCryptoCipherBuiltin *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
     }
 
     switch (alg) {
+#ifdef CONFIG_VNC
     case QCRYPTO_CIPHER_ALG_DES_RFB:
         ctxt = qcrypto_cipher_init_des_rfb(mode, key, nkey, errp);
         break;
+#endif
     case QCRYPTO_CIPHER_ALG_AES_128:
     case QCRYPTO_CIPHER_ALG_AES_192:
     case QCRYPTO_CIPHER_ALG_AES_256:
diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c
index 10d75da75d..c240aaee26 100644
--- a/crypto/cipher-gcrypt.c
+++ b/crypto/cipher-gcrypt.c
@@ -29,7 +29,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
                              QCryptoCipherMode mode)
 {
     switch (alg) {
+#ifdef CONFIG_VNC
     case QCRYPTO_CIPHER_ALG_DES_RFB:
+#endif
     case QCRYPTO_CIPHER_ALG_3DES:
     case QCRYPTO_CIPHER_ALG_AES_128:
     case QCRYPTO_CIPHER_ALG_AES_192:
@@ -114,10 +116,11 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
     }
 
     switch (alg) {
+#ifdef CONFIG_VNC
     case QCRYPTO_CIPHER_ALG_DES_RFB:
         gcryalg = GCRY_CIPHER_DES;
         break;
-
+#endif
     case QCRYPTO_CIPHER_ALG_3DES:
         gcryalg = GCRY_CIPHER_3DES;
         break;
@@ -181,6 +184,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
         }
     }
 
+#ifdef CONFIG_VNC
     if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
         /* We're using standard DES cipher from gcrypt, so we need
          * to munge the key so that the results are the same as the
@@ -190,7 +194,9 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
         err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
         g_free(rfbkey);
         ctx->blocksize = 8;
-    } else {
+    } else
+#endif /* CONFIG_VNC */
+    {
         if (mode == QCRYPTO_CIPHER_MODE_XTS) {
             nkey /= 2;
             err = gcry_cipher_setkey(ctx->handle, key, nkey);
diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c
index 3848cb3b3a..ace5ec20f6 100644
--- a/crypto/cipher-nettle.c
+++ b/crypto/cipher-nettle.c
@@ -67,6 +67,7 @@ static void aes_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
     aes_decrypt(&aesctx->dec, length, dst, src);
 }
 
+#ifdef CONFIG_VNC
 static void des_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
                                uint8_t *dst, const uint8_t *src)
 {
@@ -78,6 +79,7 @@ static void des_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
 {
     des_decrypt(ctx, length, dst, src);
 }
+#endif
 
 static void des3_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
                                 uint8_t *dst, const uint8_t *src)
@@ -141,6 +143,7 @@ static void aes_decrypt_wrapper(const void *ctx, size_t length,
     aes_decrypt(&aesctx->dec, length, dst, src);
 }
 
+#ifdef CONFIG_VNC
 static void des_encrypt_wrapper(const void *ctx, size_t length,
                                 uint8_t *dst, const uint8_t *src)
 {
@@ -152,6 +155,7 @@ static void des_decrypt_wrapper(const void *ctx, size_t length,
 {
     des_decrypt(ctx, length, dst, src);
 }
+#endif
 
 static void des3_encrypt_wrapper(const void *ctx, size_t length,
                                 uint8_t *dst, const uint8_t *src)
@@ -221,7 +225,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
                              QCryptoCipherMode mode)
 {
     switch (alg) {
+#ifdef CONFIG_VNC
     case QCRYPTO_CIPHER_ALG_DES_RFB:
+#endif
     case QCRYPTO_CIPHER_ALG_3DES:
     case QCRYPTO_CIPHER_ALG_AES_128:
     case QCRYPTO_CIPHER_ALG_AES_192:
@@ -271,7 +277,6 @@ static QCryptoCipherNettle *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
                                                    Error **errp)
 {
     QCryptoCipherNettle *ctx;
-    uint8_t *rfbkey;
 
     switch (mode) {
     case QCRYPTO_CIPHER_MODE_ECB:
@@ -292,7 +297,9 @@ static QCryptoCipherNettle *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
     ctx = g_new0(QCryptoCipherNettle, 1);
 
     switch (alg) {
-    case QCRYPTO_CIPHER_ALG_DES_RFB:
+#ifdef CONFIG_VNC
+    case QCRYPTO_CIPHER_ALG_DES_RFB: {
+        uint8_t *rfbkey;
         ctx->ctx = g_new0(struct des_ctx, 1);
         rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
         des_set_key(ctx->ctx, rfbkey);
@@ -305,7 +312,8 @@ static QCryptoCipherNettle *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
 
         ctx->blocksize = DES_BLOCK_SIZE;
         break;
-
+    }
+#endif
     case QCRYPTO_CIPHER_ALG_3DES:
         ctx->ctx = g_new0(struct des3_ctx, 1);
         des3_set_key(ctx->ctx, key);
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 0aad9d6d79..80355f4530 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -28,7 +28,9 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
     [QCRYPTO_CIPHER_ALG_AES_128] = 16,
     [QCRYPTO_CIPHER_ALG_AES_192] = 24,
     [QCRYPTO_CIPHER_ALG_AES_256] = 32,
+#ifdef CONFIG_VNC
     [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
+#endif
     [QCRYPTO_CIPHER_ALG_3DES] = 24,
     [QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
     [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
@@ -43,7 +45,9 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
     [QCRYPTO_CIPHER_ALG_AES_128] = 16,
     [QCRYPTO_CIPHER_ALG_AES_192] = 16,
     [QCRYPTO_CIPHER_ALG_AES_256] = 16,
+#ifdef CONFIG_VNC
     [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
+#endif
     [QCRYPTO_CIPHER_ALG_3DES] = 8,
     [QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
     [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
@@ -106,8 +110,11 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
     }
 
     if (mode == QCRYPTO_CIPHER_MODE_XTS) {
-        if (alg == QCRYPTO_CIPHER_ALG_DES_RFB
-                || alg == QCRYPTO_CIPHER_ALG_3DES) {
+        if (
+#ifdef CONFIG_VNC
+            alg == QCRYPTO_CIPHER_ALG_DES_RFB ||
+#endif
+            alg == QCRYPTO_CIPHER_ALG_3DES) {
             error_setg(errp, "XTS mode not compatible with DES-RFB/3DES");
             return false;
         }
@@ -131,6 +138,7 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
     return true;
 }
 
+#if defined(CONFIG_VNC)
 #if defined(CONFIG_GCRYPT) || defined(CONFIG_NETTLE)
 static uint8_t *
 qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
@@ -148,6 +156,7 @@ qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
     return ret;
 }
 #endif /* CONFIG_GCRYPT || CONFIG_NETTLE */
+#endif /* CONFIG_VNC */
 
 #ifdef CONFIG_GCRYPT
 #include "crypto/cipher-gcrypt.c"
diff --git a/hmp.c b/hmp.c
index cd046c6d71..5893e5bf16 100644
--- a/hmp.c
+++ b/hmp.c
@@ -604,6 +604,7 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
     qapi_free_BlockStatsList(stats_list);
 }
 
+#ifdef CONFIG_VNC
 /* Helper for hmp_info_vnc_clients, _servers */
 static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info,
                                   const char *name)
@@ -691,6 +692,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict)
     qapi_free_VncInfo2List(info2l);
 
 }
+#endif
 
 #ifdef CONFIG_SPICE
 void hmp_info_spice(Monitor *mon, const QDict *qdict)
@@ -1702,12 +1704,14 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &err);
 }
 
+#ifdef CONFIG_VNC
 static void hmp_change_read_arg(void *opaque, const char *password,
                                 void *readline_opaque)
 {
     qmp_change_vnc_password(password, NULL);
     monitor_read_command(opaque, 1);
 }
+#endif
 
 void hmp_change(Monitor *mon, const QDict *qdict)
 {
@@ -1718,6 +1722,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
     BlockdevChangeReadOnlyMode read_only_mode = 0;
     Error *err = NULL;
 
+#ifdef CONFIG_VNC
     if (strcmp(device, "vnc") == 0) {
         if (read_only) {
             monitor_printf(mon,
@@ -1732,7 +1737,9 @@ void hmp_change(Monitor *mon, const QDict *qdict)
             }
         }
         qmp_change("vnc", target, !!arg, arg, &err);
-    } else {
+    } else
+#endif
+    {
         if (read_only) {
             read_only_mode =
                 qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup,
diff --git a/qmp.c b/qmp.c
index b86201e349..2c90dacb56 100644
--- a/qmp.c
+++ b/qmp.c
@@ -130,22 +130,6 @@ void qmp_cpu_add(int64_t id, Error **errp)
     }
 }
 
-#ifndef CONFIG_VNC
-/* If VNC support is enabled, the "true" query-vnc command is
-   defined in the VNC subsystem */
-VncInfo *qmp_query_vnc(Error **errp)
-{
-    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
-    return NULL;
-};
-
-VncInfo2List *qmp_query_vnc_servers(Error **errp)
-{
-    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
-    return NULL;
-};
-#endif
-
 #ifndef CONFIG_SPICE
 /*
  * qmp-commands.hx ensures that QMP command query-spice exists only
@@ -403,23 +387,17 @@ static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
         qmp_change_vnc_listen(target, errp);
     }
 }
-#else
-void qmp_change_vnc_password(const char *password, Error **errp)
-{
-    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
-}
-static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
-                           Error **errp)
-{
-    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
-}
 #endif /* !CONFIG_VNC */
 
 void qmp_change(const char *device, const char *target,
                 bool has_arg, const char *arg, Error **errp)
 {
     if (strcmp(device, "vnc") == 0) {
+#ifdef CONFIG_VNC
         qmp_change_vnc(target, has_arg, arg, errp);
+#else
+        error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
+#endif
     } else {
         qmp_blockdev_change_medium(true, device, false, NULL, target,
                                    has_arg, arg, false, 0, errp);
diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c
index 07fa2fa616..5980b27389 100644
--- a/tests/test-crypto-cipher.c
+++ b/tests/test-crypto-cipher.c
@@ -149,6 +149,7 @@ static QCryptoCipherTestData test_data[] = {
             "39f23369a9d9bacfa530e26304231461"
             "b2eb05e2c39be9fcda6c19078c6a9d1b",
     },
+#ifdef CONFIG_VNC
     {
         .path = "/crypto/cipher/des-rfb-ecb-56",
         .alg = QCRYPTO_CIPHER_ALG_DES_RFB,
@@ -165,6 +166,7 @@ static QCryptoCipherTestData test_data[] = {
             "ffd29f1bb5596ad94ea2d8e6196b7f09"
             "30d8ed0bf2773af36dd82a6280c20926",
     },
+#endif
 #if defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)
     {
         /* Borrowed from linux-kernel crypto/testmgr.h */
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 4ab7fcee98..aece8c5999 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -420,6 +420,7 @@ STEXI
 Show which guest mouse is receiving events.
 ETEXI
 
+#if defined(CONFIG_VNC)
     {
         .name       = "vnc",
         .args_type  = "",
@@ -427,6 +428,7 @@ ETEXI
         .help       = "show the vnc server status",
         .cmd        = hmp_info_vnc,
     },
+#endif
 
 STEXI
 @item info vnc
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 37/50] qapi: add conditions to SPICE type/commands/events on the schema
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (35 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 36/50] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-13 14:17   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 38/50] qapi: add conditions to REPLICATION type/commands " Marc-André Lureau
                   ` (14 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Paolo Bonzini, Eric Blake, Gerd Hoffmann

Add #if defined(CONFIG_SPICE) in generated code, and adjust the
qmp/hmp code accordingly.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/char.json | 10 ++++++----
 qapi/ui.json   | 30 ++++++++++++++++++++----------
 monitor.c      |  3 ---
 qmp.c          | 16 ----------------
 4 files changed, 26 insertions(+), 33 deletions(-)

diff --git a/qapi/char.json b/qapi/char.json
index ae19dcd1ed..7fa1762ae5 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -318,7 +318,8 @@
 # Since: 1.5
 ##
 { 'struct': 'ChardevSpiceChannel', 'data': { 'type'  : 'str' },
-  'base': 'ChardevCommon' }
+  'base': 'ChardevCommon',
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @ChardevSpicePort:
@@ -330,7 +331,8 @@
 # Since: 1.5
 ##
 { 'struct': 'ChardevSpicePort', 'data': { 'fqdn'  : 'str' },
-  'base': 'ChardevCommon' }
+  'base': 'ChardevCommon',
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @ChardevVC:
@@ -384,8 +386,8 @@
                                        'testdev': 'ChardevCommon',
                                        'stdio'  : 'ChardevStdio',
                                        'console': 'ChardevCommon',
-                                       'spicevmc' : 'ChardevSpiceChannel',
-                                       'spiceport' : 'ChardevSpicePort',
+                                       'spicevmc' : { 'type': 'ChardevSpiceChannel', 'if': 'defined(CONFIG_SPICE)' },
+                                       'spiceport' : { 'type': 'ChardevSpicePort', 'if': 'defined(CONFIG_SPICE)' },
                                        'vc'     : 'ChardevVC',
                                        'ringbuf': 'ChardevRingbuf',
                                        # next one is just for compatibility
diff --git a/qapi/ui.json b/qapi/ui.json
index 4b573d214b..daa4168c14 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -110,7 +110,8 @@
 { 'struct': 'SpiceBasicInfo',
   'data': { 'host': 'str',
             'port': 'str',
-            'family': 'NetworkAddressFamily' } }
+            'family': 'NetworkAddressFamily' },
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @SpiceServerInfo:
@@ -123,7 +124,8 @@
 ##
 { 'struct': 'SpiceServerInfo',
   'base': 'SpiceBasicInfo',
-  'data': { '*auth': 'str' } }
+  'data': { '*auth': 'str' },
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @SpiceChannel:
@@ -148,7 +150,8 @@
 { 'struct': 'SpiceChannel',
   'base': 'SpiceBasicInfo',
   'data': {'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
-           'tls': 'bool'} }
+           'tls': 'bool'},
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @SpiceQueryMouseMode:
@@ -167,7 +170,8 @@
 # Since: 1.1
 ##
 { 'enum': 'SpiceQueryMouseMode',
-  'data': [ 'client', 'server', 'unknown' ] }
+  'data': [ 'client', 'server', 'unknown' ],
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @SpiceInfo:
@@ -204,7 +208,8 @@
 { 'struct': 'SpiceInfo',
   'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
            '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
-           'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
+           'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']},
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @query-spice:
@@ -249,7 +254,8 @@
 #    }
 #
 ##
-{ 'command': 'query-spice', 'returns': 'SpiceInfo' }
+{ 'command': 'query-spice', 'returns': 'SpiceInfo',
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @SPICE_CONNECTED:
@@ -274,7 +280,8 @@
 ##
 { 'event': 'SPICE_CONNECTED',
   'data': { 'server': 'SpiceBasicInfo',
-            'client': 'SpiceBasicInfo' } }
+            'client': 'SpiceBasicInfo' },
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @SPICE_INITIALIZED:
@@ -302,7 +309,8 @@
 ##
 { 'event': 'SPICE_INITIALIZED',
   'data': { 'server': 'SpiceServerInfo',
-            'client': 'SpiceChannel' } }
+            'client': 'SpiceChannel' },
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @SPICE_DISCONNECTED:
@@ -327,7 +335,8 @@
 ##
 { 'event': 'SPICE_DISCONNECTED',
   'data': { 'server': 'SpiceBasicInfo',
-            'client': 'SpiceBasicInfo' } }
+            'client': 'SpiceBasicInfo' },
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # @SPICE_MIGRATE_COMPLETED:
@@ -342,7 +351,8 @@
 #      "event": "SPICE_MIGRATE_COMPLETED" }
 #
 ##
-{ 'event': 'SPICE_MIGRATE_COMPLETED' }
+{ 'event': 'SPICE_MIGRATE_COMPLETED',
+  'if': 'defined(CONFIG_SPICE)' }
 
 ##
 # == VNC
diff --git a/monitor.c b/monitor.c
index 5685697f59..135a1e0821 100644
--- a/monitor.c
+++ b/monitor.c
@@ -970,9 +970,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
  */
 static void qmp_unregister_commands_hack(void)
 {
-#ifndef CONFIG_SPICE
-    qmp_unregister_command(&qmp_commands, "query-spice");
-#endif
 #ifndef CONFIG_REPLICATION
     qmp_unregister_command(&qmp_commands, "xen-set-replication");
     qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
diff --git a/qmp.c b/qmp.c
index 2c90dacb56..90816ba283 100644
--- a/qmp.c
+++ b/qmp.c
@@ -130,22 +130,6 @@ void qmp_cpu_add(int64_t id, Error **errp)
     }
 }
 
-#ifndef CONFIG_SPICE
-/*
- * qmp-commands.hx ensures that QMP command query-spice exists only
- * #ifdef CONFIG_SPICE.  Necessary for an accurate query-commands
- * result.  However, the QAPI schema is blissfully unaware of that,
- * and the QAPI code generator happily generates a dead
- * qmp_marshal_query_spice() that calls qmp_query_spice().  Provide it
- * one, or else linking fails.  FIXME Educate the QAPI schema on
- * CONFIG_SPICE.
- */
-SpiceInfo *qmp_query_spice(Error **errp)
-{
-    abort();
-};
-#endif
-
 void qmp_cont(Error **errp)
 {
     BlockBackend *blk;
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 38/50] qapi: add conditions to REPLICATION type/commands on the schema
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (36 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 37/50] qapi: add conditions to SPICE " Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-13 14:19   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 39/50] qapi-commands: don't initialize command list in qmp_init_marshall() Marc-André Lureau
                   ` (13 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, zhanghailiang, Juan Quintela,
	Dr. David Alan Gilbert, Eric Blake

Add #if defined(CONFIG_REPLICATION) in generated code, and adjust the
code accordingly.

Made conditional:

* xen-set-replication, query-xen-replication-status,
  xen-colo-do-checkpoint

  Before the patch, we first register the commands unconditionally in
  generated code (requires a stub), then conditionally unregister in
  qmp_unregister_commands_hack().

  Afterwards, we register only when CONFIG_REPLICATION.  The command
  fails exactly the same, with CommandNotFound.

  Improvement, because now query-qmp-schema is accurate, and we're one
  step close to killing qmp_unregister_commands_hack().

* enum BlockdevDriver value "replication" in command blockdev-add

As well as enum BlockdevDriver value @replication BlockdevOptions
variant @replication, BlockdevOptionsReplication,
BlockdevOptionsReplicationMode.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/block-core.json | 15 ++++++++++-----
 qapi/migration.json  | 12 ++++++++----
 migration/colo.c     | 16 ++++------------
 monitor.c            |  5 -----
 4 files changed, 22 insertions(+), 26 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index bb11815608..6f897cf157 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2232,8 +2232,10 @@
             'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom',
             'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
             'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
-            'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
-            'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
+            'quorum', 'raw', 'rbd',
+            { 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
+            'sheepdog', 'ssh', 'throttle',
+            'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
 
 ##
 # @BlockdevOptionsFile:
@@ -2855,7 +2857,8 @@
 #
 # Since: 2.9
 ##
-{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] }
+{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ],
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @BlockdevOptionsReplication:
@@ -2873,7 +2876,8 @@
 { 'struct': 'BlockdevOptionsReplication',
   'base': 'BlockdevOptionsGenericFormat',
   'data': { 'mode': 'ReplicationMode',
-            '*top-id': 'str' } }
+            '*top-id': 'str' },
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @NFSTransport:
@@ -3168,7 +3172,8 @@
       'quorum':     'BlockdevOptionsQuorum',
       'raw':        'BlockdevOptionsRaw',
       'rbd':        'BlockdevOptionsRbd',
-      'replication':'BlockdevOptionsReplication',
+      'replication': { 'type': 'BlockdevOptionsReplication',
+                       'if': 'defined(CONFIG_REPLICATION)' },
       'sheepdog':   'BlockdevOptionsSheepdog',
       'ssh':        'BlockdevOptionsSsh',
       'throttle':   'BlockdevOptionsThrottle',
diff --git a/qapi/migration.json b/qapi/migration.json
index ee2b3b8733..44d2ef9c94 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1034,7 +1034,8 @@
 # Since: 2.9
 ##
 { 'command': 'xen-set-replication',
-  'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' } }
+  'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' },
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @ReplicationStatus:
@@ -1049,7 +1050,8 @@
 # Since: 2.9
 ##
 { 'struct': 'ReplicationStatus',
-  'data': { 'error': 'bool', '*desc': 'str' } }
+  'data': { 'error': 'bool', '*desc': 'str' },
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @query-xen-replication-status:
@@ -1066,7 +1068,8 @@
 # Since: 2.9
 ##
 { 'command': 'query-xen-replication-status',
-  'returns': 'ReplicationStatus' }
+  'returns': 'ReplicationStatus',
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @xen-colo-do-checkpoint:
@@ -1082,4 +1085,5 @@
 #
 # Since: 2.9
 ##
-{ 'command': 'xen-colo-do-checkpoint' }
+{ 'command': 'xen-colo-do-checkpoint',
+  'if': 'defined(CONFIG_REPLICATION)' }
diff --git a/migration/colo.c b/migration/colo.c
index dee3aa8bf7..010c9e02e8 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -22,7 +22,9 @@
 #include "trace.h"
 #include "qemu/error-report.h"
 #include "migration/failover.h"
+#ifdef CONFIG_REPLICATION
 #include "replication.h"
+#endif
 #include "qmp-commands.h"
 
 static bool vmstate_loading;
@@ -147,11 +149,11 @@ void colo_do_failover(MigrationState *s)
     }
 }
 
+#ifdef CONFIG_REPLICATION
 void qmp_xen_set_replication(bool enable, bool primary,
                              bool has_failover, bool failover,
                              Error **errp)
 {
-#ifdef CONFIG_REPLICATION
     ReplicationMode mode = primary ?
                            REPLICATION_MODE_PRIMARY :
                            REPLICATION_MODE_SECONDARY;
@@ -170,14 +172,10 @@ void qmp_xen_set_replication(bool enable, bool primary,
         }
         replication_stop_all(failover, failover ? NULL : errp);
     }
-#else
-    abort();
-#endif
 }
 
 ReplicationStatus *qmp_query_xen_replication_status(Error **errp)
 {
-#ifdef CONFIG_REPLICATION
     Error *err = NULL;
     ReplicationStatus *s = g_new0(ReplicationStatus, 1);
 
@@ -192,19 +190,13 @@ ReplicationStatus *qmp_query_xen_replication_status(Error **errp)
 
     error_free(err);
     return s;
-#else
-    abort();
-#endif
 }
 
 void qmp_xen_colo_do_checkpoint(Error **errp)
 {
-#ifdef CONFIG_REPLICATION
     replication_do_checkpoint_all(errp);
-#else
-    abort();
-#endif
 }
+#endif
 
 static void colo_send_message(QEMUFile *f, COLOMessage msg,
                               Error **errp)
diff --git a/monitor.c b/monitor.c
index 135a1e0821..b5ddcf8c67 100644
--- a/monitor.c
+++ b/monitor.c
@@ -970,11 +970,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
  */
 static void qmp_unregister_commands_hack(void)
 {
-#ifndef CONFIG_REPLICATION
-    qmp_unregister_command(&qmp_commands, "xen-set-replication");
-    qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
-    qmp_unregister_command(&qmp_commands, "xen-colo-do-checkpoint");
-#endif
 #ifndef TARGET_I386
     qmp_unregister_command(&qmp_commands, "rtc-reset-reinjection");
 #endif
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 39/50] qapi-commands: don't initialize command list in qmp_init_marshall()
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (37 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 38/50] qapi: add conditions to REPLICATION type/commands " Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-13 16:23   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 40/50] qapi: add -i/--include filename.h Marc-André Lureau
                   ` (12 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Dr. David Alan Gilbert, Michael Roth

This will let the caller add several list of commands.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi-commands.py  | 2 --
 monitor.c                 | 1 +
 qga/main.c                | 1 +
 tests/test-qmp-commands.c | 1 +
 4 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 8af8d913b9..7455d2b8bb 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -211,8 +211,6 @@ def gen_registry(registry):
 
 void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
 {
-    QTAILQ_INIT(cmds);
-
 ''',
                 c_prefix=c_name(prefix, protect=False))
     ret += registry
diff --git a/monitor.c b/monitor.c
index b5ddcf8c67..bf8a7685bf 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1001,6 +1001,7 @@ void monitor_init_qmp_commands(void)
      *   "qmp_capabilities", to enforce capability negotiation
      */
 
+    QTAILQ_INIT(&qmp_commands);
     qmp_init_marshal(&qmp_commands);
 
     qmp_register_command(&qmp_commands, "query-qmp-schema",
diff --git a/qga/main.c b/qga/main.c
index 62a62755bd..b949b1ccb0 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -1360,6 +1360,7 @@ int main(int argc, char **argv)
 
     config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
 
+    QTAILQ_INIT(&ga_commands);
     qga_qmp_init_marshal(&ga_commands);
 
     init_dfl_pathnames();
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index ad7b6e4e1d..28ce88e012 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -283,6 +283,7 @@ int main(int argc, char **argv)
     g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
     g_test_add_func("/0.15/dealloc_partial", test_dealloc_partial);
 
+    QTAILQ_INIT(&qmp_commands);
     test_qmp_init_marshal(&qmp_commands);
     g_test_run();
 
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 40/50] qapi: add -i/--include filename.h
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (38 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 39/50] qapi-commands: don't initialize command list in qmp_init_marshall() Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-14 13:50   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma Marc-André Lureau
                   ` (11 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Add a new option to add user-specified #include lines in the generated
headers. This will help to split a schema, where one generated header
will depend on another.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py            | 13 +++++++++----
 scripts/qapi-commands.py   |  7 +++++--
 scripts/qapi-event.py      |  6 ++++--
 scripts/qapi-introspect.py |  5 +++--
 scripts/qapi-types.py      |  6 ++++--
 scripts/qapi-visit.py      |  5 +++--
 6 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 19e48bd4d2..eb4ffdc06d 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -2096,9 +2096,9 @@ def parse_command_line(extra_options='', extra_long_options=[]):
 
     try:
         opts, args = getopt.gnu_getopt(sys.argv[1:],
-                                       'chp:o:' + extra_options,
-                                       ['source', 'header', 'prefix=',
-                                        'output-dir='] + extra_long_options)
+            'chp:o:i:' + extra_options,
+            ['source', 'header', 'prefix=', 'output-dir=',
+             'include='] + extra_long_options)
     except getopt.GetoptError as err:
         print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
         sys.exit(1)
@@ -2107,6 +2107,7 @@ def parse_command_line(extra_options='', extra_long_options=[]):
     prefix = ''
     do_c = False
     do_h = False
+    includes = []
     extra_opts = []
 
     for oa in opts:
@@ -2125,6 +2126,8 @@ def parse_command_line(extra_options='', extra_long_options=[]):
             do_c = True
         elif o in ('-h', '--header'):
             do_h = True
+        elif o in ('-i', '--include'):
+            includes.append(a)
         else:
             extra_opts.append(oa)
 
@@ -2137,7 +2140,9 @@ def parse_command_line(extra_options='', extra_long_options=[]):
         sys.exit(1)
     fname = args[0]
 
-    return (fname, output_dir, do_c, do_h, prefix, extra_opts)
+    includes = "\n".join(['#include "%s"' % inc for inc in includes])
+
+    return (fname, output_dir, do_c, do_h, prefix, includes, extra_opts)
 
 #
 # Generate output files with boilerplate
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 7455d2b8bb..4841f4d9a1 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -253,7 +253,8 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self._regy += gen_register_command(name, success_response)
 
 
-(input_file, output_dir, do_c, do_h, prefix, opts) = parse_command_line()
+(input_file, output_dir, do_c, do_h, prefix, includes, opts) = \
+        parse_command_line()
 
 c_comment = '''
 /*
@@ -305,6 +306,7 @@ fdef.write(mcgen('''
                  prefix=prefix))
 
 fdecl.write(mcgen('''
+%(includes)s
 #include "%(prefix)sqapi-types.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/dispatch.h"
@@ -312,7 +314,8 @@ fdecl.write(mcgen('''
 
 void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
 ''',
-                  prefix=prefix, c_prefix=c_name(prefix, protect=False)))
+                  includes=includes, prefix=prefix,
+                  c_prefix=c_name(prefix, protect=False)))
 
 schema = QAPISchema(input_file)
 gen = QAPISchemaGenCommandVisitor()
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 60c6f7030d..0aba866dc8 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -171,7 +171,8 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
         self._event_names.append(QAPISchemaMember(name, ifcond))
 
 
-(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
+(input_file, output_dir, do_c, do_h, prefix, includes, dummy) = \
+        parse_command_line()
 
 c_comment = '''
 /*
@@ -218,13 +219,14 @@ fdef.write(mcgen('''
                  prefix=prefix))
 
 fdecl.write(mcgen('''
+%(includes)s
 #include "qapi/error.h"
 #include "qapi/util.h"
 #include "qapi/qmp/qdict.h"
 #include "%(prefix)sqapi-types.h"
 
 ''',
-                  prefix=prefix))
+                  includes=includes, prefix=prefix))
 
 event_enum_name = c_name(prefix + 'QAPIEvent', protect=False)
 
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index d6194ff702..f9abd83490 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -192,7 +192,7 @@ const QLitObject %(c_name)s = %(c_string)s;
 # We normally mask them, because they're not QMP wire ABI
 opt_unmask = False
 
-(input_file, output_dir, do_c, do_h, prefix, opts) = \
+(input_file, output_dir, do_c, do_h, prefix, includes, opts) = \
     parse_command_line('u', ['unmask-non-abi-names'])
 
 for o, a in opts:
@@ -235,10 +235,11 @@ fdef.write(mcgen('''
                  prefix=prefix))
 
 fdecl.write(mcgen('''
+%(includes)s
 #include "qemu/osdep.h"
 #include "qapi/qmp/qlit.h"
 
-'''))
+''', includes=includes))
 
 schema = QAPISchema(input_file)
 gen = QAPISchemaGenIntrospectVisitor(opt_unmask)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 312685c295..2b46a7e17f 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -266,7 +266,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
 # QAPISchemaGenTypeVisitor.visit_end().
 do_builtins = False
 
-(input_file, output_dir, do_c, do_h, prefix, opts) = \
+(input_file, output_dir, do_c, do_h, prefix, includes, opts) = \
     parse_command_line('b', ['builtins'])
 
 for o, a in opts:
@@ -317,7 +317,9 @@ fdef.write(mcgen('''
 
 fdecl.write(mcgen('''
 #include "qapi/util.h"
-'''))
+%(includes)s
+''',
+                  includes=includes))
 
 schema = QAPISchema(input_file)
 gen = QAPISchemaGenTypeVisitor()
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 369e1f927d..1e173d3cd7 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -338,7 +338,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
 # QAPISchemaGenVisitVisitor.visit_end().
 do_builtins = False
 
-(input_file, output_dir, do_c, do_h, prefix, opts) = \
+(input_file, output_dir, do_c, do_h, prefix, includes, opts) = \
     parse_command_line('b', ['builtins'])
 
 for o, a in opts:
@@ -387,12 +387,13 @@ fdef.write(mcgen('''
                  prefix=prefix))
 
 fdecl.write(mcgen('''
+%(includes)s
 #include "qapi/visitor.h"
 #include "qapi/qmp/qerror.h"
 #include "%(prefix)sqapi-types.h"
 
 ''',
-                  prefix=prefix))
+                  includes=includes, prefix=prefix))
 
 schema = QAPISchema(input_file)
 gen = QAPISchemaGenVisitVisitor()
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (39 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 40/50] qapi: add -i/--include filename.h Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-14 13:54   ` Markus Armbruster
  2017-12-14 16:08   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 42/50] qapi: add a -u/--unit option to specify which unit to visit Marc-André Lureau
                   ` (10 subsequent siblings)
  51 siblings, 2 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Add a pragma that allows to tag the following expressions with a unit
name. By default, an expression has no unit name.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py              | 9 ++++++++-
 docs/devel/qapi-code-gen.txt | 3 +++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index eb4ffdc06d..1d0defd638 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -279,10 +279,12 @@ class QAPISchemaParser(object):
         self.docs = []
         self.cur_doc = None
         self.accept()
+        self.unit = None
 
         while self.tok is not None:
             info = {'file': fname, 'line': self.line,
-                    'parent': self.incl_info}
+                    'parent': self.incl_info,
+                    'unit': self.unit}
             if self.tok == '#':
                 self.reject_expr_doc()
                 self.cur_doc = self.get_doc(info)
@@ -371,6 +373,11 @@ class QAPISchemaParser(object):
                                    "Pragma name-case-whitelist must be"
                                    " a list of strings")
             name_case_whitelist = value
+        elif name == 'unit':
+            if not isinstance(value, str):
+                raise QAPISemError(info,
+                                   "Pragma 'unit' must be string")
+            self.unit = value
         else:
             raise QAPISemError(info, "Unknown pragma '%s'" % name)
 
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 24fc6f74ee..37a27cd9d7 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -326,6 +326,9 @@ violate the rules on permitted return types.  Default is none.
 Pragma 'name-case-whitelist' takes a list of names that may violate
 rules on use of upper- vs. lower-case letters.  Default is none.
 
+Pragma 'unit' takes a string value. It will set the unit name for the
+following expressions in the schema. Most code generator can filter
+based on a unit name. Default is none.
 
 === Struct types ===
 
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 42/50] qapi: add a -u/--unit option to specify which unit to visit
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (40 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-14 16:16   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 43/50] build-sys: move qmp-introspect per target Marc-André Lureau
                   ` (9 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

Allow to filter expressions based on unit name.

By default, only default units are processed (unspecified pragma).

'all' will include all units. Anything else will filter by unit name.

(add a FIXME to make implicit array types use the element type unit,
not the unit of the first expression using that array type. This isn't
necessary for now, and I am not sure how to best do it yet)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py      | 14 ++++++++++++--
 scripts/qapi2texi.py |  1 +
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 1d0defd638..7778585819 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -47,6 +47,9 @@ returns_whitelist = []
 # Whitelist of entities allowed to violate case conventions
 name_case_whitelist = []
 
+# Unit to consider for the visit, 'all' for all units
+visit_unit = None
+
 enum_types = {}
 struct_types = {}
 union_types = {}
@@ -1796,6 +1799,10 @@ class QAPISchema(object):
     def visit(self, visitor):
         visitor.visit_begin(self)
         for (name, entity) in sorted(self._entity_dict.items()):
+            # FIXME: implicit array types should use element type unit
+            unit = entity.info and entity.info.get('unit')
+            if visit_unit != 'all' and visit_unit != unit:
+                continue
             if visitor.visit_needed(entity):
                 entity.visit(visitor)
         visitor.visit_end()
@@ -2103,13 +2110,14 @@ def parse_command_line(extra_options='', extra_long_options=[]):
 
     try:
         opts, args = getopt.gnu_getopt(sys.argv[1:],
-            'chp:o:i:' + extra_options,
+            'chp:o:u:i:' + extra_options,
             ['source', 'header', 'prefix=', 'output-dir=',
-             'include='] + extra_long_options)
+             'unit=', 'include='] + extra_long_options)
     except getopt.GetoptError as err:
         print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
         sys.exit(1)
 
+    global visit_unit
     output_dir = ''
     prefix = ''
     do_c = False
@@ -2129,6 +2137,8 @@ def parse_command_line(extra_options='', extra_long_options=[]):
             prefix = a
         elif o in ('-o', '--output-dir'):
             output_dir = a + '/'
+        elif o in ('-u', '--unit'):
+            visit_unit = a
         elif o in ('-c', '--source'):
             do_c = True
         elif o in ('-h', '--header'):
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 4e7b1cda87..6c856d4cb7 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -293,6 +293,7 @@ def main(argv):
         print >>sys.stderr, "%s: need exactly 1 argument: SCHEMA" % argv[0]
         sys.exit(1)
 
+    qapi.visit_unit = 'all'
     schema = qapi.QAPISchema(argv[1])
     if not qapi.doc_required:
         print >>sys.stderr, ("%s: need pragma 'doc-required' "
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 43/50] build-sys: move qmp-introspect per target
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (41 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 42/50] qapi: add a -u/--unit option to specify which unit to visit Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-14 16:30   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 44/50] build-sys: add a target schema Marc-André Lureau
                   ` (8 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Michael Roth

The following patches are going to introduce per-target #ifdef, and
but the introspection data is generated only once, and must thus be
built with the target.

Drop "do_test_visitor_in_qmp_introspect(&&qmp_schema_qlit)" since it
is no longer in a common object, and covered by "query-qmp-schema
test" instead.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/test-qobject-input-visitor.c | 1 -
 Makefile.objs                      | 3 +--
 Makefile.target                    | 2 ++
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-visitor.c
index 7c1d10e274..ad4c99a4c7 100644
--- a/tests/test-qobject-input-visitor.c
+++ b/tests/test-qobject-input-visitor.c
@@ -1267,7 +1267,6 @@ static void test_visitor_in_qmp_introspect(TestInputVisitorData *data,
                                            const void *unused)
 {
     do_test_visitor_in_qmp_introspect(data, &test_qmp_schema_qlit);
-    do_test_visitor_in_qmp_introspect(data, &qmp_schema_qlit);
 }
 
 int main(int argc, char **argv)
diff --git a/Makefile.objs b/Makefile.objs
index 24a4ea08b8..f8ba6228ca 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -2,7 +2,7 @@
 # Common libraries for tools and emulators
 stub-obj-y = stubs/ crypto/
 util-obj-y = util/ qobject/ qapi/
-util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
+util-obj-y += qapi-types.o qapi-visit.o qapi-event.o
 
 chardev-obj-y = chardev/
 
@@ -77,7 +77,6 @@ common-obj-$(CONFIG_FDT) += device_tree.o
 # qapi
 
 common-obj-y += qmp-marshal.o
-common-obj-y += qmp-introspect.o
 common-obj-y += qmp.o hmp.o
 endif
 
diff --git a/Makefile.target b/Makefile.target
index 7f42c45db8..0d28ed1df0 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -157,6 +157,8 @@ endif
 
 GENERATED_FILES += hmp-commands.h hmp-commands-info.h
 
+obj-y += qmp-introspect.o
+
 endif # CONFIG_SOFTMMU
 
 # Workaround for http://gcc.gnu.org/PR55489, see configure.
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 44/50] build-sys: add a target schema
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (42 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 43/50] build-sys: move qmp-introspect per target Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-12-14 16:34   ` Markus Armbruster
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 45/50] qapi: make rtc-reset-reinjection depend on TARGET_I386 Marc-André Lureau
                   ` (7 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Dr. David Alan Gilbert, Eric Blake

This schema is going to contain target-specific commands/events &
types, that can be conditionnally guarded with poisoned defines. To
filter it out by default, set the unit name to 'target'.

And new rules to compile this unit generated files per-target.

Use the "-u all" options for the introspection schema, since it is
generated as a single file and must contain all definitions.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json |  1 +
 qapi/target.json |  3 +++
 monitor.c        |  2 ++
 Makefile         | 29 ++++++++++++++++++++++++++++-
 Makefile.target  |  2 ++
 5 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 qapi/target.json

diff --git a/qapi-schema.json b/qapi-schema.json
index f3af2cb851..42b6aebddb 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -92,6 +92,7 @@
 { 'include': 'qapi/transaction.json' }
 { 'include': 'qapi/trace.json' }
 { 'include': 'qapi/introspect.json' }
+{ 'include': 'qapi/target.json' }
 
 ##
 # = Miscellanea
diff --git a/qapi/target.json b/qapi/target.json
new file mode 100644
index 0000000000..e9644f52c2
--- /dev/null
+++ b/qapi/target.json
@@ -0,0 +1,3 @@
+# -*- Mode: Python -*-
+
+{ 'pragma': { 'unit': 'target' } }
diff --git a/monitor.c b/monitor.c
index bf8a7685bf..af4eaeca5e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -68,6 +68,7 @@
 #include "exec/exec-all.h"
 #include "qemu/log.h"
 #include "qmp-commands.h"
+#include "target-qmp-commands.h"
 #include "hmp.h"
 #include "qemu/thread.h"
 #include "block/qapi.h"
@@ -1003,6 +1004,7 @@ void monitor_init_qmp_commands(void)
 
     QTAILQ_INIT(&qmp_commands);
     qmp_init_marshal(&qmp_commands);
+    target_qmp_init_marshal(&qmp_commands);
 
     qmp_register_command(&qmp_commands, "query-qmp-schema",
                          qmp_query_qmp_schema,
diff --git a/Makefile b/Makefile
index 337a1f6f9b..7356b4e7b7 100644
--- a/Makefile
+++ b/Makefile
@@ -54,6 +54,8 @@ include $(SRC_PATH)/rules.mak
 GENERATED_FILES = qemu-version.h config-host.h qemu-options.def
 GENERATED_FILES += qmp-commands.h qapi-types.h qapi-visit.h qapi-event.h
 GENERATED_FILES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
+GENERATED_FILES += target-qmp-commands.h target-qapi-types.h target-qapi-visit.h target-qapi-event.h
+GENERATED_FILES += target-qmp-marshal.c target-qapi-types.c target-qapi-visit.c target-qapi-event.c
 GENERATED_FILES += qmp-introspect.h
 GENERATED_FILES += qmp-introspect.c
 
@@ -418,6 +420,7 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
                $(SRC_PATH)/qapi/rocker.json \
                $(SRC_PATH)/qapi/run-state.json \
                $(SRC_PATH)/qapi/sockets.json \
+               $(SRC_PATH)/qapi/target.json \
                $(SRC_PATH)/qapi/tpm.json \
                $(SRC_PATH)/qapi/trace.json \
                $(SRC_PATH)/qapi/transaction.json \
@@ -443,10 +446,34 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
 		$(gen-out-type) -o "." $<, \
 		"GEN","$@")
+
+target-qapi-types.c target-qapi-types.h :\
+$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
+		-i qapi-types.h \
+		$(gen-out-type) -p target- -u target $<, \
+		"GEN","$@")
+target-qapi-visit.c target-qapi-visit.h :\
+$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
+		-i qapi-visit.h \
+		$(gen-out-type) -p target- -u target $<, \
+		"GEN","$@")
+target-qapi-event.c target-qapi-event.h :\
+$(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
+		$(gen-out-type) -p target- -u target  $<, \
+		"GEN","$@")
+target-qmp-commands.h target-qmp-marshal.c :\
+$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
+		$(gen-out-type) -p target- -u target $<, \
+		"GEN","$@")
+
 qmp-introspect.h qmp-introspect.c :\
 $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
-		$(gen-out-type) -o "." $<, \
+		$(gen-out-type) -o "." -u all $<, \
 		"GEN","$@")
 
 QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
diff --git a/Makefile.target b/Makefile.target
index 0d28ed1df0..e44a3847d3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -157,6 +157,8 @@ endif
 
 GENERATED_FILES += hmp-commands.h hmp-commands-info.h
 
+obj-y += target-qapi-types.o target-qapi-visit.o
+obj-y += target-qapi-event.o target-qmp-marshal.o
 obj-y += qmp-introspect.o
 
 endif # CONFIG_SOFTMMU
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 45/50] qapi: make rtc-reset-reinjection depend on TARGET_I386
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (43 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 44/50] build-sys: add a target schema Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 46/50] qapi: make s390 commands depend on TARGET_S390X Marc-André Lureau
                   ` (6 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Michael S. Tsirkin,
	Paolo Bonzini, Dr. David Alan Gilbert, Eric Blake

Move rtc-reset-reinjection in target.json and make it conditional on
TARGET_I386.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json       | 18 ------------------
 qapi/target.json       | 19 +++++++++++++++++++
 hw/timer/mc146818rtc.c |  2 +-
 monitor.c              | 10 ----------
 4 files changed, 20 insertions(+), 29 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 42b6aebddb..5b689c71ad 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2919,24 +2919,6 @@
 { 'event': 'ACPI_DEVICE_OST',
      'data': { 'info': 'ACPIOSTInfo' } }
 
-##
-# @rtc-reset-reinjection:
-#
-# This command will reset the RTC interrupt reinjection backlog.
-# Can be used if another mechanism to synchronize guest time
-# is in effect, for example QEMU guest agent's guest-set-time
-# command.
-#
-# Since: 2.1
-#
-# Example:
-#
-# -> { "execute": "rtc-reset-reinjection" }
-# <- { "return": {} }
-#
-##
-{ 'command': 'rtc-reset-reinjection' }
-
 ##
 # @RTC_CHANGE:
 #
diff --git a/qapi/target.json b/qapi/target.json
index e9644f52c2..a764377ebf 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -1,3 +1,22 @@
 # -*- Mode: Python -*-
 
 { 'pragma': { 'unit': 'target' } }
+
+##
+# @rtc-reset-reinjection:
+#
+# This command will reset the RTC interrupt reinjection backlog.
+# Can be used if another mechanism to synchronize guest time
+# is in effect, for example QEMU guest agent's guest-set-time
+# command.
+#
+# Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "rtc-reset-reinjection" }
+# <- { "return": {} }
+#
+##
+{ 'command': 'rtc-reset-reinjection',
+  'if': 'defined(TARGET_I386)' }
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 82843ed03f..3a5ddd074a 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -31,7 +31,7 @@
 #include "hw/timer/mc146818rtc.h"
 #include "qapi/visitor.h"
 #include "qapi-event.h"
-#include "qmp-commands.h"
+#include "target-qmp-commands.h"
 
 #ifdef TARGET_I386
 #include "hw/i386/apic.h"
diff --git a/monitor.c b/monitor.c
index af4eaeca5e..ff93d9a9a9 100644
--- a/monitor.c
+++ b/monitor.c
@@ -971,9 +971,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
  */
 static void qmp_unregister_commands_hack(void)
 {
-#ifndef TARGET_I386
-    qmp_unregister_command(&qmp_commands, "rtc-reset-reinjection");
-#endif
 #ifndef TARGET_S390X
     qmp_unregister_command(&qmp_commands, "dump-skeys");
 #endif
@@ -4155,13 +4152,6 @@ QemuOptsList qemu_mon_opts = {
     },
 };
 
-#ifndef TARGET_I386
-void qmp_rtc_reset_reinjection(Error **errp)
-{
-    error_setg(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
-}
-#endif
-
 #ifndef TARGET_S390X
 void qmp_dump_skeys(const char *filename, Error **errp)
 {
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 46/50] qapi: make s390 commands depend on TARGET_S390X
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (44 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 45/50] qapi: make rtc-reset-reinjection depend on TARGET_I386 Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-13  7:45   ` Cornelia Huck
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 47/50] target.json: add a note about query-cpu* not being s390x-specific Marc-André Lureau
                   ` (5 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Richard Henderson,
	Alexander Graf, Cornelia Huck, Christian Borntraeger,
	Dr. David Alan Gilbert, Eric Blake, Paolo Bonzini

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json                        | 101 -------------------------------
 qapi/target.json                        | 104 ++++++++++++++++++++++++++++++++
 include/sysemu/arch_init.h              |   7 ---
 hw/s390x/s390-skeys.c                   |   2 +-
 monitor.c                               |  14 -----
 qmp.c                                   |  14 -----
 stubs/arch-query-cpu-model-baseline.c   |  12 ----
 stubs/arch-query-cpu-model-comparison.c |  12 ----
 target/s390x/cpu_models.c               |   5 +-
 stubs/Makefile.objs                     |   2 -
 10 files changed, 108 insertions(+), 165 deletions(-)
 delete mode 100644 stubs/arch-query-cpu-model-baseline.c
 delete mode 100644 stubs/arch-query-cpu-model-comparison.c

diff --git a/qapi-schema.json b/qapi-schema.json
index 5b689c71ad..b4a5f9abc5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1771,27 +1771,6 @@
 { 'command': 'query-dump-guest-memory-capability',
   'returns': 'DumpGuestMemoryCapability' }
 
-##
-# @dump-skeys:
-#
-# Dump guest's storage keys
-#
-# @filename: the path to the file to dump to
-#
-# This command is only supported on s390 architecture.
-#
-# Since: 2.5
-#
-# Example:
-#
-# -> { "execute": "dump-skeys",
-#      "arguments": { "filename": "/tmp/skeys" } }
-# <- { "return": {} }
-#
-##
-{ 'command': 'dump-skeys',
-  'data': { 'filename': 'str' } }
-
 ##
 # @object-add:
 #
@@ -2126,46 +2105,6 @@
           }
 }
 
-##
-# @query-cpu-model-comparison:
-#
-# Compares two CPU models, returning how they compare in a specific
-# configuration. The results indicates how both models compare regarding
-# runnability. This result can be used by tooling to make decisions if a
-# certain CPU model will run in a certain configuration or if a compatible
-# CPU model has to be created by baselining.
-#
-# Usually, a CPU model is compared against the maximum possible CPU model
-# of a certain configuration (e.g. the "host" model for KVM). If that CPU
-# model is identical or a subset, it will run in that configuration.
-#
-# The result returned by this command may be affected by:
-#
-# * QEMU version: CPU models may look different depending on the QEMU version.
-#   (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine-type: CPU model may look different depending on the machine-type.
-#   (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine options (including accelerator): in some architectures, CPU models
-#   may look different depending on machine and accelerator options. (Except for
-#   CPU models reported as "static" in query-cpu-definitions.)
-# * "-cpu" arguments and global properties: arguments to the -cpu option and
-#   global properties may affect expansion of CPU models. Using
-#   query-cpu-model-expansion while using these is not advised.
-#
-# Some architectures may not support comparing CPU models. s390x supports
-# comparing CPU models.
-#
-# Returns: a CpuModelBaselineInfo. Returns an error if comparing CPU models is
-#          not supported, if a model cannot be used, if a model contains
-#          an unknown cpu definition name, unknown properties or properties
-#          with wrong types.
-#
-# Since: 2.8.0
-##
-{ 'command': 'query-cpu-model-comparison',
-  'data': { 'modela': 'CpuModelInfo', 'modelb': 'CpuModelInfo' },
-  'returns': 'CpuModelCompareInfo' }
-
 ##
 # @CpuModelBaselineInfo:
 #
@@ -2178,46 +2117,6 @@
 { 'struct': 'CpuModelBaselineInfo',
   'data': { 'model': 'CpuModelInfo' } }
 
-##
-# @query-cpu-model-baseline:
-#
-# Baseline two CPU models, creating a compatible third model. The created
-# model will always be a static, migration-safe CPU model (see "static"
-# CPU model expansion for details).
-#
-# This interface can be used by tooling to create a compatible CPU model out
-# two CPU models. The created CPU model will be identical to or a subset of
-# both CPU models when comparing them. Therefore, the created CPU model is
-# guaranteed to run where the given CPU models run.
-#
-# The result returned by this command may be affected by:
-#
-# * QEMU version: CPU models may look different depending on the QEMU version.
-#   (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine-type: CPU model may look different depending on the machine-type.
-#   (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine options (including accelerator): in some architectures, CPU models
-#   may look different depending on machine and accelerator options. (Except for
-#   CPU models reported as "static" in query-cpu-definitions.)
-# * "-cpu" arguments and global properties: arguments to the -cpu option and
-#   global properties may affect expansion of CPU models. Using
-#   query-cpu-model-expansion while using these is not advised.
-#
-# Some architectures may not support baselining CPU models. s390x supports
-# baselining CPU models.
-#
-# Returns: a CpuModelBaselineInfo. Returns an error if baselining CPU models is
-#          not supported, if a model cannot be used, if a model contains
-#          an unknown cpu definition name, unknown properties or properties
-#          with wrong types.
-#
-# Since: 2.8.0
-##
-{ 'command': 'query-cpu-model-baseline',
-  'data': { 'modela': 'CpuModelInfo',
-            'modelb': 'CpuModelInfo' },
-  'returns': 'CpuModelBaselineInfo' }
-
 ##
 # @AddfdInfo:
 #
diff --git a/qapi/target.json b/qapi/target.json
index a764377ebf..3b73a9202f 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -20,3 +20,107 @@
 ##
 { 'command': 'rtc-reset-reinjection',
   'if': 'defined(TARGET_I386)' }
+
+##
+# @dump-skeys:
+#
+# Dump guest's storage keys
+#
+# @filename: the path to the file to dump to
+#
+# This command is only supported on s390 architecture.
+#
+# Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "dump-skeys",
+#      "arguments": { "filename": "/tmp/skeys" } }
+# <- { "return": {} }
+#
+##
+{ 'command': 'dump-skeys',
+  'data': { 'filename': 'str' },
+  'if': 'defined(TARGET_S390X)' }
+
+##
+# @query-cpu-model-comparison:
+#
+# Compares two CPU models, returning how they compare in a specific
+# configuration. The results indicates how both models compare regarding
+# runnability. This result can be used by tooling to make decisions if a
+# certain CPU model will run in a certain configuration or if a compatible
+# CPU model has to be created by baselining.
+#
+# Usually, a CPU model is compared against the maximum possible CPU model
+# of a certain configuration (e.g. the "host" model for KVM). If that CPU
+# model is identical or a subset, it will run in that configuration.
+#
+# The result returned by this command may be affected by:
+#
+# * QEMU version: CPU models may look different depending on the QEMU version.
+#   (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine-type: CPU model may look different depending on the machine-type.
+#   (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine options (including accelerator): in some architectures, CPU models
+#   may look different depending on machine and accelerator options. (Except for
+#   CPU models reported as "static" in query-cpu-definitions.)
+# * "-cpu" arguments and global properties: arguments to the -cpu option and
+#   global properties may affect expansion of CPU models. Using
+#   query-cpu-model-expansion while using these is not advised.
+#
+# Some architectures may not support comparing CPU models. s390x supports
+# comparing CPU models.
+#
+# Returns: a CpuModelBaselineInfo. Returns an error if comparing CPU models is
+#          not supported, if a model cannot be used, if a model contains
+#          an unknown cpu definition name, unknown properties or properties
+#          with wrong types.
+#
+# Since: 2.8.0
+##
+{ 'command': 'query-cpu-model-comparison',
+  'data': { 'modela': 'CpuModelInfo', 'modelb': 'CpuModelInfo' },
+  'returns': 'CpuModelCompareInfo',
+  'if': 'defined(TARGET_S390X)' }
+
+##
+# @query-cpu-model-baseline:
+#
+# Baseline two CPU models, creating a compatible third model. The created
+# model will always be a static, migration-safe CPU model (see "static"
+# CPU model expansion for details).
+#
+# This interface can be used by tooling to create a compatible CPU model out
+# two CPU models. The created CPU model will be identical to or a subset of
+# both CPU models when comparing them. Therefore, the created CPU model is
+# guaranteed to run where the given CPU models run.
+#
+# The result returned by this command may be affected by:
+#
+# * QEMU version: CPU models may look different depending on the QEMU version.
+#   (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine-type: CPU model may look different depending on the machine-type.
+#   (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine options (including accelerator): in some architectures, CPU models
+#   may look different depending on machine and accelerator options. (Except for
+#   CPU models reported as "static" in query-cpu-definitions.)
+# * "-cpu" arguments and global properties: arguments to the -cpu option and
+#   global properties may affect expansion of CPU models. Using
+#   query-cpu-model-expansion while using these is not advised.
+#
+# Some architectures may not support baselining CPU models. s390x supports
+# baselining CPU models.
+#
+# Returns: a CpuModelBaselineInfo. Returns an error if baselining CPU models is
+#          not supported, if a model cannot be used, if a model contains
+#          an unknown cpu definition name, unknown properties or properties
+#          with wrong types.
+#
+# Since: 2.8.0
+##
+{ 'command': 'query-cpu-model-baseline',
+  'data': { 'modela': 'CpuModelInfo',
+            'modelb': 'CpuModelInfo' },
+  'returns': 'CpuModelBaselineInfo',
+  'if': 'defined(TARGET_S390X)' }
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 8751c468ed..f193f5189b 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -35,11 +35,4 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp);
 CpuModelExpansionInfo *arch_query_cpu_model_expansion(CpuModelExpansionType type,
                                                       CpuModelInfo *mode,
                                                       Error **errp);
-CpuModelCompareInfo *arch_query_cpu_model_comparison(CpuModelInfo *modela,
-                                                     CpuModelInfo *modelb,
-                                                     Error **errp);
-CpuModelBaselineInfo *arch_query_cpu_model_baseline(CpuModelInfo *modela,
-                                                    CpuModelInfo *modelb,
-                                                    Error **errp);
-
 #endif
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index 53ad5d38d4..5af2f89994 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -11,7 +11,7 @@
 
 #include "qemu/osdep.h"
 #include "hw/boards.h"
-#include "qmp-commands.h"
+#include "target-qmp-commands.h"
 #include "hw/s390x/storage-keys.h"
 #include "qemu/error-report.h"
 #include "sysemu/kvm.h"
diff --git a/monitor.c b/monitor.c
index ff93d9a9a9..622ba3b819 100644
--- a/monitor.c
+++ b/monitor.c
@@ -971,19 +971,12 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
  */
 static void qmp_unregister_commands_hack(void)
 {
-#ifndef TARGET_S390X
-    qmp_unregister_command(&qmp_commands, "dump-skeys");
-#endif
 #ifndef TARGET_ARM
     qmp_unregister_command(&qmp_commands, "query-gic-capabilities");
 #endif
 #if !defined(TARGET_S390X) && !defined(TARGET_I386)
     qmp_unregister_command(&qmp_commands, "query-cpu-model-expansion");
 #endif
-#if !defined(TARGET_S390X)
-    qmp_unregister_command(&qmp_commands, "query-cpu-model-baseline");
-    qmp_unregister_command(&qmp_commands, "query-cpu-model-comparison");
-#endif
 #if !defined(TARGET_PPC) && !defined(TARGET_ARM) && !defined(TARGET_I386) \
     && !defined(TARGET_S390X)
     qmp_unregister_command(&qmp_commands, "query-cpu-definitions");
@@ -4152,13 +4145,6 @@ QemuOptsList qemu_mon_opts = {
     },
 };
 
-#ifndef TARGET_S390X
-void qmp_dump_skeys(const char *filename, Error **errp)
-{
-    error_setg(errp, QERR_FEATURE_DISABLED, "dump-skeys");
-}
-#endif
-
 #ifndef TARGET_ARM
 GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
 {
diff --git a/qmp.c b/qmp.c
index 90816ba283..7b6861846f 100644
--- a/qmp.c
+++ b/qmp.c
@@ -553,20 +553,6 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
     return arch_query_cpu_model_expansion(type, model, errp);
 }
 
-CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *modela,
-                                                    CpuModelInfo *modelb,
-                                                    Error **errp)
-{
-    return arch_query_cpu_model_comparison(modela, modelb, errp);
-}
-
-CpuModelBaselineInfo *qmp_query_cpu_model_baseline(CpuModelInfo *modela,
-                                                   CpuModelInfo *modelb,
-                                                   Error **errp)
-{
-    return arch_query_cpu_model_baseline(modela, modelb, errp);
-}
-
 void qmp_add_client(const char *protocol, const char *fdname,
                     bool has_skipauth, bool skipauth, bool has_tls, bool tls,
                     Error **errp)
diff --git a/stubs/arch-query-cpu-model-baseline.c b/stubs/arch-query-cpu-model-baseline.c
deleted file mode 100644
index 094ec13c2c..0000000000
--- a/stubs/arch-query-cpu-model-baseline.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "sysemu/arch_init.h"
-#include "qapi/qmp/qerror.h"
-
-CpuModelBaselineInfo *arch_query_cpu_model_baseline(CpuModelInfo *modela,
-                                                    CpuModelInfo *modelb,
-                                                    Error **errp)
-{
-    error_setg(errp, QERR_UNSUPPORTED);
-    return NULL;
-}
diff --git a/stubs/arch-query-cpu-model-comparison.c b/stubs/arch-query-cpu-model-comparison.c
deleted file mode 100644
index d5486ae980..0000000000
--- a/stubs/arch-query-cpu-model-comparison.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "sysemu/arch_init.h"
-#include "qapi/qmp/qerror.h"
-
-CpuModelCompareInfo *arch_query_cpu_model_comparison(CpuModelInfo *modela,
-                                                     CpuModelInfo *modelb,
-                                                     Error **errp)
-{
-    error_setg(errp, QERR_UNSUPPORTED);
-    return NULL;
-}
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 18cbf91d9c..5f8151925a 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -25,6 +25,7 @@
 #ifndef CONFIG_USER_ONLY
 #include "sysemu/arch_init.h"
 #endif
+#include "target-qmp-commands.h"
 
 #define CPUDEF_INIT(_type, _gen, _ec_ga, _mha_pow, _hmfai, _name, _desc) \
     {                                                                    \
@@ -562,7 +563,7 @@ static void list_add_feat(const char *name, void *opaque)
     *last = entry;
 }
 
-CpuModelCompareInfo *arch_query_cpu_model_comparison(CpuModelInfo *infoa,
+CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
                                                      CpuModelInfo *infob,
                                                      Error **errp)
 {
@@ -635,7 +636,7 @@ CpuModelCompareInfo *arch_query_cpu_model_comparison(CpuModelInfo *infoa,
     return compare_info;
 }
 
-CpuModelBaselineInfo *arch_query_cpu_model_baseline(CpuModelInfo *infoa,
+CpuModelBaselineInfo *qmp_query_cpu_model_baseline(CpuModelInfo *infoa,
                                                     CpuModelInfo *infob,
                                                     Error **errp)
 {
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 4a33495911..5419f0f995 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -1,7 +1,5 @@
 stub-obj-y += arch-query-cpu-def.o
 stub-obj-y += arch-query-cpu-model-expansion.o
-stub-obj-y += arch-query-cpu-model-comparison.o
-stub-obj-y += arch-query-cpu-model-baseline.o
 stub-obj-y += bdrv-next-monitor-owned.o
 stub-obj-y += blk-commit-all.o
 stub-obj-y += blockdev-close-all-bdrv-states.o
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 47/50] target.json: add a note about query-cpu* not being s390x-specific
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (45 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 46/50] qapi: make s390 commands depend on TARGET_S390X Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-13  7:46   ` Cornelia Huck
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 48/50] qapi: make query-gic-capabilities depend on TARGET_ARM Marc-André Lureau
                   ` (4 subsequent siblings)
  51 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Marc-André Lureau, Eric Blake

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/target.json | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/qapi/target.json b/qapi/target.json
index 3b73a9202f..12002b54d5 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -77,6 +77,9 @@
 #          an unknown cpu definition name, unknown properties or properties
 #          with wrong types.
 #
+# Note: this command isn't specific to s390x, but is only implemented
+# on this architecture currently.
+#
 # Since: 2.8.0
 ##
 { 'command': 'query-cpu-model-comparison',
@@ -117,6 +120,9 @@
 #          an unknown cpu definition name, unknown properties or properties
 #          with wrong types.
 #
+# Note: this command isn't specific to s390x, but is only implemented
+# on this architecture currently.
+#
 # Since: 2.8.0
 ##
 { 'command': 'query-cpu-model-baseline',
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 48/50] qapi: make query-gic-capabilities depend on TARGET_ARM
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (46 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 47/50] target.json: add a note about query-cpu* not being s390x-specific Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 49/50] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
                   ` (3 subsequent siblings)
  51 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Eric Blake, Peter Maydell, open list:ARM

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     | 43 -------------------------------------------
 qapi/target.json     | 45 +++++++++++++++++++++++++++++++++++++++++++++
 monitor.c            | 11 -----------
 target/arm/monitor.c |  2 +-
 4 files changed, 46 insertions(+), 55 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index b4a5f9abc5..23151506e7 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2879,49 +2879,6 @@
 ##
 { 'command': 'xen-load-devices-state', 'data': {'filename': 'str'} }
 
-##
-# @GICCapability:
-#
-# The struct describes capability for a specific GIC (Generic
-# Interrupt Controller) version. These bits are not only decided by
-# QEMU/KVM software version, but also decided by the hardware that
-# the program is running upon.
-#
-# @version:  version of GIC to be described. Currently, only 2 and 3
-#            are supported.
-#
-# @emulated: whether current QEMU/hardware supports emulated GIC
-#            device in user space.
-#
-# @kernel:   whether current QEMU/hardware supports hardware
-#            accelerated GIC device in kernel.
-#
-# Since: 2.6
-##
-{ 'struct': 'GICCapability',
-  'data': { 'version': 'int',
-            'emulated': 'bool',
-            'kernel': 'bool' } }
-
-##
-# @query-gic-capabilities:
-#
-# This command is ARM-only. It will return a list of GICCapability
-# objects that describe its capability bits.
-#
-# Returns: a list of GICCapability objects.
-#
-# Since: 2.6
-#
-# Example:
-#
-# -> { "execute": "query-gic-capabilities" }
-# <- { "return": [{ "version": 2, "emulated": true, "kernel": false },
-#                 { "version": 3, "emulated": false, "kernel": true } ] }
-#
-##
-{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
-
 ##
 # @CpuInstanceProperties:
 #
diff --git a/qapi/target.json b/qapi/target.json
index 12002b54d5..daf4bfa8f1 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -130,3 +130,48 @@
             'modelb': 'CpuModelInfo' },
   'returns': 'CpuModelBaselineInfo',
   'if': 'defined(TARGET_S390X)' }
+
+##
+# @GICCapability:
+#
+# The struct describes capability for a specific GIC (Generic
+# Interrupt Controller) version. These bits are not only decided by
+# QEMU/KVM software version, but also decided by the hardware that
+# the program is running upon.
+#
+# @version:  version of GIC to be described. Currently, only 2 and 3
+#            are supported.
+#
+# @emulated: whether current QEMU/hardware supports emulated GIC
+#            device in user space.
+#
+# @kernel:   whether current QEMU/hardware supports hardware
+#            accelerated GIC device in kernel.
+#
+# Since: 2.6
+##
+{ 'struct': 'GICCapability',
+  'data': { 'version': 'int',
+            'emulated': 'bool',
+            'kernel': 'bool' },
+  'if': 'defined(TARGET_ARM)' }
+
+##
+# @query-gic-capabilities:
+#
+# This command is ARM-only. It will return a list of GICCapability
+# objects that describe its capability bits.
+#
+# Returns: a list of GICCapability objects.
+#
+# Since: 2.6
+#
+# Example:
+#
+# -> { "execute": "query-gic-capabilities" }
+# <- { "return": [{ "version": 2, "emulated": true, "kernel": false },
+#                 { "version": 3, "emulated": false, "kernel": true } ] }
+#
+##
+{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'],
+  'if': 'defined(TARGET_ARM)' }
diff --git a/monitor.c b/monitor.c
index 622ba3b819..acf4721b30 100644
--- a/monitor.c
+++ b/monitor.c
@@ -971,9 +971,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
  */
 static void qmp_unregister_commands_hack(void)
 {
-#ifndef TARGET_ARM
-    qmp_unregister_command(&qmp_commands, "query-gic-capabilities");
-#endif
 #if !defined(TARGET_S390X) && !defined(TARGET_I386)
     qmp_unregister_command(&qmp_commands, "query-cpu-model-expansion");
 #endif
@@ -4145,14 +4142,6 @@ QemuOptsList qemu_mon_opts = {
     },
 };
 
-#ifndef TARGET_ARM
-GICCapabilityList *qmp_query_gic_capabilities(Error **errp)
-{
-    error_setg(errp, QERR_FEATURE_DISABLED, "query-gic-capabilities");
-    return NULL;
-}
-#endif
-
 HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp)
 {
     MachineState *ms = MACHINE(qdev_get_machine());
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index 299cb80ae7..a46b0f98b4 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -20,7 +20,7 @@
  * THE SOFTWARE.
  */
 #include "qemu/osdep.h"
-#include "qmp-commands.h"
+#include "target-qmp-commands.h"
 #include "hw/boards.h"
 #include "kvm_arm.h"
 
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 49/50] qapi: make query-cpu-model-expansion depend on s390 or x86
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (47 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 48/50] qapi: make query-gic-capabilities depend on TARGET_ARM Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-12 17:40   ` Eduardo Habkost
  2017-09-13  7:47   ` Cornelia Huck
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 50/50] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
                   ` (2 subsequent siblings)
  51 siblings, 2 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Eric Blake, Paolo Bonzini, Richard Henderson, Eduardo Habkost,
	Alexander Graf

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json                       | 38 ---------------------------------
 qapi/target.json                       | 39 ++++++++++++++++++++++++++++++++++
 include/sysemu/arch_init.h             |  3 ---
 monitor.c                              |  3 ---
 qmp.c                                  |  7 ------
 stubs/arch-query-cpu-model-expansion.c | 12 -----------
 target/i386/cpu.c                      |  3 ++-
 target/s390x/cpu_models.c              |  2 +-
 stubs/Makefile.objs                    |  1 -
 9 files changed, 42 insertions(+), 66 deletions(-)
 delete mode 100644 stubs/arch-query-cpu-model-expansion.c

diff --git a/qapi-schema.json b/qapi-schema.json
index 23151506e7..98525c7702 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2020,44 +2020,6 @@
   'data': { 'model': 'CpuModelInfo' } }
 
 
-##
-# @query-cpu-model-expansion:
-#
-# Expands a given CPU model (or a combination of CPU model + additional options)
-# to different granularities, allowing tooling to get an understanding what a
-# specific CPU model looks like in QEMU under a certain configuration.
-#
-# This interface can be used to query the "host" CPU model.
-#
-# The data returned by this command may be affected by:
-#
-# * QEMU version: CPU models may look different depending on the QEMU version.
-#   (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine-type: CPU model  may look different depending on the machine-type.
-#   (Except for CPU models reported as "static" in query-cpu-definitions.)
-# * machine options (including accelerator): in some architectures, CPU models
-#   may look different depending on machine and accelerator options. (Except for
-#   CPU models reported as "static" in query-cpu-definitions.)
-# * "-cpu" arguments and global properties: arguments to the -cpu option and
-#   global properties may affect expansion of CPU models. Using
-#   query-cpu-model-expansion while using these is not advised.
-#
-# Some architectures may not support all expansion types. s390x supports
-# "full" and "static".
-#
-# Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is
-#          not supported, if the model cannot be expanded, if the model contains
-#          an unknown CPU definition name, unknown properties or properties
-#          with a wrong type. Also returns an error if an expansion type is
-#          not supported.
-#
-# Since: 2.8.0
-##
-{ 'command': 'query-cpu-model-expansion',
-  'data': { 'type': 'CpuModelExpansionType',
-            'model': 'CpuModelInfo' },
-  'returns': 'CpuModelExpansionInfo' }
-
 ##
 # @CpuModelCompareResult:
 #
diff --git a/qapi/target.json b/qapi/target.json
index daf4bfa8f1..d9f3bce22f 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -175,3 +175,42 @@
 ##
 { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'],
   'if': 'defined(TARGET_ARM)' }
+
+##
+# @query-cpu-model-expansion:
+#
+# Expands a given CPU model (or a combination of CPU model + additional options)
+# to different granularities, allowing tooling to get an understanding what a
+# specific CPU model looks like in QEMU under a certain configuration.
+#
+# This interface can be used to query the "host" CPU model.
+#
+# The data returned by this command may be affected by:
+#
+# * QEMU version: CPU models may look different depending on the QEMU version.
+#   (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine-type: CPU model  may look different depending on the machine-type.
+#   (Except for CPU models reported as "static" in query-cpu-definitions.)
+# * machine options (including accelerator): in some architectures, CPU models
+#   may look different depending on machine and accelerator options. (Except for
+#   CPU models reported as "static" in query-cpu-definitions.)
+# * "-cpu" arguments and global properties: arguments to the -cpu option and
+#   global properties may affect expansion of CPU models. Using
+#   query-cpu-model-expansion while using these is not advised.
+#
+# Some architectures may not support all expansion types. s390x supports
+# "full" and "static".
+#
+# Returns: a CpuModelExpansionInfo. Returns an error if expanding CPU models is
+#          not supported, if the model cannot be expanded, if the model contains
+#          an unknown CPU definition name, unknown properties or properties
+#          with a wrong type. Also returns an error if an expansion type is
+#          not supported.
+#
+# Since: 2.8.0
+##
+{ 'command': 'query-cpu-model-expansion',
+  'data': { 'type': 'CpuModelExpansionType',
+            'model': 'CpuModelInfo' },
+  'returns': 'CpuModelExpansionInfo',
+  'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index f193f5189b..08a607b89b 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -32,7 +32,4 @@ int kvm_available(void);
 int xen_available(void);
 
 CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp);
-CpuModelExpansionInfo *arch_query_cpu_model_expansion(CpuModelExpansionType type,
-                                                      CpuModelInfo *mode,
-                                                      Error **errp);
 #endif
diff --git a/monitor.c b/monitor.c
index acf4721b30..24680f37a6 100644
--- a/monitor.c
+++ b/monitor.c
@@ -971,9 +971,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
  */
 static void qmp_unregister_commands_hack(void)
 {
-#if !defined(TARGET_S390X) && !defined(TARGET_I386)
-    qmp_unregister_command(&qmp_commands, "query-cpu-model-expansion");
-#endif
 #if !defined(TARGET_PPC) && !defined(TARGET_ARM) && !defined(TARGET_I386) \
     && !defined(TARGET_S390X)
     qmp_unregister_command(&qmp_commands, "query-cpu-definitions");
diff --git a/qmp.c b/qmp.c
index 7b6861846f..afa266ec1e 100644
--- a/qmp.c
+++ b/qmp.c
@@ -546,13 +546,6 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
     return arch_query_cpu_definitions(errp);
 }
 
-CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
-                                                     CpuModelInfo *model,
-                                                     Error **errp)
-{
-    return arch_query_cpu_model_expansion(type, model, errp);
-}
-
 void qmp_add_client(const char *protocol, const char *fdname,
                     bool has_skipauth, bool skipauth, bool has_tls, bool tls,
                     Error **errp)
diff --git a/stubs/arch-query-cpu-model-expansion.c b/stubs/arch-query-cpu-model-expansion.c
deleted file mode 100644
index ae7cf554d1..0000000000
--- a/stubs/arch-query-cpu-model-expansion.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "sysemu/arch_init.h"
-#include "qapi/qmp/qerror.h"
-
-CpuModelExpansionInfo *arch_query_cpu_model_expansion(CpuModelExpansionType type,
-                                                      CpuModelInfo *mode,
-                                                      Error **errp)
-{
-    error_setg(errp, QERR_UNSUPPORTED);
-    return NULL;
-}
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 69676e13e1..f8719cb2de 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -36,6 +36,7 @@
 #include "qapi/visitor.h"
 #include "qom/qom-qobject.h"
 #include "sysemu/arch_init.h"
+#include "target-qmp-commands.h"
 
 #if defined(CONFIG_KVM)
 #include <linux/kvm_para.h>
@@ -2618,7 +2619,7 @@ out:
 }
 
 CpuModelExpansionInfo *
-arch_query_cpu_model_expansion(CpuModelExpansionType type,
+qmp_query_cpu_model_expansion(CpuModelExpansionType type,
                                                       CpuModelInfo *model,
                                                       Error **errp)
 {
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 5f8151925a..872dc78455 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -524,7 +524,7 @@ static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
     }
 }
 
-CpuModelExpansionInfo *arch_query_cpu_model_expansion(CpuModelExpansionType type,
+CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
                                                       CpuModelInfo *model,
                                                       Error **errp)
 {
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 5419f0f995..8d024a2b71 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -1,5 +1,4 @@
 stub-obj-y += arch-query-cpu-def.o
-stub-obj-y += arch-query-cpu-model-expansion.o
 stub-obj-y += bdrv-next-monitor-owned.o
 stub-obj-y += blk-commit-all.o
 stub-obj-y += blockdev-close-all-bdrv-states.o
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* [Qemu-devel] [PATCH v3 50/50] qapi: make query-cpu-definitions depend on specific targets
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (48 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 49/50] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
@ 2017-09-11 11:06 ` Marc-André Lureau
  2017-09-12 17:45   ` Eduardo Habkost
  2017-09-13  7:48   ` Cornelia Huck
  2017-09-11 11:54 ` [Qemu-devel] [PATCH v3 00/50] Hi, no-reply
  2017-12-18 13:14 ` Markus Armbruster
  51 siblings, 2 replies; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-11 11:06 UTC (permalink / raw)
  To: qemu-devel
  Cc: armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Eric Blake, Paolo Bonzini, Peter Maydell, Richard Henderson,
	Eduardo Habkost, David Gibson, Alexander Graf, open list:ARM,
	open list:PowerPC

It depends on TARGET_PPC || TARGET_ARM || TARGET_I386 || TARGET_S390X.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json            | 11 -----------
 qapi/target.json            | 12 ++++++++++++
 include/sysemu/arch_init.h  |  1 -
 monitor.c                   | 22 ----------------------
 qmp.c                       |  5 -----
 stubs/arch-query-cpu-def.c  | 10 ----------
 target/arm/helper.c         |  3 ++-
 target/i386/cpu.c           |  2 +-
 target/ppc/translate_init.c |  3 ++-
 target/s390x/cpu_models.c   |  2 +-
 stubs/Makefile.objs         |  1 -
 11 files changed, 18 insertions(+), 54 deletions(-)
 delete mode 100644 stubs/arch-query-cpu-def.c

diff --git a/qapi-schema.json b/qapi-schema.json
index 98525c7702..975f2fd30f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1945,17 +1945,6 @@
   'data': { 'name': 'str', '*migration-safe': 'bool', 'static': 'bool',
             '*unavailable-features': [ 'str' ], 'typename': 'str' } }
 
-##
-# @query-cpu-definitions:
-#
-# Return a list of supported virtual CPU definitions
-#
-# Returns: a list of CpuDefInfo
-#
-# Since: 1.2.0
-##
-{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
-
 ##
 # @CpuModelInfo:
 #
diff --git a/qapi/target.json b/qapi/target.json
index d9f3bce22f..e06c9e3ed7 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -214,3 +214,15 @@
             'model': 'CpuModelInfo' },
   'returns': 'CpuModelExpansionInfo',
   'if': 'defined(TARGET_S390X) || defined(TARGET_I386)' }
+
+##
+# @query-cpu-definitions:
+#
+# Return a list of supported virtual CPU definitions
+#
+# Returns: a list of CpuDefInfo
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'],
+  'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X)' }
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 08a607b89b..e9721b9ce8 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -31,5 +31,4 @@ extern const uint32_t arch_type;
 int kvm_available(void);
 int xen_available(void);
 
-CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp);
 #endif
diff --git a/monitor.c b/monitor.c
index 24680f37a6..00fb1bbf4e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -957,26 +957,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
     *ret_data = qobject_from_qlit(&qmp_schema_qlit);
 }
 
-/*
- * We used to define commands in qmp-commands.hx in addition to the
- * QAPI schema.  This permitted defining some of them only in certain
- * configurations.  query-commands has always reflected that (good,
- * because it lets QMP clients figure out what's actually available),
- * while query-qmp-schema never did (not so good).  This function is a
- * hack to keep the configuration-specific commands defined exactly as
- * before, even though qmp-commands.hx is gone.
- *
- * FIXME Educate the QAPI schema on configuration-specific commands,
- * and drop this hack.
- */
-static void qmp_unregister_commands_hack(void)
-{
-#if !defined(TARGET_PPC) && !defined(TARGET_ARM) && !defined(TARGET_I386) \
-    && !defined(TARGET_S390X)
-    qmp_unregister_command(&qmp_commands, "query-cpu-definitions");
-#endif
-}
-
 void monitor_init_qmp_commands(void)
 {
     /*
@@ -998,8 +978,6 @@ void monitor_init_qmp_commands(void)
     qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
                          QCO_NO_OPTIONS);
 
-    qmp_unregister_commands_hack();
-
     QTAILQ_INIT(&qmp_cap_negotiation_commands);
     qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
                          qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
diff --git a/qmp.c b/qmp.c
index afa266ec1e..d57ccf1251 100644
--- a/qmp.c
+++ b/qmp.c
@@ -541,11 +541,6 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
     return prop_list;
 }
 
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
-{
-    return arch_query_cpu_definitions(errp);
-}
-
 void qmp_add_client(const char *protocol, const char *fdname,
                     bool has_skipauth, bool skipauth, bool has_tls, bool tls,
                     Error **errp)
diff --git a/stubs/arch-query-cpu-def.c b/stubs/arch-query-cpu-def.c
deleted file mode 100644
index cefe4beb82..0000000000
--- a/stubs/arch-query-cpu-def.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "sysemu/arch_init.h"
-#include "qapi/qmp/qerror.h"
-
-CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
-{
-    error_setg(errp, QERR_UNSUPPORTED);
-    return NULL;
-}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 329e5178d8..b3ea771fcd 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -15,6 +15,7 @@
 #include <zlib.h> /* For crc32 */
 #include "exec/semihost.h"
 #include "sysemu/kvm.h"
+#include "target-qmp-commands.h"
 
 #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
 
@@ -5327,7 +5328,7 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
     *cpu_list = entry;
 }
 
-CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 {
     CpuDefinitionInfoList *cpu_list = NULL;
     GSList *list;
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index f8719cb2de..9cd1dee1a5 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -2363,7 +2363,7 @@ static void x86_cpu_definition_entry(gpointer data, gpointer user_data)
     *cpu_list = entry;
 }
 
-CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 {
     CpuDefinitionInfoList *cpu_list = NULL;
     GSList *list = get_sorted_cpu_model_list();
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index c827d1e388..680352f953 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -35,6 +35,7 @@
 #include "mmu-book3s-v3.h"
 #include "sysemu/qtest.h"
 #include "qemu/cutils.h"
+#include "target-qmp-commands.h"
 
 //#define PPC_DUMP_CPU
 //#define PPC_DEBUG_SPR
@@ -10415,7 +10416,7 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data)
     *first = entry;
 }
 
-CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 {
     CpuDefinitionInfoList *cpu_list = NULL;
     GSList *list;
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 872dc78455..26c9fff79c 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -390,7 +390,7 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
     *cpu_list = entry;
 }
 
-CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 {
     struct CpuDefinitionInfoListData list_data = {
         .list = NULL,
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 8d024a2b71..22e9197dcd 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -1,4 +1,3 @@
-stub-obj-y += arch-query-cpu-def.o
 stub-obj-y += bdrv-next-monitor-owned.o
 stub-obj-y += blk-commit-all.o
 stub-obj-y += blockdev-close-all-bdrv-states.o
-- 
2.14.1.146.gd35faa819

^ permalink raw reply related	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/50] Hi,
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (49 preceding siblings ...)
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 50/50] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
@ 2017-09-11 11:54 ` no-reply
  2017-12-18 13:14 ` Markus Armbruster
  51 siblings, 0 replies; 118+ messages in thread
From: no-reply @ 2017-09-11 11:54 UTC (permalink / raw)
  To: marcandre.lureau; +Cc: famz, qemu-devel, armbru

Hi,

This series failed automatic build test. Please find the testing commands and
their output below. If you have docker installed, you can probably reproduce it
locally.

Subject: [Qemu-devel] [PATCH v3 00/50] Hi,
Message-id: 20170911110623.24981-1-marcandre.lureau@redhat.com
Type: series

=== TEST SCRIPT BEGIN ===
#!/bin/bash
set -e
git submodule update --init dtc
# Let docker tests dump environment info
export SHOW_ENV=1
export J=8
time make docker-test-quick@centos6
time make docker-test-build@min-glib
time make docker-test-mingw@fedora
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
1d8781c86a qapi: make query-cpu-definitions depend on specific targets
c1814694c2 qapi: make query-cpu-model-expansion depend on s390 or x86
bd74091ade qapi: make query-gic-capabilities depend on TARGET_ARM
1d28b98dd1 target.json: add a note about query-cpu* not being s390x-specific
c7b9cba7dd qapi: make s390 commands depend on TARGET_S390X
b131645e5f qapi: make rtc-reset-reinjection depend on TARGET_I386
960aaa74bb build-sys: add a target schema
e3f318c8c3 build-sys: move qmp-introspect per target
71eab793c2 qapi: add a -u/--unit option to specify which unit to visit
9d165fe81e qapi: add a 'unit' pragma
e7ea04e24b qapi: add -i/--include filename.h
fbf22f44fa qapi-commands: don't initialize command list in qmp_init_marshall()
6def7fd06b qapi: add conditions to REPLICATION type/commands on the schema
043aba6677 qapi: add conditions to SPICE type/commands/events on the schema
cd14f015e5 qapi: add conditions to VNC type/commands/events on the schema
0aa323bee5 qapi2texi: add condition to variants
2b93c585fc qapi2texi: add 'If:' condition to struct members
bb70e84669 qapi2texi: add 'If:' condition to enum values
fd7b62cdac qapi2texi: add 'If:' section to generated documentation
44b2c49aa0 docs: document schema configuration
1cac828e3b qapi: add #if conditions to generated alternate variants
b8c8b93c51 qapi: add tests for invalid alternate
7594ba7d28 qapi: add 'if' to alternate variant
25e10a0b8a qapi: add #if conditions to generated variants
bd9efd8521 qapi: add 'if' on union variants
e82ba63f9d qapi: add #if conditions to generated struct members
cff07c1587 qapi: add some struct member tests
fd66601eec qapi: add 'if' to struct members and implicit objects members
c75e5f0c86 tests: add some enum members tests
450301d6d6 qapi: add #if conditions on generated enum members
be66ae92a3 qapi-event: add 'if' condition to generated enum
c248455099 qapi: add 'if' to enum members
ec649c084c qapi: change enum visitor to take QAPISchemaMember
a3635c5ed0 qapi: do not define enumeration value explicitely
a3de6080f9 qapi-types: add #if conditions to types & visitors
bf00d931ab qapi-types: refactor variants handling
2620d8539e qapi-event: add #if conditions to events
9afa67c39b qapi-commands: add #if conditions to commands
6016203f71 qapi-introspect: add preprocessor conditions to generated QLit
1d1970308c qapi-introspect: modify to_qlit() to generate #if code
10a53e0e87 qapi-introspect: modify to_qlit() to append ', ' on level > 0
8c1cf63678 qapi: add #if/#endif helpers
8029ce5875 qapi: mcgen() shouldn't indent # lines
1780e303b8 qapi: add 'ifcond' to visitor methods
dd93a5bdb8 qapi: pass 'if' condition into QAPISchemaEntity objects
b2df076279 qapi: add tests for invalid 'if'
186e9297f0 qapi: add 'if' to top-level expressions
0032b622c7 qapi2texi: minor python code simplification
347ba5193c qapi: generate a literal qobject for introspection
150a7e19aa qlit: add qobject_from_qlit()

=== OUTPUT BEGIN ===
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into '/var/tmp/patchew-tester-tmp-g9aaw526/src/dtc'...
Submodule path 'dtc': checked out '558cd81bdd432769b59bff01240c44f82cfb1a9d'
  BUILD   centos6
make[1]: Entering directory '/var/tmp/patchew-tester-tmp-g9aaw526/src'
  ARCHIVE qemu.tgz
  ARCHIVE dtc.tgz
  COPY    RUNNER
    RUN test-quick in qemu:centos6 
Packages installed:
SDL-devel-1.2.14-7.el6_7.1.x86_64
bison-2.4.1-5.el6.x86_64
bzip2-devel-1.0.5-7.el6_0.x86_64
ccache-3.1.6-2.el6.x86_64
csnappy-devel-0-6.20150729gitd7bc683.el6.x86_64
flex-2.5.35-9.el6.x86_64
gcc-4.4.7-18.el6.x86_64
git-1.7.1-8.el6.x86_64
glib2-devel-2.28.8-9.el6.x86_64
libepoxy-devel-1.2-3.el6.x86_64
libfdt-devel-1.4.0-1.el6.x86_64
librdmacm-devel-1.0.21-0.el6.x86_64
lzo-devel-2.03-3.1.el6_5.1.x86_64
make-3.81-23.el6.x86_64
mesa-libEGL-devel-11.0.7-4.el6.x86_64
mesa-libgbm-devel-11.0.7-4.el6.x86_64
package g++ is not installed
pixman-devel-0.32.8-1.el6.x86_64
spice-glib-devel-0.26-8.el6.x86_64
spice-server-devel-0.12.4-16.el6.x86_64
tar-1.23-15.el6_8.x86_64
vte-devel-0.25.1-9.el6.x86_64
xen-devel-4.6.3-15.el6.x86_64
zlib-devel-1.2.3-29.el6.x86_64

Environment variables:
PACKAGES=bison     bzip2-devel     ccache     csnappy-devel     flex     g++     gcc     git     glib2-devel     libepoxy-devel     libfdt-devel     librdmacm-devel     lzo-devel     make     mesa-libEGL-devel     mesa-libgbm-devel     pixman-devel     SDL-devel     spice-glib-devel     spice-server-devel     tar     vte-devel     xen-devel     zlib-devel
HOSTNAME=b98b51bd7e45
TERM=xterm
MAKEFLAGS= -j8
HISTSIZE=1000
J=8
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
MAIL=/var/spool/mail/root
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
LANG=en_US.UTF-8
TARGET_LIST=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
FEATURES= dtc
DEBUG=
G_BROKEN_FILENAMES=1
CCACHE_HASHDIR=
_=/usr/bin/env

Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/var/tmp/qemu-build/install
No C++ compiler available; disabling C++ specific optional code
Install prefix    /var/tmp/qemu-build/install
BIOS directory    /var/tmp/qemu-build/install/share/qemu
binary directory  /var/tmp/qemu-build/install/bin
library directory /var/tmp/qemu-build/install/lib
module directory  /var/tmp/qemu-build/install/lib/qemu
libexec directory /var/tmp/qemu-build/install/libexec
include directory /var/tmp/qemu-build/install/include
config directory  /var/tmp/qemu-build/install/etc
local state directory   /var/tmp/qemu-build/install/var
Manual directory  /var/tmp/qemu-build/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path       /tmp/qemu-test/src
C compiler        cc
Host C compiler   cc
C++ compiler      
Objective-C compiler cc
ARFLAGS           rv
CFLAGS            -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g 
QEMU_CFLAGS       -I/usr/include/pixman-1   -I$(SRC_PATH)/dtc/libfdt -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include   -DNCURSES_WIDECHAR   -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv  -Wendif-labels -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-all  -I/usr/include/libpng12   -I/usr/include/libdrm     -I/usr/include/spice-server -I/usr/include/cacard -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/nss3 -I/usr/include/nspr4 -I/usr/include/spice-1   -I/usr/include/cacard -I/usr/include/nss3 -I/usr/include/nspr4  
LDFLAGS           -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g 
make              make
install           install
python            python -B
smbd              /usr/sbin/smbd
module support    no
host CPU          x86_64
host big endian   no
target list       x86_64-softmmu aarch64-softmmu
gprof enabled     no
sparse enabled    no
strip binaries    yes
profiler          no
static build      no
pixman            system
SDL support       yes (1.2.14)
GTK support       yes (2.24.23)
GTK GL support    no
VTE support       yes (0.25.1)
TLS priority      NORMAL
GNUTLS support    no
GNUTLS rnd        no
libgcrypt         no
libgcrypt kdf     no
nettle            no 
nettle kdf        no
libtasn1          no
curses support    yes
virgl support     no
curl support      no
mingw32 support   no
Audio drivers     oss
Block whitelist (rw) 
Block whitelist (ro) 
VirtFS support    no
VNC support       yes
VNC SASL support  no
VNC JPEG support  yes
VNC PNG support   yes
xen support       yes
xen ctrl version  40600
pv dom build      no
brlapi support    no
bluez  support    no
Documentation     no
PIE               yes
vde support       no
netmap support    no
Linux AIO support no
ATTR/XATTR support yes
Install blobs     yes
KVM support       yes
HAX support       no
TCG support       yes
TCG debug enabled no
TCG interpreter   no
RDMA support      yes
fdt support       yes
preadv support    yes
fdatasync         yes
madvise           yes
posix_madvise     yes
libcap-ng support no
vhost-net support yes
vhost-scsi support yes
vhost-vsock support yes
vhost-user support yes
Trace backends    log
spice support     yes (0.12.6/0.12.4)
rbd support       no
xfsctl support    no
smartcard support yes
libusb            no
usb net redir     no
OpenGL support    yes
OpenGL dmabufs    no
libiscsi support  no
libnfs support    no
build guest agent yes
QGA VSS support   no
QGA w32 disk info no
QGA MSI support   no
seccomp support   no
coroutine backend ucontext
coroutine pool    yes
debug stack usage no
crypto afalg      no
GlusterFS support no
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   no
TPM passthrough   yes
QOM debugging     yes
Live block migration yes
lzo support       yes
snappy support    no
bzip2 support     yes
NUMA host support no
tcmalloc support  no
jemalloc support  no
avx2 optimization no
replication support yes
VxHS block device no
mkdir -p dtc/libfdt
mkdir -p dtc/tests
  GEN     x86_64-softmmu/config-devices.mak.tmp
  GEN     aarch64-softmmu/config-devices.mak.tmp
  GEN     qemu-options.def
  GEN     config-host.h
  GEN     qmp-commands.h
  GEN     qapi-types.h
  GEN     qapi-visit.h
Traceback (most recent call last):
  File "/tmp/qemu-test/src/scripts/qapi-commands.py", line 15, in <module>
    from qapi import *
  File "/tmp/qemu-test/src/scripts/qapi.py", line 714
    check_unknown_keys(info, value, {'type', 'if'})
                                           ^
SyntaxError: invalid syntax
  GEN     qapi-event.h
make: *** [qmp-commands.h] Error 1
make: *** Waiting for unfinished jobs....
Traceback (most recent call last):
  File "/tmp/qemu-test/src/scripts/qapi-visit.py", line 15, in <module>
    from qapi import *
  File "/tmp/qemu-test/src/scripts/qapi.py", line 714
    check_unknown_keys(info, value, {'type', 'if'})
                                           ^
SyntaxError: invalid syntax
Traceback (most recent call last):
  File "/tmp/qemu-test/src/scripts/qapi-types.py", line 14, in <module>
    from qapi import *
  File "/tmp/qemu-test/src/scripts/qapi.py", line 714
    check_unknown_keys(info, value, {'type', 'if'})
                                           ^
SyntaxError: invalid syntax
make: *** [qapi-visit.h] Error 1
make: *** [qapi-types.h] Error 1
  GEN     aarch64-softmmu/config-devices.mak
Traceback (most recent call last):
  File "/tmp/qemu-test/src/scripts/qapi-event.py", line 14, in <module>
    from qapi import *
  File "/tmp/qemu-test/src/scripts/qapi.py", line 714
    check_unknown_keys(info, value, {'type', 'if'})
                                           ^
SyntaxError: invalid syntax
make: *** [qapi-event.h] Error 1
  GEN     x86_64-softmmu/config-devices.mak
Traceback (most recent call last):
  File "./tests/docker/docker.py", line 384, in <module>
    sys.exit(main())
  File "./tests/docker/docker.py", line 381, in main
    return args.cmdobj.run(args, argv)
  File "./tests/docker/docker.py", line 239, in run
    return Docker().run(argv, args.keep, quiet=args.quiet)
  File "./tests/docker/docker.py", line 207, in run
    quiet=quiet)
  File "./tests/docker/docker.py", line 125, in _do_check
    return subprocess.check_call(self._command + cmd, **kwargs)
  File "/usr/lib64/python2.7/subprocess.py", line 186, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['docker', 'run', '--label', 'com.qemu.instance.uuid=d7268e7a96e711e7b25b52540069c830', '-u', '0', '-t', '--rm', '--net=none', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=8', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/var/tmp/patchew-tester-tmp-g9aaw526/src/docker-src.2017-09-11-07.53.31.9321:/var/tmp/qemu:z,ro', '-v', '/root/.cache/qemu-docker-ccache:/var/tmp/ccache:z', 'qemu:centos6', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit status 2
make[1]: *** [tests/docker/Makefile.include:139: docker-run] Error 1
make[1]: Leaving directory '/var/tmp/patchew-tester-tmp-g9aaw526/src'
make: *** [tests/docker/Makefile.include:168: docker-run-test-quick@centos6] Error 2

real	1m12.628s
user	0m5.082s
sys	0m1.662s
=== OUTPUT END ===

Test command exited with code: 2


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 49/50] qapi: make query-cpu-model-expansion depend on s390 or x86
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 49/50] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
@ 2017-09-12 17:40   ` Eduardo Habkost
  2017-09-13  7:47   ` Cornelia Huck
  1 sibling, 0 replies; 118+ messages in thread
From: Eduardo Habkost @ 2017-09-12 17:40 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, armbru, Dr. David Alan Gilbert, Eric Blake,
	Paolo Bonzini, Richard Henderson, Alexander Graf

On Mon, Sep 11, 2017 at 01:06:22PM +0200, Marc-André Lureau wrote:
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>

-- 
Eduardo

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 50/50] qapi: make query-cpu-definitions depend on specific targets
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 50/50] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
@ 2017-09-12 17:45   ` Eduardo Habkost
  2017-09-13  7:48   ` Cornelia Huck
  1 sibling, 0 replies; 118+ messages in thread
From: Eduardo Habkost @ 2017-09-12 17:45 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, armbru, Dr. David Alan Gilbert, Eric Blake,
	Paolo Bonzini, Peter Maydell, Richard Henderson, David Gibson,
	Alexander Graf, open list:ARM, open list:PowerPC

On Mon, Sep 11, 2017 at 01:06:23PM +0200, Marc-André Lureau wrote:
> It depends on TARGET_PPC || TARGET_ARM || TARGET_I386 || TARGET_S390X.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>

-- 
Eduardo

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 46/50] qapi: make s390 commands depend on TARGET_S390X
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 46/50] qapi: make s390 commands depend on TARGET_S390X Marc-André Lureau
@ 2017-09-13  7:45   ` Cornelia Huck
  0 siblings, 0 replies; 118+ messages in thread
From: Cornelia Huck @ 2017-09-13  7:45 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, armbru, Richard Henderson, Alexander Graf,
	Christian Borntraeger, Dr. David Alan Gilbert, Eric Blake,
	Paolo Bonzini

On Mon, 11 Sep 2017 13:06:19 +0200
Marc-André Lureau <marcandre.lureau@redhat.com> wrote:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json                        | 101 -------------------------------
>  qapi/target.json                        | 104 ++++++++++++++++++++++++++++++++
>  include/sysemu/arch_init.h              |   7 ---
>  hw/s390x/s390-skeys.c                   |   2 +-
>  monitor.c                               |  14 -----
>  qmp.c                                   |  14 -----
>  stubs/arch-query-cpu-model-baseline.c   |  12 ----
>  stubs/arch-query-cpu-model-comparison.c |  12 ----
>  target/s390x/cpu_models.c               |   5 +-
>  stubs/Makefile.objs                     |   2 -
>  10 files changed, 108 insertions(+), 165 deletions(-)
>  delete mode 100644 stubs/arch-query-cpu-model-baseline.c
>  delete mode 100644 stubs/arch-query-cpu-model-comparison.c

Together with the next patch (which makes clear that the cpu model
functions are not s390x-specific, but currently only implemented there):

Acked-by: Cornelia Huck <cohuck@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 47/50] target.json: add a note about query-cpu* not being s390x-specific
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 47/50] target.json: add a note about query-cpu* not being s390x-specific Marc-André Lureau
@ 2017-09-13  7:46   ` Cornelia Huck
  0 siblings, 0 replies; 118+ messages in thread
From: Cornelia Huck @ 2017-09-13  7:46 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, armbru

On Mon, 11 Sep 2017 13:06:20 +0200
Marc-André Lureau <marcandre.lureau@redhat.com> wrote:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi/target.json | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/qapi/target.json b/qapi/target.json
> index 3b73a9202f..12002b54d5 100644
> --- a/qapi/target.json
> +++ b/qapi/target.json
> @@ -77,6 +77,9 @@
>  #          an unknown cpu definition name, unknown properties or properties
>  #          with wrong types.
>  #
> +# Note: this command isn't specific to s390x, but is only implemented
> +# on this architecture currently.
> +#
>  # Since: 2.8.0
>  ##
>  { 'command': 'query-cpu-model-comparison',
> @@ -117,6 +120,9 @@
>  #          an unknown cpu definition name, unknown properties or properties
>  #          with wrong types.
>  #
> +# Note: this command isn't specific to s390x, but is only implemented
> +# on this architecture currently.
> +#
>  # Since: 2.8.0
>  ##
>  { 'command': 'query-cpu-model-baseline',

Acked-by: Cornelia Huck <cohuck@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 49/50] qapi: make query-cpu-model-expansion depend on s390 or x86
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 49/50] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
  2017-09-12 17:40   ` Eduardo Habkost
@ 2017-09-13  7:47   ` Cornelia Huck
  1 sibling, 0 replies; 118+ messages in thread
From: Cornelia Huck @ 2017-09-13  7:47 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Alexander Graf, Eduardo Habkost, armbru,
	Dr. David Alan Gilbert, Paolo Bonzini, Richard Henderson

On Mon, 11 Sep 2017 13:06:22 +0200
Marc-André Lureau <marcandre.lureau@redhat.com> wrote:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json                       | 38 ---------------------------------
>  qapi/target.json                       | 39 ++++++++++++++++++++++++++++++++++
>  include/sysemu/arch_init.h             |  3 ---
>  monitor.c                              |  3 ---
>  qmp.c                                  |  7 ------
>  stubs/arch-query-cpu-model-expansion.c | 12 -----------
>  target/i386/cpu.c                      |  3 ++-
>  target/s390x/cpu_models.c              |  2 +-
>  stubs/Makefile.objs                    |  1 -
>  9 files changed, 42 insertions(+), 66 deletions(-)
>  delete mode 100644 stubs/arch-query-cpu-model-expansion.c

Acked-by: Cornelia Huck <cohuck@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 50/50] qapi: make query-cpu-definitions depend on specific targets
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 50/50] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
  2017-09-12 17:45   ` Eduardo Habkost
@ 2017-09-13  7:48   ` Cornelia Huck
  1 sibling, 0 replies; 118+ messages in thread
From: Cornelia Huck @ 2017-09-13  7:48 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Peter Maydell, Eduardo Habkost, armbru,
	Dr. David Alan Gilbert, Alexander Graf, open list:ARM,
	open list:PowerPC, Paolo Bonzini, David Gibson,
	Richard Henderson

On Mon, 11 Sep 2017 13:06:23 +0200
Marc-André Lureau <marcandre.lureau@redhat.com> wrote:

> It depends on TARGET_PPC || TARGET_ARM || TARGET_I386 || TARGET_S390X.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json            | 11 -----------
>  qapi/target.json            | 12 ++++++++++++
>  include/sysemu/arch_init.h  |  1 -
>  monitor.c                   | 22 ----------------------
>  qmp.c                       |  5 -----
>  stubs/arch-query-cpu-def.c  | 10 ----------
>  target/arm/helper.c         |  3 ++-
>  target/i386/cpu.c           |  2 +-
>  target/ppc/translate_init.c |  3 ++-
>  target/s390x/cpu_models.c   |  2 +-
>  stubs/Makefile.objs         |  1 -
>  11 files changed, 18 insertions(+), 54 deletions(-)
>  delete mode 100644 stubs/arch-query-cpu-def.c

Acked-by: Cornelia Huck <cohuck@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit()
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit() Marc-André Lureau
@ 2017-09-13 13:51   ` Eric Blake
  2017-09-13 14:08     ` Marc-André Lureau
  2017-12-06 14:37   ` Markus Armbruster
  1 sibling, 1 reply; 118+ messages in thread
From: Eric Blake @ 2017-09-13 13:51 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: armbru

[-- Attachment #1: Type: text/plain, Size: 1523 bytes --]

On 09/11/2017 06:05 AM, Marc-André Lureau wrote:
> Instanciate a QObject* form a literal QLitObject.

s/Instanciate/Instantiate/
s/form/from/

> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  include/qapi/qmp/qlit.h |  2 ++
>  qobject/qlit.c          | 36 ++++++++++++++++++++++++++++++++++++
>  tests/check-qlit.c      | 26 ++++++++++++++++++++++++++
>  3 files changed, 64 insertions(+)

> +QObject *qobject_from_qlit(const QLitObject *qlit)
> +{
> +    switch (qlit->type) {
> +    case QTYPE_QNULL:
> +        return QOBJECT(qnull());
> +    case QTYPE_QNUM:
> +        return QOBJECT(qnum_from_int(qlit->value.qnum));

Is this going to work for all QNum values?

> +++ b/tests/check-qlit.c
> @@ -64,11 +64,37 @@ static void qlit_equal_qobject_test(void)
>      qobject_decref(qobj);
>  }
>  
> +static void qobject_from_qlit_test(void)
> +{
> +    QObject *obj, *qobj = qobject_from_qlit(&qlit);
> +    QDict *qdict;
> +    QList *bee;
> +
> +    qdict = qobject_to_qdict(qobj);
> +    g_assert_cmpint(qdict_get_int(qdict, "foo"), ==, 42);
> +    g_assert_cmpstr(qdict_get_str(qdict, "bar"), ==, "hello world");
> +    g_assert(qobject_type(qdict_get(qdict, "baz")) == QTYPE_QNULL);

Related to my question above - you pass because there are no floating
point values in qlit.  Is that something we want supported?

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit()
  2017-09-13 13:51   ` Eric Blake
@ 2017-09-13 14:08     ` Marc-André Lureau
  2017-12-06 14:37       ` Markus Armbruster
  0 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-09-13 14:08 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, armbru



----- Original Message -----
> On 09/11/2017 06:05 AM, Marc-André Lureau wrote:
> > Instanciate a QObject* form a literal QLitObject.
> 
> s/Instanciate/Instantiate/
> s/form/from/

thanks

> 
> > 
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  include/qapi/qmp/qlit.h |  2 ++
> >  qobject/qlit.c          | 36 ++++++++++++++++++++++++++++++++++++
> >  tests/check-qlit.c      | 26 ++++++++++++++++++++++++++
> >  3 files changed, 64 insertions(+)
> 
> > +QObject *qobject_from_qlit(const QLitObject *qlit)
> > +{
> > +    switch (qlit->type) {
> > +    case QTYPE_QNULL:
> > +        return QOBJECT(qnull());
> > +    case QTYPE_QNUM:
> > +        return QOBJECT(qnum_from_int(qlit->value.qnum));
> 
> Is this going to work for all QNum values?
> 
> > +++ b/tests/check-qlit.c
> > @@ -64,11 +64,37 @@ static void qlit_equal_qobject_test(void)
> >      qobject_decref(qobj);
> >  }
> >  
> > +static void qobject_from_qlit_test(void)
> > +{
> > +    QObject *obj, *qobj = qobject_from_qlit(&qlit);
> > +    QDict *qdict;
> > +    QList *bee;
> > +
> > +    qdict = qobject_to_qdict(qobj);
> > +    g_assert_cmpint(qdict_get_int(qdict, "foo"), ==, 42);
> > +    g_assert_cmpstr(qdict_get_str(qdict, "bar"), ==, "hello world");
> > +    g_assert(qobject_type(qdict_get(qdict, "baz")) == QTYPE_QNULL);
> 
> Related to my question above - you pass because there are no floating
> point values in qlit.  Is that something we want supported?

Markus had some remarks about it when reviewing #define QLIT_QNUM. Only i64 are supported at this point, so it's left for whoever requires it in the future.

> 
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc.           +1-919-301-3266
> Virtualization:  qemu.org | libvirt.org
> 
> 

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit()
  2017-09-13 14:08     ` Marc-André Lureau
@ 2017-12-06 14:37       ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 14:37 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: Eric Blake, qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> ----- Original Message -----
>> On 09/11/2017 06:05 AM, Marc-André Lureau wrote:
>> > Instanciate a QObject* form a literal QLitObject.
>> 
>> s/Instanciate/Instantiate/
>> s/form/from/
>
> thanks
>
>> 
>> > 
>> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> > ---
>> >  include/qapi/qmp/qlit.h |  2 ++
>> >  qobject/qlit.c          | 36 ++++++++++++++++++++++++++++++++++++
>> >  tests/check-qlit.c      | 26 ++++++++++++++++++++++++++
>> >  3 files changed, 64 insertions(+)
>> 
>> > +QObject *qobject_from_qlit(const QLitObject *qlit)
>> > +{
>> > +    switch (qlit->type) {
>> > +    case QTYPE_QNULL:
>> > +        return QOBJECT(qnull());
>> > +    case QTYPE_QNUM:
>> > +        return QOBJECT(qnum_from_int(qlit->value.qnum));
>> 
>> Is this going to work for all QNum values?
>> 
>> > +++ b/tests/check-qlit.c
>> > @@ -64,11 +64,37 @@ static void qlit_equal_qobject_test(void)
>> >      qobject_decref(qobj);
>> >  }
>> >  
>> > +static void qobject_from_qlit_test(void)
>> > +{
>> > +    QObject *obj, *qobj = qobject_from_qlit(&qlit);
>> > +    QDict *qdict;
>> > +    QList *bee;
>> > +
>> > +    qdict = qobject_to_qdict(qobj);
>> > +    g_assert_cmpint(qdict_get_int(qdict, "foo"), ==, 42);
>> > +    g_assert_cmpstr(qdict_get_str(qdict, "bar"), ==, "hello world");
>> > +    g_assert(qobject_type(qdict_get(qdict, "baz")) == QTYPE_QNULL);
>> 
>> Related to my question above - you pass because there are no floating
>> point values in qlit.  Is that something we want supported?
>
> Markus had some remarks about it when reviewing #define QLIT_QNUM. Only i64 are supported at this point, so it's left for whoever requires it in the future.

Yes, QLitObject only supports int64_t for now.  uint64_t and double
aren't implemented.

By the way, shouldn't QLitObject member type be QType instead of int?

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit()
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit() Marc-André Lureau
  2017-09-13 13:51   ` Eric Blake
@ 2017-12-06 14:37   ` Markus Armbruster
  1 sibling, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 14:37 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Instanciate a QObject* form a literal QLitObject.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  include/qapi/qmp/qlit.h |  2 ++
>  qobject/qlit.c          | 36 ++++++++++++++++++++++++++++++++++++
>  tests/check-qlit.c      | 26 ++++++++++++++++++++++++++
>  3 files changed, 64 insertions(+)
>
> diff --git a/include/qapi/qmp/qlit.h b/include/qapi/qmp/qlit.h
> index b18406bce9..56feb25e04 100644
> --- a/include/qapi/qmp/qlit.h
> +++ b/include/qapi/qmp/qlit.h
> @@ -51,4 +51,6 @@ struct QLitDictEntry {
>  
>  bool qlit_equal_qobject(const QLitObject *lhs, const QObject *rhs);
>  
> +QObject *qobject_from_qlit(const QLitObject *qlit);
> +
>  #endif /* QLIT_H */
> diff --git a/qobject/qlit.c b/qobject/qlit.c
> index 3c4882c784..df2ad97d33 100644
> --- a/qobject/qlit.c
> +++ b/qobject/qlit.c
> @@ -82,3 +82,39 @@ bool qlit_equal_qobject(const QLitObject *lhs, const QObject *rhs)
>  
>      return false;
>  }
> +
> +QObject *qobject_from_qlit(const QLitObject *qlit)
> +{
> +    switch (qlit->type) {
> +    case QTYPE_QNULL:
> +        return QOBJECT(qnull());
> +    case QTYPE_QNUM:
> +        return QOBJECT(qnum_from_int(qlit->value.qnum));
> +    case QTYPE_QSTRING:
> +        return QOBJECT(qstring_from_str(qlit->value.qstr));
> +    case QTYPE_QDICT: {
> +        QDict *qdict = qdict_new();
> +        QLitDictEntry *e;
> +
> +        for (e = qlit->value.qdict; e->key; e++) {
> +            qdict_put_obj(qdict, e->key, qobject_from_qlit(&e->value));
> +        }
> +        return QOBJECT(qdict);
> +    }
> +    case QTYPE_QLIST: {
> +        QList *qlist = qlist_new();
> +        QLitObject *e;
> +
> +        for (e = qlit->value.qlist; e->type != QTYPE_NONE; e++) {
> +            qlist_append_obj(qlist, qobject_from_qlit(e));
> +        }
> +        return QOBJECT(qlist);
> +    }
> +    case QTYPE_QBOOL:
> +        return QOBJECT(qbool_from_bool(qlit->value.qbool));
> +    case QTYPE_NONE:

Please make that

       default:

to remove the compiler's license to have the function return null on
corrupted qlit->type.  If compilers gripe unless you keep case
QTYPE_NONE in place, keep it.


> +        assert(0);
> +    }
> +
> +    return NULL;
> +}
> diff --git a/tests/check-qlit.c b/tests/check-qlit.c
> index c59ec1ab88..acd6e02e96 100644
> --- a/tests/check-qlit.c
> +++ b/tests/check-qlit.c
> @@ -64,11 +64,37 @@ static void qlit_equal_qobject_test(void)
>      qobject_decref(qobj);
>  }
>  
> +static void qobject_from_qlit_test(void)
> +{
> +    QObject *obj, *qobj = qobject_from_qlit(&qlit);
> +    QDict *qdict;
> +    QList *bee;
> +
> +    qdict = qobject_to_qdict(qobj);
> +    g_assert_cmpint(qdict_get_int(qdict, "foo"), ==, 42);
> +    g_assert_cmpstr(qdict_get_str(qdict, "bar"), ==, "hello world");
> +    g_assert(qobject_type(qdict_get(qdict, "baz")) == QTYPE_QNULL);
> +
> +    bee = qdict_get_qlist(qdict, "bee");
> +    obj = qlist_pop(bee);
> +    g_assert_cmpint(qnum_get_int(qobject_to_qnum(obj)), ==, 43);
> +    qobject_decref(obj);
> +    obj = qlist_pop(bee);
> +    g_assert_cmpint(qnum_get_int(qobject_to_qnum(obj)), ==, 44);
> +    qobject_decref(obj);
> +    obj = qlist_pop(bee);
> +    g_assert(qbool_get_bool(qobject_to_qbool(obj)));
> +    qobject_decref(obj);
> +
> +    qobject_decref(qobj);
> +}
> +
>  int main(int argc, char **argv)
>  {
>      g_test_init(&argc, &argv, NULL);
>  
>      g_test_add_func("/qlit/equal_qobject", qlit_equal_qobject_test);
> +    g_test_add_func("/qlit/qobject_from_qlit", qobject_from_qlit_test);
>  
>      return g_test_run();
>  }

With the assertion tightened and the typos pointed out by Eric fixed:

Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 02/50] qapi: generate a literal qobject for introspection
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 02/50] qapi: generate a literal qobject for introspection Marc-André Lureau
@ 2017-12-06 15:17   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 15:17 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth, Dr. David Alan Gilbert

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Replace the generated json string with a literal qobject. The later is
> easier to deal with, at run time as well as compile time: adding #if
> conditionals will be easier than in a json string.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/50] qapi2texi: minor python code simplification
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 03/50] qapi2texi: minor python code simplification Marc-André Lureau
@ 2017-12-06 15:19   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 15:19 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions Marc-André Lureau
@ 2017-12-06 15:46   ` Markus Armbruster
  2017-12-06 16:23   ` Markus Armbruster
  1 sibling, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 15:46 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Accept 'if' key in top-level elements, accepted as string or list of
> string type. The following patches will modify the test visitor to
> check the value is correctly saved, and generate #if/#endif code (as a
> single #if/endif line or a series for a list).
>
> Example of 'if' key:
> { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
>   'if': 'defined(TEST_IF_STRUCT)' }
>
> The generated code is for now *unconditional*. Later patches generate
> the conditionals.
>
> A following patch for qapi-code-gen.txt will provide more complete
> documentation for 'if' usage.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions Marc-André Lureau
  2017-12-06 15:46   ` Markus Armbruster
@ 2017-12-06 16:23   ` Markus Armbruster
  1 sibling, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 16:23 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Second thoughts...

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Accept 'if' key in top-level elements, accepted as string or list of
> string type. The following patches will modify the test visitor to
> check the value is correctly saved, and generate #if/#endif code (as a
> single #if/endif line or a series for a list).
>
> Example of 'if' key:
> { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
>   'if': 'defined(TEST_IF_STRUCT)' }
>
> The generated code is for now *unconditional*. Later patches generate
> the conditionals.
>
> A following patch for qapi-code-gen.txt will provide more complete
> documentation for 'if' usage.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py                         | 35 +++++++++++++++++++++++++++------
>  tests/test-qmp-commands.c               |  6 ++++++
>  tests/qapi-schema/qapi-schema-test.json | 20 +++++++++++++++++++
>  tests/qapi-schema/qapi-schema-test.out  | 22 +++++++++++++++++++++
>  4 files changed, 77 insertions(+), 6 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 62dc52ed6e..20c1abf915 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -639,6 +639,26 @@ def add_name(name, info, meta, implicit=False):
>      all_names[name] = meta
>  
>  
> +def check_if(expr, info):
> +
> +    def check_if_str(ifcond, info):
> +        if ifcond == '':
> +            raise QAPISemError(info, "'if' condition '' makes no sense")
> +
> +    ifcond = expr['if']
> +    if isinstance(ifcond, str):
> +        check_if_str(ifcond, info)
> +    elif (isinstance(ifcond, list)
> +          and all(isinstance(elt, str) for elt in ifcond)):
> +        if ifcond == []:
> +            raise QAPISemError(info, "'if' condition [] is useless")
> +        for elt in ifcond:
> +            check_if_str(elt, info)
> +    else:
> +        raise QAPISemError(
> +            info, "'if' condition must be a string or a list of strings")
> +
> +

Slightly terser:

   def check_if(expr, info):

       def check_if_str(ifcond, info):
           if not isinstance(ifcond, str):
               raise QAPISemError(
                   info, "'if' condition must be a string or a list of strings")
           if ifcond == '':
               raise QAPISemError(info, "'if' condition '' makes no sense")

       ifcond = expr['if']
       if isinstance(ifcond, list):
           if ifcond == []:
               raise QAPISemError(info, "'if' condition [] is useless")
           for elt in ifcond:
               check_if_str(elt, info)
       else:
           check_if_str(ifcond, info)

Can slot this in on commit.

>  def check_type(info, source, value, allow_array=False,
>                 allow_dict=False, allow_optional=False,
>                 allow_metas=[]):
[...]

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 05/50] qapi: add tests for invalid 'if'
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 05/50] qapi: add tests for invalid 'if' Marc-André Lureau
@ 2017-12-06 16:34   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 16:34 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

This tests error conditions added in the previous commit.  I recommend
squashing the two together.

> ---
>  tests/Makefile.include                   | 3 +++
>  tests/qapi-schema/bad-if-empty-list.err  | 1 +
>  tests/qapi-schema/bad-if-empty-list.exit | 1 +
>  tests/qapi-schema/bad-if-empty-list.json | 3 +++
>  tests/qapi-schema/bad-if-empty-list.out  | 0
>  tests/qapi-schema/bad-if-empty.err       | 1 +
>  tests/qapi-schema/bad-if-empty.exit      | 1 +
>  tests/qapi-schema/bad-if-empty.json      | 3 +++
>  tests/qapi-schema/bad-if-empty.out       | 0
>  tests/qapi-schema/bad-if.err             | 1 +
>  tests/qapi-schema/bad-if.exit            | 1 +
>  tests/qapi-schema/bad-if.json            | 3 +++
>  tests/qapi-schema/bad-if.out             | 0
>  13 files changed, 18 insertions(+)
>  create mode 100644 tests/qapi-schema/bad-if-empty-list.err
>  create mode 100644 tests/qapi-schema/bad-if-empty-list.exit
>  create mode 100644 tests/qapi-schema/bad-if-empty-list.json
>  create mode 100644 tests/qapi-schema/bad-if-empty-list.out
>  create mode 100644 tests/qapi-schema/bad-if-empty.err
>  create mode 100644 tests/qapi-schema/bad-if-empty.exit
>  create mode 100644 tests/qapi-schema/bad-if-empty.json
>  create mode 100644 tests/qapi-schema/bad-if-empty.out
>  create mode 100644 tests/qapi-schema/bad-if.err
>  create mode 100644 tests/qapi-schema/bad-if.exit
>  create mode 100644 tests/qapi-schema/bad-if.json
>  create mode 100644 tests/qapi-schema/bad-if.out
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index fae5715e9c..8dac7c9083 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -402,6 +402,9 @@ qapi-schema += args-unknown.json
>  qapi-schema += bad-base.json
>  qapi-schema += bad-data.json
>  qapi-schema += bad-ident.json
> +qapi-schema += bad-if.json
> +qapi-schema += bad-if-empty.json
> +qapi-schema += bad-if-empty-list.json
>  qapi-schema += bad-type-bool.json
>  qapi-schema += bad-type-dict.json
>  qapi-schema += bad-type-int.json
> diff --git a/tests/qapi-schema/bad-if-empty-list.err b/tests/qapi-schema/bad-if-empty-list.err
> new file mode 100644
> index 0000000000..75fe6497bc
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if-empty-list.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
> diff --git a/tests/qapi-schema/bad-if-empty-list.exit b/tests/qapi-schema/bad-if-empty-list.exit
> new file mode 100644
> index 0000000000..d00491fd7e
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if-empty-list.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/bad-if-empty-list.json b/tests/qapi-schema/bad-if-empty-list.json
> new file mode 100644
> index 0000000000..94f2eb8670
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if-empty-list.json
> @@ -0,0 +1,3 @@
> +# check empty 'if' list
> +{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
> +  'if': [] }
> diff --git a/tests/qapi-schema/bad-if-empty-list.out b/tests/qapi-schema/bad-if-empty-list.out
> new file mode 100644
> index 0000000000..e69de29bb2

This covers "'if' condition [] is useless".

> diff --git a/tests/qapi-schema/bad-if-empty.err b/tests/qapi-schema/bad-if-empty.err
> new file mode 100644
> index 0000000000..358bdc3e51
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if-empty.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense
> diff --git a/tests/qapi-schema/bad-if-empty.exit b/tests/qapi-schema/bad-if-empty.exit
> new file mode 100644
> index 0000000000..d00491fd7e
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if-empty.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/bad-if-empty.json b/tests/qapi-schema/bad-if-empty.json
> new file mode 100644
> index 0000000000..fe1dd4eca6
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if-empty.json
> @@ -0,0 +1,3 @@
> +# check empty 'if'
> +{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
> +  'if': '' }
> diff --git a/tests/qapi-schema/bad-if-empty.out b/tests/qapi-schema/bad-if-empty.out
> new file mode 100644
> index 0000000000..e69de29bb2

This covers "'if' condition '' makes no sense", not wrapped in a list.

> diff --git a/tests/qapi-schema/bad-if.err b/tests/qapi-schema/bad-if.err
> new file mode 100644
> index 0000000000..c2e3f5f44c
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/bad-if.json:2: 'if' condition must be a string or a list of strings
> diff --git a/tests/qapi-schema/bad-if.exit b/tests/qapi-schema/bad-if.exit
> new file mode 100644
> index 0000000000..d00491fd7e
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/bad-if.json b/tests/qapi-schema/bad-if.json
> new file mode 100644
> index 0000000000..3edd1a0bf2
> --- /dev/null
> +++ b/tests/qapi-schema/bad-if.json
> @@ -0,0 +1,3 @@
> +# check invalid 'if' type
> +{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
> +  'if': { 'value': 'defined(TEST_IF_STRUCT)' } }
> diff --git a/tests/qapi-schema/bad-if.out b/tests/qapi-schema/bad-if.out
> new file mode 100644
> index 0000000000..e69de29bb2

This covers "'if' condition must be a string or a list of strings", not
wrapped in a list.

Not covered: the two not wrapped in a list cases wrapped in a list.
However, I figure this is good enough as is, thus
Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/50] qapi: pass 'if' condition into QAPISchemaEntity objects
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 06/50] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
@ 2017-12-06 17:13   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 17:13 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Built-in objects remain unconditional.  Explicitly defined objects
> use the condition specified in the schema.  Implicitly defined
> objects inherit their condition from their users.  For most of them,
> there is exactly one user, so the condition to use is obvious.  The
> exception is the wrapper types generated for simple union variants,
> which can be shared by any number of simple unions.  The tight
> condition would be the disjunction of the conditions of these simple
> unions.  For now, use wrapped type's condition instead.  Much

the wrapped type's

> simpler and good enough for now.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py | 89 ++++++++++++++++++++++++++++++++++++---------------------
>  1 file changed, 57 insertions(+), 32 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 20c1abf915..0f55caa18d 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1000,7 +1000,7 @@ def check_exprs(exprs):
>  #
>  
>  class QAPISchemaEntity(object):
> -    def __init__(self, name, info, doc):
> +    def __init__(self, name, info, doc, ifcond=None):
>          assert isinstance(name, str)
>          self.name = name
>          # For explicitly defined entities, info points to the (explicit)
> @@ -1010,6 +1010,7 @@ class QAPISchemaEntity(object):
>          # such place).
>          self.info = info
>          self.doc = doc
> +        self.ifcond = ifcond
>  
>      def c_name(self):
>          return c_name(self.name)
> @@ -1126,8 +1127,8 @@ class QAPISchemaBuiltinType(QAPISchemaType):
>  
>  
>  class QAPISchemaEnumType(QAPISchemaType):
> -    def __init__(self, name, info, doc, values, prefix):
> -        QAPISchemaType.__init__(self, name, info, doc)
> +    def __init__(self, name, info, doc, ifcond, values, prefix):
> +        QAPISchemaType.__init__(self, name, info, doc, ifcond)
>          for v in values:
>              assert isinstance(v, QAPISchemaMember)
>              v.set_owner(name)
> @@ -1162,7 +1163,7 @@ class QAPISchemaEnumType(QAPISchemaType):
>  
>  class QAPISchemaArrayType(QAPISchemaType):
>      def __init__(self, name, info, element_type):
> -        QAPISchemaType.__init__(self, name, info, None)
> +        QAPISchemaType.__init__(self, name, info, None, None)
>          assert isinstance(element_type, str)
>          self._element_type_name = element_type
>          self.element_type = None
> @@ -1170,6 +1171,7 @@ class QAPISchemaArrayType(QAPISchemaType):
>      def check(self, schema):
>          self.element_type = schema.lookup_type(self._element_type_name)
>          assert self.element_type
> +        self.ifcond = self.element_type.ifcond
>  
>      def is_implicit(self):
>          return True

In my review of v2, I wrote:

    This is subtler than it looks on first glance.

    All the other entities set self.ifcond in their constructor to the true
    value passed in as argument.

    QAPISchemaArrayType doesn't take such an argument.  Instead, it inherits
    its .ifcond from its .element_type.  However, .element_type isn't known
    at construction time if it's a forward reference.  We therefore delay
    setting it until .check() time.  You do the same for .ifcond (no
    choice).

    Before .check(), .ifcond is None, because the constructor sets it that
    way: it calls QAPISchemaType.__init__() without passing a ifcond
    argument, which then sets self.ifcond to its default argument None.

    Pitfall: accessing ent.ifcond before ent.check() works *except* when ent
    is an array type.  Hmm.

The problem is of course more general.  We commonly initialize
attributes to None in .init(), then set their real value in .check().
Accessing the attribute before .check() yields None.  If we're lucky,
the code that accesses the attribute prematurely chokes on None.

It won't for .ifcond, because None is a legitimate value.

Perhaps we should leave such attributes undefined until .check().  What
do you think?  No need to tie that idea to this series, though.

[...]

With the commit message tidied up:
Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/50] qapi: add 'ifcond' to visitor methods
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 07/50] qapi: add 'ifcond' to visitor methods Marc-André Lureau
@ 2017-12-06 17:23   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 17:23 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Modify the test visitor to check correct passing of values.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 08/50] qapi: mcgen() shouldn't indent # lines
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 08/50] qapi: mcgen() shouldn't indent # lines Marc-André Lureau
@ 2017-12-06 17:41   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-06 17:41 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Skip preprocessor lines when adding indentation, since that would
> likely result in invalid code.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index f2b5a7e131..2a8e60e975 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1862,7 +1862,7 @@ def cgen(code, **kwds):
>      if indent_level:
>          indent = genindent(indent_level)
>          # re.subn() lacks flags support before Python 2.7, use re.compile()
> -        raw = re.subn(re.compile(r'^.', re.MULTILINE),
> +        raw = re.subn(re.compile(r'^[^#\n].', re.MULTILINE),
>                        indent + r'\g<0>', raw)
>          raw = raw[0]
>      return re.sub(re.escape(eatspace) + r' *', '', raw)

Old: we want to indent all non-empty lines.  Such a line starts with a
character other than newline, matched by '.'.  Replace that character by
indent + the character.

New regexp: we want to indent all non-empty lines not starting with '#'.
Such a line starts with a character other than newline and '#', matched
by '[^#\n]'.  But there's a '.' afterwards, and therefore we don't match
*any* lines consisting of just one character:

    >>> cgen('a\n')
    'a\n'

I think you should drop the '.'.

Alternatively, use a negative lookahead assertion:

        raw = re.subn(re.compile(r'^(?!(#|$))', re.MULTILINE),
                      indent, raw)

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/50] qapi: add #if/#endif helpers
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 09/50] qapi: add #if/#endif helpers Marc-André Lureau
@ 2017-12-07 14:10   ` Markus Armbruster
  2018-01-11 21:21     ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-07 14:10 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add helpers to wrap generated code with #if/#endif lines.
>
> Add a function decorator that will be used to wrap visitor methods.
> The decorator will check if code was generated before adding #if/#endif
> lines. Used in the following patches.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 55 insertions(+)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 2a8e60e975..94b735d8d6 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1897,6 +1897,61 @@ def guardend(name):
>                   name=guardname(name))
>  
>  
> +def gen_if(ifcond):
> +    if not ifcond:
> +        return ''
> +    if isinstance(ifcond, str):
> +        ifcond = [ifcond]

Perhaps we should take this normalization step in the QAPISchema
constructors.

> +    ret = ''
> +    for ifc in ifcond:
> +        ret += mcgen('''
> +#if %(cond)s
> +''', cond=ifc)
> +    return ret
> +
> +
> +def gen_endif(ifcond):
> +    if not ifcond:
> +        return ''
> +    if isinstance(ifcond, str):
> +        ifcond = [ifcond]
> +    ret = ''
> +    for ifc in reversed(ifcond):
> +        ret += mcgen('''
> +#endif /* %(cond)s */
> +''', cond=ifc)
> +    return ret
> +
> +
> +# Wrap a method to add #if / #endif to generated code, only if some
> +# code was generated. The method must have an 'ifcond' argument.
> +# self must have 'if_members' listing the attributes to wrap.
> +def ifcond_decorator(func):
> +
> +    def func_wrapper(self, *args, **kwargs):
> +        import inspect

Is hiding imports in function a good idea?

> +        idx = inspect.getargspec(func).args.index('ifcond')
> +        ifcond = args[idx - 1]
> +        save = {}
> +        for mem in self.if_members:
> +            save[mem] = getattr(self, mem)
> +        func(self, *args, **kwargs)
> +        for mem, val in save.items():
> +            newval = getattr(self, mem)
> +            if newval != val:
> +                assert newval.startswith(val)
> +                newval = newval[len(val):]
> +                if newval[0] == '\n':
> +                    val += '\n'
> +                    newval = newval[1:]
> +                val += gen_if(ifcond)
> +                val += newval
> +                val += gen_endif(ifcond)
> +            setattr(self, mem, val)
> +
> +    return func_wrapper
> +
> +
>  def gen_enum_lookup(name, values, prefix=None):
>      ret = mcgen('''

My gut feeling is still "too clever by half", but i'm reserving
judgement until after review of its use, and exploration of
alternatives.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/50] qapi-introspect: modify to_qlit() to append ', ' on level > 0
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 10/50] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Marc-André Lureau
@ 2017-12-07 14:47   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-07 14:47 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The following patch is going to break list entries with #if/#endif, so
> they should have the trailing ',' as suffix.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi-introspect.py | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
> index 56c1f9d548..b1d08ec97b 100644
> --- a/scripts/qapi-introspect.py
> +++ b/scripts/qapi-introspect.py
> @@ -29,7 +29,7 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
>                  for elt in obj]
>          elts.append(indent(level + 1) + "{}")
>          ret += 'QLIT_QLIST(((QLitObject[]) {\n'
> -        ret += ',\n'.join(elts) + '\n'
> +        ret += '\n'.join(elts) + '\n'
>          ret += indent(level) + '}))'
>      elif isinstance(obj, dict):
>          elts = []
> @@ -42,6 +42,8 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
>          ret += indent(level) + '}))'
>      else:
>          assert False                # not implemented
> +    if level > 0:
> +        ret += ','
>      return ret

Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 11/50] qapi-introspect: modify to_qlit() to generate #if code
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 11/50] qapi-introspect: modify to_qlit() to generate #if code Marc-André Lureau
@ 2017-12-07 14:50   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-07 14:50 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The generator now accepts (obj, condition) tuples to wrap generated
> QLit objects for 'obj' with #if/#endif conditions.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi-introspect.py | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
> index b1d08ec97b..dc70954e8a 100644
> --- a/scripts/qapi-introspect.py
> +++ b/scripts/qapi-introspect.py
> @@ -17,6 +17,13 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
>      def indent(level):
>          return level * 4 * ' '
>  
> +    if isinstance(obj, tuple):
> +        ifobj, ifcond = obj
> +        ret = gen_if(ifcond)
> +        ret += to_qlit(ifobj, level)
> +        ret += '\n' + gen_endif(ifcond)
> +        return ret
> +
>      ret = ''
>      if not suppress_first_indent:
>          ret += indent(level)

Reviewed-by: Markus Armbruster <armbru@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 12/50] qapi-introspect: add preprocessor conditions to generated QLit
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 12/50] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
@ 2017-12-07 15:41   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-07 15:41 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add 'ifcond' condition to top-level QLit objects.
>
> to_qlit() handles the (obj, ifcond) tuples in previous patch.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

According to my testing, this patch adds blank lines between the
elements of qmp_schema_qlit.  I suspect this is because to_qlit((obj,
None) is not actually equivalent to to_qlit(obj).  It should be.

Note that the issue is in PATCH 11, but becomes visible only in PATCH
12, because the new code only gets used in PATCH 12.  Consider squashing
the two together.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 15/50] qapi-types: refactor variants handling
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 15/50] qapi-types: refactor variants handling Marc-André Lureau
@ 2017-12-07 15:57   ` Markus Armbruster
  2018-01-11 21:22     ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-07 15:57 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Generate variants objects outside gen_object(). This will allow to
> easily wrap gen_object() with ifcond_decorator in the following patch.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi-types.py | 37 +++++++++++++++++++++++--------------
>  1 file changed, 23 insertions(+), 14 deletions(-)
>
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> index 915786c463..2b3588267b 100644
> --- a/scripts/qapi-types.py
> +++ b/scripts/qapi-types.py
> @@ -53,23 +53,27 @@ def gen_struct_members(members):
>      return ret
>  
>  
> -def gen_object(name, base, members, variants):
> -    if name in objects_seen:
> -        return ''
> -    objects_seen.add(name)
> -
> +def gen_variants_objects(variants):
>      ret = ''
>      if variants:
>          for v in variants.variants:
>              if isinstance(v.type, QAPISchemaObjectType):
> +                ret += gen_variants_objects(v.type.variants)
>                  ret += gen_object(v.type.name, v.type.base,
>                                    v.type.local_members, v.type.variants)
> +    return ret
>  
> -    ret += mcgen('''
> +
> +def gen_object(name, base, members, variants):
> +    if name in objects_seen:
> +        return ''
> +    objects_seen.add(name)
> +
> +    ret = mcgen('''
>  
>  struct %(c_name)s {
>  ''',
> -                 c_name=c_name(name))
> +                c_name=c_name(name))
>  
>      if base:
>          if not base.is_implicit():
> @@ -218,11 +222,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
>              self.decl += gen_array(name, element_type)
>              self._gen_type_cleanup(name)
>  
> -    def visit_object_type(self, name, info, ifcond, base, members, variants):
> -        # Nothing to do for the special empty builtin
> -        if name == 'q_empty':
> -            return
> -        self._fwdecl += gen_fwd_object_or_array(name)
> +    def _gen_object(self, name, info, ifcond, base, members, variants):
>          self.decl += gen_object(name, base, members, variants)
>          if base and not base.is_implicit():
>              self.decl += gen_upcast(name, base)
> @@ -232,10 +232,19 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
>              # implicit types won't be directly allocated/freed
>              self._gen_type_cleanup(name)
>  
> +    def visit_object_type(self, name, info, ifcond, base, members, variants):
> +        # Nothing to do for the special empty builtin
> +        if name == 'q_empty':
> +            return
> +        self._fwdecl += gen_fwd_object_or_array(name)
> +        self.decl += gen_variants_objects(variants)
> +        self._gen_object(name, info, None, base, members, variants)
> +
>      def visit_alternate_type(self, name, info, ifcond, variants):
>          self._fwdecl += gen_fwd_object_or_array(name)
> -        self.decl += gen_object(name, None, [variants.tag_member], variants)
> -        self._gen_type_cleanup(name)
> +        self.decl += gen_variants_objects(variants)
> +        self._gen_object(name, info, None, None,
> +                         [variants.tag_member], variants)

Where did self._gen_type_cleanup(name) go?  Hmm, I guess it's now in
_gen_object().  Confusing.

>  
>  # If you link code generated from multiple schemata, you want only one
>  # instance of the code for built-in types.  Generate it only when

If I read this patch correctly, you move code from the beginning of
gen_object() to new gen_variants_objects(), then arrange to have
gen_variants_objects() called right before gen_object().  Correct?

In old gen_object(), the code is guarded by

       if name in objects_seen:
           return ''
       objects_seen.add(name)

In new gen_variants_objects(), it isn't.  Why?

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely Marc-André Lureau
@ 2017-12-07 16:23   ` Markus Armbruster
  2017-12-07 17:01     ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-07 16:23 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The C standard has the initial value at 0 and the subsequent values
> incremented by 1. No need to set this explicitely.
>
> This will prevent from artificial "gaps" when compiling out some enum
> values and having unnecessarily large MAX values & enums arrays.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py | 7 ++-----
>  1 file changed, 2 insertions(+), 5 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 94b735d8d6..074ee221a1 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1985,14 +1985,11 @@ typedef enum %(c_name)s {
>  ''',
>                  c_name=c_name(name))
>  
> -    i = 0
>      for value in enum_values:
>          ret += mcgen('''
> -    %(c_enum)s = %(i)d,
> +    %(c_enum)s,
>  ''',
> -                     c_enum=c_enum_const(name, value, prefix),
> -                     i=i)
> -        i += 1
> +                     c_enum=c_enum_const(name, value, prefix))
>  
>      ret += mcgen('''
>  } %(c_name)s;

Recapitulate review of v2: this risks entertaining mishaps like
compiling this one

    typedef enum Color {
        COLOR_WHITE,
#if defined(NEED_CPU_H)
#if defined(TARGET_S390X)
        COLOR_BLUE,
#endif /* defined(TARGET_S390X) */
#endif /* defined(NEED_CPU_H) */
        COLOR_BLACK,
    } Color;

in s390x-code (COLOR_BLACK = 2) and in target-independent code
(COLOR_BLACK = 1), then linking the two together.

Same issue for struct members and such (previous patch).

What's our story on preventing disaster here?

In the long run, we want to split the generated code so that
target-specific and target-independent code are separate, and each part
is always compiled with consistent preprocessor symbols.  But I'm afraid
that's not in the card right now.

I therefore proposed the stupidest temporary stopgap that could possibly
work: apply conditionals *only* to qmp-introspect.c, leave everything
unconditional elsewhere.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely
  2017-12-07 16:23   ` Markus Armbruster
@ 2017-12-07 17:01     ` Marc-André Lureau
  2017-12-08  7:50       ` Markus Armbruster
  0 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-12-07 17:01 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

On Thu, Dec 7, 2017 at 5:23 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> The C standard has the initial value at 0 and the subsequent values
>> incremented by 1. No need to set this explicitely.
>>
>> This will prevent from artificial "gaps" when compiling out some enum
>> values and having unnecessarily large MAX values & enums arrays.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  scripts/qapi.py | 7 ++-----
>>  1 file changed, 2 insertions(+), 5 deletions(-)
>>
>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>> index 94b735d8d6..074ee221a1 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -1985,14 +1985,11 @@ typedef enum %(c_name)s {
>>  ''',
>>                  c_name=c_name(name))
>>
>> -    i = 0
>>      for value in enum_values:
>>          ret += mcgen('''
>> -    %(c_enum)s = %(i)d,
>> +    %(c_enum)s,
>>  ''',
>> -                     c_enum=c_enum_const(name, value, prefix),
>> -                     i=i)
>> -        i += 1
>> +                     c_enum=c_enum_const(name, value, prefix))
>>
>>      ret += mcgen('''
>>  } %(c_name)s;
>
> Recapitulate review of v2: this risks entertaining mishaps like
> compiling this one
>
>     typedef enum Color {
>         COLOR_WHITE,
> #if defined(NEED_CPU_H)
> #if defined(TARGET_S390X)
>         COLOR_BLUE,
> #endif /* defined(TARGET_S390X) */
> #endif /* defined(NEED_CPU_H) */
>         COLOR_BLACK,
>     } Color;
>
> in s390x-code (COLOR_BLACK = 2) and in target-independent code
> (COLOR_BLACK = 1), then linking the two together.
>
> Same issue for struct members and such (previous patch).
>
> What's our story on preventing disaster here?
>
> In the long run, we want to split the generated code so that
> target-specific and target-independent code are separate, and each part
> is always compiled with consistent preprocessor symbols.  But I'm afraid
> that's not in the card right now.

Eh, I need to refresh my memories about that series, but I think
that's what I did in v3

It doesn't use the NEED_CPU_H trick. It has a seperate per-target target.json


>
> I therefore proposed the stupidest temporary stopgap that could possibly
> work: apply conditionals *only* to qmp-introspect.c, leave everything
> unconditional elsewhere.

I don't like that idea much and I don't think we need that
restriction, but I need to get back to that series on some point
(probably after you finish the review).

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 18/50] qapi: change enum visitor to take QAPISchemaMember
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 18/50] qapi: change enum visitor to take QAPISchemaMember Marc-André Lureau
@ 2017-12-07 17:34   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-07 17:34 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> This will allow to add and access more properties associated with enum
> values/members, like the associated 'if' condition. We may want to
> have a specialized type QAPISchemaEnumMember, for now this will do.
>
> Suggested-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py                          | 40 +++++++++++++-------------
>  scripts/qapi-event.py                    |  2 +-
>  scripts/qapi-introspect.py               |  5 ++--
>  scripts/qapi-types.py                    | 10 +++----
>  scripts/qapi-visit.py                    |  2 +-
>  scripts/qapi2texi.py                     |  2 +-
>  tests/qapi-schema/comments.out           | 14 +++++++--
>  tests/qapi-schema/doc-good.out           | 17 +++++++++--
>  tests/qapi-schema/empty.out              |  9 +++++-
>  tests/qapi-schema/event-case.out         |  9 +++++-
>  tests/qapi-schema/ident-with-escape.out  |  9 +++++-
>  tests/qapi-schema/include-relpath.out    | 14 +++++++--
>  tests/qapi-schema/include-repetition.out | 14 +++++++--
>  tests/qapi-schema/include-simple.out     | 14 +++++++--
>  tests/qapi-schema/indented-expr.out      |  9 +++++-
>  tests/qapi-schema/qapi-schema-test.out   | 49 ++++++++++++++++++++++++++------
>  tests/qapi-schema/test-qapi.py           | 17 +++++++----
>  17 files changed, 177 insertions(+), 59 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 074ee221a1..386a577a59 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1039,7 +1039,7 @@ class QAPISchemaVisitor(object):
>      def visit_builtin_type(self, name, info, json_type):
>          pass
>  
> -    def visit_enum_type(self, name, info, ifcond, values, prefix):
> +    def visit_enum_type(self, name, info, ifcond, members, prefix):
>          pass
>  
>      def visit_array_type(self, name, info, ifcond, element_type):
> @@ -1127,21 +1127,21 @@ class QAPISchemaBuiltinType(QAPISchemaType):
>  
>  
>  class QAPISchemaEnumType(QAPISchemaType):
> -    def __init__(self, name, info, doc, ifcond, values, prefix):
> +    def __init__(self, name, info, doc, ifcond, members, prefix):
>          QAPISchemaType.__init__(self, name, info, doc, ifcond)
> -        for v in values:
> -            assert isinstance(v, QAPISchemaMember)
> -            v.set_owner(name)
> +        for m in members:
> +            assert isinstance(m, QAPISchemaMember)
> +            m.set_owner(name)
>          assert prefix is None or isinstance(prefix, str)
> -        self.values = values
> +        self.members = members
>          self.prefix = prefix
>  
>      def check(self, schema):
>          seen = {}
> -        for v in self.values:
> -            v.check_clash(self.info, seen)
> +        for m in self.members:
> +            m.check_clash(self.info, seen)
>              if self.doc:
> -                self.doc.connect_member(v)
> +                self.doc.connect_member(m)
>  
>      def is_implicit(self):
>          # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
> @@ -1151,14 +1151,14 @@ class QAPISchemaEnumType(QAPISchemaType):
>          return c_name(self.name)
>  
>      def member_names(self):
> -        return [v.name for v in self.values]
> +        return [m.name for m in self.members]
>  
>      def json_type(self):
>          return 'string'
>  
>      def visit(self, visitor):
>          visitor.visit_enum_type(self.name, self.info, self.ifcond,
> -                                self.member_names(), self.prefix)
> +                                self.members, self.prefix)
>  
>  
>  class QAPISchemaArrayType(QAPISchemaType):
> @@ -1952,19 +1952,19 @@ def ifcond_decorator(func):
>      return func_wrapper
>  
>  
> -def gen_enum_lookup(name, values, prefix=None):
> +def gen_enum_lookup(name, members, prefix=None):
>      ret = mcgen('''
>  
>  const QEnumLookup %(c_name)s_lookup = {
>      .array = (const char *const[]) {
>  ''',
>                  c_name=c_name(name))
> -    for value in values:
> -        index = c_enum_const(name, value, prefix)
> +    for m in members:
> +        index = c_enum_const(name, m.name, prefix)
>          ret += mcgen('''
> -        [%(index)s] = "%(value)s",
> +        [%(index)s] = "%(name)s",
>  ''',
> -                     index=index, value=value)
> +                     index=index, name=m.name)
>  
>      ret += mcgen('''
>      },
> @@ -1975,9 +1975,9 @@ const QEnumLookup %(c_name)s_lookup = {
>      return ret
>  
>  
> -def gen_enum(name, values, prefix=None):
> +def gen_enum(name, members, prefix=None):
>      # append automatically generated _MAX value
> -    enum_values = values + ['_MAX']
> +    enum_members = members + [QAPISchemaMember('_MAX')]
>  
>      ret = mcgen('''
>  
> @@ -1985,11 +1985,11 @@ typedef enum %(c_name)s {
>  ''',
>                  c_name=c_name(name))
>  
> -    for value in enum_values:
> +    for m in enum_members:
>          ret += mcgen('''
>      %(c_enum)s,
>  ''',
> -                     c_enum=c_enum_const(name, value, prefix))
> +                     c_enum=c_enum_const(name, m.name, prefix))
>  
>      ret += mcgen('''
>  } %(c_name)s;
> diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
> index bef301dfe9..38f4264817 100644
> --- a/scripts/qapi-event.py
> +++ b/scripts/qapi-event.py
> @@ -168,7 +168,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
>      def visit_event(self, name, info, ifcond, arg_type, boxed):
>          self.decl += gen_event_send_decl(name, arg_type, boxed)
>          self.defn += gen_event_send(name, arg_type, boxed)
> -        self._event_names.append(name)
> +        self._event_names.append(QAPISchemaMember(name))
>  
>  
>  (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
> diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
> index 69d9afc792..32a58cf879 100644
> --- a/scripts/qapi-introspect.py
> +++ b/scripts/qapi-introspect.py
> @@ -151,8 +151,9 @@ const QLitObject %(c_name)s = %(c_string)s;
>      def visit_builtin_type(self, name, info, json_type):
>          self._gen_qlit(name, 'builtin', {'json-type': json_type}, None)
>  
> -    def visit_enum_type(self, name, info, ifcond, values, prefix):
> -        self._gen_qlit(name, 'enum', {'values': values}, ifcond)
> +    def visit_enum_type(self, name, info, ifcond, members, prefix):
> +        self._gen_qlit(name, 'enum',
> +                       {'values': [m.name for m in members]}, ifcond)
>  
>      def visit_array_type(self, name, info, ifcond, element_type):
>          element = self._use_type(element_type)
> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
> index 789e89ff59..75c1823e44 100644
> --- a/scripts/qapi-types.py
> +++ b/scripts/qapi-types.py
> @@ -203,16 +203,16 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
>          self.defn += gen_type_cleanup(name)
>  
>      @ifcond_decorator
> -    def visit_enum_type(self, name, info, ifcond, values, prefix):
> +    def visit_enum_type(self, name, info, ifcond, members, prefix):
>          # Special case for our lone builtin enum type
>          # TODO use something cleaner than existence of info
>          if not info:
> -            self._btin += gen_enum(name, values, prefix)
> +            self._btin += gen_enum(name, members, prefix)
>              if do_builtins:
> -                self.defn += gen_enum_lookup(name, values, prefix)
> +                self.defn += gen_enum_lookup(name, members, prefix)
>          else:
> -            self._fwdecl += gen_enum(name, values, prefix)
> -            self.defn += gen_enum_lookup(name, values, prefix)
> +            self._fwdecl += gen_enum(name, members, prefix)
> +            self.defn += gen_enum_lookup(name, members, prefix)
>  
>      @ifcond_decorator
>      def visit_array_type(self, name, info, ifcond, element_type):
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index 4b0e005437..7e816ae98e 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -284,7 +284,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
>          self._btin = None
>  
>      @ifcond_decorator
> -    def visit_enum_type(self, name, info, ifcond, values, prefix):
> +    def visit_enum_type(self, name, info, ifcond, members, prefix):
>          # Special case for our lone builtin enum type
>          # TODO use something cleaner than existence of info
>          if not info:
> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> index cf63cb0006..e72e7cfe0b 100755
> --- a/scripts/qapi2texi.py
> +++ b/scripts/qapi2texi.py
> @@ -207,7 +207,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>      def visit_begin(self, schema):
>          self.out = ''
>  
> -    def visit_enum_type(self, name, info, ifcond, values, prefix):
> +    def visit_enum_type(self, name, info, ifcond, members, prefix):
>          doc = self.cur_doc
>          if self.out:
>              self.out += '\n'
> diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
> index 17e652535c..17b493ec24 100644
> --- a/tests/qapi-schema/comments.out
> +++ b/tests/qapi-schema/comments.out
> @@ -1,4 +1,14 @@
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> -enum Status ['good', 'bad', 'ugly']
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
> +enum Status
> +    member good:
> +    member bad:
> +    member ugly:
>  object q_empty
> diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
> index 63ca25a8b9..0de06ce345 100644
> --- a/tests/qapi-schema/doc-good.out
> +++ b/tests/qapi-schema/doc-good.out
> @@ -1,19 +1,30 @@
>  object Base
>      member base1: Enum optional=False
> -enum Enum ['one', 'two']
> +enum Enum
> +    member one:
> +    member two:
>  object Object
>      base Base
>      tag base1
>      case one: Variant1
>      case two: Variant2
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
>  object SugaredUnion
>      member type: SugaredUnionKind optional=False
>      tag type
>      case one: q_obj_Variant1-wrapper
>      case two: q_obj_Variant2-wrapper
> -enum SugaredUnionKind ['one', 'two']
> +enum SugaredUnionKind
> +    member one:
> +    member two:
>  object Variant1
>      member var1: str optional=False
>  object Variant2
> diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
> index 40b886ddae..9859251087 100644
> --- a/tests/qapi-schema/empty.out
> +++ b/tests/qapi-schema/empty.out
> @@ -1,3 +1,10 @@
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
>  object q_empty
> diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
> index 313c0fe7be..4dccc8f61e 100644
> --- a/tests/qapi-schema/event-case.out
> +++ b/tests/qapi-schema/event-case.out
> @@ -1,5 +1,12 @@
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
>  event oops None
>     boxed=False
>  object q_empty
> diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
> index b5637cb2e0..4d17bc6783 100644
> --- a/tests/qapi-schema/ident-with-escape.out
> +++ b/tests/qapi-schema/ident-with-escape.out
> @@ -1,5 +1,12 @@
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
>  command fooA q_obj_fooA-arg -> None
>     gen=True success_response=True boxed=False
>  object q_empty
> diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out
> index 17e652535c..17b493ec24 100644
> --- a/tests/qapi-schema/include-relpath.out
> +++ b/tests/qapi-schema/include-relpath.out
> @@ -1,4 +1,14 @@
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> -enum Status ['good', 'bad', 'ugly']
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
> +enum Status
> +    member good:
> +    member bad:
> +    member ugly:
>  object q_empty
> diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
> index 17e652535c..17b493ec24 100644
> --- a/tests/qapi-schema/include-repetition.out
> +++ b/tests/qapi-schema/include-repetition.out
> @@ -1,4 +1,14 @@
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> -enum Status ['good', 'bad', 'ugly']
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
> +enum Status
> +    member good:
> +    member bad:
> +    member ugly:
>  object q_empty
> diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
> index 17e652535c..17b493ec24 100644
> --- a/tests/qapi-schema/include-simple.out
> +++ b/tests/qapi-schema/include-simple.out
> @@ -1,4 +1,14 @@
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> -enum Status ['good', 'bad', 'ugly']
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
> +enum Status
> +    member good:
> +    member bad:
> +    member ugly:
>  object q_empty
> diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
> index 586795f44d..8bdc016e55 100644
> --- a/tests/qapi-schema/indented-expr.out
> +++ b/tests/qapi-schema/indented-expr.out
> @@ -1,5 +1,12 @@
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +enum QType
>      prefix QTYPE
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
>  command eins None -> None
>     gen=True success_response=True boxed=False
>  object q_empty
> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
> index fc5fd25f1b..9a7cafc269 100644
> --- a/tests/qapi-schema/qapi-schema-test.out
> +++ b/tests/qapi-schema/qapi-schema-test.out
> @@ -33,7 +33,10 @@ event EVENT_F UserDefAlternate
>  object Empty1
>  object Empty2
>      base Empty1
> -enum EnumOne ['value1', 'value2', 'value3']
> +enum EnumOne
> +    member value1:
> +    member value2:
> +    member value3:
>  object EventStructOne
>      member struct1: UserDefOne optional=False
>      member string: str optional=False
> @@ -42,16 +45,25 @@ object ForceArrays
>      member unused1: UserDefOneList optional=False
>      member unused2: UserDefTwoList optional=False
>      member unused3: TestStructList optional=False
> -enum MyEnum []
> +enum MyEnum
>  object NestedEnumsOne
>      member enum1: EnumOne optional=False
>      member enum2: EnumOne optional=True
>      member enum3: EnumOne optional=False
>      member enum4: EnumOne optional=True
> -enum QEnumTwo ['value1', 'value2']
> +enum QEnumTwo
>      prefix QENUM_TWO
> -enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
> +    member value1:
> +    member value2:
> +enum QType
>      prefix QTYPE
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
>  alternate TestIfAlternate
>      tag type
>      case foo: int
> @@ -60,7 +72,9 @@ alternate TestIfAlternate
>  command TestIfCmd q_obj_TestIfCmd-arg -> None
>     gen=True success_response=True boxed=False
>      if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
> -enum TestIfEnum ['foo', 'bar']
> +enum TestIfEnum
> +    member foo:
> +    member bar:
>      if defined(TEST_IF_ENUM)
>  event TestIfEvent q_obj_TestIfEvent-arg
>     boxed=False
> @@ -73,7 +87,8 @@ object TestIfUnion
>      tag type
>      case foo: q_obj_TestStruct-wrapper
>      if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
> -enum TestIfUnionKind ['foo']
> +enum TestIfUnionKind
> +    member foo:
>      if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
>  object TestStruct
>      member integer: int optional=False
> @@ -122,7 +137,21 @@ object UserDefNativeListUnion
>      case string: q_obj_strList-wrapper
>      case sizes: q_obj_sizeList-wrapper
>      case any: q_obj_anyList-wrapper
> -enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any']
> +enum UserDefNativeListUnionKind
> +    member integer:
> +    member s8:
> +    member s16:
> +    member s32:
> +    member s64:
> +    member u8:
> +    member u16:
> +    member u32:
> +    member u64:
> +    member number:
> +    member boolean:
> +    member string:
> +    member sizes:
> +    member any:
>  object UserDefOne
>      base UserDefZero
>      member string: str optional=False
> @@ -159,7 +188,8 @@ alternate __org.qemu_x-Alt
>      case b: __org.qemu_x-Base
>  object __org.qemu_x-Base
>      member __org.qemu_x-member1: __org.qemu_x-Enum optional=False
> -enum __org.qemu_x-Enum ['__org.qemu_x-value']
> +enum __org.qemu_x-Enum
> +    member __org.qemu_x-value:
>  object __org.qemu_x-Struct
>      base __org.qemu_x-Base
>      member __org.qemu_x-member2: str optional=False
> @@ -170,7 +200,8 @@ object __org.qemu_x-Union1
>      member type: __org.qemu_x-Union1Kind optional=False
>      tag type
>      case __org.qemu_x-branch: q_obj_str-wrapper
> -enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch']
> +enum __org.qemu_x-Union1Kind
> +    member __org.qemu_x-branch:
>  object __org.qemu_x-Union2
>      base __org.qemu_x-Base
>      tag __org.qemu_x-member1
> diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
> index 8627f978af..67c6c1ecef 100644
> --- a/tests/qapi-schema/test-qapi.py
> +++ b/tests/qapi-schema/test-qapi.py
> @@ -17,19 +17,18 @@ import sys
>  
>  
>  class QAPISchemaTestVisitor(QAPISchemaVisitor):
> -    def visit_enum_type(self, name, info, ifcond, values, prefix):
> -        print 'enum %s %s' % (name, values)
> +    def visit_enum_type(self, name, info, ifcond, members, prefix):
> +        print 'enum %s' % name
>          if prefix:
>              print '    prefix %s' % prefix
> +        self._print_members(members)
>          self._print_if(ifcond)
>  
>      def visit_object_type(self, name, info, ifcond, base, members, variants):
>          print 'object %s' % name
>          if base:
>              print '    base %s' % base.name
> -        for m in members:
> -            print '    member %s: %s optional=%s' % \
> -                (m.name, m.type.name, m.optional)
> +        self._print_members(members)
>          self._print_variants(variants)
>          self._print_if(ifcond)
>  
> @@ -51,6 +50,14 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
>          print '   boxed=%s' % boxed
>          self._print_if(ifcond)
>  
> +    @staticmethod
> +    def _print_members(members):
> +        for m in members:
> +            print '    member %s:' % m.name,
> +            if isinstance(m, QAPISchemaObjectTypeMember):
> +                print '%s optional=%s' % (m.type.name, m.optional),
> +            print
> +
>      @staticmethod
>      def _print_variants(variants):
>          if variants:

The change advertized in the commit message is hard to see among all the
other stuff going on.  I think this patch should be split into three
parts:

1. Rename QAPISchemaEnumType.values and related variables to members.
   Makes sense ever since commit 93bda4dd4 changed .values from list of
   string to list of QAPISchemaMember.  Obvious no-op.

2. Change the visit_enum_type().

3. Change test-qapi.py.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely
  2017-12-07 17:01     ` Marc-André Lureau
@ 2017-12-08  7:50       ` Markus Armbruster
  2018-01-11 21:24         ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-08  7:50 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU, Michael Roth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> On Thu, Dec 7, 2017 at 5:23 PM, Markus Armbruster <armbru@redhat.com> wrote:
>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>>
>>> The C standard has the initial value at 0 and the subsequent values
>>> incremented by 1. No need to set this explicitely.
>>>
>>> This will prevent from artificial "gaps" when compiling out some enum
>>> values and having unnecessarily large MAX values & enums arrays.
>>>
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>  scripts/qapi.py | 7 ++-----
>>>  1 file changed, 2 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>>> index 94b735d8d6..074ee221a1 100644
>>> --- a/scripts/qapi.py
>>> +++ b/scripts/qapi.py
>>> @@ -1985,14 +1985,11 @@ typedef enum %(c_name)s {
>>>  ''',
>>>                  c_name=c_name(name))
>>>
>>> -    i = 0
>>>      for value in enum_values:
>>>          ret += mcgen('''
>>> -    %(c_enum)s = %(i)d,
>>> +    %(c_enum)s,
>>>  ''',
>>> -                     c_enum=c_enum_const(name, value, prefix),
>>> -                     i=i)
>>> -        i += 1
>>> +                     c_enum=c_enum_const(name, value, prefix))
>>>
>>>      ret += mcgen('''
>>>  } %(c_name)s;
>>
>> Recapitulate review of v2: this risks entertaining mishaps like
>> compiling this one
>>
>>     typedef enum Color {
>>         COLOR_WHITE,
>> #if defined(NEED_CPU_H)
>> #if defined(TARGET_S390X)
>>         COLOR_BLUE,
>> #endif /* defined(TARGET_S390X) */
>> #endif /* defined(NEED_CPU_H) */
>>         COLOR_BLACK,
>>     } Color;
>>
>> in s390x-code (COLOR_BLACK = 2) and in target-independent code
>> (COLOR_BLACK = 1), then linking the two together.
>>
>> Same issue for struct members and such (previous patch).
>>
>> What's our story on preventing disaster here?
>>
>> In the long run, we want to split the generated code so that
>> target-specific and target-independent code are separate, and each part
>> is always compiled with consistent preprocessor symbols.  But I'm afraid
>> that's not in the card right now.
>
> Eh, I need to refresh my memories about that series, but I think
> that's what I did in v3
>
> It doesn't use the NEED_CPU_H trick. It has a seperate per-target target.json

Looking... aha!  target.json appears in PATCH 44 (which I haven't even
glanced at, yet).  The problem appears in PATCH 16, though.  Perhaps a
bit of patch reshuffling would do.

>> I therefore proposed the stupidest temporary stopgap that could possibly
>> work: apply conditionals *only* to qmp-introspect.c, leave everything
>> unconditional elsewhere.
>
> I don't like that idea much and I don't think we need that
> restriction, but I need to get back to that series on some point
> (probably after you finish the review).

It's a beefy series, and it's probably best to let me review the largest
prefix I can before we dive into discussion.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 19/50] qapi: add 'if' to enum members
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 19/50] qapi: add 'if' to enum members Marc-André Lureau
@ 2017-12-08  8:38   ` Markus Armbruster
  2018-01-11 21:24     ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-08  8:38 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

A bit more detail in the commit message would make this patch easier to
review.

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py                         | 39 ++++++++++++++++++++++++++++-----
>  tests/Makefile.include                  |  1 -
>  tests/qapi-schema/enum-dict-member.err  |  1 -
>  tests/qapi-schema/enum-dict-member.exit |  1 -
>  tests/qapi-schema/enum-dict-member.json |  2 --
>  tests/qapi-schema/enum-dict-member.out  |  0
>  tests/qapi-schema/qapi-schema-test.json |  5 +++--
>  tests/qapi-schema/qapi-schema-test.out  |  3 ++-
>  tests/qapi-schema/test-qapi.py          |  2 ++
>  9 files changed, 41 insertions(+), 13 deletions(-)
>  delete mode 100644 tests/qapi-schema/enum-dict-member.err
>  delete mode 100644 tests/qapi-schema/enum-dict-member.exit
>  delete mode 100644 tests/qapi-schema/enum-dict-member.json
>  delete mode 100644 tests/qapi-schema/enum-dict-member.out
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 386a577a59..1535de9ce7 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -659,6 +659,14 @@ def check_if(expr, info):
>              info, "'if' condition must be a string or a list of strings")
>  
>  
> +def check_unknown_keys(info, dict, allowed_keys):
> +    diff = set(dict) - allowed_keys
> +    if not diff:
> +        return
> +    raise QAPISemError(info, "Dictionnary has unknown keys: %s (allowed: %s)" %

s/Dictionnary/Dictionary/

> +        (', '.join(diff), ', '.join(allowed_keys)))

I'm afraid this duplicates a part of check_keys().  Could it be factored
out?

> +
> +
>  def check_type(info, source, value, allow_array=False,
>                 allow_dict=False, allow_optional=False,
>                 allow_metas=[]):
> @@ -739,6 +747,10 @@ def check_event(expr, info):
>                 allow_metas=meta)
>  
>  
> +def enum_get_values(expr):
> +    return [e if isinstance(e, str) else e['name'] for e in expr['data']]
> +
> +
>  def check_union(expr, info):
>      name = expr['union']
>      base = expr.get('base')
> @@ -798,7 +810,7 @@ def check_union(expr, info):
>          # If the discriminator names an enum type, then all members
>          # of 'data' must also be members of the enum type.
>          if enum_define:
> -            if key not in enum_define['data']:
> +            if key not in enum_get_values(enum_define):
>                  raise QAPISemError(info,
>                                     "Discriminator value '%s' is not found in "
>                                     "enum '%s'"
> @@ -806,7 +818,7 @@ def check_union(expr, info):
>  
>      # If discriminator is user-defined, ensure all values are covered
>      if enum_define:
> -        for value in enum_define['data']:
> +        for value in enum_get_values(enum_define):
>              if value not in members.keys():
>                  raise QAPISemError(info, "Union '%s' data missing '%s' branch"
>                                     % (name, value))
> @@ -837,7 +849,7 @@ def check_alternate(expr, info):
>          if qtype == 'QTYPE_QSTRING':
>              enum_expr = enum_types.get(value)
>              if enum_expr:
> -                for v in enum_expr['data']:
> +                for v in enum_get_values(enum_expr):
>                      if v in ['on', 'off']:
>                          conflicting.add('QTYPE_QBOOL')
>                      if re.match(r'[-+0-9.]', v): # lazy, could be tightened
> @@ -865,6 +877,14 @@ def check_enum(expr, info):
>          raise QAPISemError(info,
>                             "Enum '%s' requires a string for 'prefix'" % name)
>      for member in members:
> +        if isinstance(member, dict):
> +            if 'name' not in member:
> +                raise QAPISemError(info, "Dictionary member of enum '%s' must "
> +                                   "have a 'name' key" % name)
> +            if 'if' in member:
> +                check_if(member, info)
> +            check_unknown_keys(info, member, {'name', 'if'})
> +            member = member['name']
>          check_name(info, "Member of enum '%s'" % name, member,
>                     enum_member=True)
>  
> @@ -1280,9 +1300,11 @@ class QAPISchemaObjectType(QAPISchemaType):
>  class QAPISchemaMember(object):
>      role = 'member'
>  
> -    def __init__(self, name):
> +    def __init__(self, name, ifcond=None):
>          assert isinstance(name, str)
> +        assert ifcond is None or isinstance(ifcond, str)
>          self.name = name
> +        self.ifcond = ifcond
>          self.owner = None
>  
>      def set_owner(self, name):

QAPISchemaObjectTypeMember inherits .ifcond.  Peeking ahead: looks like
it'll get used when we add conditions to object type members, PATCH
23ff.  Okay.  Mentioning it in the commit message wouldn't hurt, though.

> @@ -1559,7 +1581,14 @@ class QAPISchema(object):
>                                              qtype_values, 'QTYPE'))
>  
>      def _make_enum_members(self, values):
> -        return [QAPISchemaMember(v) for v in values]
> +        enum = []
> +        for v in values:
> +            ifcond = None
> +            if isinstance(v, dict):
> +                ifcond = v.get('if')
> +                v = v['name']
> +            enum.append(QAPISchemaMember(v, ifcond))


I like brevity a lot, but if it's bought by assigning to a loop control
variable, I pass.  Cleaner:

           for v in values:
               if isinstance(v, dict):
                   name = v['name']
                   ifcond = v.get('if')
               else:
                   name = v
                   ifcond = None
           enum.append(QAPISchemaMember(name, ifcond))
                   
> +        return enum
>  
>      def _make_implicit_enum_type(self, name, info, ifcond, values):
>          # See also QAPISchemaObjectTypeMember._pretty_owner()
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 8dac7c9083..a9f0ddbe01 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -443,7 +443,6 @@ qapi-schema += empty.json
>  qapi-schema += enum-bad-name.json
>  qapi-schema += enum-bad-prefix.json
>  qapi-schema += enum-clash-member.json
> -qapi-schema += enum-dict-member.json
>  qapi-schema += enum-int-member.json
>  qapi-schema += enum-member-case.json
>  qapi-schema += enum-missing-data.json
> diff --git a/tests/qapi-schema/enum-dict-member.err b/tests/qapi-schema/enum-dict-member.err
> deleted file mode 100644
> index 8ca146ea59..0000000000
> --- a/tests/qapi-schema/enum-dict-member.err
> +++ /dev/null
> @@ -1 +0,0 @@
> -tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum' requires a string name
> diff --git a/tests/qapi-schema/enum-dict-member.exit b/tests/qapi-schema/enum-dict-member.exit
> deleted file mode 100644
> index d00491fd7e..0000000000
> --- a/tests/qapi-schema/enum-dict-member.exit
> +++ /dev/null
> @@ -1 +0,0 @@
> -1
> diff --git a/tests/qapi-schema/enum-dict-member.json b/tests/qapi-schema/enum-dict-member.json
> deleted file mode 100644
> index 79672e0f09..0000000000
> --- a/tests/qapi-schema/enum-dict-member.json
> +++ /dev/null
> @@ -1,2 +0,0 @@
> -# we reject any enum member that is not a string
> -{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
> diff --git a/tests/qapi-schema/enum-dict-member.out b/tests/qapi-schema/enum-dict-member.out
> deleted file mode 100644
> index e69de29bb2..0000000000

Hmm.  The dict instance of "enum value must be of an appropriate JSON
type" error class goes away in this patch, but the class remains.  Do we
still cover it?

There's enum-int-member.json, but it's not a good test: it dies in the
lexer.  I think we should replace the two tests by a single one.
Perhaps something like 'data': [ [] ] would do.

> diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
> index dc2c444fc1..ad2b405d83 100644
> --- a/tests/qapi-schema/qapi-schema-test.json
> +++ b/tests/qapi-schema/qapi-schema-test.json
> @@ -194,7 +194,8 @@
>  { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
>    'if': 'defined(TEST_IF_STRUCT)' }
>  
> -{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
> +{ 'enum': 'TestIfEnum', 'data':
> +  [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
>    'if': 'defined(TEST_IF_ENUM)' }
>  
>  { 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
> @@ -203,7 +204,7 @@
>  { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
>    'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
>  
> -{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
> +{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': 'TestIfEnum' },
>    'if': 'defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)' }
>  
>  { 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },

Should this hunk be in PATCH 04?

> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
> index 9a7cafc269..8a0cf1a551 100644
> --- a/tests/qapi-schema/qapi-schema-test.out
> +++ b/tests/qapi-schema/qapi-schema-test.out
> @@ -74,7 +74,7 @@ command TestIfCmd q_obj_TestIfCmd-arg -> None
>      if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
>  enum TestIfEnum
>      member foo:
> -    member bar:
> +    member bar: if=defined(TEST_IF_ENUM_BAR)
>      if defined(TEST_IF_ENUM)
>  event TestIfEvent q_obj_TestIfEvent-arg
>     boxed=False
> @@ -228,6 +228,7 @@ object q_obj_EVENT_D-arg
>      member enum3: EnumOne optional=True
>  object q_obj_TestIfCmd-arg
>      member foo: TestIfStruct optional=False
> +    member bar: TestIfEnum optional=False
>      if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
>  object q_obj_TestIfEvent-arg
>      member foo: TestIfStruct optional=False
> diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
> index 67c6c1ecef..a86c3b5ee1 100644
> --- a/tests/qapi-schema/test-qapi.py
> +++ b/tests/qapi-schema/test-qapi.py
> @@ -56,6 +56,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
>              print '    member %s:' % m.name,
>              if isinstance(m, QAPISchemaObjectTypeMember):
>                  print '%s optional=%s' % (m.type.name, m.optional),
> +            if m.ifcond:
> +                print 'if=%s' % m.ifcond,
>              print
>  
>      @staticmethod

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 20/50] qapi-event: add 'if' condition to generated enum
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 20/50] qapi-event: add 'if' condition to generated enum Marc-André Lureau
@ 2017-12-08 13:58   ` Markus Armbruster
  2017-12-08 14:07     ` Markus Armbruster
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-08 13:58 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add condition to QAPIEvent enum members based on the event 'if'.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi-event.py | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
> index 38f4264817..60c6f7030d 100644
> --- a/scripts/qapi-event.py
> +++ b/scripts/qapi-event.py
> @@ -168,7 +168,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
>      def visit_event(self, name, info, ifcond, arg_type, boxed):
>          self.decl += gen_event_send_decl(name, arg_type, boxed)
>          self.defn += gen_event_send(name, arg_type, boxed)
> -        self._event_names.append(QAPISchemaMember(name))
> +        self._event_names.append(QAPISchemaMember(name, ifcond))
>  
>  
>  (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()

No test coverage?

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 20/50] qapi-event: add 'if' condition to generated enum
  2017-12-08 13:58   ` Markus Armbruster
@ 2017-12-08 14:07     ` Markus Armbruster
  2018-01-11 21:31       ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-08 14:07 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Markus Armbruster <armbru@redhat.com> writes:

> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Add condition to QAPIEvent enum members based on the event 'if'.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  scripts/qapi-event.py | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
>> index 38f4264817..60c6f7030d 100644
>> --- a/scripts/qapi-event.py
>> +++ b/scripts/qapi-event.py
>> @@ -168,7 +168,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
>>      def visit_event(self, name, info, ifcond, arg_type, boxed):
>>          self.decl += gen_event_send_decl(name, arg_type, boxed)
>>          self.defn += gen_event_send(name, arg_type, boxed)
>> -        self._event_names.append(QAPISchemaMember(name))
>> +        self._event_names.append(QAPISchemaMember(name, ifcond))
>>  
>>  
>>  (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
>
> No test coverage?

Wait!  This patch has no effect, because the it merely puts the ifcond
argument into QAPISchemaMember.ifcond.  Only later patches put
QAPISchemaMember.ifcond to use.  Correct?

Aside: the ifcond_decorator could already be doing something with the
argument, but I'll be hanged if I remember how that magic works.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 22/50] tests: add some enum members tests
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 22/50] tests: add some enum members tests Marc-André Lureau
@ 2017-12-08 17:58   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-08 17:58 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  tests/Makefile.include                           | 3 +++
>  tests/qapi-schema/enum-dict-member-invalid.err   | 1 +
>  tests/qapi-schema/enum-dict-member-invalid.exit  | 1 +
>  tests/qapi-schema/enum-dict-member-invalid.json  | 2 ++
>  tests/qapi-schema/enum-dict-member-invalid.out   | 0
>  tests/qapi-schema/enum-dict-member-invalid2.err  | 1 +
>  tests/qapi-schema/enum-dict-member-invalid2.exit | 1 +
>  tests/qapi-schema/enum-dict-member-invalid2.json | 2 ++
>  tests/qapi-schema/enum-dict-member-invalid2.out  | 0
>  tests/qapi-schema/enum-if-invalid.err            | 1 +
>  tests/qapi-schema/enum-if-invalid.exit           | 1 +
>  tests/qapi-schema/enum-if-invalid.json           | 3 +++
>  tests/qapi-schema/enum-if-invalid.out            | 0
>  13 files changed, 16 insertions(+)
>  create mode 100644 tests/qapi-schema/enum-dict-member-invalid.err
>  create mode 100644 tests/qapi-schema/enum-dict-member-invalid.exit
>  create mode 100644 tests/qapi-schema/enum-dict-member-invalid.json
>  create mode 100644 tests/qapi-schema/enum-dict-member-invalid.out
>  create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.err
>  create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.exit
>  create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.json
>  create mode 100644 tests/qapi-schema/enum-dict-member-invalid2.out
>  create mode 100644 tests/qapi-schema/enum-if-invalid.err
>  create mode 100644 tests/qapi-schema/enum-if-invalid.exit
>  create mode 100644 tests/qapi-schema/enum-if-invalid.json
>  create mode 100644 tests/qapi-schema/enum-if-invalid.out
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index a9f0ddbe01..0aa532f029 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -443,6 +443,9 @@ qapi-schema += empty.json
>  qapi-schema += enum-bad-name.json
>  qapi-schema += enum-bad-prefix.json
>  qapi-schema += enum-clash-member.json
> +qapi-schema += enum-dict-member-invalid.json
> +qapi-schema += enum-dict-member-invalid2.json
> +qapi-schema += enum-if-invalid.json
>  qapi-schema += enum-int-member.json
>  qapi-schema += enum-member-case.json
>  qapi-schema += enum-missing-data.json
> diff --git a/tests/qapi-schema/enum-dict-member-invalid.err b/tests/qapi-schema/enum-dict-member-invalid.err
> new file mode 100644
> index 0000000000..d12cca0df3
> --- /dev/null
> +++ b/tests/qapi-schema/enum-dict-member-invalid.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/enum-dict-member-invalid.json:2: Dictionary member of enum 'MyEnum' must have a 'name' key
> diff --git a/tests/qapi-schema/enum-dict-member-invalid.exit b/tests/qapi-schema/enum-dict-member-invalid.exit
> new file mode 100644
> index 0000000000..d00491fd7e
> --- /dev/null
> +++ b/tests/qapi-schema/enum-dict-member-invalid.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/enum-dict-member-invalid.json b/tests/qapi-schema/enum-dict-member-invalid.json
> new file mode 100644
> index 0000000000..9cf8406867
> --- /dev/null
> +++ b/tests/qapi-schema/enum-dict-member-invalid.json
> @@ -0,0 +1,2 @@
> +# we reject any enum member that is not a string or a dict with 'name'
> +{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
> diff --git a/tests/qapi-schema/enum-dict-member-invalid.out b/tests/qapi-schema/enum-dict-member-invalid.out
> new file mode 100644
> index 0000000000..e69de29bb2
> diff --git a/tests/qapi-schema/enum-dict-member-invalid2.err b/tests/qapi-schema/enum-dict-member-invalid2.err
> new file mode 100644
> index 0000000000..f7dc1a2b33
> --- /dev/null
> +++ b/tests/qapi-schema/enum-dict-member-invalid2.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/enum-dict-member-invalid2.json:2: Dictionnary has unknown keys: bad-key (allowed: name, if)
> diff --git a/tests/qapi-schema/enum-dict-member-invalid2.exit b/tests/qapi-schema/enum-dict-member-invalid2.exit
> new file mode 100644
> index 0000000000..d00491fd7e
> --- /dev/null
> +++ b/tests/qapi-schema/enum-dict-member-invalid2.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/enum-dict-member-invalid2.json b/tests/qapi-schema/enum-dict-member-invalid2.json
> new file mode 100644
> index 0000000000..6664c59201
> --- /dev/null
> +++ b/tests/qapi-schema/enum-dict-member-invalid2.json
> @@ -0,0 +1,2 @@
> +# we reject any enum member that is not a string or a dict with 'name'
> +{ 'enum': 'MyEnum', 'data': [ { 'name': 'foo', 'bad-key': 'str' } ] }
> diff --git a/tests/qapi-schema/enum-dict-member-invalid2.out b/tests/qapi-schema/enum-dict-member-invalid2.out
> new file mode 100644
> index 0000000000..e69de29bb2
> diff --git a/tests/qapi-schema/enum-if-invalid.err b/tests/qapi-schema/enum-if-invalid.err
> new file mode 100644
> index 0000000000..54c3cf887b
> --- /dev/null
> +++ b/tests/qapi-schema/enum-if-invalid.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/enum-if-invalid.json:2: 'if' condition must be a string or a list of strings
> diff --git a/tests/qapi-schema/enum-if-invalid.exit b/tests/qapi-schema/enum-if-invalid.exit
> new file mode 100644
> index 0000000000..d00491fd7e
> --- /dev/null
> +++ b/tests/qapi-schema/enum-if-invalid.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/enum-if-invalid.json b/tests/qapi-schema/enum-if-invalid.json
> new file mode 100644
> index 0000000000..60bd0ef1d7
> --- /dev/null
> +++ b/tests/qapi-schema/enum-if-invalid.json
> @@ -0,0 +1,3 @@
> +# check invalid 'if' type
> +{ 'enum': 'TestIfEnum', 'data':
> +  [ 'foo', { 'name' : 'bar', 'if': { 'val': 'foo' } } ] }
> diff --git a/tests/qapi-schema/enum-if-invalid.out b/tests/qapi-schema/enum-if-invalid.out
> new file mode 100644
> index 0000000000..e69de29bb2

These tests are related to the coverage gap I mentioned in my review of
PATCH 19.

I think it makes sense to add related new tests together, right when we
add whatever they test.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 23/50] qapi: add 'if' to struct members and implicit objects members
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 23/50] qapi: add 'if' to struct members and implicit objects members Marc-André Lureau
@ 2017-12-09  8:18   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-09  8:18 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> check_type() will now accept a DICT { 'type': TYPENAME, 'if': ... }
> instead of a TYPENAME. This is the case in various situations where
> implicit object types are allowed such as commands/events arguments
> and return type, base and branches of union & alternate.

Uh, do you mean where implicit object type are *not* allowed?

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py                         | 20 ++++++++++++++++----
>  tests/qapi-schema/qapi-schema-test.json | 12 +++++++++---
>  tests/qapi-schema/qapi-schema-test.out  |  4 +++-
>  3 files changed, 28 insertions(+), 8 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index df2a304e8f..15711f96fa 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -696,7 +696,15 @@ def check_type(info, source, value, allow_array=False,
>          return
>  
>      if not allow_dict:
> -        raise QAPISemError(info, "%s should be a type name" % source)
> +        if isinstance(value, dict) and 'type' in value:
> +            check_type(info, source, value['type'], allow_array,
> +                       allow_dict, allow_optional, allow_metas)
> +            if 'if' in value:
> +                check_if(value, info)
> +            check_unknown_keys(info, value, {'type', 'if'})
> +            return
> +        else:
> +            raise QAPISemError(info, "%s should be a type name" % source)

@allow_dict becomes a misnomer: dictionaries are now always allowed, but
they have different meaning (implicit type vs. named type with
additional attributes).

Rename to @allow_implicit?

>  
>      if not isinstance(value, OrderedDict):
>          raise QAPISemError(info,
[...]

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 24/50] qapi: add some struct member tests
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 24/50] qapi: add some struct member tests Marc-André Lureau
@ 2017-12-09  9:07   ` Markus Armbruster
  2018-01-11 21:31     ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-09  9:07 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  tests/Makefile.include                    |  2 ++
>  tests/qapi-schema/struct-if-invalid.err   |  1 +
>  tests/qapi-schema/struct-if-invalid.exit  |  1 +
>  tests/qapi-schema/struct-if-invalid.json  |  3 +++
>  tests/qapi-schema/struct-if-invalid.out   |  0
>  tests/qapi-schema/struct-member-type.err  |  0
>  tests/qapi-schema/struct-member-type.exit |  1 +
>  tests/qapi-schema/struct-member-type.json |  2 ++
>  tests/qapi-schema/struct-member-type.out  | 12 ++++++++++++
>  9 files changed, 22 insertions(+)
>  create mode 100644 tests/qapi-schema/struct-if-invalid.err
>  create mode 100644 tests/qapi-schema/struct-if-invalid.exit
>  create mode 100644 tests/qapi-schema/struct-if-invalid.json
>  create mode 100644 tests/qapi-schema/struct-if-invalid.out
>  create mode 100644 tests/qapi-schema/struct-member-type.err
>  create mode 100644 tests/qapi-schema/struct-member-type.exit
>  create mode 100644 tests/qapi-schema/struct-member-type.json
>  create mode 100644 tests/qapi-schema/struct-member-type.out
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 0aa532f029..44a3d8895e 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -520,7 +520,9 @@ qapi-schema += returns-whitelist.json
>  qapi-schema += struct-base-clash-deep.json
>  qapi-schema += struct-base-clash.json
>  qapi-schema += struct-data-invalid.json
> +qapi-schema += struct-if-invalid.json
>  qapi-schema += struct-member-invalid.json
> +qapi-schema += struct-member-type.json
>  qapi-schema += trailing-comma-list.json
>  qapi-schema += trailing-comma-object.json
>  qapi-schema += type-bypass-bad-gen.json
> diff --git a/tests/qapi-schema/struct-if-invalid.err b/tests/qapi-schema/struct-if-invalid.err
> new file mode 100644
> index 0000000000..42245262a9
> --- /dev/null
> +++ b/tests/qapi-schema/struct-if-invalid.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/struct-if-invalid.json:2: Member 'bar' of 'data' for struct 'TestIfStruct' should be a type name
> diff --git a/tests/qapi-schema/struct-if-invalid.exit b/tests/qapi-schema/struct-if-invalid.exit
> new file mode 100644
> index 0000000000..d00491fd7e
> --- /dev/null
> +++ b/tests/qapi-schema/struct-if-invalid.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/struct-if-invalid.json b/tests/qapi-schema/struct-if-invalid.json
> new file mode 100644
> index 0000000000..466cdb61e1
> --- /dev/null
> +++ b/tests/qapi-schema/struct-if-invalid.json
> @@ -0,0 +1,3 @@
> +# check missing 'type'
> +{ 'struct': 'TestIfStruct', 'data':
> +  { 'foo': 'int', 'bar': { 'if': 'defined(TEST_IF_STRUCT_BAR)' } } }

Hmm.  This tests the previous patch's change to check_type().  It
demonstrates that the "should be a type name" error message can be
suboptimal: it gets triggered when

    not isinstance(value, str)
    and not (isinstance(value, dict) and 'type' in value)

Fine when the value is neither str not dict.  Suboptimal when it's dict
and 'type' is missing.  A more obvious example of suboptimality would be

   'bar': { 'tvpe': 'int' }

The previous patch's

        if isinstance(value, dict) and 'type' in value:
            check_type(info, source, value['type'], allow_array,
                       allow_dict, allow_optional, allow_metas)
            if 'if' in value:
                check_if(value, info)
            check_unknown_keys(info, value, {'type', 'if'})
            return
        else:
            raise QAPISemError(info, "%s should be a type name" % source)

should be improved to something like

        if not isinstance(value, dict):
            raise QAPISemError(
                info, "%s should be a type name or dictionary" % source)
        if 'type' not in value:
            raise QAPISemError(
                info, "%s must have a member 'type'" % source)
        check_type(info, source, value['type'], allow_array,
                   allow_dict, allow_optional, allow_metas)
        if 'if' in value:
            check_if(value, info)
        check_unknown_keys(info, value, {'type', 'if'})
        return

producing

    struct-if-invalid.json:2: Member 'bar' of 'data' for struct 'TestIfStruct' must have a member 'type'

The fact that I missed this in review of the code, but noticed it in the
tests is why I want tests added together with the code they test.

Nitpick: the file name struct-if-invalid makes me expect an invalid if.
Not the case.  It's a missing type.  Let's rename accordingly.

> diff --git a/tests/qapi-schema/struct-if-invalid.out b/tests/qapi-schema/struct-if-invalid.out
> new file mode 100644
> index 0000000000..e69de29bb2
> diff --git a/tests/qapi-schema/struct-member-type.err b/tests/qapi-schema/struct-member-type.err
> new file mode 100644
> index 0000000000..e69de29bb2
> diff --git a/tests/qapi-schema/struct-member-type.exit b/tests/qapi-schema/struct-member-type.exit
> new file mode 100644
> index 0000000000..573541ac97
> --- /dev/null
> +++ b/tests/qapi-schema/struct-member-type.exit
> @@ -0,0 +1 @@
> +0
> diff --git a/tests/qapi-schema/struct-member-type.json b/tests/qapi-schema/struct-member-type.json
> new file mode 100644
> index 0000000000..8b33027817
> --- /dev/null
> +++ b/tests/qapi-schema/struct-member-type.json
> @@ -0,0 +1,2 @@
> +# check member 'a' with 'type' key only
> +{ 'struct': 'foo', 'data': { 'a': { 'type': 'str' } } }
> diff --git a/tests/qapi-schema/struct-member-type.out b/tests/qapi-schema/struct-member-type.out
> new file mode 100644
> index 0000000000..04b969d2e3
> --- /dev/null
> +++ b/tests/qapi-schema/struct-member-type.out
> @@ -0,0 +1,12 @@
> +enum QType
> +    prefix QTYPE
> +    member none:
> +    member qnull:
> +    member qnum:
> +    member qstring:
> +    member qdict:
> +    member qlist:
> +    member qbool:
> +object foo
> +    member a: str optional=False
> +object q_empty

This is a positive test, isn't it?  Positive tests go into
qapi-schema-test.json.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 26/50] qapi: add 'if' on union variants
  2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 26/50] qapi: add 'if' on union variants Marc-André Lureau
@ 2017-12-11 10:36   ` Markus Armbruster
  2018-01-11 21:32     ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-11 10:36 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py                         | 15 ++++++++++-----
>  tests/qapi-schema/qapi-schema-test.json |  7 ++++++-
>  tests/qapi-schema/qapi-schema-test.out  |  8 ++++++++
>  tests/qapi-schema/test-qapi.py          |  5 ++++-
>  4 files changed, 28 insertions(+), 7 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 15711f96fa..2f14edfa1f 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1412,8 +1412,8 @@ class QAPISchemaObjectTypeVariants(object):
>  class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
>      role = 'branch'
>  
> -    def __init__(self, name, typ):
> -        QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
> +    def __init__(self, name, typ, ifcond=None):
> +        QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond)
>  
>  
>  class QAPISchemaAlternateType(QAPISchemaType):
> @@ -1674,13 +1674,18 @@ class QAPISchema(object):
>          return QAPISchemaObjectTypeVariant(case, typ)
>  
>      def _make_simple_variant(self, case, typ, info):
> +        ifcond = None
> +        if isinstance(typ, dict):
> +            check_unknown_keys(info, typ, {'type', 'if'})
> +            ifcond = typ.get('if')
> +            typ = typ['type']
>          if isinstance(typ, list):
>              assert len(typ) == 1
>              typ = self._make_array_type(typ[0], info)
>          typ = self._make_implicit_object_type(
>              typ, info, None, self.lookup_type(typ).ifcond,
>              'wrapper', [self._make_member('data', typ, info)])
> -        return QAPISchemaObjectTypeVariant(case, typ)
> +        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
>  
>      def _def_union_type(self, expr, info, doc):
>          name = expr['union']
> @@ -1700,8 +1705,8 @@ class QAPISchema(object):
>          else:
>              variants = [self._make_simple_variant(key, value, info)
>                          for (key, value) in data.iteritems()]
> -            typ = self._make_implicit_enum_type(name, info, ifcond,
> -                                                [v.name for v in variants])
> +            values = [{'name': v.name, 'if': v.ifcond} for v in variants]
> +            typ = self._make_implicit_enum_type(name, info, ifcond, values)
>              tag_member = QAPISchemaObjectTypeMember('type', typ, False)
>              members = [tag_member]
>          self._def_entity(
> diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
> index 5cfccabb3d..895e80a978 100644
> --- a/tests/qapi-schema/qapi-schema-test.json
> +++ b/tests/qapi-schema/qapi-schema-test.json
> @@ -200,9 +200,14 @@
>    [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
>    'if': 'defined(TEST_IF_ENUM)' }
>  
> -{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
> +{ 'union': 'TestIfUnion', 'data':
> +  { 'foo': 'TestStruct',
> +    'union_bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
>    'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
>  
> +{ 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' },
> +  'if': 'defined(TEST_IF_UNION)' }
> +
>  { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
>    'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
>  
> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
> index 6df4e49c69..ee009c5626 100644
> --- a/tests/qapi-schema/qapi-schema-test.out
> +++ b/tests/qapi-schema/qapi-schema-test.out
> @@ -87,9 +87,14 @@ object TestIfUnion
>      member type: TestIfUnionKind optional=False
>      tag type
>      case foo: q_obj_TestStruct-wrapper
> +    case union_bar: q_obj_str-wrapper if=defined(TEST_IF_UNION_BAR)

PATCH 22, but I only spotted it here.  We say "if=COND" in some places,
...

>      if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
> +command TestIfUnionCmd q_obj_TestIfUnionCmd-arg -> None
> +   gen=True success_response=True boxed=False
> +    if defined(TEST_IF_UNION)

... and "if COND" in other places.  I guess the '=' is there to match
existing flag printing like optional=BOOL.

I'd prefer less decorated output, i.e. instead of

    enum TestIfEnum
        member foo:
        member bar: if=defined(TEST_IF_ENUM_BAR)
        if defined(TEST_IF_ENUM)

something like

enum TestIfEnum
    member foo
    member bar
        if defined(TEST_IF_ENUM_BAR)
    if defined(TEST_IF_ENUM)

Could touch that up on commit.

>  enum TestIfUnionKind
>      member foo:
> +    member union_bar: if=defined(TEST_IF_UNION_BAR)
>      if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
>  object TestStruct
>      member integer: int optional=False
> @@ -235,6 +240,9 @@ object q_obj_TestIfEvent-arg
>      member foo: TestIfStruct optional=False
>      member bar: TestIfEnum optional=False if=defined(TEST_IF_EVT_BAR)
>      if defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)
> +object q_obj_TestIfUnionCmd-arg
> +    member union_cmd_arg: TestIfUnion optional=False
> +    if defined(TEST_IF_UNION)
>  object q_obj_TestStruct-wrapper
>      member data: TestStruct optional=False
>  object q_obj_UserDefFlatUnion2-base
> diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
> index a86c3b5ee1..87a8efff78 100644
> --- a/tests/qapi-schema/test-qapi.py
> +++ b/tests/qapi-schema/test-qapi.py
> @@ -65,7 +65,10 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
>          if variants:
>              print '    tag %s' % variants.tag_member.name
>              for v in variants.variants:
> -                print '    case %s: %s' % (v.name, v.type.name)
> +                print '    case %s: %s' % (v.name, v.type.name),
> +                if v.ifcond:
> +                    print 'if=%s' % v.ifcond,
> +                print
>  
>      @staticmethod
>      def _print_if(ifcond):

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 28/50] qapi: add 'if' to alternate variant
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 28/50] qapi: add 'if' to alternate variant Marc-André Lureau
@ 2017-12-12 14:51   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-12 14:51 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py                         | 9 ++++++++-
>  tests/qapi-schema/qapi-schema-test.json | 6 +++++-
>  tests/qapi-schema/qapi-schema-test.out  | 8 +++++++-
>  3 files changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 2f14edfa1f..19e48bd4d2 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -849,6 +849,9 @@ def check_alternate(expr, info):
       for (key, value) in members.items():
           check_name(info, "Member of alternate '%s'" % name, key)

           # Ensure alternates have no type conflicts.
>          check_type(info, "Member '%s' of alternate '%s'" % (key, name),
>                     value,
>                     allow_metas=['built-in', 'union', 'struct', 'enum'])
> +        if isinstance(value, dict):
> +            check_unknown_keys(info, value, {'type', 'if'})
> +            value = value['type']
>          qtype = find_alternate_member_qtype(value)
>          if not qtype:
>              raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "

I stared at this some because I couldn't see the check_if().  Looks like
it's done in check_type().  I guess I'm hitting the limits of what I can
do in *patch* review, and to do better, I'd have to go through the
resulting code with a fine comb.

You generalize the right hand side from "TYPE" to {"type": "TYPE", "if:
"IFCOND"}, where "if" is optional.  The old "TYPE" becomes syntactic
sugar for {"type": "TYPE"}.  Two remarks:

* Since the right hand side is more than just a type, the name
  check_type() is now inappropriate.  Since PATCH 23.

* The sane way to do syntactic sugar is to desugar at the first
  opportunity.  You do the opposite: you handle the new aspect of the
  general form first, and then rewrite it to the sugared form for
  further processing, most probably to reduce churn.  Reducing churn is
  good, but I find the resulting code hard to follow, because @value
  changes meaning halfway through.  May well apply to the other similar
  patches, too.

> @@ -1671,7 +1674,11 @@ class QAPISchema(object):
>                                                None))
>  
>      def _make_variant(self, case, typ):
> -        return QAPISchemaObjectTypeVariant(case, typ)
> +        ifcond = None
> +        if isinstance(typ, dict):
> +            ifcond = typ.get('if')
> +            typ = typ['type']
> +        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
>  
>      def _make_simple_variant(self, case, typ, info):
>          ifcond = None
> diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
> index 895e80a978..f7a62b24d1 100644
> --- a/tests/qapi-schema/qapi-schema-test.json
> +++ b/tests/qapi-schema/qapi-schema-test.json
> @@ -208,9 +208,13 @@
>  { 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' },
>    'if': 'defined(TEST_IF_UNION)' }
>  
> -{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
> +{ 'alternate': 'TestIfAlternate', 'data':
> +  { 'foo': 'int', 'alt_bar': { 'type': 'TestStruct', 'if': 'defined(TEST_IF_ALT_BAR)'} },
>    'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
>  
> +{ 'command': 'TestIfAlternateCmd', 'data': { 'alt_cmd_arg': 'TestIfAlternate' },
> +  'if': 'defined(TEST_IF_ALT)' }
> +
>  { 'command': 'TestIfCmd', 'data':
>    { 'foo': 'TestIfStruct',
>      'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } },
> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
> index ee009c5626..6887e49c9b 100644
> --- a/tests/qapi-schema/qapi-schema-test.out
> +++ b/tests/qapi-schema/qapi-schema-test.out
> @@ -67,8 +67,11 @@ enum QType
>  alternate TestIfAlternate
>      tag type
>      case foo: int
> -    case bar: TestStruct
> +    case alt_bar: TestStruct if=defined(TEST_IF_ALT_BAR)
>      if defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)
> +command TestIfAlternateCmd q_obj_TestIfAlternateCmd-arg -> None
> +   gen=True success_response=True boxed=False
> +    if defined(TEST_IF_ALT)
>  command TestIfCmd q_obj_TestIfCmd-arg -> None
>     gen=True success_response=True boxed=False
>      if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
> @@ -232,6 +235,9 @@ object q_obj_EVENT_D-arg
>      member b: str optional=False
>      member c: str optional=True
>      member enum3: EnumOne optional=True
> +object q_obj_TestIfAlternateCmd-arg
> +    member alt_cmd_arg: TestIfAlternate optional=False
> +    if defined(TEST_IF_ALT)
>  object q_obj_TestIfCmd-arg
>      member foo: TestIfStruct optional=False
>      member bar: TestIfEnum optional=False if=defined(TEST_IF_CMD_BAR)

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 30/50] qapi: add #if conditions to generated alternate variants
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 30/50] qapi: add #if conditions to generated alternate variants Marc-André Lureau
@ 2017-12-12 19:25   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-12 19:25 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Mostly covered by previous patches already.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi-introspect.py | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
> index ef2d5577db..d6194ff702 100644
> --- a/scripts/qapi-introspect.py
> +++ b/scripts/qapi-introspect.py
> @@ -172,7 +172,7 @@ const QLitObject %(c_name)s = %(c_string)s;
>  
>      def visit_alternate_type(self, name, info, ifcond, variants):
>          self._gen_qlit(name, 'alternate',
> -                       {'members': [{'type': self._use_type(m.type)}
> +                       {'members': [({'type': self._use_type(m.type)}, m.ifcond)
>                                      for m in variants.variants]}, ifcond)
>  
>      def visit_command(self, name, info, ifcond, arg_type, ret_type,

Adds blank lines to qmp-introspect.c, just like PATCH 12, which see.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 31/50] docs: document schema configuration
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 31/50] docs: document schema configuration Marc-André Lureau
@ 2017-12-13 10:41   ` Markus Armbruster
  2017-12-13 19:49     ` Eric Blake
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-13 10:41 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Eric Blake

Cc: Eric for an additional pair of eyeballs.

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  docs/devel/qapi-code-gen.txt | 37 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 37 insertions(+)
>
> diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
> index 0a90f2278a..24fc6f74ee 100644
> --- a/docs/devel/qapi-code-gen.txt
> +++ b/docs/devel/qapi-code-gen.txt
> @@ -682,6 +682,43 @@ Example: Red Hat, Inc. controls redhat.com, and may therefore add a
>  downstream command __com.redhat_drive-mirror.
>  
>  
> +=== Configuring the schema ===
> +
> +'struct', 'enum', 'union', 'alternate', 'command' and 'event'
> +top-level QAPI expressions can take a 'if' keyword like:

an 'if' key

> +
> +{ 'struct': 'IfStruct', 'data': { 'foo': 'int' },
> +  'if': 'defined(IF_STRUCT) && defined(FOO)' }

Perhaps we should add something like

    Code generated for such conditional definitions will be guarded with
    #if IFCOND, where IFCOND is the value of the 'if' key.

> +
> +Members can be exploded as dictionnary with 'type' & 'if' keys:

dictionary

I get what you mean by "can be exploded", but can we phrase this more
clearly?

In section "Struct types", we have

    A struct is a dictionary containing a single 'data' key whose value is
    a dictionary; the dictionary may be empty.  This corresponds to a
    struct in C or an Object in JSON. Each value of the 'data' dictionary
    must be the name of a type, or a one-element array containing a type
    name.

The part "must be the name of a type, or a one-element array containing
a type" name is now wrong.

Likewise, in section "Enumeration types"

    An enumeration type is a dictionary containing a single 'data' key
    whose value is a list of strings.

> +
> +{ 'struct': 'IfStruct', 'data':
> +  { 'foo': 'int',
> +    'bar': { 'type': 'int', 'if': 'defined(IF_STRUCT_BAR)'} } }

Perhaps add something like

    Code generated for such conditional members will be guarded with #if
    IFCOND, where IFCOND is the value of the 'if' key.

> +
> +Enum values can be exploded as dictionnary with 'name' & 'if' keys:

dictionnary and exploded again.

> +
> +{ 'enum': 'IfEnum', 'data':
> +  [ 'foo',
> +    { 'name' : 'bar', 'if': 'defined(IF_ENUM_BAR)' } ] }
> +
> +The C code generators will wrap the corresponding lines with #if / #endif
> +pre-processor conditions for a given 'if' value.
> +
> +Example for enum values:
> +
> +enum IfEnum {
> +     IF_ENUM_FOO,
> +#if defined(IF_ENUM_BAR)
> +     IF_ENUM_BAR,
> +#endif /* defined(IF_ENUM_BAR) */
> +     IF_ENUM__MAX
> +}

Hmm.  If enumeration documentation profits from an example, it stands to
reason that the previous two would, too.

Should we (additionally?) add examples of 'if' in section "Code
generation"?

> +
> +Please note that you are responsbile to ensure that the C code will
> +compile with an arbitrary combination of conditions, since the
> +generators are unable to check it at this point.
> +
>  == Client JSON Protocol introspection ==
>  
>  Clients of a Client JSON Protocol commonly need to figure out what

Do we need to update section "Client JSON Protocol introspection"?

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 32/50] qapi2texi: add 'If:' section to generated documentation
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 32/50] qapi2texi: add 'If:' section to generated documentation Marc-André Lureau
@ 2017-12-13 12:35   ` Markus Armbruster
  2017-12-13 19:54     ` Eric Blake
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-13 12:35 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth, Eric Blake

Cc: Eric for an additional pair of eyeballs.

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The documentation is generated only once, and doesn't know C
> pre-conditions. Add 'If:' sections for top-level entities.

Is this what we want?

QMP also exists only once.  Should the generated qemu-qmp-ref.* document
that instance of QMP, or should it document all potential instances of
QMP?

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi2texi.py | 24 +++++++++++++-----------
>  1 file changed, 13 insertions(+), 11 deletions(-)
>
> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> index e72e7cfe0b..150e7045d2 100755
> --- a/scripts/qapi2texi.py
> +++ b/scripts/qapi2texi.py
> @@ -132,7 +132,6 @@ def texi_enum_value(value):
>      """Format a table of members item for an enumeration value"""
>      return '@item @code{%s}\n' % value.name
>  
> -
>  def texi_member(member, suffix=''):
>      """Format a table of members item for an object type member"""
>      typ = member.type.doc_type()

Spurious whitespace change.  PEP8 wants the original spacing here.

> @@ -175,7 +174,7 @@ def texi_members(doc, what, base, variants, member_func):
>      return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items)
>  
>  
> -def texi_sections(doc):
> +def texi_sections(doc, ifcond):
>      """Format additional sections following arguments"""
>      body = ''
>      for section in doc.sections:
> @@ -189,14 +188,16 @@ def texi_sections(doc):
>              body += '\n\n@b{%s:}\n' % name
>  
>          body += func(doc)
> +    if ifcond:
> +        body += '\n\n@b{If:} @code{%s}' % ifcond
>      return body
>  
>  
> -def texi_entity(doc, what, base=None, variants=None,
> +def texi_entity(doc, what, ifcond, base=None, variants=None,
>                  member_func=texi_member):
>      return (texi_body(doc)
>              + texi_members(doc, what, base, variants, member_func)
> -            + texi_sections(doc))
> +            + texi_sections(doc, ifcond))
>  
>  
>  class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
> @@ -213,7 +214,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>              self.out += '\n'
>          self.out += TYPE_FMT(type='Enum',
>                               name=doc.symbol,
> -                             body=texi_entity(doc, 'Values',
> +                             body=texi_entity(doc, 'Values', ifcond,
>                                                member_func=texi_enum_value))
>  
>      def visit_object_type(self, name, info, ifcond, base, members, variants):
> @@ -224,7 +225,8 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>              self.out += '\n'
>          self.out += TYPE_FMT(type='Object',
>                               name=doc.symbol,
> -                             body=texi_entity(doc, 'Members', base, variants))
> +                             body=texi_entity(doc, 'Members', ifcond,
> +                                              base, variants))
>  
>      def visit_alternate_type(self, name, info, ifcond, variants):
>          doc = self.cur_doc
> @@ -232,7 +234,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>              self.out += '\n'
>          self.out += TYPE_FMT(type='Alternate',
>                               name=doc.symbol,
> -                             body=texi_entity(doc, 'Members'))
> +                             body=texi_entity(doc, 'Members', ifcond))
>  
>      def visit_command(self, name, info, ifcond, arg_type, ret_type,
>                        gen, success_response, boxed):
> @@ -242,9 +244,9 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>          if boxed:
>              body = texi_body(doc)
>              body += '\n@b{Arguments:} the members of @code{%s}' % arg_type.name
> -            body += texi_sections(doc)
> +            body += texi_sections(doc, ifcond)
>          else:
> -            body = texi_entity(doc, 'Arguments')
> +            body = texi_entity(doc, 'Arguments', ifcond)
>          self.out += MSG_FMT(type='Command',
>                              name=doc.symbol,
>                              body=body)
> @@ -255,7 +257,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>              self.out += '\n'
>          self.out += MSG_FMT(type='Event',
>                              name=doc.symbol,
> -                            body=texi_entity(doc, 'Arguments'))
> +                            body=texi_entity(doc, 'Arguments', ifcond))
>  
>      def symbol(self, doc, entity):
>          self.cur_doc = doc
> @@ -266,7 +268,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>          assert not doc.args
>          if self.out:
>              self.out += '\n'
> -        self.out += texi_body(doc) + texi_sections(doc)
> +        self.out += texi_body(doc) + texi_sections(doc, None)
>  
>  
>  def texi_schema(schema):

Missing: coverage in tests/qapi-schema/doc-good.json.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 27/50] qapi: add #if conditions to generated variants
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 27/50] qapi: add #if conditions to generated variants Marc-André Lureau
@ 2017-12-13 12:37   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-13 12:37 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Adds blank lines to qmp-introspect.c, just like PATCH 12, which see.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 36/50] qapi: add conditions to VNC type/commands/events on the schema
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 36/50] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
@ 2017-12-13 14:12   ` Markus Armbruster
  2017-12-13 14:20     ` Daniel P. Berrange
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-13 14:12 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Dr. David Alan Gilbert, Gerd Hoffmann, Daniel P. Berrange

Cc: Daniel for his opinion on QCryptoCipherAlgorithm member des-rfb.

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add #if defined(CONFIG_VNC) in generated code, and adjust the
> qmp/hmp code accordingly.
>
> Commands made conditional:
>
> * query-vnc, query-vnc-servers, change-vnc-password
>
>   Before the patch, the commands for !CONFIG_VNC are stubs that fail
>   like this:
>
>     {"error": {"class": "GenericError",
>                "desc": "The feature 'vnc' is not enabled"}}
>
>   Afterwards, they fail like this:
>
>     {"error": {"class": "CommandNotFound",
>                "desc": "The command FOO has not been found"}}
>
>   I call that an improvement, because it lets clients distinguish
>   between command unavailable (class CommandNotFound) and command failed
>   (class GenericError).

Moreover, query-qmp-schema no longer reports the command as available.
That's the point of this series!  Let's spell it out in the commit
message.

Same for events etc.

How this affects HMP is worth describing, too.

> Events made conditional:
>
> * VNC_CONNECTED, VNC_INITIALIZED, VNC_DISCONNECTED
>
> Enum made conditional:

The enum isn't made conditional, only one of its values is.  Suggest "
Enumeration values made conditional:".

> * QCryptoCipherAlgorithm
>
>     # @des-rfb: RFB specific variant of single DES. Do not use except in VNC.

Daniel, is this okay?

> Occurrences of VNC (case insensitive) in the schema that aren't
> covered by this change:
>
> * add_client
>
>   Command has other uses, including "socket bases character devices".
>   These are unconditional as far as I can tell.
>
> * set_password, expire_password
>
>   In theory, these commands could be used for managing any service's
>   password.  In practice, they're used for VNC and SPICE services.
>   They're documented for "remote display session" / "remote display
>   server".
>
>   The service is selected by argument @protocol.  The code special-cases
>   protocol-specific argument checking, then calls a protocol-specific
>   function to do the work.  If it fails, the command fails with "Could
>   not set password".  It does when the service isn't compiled in (it's a
>   stub then).
>
>   We could make these commands conditional on the conjunction of all
>   services [currently: defined(CONFIG_VNC) || defined(CONFIG_SPICE)],
>   but I doubt it's worthwhile.

What could be worthwhile: change @protocol from 'str' to suitable
enumeration type with appropriately conditional values, so that
introspection correctly reports available functioniality.

Not possible for add_client, because that one overloads protocol
further: "spice" and "vnc" are special, anything else is interpreted as
character device name.  Character devices named "spice" or "vnc" don't
work.  Bad design.  Needs to be replaced & deprecated.

> * change
>
>   Command has other uses, namely changing media.
>   This patch inlines a stub; no functional change.

Already deprecated.

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi/crypto.json           |  3 ++-
>  qapi/ui.json               | 45 ++++++++++++++++++++++++++++-----------------
>  ui/vnc.h                   |  2 ++
>  crypto/cipher-builtin.c    |  9 +++++++++
>  crypto/cipher-gcrypt.c     | 10 ++++++++--
>  crypto/cipher-nettle.c     | 14 +++++++++++---
>  crypto/cipher.c            | 13 +++++++++++--
>  hmp.c                      |  9 ++++++++-
>  qmp.c                      | 30 ++++--------------------------
>  tests/test-crypto-cipher.c |  2 ++
>  hmp-commands-info.hx       |  2 ++
>  11 files changed, 87 insertions(+), 52 deletions(-)
>
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 288bc056ef..09535b7be2 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -79,7 +79,8 @@
>  { 'enum': 'QCryptoCipherAlgorithm',
>    'prefix': 'QCRYPTO_CIPHER_ALG',
>    'data': ['aes-128', 'aes-192', 'aes-256',
> -           'des-rfb', '3des',
> +           { 'name': 'des-rfb', 'if': 'defined(CONFIG_VNC)' },
> +           '3des',
>             'cast5-128',
>             'serpent-128', 'serpent-192', 'serpent-256',
>             'twofish-128', 'twofish-192', 'twofish-256']}
> diff --git a/qapi/ui.json b/qapi/ui.json
> index e5d6610b4a..4b573d214b 100644
> --- a/qapi/ui.json
> +++ b/qapi/ui.json
> @@ -369,7 +369,8 @@
>    'data': { 'host': 'str',
>              'service': 'str',
>              'family': 'NetworkAddressFamily',
> -            'websocket': 'bool' } }
> +            'websocket': 'bool' },
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VncServerInfo:
> @@ -383,7 +384,8 @@
>  ##
>  { 'struct': 'VncServerInfo',
>    'base': 'VncBasicInfo',
> -  'data': { '*auth': 'str' } }
> +  'data': { '*auth': 'str' },
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VncClientInfo:
> @@ -400,7 +402,8 @@
>  ##
>  { 'struct': 'VncClientInfo',
>    'base': 'VncBasicInfo',
> -  'data': { '*x509_dname': 'str', '*sasl_username': 'str' } }
> +  'data': { '*x509_dname': 'str', '*sasl_username': 'str' },
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VncInfo:
> @@ -441,7 +444,8 @@
>  { 'struct': 'VncInfo',
>    'data': {'enabled': 'bool', '*host': 'str',
>             '*family': 'NetworkAddressFamily',
> -           '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
> +           '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']},
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VncPrimaryAuth:
> @@ -452,7 +456,8 @@
>  ##
>  { 'enum': 'VncPrimaryAuth',
>    'data': [ 'none', 'vnc', 'ra2', 'ra2ne', 'tight', 'ultra',
> -            'tls', 'vencrypt', 'sasl' ] }
> +            'tls', 'vencrypt', 'sasl' ],
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VncVencryptSubAuth:
> @@ -466,8 +471,8 @@
>              'tls-none',  'x509-none',
>              'tls-vnc',   'x509-vnc',
>              'tls-plain', 'x509-plain',
> -            'tls-sasl',  'x509-sasl' ] }
> -
> +            'tls-sasl',  'x509-sasl' ],
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VncServerInfo2:
> @@ -484,8 +489,8 @@
>  { 'struct': 'VncServerInfo2',
>    'base': 'VncBasicInfo',
>    'data': { 'auth'      : 'VncPrimaryAuth',
> -            '*vencrypt' : 'VncVencryptSubAuth' } }
> -
> +            '*vencrypt' : 'VncVencryptSubAuth' },
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VncInfo2:
> @@ -517,7 +522,8 @@
>              'clients'   : ['VncClientInfo'],
>              'auth'      : 'VncPrimaryAuth',
>              '*vencrypt' : 'VncVencryptSubAuth',
> -            '*display'  : 'str' } }
> +            '*display'  : 'str' },
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @query-vnc:
> @@ -548,8 +554,8 @@
>  #    }
>  #
>  ##
> -{ 'command': 'query-vnc', 'returns': 'VncInfo' }
> -
> +{ 'command': 'query-vnc', 'returns': 'VncInfo',
> +  'if': 'defined(CONFIG_VNC)' }
>  ##
>  # @query-vnc-servers:
>  #
> @@ -559,7 +565,8 @@
>  #
>  # Since: 2.3
>  ##
> -{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'] }
> +{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'],
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @change-vnc-password:
> @@ -573,7 +580,8 @@
>  # Notes:  An empty password in this command will set the password to the empty
>  #         string.  Existing clients are unaffected by executing this command.
>  ##
> -{ 'command': 'change-vnc-password', 'data': {'password': 'str'} }
> +{ 'command': 'change-vnc-password', 'data': {'password': 'str'},
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VNC_CONNECTED:
> @@ -602,7 +610,8 @@
>  ##
>  { 'event': 'VNC_CONNECTED',
>    'data': { 'server': 'VncServerInfo',
> -            'client': 'VncBasicInfo' } }
> +            'client': 'VncBasicInfo' },
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VNC_INITIALIZED:
> @@ -629,7 +638,8 @@
>  ##
>  { 'event': 'VNC_INITIALIZED',
>    'data': { 'server': 'VncServerInfo',
> -            'client': 'VncClientInfo' } }
> +            'client': 'VncClientInfo' },
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # @VNC_DISCONNECTED:
> @@ -655,7 +665,8 @@
>  ##
>  { 'event': 'VNC_DISCONNECTED',
>    'data': { 'server': 'VncServerInfo',
> -            'client': 'VncClientInfo' } }
> +            'client': 'VncClientInfo' },
> +  'if': 'defined(CONFIG_VNC)' }
>  
>  ##
>  # = Input
> diff --git a/ui/vnc.h b/ui/vnc.h
> index 694cf32ca9..5572bfdc9e 100644
> --- a/ui/vnc.h
> +++ b/ui/vnc.h
> @@ -291,7 +291,9 @@ struct VncState
>      bool encode_ws;
>      bool websocket;
>  
> +#ifdef CONFIG_VNC
>      VncClientInfo *info;
> +#endif
>  
>      Buffer output;
>      Buffer input;
> diff --git a/crypto/cipher-builtin.c b/crypto/cipher-builtin.c
> index d8c811fd33..647850843e 100644
> --- a/crypto/cipher-builtin.c
> +++ b/crypto/cipher-builtin.c
> @@ -35,17 +35,22 @@ struct QCryptoCipherBuiltinAES {
>      QCryptoCipherBuiltinAESContext key_tweak;
>      uint8_t iv[AES_BLOCK_SIZE];
>  };
> +
> +#ifdef CONFIG_VNC
>  typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
>  struct QCryptoCipherBuiltinDESRFB {
>      uint8_t *key;
>      size_t nkey;
>  };
> +#endif
>  
>  typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin;
>  struct QCryptoCipherBuiltin {
>      union {
>          QCryptoCipherBuiltinAES aes;
> +#ifdef CONFIG_VNC
>          QCryptoCipherBuiltinDESRFB desrfb;
> +#endif
>      } state;
>      size_t blocksize;
>      void (*free)(QCryptoCipher *cipher);
> @@ -403,7 +408,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
>                               QCryptoCipherMode mode)
>  {
>      switch (alg) {
> +#ifdef CONFIG_VNC
>      case QCRYPTO_CIPHER_ALG_DES_RFB:
> +#endif
>      case QCRYPTO_CIPHER_ALG_AES_128:
>      case QCRYPTO_CIPHER_ALG_AES_192:
>      case QCRYPTO_CIPHER_ALG_AES_256:
> @@ -449,9 +456,11 @@ static QCryptoCipherBuiltin *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
>      }
>  
>      switch (alg) {
> +#ifdef CONFIG_VNC
>      case QCRYPTO_CIPHER_ALG_DES_RFB:
>          ctxt = qcrypto_cipher_init_des_rfb(mode, key, nkey, errp);
>          break;
> +#endif
>      case QCRYPTO_CIPHER_ALG_AES_128:
>      case QCRYPTO_CIPHER_ALG_AES_192:
>      case QCRYPTO_CIPHER_ALG_AES_256:
> diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c
> index 10d75da75d..c240aaee26 100644
> --- a/crypto/cipher-gcrypt.c
> +++ b/crypto/cipher-gcrypt.c
> @@ -29,7 +29,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
>                               QCryptoCipherMode mode)
>  {
>      switch (alg) {
> +#ifdef CONFIG_VNC
>      case QCRYPTO_CIPHER_ALG_DES_RFB:
> +#endif
>      case QCRYPTO_CIPHER_ALG_3DES:
>      case QCRYPTO_CIPHER_ALG_AES_128:
>      case QCRYPTO_CIPHER_ALG_AES_192:
> @@ -114,10 +116,11 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
>      }
>  
>      switch (alg) {
> +#ifdef CONFIG_VNC
>      case QCRYPTO_CIPHER_ALG_DES_RFB:
>          gcryalg = GCRY_CIPHER_DES;
>          break;
> -
> +#endif
>      case QCRYPTO_CIPHER_ALG_3DES:
>          gcryalg = GCRY_CIPHER_3DES;
>          break;
> @@ -181,6 +184,7 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
>          }
>      }
>  
> +#ifdef CONFIG_VNC
>      if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
>          /* We're using standard DES cipher from gcrypt, so we need
>           * to munge the key so that the results are the same as the
> @@ -190,7 +194,9 @@ static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
>          err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
>          g_free(rfbkey);
>          ctx->blocksize = 8;
> -    } else {
> +    } else
> +#endif /* CONFIG_VNC */
> +    {
>          if (mode == QCRYPTO_CIPHER_MODE_XTS) {
>              nkey /= 2;
>              err = gcry_cipher_setkey(ctx->handle, key, nkey);
> diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c
> index 3848cb3b3a..ace5ec20f6 100644
> --- a/crypto/cipher-nettle.c
> +++ b/crypto/cipher-nettle.c
> @@ -67,6 +67,7 @@ static void aes_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
>      aes_decrypt(&aesctx->dec, length, dst, src);
>  }
>  
> +#ifdef CONFIG_VNC
>  static void des_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
>                                 uint8_t *dst, const uint8_t *src)
>  {
> @@ -78,6 +79,7 @@ static void des_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
>  {
>      des_decrypt(ctx, length, dst, src);
>  }
> +#endif
>  
>  static void des3_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
>                                  uint8_t *dst, const uint8_t *src)
> @@ -141,6 +143,7 @@ static void aes_decrypt_wrapper(const void *ctx, size_t length,
>      aes_decrypt(&aesctx->dec, length, dst, src);
>  }
>  
> +#ifdef CONFIG_VNC
>  static void des_encrypt_wrapper(const void *ctx, size_t length,
>                                  uint8_t *dst, const uint8_t *src)
>  {
> @@ -152,6 +155,7 @@ static void des_decrypt_wrapper(const void *ctx, size_t length,
>  {
>      des_decrypt(ctx, length, dst, src);
>  }
> +#endif
>  
>  static void des3_encrypt_wrapper(const void *ctx, size_t length,
>                                  uint8_t *dst, const uint8_t *src)
> @@ -221,7 +225,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
>                               QCryptoCipherMode mode)
>  {
>      switch (alg) {
> +#ifdef CONFIG_VNC
>      case QCRYPTO_CIPHER_ALG_DES_RFB:
> +#endif
>      case QCRYPTO_CIPHER_ALG_3DES:
>      case QCRYPTO_CIPHER_ALG_AES_128:
>      case QCRYPTO_CIPHER_ALG_AES_192:
> @@ -271,7 +277,6 @@ static QCryptoCipherNettle *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
>                                                     Error **errp)
>  {
>      QCryptoCipherNettle *ctx;
> -    uint8_t *rfbkey;
>  
>      switch (mode) {
>      case QCRYPTO_CIPHER_MODE_ECB:
> @@ -292,7 +297,9 @@ static QCryptoCipherNettle *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
>      ctx = g_new0(QCryptoCipherNettle, 1);
>  
>      switch (alg) {
> -    case QCRYPTO_CIPHER_ALG_DES_RFB:
> +#ifdef CONFIG_VNC
> +    case QCRYPTO_CIPHER_ALG_DES_RFB: {
> +        uint8_t *rfbkey;
>          ctx->ctx = g_new0(struct des_ctx, 1);
>          rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
>          des_set_key(ctx->ctx, rfbkey);
> @@ -305,7 +312,8 @@ static QCryptoCipherNettle *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
>  
>          ctx->blocksize = DES_BLOCK_SIZE;
>          break;
> -
> +    }
> +#endif
>      case QCRYPTO_CIPHER_ALG_3DES:
>          ctx->ctx = g_new0(struct des3_ctx, 1);
>          des3_set_key(ctx->ctx, key);
> diff --git a/crypto/cipher.c b/crypto/cipher.c
> index 0aad9d6d79..80355f4530 100644
> --- a/crypto/cipher.c
> +++ b/crypto/cipher.c
> @@ -28,7 +28,9 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
>      [QCRYPTO_CIPHER_ALG_AES_128] = 16,
>      [QCRYPTO_CIPHER_ALG_AES_192] = 24,
>      [QCRYPTO_CIPHER_ALG_AES_256] = 32,
> +#ifdef CONFIG_VNC
>      [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
> +#endif
>      [QCRYPTO_CIPHER_ALG_3DES] = 24,
>      [QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
>      [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
> @@ -43,7 +45,9 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
>      [QCRYPTO_CIPHER_ALG_AES_128] = 16,
>      [QCRYPTO_CIPHER_ALG_AES_192] = 16,
>      [QCRYPTO_CIPHER_ALG_AES_256] = 16,
> +#ifdef CONFIG_VNC
>      [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
> +#endif
>      [QCRYPTO_CIPHER_ALG_3DES] = 8,
>      [QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
>      [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
> @@ -106,8 +110,11 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
>      }
>  
>      if (mode == QCRYPTO_CIPHER_MODE_XTS) {
> -        if (alg == QCRYPTO_CIPHER_ALG_DES_RFB
> -                || alg == QCRYPTO_CIPHER_ALG_3DES) {
> +        if (
> +#ifdef CONFIG_VNC
> +            alg == QCRYPTO_CIPHER_ALG_DES_RFB ||
> +#endif
> +            alg == QCRYPTO_CIPHER_ALG_3DES) {
>              error_setg(errp, "XTS mode not compatible with DES-RFB/3DES");
>              return false;
>          }
> @@ -131,6 +138,7 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
>      return true;
>  }
>  
> +#if defined(CONFIG_VNC)
>  #if defined(CONFIG_GCRYPT) || defined(CONFIG_NETTLE)
>  static uint8_t *
>  qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
> @@ -148,6 +156,7 @@ qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
>      return ret;
>  }
>  #endif /* CONFIG_GCRYPT || CONFIG_NETTLE */
> +#endif /* CONFIG_VNC */
>  
>  #ifdef CONFIG_GCRYPT
>  #include "crypto/cipher-gcrypt.c"
> diff --git a/hmp.c b/hmp.c
> index cd046c6d71..5893e5bf16 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -604,6 +604,7 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
>      qapi_free_BlockStatsList(stats_list);
>  }
>  
> +#ifdef CONFIG_VNC
>  /* Helper for hmp_info_vnc_clients, _servers */
>  static void hmp_info_VncBasicInfo(Monitor *mon, VncBasicInfo *info,
>                                    const char *name)
> @@ -691,6 +692,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict)
>      qapi_free_VncInfo2List(info2l);
>  
>  }
> +#endif
>  
>  #ifdef CONFIG_SPICE
>  void hmp_info_spice(Monitor *mon, const QDict *qdict)
> @@ -1702,12 +1704,14 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
>      hmp_handle_error(mon, &err);
>  }
>  
> +#ifdef CONFIG_VNC
>  static void hmp_change_read_arg(void *opaque, const char *password,
>                                  void *readline_opaque)
>  {
>      qmp_change_vnc_password(password, NULL);
>      monitor_read_command(opaque, 1);
>  }
> +#endif
>  
>  void hmp_change(Monitor *mon, const QDict *qdict)
>  {
> @@ -1718,6 +1722,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
>      BlockdevChangeReadOnlyMode read_only_mode = 0;
>      Error *err = NULL;
>  
> +#ifdef CONFIG_VNC
>      if (strcmp(device, "vnc") == 0) {
>          if (read_only) {
>              monitor_printf(mon,
> @@ -1732,7 +1737,9 @@ void hmp_change(Monitor *mon, const QDict *qdict)
>              }
>          }
>          qmp_change("vnc", target, !!arg, arg, &err);
> -    } else {
> +    } else
> +#endif
> +    {
>          if (read_only) {
>              read_only_mode =
>                  qapi_enum_parse(&BlockdevChangeReadOnlyMode_lookup,
> diff --git a/qmp.c b/qmp.c
> index b86201e349..2c90dacb56 100644
> --- a/qmp.c
> +++ b/qmp.c
> @@ -130,22 +130,6 @@ void qmp_cpu_add(int64_t id, Error **errp)
>      }
>  }
>  
> -#ifndef CONFIG_VNC
> -/* If VNC support is enabled, the "true" query-vnc command is
> -   defined in the VNC subsystem */
> -VncInfo *qmp_query_vnc(Error **errp)
> -{
> -    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
> -    return NULL;
> -};
> -
> -VncInfo2List *qmp_query_vnc_servers(Error **errp)
> -{
> -    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
> -    return NULL;
> -};
> -#endif
> -
>  #ifndef CONFIG_SPICE
>  /*
>   * qmp-commands.hx ensures that QMP command query-spice exists only
> @@ -403,23 +387,17 @@ static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
>          qmp_change_vnc_listen(target, errp);
>      }
>  }
> -#else
> -void qmp_change_vnc_password(const char *password, Error **errp)
> -{
> -    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
> -}
> -static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
> -                           Error **errp)
> -{
> -    error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
> -}
>  #endif /* !CONFIG_VNC */
>  
>  void qmp_change(const char *device, const char *target,
>                  bool has_arg, const char *arg, Error **errp)
>  {
>      if (strcmp(device, "vnc") == 0) {
> +#ifdef CONFIG_VNC
>          qmp_change_vnc(target, has_arg, arg, errp);
> +#else
> +        error_setg(errp, QERR_FEATURE_DISABLED, "vnc");
> +#endif
>      } else {
>          qmp_blockdev_change_medium(true, device, false, NULL, target,
>                                     has_arg, arg, false, 0, errp);
> diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c
> index 07fa2fa616..5980b27389 100644
> --- a/tests/test-crypto-cipher.c
> +++ b/tests/test-crypto-cipher.c
> @@ -149,6 +149,7 @@ static QCryptoCipherTestData test_data[] = {
>              "39f23369a9d9bacfa530e26304231461"
>              "b2eb05e2c39be9fcda6c19078c6a9d1b",
>      },
> +#ifdef CONFIG_VNC
>      {
>          .path = "/crypto/cipher/des-rfb-ecb-56",
>          .alg = QCRYPTO_CIPHER_ALG_DES_RFB,
> @@ -165,6 +166,7 @@ static QCryptoCipherTestData test_data[] = {
>              "ffd29f1bb5596ad94ea2d8e6196b7f09"
>              "30d8ed0bf2773af36dd82a6280c20926",
>      },
> +#endif
>  #if defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)
>      {
>          /* Borrowed from linux-kernel crypto/testmgr.h */
> diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
> index 4ab7fcee98..aece8c5999 100644
> --- a/hmp-commands-info.hx
> +++ b/hmp-commands-info.hx
> @@ -420,6 +420,7 @@ STEXI
>  Show which guest mouse is receiving events.
>  ETEXI
>  
> +#if defined(CONFIG_VNC)
>      {
>          .name       = "vnc",
>          .args_type  = "",
> @@ -427,6 +428,7 @@ ETEXI
>          .help       = "show the vnc server status",
>          .cmd        = hmp_info_vnc,
>      },
> +#endif
>  
>  STEXI
>  @item info vnc

I should mention at this point: the resulting change to generated code
is lovely :)

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 37/50] qapi: add conditions to SPICE type/commands/events on the schema
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 37/50] qapi: add conditions to SPICE " Marc-André Lureau
@ 2017-12-13 14:17   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-13 14:17 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Dr. David Alan Gilbert, Gerd Hoffmann, Paolo Bonzini

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add #if defined(CONFIG_SPICE) in generated code, and adjust the
> qmp/hmp code accordingly.

I'd like to see a description of how this affects QMP and HMP, like the
one in the previous patch.

Are there any occurrences of SPICE in the schema that aren't made
conditional by this patch?

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi/char.json | 10 ++++++----
>  qapi/ui.json   | 30 ++++++++++++++++++++----------
>  monitor.c      |  3 ---
>  qmp.c          | 16 ----------------
>  4 files changed, 26 insertions(+), 33 deletions(-)
>
> diff --git a/qapi/char.json b/qapi/char.json
> index ae19dcd1ed..7fa1762ae5 100644
> --- a/qapi/char.json
> +++ b/qapi/char.json
> @@ -318,7 +318,8 @@
>  # Since: 1.5
>  ##
>  { 'struct': 'ChardevSpiceChannel', 'data': { 'type'  : 'str' },
> -  'base': 'ChardevCommon' }
> +  'base': 'ChardevCommon',
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @ChardevSpicePort:
> @@ -330,7 +331,8 @@
>  # Since: 1.5
>  ##
>  { 'struct': 'ChardevSpicePort', 'data': { 'fqdn'  : 'str' },
> -  'base': 'ChardevCommon' }
> +  'base': 'ChardevCommon',
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @ChardevVC:
> @@ -384,8 +386,8 @@
>                                         'testdev': 'ChardevCommon',
>                                         'stdio'  : 'ChardevStdio',
>                                         'console': 'ChardevCommon',
> -                                       'spicevmc' : 'ChardevSpiceChannel',
> -                                       'spiceport' : 'ChardevSpicePort',
> +                                       'spicevmc' : { 'type': 'ChardevSpiceChannel', 'if': 'defined(CONFIG_SPICE)' },
> +                                       'spiceport' : { 'type': 'ChardevSpicePort', 'if': 'defined(CONFIG_SPICE)' },
>                                         'vc'     : 'ChardevVC',
>                                         'ringbuf': 'ChardevRingbuf',
>                                         # next one is just for compatibility
> diff --git a/qapi/ui.json b/qapi/ui.json
> index 4b573d214b..daa4168c14 100644
> --- a/qapi/ui.json
> +++ b/qapi/ui.json
> @@ -110,7 +110,8 @@
>  { 'struct': 'SpiceBasicInfo',
>    'data': { 'host': 'str',
>              'port': 'str',
> -            'family': 'NetworkAddressFamily' } }
> +            'family': 'NetworkAddressFamily' },
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @SpiceServerInfo:
> @@ -123,7 +124,8 @@
>  ##
>  { 'struct': 'SpiceServerInfo',
>    'base': 'SpiceBasicInfo',
> -  'data': { '*auth': 'str' } }
> +  'data': { '*auth': 'str' },
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @SpiceChannel:
> @@ -148,7 +150,8 @@
>  { 'struct': 'SpiceChannel',
>    'base': 'SpiceBasicInfo',
>    'data': {'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int',
> -           'tls': 'bool'} }
> +           'tls': 'bool'},
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @SpiceQueryMouseMode:
> @@ -167,7 +170,8 @@
>  # Since: 1.1
>  ##
>  { 'enum': 'SpiceQueryMouseMode',
> -  'data': [ 'client', 'server', 'unknown' ] }
> +  'data': [ 'client', 'server', 'unknown' ],
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @SpiceInfo:
> @@ -204,7 +208,8 @@
>  { 'struct': 'SpiceInfo',
>    'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int',
>             '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str',
> -           'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
> +           'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']},
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @query-spice:
> @@ -249,7 +254,8 @@
>  #    }
>  #
>  ##
> -{ 'command': 'query-spice', 'returns': 'SpiceInfo' }
> +{ 'command': 'query-spice', 'returns': 'SpiceInfo',
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @SPICE_CONNECTED:
> @@ -274,7 +280,8 @@
>  ##
>  { 'event': 'SPICE_CONNECTED',
>    'data': { 'server': 'SpiceBasicInfo',
> -            'client': 'SpiceBasicInfo' } }
> +            'client': 'SpiceBasicInfo' },
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @SPICE_INITIALIZED:
> @@ -302,7 +309,8 @@
>  ##
>  { 'event': 'SPICE_INITIALIZED',
>    'data': { 'server': 'SpiceServerInfo',
> -            'client': 'SpiceChannel' } }
> +            'client': 'SpiceChannel' },
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @SPICE_DISCONNECTED:
> @@ -327,7 +335,8 @@
>  ##
>  { 'event': 'SPICE_DISCONNECTED',
>    'data': { 'server': 'SpiceBasicInfo',
> -            'client': 'SpiceBasicInfo' } }
> +            'client': 'SpiceBasicInfo' },
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # @SPICE_MIGRATE_COMPLETED:
> @@ -342,7 +351,8 @@
>  #      "event": "SPICE_MIGRATE_COMPLETED" }
>  #
>  ##
> -{ 'event': 'SPICE_MIGRATE_COMPLETED' }
> +{ 'event': 'SPICE_MIGRATE_COMPLETED',
> +  'if': 'defined(CONFIG_SPICE)' }
>  
>  ##
>  # == VNC
> diff --git a/monitor.c b/monitor.c
> index 5685697f59..135a1e0821 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -970,9 +970,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
>   */
>  static void qmp_unregister_commands_hack(void)
>  {
> -#ifndef CONFIG_SPICE
> -    qmp_unregister_command(&qmp_commands, "query-spice");
> -#endif
>  #ifndef CONFIG_REPLICATION
>      qmp_unregister_command(&qmp_commands, "xen-set-replication");
>      qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
> diff --git a/qmp.c b/qmp.c
> index 2c90dacb56..90816ba283 100644
> --- a/qmp.c
> +++ b/qmp.c
> @@ -130,22 +130,6 @@ void qmp_cpu_add(int64_t id, Error **errp)
>      }
>  }
>  
> -#ifndef CONFIG_SPICE
> -/*
> - * qmp-commands.hx ensures that QMP command query-spice exists only
> - * #ifdef CONFIG_SPICE.  Necessary for an accurate query-commands
> - * result.  However, the QAPI schema is blissfully unaware of that,
> - * and the QAPI code generator happily generates a dead
> - * qmp_marshal_query_spice() that calls qmp_query_spice().  Provide it
> - * one, or else linking fails.  FIXME Educate the QAPI schema on
> - * CONFIG_SPICE.
> - */
> -SpiceInfo *qmp_query_spice(Error **errp)
> -{
> -    abort();
> -};
> -#endif
> -
>  void qmp_cont(Error **errp)
>  {
>      BlockBackend *blk;

Hmm, shouldn't you compile out "info spice", like you did for "info vnc"
in the previous patch?

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 38/50] qapi: add conditions to REPLICATION type/commands on the schema
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 38/50] qapi: add conditions to REPLICATION type/commands " Marc-André Lureau
@ 2017-12-13 14:19   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-13 14:19 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, zhanghailiang, Juan Quintela, Dr. David Alan Gilbert

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add #if defined(CONFIG_REPLICATION) in generated code, and adjust the
> code accordingly.
>
> Made conditional:
>
> * xen-set-replication, query-xen-replication-status,
>   xen-colo-do-checkpoint
>
>   Before the patch, we first register the commands unconditionally in
>   generated code (requires a stub), then conditionally unregister in
>   qmp_unregister_commands_hack().
>
>   Afterwards, we register only when CONFIG_REPLICATION.  The command
>   fails exactly the same, with CommandNotFound.
>
>   Improvement, because now query-qmp-schema is accurate, and we're one
>   step close to killing qmp_unregister_commands_hack().

s/close/closer/

>
> * enum BlockdevDriver value "replication" in command blockdev-add
>
> As well as enum BlockdevDriver value @replication BlockdevOptions

Missing a comma after @replication?

> variant @replication, BlockdevOptionsReplication,
> BlockdevOptionsReplicationMode.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi/block-core.json | 15 ++++++++++-----
>  qapi/migration.json  | 12 ++++++++----
>  migration/colo.c     | 16 ++++------------
>  monitor.c            |  5 -----
>  4 files changed, 22 insertions(+), 26 deletions(-)
>
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index bb11815608..6f897cf157 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -2232,8 +2232,10 @@
>              'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom',
>              'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
>              'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
> -            'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
> -            'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
> +            'quorum', 'raw', 'rbd',
> +            { 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
> +            'sheepdog', 'ssh', 'throttle',
> +            'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
>  
>  ##
>  # @BlockdevOptionsFile:
> @@ -2855,7 +2857,8 @@
>  #
>  # Since: 2.9
>  ##
> -{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] }
> +{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ],
> +  'if': 'defined(CONFIG_REPLICATION)' }
>  
>  ##
>  # @BlockdevOptionsReplication:
> @@ -2873,7 +2876,8 @@
>  { 'struct': 'BlockdevOptionsReplication',
>    'base': 'BlockdevOptionsGenericFormat',
>    'data': { 'mode': 'ReplicationMode',
> -            '*top-id': 'str' } }
> +            '*top-id': 'str' },
> +  'if': 'defined(CONFIG_REPLICATION)' }
>  
>  ##
>  # @NFSTransport:
> @@ -3168,7 +3172,8 @@
>        'quorum':     'BlockdevOptionsQuorum',
>        'raw':        'BlockdevOptionsRaw',
>        'rbd':        'BlockdevOptionsRbd',
> -      'replication':'BlockdevOptionsReplication',
> +      'replication': { 'type': 'BlockdevOptionsReplication',
> +                       'if': 'defined(CONFIG_REPLICATION)' },
>        'sheepdog':   'BlockdevOptionsSheepdog',
>        'ssh':        'BlockdevOptionsSsh',
>        'throttle':   'BlockdevOptionsThrottle',
> diff --git a/qapi/migration.json b/qapi/migration.json
> index ee2b3b8733..44d2ef9c94 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -1034,7 +1034,8 @@
>  # Since: 2.9
>  ##
>  { 'command': 'xen-set-replication',
> -  'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' } }
> +  'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' },
> +  'if': 'defined(CONFIG_REPLICATION)' }
>  
>  ##
>  # @ReplicationStatus:
> @@ -1049,7 +1050,8 @@
>  # Since: 2.9
>  ##
>  { 'struct': 'ReplicationStatus',
> -  'data': { 'error': 'bool', '*desc': 'str' } }
> +  'data': { 'error': 'bool', '*desc': 'str' },
> +  'if': 'defined(CONFIG_REPLICATION)' }
>  
>  ##
>  # @query-xen-replication-status:
> @@ -1066,7 +1068,8 @@
>  # Since: 2.9
>  ##
>  { 'command': 'query-xen-replication-status',
> -  'returns': 'ReplicationStatus' }
> +  'returns': 'ReplicationStatus',
> +  'if': 'defined(CONFIG_REPLICATION)' }
>  
>  ##
>  # @xen-colo-do-checkpoint:
> @@ -1082,4 +1085,5 @@
>  #
>  # Since: 2.9
>  ##
> -{ 'command': 'xen-colo-do-checkpoint' }
> +{ 'command': 'xen-colo-do-checkpoint',
> +  'if': 'defined(CONFIG_REPLICATION)' }
> diff --git a/migration/colo.c b/migration/colo.c
> index dee3aa8bf7..010c9e02e8 100644
> --- a/migration/colo.c
> +++ b/migration/colo.c
> @@ -22,7 +22,9 @@
>  #include "trace.h"
>  #include "qemu/error-report.h"
>  #include "migration/failover.h"
> +#ifdef CONFIG_REPLICATION
>  #include "replication.h"
> +#endif
>  #include "qmp-commands.h"
>  
>  static bool vmstate_loading;
> @@ -147,11 +149,11 @@ void colo_do_failover(MigrationState *s)
>      }
>  }
>  
> +#ifdef CONFIG_REPLICATION
>  void qmp_xen_set_replication(bool enable, bool primary,
>                               bool has_failover, bool failover,
>                               Error **errp)
>  {
> -#ifdef CONFIG_REPLICATION
>      ReplicationMode mode = primary ?
>                             REPLICATION_MODE_PRIMARY :
>                             REPLICATION_MODE_SECONDARY;
> @@ -170,14 +172,10 @@ void qmp_xen_set_replication(bool enable, bool primary,
>          }
>          replication_stop_all(failover, failover ? NULL : errp);
>      }
> -#else
> -    abort();
> -#endif
>  }
>  
>  ReplicationStatus *qmp_query_xen_replication_status(Error **errp)
>  {
> -#ifdef CONFIG_REPLICATION
>      Error *err = NULL;
>      ReplicationStatus *s = g_new0(ReplicationStatus, 1);
>  
> @@ -192,19 +190,13 @@ ReplicationStatus *qmp_query_xen_replication_status(Error **errp)
>  
>      error_free(err);
>      return s;
> -#else
> -    abort();
> -#endif
>  }
>  
>  void qmp_xen_colo_do_checkpoint(Error **errp)
>  {
> -#ifdef CONFIG_REPLICATION
>      replication_do_checkpoint_all(errp);
> -#else
> -    abort();
> -#endif
>  }
> +#endif
>  
>  static void colo_send_message(QEMUFile *f, COLOMessage msg,
>                                Error **errp)
> diff --git a/monitor.c b/monitor.c
> index 135a1e0821..b5ddcf8c67 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -970,11 +970,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
>   */
>  static void qmp_unregister_commands_hack(void)
>  {
> -#ifndef CONFIG_REPLICATION
> -    qmp_unregister_command(&qmp_commands, "xen-set-replication");
> -    qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
> -    qmp_unregister_command(&qmp_commands, "xen-colo-do-checkpoint");
> -#endif
>  #ifndef TARGET_I386
>      qmp_unregister_command(&qmp_commands, "rtc-reset-reinjection");
>  #endif

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 36/50] qapi: add conditions to VNC type/commands/events on the schema
  2017-12-13 14:12   ` Markus Armbruster
@ 2017-12-13 14:20     ` Daniel P. Berrange
  0 siblings, 0 replies; 118+ messages in thread
From: Daniel P. Berrange @ 2017-12-13 14:20 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Marc-André Lureau, qemu-devel, Dr. David Alan Gilbert,
	Gerd Hoffmann

On Wed, Dec 13, 2017 at 03:12:26PM +0100, Markus Armbruster wrote:
> Cc: Daniel for his opinion on QCryptoCipherAlgorithm member des-rfb.

> > Enum made conditional:
> 
> The enum isn't made conditional, only one of its values is.  Suggest "
> Enumeration values made conditional:".
> 
> > * QCryptoCipherAlgorithm
> >
> >     # @des-rfb: RFB specific variant of single DES. Do not use except in VNC.
> 
> Daniel, is this okay?

I don't think we should touch the crypto/ code at all here.

Although the VNC server is the only intended user of the des-rfb choice,
I don't really think we should make this conditional on CONFIG_VNC. It
isn't reducing the amount of code we build in any meaningful way and is
littering the crypto code with '#ifdef CONFIG_VNC' conditionals, which
harms readability and I think it is a code layering violation.

So please drop the following changes:

> >  qapi/crypto.json           |  3 ++-
> >  crypto/cipher-builtin.c    |  9 +++++++++
> >  crypto/cipher-gcrypt.c     | 10 ++++++++--
> >  crypto/cipher-nettle.c     | 14 +++++++++++---
> >  crypto/cipher.c            | 13 +++++++++++--
> >  tests/test-crypto-cipher.c |  2 ++

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 39/50] qapi-commands: don't initialize command list in qmp_init_marshall()
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 39/50] qapi-commands: don't initialize command list in qmp_init_marshall() Marc-André Lureau
@ 2017-12-13 16:23   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-13 16:23 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth, Dr. David Alan Gilbert

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> This will let the caller add several list of commands.

What for?  I guess that'll become clear later in this series.

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi-commands.py  | 2 --
>  monitor.c                 | 1 +
>  qga/main.c                | 1 +
>  tests/test-qmp-commands.c | 1 +
>  4 files changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
> index 8af8d913b9..7455d2b8bb 100644
> --- a/scripts/qapi-commands.py
> +++ b/scripts/qapi-commands.py
> @@ -211,8 +211,6 @@ def gen_registry(registry):
>  
>  void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds)
>  {
> -    QTAILQ_INIT(cmds);
> -
>  ''',
>                  c_prefix=c_name(prefix, protect=False))
>      ret += registry

Please update qapi-code-gen.txt, too.

> diff --git a/monitor.c b/monitor.c
> index b5ddcf8c67..bf8a7685bf 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -1001,6 +1001,7 @@ void monitor_init_qmp_commands(void)
>       *   "qmp_capabilities", to enforce capability negotiation
>       */
>  
> +    QTAILQ_INIT(&qmp_commands);
>      qmp_init_marshal(&qmp_commands);
>  
>      qmp_register_command(&qmp_commands, "query-qmp-schema",
> diff --git a/qga/main.c b/qga/main.c
> index 62a62755bd..b949b1ccb0 100644
> --- a/qga/main.c
> +++ b/qga/main.c
> @@ -1360,6 +1360,7 @@ int main(int argc, char **argv)
>  
>      config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
>  
> +    QTAILQ_INIT(&ga_commands);
>      qga_qmp_init_marshal(&ga_commands);
>  
>      init_dfl_pathnames();
> diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
> index ad7b6e4e1d..28ce88e012 100644
> --- a/tests/test-qmp-commands.c
> +++ b/tests/test-qmp-commands.c
> @@ -283,6 +283,7 @@ int main(int argc, char **argv)
>      g_test_add_func("/0.15/dealloc_types", test_dealloc_types);
>      g_test_add_func("/0.15/dealloc_partial", test_dealloc_partial);
>  
> +    QTAILQ_INIT(&qmp_commands);
>      test_qmp_init_marshal(&qmp_commands);
>      g_test_run();

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 31/50] docs: document schema configuration
  2017-12-13 10:41   ` Markus Armbruster
@ 2017-12-13 19:49     ` Eric Blake
  0 siblings, 0 replies; 118+ messages in thread
From: Eric Blake @ 2017-12-13 19:49 UTC (permalink / raw)
  To: Markus Armbruster, Marc-André Lureau; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2583 bytes --]

On 12/13/2017 04:41 AM, Markus Armbruster wrote:
> Cc: Eric for an additional pair of eyeballs.
> 
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
> 
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>> +
>> +Members can be exploded as dictionnary with 'type' & 'if' keys:
> 
> dictionary
> 
> I get what you mean by "can be exploded", but can we phrase this more
> clearly?
> 
> In section "Struct types", we have
> 
>     A struct is a dictionary containing a single 'data' key whose value is
>     a dictionary; the dictionary may be empty.  This corresponds to a
>     struct in C or an Object in JSON. Each value of the 'data' dictionary
>     must be the name of a type, or a one-element array containing a type
>     name.
> 
> The part "must be the name of a type, or a one-element array containing
> a type" name is now wrong.

Maybe:

Where a member can normally be defined with a single string value as its
type, it is also possible to supply a dictionary with both 'type' and
'if' keys.  The generated code will then guard the inclusion of that
member in the larger struct or command with #if IFCOND, where IFCOND is
the value of the 'if' key.

>> +
>> +{ 'struct': 'IfStruct', 'data':
>> +  { 'foo': 'int',
>> +    'bar': { 'type': 'int', 'if': 'defined(IF_STRUCT_BAR)'} } }
> 
> Perhaps add something like
> 
>     Code generated for such conditional members will be guarded with #if
>     IFCOND, where IFCOND is the value of the 'if' key.
> 

> 
> Hmm.  If enumeration documentation profits from an example, it stands to
> reason that the previous two would, too.
> 
> Should we (additionally?) add examples of 'if' in section "Code
> generation"?

It makes the examples longer, but may be worthwhile.

> 
>> +
>> +Please note that you are responsbile to ensure that the C code will

s/responsbile/responsible/

>> +compile with an arbitrary combination of conditions, since the
>> +generators are unable to check it at this point.
>> +
>>  == Client JSON Protocol introspection ==
>>  
>>  Clients of a Client JSON Protocol commonly need to figure out what
> 
> Do we need to update section "Client JSON Protocol introspection"?

It doesn't affect what the client can do with what it introspects, but
may indeed be worth mentioning that the presence of 'if' keys in the
schema is reflected through to the introspection output.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 32/50] qapi2texi: add 'If:' section to generated documentation
  2017-12-13 12:35   ` Markus Armbruster
@ 2017-12-13 19:54     ` Eric Blake
  0 siblings, 0 replies; 118+ messages in thread
From: Eric Blake @ 2017-12-13 19:54 UTC (permalink / raw)
  To: Markus Armbruster, Marc-André Lureau; +Cc: qemu-devel, Michael Roth

[-- Attachment #1: Type: text/plain, Size: 1551 bytes --]

On 12/13/2017 06:35 AM, Markus Armbruster wrote:
> Cc: Eric for an additional pair of eyeballs.
> 
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
> 
>> The documentation is generated only once, and doesn't know C
>> pre-conditions. Add 'If:' sections for top-level entities.
> 
> Is this what we want?
> 
> QMP also exists only once.  Should the generated qemu-qmp-ref.* document
> that instance of QMP, or should it document all potential instances of
> QMP?
> 

I can go either way; it's nice to know that the binary that this copy of
documentation was bundled with only understands these terms (the binary
was compiled without HAVE_FOO, so any code guarded by HAVE_FOO doesn't
need to be documented); but that limits the usability of that
documentation to just that binary.  It's also useful to have
fully-generic documentation hosted on the website, where everything is
documented (the documentation describes all possible builds of qemu
2.12, not just the one you installed), while mentioning the conditional
nature of the documented feature ("qemu in general knows about these
things; but check your particular binary by doing XYZ to learn if that
support was compiled in to your binary").

So having typed that, I think I'm leaning slightly towards documenting
everything, including conditionals, rather than trimming the document to
match the current build conditions.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 40/50] qapi: add -i/--include filename.h
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 40/50] qapi: add -i/--include filename.h Marc-André Lureau
@ 2017-12-14 13:50   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-14 13:50 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add a new option to add user-specified #include lines in the generated
> headers. This will help to split a schema, where one generated header
> will depend on another.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

If we need to manage includes manually, then this patch is one way to do
it.  But I'm not sure we need to.  Let me review the remainder of the
series before we analyze this further.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma Marc-André Lureau
@ 2017-12-14 13:54   ` Markus Armbruster
  2017-12-14 14:00     ` Marc-André Lureau
  2017-12-14 16:08   ` Markus Armbruster
  1 sibling, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-14 13:54 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add a pragma that allows to tag the following expressions with a unit
> name. By default, an expression has no unit name.

Please explain the unit name's intended purpose.

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py              | 9 ++++++++-
>  docs/devel/qapi-code-gen.txt | 3 +++
>  2 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index eb4ffdc06d..1d0defd638 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -279,10 +279,12 @@ class QAPISchemaParser(object):
>          self.docs = []
>          self.cur_doc = None
>          self.accept()
> +        self.unit = None
>  
>          while self.tok is not None:
>              info = {'file': fname, 'line': self.line,
> -                    'parent': self.incl_info}
> +                    'parent': self.incl_info,
> +                    'unit': self.unit}
>              if self.tok == '#':
>                  self.reject_expr_doc()
>                  self.cur_doc = self.get_doc(info)
> @@ -371,6 +373,11 @@ class QAPISchemaParser(object):
>                                     "Pragma name-case-whitelist must be"
>                                     " a list of strings")
>              name_case_whitelist = value
> +        elif name == 'unit':
> +            if not isinstance(value, str):
> +                raise QAPISemError(info,
> +                                   "Pragma 'unit' must be string")
> +            self.unit = value
>          else:
>              raise QAPISemError(info, "Unknown pragma '%s'" % name)
>  
> diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
> index 24fc6f74ee..37a27cd9d7 100644
> --- a/docs/devel/qapi-code-gen.txt
> +++ b/docs/devel/qapi-code-gen.txt
> @@ -326,6 +326,9 @@ violate the rules on permitted return types.  Default is none.
>  Pragma 'name-case-whitelist' takes a list of names that may violate
>  rules on use of upper- vs. lower-case letters.  Default is none.
>  
> +Pragma 'unit' takes a string value. It will set the unit name for the
> +following expressions in the schema. Most code generator can filter
> +based on a unit name. Default is none.

Do you mean "most code generators"?

What does "filtering" mean?

>  
>  === Struct types ===

Humor me: put two spaces after a sentence-ending period.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma
  2017-12-14 13:54   ` Markus Armbruster
@ 2017-12-14 14:00     ` Marc-André Lureau
  2017-12-14 14:33       ` Markus Armbruster
  0 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2017-12-14 14:00 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Thu, Dec 14, 2017 at 2:54 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Add a pragma that allows to tag the following expressions with a unit
>> name. By default, an expression has no unit name.
>
> Please explain the unit name's intended purpose.
>

It's syccintly explained in the doc.

>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  scripts/qapi.py              | 9 ++++++++-
>>  docs/devel/qapi-code-gen.txt | 3 +++
>>  2 files changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>> index eb4ffdc06d..1d0defd638 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -279,10 +279,12 @@ class QAPISchemaParser(object):
>>          self.docs = []
>>          self.cur_doc = None
>>          self.accept()
>> +        self.unit = None
>>
>>          while self.tok is not None:
>>              info = {'file': fname, 'line': self.line,
>> -                    'parent': self.incl_info}
>> +                    'parent': self.incl_info,
>> +                    'unit': self.unit}
>>              if self.tok == '#':
>>                  self.reject_expr_doc()
>>                  self.cur_doc = self.get_doc(info)
>> @@ -371,6 +373,11 @@ class QAPISchemaParser(object):
>>                                     "Pragma name-case-whitelist must be"
>>                                     " a list of strings")
>>              name_case_whitelist = value
>> +        elif name == 'unit':
>> +            if not isinstance(value, str):
>> +                raise QAPISemError(info,
>> +                                   "Pragma 'unit' must be string")
>> +            self.unit = value
>>          else:
>>              raise QAPISemError(info, "Unknown pragma '%s'" % name)
>>
>> diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
>> index 24fc6f74ee..37a27cd9d7 100644
>> --- a/docs/devel/qapi-code-gen.txt
>> +++ b/docs/devel/qapi-code-gen.txt
>> @@ -326,6 +326,9 @@ violate the rules on permitted return types.  Default is none.
>>  Pragma 'name-case-whitelist' takes a list of names that may violate
>>  rules on use of upper- vs. lower-case letters.  Default is none.
>>
>> +Pragma 'unit' takes a string value. It will set the unit name for the
>> +following expressions in the schema. Most code generator can filter
>> +based on a unit name. Default is none.
>
> Do you mean "most code generators"?

The qapi code/doc generators.

>
> What does "filtering" mean?

To be able to select a subset of expressions based on the unit name.

>>
>>  === Struct types ===
>
> Humor me: put two spaces after a sentence-ending period.
>

I don't get what you mean.

thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma
  2017-12-14 14:00     ` Marc-André Lureau
@ 2017-12-14 14:33       ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-14 14:33 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU, Michael Roth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Thu, Dec 14, 2017 at 2:54 PM, Markus Armbruster <armbru@redhat.com> wrote:
>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>>
>>> Add a pragma that allows to tag the following expressions with a unit
>>> name. By default, an expression has no unit name.
>>
>> Please explain the unit name's intended purpose.
>>
>
> It's syccintly explained in the doc.

The commit message should state the patch's purpose.  When the patch
adds documentation, and you'd rather not duplicate it in the commit
message, a short summary plus a pointer there may do.

>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>  scripts/qapi.py              | 9 ++++++++-
>>>  docs/devel/qapi-code-gen.txt | 3 +++
>>>  2 files changed, 11 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>>> index eb4ffdc06d..1d0defd638 100644
>>> --- a/scripts/qapi.py
>>> +++ b/scripts/qapi.py
>>> @@ -279,10 +279,12 @@ class QAPISchemaParser(object):
>>>          self.docs = []
>>>          self.cur_doc = None
>>>          self.accept()
>>> +        self.unit = None
>>>
>>>          while self.tok is not None:
>>>              info = {'file': fname, 'line': self.line,
>>> -                    'parent': self.incl_info}
>>> +                    'parent': self.incl_info,
>>> +                    'unit': self.unit}
>>>              if self.tok == '#':
>>>                  self.reject_expr_doc()
>>>                  self.cur_doc = self.get_doc(info)
>>> @@ -371,6 +373,11 @@ class QAPISchemaParser(object):
>>>                                     "Pragma name-case-whitelist must be"
>>>                                     " a list of strings")
>>>              name_case_whitelist = value
>>> +        elif name == 'unit':
>>> +            if not isinstance(value, str):
>>> +                raise QAPISemError(info,
>>> +                                   "Pragma 'unit' must be string")
>>> +            self.unit = value
>>>          else:
>>>              raise QAPISemError(info, "Unknown pragma '%s'" % name)
>>>
>>> diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
>>> index 24fc6f74ee..37a27cd9d7 100644
>>> --- a/docs/devel/qapi-code-gen.txt
>>> +++ b/docs/devel/qapi-code-gen.txt
>>> @@ -326,6 +326,9 @@ violate the rules on permitted return types.  Default is none.
>>>  Pragma 'name-case-whitelist' takes a list of names that may violate
>>>  rules on use of upper- vs. lower-case letters.  Default is none.
>>>
>>> +Pragma 'unit' takes a string value. It will set the unit name for the
>>> +following expressions in the schema. Most code generator can filter
>>> +based on a unit name. Default is none.
>>
>> Do you mean "most code generators"?
>
> The qapi code/doc generators.

So plural is intended.  Easy enough to fix.

>>
>> What does "filtering" mean?
>
> To be able to select a subset of expressions based on the unit name.

Let's spell that out.

>>>
>>>  === Struct types ===
>>
>> Humor me: put two spaces after a sentence-ending period.
>>
>
> I don't get what you mean.

This sentence ends with a period, which is followed by two spaces.  This
sentence is followed by just one space. I prefer two.  A few
inconsistencies have crept into this file over time, let's not add more.
All clear now?

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma Marc-André Lureau
  2017-12-14 13:54   ` Markus Armbruster
@ 2017-12-14 16:08   ` Markus Armbruster
  1 sibling, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-14 16:08 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add a pragma that allows to tag the following expressions with a unit
> name. By default, an expression has no unit name.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py              | 9 ++++++++-
>  docs/devel/qapi-code-gen.txt | 3 +++
>  2 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index eb4ffdc06d..1d0defd638 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -279,10 +279,12 @@ class QAPISchemaParser(object):
>          self.docs = []
>          self.cur_doc = None
>          self.accept()
> +        self.unit = None
>  
>          while self.tok is not None:
>              info = {'file': fname, 'line': self.line,
> -                    'parent': self.incl_info}
> +                    'parent': self.incl_info,
> +                    'unit': self.unit}
>              if self.tok == '#':
>                  self.reject_expr_doc()
>                  self.cur_doc = self.get_doc(info)
> @@ -371,6 +373,11 @@ class QAPISchemaParser(object):
>                                     "Pragma name-case-whitelist must be"
>                                     " a list of strings")
>              name_case_whitelist = value
> +        elif name == 'unit':
> +            if not isinstance(value, str):
> +                raise QAPISemError(info,
> +                                   "Pragma 'unit' must be string")
> +            self.unit = value
>          else:
>              raise QAPISemError(info, "Unknown pragma '%s'" % name)
>  
> diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
> index 24fc6f74ee..37a27cd9d7 100644
> --- a/docs/devel/qapi-code-gen.txt
> +++ b/docs/devel/qapi-code-gen.txt
> @@ -326,6 +326,9 @@ violate the rules on permitted return types.  Default is none.
>  Pragma 'name-case-whitelist' takes a list of names that may violate
>  rules on use of upper- vs. lower-case letters.  Default is none.
>  
> +Pragma 'unit' takes a string value. It will set the unit name for the
> +following expressions in the schema. Most code generator can filter
> +based on a unit name. Default is none.
>  
>  === Struct types ===

Test coverage?

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 42/50] qapi: add a -u/--unit option to specify which unit to visit
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 42/50] qapi: add a -u/--unit option to specify which unit to visit Marc-André Lureau
@ 2017-12-14 16:16   ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-14 16:16 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Allow to filter expressions based on unit name.
>
> By default, only default units are processed (unspecified pragma).
>
> 'all' will include all units. Anything else will filter by unit name.

You therefore can't have a unit called 'all'.  Hardly a loss, but I
suspect documenting and guarding against it is more trouble than the
feature's worth.

If we want to keep it, the previous patch needs to reject { 'pragma': {
'unit': 'all' } }.

> (add a FIXME to make implicit array types use the element type unit,
> not the unit of the first expression using that array type. This isn't
> necessary for now, and I am not sure how to best do it yet)
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py      | 14 ++++++++++++--
>  scripts/qapi2texi.py |  1 +
>  2 files changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 1d0defd638..7778585819 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -47,6 +47,9 @@ returns_whitelist = []
>  # Whitelist of entities allowed to violate case conventions
>  name_case_whitelist = []
>  
> +# Unit to consider for the visit, 'all' for all units
> +visit_unit = None
> +
>  enum_types = {}
>  struct_types = {}
>  union_types = {}
> @@ -1796,6 +1799,10 @@ class QAPISchema(object):
>      def visit(self, visitor):
>          visitor.visit_begin(self)
>          for (name, entity) in sorted(self._entity_dict.items()):
> +            # FIXME: implicit array types should use element type unit
> +            unit = entity.info and entity.info.get('unit')

@unit is str, ensured by QAPISchemaParser.

> +            if visit_unit != 'all' and visit_unit != unit:
> +                continue

If visit_unit is still None, we don't visit anything.

>              if visitor.visit_needed(entity):
>                  entity.visit(visitor)
>          visitor.visit_end()
> @@ -2103,13 +2110,14 @@ def parse_command_line(extra_options='', extra_long_options=[]):
>  
>      try:
>          opts, args = getopt.gnu_getopt(sys.argv[1:],
> -            'chp:o:i:' + extra_options,
> +            'chp:o:u:i:' + extra_options,
>              ['source', 'header', 'prefix=', 'output-dir=',
> -             'include='] + extra_long_options)
> +             'unit=', 'include='] + extra_long_options)
>      except getopt.GetoptError as err:
>          print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
>          sys.exit(1)
>  
> +    global visit_unit
>      output_dir = ''
>      prefix = ''
>      do_c = False
> @@ -2129,6 +2137,8 @@ def parse_command_line(extra_options='', extra_long_options=[]):
>              prefix = a
>          elif o in ('-o', '--output-dir'):
>              output_dir = a + '/'
> +        elif o in ('-u', '--unit'):
> +            visit_unit = a
>          elif o in ('-c', '--source'):
>              do_c = True
>          elif o in ('-h', '--header'):

If the user doesn't give -u, @visit_unit remains None, and
QAPISchema.visit() won't visit anything.

I recommend to dumb this down as follows.  No special unit name 'all'.
If you want all, don't specify -u.  @visit_unit remains None then.

> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> index 4e7b1cda87..6c856d4cb7 100755
> --- a/scripts/qapi2texi.py
> +++ b/scripts/qapi2texi.py
> @@ -293,6 +293,7 @@ def main(argv):
>          print >>sys.stderr, "%s: need exactly 1 argument: SCHEMA" % argv[0]
>          sys.exit(1)
>  
> +    qapi.visit_unit = 'all'
>      schema = qapi.QAPISchema(argv[1])
>      if not qapi.doc_required:
>          print >>sys.stderr, ("%s: need pragma 'doc-required' "

Bonus: this hunk won't be needed then, because the default value just
works.

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 43/50] build-sys: move qmp-introspect per target
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 43/50] build-sys: move qmp-introspect per target Marc-André Lureau
@ 2017-12-14 16:30   ` Markus Armbruster
  2018-01-11 21:32     ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-14 16:30 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Michael Roth

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The following patches are going to introduce per-target #ifdef, and
> but the introspection data is generated only once, and must thus be
> built with the target.

"and but"?

> Drop "do_test_visitor_in_qmp_introspect(&&qmp_schema_qlit)" since it

s/&&/&/

> is no longer in a common object, and covered by "query-qmp-schema
> test" instead.

Do you mean test /x86_64/qmp/query-qmp-schema of tests/qmp-test.c?

That test tests significantly less.  It runs the command, tests it
succeeds and returns something.  The test you remove additionally tests
the returned value conforms to the schema, by passing it to
visit_type_SchemaInfoList().

Perhaps we can enhance the test you keep to avoid this loss.

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 44/50] build-sys: add a target schema
  2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 44/50] build-sys: add a target schema Marc-André Lureau
@ 2017-12-14 16:34   ` Markus Armbruster
  2018-01-11 21:32     ` Marc-André Lureau
  0 siblings, 1 reply; 118+ messages in thread
From: Markus Armbruster @ 2017-12-14 16:34 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, Dr. David Alan Gilbert

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> This schema is going to contain target-specific commands/events &
> types, that can be conditionnally guarded with poisoned defines. To
> filter it out by default, set the unit name to 'target'.
>
> And new rules to compile this unit generated files per-target.
>
> Use the "-u all" options for the introspection schema, since it is
> generated as a single file and must contain all definitions.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json |  1 +
>  qapi/target.json |  3 +++
>  monitor.c        |  2 ++
>  Makefile         | 29 ++++++++++++++++++++++++++++-
>  Makefile.target  |  2 ++
>  5 files changed, 36 insertions(+), 1 deletion(-)
>  create mode 100644 qapi/target.json
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index f3af2cb851..42b6aebddb 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -92,6 +92,7 @@
>  { 'include': 'qapi/transaction.json' }
>  { 'include': 'qapi/trace.json' }
>  { 'include': 'qapi/introspect.json' }
> +{ 'include': 'qapi/target.json' }
>  
>  ##
>  # = Miscellanea
> diff --git a/qapi/target.json b/qapi/target.json
> new file mode 100644
> index 0000000000..e9644f52c2
> --- /dev/null
> +++ b/qapi/target.json
> @@ -0,0 +1,3 @@
> +# -*- Mode: Python -*-
> +
> +{ 'pragma': { 'unit': 'target' } }
> diff --git a/monitor.c b/monitor.c
> index bf8a7685bf..af4eaeca5e 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -68,6 +68,7 @@
>  #include "exec/exec-all.h"
>  #include "qemu/log.h"
>  #include "qmp-commands.h"
> +#include "target-qmp-commands.h"
>  #include "hmp.h"
>  #include "qemu/thread.h"
>  #include "block/qapi.h"
> @@ -1003,6 +1004,7 @@ void monitor_init_qmp_commands(void)
>  
>      QTAILQ_INIT(&qmp_commands);
>      qmp_init_marshal(&qmp_commands);
> +    target_qmp_init_marshal(&qmp_commands);
>  
>      qmp_register_command(&qmp_commands, "query-qmp-schema",
>                           qmp_query_qmp_schema,
> diff --git a/Makefile b/Makefile
> index 337a1f6f9b..7356b4e7b7 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -54,6 +54,8 @@ include $(SRC_PATH)/rules.mak
>  GENERATED_FILES = qemu-version.h config-host.h qemu-options.def
>  GENERATED_FILES += qmp-commands.h qapi-types.h qapi-visit.h qapi-event.h
>  GENERATED_FILES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
> +GENERATED_FILES += target-qmp-commands.h target-qapi-types.h target-qapi-visit.h target-qapi-event.h
> +GENERATED_FILES += target-qmp-marshal.c target-qapi-types.c target-qapi-visit.c target-qapi-event.c
>  GENERATED_FILES += qmp-introspect.h
>  GENERATED_FILES += qmp-introspect.c
>  
> @@ -418,6 +420,7 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
>                 $(SRC_PATH)/qapi/rocker.json \
>                 $(SRC_PATH)/qapi/run-state.json \
>                 $(SRC_PATH)/qapi/sockets.json \
> +               $(SRC_PATH)/qapi/target.json \
>                 $(SRC_PATH)/qapi/tpm.json \
>                 $(SRC_PATH)/qapi/trace.json \
>                 $(SRC_PATH)/qapi/transaction.json \
> @@ -443,10 +446,34 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
>  	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
>  		$(gen-out-type) -o "." $<, \
>  		"GEN","$@")
> +
> +target-qapi-types.c target-qapi-types.h :\
> +$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
> +	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
> +		-i qapi-types.h \
> +		$(gen-out-type) -p target- -u target $<, \
> +		"GEN","$@")
> +target-qapi-visit.c target-qapi-visit.h :\
> +$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
> +	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
> +		-i qapi-visit.h \
> +		$(gen-out-type) -p target- -u target $<, \
> +		"GEN","$@")
> +target-qapi-event.c target-qapi-event.h :\
> +$(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
> +	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
> +		$(gen-out-type) -p target- -u target  $<, \
> +		"GEN","$@")
> +target-qmp-commands.h target-qmp-marshal.c :\
> +$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
> +	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
> +		$(gen-out-type) -p target- -u target $<, \
> +		"GEN","$@")
> +
>  qmp-introspect.h qmp-introspect.c :\
>  $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
>  	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
> -		$(gen-out-type) -o "." $<, \
> +		$(gen-out-type) -o "." -u all $<, \
>  		"GEN","$@")
>  

Let's see whether I understand how this works.  Without -u (not fully
visible in the diff), we get everything but the target-specific stuff.
With -u target, we get just the target-specific stuff.  With -u all, we
get everything.  Correct?

>  QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
> diff --git a/Makefile.target b/Makefile.target
> index 0d28ed1df0..e44a3847d3 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -157,6 +157,8 @@ endif
>  
>  GENERATED_FILES += hmp-commands.h hmp-commands-info.h
>  
> +obj-y += target-qapi-types.o target-qapi-visit.o
> +obj-y += target-qapi-event.o target-qmp-marshal.o
>  obj-y += qmp-introspect.o
>  
>  endif # CONFIG_SOFTMMU

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 00/50] Hi,
  2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
                   ` (50 preceding siblings ...)
  2017-09-11 11:54 ` [Qemu-devel] [PATCH v3 00/50] Hi, no-reply
@ 2017-12-18 13:14 ` Markus Armbruster
  51 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2017-12-18 13:14 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> In order to clean-up some hacks in qapi (having to unregister commands
> at runtime), I proposed a "[PATCH v5 02/20] qapi.py: add a simple #ifdef condition"
>
> (see http://lists.gnu.org/archive/html/qemu-devel/2016-08/msg03106.html).
>
> However, we decided to drop that patch from the series and solve the
> problem later. The main issues were:
> - the syntax was awkward to the JSON schema and documentation
> - the evaluation of the condition was done in the qapi scripts, with
>   very limited capability
> - each target/config would need different generated files.
>
> Instead, it could defer the #if evaluation to the C-preprocessor.
>
> With this series, top-level qapi JSON entity can take 'if' keys:
>
> { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
>   'if': 'defined(TEST_IF_STRUCT)' }
>
> Members can be exploded as dictionnary with 'type'/'if' keys:
>
> { 'struct': 'TestIfStruct', 'data':
>   { 'foo': 'int',
>     'bar': { 'type': 'int', 'if': 'defined(TEST_IF_STRUCT_BAR)'} } }
>
> Enum values can be exploded as dictionnary with 'type'/'if' keys:
>
> { 'enum': 'TestIfEnum', 'data':
>   [ 'foo',
>     { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ] }
>
> A good benefit from having conditional schema is that introspection
> will reflect more accurately the capability of the server. Another
> benefit is that it may help to remove some dead code when disabling a
> functionality.
>
> Starting from patch "qapi: add conditions to VNC type/commands/events
> on the schema", the series demonstrate adding conditions, in order to
> remove qmp_unregister_commands_hack(). The main difference with v2, is
> the addition of a per-target schema in "build-sys: add a target
> schema". This removes the NEED_CPU_H hack, and keep most of the qapi
> files in common build.
>
> There are a lot more things we could make conditional in the QAPI
> schema, like pci/kvm/xen/numa/vde/slirp/posix/win32/vsock/lzo etc etc,
> however I am still evaluating the implication of such changes both
> externally and internally, for those interested, I can share my wip
> branch.
>
> Comments welcome,
>
> v3:
> - rebased (qlit is now merged upstream)
> - solve the per-target #ifdef problem by using a target.json
>   and new qapi generated target files
> - update some commit messages based on Markus review
> - more schema error reporting
> - move the ifcond argument closer to info/doc
> - use mcgen() in gen_if()/gen_endif()
> - simplify "modify to_qlit() to take an optional suffix"
> - fix generated qlit indentation
> - fix temporary build break by merging #if types & visitors patch
> - fix some redundant condtionals generation
> - change enum visitor to take QAPISchemaMember
> - reject unknown dictionnary keys in { .., 'if': ..}
> - split qapi test visitor print() with trailing ',' trick

Things I like:

* How you add conditionals to the QAPI language

* How the generated code changes

Things I don't like so much:

* A few commit messages are just too terse

* Code and its test added in separate patches

* ifcond_decorator

  I guess can either accept it, or come up with a better solution.

* Unconventional handling of sugared forms (see my review of PATCH 28).

* Addressing complilation consistency problems (see my review of PATCH
  17) before addressing them by splitting off target-specific generated
  files (PATCH 39..)

* Manual splitting of the generated monolith with pragma unit, -i and
  -u.  I guess can either accept it, or come up with a better solution.

Additionally, there are couple of minor things here and there, and a few
questions.  The usual patch review business.

Overall, there's much more for me to like than to dislike :)

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/50] qapi: add #if/#endif helpers
  2017-12-07 14:10   ` Markus Armbruster
@ 2018-01-11 21:21     ` Marc-André Lureau
  0 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:21 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Thu, Dec 7, 2017 at 3:10 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Add helpers to wrap generated code with #if/#endif lines.
>>
>> Add a function decorator that will be used to wrap visitor methods.
>> The decorator will check if code was generated before adding #if/#endif
>> lines. Used in the following patches.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  scripts/qapi.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 55 insertions(+)
>>
>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>> index 2a8e60e975..94b735d8d6 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -1897,6 +1897,61 @@ def guardend(name):
>>                   name=guardname(name))
>>
>>
>> +def gen_if(ifcond):
>> +    if not ifcond:
>> +        return ''
>> +    if isinstance(ifcond, str):
>> +        ifcond = [ifcond]
>
> Perhaps we should take this normalization step in the QAPISchema
> constructors.

Yes, it's not very convenient though, I added a TODO note

>
>> +    ret = ''
>> +    for ifc in ifcond:
>> +        ret += mcgen('''
>> +#if %(cond)s
>> +''', cond=ifc)
>> +    return ret
>> +
>> +
>> +def gen_endif(ifcond):
>> +    if not ifcond:
>> +        return ''
>> +    if isinstance(ifcond, str):
>> +        ifcond = [ifcond]
>> +    ret = ''
>> +    for ifc in reversed(ifcond):
>> +        ret += mcgen('''
>> +#endif /* %(cond)s */
>> +''', cond=ifc)
>> +    return ret
>> +
>> +
>> +# Wrap a method to add #if / #endif to generated code, only if some
>> +# code was generated. The method must have an 'ifcond' argument.
>> +# self must have 'if_members' listing the attributes to wrap.
>> +def ifcond_decorator(func):
>> +
>> +    def func_wrapper(self, *args, **kwargs):
>> +        import inspect
>
> Is hiding imports in function a good idea?

I believe it's best to restrict the import to the scope it is being
used, especially if it's very specific to that place. Some code do
that already.

>
>> +        idx = inspect.getargspec(func).args.index('ifcond')
>> +        ifcond = args[idx - 1]
>> +        save = {}
>> +        for mem in self.if_members:
>> +            save[mem] = getattr(self, mem)
>> +        func(self, *args, **kwargs)
>> +        for mem, val in save.items():
>> +            newval = getattr(self, mem)
>> +            if newval != val:
>> +                assert newval.startswith(val)
>> +                newval = newval[len(val):]
>> +                if newval[0] == '\n':
>> +                    val += '\n'
>> +                    newval = newval[1:]
>> +                val += gen_if(ifcond)
>> +                val += newval
>> +                val += gen_endif(ifcond)
>> +            setattr(self, mem, val)
>> +
>> +    return func_wrapper
>> +
>> +
>>  def gen_enum_lookup(name, values, prefix=None):
>>      ret = mcgen('''
>
> My gut feeling is still "too clever by half", but i'm reserving
> judgement until after review of its use, and exploration of
> alternatives.
>

Could easily be done as a follow-up.

thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 15/50] qapi-types: refactor variants handling
  2017-12-07 15:57   ` Markus Armbruster
@ 2018-01-11 21:22     ` Marc-André Lureau
  0 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:22 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Thu, Dec 7, 2017 at 4:57 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Generate variants objects outside gen_object(). This will allow to
>> easily wrap gen_object() with ifcond_decorator in the following patch.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  scripts/qapi-types.py | 37 +++++++++++++++++++++++--------------
>>  1 file changed, 23 insertions(+), 14 deletions(-)
>>
>> diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
>> index 915786c463..2b3588267b 100644
>> --- a/scripts/qapi-types.py
>> +++ b/scripts/qapi-types.py
>> @@ -53,23 +53,27 @@ def gen_struct_members(members):
>>      return ret
>>
>>
>> -def gen_object(name, base, members, variants):
>> -    if name in objects_seen:
>> -        return ''
>> -    objects_seen.add(name)
>> -
>> +def gen_variants_objects(variants):
>>      ret = ''
>>      if variants:
>>          for v in variants.variants:
>>              if isinstance(v.type, QAPISchemaObjectType):
>> +                ret += gen_variants_objects(v.type.variants)
>>                  ret += gen_object(v.type.name, v.type.base,
>>                                    v.type.local_members, v.type.variants)
>> +    return ret
>>
>> -    ret += mcgen('''
>> +
>> +def gen_object(name, base, members, variants):
>> +    if name in objects_seen:
>> +        return ''
>> +    objects_seen.add(name)
>> +
>> +    ret = mcgen('''
>>
>>  struct %(c_name)s {
>>  ''',
>> -                 c_name=c_name(name))
>> +                c_name=c_name(name))
>>
>>      if base:
>>          if not base.is_implicit():
>> @@ -218,11 +222,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
>>              self.decl += gen_array(name, element_type)
>>              self._gen_type_cleanup(name)
>>
>> -    def visit_object_type(self, name, info, ifcond, base, members, variants):
>> -        # Nothing to do for the special empty builtin
>> -        if name == 'q_empty':
>> -            return
>> -        self._fwdecl += gen_fwd_object_or_array(name)
>> +    def _gen_object(self, name, info, ifcond, base, members, variants):
>>          self.decl += gen_object(name, base, members, variants)
>>          if base and not base.is_implicit():
>>              self.decl += gen_upcast(name, base)
>> @@ -232,10 +232,19 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
>>              # implicit types won't be directly allocated/freed
>>              self._gen_type_cleanup(name)
>>
>> +    def visit_object_type(self, name, info, ifcond, base, members, variants):
>> +        # Nothing to do for the special empty builtin
>> +        if name == 'q_empty':
>> +            return
>> +        self._fwdecl += gen_fwd_object_or_array(name)
>> +        self.decl += gen_variants_objects(variants)
>> +        self._gen_object(name, info, None, base, members, variants)
>> +
>>      def visit_alternate_type(self, name, info, ifcond, variants):
>>          self._fwdecl += gen_fwd_object_or_array(name)
>> -        self.decl += gen_object(name, None, [variants.tag_member], variants)
>> -        self._gen_type_cleanup(name)
>> +        self.decl += gen_variants_objects(variants)
>> +        self._gen_object(name, info, None, None,
>> +                         [variants.tag_member], variants)
>
> Where did self._gen_type_cleanup(name) go?  Hmm, I guess it's now in
> _gen_object().  Confusing.

This factors out common code that must be wrap by the same ifcond, in
the following patch.

>>
>>  # If you link code generated from multiple schemata, you want only one
>>  # instance of the code for built-in types.  Generate it only when
>
> If I read this patch correctly, you move code from the beginning of
> gen_object() to new gen_variants_objects(), then arrange to have
> gen_variants_objects() called right before gen_object().  Correct?
>
> In old gen_object(), the code is guarded by
>
>        if name in objects_seen:
>            return ''
>        objects_seen.add(name)
>
> In new gen_variants_objects(), it isn't.  Why?

gen_variants_objects() calls gen_object() for each variants, so it
remains guarded.



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely
  2017-12-08  7:50       ` Markus Armbruster
@ 2018-01-11 21:24         ` Marc-André Lureau
  2018-02-02 14:43           ` Markus Armbruster
  0 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:24 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Fri, Dec 8, 2017 at 8:50 AM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>
>> On Thu, Dec 7, 2017 at 5:23 PM, Markus Armbruster <armbru@redhat.com> wrote:
>>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>>>
>>>> The C standard has the initial value at 0 and the subsequent values
>>>> incremented by 1. No need to set this explicitely.
>>>>
>>>> This will prevent from artificial "gaps" when compiling out some enum
>>>> values and having unnecessarily large MAX values & enums arrays.
>>>>
>>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>> ---
>>>>  scripts/qapi.py | 7 ++-----
>>>>  1 file changed, 2 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>>>> index 94b735d8d6..074ee221a1 100644
>>>> --- a/scripts/qapi.py
>>>> +++ b/scripts/qapi.py
>>>> @@ -1985,14 +1985,11 @@ typedef enum %(c_name)s {
>>>>  ''',
>>>>                  c_name=c_name(name))
>>>>
>>>> -    i = 0
>>>>      for value in enum_values:
>>>>          ret += mcgen('''
>>>> -    %(c_enum)s = %(i)d,
>>>> +    %(c_enum)s,
>>>>  ''',
>>>> -                     c_enum=c_enum_const(name, value, prefix),
>>>> -                     i=i)
>>>> -        i += 1
>>>> +                     c_enum=c_enum_const(name, value, prefix))
>>>>
>>>>      ret += mcgen('''
>>>>  } %(c_name)s;
>>>
>>> Recapitulate review of v2: this risks entertaining mishaps like
>>> compiling this one
>>>
>>>     typedef enum Color {
>>>         COLOR_WHITE,
>>> #if defined(NEED_CPU_H)
>>> #if defined(TARGET_S390X)
>>>         COLOR_BLUE,
>>> #endif /* defined(TARGET_S390X) */
>>> #endif /* defined(NEED_CPU_H) */
>>>         COLOR_BLACK,
>>>     } Color;
>>>
>>> in s390x-code (COLOR_BLACK = 2) and in target-independent code
>>> (COLOR_BLACK = 1), then linking the two together.
>>>
>>> Same issue for struct members and such (previous patch).
>>>
>>> What's our story on preventing disaster here?
>>>
>>> In the long run, we want to split the generated code so that
>>> target-specific and target-independent code are separate, and each part
>>> is always compiled with consistent preprocessor symbols.  But I'm afraid
>>> that's not in the card right now.
>>
>> Eh, I need to refresh my memories about that series, but I think
>> that's what I did in v3
>>
>> It doesn't use the NEED_CPU_H trick. It has a seperate per-target target.json
>
> Looking... aha!  target.json appears in PATCH 44 (which I haven't even
> glanced at, yet).  The problem appears in PATCH 16, though.  Perhaps a
> bit of patch reshuffling would do.

What problem appears in patch 16? Some code could be introduced using
NEED_CPU_H and link arch & independent code together? It is still true
after patch 44. If necessary, I can work on a split-qapi series before
the conditionals are added. But the real benefit is only apparent
after the conditional are introduced, so I am not motivated to
reorder.

>
>>> I therefore proposed the stupidest temporary stopgap that could possibly
>>> work: apply conditionals *only* to qmp-introspect.c, leave everything
>>> unconditional elsewhere.
>>
>> I don't like that idea much and I don't think we need that
>> restriction, but I need to get back to that series on some point
>> (probably after you finish the review).
>
> It's a beefy series, and it's probably best to let me review the largest
> prefix I can before we dive into discussion.

thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 19/50] qapi: add 'if' to enum members
  2017-12-08  8:38   ` Markus Armbruster
@ 2018-01-11 21:24     ` Marc-André Lureau
  0 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:24 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Fri, Dec 8, 2017 at 9:38 AM, Markus Armbruster <armbru@redhat.com> wrote:
> A bit more detail in the commit message would make this patch easier to
> review.
>
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  scripts/qapi.py                         | 39 ++++++++++++++++++++++++++++-----
>>  tests/Makefile.include                  |  1 -
>>  tests/qapi-schema/enum-dict-member.err  |  1 -
>>  tests/qapi-schema/enum-dict-member.exit |  1 -
>>  tests/qapi-schema/enum-dict-member.json |  2 --
>>  tests/qapi-schema/enum-dict-member.out  |  0
>>  tests/qapi-schema/qapi-schema-test.json |  5 +++--
>>  tests/qapi-schema/qapi-schema-test.out  |  3 ++-
>>  tests/qapi-schema/test-qapi.py          |  2 ++
>>  9 files changed, 41 insertions(+), 13 deletions(-)
>>  delete mode 100644 tests/qapi-schema/enum-dict-member.err
>>  delete mode 100644 tests/qapi-schema/enum-dict-member.exit
>>  delete mode 100644 tests/qapi-schema/enum-dict-member.json
>>  delete mode 100644 tests/qapi-schema/enum-dict-member.out
>>
>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>> index 386a577a59..1535de9ce7 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -659,6 +659,14 @@ def check_if(expr, info):
>>              info, "'if' condition must be a string or a list of strings")
>>
>>
>> +def check_unknown_keys(info, dict, allowed_keys):
>> +    diff = set(dict) - allowed_keys
>> +    if not diff:
>> +        return
>> +    raise QAPISemError(info, "Dictionnary has unknown keys: %s (allowed: %s)" %
>
> s/Dictionnary/Dictionary/

ok

>
>> +        (', '.join(diff), ', '.join(allowed_keys)))
>
> I'm afraid this duplicates a part of check_keys().  Could it be factored
> out?

done

>
>> +
>> +
>>  def check_type(info, source, value, allow_array=False,
>>                 allow_dict=False, allow_optional=False,
>>                 allow_metas=[]):
>> @@ -739,6 +747,10 @@ def check_event(expr, info):
>>                 allow_metas=meta)
>>
>>
>> +def enum_get_values(expr):
>> +    return [e if isinstance(e, str) else e['name'] for e in expr['data']]
>> +
>> +
>>  def check_union(expr, info):
>>      name = expr['union']
>>      base = expr.get('base')
>> @@ -798,7 +810,7 @@ def check_union(expr, info):
>>          # If the discriminator names an enum type, then all members
>>          # of 'data' must also be members of the enum type.
>>          if enum_define:
>> -            if key not in enum_define['data']:
>> +            if key not in enum_get_values(enum_define):
>>                  raise QAPISemError(info,
>>                                     "Discriminator value '%s' is not found in "
>>                                     "enum '%s'"
>> @@ -806,7 +818,7 @@ def check_union(expr, info):
>>
>>      # If discriminator is user-defined, ensure all values are covered
>>      if enum_define:
>> -        for value in enum_define['data']:
>> +        for value in enum_get_values(enum_define):
>>              if value not in members.keys():
>>                  raise QAPISemError(info, "Union '%s' data missing '%s' branch"
>>                                     % (name, value))
>> @@ -837,7 +849,7 @@ def check_alternate(expr, info):
>>          if qtype == 'QTYPE_QSTRING':
>>              enum_expr = enum_types.get(value)
>>              if enum_expr:
>> -                for v in enum_expr['data']:
>> +                for v in enum_get_values(enum_expr):
>>                      if v in ['on', 'off']:
>>                          conflicting.add('QTYPE_QBOOL')
>>                      if re.match(r'[-+0-9.]', v): # lazy, could be tightened
>> @@ -865,6 +877,14 @@ def check_enum(expr, info):
>>          raise QAPISemError(info,
>>                             "Enum '%s' requires a string for 'prefix'" % name)
>>      for member in members:
>> +        if isinstance(member, dict):
>> +            if 'name' not in member:
>> +                raise QAPISemError(info, "Dictionary member of enum '%s' must "
>> +                                   "have a 'name' key" % name)
>> +            if 'if' in member:
>> +                check_if(member, info)
>> +            check_unknown_keys(info, member, {'name', 'if'})
>> +            member = member['name']
>>          check_name(info, "Member of enum '%s'" % name, member,
>>                     enum_member=True)
>>
>> @@ -1280,9 +1300,11 @@ class QAPISchemaObjectType(QAPISchemaType):
>>  class QAPISchemaMember(object):
>>      role = 'member'
>>
>> -    def __init__(self, name):
>> +    def __init__(self, name, ifcond=None):
>>          assert isinstance(name, str)
>> +        assert ifcond is None or isinstance(ifcond, str)
>>          self.name = name
>> +        self.ifcond = ifcond
>>          self.owner = None
>>
>>      def set_owner(self, name):
>
> QAPISchemaObjectTypeMember inherits .ifcond.  Peeking ahead: looks like
> it'll get used when we add conditions to object type members, PATCH
> 23ff.  Okay.  Mentioning it in the commit message wouldn't hurt, though.

It will *also* get used. Ok, updated commit message.

>
>> @@ -1559,7 +1581,14 @@ class QAPISchema(object):
>>                                              qtype_values, 'QTYPE'))
>>
>>      def _make_enum_members(self, values):
>> -        return [QAPISchemaMember(v) for v in values]
>> +        enum = []
>> +        for v in values:
>> +            ifcond = None
>> +            if isinstance(v, dict):
>> +                ifcond = v.get('if')
>> +                v = v['name']
>> +            enum.append(QAPISchemaMember(v, ifcond))
>
>
> I like brevity a lot, but if it's bought by assigning to a loop control
> variable, I pass.  Cleaner:
>
>            for v in values:
>                if isinstance(v, dict):
>                    name = v['name']
>                    ifcond = v.get('if')
>                else:
>                    name = v
>                    ifcond = None
>            enum.append(QAPISchemaMember(name, ifcond))
>

sure

>> +        return enum
>>
>>      def _make_implicit_enum_type(self, name, info, ifcond, values):
>>          # See also QAPISchemaObjectTypeMember._pretty_owner()
>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>> index 8dac7c9083..a9f0ddbe01 100644
>> --- a/tests/Makefile.include
>> +++ b/tests/Makefile.include
>> @@ -443,7 +443,6 @@ qapi-schema += empty.json
>>  qapi-schema += enum-bad-name.json
>>  qapi-schema += enum-bad-prefix.json
>>  qapi-schema += enum-clash-member.json
>> -qapi-schema += enum-dict-member.json
>>  qapi-schema += enum-int-member.json
>>  qapi-schema += enum-member-case.json
>>  qapi-schema += enum-missing-data.json
>> diff --git a/tests/qapi-schema/enum-dict-member.err b/tests/qapi-schema/enum-dict-member.err
>> deleted file mode 100644
>> index 8ca146ea59..0000000000
>> --- a/tests/qapi-schema/enum-dict-member.err
>> +++ /dev/null
>> @@ -1 +0,0 @@
>> -tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum' requires a string name
>> diff --git a/tests/qapi-schema/enum-dict-member.exit b/tests/qapi-schema/enum-dict-member.exit
>> deleted file mode 100644
>> index d00491fd7e..0000000000
>> --- a/tests/qapi-schema/enum-dict-member.exit
>> +++ /dev/null
>> @@ -1 +0,0 @@
>> -1
>> diff --git a/tests/qapi-schema/enum-dict-member.json b/tests/qapi-schema/enum-dict-member.json
>> deleted file mode 100644
>> index 79672e0f09..0000000000
>> --- a/tests/qapi-schema/enum-dict-member.json
>> +++ /dev/null
>> @@ -1,2 +0,0 @@
>> -# we reject any enum member that is not a string
>> -{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
>> diff --git a/tests/qapi-schema/enum-dict-member.out b/tests/qapi-schema/enum-dict-member.out
>> deleted file mode 100644
>> index e69de29bb2..0000000000
>
> Hmm.  The dict instance of "enum value must be of an appropriate JSON
> type" error class goes away in this patch, but the class remains.  Do we
> still cover it?
>
> There's enum-int-member.json, but it's not a good test: it dies in the
> lexer.  I think we should replace the two tests by a single one.
> Perhaps something like 'data': [ [] ] would do.

I replaced enum-dict-member by enum-bad-member. I left the int-member
test, because it has also the purpose to check the lexer.

>
>> diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
>> index dc2c444fc1..ad2b405d83 100644
>> --- a/tests/qapi-schema/qapi-schema-test.json
>> +++ b/tests/qapi-schema/qapi-schema-test.json
>> @@ -194,7 +194,8 @@
>>  { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
>>    'if': 'defined(TEST_IF_STRUCT)' }
>>
>> -{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
>> +{ 'enum': 'TestIfEnum', 'data':
>> +  [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
>>    'if': 'defined(TEST_IF_ENUM)' }
>>
>>  { 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
>> @@ -203,7 +204,7 @@
>>  { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
>>    'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
>>
>> -{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
>> +{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct', 'bar': 'TestIfEnum' },
>>    'if': 'defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)' }
>>
>>  { 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
>
> Should this hunk be in PATCH 04?

It could, but it is not necessary until conditionals are added to
verify introspection generation.

>
>> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
>> index 9a7cafc269..8a0cf1a551 100644
>> --- a/tests/qapi-schema/qapi-schema-test.out
>> +++ b/tests/qapi-schema/qapi-schema-test.out
>> @@ -74,7 +74,7 @@ command TestIfCmd q_obj_TestIfCmd-arg -> None
>>      if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
>>  enum TestIfEnum
>>      member foo:
>> -    member bar:
>> +    member bar: if=defined(TEST_IF_ENUM_BAR)
>>      if defined(TEST_IF_ENUM)
>>  event TestIfEvent q_obj_TestIfEvent-arg
>>     boxed=False
>> @@ -228,6 +228,7 @@ object q_obj_EVENT_D-arg
>>      member enum3: EnumOne optional=True
>>  object q_obj_TestIfCmd-arg
>>      member foo: TestIfStruct optional=False
>> +    member bar: TestIfEnum optional=False
>>      if defined(TEST_IF_CMD) && defined(TEST_IF_STRUCT)
>>  object q_obj_TestIfEvent-arg
>>      member foo: TestIfStruct optional=False
>> diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
>> index 67c6c1ecef..a86c3b5ee1 100644
>> --- a/tests/qapi-schema/test-qapi.py
>> +++ b/tests/qapi-schema/test-qapi.py
>> @@ -56,6 +56,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
>>              print '    member %s:' % m.name,
>>              if isinstance(m, QAPISchemaObjectTypeMember):
>>                  print '%s optional=%s' % (m.type.name, m.optional),
>> +            if m.ifcond:
>> +                print 'if=%s' % m.ifcond,
>>              print
>>
>>      @staticmethod
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 20/50] qapi-event: add 'if' condition to generated enum
  2017-12-08 14:07     ` Markus Armbruster
@ 2018-01-11 21:31       ` Marc-André Lureau
  0 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:31 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Fri, Dec 8, 2017 at 3:07 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Markus Armbruster <armbru@redhat.com> writes:
>
>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>>
>>> Add condition to QAPIEvent enum members based on the event 'if'.
>>>
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>  scripts/qapi-event.py | 2 +-
>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
>>> index 38f4264817..60c6f7030d 100644
>>> --- a/scripts/qapi-event.py
>>> +++ b/scripts/qapi-event.py
>>> @@ -168,7 +168,7 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
>>>      def visit_event(self, name, info, ifcond, arg_type, boxed):
>>>          self.decl += gen_event_send_decl(name, arg_type, boxed)
>>>          self.defn += gen_event_send(name, arg_type, boxed)
>>> -        self._event_names.append(QAPISchemaMember(name))
>>> +        self._event_names.append(QAPISchemaMember(name, ifcond))
>>>
>>>
>>>  (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
>>
>> No test coverage?

There is no coverage of this change in qapi-schema-test.out since the
event_names enum is an implicit type created by qapi-event.py.

We verify the generated event.h still compiles ;)

Seriously, if necessary we could add a specific test somehow, checking
the generated code further.

>
> Wait!  This patch has no effect, because the it merely puts the ifcond
> argument into QAPISchemaMember.ifcond.  Only later patches put
> QAPISchemaMember.ifcond to use.  Correct?

In general, the patches were splitted this way:
1. accept 'if' in json & verify with visitors
2. add the #if wrapping in the generated code
3. add negative / error tests

In v4, I merged most tests with 1.

> Aside: the ifcond_decorator could already be doing something with the
> argument, but I'll be hanged if I remember how that magic works.
>

It's wrapping visitor methods with a ifcond argument in the previous
patches, not used later.

thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 24/50] qapi: add some struct member tests
  2017-12-09  9:07   ` Markus Armbruster
@ 2018-01-11 21:31     ` Marc-André Lureau
  2018-02-02 14:51       ` Markus Armbruster
  0 siblings, 1 reply; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:31 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Sat, Dec 9, 2017 at 10:07 AM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  tests/Makefile.include                    |  2 ++
>>  tests/qapi-schema/struct-if-invalid.err   |  1 +
>>  tests/qapi-schema/struct-if-invalid.exit  |  1 +
>>  tests/qapi-schema/struct-if-invalid.json  |  3 +++
>>  tests/qapi-schema/struct-if-invalid.out   |  0
>>  tests/qapi-schema/struct-member-type.err  |  0
>>  tests/qapi-schema/struct-member-type.exit |  1 +
>>  tests/qapi-schema/struct-member-type.json |  2 ++
>>  tests/qapi-schema/struct-member-type.out  | 12 ++++++++++++
>>  9 files changed, 22 insertions(+)
>>  create mode 100644 tests/qapi-schema/struct-if-invalid.err
>>  create mode 100644 tests/qapi-schema/struct-if-invalid.exit
>>  create mode 100644 tests/qapi-schema/struct-if-invalid.json
>>  create mode 100644 tests/qapi-schema/struct-if-invalid.out
>>  create mode 100644 tests/qapi-schema/struct-member-type.err
>>  create mode 100644 tests/qapi-schema/struct-member-type.exit
>>  create mode 100644 tests/qapi-schema/struct-member-type.json
>>  create mode 100644 tests/qapi-schema/struct-member-type.out
>>
>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>> index 0aa532f029..44a3d8895e 100644
>> --- a/tests/Makefile.include
>> +++ b/tests/Makefile.include
>> @@ -520,7 +520,9 @@ qapi-schema += returns-whitelist.json
>>  qapi-schema += struct-base-clash-deep.json
>>  qapi-schema += struct-base-clash.json
>>  qapi-schema += struct-data-invalid.json
>> +qapi-schema += struct-if-invalid.json
>>  qapi-schema += struct-member-invalid.json
>> +qapi-schema += struct-member-type.json
>>  qapi-schema += trailing-comma-list.json
>>  qapi-schema += trailing-comma-object.json
>>  qapi-schema += type-bypass-bad-gen.json
>> diff --git a/tests/qapi-schema/struct-if-invalid.err b/tests/qapi-schema/struct-if-invalid.err
>> new file mode 100644
>> index 0000000000..42245262a9
>> --- /dev/null
>> +++ b/tests/qapi-schema/struct-if-invalid.err
>> @@ -0,0 +1 @@
>> +tests/qapi-schema/struct-if-invalid.json:2: Member 'bar' of 'data' for struct 'TestIfStruct' should be a type name
>> diff --git a/tests/qapi-schema/struct-if-invalid.exit b/tests/qapi-schema/struct-if-invalid.exit
>> new file mode 100644
>> index 0000000000..d00491fd7e
>> --- /dev/null
>> +++ b/tests/qapi-schema/struct-if-invalid.exit
>> @@ -0,0 +1 @@
>> +1
>> diff --git a/tests/qapi-schema/struct-if-invalid.json b/tests/qapi-schema/struct-if-invalid.json
>> new file mode 100644
>> index 0000000000..466cdb61e1
>> --- /dev/null
>> +++ b/tests/qapi-schema/struct-if-invalid.json
>> @@ -0,0 +1,3 @@
>> +# check missing 'type'
>> +{ 'struct': 'TestIfStruct', 'data':
>> +  { 'foo': 'int', 'bar': { 'if': 'defined(TEST_IF_STRUCT_BAR)' } } }
>
> Hmm.  This tests the previous patch's change to check_type().  It
> demonstrates that the "should be a type name" error message can be
> suboptimal: it gets triggered when
>
>     not isinstance(value, str)
>     and not (isinstance(value, dict) and 'type' in value)
>
> Fine when the value is neither str not dict.  Suboptimal when it's dict
> and 'type' is missing.  A more obvious example of suboptimality would be
>
>    'bar': { 'tvpe': 'int' }
>
> The previous patch's
>
>         if isinstance(value, dict) and 'type' in value:
>             check_type(info, source, value['type'], allow_array,
>                        allow_dict, allow_optional, allow_metas)
>             if 'if' in value:
>                 check_if(value, info)
>             check_unknown_keys(info, value, {'type', 'if'})
>             return
>         else:
>             raise QAPISemError(info, "%s should be a type name" % source)
>
> should be improved to something like
>
>         if not isinstance(value, dict):
>             raise QAPISemError(
>                 info, "%s should be a type name or dictionary" % source)
>         if 'type' not in value:
>             raise QAPISemError(
>                 info, "%s must have a member 'type'" % source)
>         check_type(info, source, value['type'], allow_array,
>                    allow_dict, allow_optional, allow_metas)
>         if 'if' in value:
>             check_if(value, info)
>         check_unknown_keys(info, value, {'type', 'if'})
>         return
>
> producing
>
>     struct-if-invalid.json:2: Member 'bar' of 'data' for struct 'TestIfStruct' must have a member 'type'
>

Fixed differently in v4

> The fact that I missed this in review of the code, but noticed it in the
> tests is why I want tests added together with the code they test.
>

Changed in v4

> Nitpick: the file name struct-if-invalid makes me expect an invalid if.
> Not the case.  It's a missing type.  Let's rename accordingly.

Done

>
>> diff --git a/tests/qapi-schema/struct-if-invalid.out b/tests/qapi-schema/struct-if-invalid.out
>> new file mode 100644
>> index 0000000000..e69de29bb2
>> diff --git a/tests/qapi-schema/struct-member-type.err b/tests/qapi-schema/struct-member-type.err
>> new file mode 100644
>> index 0000000000..e69de29bb2
>> diff --git a/tests/qapi-schema/struct-member-type.exit b/tests/qapi-schema/struct-member-type.exit
>> new file mode 100644
>> index 0000000000..573541ac97
>> --- /dev/null
>> +++ b/tests/qapi-schema/struct-member-type.exit
>> @@ -0,0 +1 @@
>> +0
>> diff --git a/tests/qapi-schema/struct-member-type.json b/tests/qapi-schema/struct-member-type.json
>> new file mode 100644
>> index 0000000000..8b33027817
>> --- /dev/null
>> +++ b/tests/qapi-schema/struct-member-type.json
>> @@ -0,0 +1,2 @@
>> +# check member 'a' with 'type' key only
>> +{ 'struct': 'foo', 'data': { 'a': { 'type': 'str' } } }
>> diff --git a/tests/qapi-schema/struct-member-type.out b/tests/qapi-schema/struct-member-type.out
>> new file mode 100644
>> index 0000000000..04b969d2e3
>> --- /dev/null
>> +++ b/tests/qapi-schema/struct-member-type.out
>> @@ -0,0 +1,12 @@
>> +enum QType
>> +    prefix QTYPE
>> +    member none:
>> +    member qnull:
>> +    member qnum:
>> +    member qstring:
>> +    member qdict:
>> +    member qlist:
>> +    member qbool:
>> +object foo
>> +    member a: str optional=False
>> +object q_empty
>
> This is a positive test, isn't it?  Positive tests go into
> qapi-schema-test.json.
>

Right, I wonder why we have .exit files then. Perhaps the few ones
that return 0 shouldn't exist.

thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 26/50] qapi: add 'if' on union variants
  2017-12-11 10:36   ` Markus Armbruster
@ 2018-01-11 21:32     ` Marc-André Lureau
  0 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Mon, Dec 11, 2017 at 11:36 AM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  scripts/qapi.py                         | 15 ++++++++++-----
>>  tests/qapi-schema/qapi-schema-test.json |  7 ++++++-
>>  tests/qapi-schema/qapi-schema-test.out  |  8 ++++++++
>>  tests/qapi-schema/test-qapi.py          |  5 ++++-
>>  4 files changed, 28 insertions(+), 7 deletions(-)
>>
>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>> index 15711f96fa..2f14edfa1f 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -1412,8 +1412,8 @@ class QAPISchemaObjectTypeVariants(object):
>>  class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
>>      role = 'branch'
>>
>> -    def __init__(self, name, typ):
>> -        QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
>> +    def __init__(self, name, typ, ifcond=None):
>> +        QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond)
>>
>>
>>  class QAPISchemaAlternateType(QAPISchemaType):
>> @@ -1674,13 +1674,18 @@ class QAPISchema(object):
>>          return QAPISchemaObjectTypeVariant(case, typ)
>>
>>      def _make_simple_variant(self, case, typ, info):
>> +        ifcond = None
>> +        if isinstance(typ, dict):
>> +            check_unknown_keys(info, typ, {'type', 'if'})
>> +            ifcond = typ.get('if')
>> +            typ = typ['type']
>>          if isinstance(typ, list):
>>              assert len(typ) == 1
>>              typ = self._make_array_type(typ[0], info)
>>          typ = self._make_implicit_object_type(
>>              typ, info, None, self.lookup_type(typ).ifcond,
>>              'wrapper', [self._make_member('data', typ, info)])
>> -        return QAPISchemaObjectTypeVariant(case, typ)
>> +        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
>>
>>      def _def_union_type(self, expr, info, doc):
>>          name = expr['union']
>> @@ -1700,8 +1705,8 @@ class QAPISchema(object):
>>          else:
>>              variants = [self._make_simple_variant(key, value, info)
>>                          for (key, value) in data.iteritems()]
>> -            typ = self._make_implicit_enum_type(name, info, ifcond,
>> -                                                [v.name for v in variants])
>> +            values = [{'name': v.name, 'if': v.ifcond} for v in variants]
>> +            typ = self._make_implicit_enum_type(name, info, ifcond, values)
>>              tag_member = QAPISchemaObjectTypeMember('type', typ, False)
>>              members = [tag_member]
>>          self._def_entity(
>> diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
>> index 5cfccabb3d..895e80a978 100644
>> --- a/tests/qapi-schema/qapi-schema-test.json
>> +++ b/tests/qapi-schema/qapi-schema-test.json
>> @@ -200,9 +200,14 @@
>>    [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
>>    'if': 'defined(TEST_IF_ENUM)' }
>>
>> -{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
>> +{ 'union': 'TestIfUnion', 'data':
>> +  { 'foo': 'TestStruct',
>> +    'union_bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
>>    'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
>>
>> +{ 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' },
>> +  'if': 'defined(TEST_IF_UNION)' }
>> +
>>  { 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
>>    'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
>>
>> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
>> index 6df4e49c69..ee009c5626 100644
>> --- a/tests/qapi-schema/qapi-schema-test.out
>> +++ b/tests/qapi-schema/qapi-schema-test.out
>> @@ -87,9 +87,14 @@ object TestIfUnion
>>      member type: TestIfUnionKind optional=False
>>      tag type
>>      case foo: q_obj_TestStruct-wrapper
>> +    case union_bar: q_obj_str-wrapper if=defined(TEST_IF_UNION_BAR)
>
> PATCH 22, but I only spotted it here.  We say "if=COND" in some places,
> ...
>
>>      if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
>> +command TestIfUnionCmd q_obj_TestIfUnionCmd-arg -> None
>> +   gen=True success_response=True boxed=False
>> +    if defined(TEST_IF_UNION)
>
> ... and "if COND" in other places.  I guess the '=' is there to match
> existing flag printing like optional=BOOL.
>
> I'd prefer less decorated output, i.e. instead of
>
>     enum TestIfEnum
>         member foo:
>         member bar: if=defined(TEST_IF_ENUM_BAR)
>         if defined(TEST_IF_ENUM)
>
> something like
>
> enum TestIfEnum
>     member foo
>     member bar
>         if defined(TEST_IF_ENUM_BAR)
>     if defined(TEST_IF_ENUM)
>
> Could touch that up on commit.
>

ok, changed

>>  enum TestIfUnionKind
>>      member foo:
>> +    member union_bar: if=defined(TEST_IF_UNION_BAR)
>>      if defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)
>>  object TestStruct
>>      member integer: int optional=False
>> @@ -235,6 +240,9 @@ object q_obj_TestIfEvent-arg
>>      member foo: TestIfStruct optional=False
>>      member bar: TestIfEnum optional=False if=defined(TEST_IF_EVT_BAR)
>>      if defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)
>> +object q_obj_TestIfUnionCmd-arg
>> +    member union_cmd_arg: TestIfUnion optional=False
>> +    if defined(TEST_IF_UNION)
>>  object q_obj_TestStruct-wrapper
>>      member data: TestStruct optional=False
>>  object q_obj_UserDefFlatUnion2-base
>> diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
>> index a86c3b5ee1..87a8efff78 100644
>> --- a/tests/qapi-schema/test-qapi.py
>> +++ b/tests/qapi-schema/test-qapi.py
>> @@ -65,7 +65,10 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
>>          if variants:
>>              print '    tag %s' % variants.tag_member.name
>>              for v in variants.variants:
>> -                print '    case %s: %s' % (v.name, v.type.name)
>> +                print '    case %s: %s' % (v.name, v.type.name),
>> +                if v.ifcond:
>> +                    print 'if=%s' % v.ifcond,
>> +                print
>>
>>      @staticmethod
>>      def _print_if(ifcond):
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 43/50] build-sys: move qmp-introspect per target
  2017-12-14 16:30   ` Markus Armbruster
@ 2018-01-11 21:32     ` Marc-André Lureau
  0 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth

Hi

On Thu, Dec 14, 2017 at 5:30 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> The following patches are going to introduce per-target #ifdef, and
>> but the introspection data is generated only once, and must thus be
>> built with the target.
>
> "and but"?
>
>> Drop "do_test_visitor_in_qmp_introspect(&&qmp_schema_qlit)" since it
>
> s/&&/&/
>
>> is no longer in a common object, and covered by "query-qmp-schema
>> test" instead.
>
> Do you mean test /x86_64/qmp/query-qmp-schema of tests/qmp-test.c?
>

I updated the commit message.

> That test tests significantly less.  It runs the command, tests it
> succeeds and returns something.  The test you remove additionally tests
> the returned value conforms to the schema, by passing it to
> visit_type_SchemaInfoList().
>
> Perhaps we can enhance the test you keep to avoid this loss.
>

It does call visit_type_SchemaInfoList() already on the return value.

thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 44/50] build-sys: add a target schema
  2017-12-14 16:34   ` Markus Armbruster
@ 2018-01-11 21:32     ` Marc-André Lureau
  0 siblings, 0 replies; 118+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Dr. David Alan Gilbert

Hi

On Thu, Dec 14, 2017 at 5:34 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
>> This schema is going to contain target-specific commands/events &
>> types, that can be conditionnally guarded with poisoned defines. To
>> filter it out by default, set the unit name to 'target'.
>>
>> And new rules to compile this unit generated files per-target.
>>
>> Use the "-u all" options for the introspection schema, since it is
>> generated as a single file and must contain all definitions.
>>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  qapi-schema.json |  1 +
>>  qapi/target.json |  3 +++
>>  monitor.c        |  2 ++
>>  Makefile         | 29 ++++++++++++++++++++++++++++-
>>  Makefile.target  |  2 ++
>>  5 files changed, 36 insertions(+), 1 deletion(-)
>>  create mode 100644 qapi/target.json
>>
>> diff --git a/qapi-schema.json b/qapi-schema.json
>> index f3af2cb851..42b6aebddb 100644
>> --- a/qapi-schema.json
>> +++ b/qapi-schema.json
>> @@ -92,6 +92,7 @@
>>  { 'include': 'qapi/transaction.json' }
>>  { 'include': 'qapi/trace.json' }
>>  { 'include': 'qapi/introspect.json' }
>> +{ 'include': 'qapi/target.json' }
>>
>>  ##
>>  # = Miscellanea
>> diff --git a/qapi/target.json b/qapi/target.json
>> new file mode 100644
>> index 0000000000..e9644f52c2
>> --- /dev/null
>> +++ b/qapi/target.json
>> @@ -0,0 +1,3 @@
>> +# -*- Mode: Python -*-
>> +
>> +{ 'pragma': { 'unit': 'target' } }
>> diff --git a/monitor.c b/monitor.c
>> index bf8a7685bf..af4eaeca5e 100644
>> --- a/monitor.c
>> +++ b/monitor.c
>> @@ -68,6 +68,7 @@
>>  #include "exec/exec-all.h"
>>  #include "qemu/log.h"
>>  #include "qmp-commands.h"
>> +#include "target-qmp-commands.h"
>>  #include "hmp.h"
>>  #include "qemu/thread.h"
>>  #include "block/qapi.h"
>> @@ -1003,6 +1004,7 @@ void monitor_init_qmp_commands(void)
>>
>>      QTAILQ_INIT(&qmp_commands);
>>      qmp_init_marshal(&qmp_commands);
>> +    target_qmp_init_marshal(&qmp_commands);
>>
>>      qmp_register_command(&qmp_commands, "query-qmp-schema",
>>                           qmp_query_qmp_schema,
>> diff --git a/Makefile b/Makefile
>> index 337a1f6f9b..7356b4e7b7 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -54,6 +54,8 @@ include $(SRC_PATH)/rules.mak
>>  GENERATED_FILES = qemu-version.h config-host.h qemu-options.def
>>  GENERATED_FILES += qmp-commands.h qapi-types.h qapi-visit.h qapi-event.h
>>  GENERATED_FILES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
>> +GENERATED_FILES += target-qmp-commands.h target-qapi-types.h target-qapi-visit.h target-qapi-event.h
>> +GENERATED_FILES += target-qmp-marshal.c target-qapi-types.c target-qapi-visit.c target-qapi-event.c
>>  GENERATED_FILES += qmp-introspect.h
>>  GENERATED_FILES += qmp-introspect.c
>>
>> @@ -418,6 +420,7 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
>>                 $(SRC_PATH)/qapi/rocker.json \
>>                 $(SRC_PATH)/qapi/run-state.json \
>>                 $(SRC_PATH)/qapi/sockets.json \
>> +               $(SRC_PATH)/qapi/target.json \
>>                 $(SRC_PATH)/qapi/tpm.json \
>>                 $(SRC_PATH)/qapi/trace.json \
>>                 $(SRC_PATH)/qapi/transaction.json \
>> @@ -443,10 +446,34 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
>>       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
>>               $(gen-out-type) -o "." $<, \
>>               "GEN","$@")
>> +
>> +target-qapi-types.c target-qapi-types.h :\
>> +$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
>> +     $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
>> +             -i qapi-types.h \
>> +             $(gen-out-type) -p target- -u target $<, \
>> +             "GEN","$@")
>> +target-qapi-visit.c target-qapi-visit.h :\
>> +$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
>> +     $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
>> +             -i qapi-visit.h \
>> +             $(gen-out-type) -p target- -u target $<, \
>> +             "GEN","$@")
>> +target-qapi-event.c target-qapi-event.h :\
>> +$(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
>> +     $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
>> +             $(gen-out-type) -p target- -u target  $<, \
>> +             "GEN","$@")
>> +target-qmp-commands.h target-qmp-marshal.c :\
>> +$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
>> +     $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
>> +             $(gen-out-type) -p target- -u target $<, \
>> +             "GEN","$@")
>> +
>>  qmp-introspect.h qmp-introspect.c :\
>>  $(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
>>       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
>> -             $(gen-out-type) -o "." $<, \
>> +             $(gen-out-type) -o "." -u all $<, \
>>               "GEN","$@")
>>
>
> Let's see whether I understand how this works.  Without -u (not fully
> visible in the diff), we get everything but the target-specific stuff.
> With -u target, we get just the target-specific stuff.  With -u all, we
> get everything.  Correct?
>

Right, but I changed the logic as discussed in "qapi: add a -u/--unit
option to specify which unit to visit " (this changes a bit the way
inclusion is being done, now target.json is the top-level for the
documentation)

So only -u target will be needed to generate the target specific code
now (while still parsing and checking with the rest of the schemas)

All documentation is generated from target.json. The rest is
unaffected by this new schema (which is a good thing imho).

>>  QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
>> diff --git a/Makefile.target b/Makefile.target
>> index 0d28ed1df0..e44a3847d3 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -157,6 +157,8 @@ endif
>>
>>  GENERATED_FILES += hmp-commands.h hmp-commands-info.h
>>
>> +obj-y += target-qapi-types.o target-qapi-visit.o
>> +obj-y += target-qapi-event.o target-qmp-marshal.o
>>  obj-y += qmp-introspect.o
>>
>>  endif # CONFIG_SOFTMMU
>


thanks

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely
  2018-01-11 21:24         ` Marc-André Lureau
@ 2018-02-02 14:43           ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2018-02-02 14:43 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU, Michael Roth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Fri, Dec 8, 2017 at 8:50 AM, Markus Armbruster <armbru@redhat.com> wrote:
>> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>>
>>> On Thu, Dec 7, 2017 at 5:23 PM, Markus Armbruster <armbru@redhat.com> wrote:
>>>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>>>>
>>>>> The C standard has the initial value at 0 and the subsequent values
>>>>> incremented by 1. No need to set this explicitely.
>>>>>
>>>>> This will prevent from artificial "gaps" when compiling out some enum
>>>>> values and having unnecessarily large MAX values & enums arrays.
>>>>>
>>>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>>> ---
>>>>>  scripts/qapi.py | 7 ++-----
>>>>>  1 file changed, 2 insertions(+), 5 deletions(-)
>>>>>
>>>>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>>>>> index 94b735d8d6..074ee221a1 100644
>>>>> --- a/scripts/qapi.py
>>>>> +++ b/scripts/qapi.py
>>>>> @@ -1985,14 +1985,11 @@ typedef enum %(c_name)s {
>>>>>  ''',
>>>>>                  c_name=c_name(name))
>>>>>
>>>>> -    i = 0
>>>>>      for value in enum_values:
>>>>>          ret += mcgen('''
>>>>> -    %(c_enum)s = %(i)d,
>>>>> +    %(c_enum)s,
>>>>>  ''',
>>>>> -                     c_enum=c_enum_const(name, value, prefix),
>>>>> -                     i=i)
>>>>> -        i += 1
>>>>> +                     c_enum=c_enum_const(name, value, prefix))
>>>>>
>>>>>      ret += mcgen('''
>>>>>  } %(c_name)s;
>>>>
>>>> Recapitulate review of v2: this risks entertaining mishaps like
>>>> compiling this one
>>>>
>>>>     typedef enum Color {
>>>>         COLOR_WHITE,
>>>> #if defined(NEED_CPU_H)
>>>> #if defined(TARGET_S390X)
>>>>         COLOR_BLUE,
>>>> #endif /* defined(TARGET_S390X) */
>>>> #endif /* defined(NEED_CPU_H) */
>>>>         COLOR_BLACK,
>>>>     } Color;
>>>>
>>>> in s390x-code (COLOR_BLACK = 2) and in target-independent code
>>>> (COLOR_BLACK = 1), then linking the two together.
>>>>
>>>> Same issue for struct members and such (previous patch).
>>>>
>>>> What's our story on preventing disaster here?
>>>>
>>>> In the long run, we want to split the generated code so that
>>>> target-specific and target-independent code are separate, and each part
>>>> is always compiled with consistent preprocessor symbols.  But I'm afraid
>>>> that's not in the card right now.
>>>
>>> Eh, I need to refresh my memories about that series, but I think
>>> that's what I did in v3
>>>
>>> It doesn't use the NEED_CPU_H trick. It has a seperate per-target target.json
>>
>> Looking... aha!  target.json appears in PATCH 44 (which I haven't even
>> glanced at, yet).  The problem appears in PATCH 16, though.  Perhaps a
>> bit of patch reshuffling would do.
>
> What problem appears in patch 16? Some code could be introduced using
> NEED_CPU_H and link arch & independent code together?

It's been a while...

Generated headers using conditionals must include the headers providing
the symbols used in conditionals.  Not doing so is an open death trap.

PATCH 16 sets up the first instance of the death trap.  Or maybe it's
PATCH 13.

However, including these headers only becomes possible *after* you split
off the target-specific stuff in PATCH 44.

Do I make any sense?

>                                                       It is still true
> after patch 44. If necessary, I can work on a split-qapi series before
> the conditionals are added. But the real benefit is only apparent
> after the conditional are introduced, so I am not motivated to
> reorder.

Understand.

As a maintainer, I can ask for improvements, but the only lever I have
is saying no.  Which should be reserved for cases that are actually
wrong, or create inacceptable technical debt.  Temporary death traps
don't count as either.  For cases I merely hate, when asking doesn't
help, all I can do is do the work myself.  So I did:

    [PATCH RFC 00/21] Modularize generated QAPI code
    Message-Id: <20180202130336.24719-1-armbru@redhat.com>

[...]

^ permalink raw reply	[flat|nested] 118+ messages in thread

* Re: [Qemu-devel] [PATCH v3 24/50] qapi: add some struct member tests
  2018-01-11 21:31     ` Marc-André Lureau
@ 2018-02-02 14:51       ` Markus Armbruster
  0 siblings, 0 replies; 118+ messages in thread
From: Markus Armbruster @ 2018-02-02 14:51 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU, Michael Roth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Sat, Dec 9, 2017 at 10:07 AM, Markus Armbruster <armbru@redhat.com> wrote:
>> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
[...]
>>> diff --git a/tests/qapi-schema/struct-member-type.json b/tests/qapi-schema/struct-member-type.json
>>> new file mode 100644
>>> index 0000000000..8b33027817
>>> --- /dev/null
>>> +++ b/tests/qapi-schema/struct-member-type.json
>>> @@ -0,0 +1,2 @@
>>> +# check member 'a' with 'type' key only
>>> +{ 'struct': 'foo', 'data': { 'a': { 'type': 'str' } } }
>>> diff --git a/tests/qapi-schema/struct-member-type.out b/tests/qapi-schema/struct-member-type.out
>>> new file mode 100644
>>> index 0000000000..04b969d2e3
>>> --- /dev/null
>>> +++ b/tests/qapi-schema/struct-member-type.out
>>> @@ -0,0 +1,12 @@
>>> +enum QType
>>> +    prefix QTYPE
>>> +    member none:
>>> +    member qnull:
>>> +    member qnum:
>>> +    member qstring:
>>> +    member qdict:
>>> +    member qlist:
>>> +    member qbool:
>>> +object foo
>>> +    member a: str optional=False
>>> +object q_empty
>>
>> This is a positive test, isn't it?  Positive tests go into
>> qapi-schema-test.json.
>>
>
> Right, I wonder why we have .exit files then. Perhaps the few ones
> that return 0 shouldn't exist.

There are a few legitimate positive test cases, such as empty.json and
doc-good.json.

Moreover, we occasionally add negative test cases that fail to fail,
demonstrating a bug.  Example: quoted-structural-chars in commit
98626572f1, fixed in commit c7a3f25200.

^ permalink raw reply	[flat|nested] 118+ messages in thread

end of thread, other threads:[~2018-02-02 14:51 UTC | newest]

Thread overview: 118+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-11 11:05 [Qemu-devel] [PATCH v3 00/50] Hi, Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 01/50] qlit: add qobject_from_qlit() Marc-André Lureau
2017-09-13 13:51   ` Eric Blake
2017-09-13 14:08     ` Marc-André Lureau
2017-12-06 14:37       ` Markus Armbruster
2017-12-06 14:37   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 02/50] qapi: generate a literal qobject for introspection Marc-André Lureau
2017-12-06 15:17   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 03/50] qapi2texi: minor python code simplification Marc-André Lureau
2017-12-06 15:19   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 04/50] qapi: add 'if' to top-level expressions Marc-André Lureau
2017-12-06 15:46   ` Markus Armbruster
2017-12-06 16:23   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 05/50] qapi: add tests for invalid 'if' Marc-André Lureau
2017-12-06 16:34   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 06/50] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
2017-12-06 17:13   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 07/50] qapi: add 'ifcond' to visitor methods Marc-André Lureau
2017-12-06 17:23   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 08/50] qapi: mcgen() shouldn't indent # lines Marc-André Lureau
2017-12-06 17:41   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 09/50] qapi: add #if/#endif helpers Marc-André Lureau
2017-12-07 14:10   ` Markus Armbruster
2018-01-11 21:21     ` Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 10/50] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Marc-André Lureau
2017-12-07 14:47   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 11/50] qapi-introspect: modify to_qlit() to generate #if code Marc-André Lureau
2017-12-07 14:50   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 12/50] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
2017-12-07 15:41   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 13/50] qapi-commands: add #if conditions to commands Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 14/50] qapi-event: add #if conditions to events Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 15/50] qapi-types: refactor variants handling Marc-André Lureau
2017-12-07 15:57   ` Markus Armbruster
2018-01-11 21:22     ` Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 16/50] qapi-types: add #if conditions to types & visitors Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 17/50] qapi: do not define enumeration value explicitely Marc-André Lureau
2017-12-07 16:23   ` Markus Armbruster
2017-12-07 17:01     ` Marc-André Lureau
2017-12-08  7:50       ` Markus Armbruster
2018-01-11 21:24         ` Marc-André Lureau
2018-02-02 14:43           ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 18/50] qapi: change enum visitor to take QAPISchemaMember Marc-André Lureau
2017-12-07 17:34   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 19/50] qapi: add 'if' to enum members Marc-André Lureau
2017-12-08  8:38   ` Markus Armbruster
2018-01-11 21:24     ` Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 20/50] qapi-event: add 'if' condition to generated enum Marc-André Lureau
2017-12-08 13:58   ` Markus Armbruster
2017-12-08 14:07     ` Markus Armbruster
2018-01-11 21:31       ` Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 21/50] qapi: add #if conditions on generated enum members Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 22/50] tests: add some enum members tests Marc-André Lureau
2017-12-08 17:58   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 23/50] qapi: add 'if' to struct members and implicit objects members Marc-André Lureau
2017-12-09  8:18   ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 24/50] qapi: add some struct member tests Marc-André Lureau
2017-12-09  9:07   ` Markus Armbruster
2018-01-11 21:31     ` Marc-André Lureau
2018-02-02 14:51       ` Markus Armbruster
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 25/50] qapi: add #if conditions to generated struct members Marc-André Lureau
2017-09-11 11:05 ` [Qemu-devel] [PATCH v3 26/50] qapi: add 'if' on union variants Marc-André Lureau
2017-12-11 10:36   ` Markus Armbruster
2018-01-11 21:32     ` Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 27/50] qapi: add #if conditions to generated variants Marc-André Lureau
2017-12-13 12:37   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 28/50] qapi: add 'if' to alternate variant Marc-André Lureau
2017-12-12 14:51   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 29/50] qapi: add tests for invalid alternate Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 30/50] qapi: add #if conditions to generated alternate variants Marc-André Lureau
2017-12-12 19:25   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 31/50] docs: document schema configuration Marc-André Lureau
2017-12-13 10:41   ` Markus Armbruster
2017-12-13 19:49     ` Eric Blake
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 32/50] qapi2texi: add 'If:' section to generated documentation Marc-André Lureau
2017-12-13 12:35   ` Markus Armbruster
2017-12-13 19:54     ` Eric Blake
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 33/50] qapi2texi: add 'If:' condition to enum values Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 34/50] qapi2texi: add 'If:' condition to struct members Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 35/50] qapi2texi: add condition to variants Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 36/50] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
2017-12-13 14:12   ` Markus Armbruster
2017-12-13 14:20     ` Daniel P. Berrange
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 37/50] qapi: add conditions to SPICE " Marc-André Lureau
2017-12-13 14:17   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 38/50] qapi: add conditions to REPLICATION type/commands " Marc-André Lureau
2017-12-13 14:19   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 39/50] qapi-commands: don't initialize command list in qmp_init_marshall() Marc-André Lureau
2017-12-13 16:23   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 40/50] qapi: add -i/--include filename.h Marc-André Lureau
2017-12-14 13:50   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 41/50] qapi: add a 'unit' pragma Marc-André Lureau
2017-12-14 13:54   ` Markus Armbruster
2017-12-14 14:00     ` Marc-André Lureau
2017-12-14 14:33       ` Markus Armbruster
2017-12-14 16:08   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 42/50] qapi: add a -u/--unit option to specify which unit to visit Marc-André Lureau
2017-12-14 16:16   ` Markus Armbruster
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 43/50] build-sys: move qmp-introspect per target Marc-André Lureau
2017-12-14 16:30   ` Markus Armbruster
2018-01-11 21:32     ` Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 44/50] build-sys: add a target schema Marc-André Lureau
2017-12-14 16:34   ` Markus Armbruster
2018-01-11 21:32     ` Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 45/50] qapi: make rtc-reset-reinjection depend on TARGET_I386 Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 46/50] qapi: make s390 commands depend on TARGET_S390X Marc-André Lureau
2017-09-13  7:45   ` Cornelia Huck
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 47/50] target.json: add a note about query-cpu* not being s390x-specific Marc-André Lureau
2017-09-13  7:46   ` Cornelia Huck
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 48/50] qapi: make query-gic-capabilities depend on TARGET_ARM Marc-André Lureau
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 49/50] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
2017-09-12 17:40   ` Eduardo Habkost
2017-09-13  7:47   ` Cornelia Huck
2017-09-11 11:06 ` [Qemu-devel] [PATCH v3 50/50] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
2017-09-12 17:45   ` Eduardo Habkost
2017-09-13  7:48   ` Cornelia Huck
2017-09-11 11:54 ` [Qemu-devel] [PATCH v3 00/50] Hi, no-reply
2017-12-18 13:14 ` Markus Armbruster

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.