All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v4 00/51] Hi,
@ 2018-01-11 21:31 Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int Marc-André Lureau
                   ` (50 more replies)
  0 siblings, 51 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, 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 demonstrates adding conditions.

The schema is splitted in common and per-target parts starting from
"build-sys: add a target schema", using a simple expression filtering
mechanism based on a 'unit' name pragma. This allows target schema to
use target-poisoned defines as conditions (such as TARGET_I386).

Ultimately, qmp_unregister_commands() hack is removed.

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,

v4:
- added "qlit: use QType instead of int" patch
- use a "default:" case in qobject_from_qlit()
- added a test for invalid 'if': ['']
- listify ifcond in constructors
- added "qapi: leave the ifcond attribute undefined until check()"
  patch (could be squashed)
- use a negative lookahead in "qapi: mcgen() shouldn't indent # lines"
- fix extra empty line in "qapi-introspect: add preprocessor
  conditions to generated QLit"
- added desugar/normalization passes, such as NAME -> { 'name': NAME }
- splitted "qapi: change enum visitor to take QAPISchemaMember"
- prettify test-qapi.py members output
- added missing #if wrapping for enum members in generated introspection
- clarified some error messages
- added "qapi: rename allow_dict to allow_implicit" patch for clarity
- added a seperate patch for "qapi: add a dictionnary form" for enum
  names
- added a seperate patch for "qapi: add a dictionnary form" for struct
  members
- squashed the patches adding #if to generated code (some types
  generate both enum and struct members for example, so a step-by-step
  is unnecessarily complicated to deal with)
- squashed some tests with related patch
- added "qapi: add an error in case a discriminator is conditionnal"
- add back VNC-specific crypto 'des-rfb' when VNC is disabled
- change the way unit filtering is done (so no -u means no filtering)
- made target.json the top-level documentation schema
- removed some blank lines in generated code output
- improve documentation, add various tests
- commit message improvements
- misc pycodestyle/pep8 fixes
- add r-b tags

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 (51):
  qlit: use QType instead of int
  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: pass 'if' condition into QAPISchemaEntity objects
  qapi: leave the ifcond attribute undefined until check()
  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: 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: rename QAPISchemaEnumType.values to .members
  qapi: change enum visitor to take QAPISchemaMember
  tests: modify visit_enum_type() in test-qapi to print members
  qapi: factor out check_known_keys()
  qapi: add a dictionnary form with 'name' key for enum members
  qapi: add 'if' to enum members
  qapi-event: add 'if' condition to implicit event enum
  qapi: rename allow_dict to allow_implicit
  qapi: add a dictionary form with 'type' key for members
  qapi: add 'if' to implicit struct members
  qapi: add an error in case a discriminator is conditionnal
  qapi: add 'if' on union members
  qapi: add 'if' to alternate members
  qapi: add #if conditions to generated code
  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
  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: remove qmp_unregister_command()

 qapi-schema.json                                   | 210 ---------
 qapi/block-core.json                               |  15 +-
 qapi/char.json                                     |  10 +-
 qapi/migration.json                                |  12 +-
 qapi/target.json                                   | 230 ++++++++++
 qapi/ui.json                                       |  75 ++--
 scripts/qapi.py                                    | 494 +++++++++++++++------
 scripts/qapi-commands.py                           |  13 +-
 scripts/qapi-event.py                              |  12 +-
 scripts/qapi-introspect.py                         | 126 ++++--
 scripts/qapi-types.py                              |  72 ++-
 scripts/qapi-visit.py                              |  27 +-
 scripts/qapi2texi.py                               |  52 ++-
 include/qapi/qmp/dispatch.h                        |   1 -
 include/qapi/qmp/qlit.h                            |   4 +-
 include/sysemu/arch_init.h                         |  11 -
 ui/vnc.h                                           |   2 +
 hmp.c                                              |   9 +-
 hw/s390x/s390-skeys.c                              |   2 +-
 hw/timer/mc146818rtc.c                             |   2 +-
 migration/colo.c                                   |  16 +-
 monitor.c                                          |  73 +--
 qapi/qmp-registry.c                                |   8 -
 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-qmp-commands.c                          |   7 +
 tests/test-qobject-input-visitor.c                 |  10 +-
 Makefile                                           |  45 +-
 Makefile.objs                                      |   3 +-
 Makefile.target                                    |   4 +
 docs/devel/qapi-code-gen.txt                       |  71 ++-
 hmp-commands-info.hx                               |   2 +
 stubs/Makefile.objs                                |   4 -
 tests/Makefile.include                             |  23 +-
 tests/qapi-schema/alternate-base.err               |   2 +-
 tests/qapi-schema/alternate-invalid-dict.err       |   1 +
 ...ict-member.exit => alternate-invalid-dict.exit} |   0
 tests/qapi-schema/alternate-invalid-dict.json      |   4 +
 ...-dict-member.out => alternate-invalid-dict.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-list.err                  |   1 +
 tests/qapi-schema/bad-if-list.exit                 |   1 +
 tests/qapi-schema/bad-if-list.json                 |   3 +
 tests/qapi-schema/bad-if-list.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-bad-section.out              |  13 +-
 tests/qapi-schema/doc-good.json                    |  11 +-
 tests/qapi-schema/doc-good.out                     |  23 +-
 tests/qapi-schema/doc-good.texi                    |  10 +-
 tests/qapi-schema/double-type.err                  |   2 +-
 tests/qapi-schema/empty.out                        |   9 +-
 tests/qapi-schema/enum-bad-member.err              |   1 +
 tests/qapi-schema/enum-bad-member.exit             |   1 +
 tests/qapi-schema/enum-bad-member.json             |   2 +
 tests/qapi-schema/enum-bad-member.out              |   0
 tests/qapi-schema/enum-dict-member-unknown.err     |   1 +
 tests/qapi-schema/enum-dict-member-unknown.exit    |   1 +
 tests/qapi-schema/enum-dict-member-unknown.json    |   2 +
 tests/qapi-schema/enum-dict-member-unknown.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/enum-missing-data.err            |   2 +-
 tests/qapi-schema/event-case.out                   |   9 +-
 tests/qapi-schema/event-nest-struct.err            |   2 +-
 tests/qapi-schema/flat-union-inline.err            |   2 +-
 .../flat-union-invalid-if-discriminator.err        |   1 +
 .../flat-union-invalid-if-discriminator.exit       |   1 +
 .../flat-union-invalid-if-discriminator.json       |  17 +
 .../flat-union-invalid-if-discriminator.out        |   0
 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/nested-struct-data.err           |   2 +-
 tests/qapi-schema/pragma-unit-invalid.err          |   1 +
 tests/qapi-schema/pragma-unit-invalid.exit         |   1 +
 tests/qapi-schema/pragma-unit-invalid.json         |   3 +
 tests/qapi-schema/pragma-unit-invalid.out          |   0
 tests/qapi-schema/qapi-schema-test.json            |  52 ++-
 tests/qapi-schema/qapi-schema-test.out             | 102 ++++-
 tests/qapi-schema/struct-member-invalid-dict.err   |   1 +
 tests/qapi-schema/struct-member-invalid-dict.exit  |   1 +
 tests/qapi-schema/struct-member-invalid-dict.json  |   3 +
 tests/qapi-schema/struct-member-invalid-dict.out   |   0
 tests/qapi-schema/test-qapi.py                     |  38 +-
 tests/qapi-schema/union-branch-invalid-dict.err    |   1 +
 tests/qapi-schema/union-branch-invalid-dict.exit   |   1 +
 tests/qapi-schema/union-branch-invalid-dict.json   |   4 +
 tests/qapi-schema/union-branch-invalid-dict.out    |   0
 tests/qapi-schema/unknown-expr-key.err             |   2 +-
 tests/qapi-schema/unknown-expr-key.json            |   2 +-
 118 files changed, 1473 insertions(+), 808 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-invalid-dict.err
 rename tests/qapi-schema/{enum-dict-member.exit => alternate-invalid-dict.exit} (100%)
 create mode 100644 tests/qapi-schema/alternate-invalid-dict.json
 rename tests/qapi-schema/{enum-dict-member.out => alternate-invalid-dict.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-list.err
 create mode 100644 tests/qapi-schema/bad-if-list.exit
 create mode 100644 tests/qapi-schema/bad-if-list.json
 create mode 100644 tests/qapi-schema/bad-if-list.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-bad-member.err
 create mode 100644 tests/qapi-schema/enum-bad-member.exit
 create mode 100644 tests/qapi-schema/enum-bad-member.json
 create mode 100644 tests/qapi-schema/enum-bad-member.out
 create mode 100644 tests/qapi-schema/enum-dict-member-unknown.err
 create mode 100644 tests/qapi-schema/enum-dict-member-unknown.exit
 create mode 100644 tests/qapi-schema/enum-dict-member-unknown.json
 create mode 100644 tests/qapi-schema/enum-dict-member-unknown.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/flat-union-invalid-if-discriminator.err
 create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.exit
 create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.json
 create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.out
 create mode 100644 tests/qapi-schema/pragma-unit-invalid.err
 create mode 100644 tests/qapi-schema/pragma-unit-invalid.exit
 create mode 100644 tests/qapi-schema/pragma-unit-invalid.json
 create mode 100644 tests/qapi-schema/pragma-unit-invalid.out
 create mode 100644 tests/qapi-schema/struct-member-invalid-dict.err
 create mode 100644 tests/qapi-schema/struct-member-invalid-dict.exit
 create mode 100644 tests/qapi-schema/struct-member-invalid-dict.json
 create mode 100644 tests/qapi-schema/struct-member-invalid-dict.out
 create mode 100644 tests/qapi-schema/union-branch-invalid-dict.err
 create mode 100644 tests/qapi-schema/union-branch-invalid-dict.exit
 create mode 100644 tests/qapi-schema/union-branch-invalid-dict.json
 create mode 100644 tests/qapi-schema/union-branch-invalid-dict.out

-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 22:52   ` Eric Blake
  2018-02-05  6:05   ` Markus Armbruster
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 02/51] qlit: add qobject_from_qlit() Marc-André Lureau
                   ` (49 subsequent siblings)
  50 siblings, 2 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/qlit.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/qapi/qmp/qlit.h b/include/qapi/qmp/qlit.h
index b18406bce9..0c6809ef3c 100644
--- a/include/qapi/qmp/qlit.h
+++ b/include/qapi/qmp/qlit.h
@@ -21,7 +21,7 @@ typedef struct QLitDictEntry QLitDictEntry;
 typedef struct QLitObject QLitObject;
 
 struct QLitObject {
-    int type;
+    QType type;
     union {
         bool qbool;
         int64_t qnum;
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 02/51] qlit: add qobject_from_qlit()
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 03/51] qapi: generate a literal qobject for introspection Marc-André Lureau
                   ` (48 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Instantiate a QObject* from a literal QLitObject.

LitObject only supports int64_t for now.  uint64_t and double aren't
implemented.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@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 0c6809ef3c..46cefa464e 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..be0e14f778 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));
+    default:
+        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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 03/51] qapi: generate a literal qobject for introspection
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 02/51] qlit: add qobject_from_qlit() Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-02-06 10:04   ` Markus Armbruster
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 04/51] qapi2texi: minor python code simplification Marc-André Lureau
                   ` (47 subsequent siblings)
  50 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Dr. David Alan Gilbert, Eduardo Habkost, Cleber Rosa

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>
---
 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 d682eee2d8..b8931364f2 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 06ab699066..f58d62686a 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 04/51] qapi2texi: minor python code simplification
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (2 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 03/51] qapi: generate a literal qobject for introspection Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions Marc-André Lureau
                   ` (46 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 92e2af2cd6..0a08fbaf7b 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -134,10 +134,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (3 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 04/51] qapi2texi: minor python code simplification Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-02-05  6:12   ` Markus Armbruster
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
                   ` (45 subsequent siblings)
  50 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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>
---
 scripts/qapi.py                          | 36 ++++++++++++++++++++++++++------
 tests/test-qmp-commands.c                |  6 ++++++
 tests/Makefile.include                   |  4 ++++
 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-list.err        |  1 +
 tests/qapi-schema/bad-if-list.exit       |  1 +
 tests/qapi-schema/bad-if-list.json       |  3 +++
 tests/qapi-schema/bad-if-list.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/qapi-schema-test.json  | 20 ++++++++++++++++++
 tests/qapi-schema/qapi-schema-test.out   | 22 +++++++++++++++++++
 21 files changed, 102 insertions(+), 6 deletions(-)
 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-list.err
 create mode 100644 tests/qapi-schema/bad-if-list.exit
 create mode 100644 tests/qapi-schema/bad-if-list.json
 create mode 100644 tests/qapi-schema/bad-if-list.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/scripts/qapi.py b/scripts/qapi.py
index 43a54bf40f..27df0fcf48 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -630,6 +630,27 @@ def add_name(name, info, meta, implicit=False):
     all_names[name] = meta
 
 
+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.get('if')
+    if ifcond is None:
+        return
+    elif 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)
+
+
 def check_type(info, source, value, allow_array=False,
                allow_dict=False, allow_optional=False,
                allow_metas=[]):
@@ -869,6 +890,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'"
@@ -894,27 +917,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/Makefile.include b/tests/Makefile.include
index 39a4b5359d..501a5713b5 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -410,6 +410,10 @@ 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-if-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-list.err b/tests/qapi-schema/bad-if-list.err
new file mode 100644
index 0000000000..0af6316f78
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.err
@@ -0,0 +1 @@
+tests/qapi-schema/bad-if-list.json:2: 'if' condition '' makes no sense
diff --git a/tests/qapi-schema/bad-if-list.exit b/tests/qapi-schema/bad-if-list.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/bad-if-list.json b/tests/qapi-schema/bad-if-list.json
new file mode 100644
index 0000000000..49ced9b9ca
--- /dev/null
+++ b/tests/qapi-schema/bad-if-list.json
@@ -0,0 +1,3 @@
+# check invalid 'if' content
+{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+  'if': ['foo', ''] }
diff --git a/tests/qapi-schema/bad-if-list.out b/tests/qapi-schema/bad-if-list.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
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index c72dbd8050..b997b2d43d 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (4 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-02-05  6:16   ` Markus Armbruster
  2018-02-06 10:12   ` Markus Armbruster
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check() Marc-André Lureau
                   ` (44 subsequent siblings)
  50 siblings, 2 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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 wrapped type's 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>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 98 ++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 66 insertions(+), 32 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 27df0fcf48..8f54dead8d 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -991,8 +991,17 @@ def check_exprs(exprs):
 # Schema compiler frontend
 #
 
+def listify_cond(ifcond):
+    if not ifcond:
+        return []
+    elif not isinstance(ifcond, list):
+        return [ifcond]
+    else:
+        return ifcond
+
+
 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)
@@ -1002,6 +1011,7 @@ class QAPISchemaEntity(object):
         # such place).
         self.info = info
         self.doc = doc
+        self.ifcond = listify_cond(ifcond)
 
     def c_name(self):
         return c_name(self.name)
@@ -1118,8 +1128,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)
@@ -1154,7 +1164,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
@@ -1162,6 +1172,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
@@ -1183,11 +1194,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)
@@ -1375,8 +1387,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)
@@ -1412,9 +1424,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
@@ -1451,8 +1463,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
@@ -1536,22 +1548,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):
@@ -1560,22 +1572,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
@@ -1595,7 +1622,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))
 
@@ -1607,18 +1635,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()]
@@ -1626,12 +1657,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)))
@@ -1639,11 +1670,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)))
@@ -1655,23 +1687,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check()
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (5 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-02-05  6:22   ` Markus Armbruster
  2018-02-06 11:20   ` Markus Armbruster
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 08/51] qapi: add 'ifcond' to visitor methods Marc-André Lureau
                   ` (43 subsequent siblings)
  50 siblings, 2 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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.

Leave the ifcond attribute undefined until check().

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

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8f54dead8d..4d2c214f19 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1011,13 +1011,19 @@ class QAPISchemaEntity(object):
         # such place).
         self.info = info
         self.doc = doc
-        self.ifcond = listify_cond(ifcond)
+        self._ifcond = ifcond  # self.ifcond is set after check()
 
     def c_name(self):
         return c_name(self.name)
 
     def check(self, schema):
-        pass
+        if isinstance(self._ifcond, QAPISchemaType):
+            # inherit the condition from a type
+            typ = self._ifcond
+            typ.check(schema)
+            self.ifcond = typ.ifcond
+        else:
+            self.ifcond = listify_cond(self._ifcond)
 
     def is_implicit(self):
         return not self.info
@@ -1138,6 +1144,7 @@ class QAPISchemaEnumType(QAPISchemaType):
         self.prefix = prefix
 
     def check(self, schema):
+        QAPISchemaType.check(self, schema)
         seen = {}
         for v in self.values:
             v.check_clash(self.info, seen)
@@ -1170,8 +1177,10 @@ class QAPISchemaArrayType(QAPISchemaType):
         self.element_type = None
 
     def check(self, schema):
+        QAPISchemaType.check(self, schema)
         self.element_type = schema.lookup_type(self._element_type_name)
         assert self.element_type
+        self.element_type.check(schema)
         self.ifcond = self.element_type.ifcond
 
     def is_implicit(self):
@@ -1214,6 +1223,7 @@ class QAPISchemaObjectType(QAPISchemaType):
         self.members = None
 
     def check(self, schema):
+        QAPISchemaType.check(self, schema)
         if self.members is False:               # check for cycles
             raise QAPISemError(self.info,
                                "Object %s contains itself" % self.name)
@@ -1396,6 +1406,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
         self.variants = variants
 
     def check(self, schema):
+        QAPISchemaType.check(self, schema)
         self.variants.tag_member.check(schema)
         # Not calling self.variants.check_clash(), because there's nothing
         # to clash with
@@ -1438,6 +1449,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
         self.boxed = boxed
 
     def check(self, schema):
+        QAPISchemaEntity.check(self, schema)
         if self._arg_type_name:
             self.arg_type = schema.lookup_type(self._arg_type_name)
             assert (isinstance(self.arg_type, QAPISchemaObjectType) or
@@ -1471,6 +1483,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
         self.boxed = boxed
 
     def check(self, schema):
+        QAPISchemaEntity.check(self, schema)
         if self._arg_type_name:
             self.arg_type = schema.lookup_type(self._arg_type_name)
             assert (isinstance(self.arg_type, QAPISchemaObjectType) or
@@ -1589,7 +1602,7 @@ class QAPISchema(object):
             # 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
+            assert ifcond == typ._ifcond
         else:
             self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
                                                   None, members, None))
@@ -1635,7 +1648,7 @@ class QAPISchema(object):
             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,
+            typ, info, None, self.lookup_type(typ),
             'wrapper', [self._make_member('data', typ, info)])
         return QAPISchemaObjectTypeVariant(case, typ)
 
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 08/51] qapi: add 'ifcond' to visitor methods
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (6 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check() Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 09/51] qapi: mcgen() shouldn't indent # lines Marc-André Lureau
                   ` (42 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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>
---
 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 4d2c214f19..ffb4fb58e0 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1046,26 +1046,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
 
 
@@ -1165,7 +1165,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)
 
 
@@ -1199,7 +1199,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):
@@ -1281,9 +1282,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)
 
 
@@ -1428,7 +1429,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
@@ -1469,7 +1471,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)
 
@@ -1500,7 +1502,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 0a08fbaf7b..f24fb89bd5 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -203,14 +203,14 @@ 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
         self.out += TYPE_FMT(type='Enum',
                              name=doc.symbol,
                              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
@@ -218,13 +218,13 @@ 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
         self.out += TYPE_FMT(type='Alternate',
                              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 boxed:
@@ -238,7 +238,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
         self.out += MSG_FMT(type='Event',
                             name=doc.symbol,
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 7fbaea19bc..0804c3af84 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 fe0ca08d78..a4b3a00bbd 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, indent=4):
+        if ifcond:
+            print '%sif %s' % (' ' * indent, ifcond)
+
+
 schema = QAPISchema(sys.argv[1])
 schema.visit(QAPISchemaTestVisitor())
 
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 09/51] qapi: mcgen() shouldn't indent # lines
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (7 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 08/51] qapi: add 'ifcond' to visitor methods Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 10/51] qapi: add #if/#endif helpers Marc-André Lureau
                   ` (41 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index ffb4fb58e0..3d33ed7d76 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1876,8 +1876,8 @@ 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),
-                      indent + r'\g<0>', raw)
+        raw = re.subn(re.compile(r'^(?!(#|$))', re.MULTILINE),
+                      indent, raw)
         raw = raw[0]
     return re.sub(re.escape(eatspace) + r' *', '', raw)
 
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 10/51] qapi: add #if/#endif helpers
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (8 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 09/51] qapi: mcgen() shouldn't indent # lines Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-02-05  7:03   ` Markus Armbruster
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 11/51] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Marc-André Lureau
                   ` (40 subsequent siblings)
  50 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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 | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 3d33ed7d76..71f28fc6d8 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1911,6 +1911,53 @@ def guardend(name):
                  name=guardname(name))
 
 
+def gen_if(ifcond):
+    ret = ''
+    for ifc in ifcond:
+        ret += mcgen('''
+#if %(cond)s
+''', cond=ifc)
+    return ret
+
+
+def gen_endif(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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 11/51] qapi-introspect: modify to_qlit() to append ', ' on level > 0
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (9 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 10/51] qapi: add #if/#endif helpers Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 12/51] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
                   ` (39 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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>
Reviewed-by: Markus Armbruster <armbru@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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 12/51] qapi-introspect: add preprocessor conditions to generated QLit
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (10 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 11/51] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-12 10:27   ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 13/51] qapi-commands: add #if conditions to commands Marc-André Lureau
                   ` (38 subsequent siblings)
  50 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, Michael Roth

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

This commit adds 'ifcond' condition to top-level QLit objects.

See generated tests/test-qmp-introspect.c. Example diff after this patch:

--- before	2018-01-08 11:55:24.757083654 +0100
+++ tests/test-qmp-introspect.c	2018-01-08 13:08:44.477641629 +0100
@@ -51,6 +51,8 @@
         { "name", QLIT_QSTR("EVENT_F"), },
         {}
     })),
+#if defined(TEST_IF_CMD)
+#if defined(TEST_IF_STRUCT)
     QLIT_QDICT(((QLitDictEntry[]) {
         { "arg-type", QLIT_QSTR("5"), },
         { "meta-type", QLIT_QSTR("command"), },
@@ -58,12 +60,16 @@
         { "ret-type", QLIT_QSTR("0"), },
         {}
     })),
+#endif /* defined(TEST_IF_STRUCT) */
+#endif /* defined(TEST_IF_CMD) */

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

diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index b1d08ec97b..7d3a5c37fd 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -17,6 +17,15 @@ 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)
+        endif = gen_endif(ifcond)
+        if endif:
+            ret += '\n' + endif
+        return ret
+
     ret = ''
     if not suppress_first_indent:
         ret += indent(level)
@@ -25,7 +34,7 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
     elif isinstance(obj, str):
         ret += 'QLIT_QSTR(' + to_c_string(obj) + ')'
     elif isinstance(obj, list):
-        elts = [to_qlit(elt, level + 1)
+        elts = [to_qlit(elt, level + 1).strip('\n')
                 for elt in obj]
         elts.append(indent(level + 1) + "{}")
         ret += 'QLIT_QLIST(((QLitObject[]) {\n'
@@ -121,12 +130,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)}
@@ -142,26 +151,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}, [])
 
     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):
@@ -169,11 +179,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 13/51] qapi-commands: add #if conditions to commands
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (11 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 12/51] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 14/51] qapi-event: add #if conditions to events Marc-André Lureau
                   ` (37 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 14/51] qapi-event: add #if conditions to events
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (12 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 13/51] qapi-commands: add #if conditions to commands Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 15/51] qapi-types: refactor variants handling Marc-André Lureau
                   ` (36 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 15/51] qapi-types: refactor variants handling
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (13 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 14/51] qapi-event: add #if conditions to events Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 16/51] qapi-types: add #if conditions to types & visitors Marc-André Lureau
                   ` (35 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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

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

self._gen_type_cleanup(name) is factored out in _gen_object(), helping
generated code to be wrapped by the same condition 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 16/51] qapi-types: add #if conditions to types & visitors
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (14 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 15/51] qapi-types: refactor variants handling Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 17/51] qapi: do not define enumeration value explicitely Marc-André Lureau
                   ` (34 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 17/51] qapi: do not define enumeration value explicitely
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (15 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 16/51] qapi-types: add #if conditions to types & visitors Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 18/51] qapi: rename QAPISchemaEnumType.values to .members Marc-André Lureau
                   ` (33 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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 71f28fc6d8..ee759489cb 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1991,14 +1991,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 18/51] qapi: rename QAPISchemaEnumType.values to .members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (16 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 17/51] qapi: do not define enumeration value explicitely Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 19/51] qapi: change enum visitor to take QAPISchemaMember Marc-André Lureau
                   ` (32 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                | 36 ++++++++++++++++++------------------
 scripts/qapi-introspect.py     |  4 ++--
 scripts/qapi-types.py          | 10 +++++-----
 scripts/qapi-visit.py          |  2 +-
 scripts/qapi2texi.py           |  2 +-
 tests/qapi-schema/test-qapi.py |  4 ++--
 6 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index ee759489cb..c7cd98a890 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1046,7 +1046,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):
@@ -1134,22 +1134,22 @@ 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):
         QAPISchemaType.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()
@@ -1159,7 +1159,7 @@ 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'
@@ -1958,19 +1958,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, prefix)
         ret += mcgen('''
         [%(index)s] = "%(value)s",
 ''',
-                     index=index, value=value)
+                     index=index, value=m)
 
     ret += mcgen('''
     },
@@ -1981,9 +1981,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 + ['_MAX']
 
     ret = mcgen('''
 
@@ -1991,11 +1991,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, prefix))
 
     ret += mcgen('''
 } %(c_name)s;
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 7d3a5c37fd..9fcb342c91 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -153,8 +153,8 @@ 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, 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': 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 f24fb89bd5..755bd2f15d 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -203,7 +203,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
         self.out += TYPE_FMT(type='Enum',
                              name=doc.symbol,
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index a4b3a00bbd..1c4f9e0dac 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -17,8 +17,8 @@ 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 %s' % (name, members)
         if prefix:
             print '    prefix %s' % prefix
         self._print_if(ifcond)
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 19/51] qapi: change enum visitor to take QAPISchemaMember
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (17 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 18/51] qapi: rename QAPISchemaEnumType.values to .members Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 20/51] tests: modify visit_enum_type() in test-qapi to print members Marc-André Lureau
                   ` (31 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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                | 12 ++++++------
 scripts/qapi-event.py          |  2 +-
 scripts/qapi-introspect.py     |  3 ++-
 tests/qapi-schema/test-qapi.py |  2 +-
 4 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index c7cd98a890..f8c711b81b 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1166,7 +1166,7 @@ class QAPISchemaEnumType(QAPISchemaType):
 
     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):
@@ -1966,11 +1966,11 @@ const QEnumLookup %(c_name)s_lookup = {
 ''',
                 c_name=c_name(name))
     for m in members:
-        index = c_enum_const(name, m, prefix)
+        index = c_enum_const(name, m.name, prefix)
         ret += mcgen('''
-        [%(index)s] = "%(value)s",
+        [%(index)s] = "%(name)s",
 ''',
-                     index=index, value=m)
+                     index=index, name=m.name)
 
     ret += mcgen('''
     },
@@ -1983,7 +1983,7 @@ const QEnumLookup %(c_name)s_lookup = {
 
 def gen_enum(name, members, prefix=None):
     # append automatically generated _MAX value
-    enum_members = members + ['_MAX']
+    enum_members = members + [QAPISchemaMember('_MAX')]
 
     ret = mcgen('''
 
@@ -1995,7 +1995,7 @@ typedef enum %(c_name)s {
         ret += mcgen('''
     %(c_enum)s,
 ''',
-                     c_enum=c_enum_const(name, m, 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 9fcb342c91..868d12f504 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -154,7 +154,8 @@ const QLitObject %(c_name)s = %(c_string)s;
         self._gen_qlit(name, 'builtin', {'json-type': json_type}, [])
 
     def visit_enum_type(self, name, info, ifcond, members, prefix):
-        self._gen_qlit(name, 'enum', {'values': members}, ifcond)
+        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/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 1c4f9e0dac..2ab79230c2 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -18,7 +18,7 @@ import sys
 
 class QAPISchemaTestVisitor(QAPISchemaVisitor):
     def visit_enum_type(self, name, info, ifcond, members, prefix):
-        print 'enum %s %s' % (name, members)
+        print 'enum %s %s' % (name, [m.name for m in members])
         if prefix:
             print '    prefix %s' % prefix
         self._print_if(ifcond)
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 20/51] tests: modify visit_enum_type() in test-qapi to print members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (18 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 19/51] qapi: change enum visitor to take QAPISchemaMember Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 21/51] qapi: factor out check_known_keys() Marc-André Lureau
                   ` (30 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau, Michael Roth

Use a common self._print_members() to print enum members details.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/qapi-schema/comments.out           | 14 +++++++--
 tests/qapi-schema/doc-bad-section.out    | 13 +++++++--
 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           | 15 +++++++---
 12 files changed, 156 insertions(+), 30 deletions(-)

diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 17e652535c..7c243b246b 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-bad-section.out b/tests/qapi-schema/doc-bad-section.out
index 089bde1381..77e223ba41 100644
--- a/tests/qapi-schema/doc-bad-section.out
+++ b/tests/qapi-schema/doc-bad-section.out
@@ -1,6 +1,15 @@
-enum Enum ['one', 'two']
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum Enum
+    member one
+    member two
+enum QType
     prefix QTYPE
+    member none
+    member qnull
+    member qnum
+    member qstring
+    member qdict
+    member qlist
+    member qbool
 object q_empty
 doc symbol=Enum
     body=
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 1d2c250527..e615b04281 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..0bd6d1421d 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..fc64383edb 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..6458ffb28c 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..7c243b246b 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..7c243b246b 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..7c243b246b 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..7b066235fa 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 0804c3af84..33afa965e8 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 2ab79230c2..aadc8452b4 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -18,18 +18,17 @@ import sys
 
 class QAPISchemaTestVisitor(QAPISchemaVisitor):
     def visit_enum_type(self, name, info, ifcond, members, prefix):
-        print 'enum %s %s' % (name, [m.name for m in members])
+        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%s' % (
+                m.name,
+                ': %s optional=%s' % (m.type.name, m.optional)
+                if isinstance(m, QAPISchemaObjectTypeMember) else '')
+
     @staticmethod
     def _print_variants(variants):
         if variants:
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 21/51] qapi: factor out check_known_keys()
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (19 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 20/51] tests: modify visit_enum_type() in test-qapi to print members Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 22/51] qapi: add a dictionnary form with 'name' key for enum members Marc-André Lureau
                   ` (29 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, Michael Roth

The following patches are going to need similar checks from various
code path. This refactoring will report all conflicting keys (instead
of the first one encountered).

Modify unknown-expr-key to check plural form.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                         | 27 ++++++++++++++++++++-------
 tests/qapi-schema/alternate-base.err    |  2 +-
 tests/qapi-schema/double-type.err       |  2 +-
 tests/qapi-schema/enum-missing-data.err |  2 +-
 tests/qapi-schema/unknown-expr-key.err  |  2 +-
 tests/qapi-schema/unknown-expr-key.json |  2 +-
 6 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index f8c711b81b..a9dcfc064c 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -871,6 +871,24 @@ def check_struct(expr, info):
                allow_metas=['struct'])
 
 
+def check_known_keys(info, source, keys, required, optional):
+
+    def pprint(elems):
+        return ', '.join("'" + e + "'" for e in elems)
+
+    missing = set(required) - set(keys)
+    if missing:
+        raise QAPISemError(info, "%s must have %s key%s"
+                           % (source, pprint(missing),
+                              's' if len(missing) > 1 else ''))
+    allowed = set(required + optional)
+    unknown = set(keys) - allowed
+    if unknown:
+        raise QAPISemError(info, "%s has unknown key%s %s (allowed: %s)"
+                           % (source, 's' if len(unknown) > 1 else '',
+                              pprint(unknown), pprint(allowed)))
+
+
 def check_keys(expr_elem, meta, required, optional=[]):
     expr = expr_elem['expr']
     info = expr_elem['info']
@@ -878,10 +896,9 @@ def check_keys(expr_elem, meta, required, optional=[]):
     if not isinstance(name, str):
         raise QAPISemError(info, "'%s' key must have a string value" % meta)
     required = required + [meta]
+    source = "%s '%s'" % (meta, name)
+    check_known_keys(info, source, expr, required, optional)
     for (key, value) in expr.items():
-        if key not in required and key not in optional:
-            raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
-                               % (key, meta, name))
         if (key == 'gen' or key == 'success-response') and value is not False:
             raise QAPISemError(info,
                                "'%s' of %s '%s' should only use false value"
@@ -892,10 +909,6 @@ def check_keys(expr_elem, meta, required, optional=[]):
                                % (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'"
-                               % (key, meta, name))
 
 
 def check_exprs(exprs):
diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alternate-base.err
index 30d8a34373..2b09c4c7a3 100644
--- a/tests/qapi-schema/alternate-base.err
+++ b/tests/qapi-schema/alternate-base.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt'
+tests/qapi-schema/alternate-base.json:4: alternate 'Alt' has unknown key 'base' (allowed: 'alternate', 'data', 'if')
diff --git a/tests/qapi-schema/double-type.err b/tests/qapi-schema/double-type.err
index f9613c6d6b..968fac6b66 100644
--- a/tests/qapi-schema/double-type.err
+++ b/tests/qapi-schema/double-type.err
@@ -1 +1 @@
-tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar'
+tests/qapi-schema/double-type.json:2: struct 'bar' has unknown key 'command' (allowed: 'base', 'data', 'struct', 'if')
diff --git a/tests/qapi-schema/enum-missing-data.err b/tests/qapi-schema/enum-missing-data.err
index ba4873ae69..68e286badc 100644
--- a/tests/qapi-schema/enum-missing-data.err
+++ b/tests/qapi-schema/enum-missing-data.err
@@ -1 +1 @@
-tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from enum 'MyEnum'
+tests/qapi-schema/enum-missing-data.json:2: enum 'MyEnum' must have 'data' key
diff --git a/tests/qapi-schema/unknown-expr-key.err b/tests/qapi-schema/unknown-expr-key.err
index 12f5ed5b43..6a28af8ffc 100644
--- a/tests/qapi-schema/unknown-expr-key.err
+++ b/tests/qapi-schema/unknown-expr-key.err
@@ -1 +1 @@
-tests/qapi-schema/unknown-expr-key.json:2: Unknown key 'bogus' in struct 'bar'
+tests/qapi-schema/unknown-expr-key.json:2: struct 'bar' has unknown keys 'foo', 'bogus' (allowed: 'base', 'data', 'struct', 'if')
diff --git a/tests/qapi-schema/unknown-expr-key.json b/tests/qapi-schema/unknown-expr-key.json
index 3b2be00cc4..5bcb8efd1d 100644
--- a/tests/qapi-schema/unknown-expr-key.json
+++ b/tests/qapi-schema/unknown-expr-key.json
@@ -1,2 +1,2 @@
 # we reject an expression with unknown top-level keys
-{ 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { } }
+{ 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { }, 'foo': { } }
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 22/51] qapi: add a dictionnary form with 'name' key for enum members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (20 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 21/51] qapi: factor out check_known_keys() Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 23/51] qapi: add 'if' to " Marc-André Lureau
                   ` (28 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, Michael Roth

Desugar the enum NAME form to { 'name': NAME }. This will allow to add
new enum members, such as 'if' in the following patch.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                                    | 49 ++++++++++++++++++----
 tests/Makefile.include                             |  3 +-
 tests/qapi-schema/enum-bad-member.err              |  1 +
 ...{enum-dict-member.exit => enum-bad-member.exit} |  0
 tests/qapi-schema/enum-bad-member.json             |  2 +
 .../{enum-dict-member.out => enum-bad-member.out}  |  0
 tests/qapi-schema/enum-dict-member-unknown.err     |  1 +
 tests/qapi-schema/enum-dict-member-unknown.exit    |  1 +
 tests/qapi-schema/enum-dict-member-unknown.json    |  2 +
 tests/qapi-schema/enum-dict-member-unknown.out     |  0
 tests/qapi-schema/enum-dict-member.err             |  1 -
 tests/qapi-schema/enum-dict-member.json            |  2 -
 tests/qapi-schema/enum-missing-data.err            |  2 +-
 13 files changed, 51 insertions(+), 13 deletions(-)
 create mode 100644 tests/qapi-schema/enum-bad-member.err
 rename tests/qapi-schema/{enum-dict-member.exit => enum-bad-member.exit} (100%)
 create mode 100644 tests/qapi-schema/enum-bad-member.json
 rename tests/qapi-schema/{enum-dict-member.out => enum-bad-member.out} (100%)
 create mode 100644 tests/qapi-schema/enum-dict-member-unknown.err
 create mode 100644 tests/qapi-schema/enum-dict-member-unknown.exit
 create mode 100644 tests/qapi-schema/enum-dict-member-unknown.json
 create mode 100644 tests/qapi-schema/enum-dict-member-unknown.out
 delete mode 100644 tests/qapi-schema/enum-dict-member.err
 delete mode 100644 tests/qapi-schema/enum-dict-member.json

diff --git a/scripts/qapi.py b/scripts/qapi.py
index a9dcfc064c..1338be4efe 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -731,6 +731,10 @@ def check_event(expr, info):
                allow_metas=meta)
 
 
+def enum_get_names(expr):
+    return [e['name'] for e in expr['data']]
+
+
 def check_union(expr, info):
     name = expr['union']
     base = expr.get('base')
@@ -790,7 +794,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_names(enum_define):
                 raise QAPISemError(info,
                                    "Discriminator value '%s' is not found in "
                                    "enum '%s'"
@@ -798,7 +802,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_names(enum_define):
             if value not in members.keys():
                 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
                                    % (name, value))
@@ -829,10 +833,10 @@ 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_names(enum_expr):
                     if v in ['on', 'off']:
                         conflicting.add('QTYPE_QBOOL')
-                    if re.match(r'[-+0-9.]', v): # lazy, could be tightened
+                    if re.match(r'[-+0-9.]', v):  # lazy, could be tightened
                         conflicting.add('QTYPE_QNUM')
             else:
                 conflicting.add('QTYPE_QNUM')
@@ -845,19 +849,34 @@ def check_alternate(expr, info):
             types_seen[qt] = key
 
 
-def check_enum(expr, info):
+def normalize_enum(expr, info):
     name = expr['enum']
     members = expr.get('data')
-    prefix = expr.get('prefix')
 
     if not isinstance(members, list):
         raise QAPISemError(info,
                            "Enum '%s' requires an array for 'data'" % name)
+
+    # translate short member form to dict form
+    for i, member in enumerate(members):
+        if not isinstance(member, dict):
+            member = {'name': member}
+            members[i] = member
+
+
+def check_enum(expr, info):
+    name = expr['enum']
+    members = expr.get('data')
+    prefix = expr.get('prefix')
+
     if prefix is not None and not isinstance(prefix, str):
         raise QAPISemError(info,
                            "Enum '%s' requires a string for 'prefix'" % name)
+
     for member in members:
-        check_name(info, "Member of enum '%s'" % name, member,
+        source = "Dictionary member of enum '%s'" % name
+        check_known_keys(info, source, member, ['name'], [])
+        check_name(info, "Member of enum '%s'" % name, member['name'],
                    enum_member=True)
 
 
@@ -918,6 +937,13 @@ def check_exprs(exprs):
     for builtin in builtin_types.keys():
         all_names[builtin] = 'built-in'
 
+    # Normalize exprs
+    for expr_elem in exprs:
+        expr = expr_elem['expr']
+        info = expr_elem['info']
+        if 'enum' in expr:
+            normalize_enum(expr, info)
+
     # Learn the types and check for valid expression keys
     for expr_elem in exprs:
         expr = expr_elem['expr']
@@ -1586,7 +1612,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:
+            if isinstance(v, dict):
+                name = v['name']
+            else:
+                name = v
+            enum.append(QAPISchemaMember(name))
+        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 501a5713b5..3634e8f67c 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -450,10 +450,11 @@ qapi-schema += double-data.json
 qapi-schema += double-type.json
 qapi-schema += duplicate-key.json
 qapi-schema += empty.json
+qapi-schema += enum-bad-member.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-dict-member-unknown.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-bad-member.err b/tests/qapi-schema/enum-bad-member.err
new file mode 100644
index 0000000000..211db9e6fc
--- /dev/null
+++ b/tests/qapi-schema/enum-bad-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-bad-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-bad-member.exit
similarity index 100%
rename from tests/qapi-schema/enum-dict-member.exit
rename to tests/qapi-schema/enum-bad-member.exit
diff --git a/tests/qapi-schema/enum-bad-member.json b/tests/qapi-schema/enum-bad-member.json
new file mode 100644
index 0000000000..98da6828b4
--- /dev/null
+++ b/tests/qapi-schema/enum-bad-member.json
@@ -0,0 +1,2 @@
+# we reject any enum member that is not a string
+{ 'enum': 'MyEnum', 'data': [ [ ] ] }
diff --git a/tests/qapi-schema/enum-dict-member.out b/tests/qapi-schema/enum-bad-member.out
similarity index 100%
rename from tests/qapi-schema/enum-dict-member.out
rename to tests/qapi-schema/enum-bad-member.out
diff --git a/tests/qapi-schema/enum-dict-member-unknown.err b/tests/qapi-schema/enum-dict-member-unknown.err
new file mode 100644
index 0000000000..7ed48beb2e
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-unknown.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-dict-member-unknown.json:2: Dictionary member of enum 'MyEnum' has unknown key 'bad-key' (allowed: 'name')
diff --git a/tests/qapi-schema/enum-dict-member-unknown.exit b/tests/qapi-schema/enum-dict-member-unknown.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-unknown.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-dict-member-unknown.json b/tests/qapi-schema/enum-dict-member-unknown.json
new file mode 100644
index 0000000000..6664c59201
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-unknown.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-unknown.out b/tests/qapi-schema/enum-dict-member-unknown.out
new file mode 100644
index 0000000000..e69de29bb2
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.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-missing-data.err b/tests/qapi-schema/enum-missing-data.err
index 68e286badc..b8ccae071b 100644
--- a/tests/qapi-schema/enum-missing-data.err
+++ b/tests/qapi-schema/enum-missing-data.err
@@ -1 +1 @@
-tests/qapi-schema/enum-missing-data.json:2: enum 'MyEnum' must have 'data' key
+tests/qapi-schema/enum-missing-data.json:2: Enum 'MyEnum' requires an array for 'data'
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 23/51] qapi: add 'if' to enum members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (21 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 22/51] qapi: add a dictionnary form with 'name' key for enum members Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 24/51] qapi-event: add 'if' condition to implicit event enum Marc-André Lureau
                   ` (27 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, Michael Roth

QAPISchemaMember gains .ifcond for enum members: inherited classes,
such as QAPISchemaObjectTypeMember, will thus have an ifcond member
after this (those different types will also use the .ifcond to store
the condition and generate conditional code in the following patches).

Generated code is not changed by this patch, but with "qapi: add #if
conditions to generated code" patch.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                                | 10 +++++++---
 tests/Makefile.include                         |  1 +
 tests/qapi-schema/enum-dict-member-unknown.err |  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/qapi-schema-test.json        |  5 +++--
 tests/qapi-schema/qapi-schema-test.out         |  2 ++
 tests/qapi-schema/test-qapi.py                 |  1 +
 10 files changed, 20 insertions(+), 6 deletions(-)
 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/scripts/qapi.py b/scripts/qapi.py
index 1338be4efe..e203734254 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -875,7 +875,8 @@ def check_enum(expr, info):
 
     for member in members:
         source = "Dictionary member of enum '%s'" % name
-        check_known_keys(info, source, member, ['name'], [])
+        check_known_keys(info, source, member, ['name'], ['if'])
+        check_if(member, info)
         check_name(info, "Member of enum '%s'" % name, member['name'],
                    enum_member=True)
 
@@ -1330,9 +1331,10 @@ class QAPISchemaObjectType(QAPISchemaType):
 class QAPISchemaMember(object):
     role = 'member'
 
-    def __init__(self, name):
+    def __init__(self, name, ifcond=None):
         assert isinstance(name, str)
         self.name = name
+        self.ifcond = listify_cond(ifcond)
         self.owner = None
 
     def set_owner(self, name):
@@ -1616,9 +1618,11 @@ class QAPISchema(object):
         for v in values:
             if isinstance(v, dict):
                 name = v['name']
+                ifcond = v.get('if')
             else:
                 name = v
-            enum.append(QAPISchemaMember(name))
+                ifcond = None
+            enum.append(QAPISchemaMember(name, ifcond))
         return enum
 
     def _make_implicit_enum_type(self, name, info, ifcond, values):
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3634e8f67c..aa5a572403 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -455,6 +455,7 @@ qapi-schema += enum-bad-name.json
 qapi-schema += enum-bad-prefix.json
 qapi-schema += enum-clash-member.json
 qapi-schema += enum-dict-member-unknown.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-unknown.err b/tests/qapi-schema/enum-dict-member-unknown.err
index 7ed48beb2e..94e02ecd25 100644
--- a/tests/qapi-schema/enum-dict-member-unknown.err
+++ b/tests/qapi-schema/enum-dict-member-unknown.err
@@ -1 +1 @@
-tests/qapi-schema/enum-dict-member-unknown.json:2: Dictionary member of enum 'MyEnum' has unknown key 'bad-key' (allowed: 'name')
+tests/qapi-schema/enum-dict-member-unknown.json:2: Dictionary member of enum 'MyEnum' has unknown key 'bad-key' (allowed: 'name', 'if')
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
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index b997b2d43d..6a1d3b6337 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 33afa965e8..b5fff8d538 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -75,6 +75,7 @@ command TestIfCmd q_obj_TestIfCmd-arg -> None
 enum TestIfEnum
     member foo
     member bar
+        if ['defined(TEST_IF_ENUM_BAR)']
     if ['defined(TEST_IF_ENUM)']
 event TestIfEvent q_obj_TestIfEvent-arg
    boxed=False
@@ -228,6 +229,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 aadc8452b4..1269b8fbc5 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -57,6 +57,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
                 m.name,
                 ': %s optional=%s' % (m.type.name, m.optional)
                 if isinstance(m, QAPISchemaObjectTypeMember) else '')
+            QAPISchemaTestVisitor._print_if(m.ifcond, 8)
 
     @staticmethod
     def _print_variants(variants):
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 24/51] qapi-event: add 'if' condition to implicit event enum
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (22 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 23/51] qapi: add 'if' to " Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 25/51] qapi: rename allow_dict to allow_implicit Marc-André Lureau
                   ` (26 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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

Generated code is not changed by this patch, but with "qapi: add #if
conditions to generated code" patch.

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.

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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 25/51] qapi: rename allow_dict to allow_implicit
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (23 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 24/51] qapi-event: add 'if' condition to implicit event enum Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 26/51] qapi: add a dictionary form with 'type' key for members Marc-André Lureau
                   ` (25 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, Michael Roth

This makes it a bit clearer what is the intent of the dictionnary for
the check_type() function, since there was some confusion on a
previous iteration of this series.

Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index e203734254..5b41114949 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -652,7 +652,7 @@ def check_if(expr, info):
 
 
 def check_type(info, source, value, allow_array=False,
-               allow_dict=False, allow_optional=False,
+               allow_implicit=False, allow_optional=False,
                allow_metas=[]):
     global all_names
 
@@ -679,7 +679,7 @@ def check_type(info, source, value, allow_array=False,
                                (source, all_names[value], value))
         return
 
-    if not allow_dict:
+    if not allow_implicit:
         raise QAPISemError(info, "%s should be a type name" % source)
 
     if not isinstance(value, OrderedDict):
@@ -709,7 +709,7 @@ def check_command(expr, info):
     if boxed:
         args_meta += ['union', 'alternate']
     check_type(info, "'data' for command '%s'" % name,
-               expr.get('data'), allow_dict=not boxed, allow_optional=True,
+               expr.get('data'), allow_implicit=not boxed, allow_optional=True,
                allow_metas=args_meta)
     returns_meta = ['union', 'struct']
     if name in returns_whitelist:
@@ -727,7 +727,7 @@ def check_event(expr, info):
     if boxed:
         meta += ['union', 'alternate']
     check_type(info, "'data' for event '%s'" % name,
-               expr.get('data'), allow_dict=not boxed, allow_optional=True,
+               expr.get('data'), allow_implicit=not boxed, allow_optional=True,
                allow_metas=meta)
 
 
@@ -755,7 +755,7 @@ def check_union(expr, info):
     else:
         # The object must have a string or dictionary 'base'.
         check_type(info, "'base' for union '%s'" % name,
-                   base, allow_dict=True, allow_optional=True,
+                   base, allow_implicit=True, allow_optional=True,
                    allow_metas=['struct'])
         if not base:
             raise QAPISemError(info, "Flat union '%s' must have a base"
@@ -886,7 +886,7 @@ def check_struct(expr, info):
     members = expr['data']
 
     check_type(info, "'data' for struct '%s'" % name, members,
-               allow_dict=True, allow_optional=True)
+               allow_implicit=True, allow_optional=True)
     check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
                allow_metas=['struct'])
 
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 26/51] qapi: add a dictionary form with 'type' key for members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (24 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 25/51] qapi: rename allow_dict to allow_implicit Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 27/51] qapi: add 'if' to implicit struct members Marc-André Lureau
                   ` (24 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

Wherever a struct/union/alternate/command/event member with NAME: TYPE
form is accepted, desugar it to a NAME: { 'type': TYPE } form.

This will allow to add new member details, such as 'if' in the
following patch to introduce conditionals, or 'default' for default
values etc.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                                   | 57 +++++++++++++++--------
 tests/Makefile.include                            |  3 ++
 tests/qapi-schema/alternate-invalid-dict.err      |  1 +
 tests/qapi-schema/alternate-invalid-dict.exit     |  1 +
 tests/qapi-schema/alternate-invalid-dict.json     |  4 ++
 tests/qapi-schema/alternate-invalid-dict.out      |  0
 tests/qapi-schema/event-nest-struct.err           |  2 +-
 tests/qapi-schema/flat-union-inline.err           |  2 +-
 tests/qapi-schema/nested-struct-data.err          |  2 +-
 tests/qapi-schema/qapi-schema-test.json           | 10 ++--
 tests/qapi-schema/struct-member-invalid-dict.err  |  1 +
 tests/qapi-schema/struct-member-invalid-dict.exit |  1 +
 tests/qapi-schema/struct-member-invalid-dict.json |  3 ++
 tests/qapi-schema/struct-member-invalid-dict.out  |  0
 tests/qapi-schema/union-branch-invalid-dict.err   |  1 +
 tests/qapi-schema/union-branch-invalid-dict.exit  |  1 +
 tests/qapi-schema/union-branch-invalid-dict.json  |  4 ++
 tests/qapi-schema/union-branch-invalid-dict.out   |  0
 18 files changed, 66 insertions(+), 27 deletions(-)
 create mode 100644 tests/qapi-schema/alternate-invalid-dict.err
 create mode 100644 tests/qapi-schema/alternate-invalid-dict.exit
 create mode 100644 tests/qapi-schema/alternate-invalid-dict.json
 create mode 100644 tests/qapi-schema/alternate-invalid-dict.out
 create mode 100644 tests/qapi-schema/struct-member-invalid-dict.err
 create mode 100644 tests/qapi-schema/struct-member-invalid-dict.exit
 create mode 100644 tests/qapi-schema/struct-member-invalid-dict.json
 create mode 100644 tests/qapi-schema/struct-member-invalid-dict.out
 create mode 100644 tests/qapi-schema/union-branch-invalid-dict.err
 create mode 100644 tests/qapi-schema/union-branch-invalid-dict.exit
 create mode 100644 tests/qapi-schema/union-branch-invalid-dict.json
 create mode 100644 tests/qapi-schema/union-branch-invalid-dict.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 5b41114949..49fdf6bacf 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -579,11 +579,11 @@ def discriminator_find_enum_define(expr):
     if not base_members:
         return None
 
-    discriminator_type = base_members.get(discriminator)
-    if not discriminator_type:
+    discriminator_member = base_members.get(discriminator)
+    if not discriminator_member:
         return None
 
-    return enum_types.get(discriminator_type)
+    return enum_types.get(discriminator_member['type'])
 
 
 # Names must be letters, numbers, -, and _.  They must start with letter,
@@ -651,6 +651,15 @@ def check_if(expr, info):
         check_if_str(ifcond, info)
 
 
+def normalize_members(expr, field):
+    members = expr.get(field)
+    if isinstance(members, OrderedDict):
+        for key, arg in members.items():
+            if isinstance(arg, dict):
+                continue
+            members[key] = {'type': arg}
+
+
 def check_type(info, source, value, allow_array=False,
                allow_implicit=False, allow_optional=False,
                allow_metas=[]):
@@ -695,8 +704,9 @@ def check_type(info, source, value, allow_array=False,
                                % (source, key))
         # Todo: allow dictionaries to represent default values of
         # an optional argument.
-        check_type(info, "Member '%s' of %s" % (key, source), arg,
-                   allow_array=True,
+        member_source = "Member '%s' of %s" % (key, source)
+        check_known_keys(info, member_source, arg, ['type'], [])
+        check_type(info, member_source, arg['type'], allow_array=True,
                    allow_metas=['built-in', 'union', 'alternate', 'struct',
                                 'enum'])
 
@@ -767,13 +777,13 @@ def check_union(expr, info):
         # member of the base struct.
         check_name(info, "Discriminator of flat union '%s'" % name,
                    discriminator)
-        discriminator_type = base_members.get(discriminator)
-        if not discriminator_type:
+        discriminator_member = base_members.get(discriminator)
+        if not discriminator_member:
             raise QAPISemError(info,
                                "Discriminator '%s' is not a member of base "
                                "struct '%s'"
                                % (discriminator, base))
-        enum_define = enum_types.get(discriminator_type)
+        enum_define = enum_types.get(discriminator_member['type'])
         allow_metas = ['struct']
         # Do not allow string discriminator
         if not enum_define:
@@ -785,11 +795,14 @@ def check_union(expr, info):
     if len(members) == 0:
         raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name)
     for (key, value) in members.items():
-        check_name(info, "Member of union '%s'" % name, key)
+        source = "Member of union '%s'" % name
+        check_name(info, source, key)
+        check_known_keys(info, source, value, ['type'], [])
+        typ = value['type']
 
         # Each value must name a known type
         check_type(info, "Member '%s' of union '%s'" % (key, name),
-                   value, allow_array=not base, allow_metas=allow_metas)
+                   typ, allow_array=not base, allow_metas=allow_metas)
 
         # If the discriminator names an enum type, then all members
         # of 'data' must also be members of the enum type.
@@ -820,18 +833,20 @@ def check_alternate(expr, info):
                            "in 'data'" % name)
     for (key, value) in members.items():
         check_name(info, "Member of alternate '%s'" % name, key)
+        source = "Member '%s' of alternate '%s'" % (key, name)
+        check_known_keys(info, source, value, ['type'], [])
+        typ = value['type']
 
         # Ensure alternates have no type conflicts.
-        check_type(info, "Member '%s' of alternate '%s'" % (key, name),
-                   value,
+        check_type(info, source, typ,
                    allow_metas=['built-in', 'union', 'struct', 'enum'])
-        qtype = find_alternate_member_qtype(value)
+        qtype = find_alternate_member_qtype(typ)
         if not qtype:
             raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
-                               "type '%s'" % (name, key, value))
+                               "type '%s'" % (name, key, typ))
         conflicting = set([qtype])
         if qtype == 'QTYPE_QSTRING':
-            enum_expr = enum_types.get(value)
+            enum_expr = enum_types.get(typ)
             if enum_expr:
                 for v in enum_get_names(enum_expr):
                     if v in ['on', 'off']:
@@ -944,6 +959,10 @@ def check_exprs(exprs):
         info = expr_elem['info']
         if 'enum' in expr:
             normalize_enum(expr, info)
+        elif 'union' in expr:
+            normalize_members(expr, 'base')
+        if {'union', 'alternate', 'struct', 'command', 'event'} & set(expr):
+            normalize_members(expr, 'data')
 
     # Learn the types and check for valid expression keys
     for expr_elem in exprs:
@@ -1681,7 +1700,7 @@ class QAPISchema(object):
         return QAPISchemaObjectTypeMember(name, typ, optional)
 
     def _make_members(self, data, info):
-        return [self._make_member(key, value, info)
+        return [self._make_member(key, value['type'], info)
                 for (key, value) in data.iteritems()]
 
     def _def_struct_type(self, expr, info, doc):
@@ -1717,11 +1736,11 @@ class QAPISchema(object):
                 name, info, doc, ifcond,
                 'base', self._make_members(base, info))
         if tag_name:
-            variants = [self._make_variant(key, value)
+            variants = [self._make_variant(key, value['type'])
                         for (key, value) in data.iteritems()]
             members = []
         else:
-            variants = [self._make_simple_variant(key, value, info)
+            variants = [self._make_simple_variant(key, value['type'], info)
                         for (key, value) in data.iteritems()]
             typ = self._make_implicit_enum_type(name, info, ifcond,
                                                 [v.name for v in variants])
@@ -1737,7 +1756,7 @@ class QAPISchema(object):
         name = expr['alternate']
         data = expr['data']
         ifcond = expr.get('if')
-        variants = [self._make_variant(key, value)
+        variants = [self._make_variant(key, value['type'])
                     for (key, value) in data.iteritems()]
         tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
         self._def_entity(
diff --git a/tests/Makefile.include b/tests/Makefile.include
index aa5a572403..afd2971147 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -389,6 +389,7 @@ qapi-schema += alternate-conflict-string.json
 qapi-schema += alternate-conflict-bool-string.json
 qapi-schema += alternate-conflict-num-string.json
 qapi-schema += alternate-empty.json
+qapi-schema += alternate-invalid-dict.json
 qapi-schema += alternate-nested.json
 qapi-schema += alternate-unknown.json
 qapi-schema += args-alternate.json
@@ -530,6 +531,7 @@ 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-member-invalid-dict.json
 qapi-schema += struct-member-invalid.json
 qapi-schema += trailing-comma-list.json
 qapi-schema += trailing-comma-object.json
@@ -541,6 +543,7 @@ qapi-schema += unicode-str.json
 qapi-schema += union-base-empty.json
 qapi-schema += union-base-no-discriminator.json
 qapi-schema += union-branch-case.json
+qapi-schema += union-branch-invalid-dict.json
 qapi-schema += union-clash-branches.json
 qapi-schema += union-empty.json
 qapi-schema += union-invalid-base.json
diff --git a/tests/qapi-schema/alternate-invalid-dict.err b/tests/qapi-schema/alternate-invalid-dict.err
new file mode 100644
index 0000000000..39d3b6bca5
--- /dev/null
+++ b/tests/qapi-schema/alternate-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-invalid-dict.json:2: Member 'two' of alternate 'Alt' must have 'type' key
diff --git a/tests/qapi-schema/alternate-invalid-dict.exit b/tests/qapi-schema/alternate-invalid-dict.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/alternate-invalid-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/alternate-invalid-dict.json b/tests/qapi-schema/alternate-invalid-dict.json
new file mode 100644
index 0000000000..45f2c8ebef
--- /dev/null
+++ b/tests/qapi-schema/alternate-invalid-dict.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-invalid-dict.out b/tests/qapi-schema/alternate-invalid-dict.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/event-nest-struct.err b/tests/qapi-schema/event-nest-struct.err
index 5a42701b8f..66cd141112 100644
--- a/tests/qapi-schema/event-nest-struct.err
+++ b/tests/qapi-schema/event-nest-struct.err
@@ -1 +1 @@
-tests/qapi-schema/event-nest-struct.json:1: Member 'a' of 'data' for event 'EVENT_A' should be a type name
+tests/qapi-schema/event-nest-struct.json:1: Member 'a' of 'data' for event 'EVENT_A' must have 'type' key
diff --git a/tests/qapi-schema/flat-union-inline.err b/tests/qapi-schema/flat-union-inline.err
index 2333358d28..82d511c7ef 100644
--- a/tests/qapi-schema/flat-union-inline.err
+++ b/tests/qapi-schema/flat-union-inline.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-inline.json:7: Member 'value1' of union 'TestUnion' should be a type name
+tests/qapi-schema/flat-union-inline.json:7: Member of union 'TestUnion' must have 'type' key
diff --git a/tests/qapi-schema/nested-struct-data.err b/tests/qapi-schema/nested-struct-data.err
index da767bade2..728591fde3 100644
--- a/tests/qapi-schema/nested-struct-data.err
+++ b/tests/qapi-schema/nested-struct-data.err
@@ -1 +1 @@
-tests/qapi-schema/nested-struct-data.json:2: Member 'a' of 'data' for command 'foo' should be a type name
+tests/qapi-schema/nested-struct-data.json:2: Member 'a' of 'data' for command 'foo' must have 'type' key
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 6a1d3b6337..71023fb277 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -11,7 +11,7 @@
         'guest-sync' ] } }
 
 { 'struct': 'TestStruct',
-  'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } }
+  'data': { 'integer': {'type': 'int'}, 'boolean': 'bool', 'string': 'str' } }
 
 # for testing enums
 { 'struct': 'NestedEnumsOne',
@@ -74,7 +74,7 @@
 { 'union': 'UserDefFlatUnion',
   'base': 'UserDefUnionBase',   # intentional forward reference
   'discriminator': 'enum1',
-  'data': { 'value1' : 'UserDefA',
+  'data': { 'value1' : {'type': 'UserDefA'},
             'value2' : 'UserDefB',
             'value3' : 'UserDefB' } }
 
@@ -93,7 +93,7 @@
 { 'struct': 'WrapAlternate',
   'data': { 'alt': 'UserDefAlternate' } }
 { 'alternate': 'UserDefAlternate',
-  'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int',
+  'data': { 'udfu': {'type': 'UserDefFlatUnion'}, 'e': 'EnumOne', 'i': 'int',
             'n': 'null' } }
 
 { 'struct': 'UserDefC',
@@ -129,7 +129,7 @@
 { 'command': 'user_def_cmd', 'data': {} }
 { 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
 { 'command': 'user_def_cmd2',
-  'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'},
+  'data': {'ud1a': {'type': 'UserDefOne'}, '*ud1b': 'UserDefOne'},
   'returns': 'UserDefTwo' }
 
 # Returning a non-dictionary requires a name from the whitelist
@@ -156,7 +156,7 @@
 
 # testing event
 { 'struct': 'EventStructOne',
-  'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } }
+  'data': { 'struct1': {'type': 'UserDefOne'}, 'string': 'str', '*enum2': 'EnumOne' } }
 
 { 'event': 'EVENT_A' }
 { 'event': 'EVENT_B',
diff --git a/tests/qapi-schema/struct-member-invalid-dict.err b/tests/qapi-schema/struct-member-invalid-dict.err
new file mode 100644
index 0000000000..8435a78cb4
--- /dev/null
+++ b/tests/qapi-schema/struct-member-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-member-invalid-dict.json:2: Member '*a' of 'data' for struct 'foo' must have 'type' key
diff --git a/tests/qapi-schema/struct-member-invalid-dict.exit b/tests/qapi-schema/struct-member-invalid-dict.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/struct-member-invalid-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/struct-member-invalid-dict.json b/tests/qapi-schema/struct-member-invalid-dict.json
new file mode 100644
index 0000000000..ebd9733b49
--- /dev/null
+++ b/tests/qapi-schema/struct-member-invalid-dict.json
@@ -0,0 +1,3 @@
+# exploded member form must have a 'type'
+{ 'struct': 'foo',
+  'data': { '*a': { 'case': 'foo' } } }
diff --git a/tests/qapi-schema/struct-member-invalid-dict.out b/tests/qapi-schema/struct-member-invalid-dict.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/union-branch-invalid-dict.err b/tests/qapi-schema/union-branch-invalid-dict.err
new file mode 100644
index 0000000000..65f9999fc0
--- /dev/null
+++ b/tests/qapi-schema/union-branch-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-branch-invalid-dict.json:2: Member of union 'UnionInvalidBranch' must have 'type' key
diff --git a/tests/qapi-schema/union-branch-invalid-dict.exit b/tests/qapi-schema/union-branch-invalid-dict.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/union-branch-invalid-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/union-branch-invalid-dict.json b/tests/qapi-schema/union-branch-invalid-dict.json
new file mode 100644
index 0000000000..19c5d9cacd
--- /dev/null
+++ b/tests/qapi-schema/union-branch-invalid-dict.json
@@ -0,0 +1,4 @@
+# exploded member form must have a 'type'
+{ 'union': 'UnionInvalidBranch',
+  'data': { 'integer': { 'if': 'foo'},
+            's8': 'int8' } }
diff --git a/tests/qapi-schema/union-branch-invalid-dict.out b/tests/qapi-schema/union-branch-invalid-dict.out
new file mode 100644
index 0000000000..e69de29bb2
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 27/51] qapi: add 'if' to implicit struct members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (25 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 26/51] qapi: add a dictionary form with 'type' key for members Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 28/51] qapi: add an error in case a discriminator is conditionnal Marc-André Lureau
                   ` (23 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

Generated code is not changed by this patch, but with "qapi: add #if
conditions to generated code" patch.

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

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 49fdf6bacf..c4a2623864 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -705,7 +705,7 @@ def check_type(info, source, value, allow_array=False,
         # Todo: allow dictionaries to represent default values of
         # an optional argument.
         member_source = "Member '%s' of %s" % (key, source)
-        check_known_keys(info, member_source, arg, ['type'], [])
+        check_known_keys(info, member_source, arg, ['type'], ['if'])
         check_type(info, member_source, arg['type'], allow_array=True,
                    allow_metas=['built-in', 'union', 'alternate', 'struct',
                                 'enum'])
@@ -1394,8 +1394,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
@@ -1689,7 +1689,7 @@ class QAPISchema(object):
             name, info, doc, ifcond,
             self._make_enum_members(data), prefix))
 
-    def _make_member(self, name, typ, info):
+    def _make_member(self, name, typ, ifcond, info):
         optional = False
         if name.startswith('*'):
             name = name[1:]
@@ -1697,10 +1697,10 @@ class QAPISchema(object):
         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['type'], info)
+        return [self._make_member(key, value['type'], value.get('if'), info)
                 for (key, value) in data.iteritems()]
 
     def _def_struct_type(self, expr, info, doc):
@@ -1721,7 +1721,7 @@ class QAPISchema(object):
             typ = self._make_array_type(typ[0], info)
         typ = self._make_implicit_object_type(
             typ, info, None, self.lookup_type(typ),
-            'wrapper', [self._make_member('data', typ, info)])
+            'wrapper', [self._make_member('data', typ, None, info)])
         return QAPISchemaObjectTypeVariant(case, typ)
 
     def _def_union_type(self, expr, info, doc):
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 71023fb277..e29c9f0769 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 b5fff8d538..734d3f53aa 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -82,6 +82,8 @@ 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
@@ -230,9 +232,12 @@ object q_obj_EVENT_D-arg
 object q_obj_TestIfCmd-arg
     member foo: TestIfStruct 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 28/51] qapi: add an error in case a discriminator is conditionnal
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (26 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 27/51] qapi: add 'if' to implicit struct members Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 29/51] qapi: add 'if' on union members Marc-André Lureau
                   ` (22 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

Making a discriminator conditonal doesn't make much sense. Instead,
the union could be made conditional.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                                         | 11 +++++++++--
 tests/Makefile.include                                  |  1 +
 .../qapi-schema/flat-union-invalid-if-discriminator.err |  1 +
 .../flat-union-invalid-if-discriminator.exit            |  1 +
 .../flat-union-invalid-if-discriminator.json            | 17 +++++++++++++++++
 .../qapi-schema/flat-union-invalid-if-discriminator.out |  0
 6 files changed, 29 insertions(+), 2 deletions(-)
 create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.err
 create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.exit
 create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.json
 create mode 100644 tests/qapi-schema/flat-union-invalid-if-discriminator.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index c4a2623864..0f6d5dd179 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -568,7 +568,8 @@ def find_alternate_member_qtype(qapi_type):
 
 # Return the discriminator enum define if discriminator is specified as an
 # enum type, otherwise return None.
-def discriminator_find_enum_define(expr):
+def discriminator_find_enum_define(expr, info):
+    name = expr['union']
     base = expr.get('base')
     discriminator = expr.get('discriminator')
 
@@ -583,6 +584,11 @@ def discriminator_find_enum_define(expr):
     if not discriminator_member:
         return None
 
+    if discriminator_member.get('if'):
+        raise QAPISemError(info, 'The discriminator %s.%s for union %s '
+                           'must not be conditional' %
+                           (base, discriminator, name))
+
     return enum_types.get(discriminator_member['type'])
 
 
@@ -1010,7 +1016,8 @@ def check_exprs(exprs):
     # Try again for hidden UnionKind enum
     for expr_elem in exprs:
         expr = expr_elem['expr']
-        if 'union' in expr and not discriminator_find_enum_define(expr):
+        info = expr_elem['info']
+        if 'union' in expr and not discriminator_find_enum_define(expr, info):
             name = '%sKind' % expr['union']
         elif 'alternate' in expr:
             name = '%sKind' % expr['alternate']
diff --git a/tests/Makefile.include b/tests/Makefile.include
index afd2971147..3aec5b0874 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -479,6 +479,7 @@ qapi-schema += flat-union-inline.json
 qapi-schema += flat-union-int-branch.json
 qapi-schema += flat-union-invalid-branch-key.json
 qapi-schema += flat-union-invalid-discriminator.json
+qapi-schema += flat-union-invalid-if-discriminator.json
 qapi-schema += flat-union-no-base.json
 qapi-schema += flat-union-optional-discriminator.json
 qapi-schema += flat-union-string-discriminator.json
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.err b/tests/qapi-schema/flat-union-invalid-if-discriminator.err
new file mode 100644
index 0000000000..0c94c9860d
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-invalid-if-discriminator.json:13: The discriminator TestBase.enum1 for union TestUnion must not be conditional
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.exit b/tests/qapi-schema/flat-union-invalid-if-discriminator.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.json b/tests/qapi-schema/flat-union-invalid-if-discriminator.json
new file mode 100644
index 0000000000..618ec36396
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.json
@@ -0,0 +1,17 @@
+{ 'enum': 'TestEnum',
+  'data': [ 'value1', 'value2' ] }
+
+{ 'struct': 'TestBase',
+  'data': { 'enum1': { 'type': 'TestEnum', 'if': 'FOO' } } }
+
+{ 'struct': 'TestTypeA',
+  'data': { 'string': 'str' } }
+
+{ 'struct': 'TestTypeB',
+  'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+  'base': 'TestBase',
+  'discriminator': 'enum1',
+  'data': { 'value1': 'TestTypeA',
+            'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.out b/tests/qapi-schema/flat-union-invalid-if-discriminator.out
new file mode 100644
index 0000000000..e69de29bb2
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 29/51] qapi: add 'if' on union members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (27 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 28/51] qapi: add an error in case a discriminator is conditionnal Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 30/51] qapi: add 'if' to alternate members Marc-André Lureau
                   ` (21 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, Michael Roth

Add 'if' key to union members:

{ 'union': 'TestIfUnion', 'data':
    'mem': { 'type': 'str', 'if': 'COND'} }

Generated code is not changed by this patch but with "qapi: add #if
conditions to generated code".

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

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 0f6d5dd179..24d6aef13f 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -803,7 +803,7 @@ def check_union(expr, info):
     for (key, value) in members.items():
         source = "Member of union '%s'" % name
         check_name(info, source, key)
-        check_known_keys(info, source, value, ['type'], [])
+        check_known_keys(info, source, value, ['type'], ['if'])
         typ = value['type']
 
         # Each value must name a known type
@@ -1460,8 +1460,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):
@@ -1722,14 +1722,14 @@ class QAPISchema(object):
     def _make_variant(self, case, typ):
         return QAPISchemaObjectTypeVariant(case, typ)
 
-    def _make_simple_variant(self, case, typ, info):
+    def _make_simple_variant(self, case, typ, ifcond, info):
         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),
             'wrapper', [self._make_member('data', typ, None, info)])
-        return QAPISchemaObjectTypeVariant(case, typ)
+        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
 
     def _def_union_type(self, expr, info, doc):
         name = expr['union']
@@ -1747,10 +1747,11 @@ class QAPISchema(object):
                         for (key, value) in data.iteritems()]
             members = []
         else:
-            variants = [self._make_simple_variant(key, value['type'], info)
+            variants = [self._make_simple_variant(key, value['type'],
+                                                  value.get('if'), info)
                         for (key, value) in data.iteritems()]
-            typ = self._make_implicit_enum_type(name, info, ifcond,
-                                                [v.name for v in variants])
+            enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
+            typ = self._make_implicit_enum_type(name, info, ifcond, enum)
             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 e29c9f0769..b4b8a0a2cc 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 734d3f53aa..001fa143cd 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -89,9 +89,16 @@ 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
@@ -239,6 +246,9 @@ object q_obj_TestIfEvent-arg
     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 1269b8fbc5..61fb8394d7 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -65,6 +65,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
             print '    tag %s' % variants.tag_member.name
             for v in variants.variants:
                 print '    case %s: %s' % (v.name, v.type.name)
+                QAPISchemaTestVisitor._print_if(v.ifcond, 8)
 
     @staticmethod
     def _print_if(ifcond, indent=4):
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 30/51] qapi: add 'if' to alternate members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (28 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 29/51] qapi: add 'if' on union members Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 31/51] qapi: add #if conditions to generated code Marc-André Lureau
                   ` (20 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

Add 'if' key to alternate members:

{ 'alternate': 'TestIfAlternate', 'data':
  { 'alt': { 'type': 'TestStruct', 'if': 'COND' } } }

Generated code is not changed by this patch but with "qapi: add #if
conditions to generated code".

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

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 24d6aef13f..f24cf8bda6 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -840,7 +840,7 @@ def check_alternate(expr, info):
     for (key, value) in members.items():
         check_name(info, "Member of alternate '%s'" % name, key)
         source = "Member '%s' of alternate '%s'" % (key, name)
-        check_known_keys(info, source, value, ['type'], [])
+        check_known_keys(info, source, value, ['type'], ['if'])
         typ = value['type']
 
         # Ensure alternates have no type conflicts.
@@ -1719,8 +1719,8 @@ class QAPISchema(object):
                                               self._make_members(data, info),
                                               None))
 
-    def _make_variant(self, case, typ):
-        return QAPISchemaObjectTypeVariant(case, typ)
+    def _make_variant(self, case, typ, ifcond):
+        return QAPISchemaObjectTypeVariant(case, typ, ifcond)
 
     def _make_simple_variant(self, case, typ, ifcond, info):
         if isinstance(typ, list):
@@ -1743,7 +1743,7 @@ class QAPISchema(object):
                 name, info, doc, ifcond,
                 'base', self._make_members(base, info))
         if tag_name:
-            variants = [self._make_variant(key, value['type'])
+            variants = [self._make_variant(key, value['type'], value.get('if'))
                         for (key, value) in data.iteritems()]
             members = []
         else:
@@ -1764,7 +1764,7 @@ class QAPISchema(object):
         name = expr['alternate']
         data = expr['data']
         ifcond = expr.get('if')
-        variants = [self._make_variant(key, value['type'])
+        variants = [self._make_variant(key, value['type'], value.get('if'))
                     for (key, value) in data.iteritems()]
         tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
         self._def_entity(
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index b4b8a0a2cc..cd33c084cb 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 001fa143cd..7215aeb4a6 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -67,8 +67,12 @@ 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)']
@@ -236,6 +240,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
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 31/51] qapi: add #if conditions to generated code
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (29 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 30/51] qapi: add 'if' to alternate members Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 32/51] docs: document schema configuration Marc-André Lureau
                   ` (19 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, Michael Roth

Wrap generated enum/struct members and code with #if/#endif, using the
.ifcond members added in the previous patches.

Some types generate both enum and struct members for example, so a
step-by-step is unnecessarily complicated to deal with (it would
easily generate invalid intermediary code).

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

diff --git a/scripts/qapi.py b/scripts/qapi.py
index f24cf8bda6..1668a6da6c 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -2043,11 +2043,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('''
     },
@@ -2069,10 +2071,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;
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 868d12f504..6a66047243 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -141,6 +141,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):
@@ -148,14 +150,16 @@ 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}, [])
 
     def visit_enum_type(self, name, info, ifcond, members, prefix):
         self._gen_qlit(name, 'enum',
-                       {'values': [m.name for m in members]}, ifcond)
+                       {'values': [(m.name, m.ifcond) for m in members]},
+                       ifcond)
 
     def visit_array_type(self, name, info, ifcond, element_type):
         element = self._use_type(element_type)
@@ -171,8 +175,9 @@ 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)}
-                                    for m in variants.variants]}, ifcond)
+                       {'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,
                       gen, success_response, boxed):
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 75c1823e44..312685c295 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
 
 
@@ -129,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 7e816ae98e..48ac1c9a42 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('''
@@ -80,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);
@@ -90,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();
@@ -177,9 +181,10 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
     }
     switch ((*obj)->type) {
 ''',
-                 c_name=c_name(name))
+                c_name=c_name(name))
 
     for var in variants.variants:
+        ret += gen_if(var.ifcond)
         ret += mcgen('''
     case %(case)s:
 ''',
@@ -207,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 32/51] docs: document schema configuration
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (30 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 31/51] qapi: add #if conditions to generated code Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 33/51] qapi2texi: add 'If:' section to generated documentation Marc-André Lureau
                   ` (18 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau, Michael Roth

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

diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index f58d62686a..479b755609 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -682,6 +682,44 @@ Example: Red Hat, Inc. controls redhat.com, and may therefore add a
 downstream command __com.redhat_drive-mirror.
 
 
+=== Configuring the schema ===
+
+Top-level QAPI expressions and various type expressions listed below
+can take an 'if' key.  The value must be a string or a list of
+string.  The corresponding generated code will then guard the inclusion
+of that member in the larger struct or function with #if IFCOND
+(or several #if lines for a list), where IFCOND is the value of the
+'if' key.
+
+'struct', 'enum', 'union', 'alternate', 'command' and 'event'
+top-level QAPI expressions can take an 'if' keyword like:
+
+{ 'struct': 'IfStruct', 'data': { 'foo': 'int' },
+  'if': 'defined(IFCOND)' }
+
+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.
+
+{ 'struct': 'IfStruct', 'data':
+  { 'foo': 'int',
+    'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } }
+
+An enum value can be replaced by a dictionary with a 'name' and a 'if'
+key:
+
+{ 'enum': 'IfEnum', 'data':
+  [ 'foo',
+    { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] }
+
+Please note that you are responsible 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.
+
+The presence of 'if' keys in the schema is reflected through to the
+introspection output depending on the build configuration.
+
+
 == Client JSON Protocol introspection ==
 
 Clients of a Client JSON Protocol commonly need to figure out what
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 33/51] qapi2texi: add 'If:' section to generated documentation
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (31 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 32/51] docs: document schema configuration Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 34/51] qapi2texi: add 'If:' condition to enum values Marc-André Lureau
                   ` (17 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, 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            | 23 +++++++++++++----------
 tests/qapi-schema/doc-good.json |  2 +-
 tests/qapi-schema/doc-good.out  |  1 +
 tests/qapi-schema/doc-good.texi |  2 ++
 4 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 755bd2f15d..76c336af34 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -174,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:
@@ -185,14 +185,16 @@ def texi_sections(doc):
             body += texi_example(section.text)
         else:
             body += texi_format(section.text)
+    if ifcond:
+        body += '\n\n@b{If:} @code{%s}' % ", ".join(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):
@@ -207,7 +209,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
         doc = self.cur_doc
         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):
@@ -216,13 +218,14 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             base = None
         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
         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):
@@ -231,9 +234,9 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             body = texi_body(doc)
             body += ('\n@b{Arguments:} the members of @code{%s}\n'
                      % 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)
@@ -242,7 +245,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
         doc = self.cur_doc
         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):
         if self.out:
@@ -255,7 +258,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):
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index 97ab4625ff..984cd8ed06 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -55,7 +55,7 @@
 #
 # @two is undocumented
 ##
-{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
+{ 'enum': 'Enum', 'data': [ 'one', 'two' ], 'if': 'defined(IFCOND)' }
 
 ##
 # @Base:
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index e615b04281..8c75da180c 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -3,6 +3,7 @@ object Base
 enum Enum
     member one
     member two
+    if ['defined(IFCOND)']
 object Object
     base Base
     tag base1
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index 1778312581..cd422f8a8f 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -87,6 +87,8 @@ Not documented
 @end table
 @code{two} is undocumented
 
+
+@b{If:} @code{defined(IFCOND)}
 @end deftp
 
 
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 34/51] qapi2texi: add 'If:' condition to enum values
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (32 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 33/51] qapi2texi: add 'If:' section to generated documentation Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 35/51] qapi2texi: add 'If:' condition to struct members Marc-André Lureau
                   ` (16 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Eduardo Habkost,
	Cleber Rosa, Michael Roth

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi2texi.py            | 5 ++++-
 tests/qapi-schema/doc-good.json | 4 +++-
 tests/qapi-schema/doc-good.out  | 1 +
 tests/qapi-schema/doc-good.texi | 2 ++
 4 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 76c336af34..d1e69358f6 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -128,7 +128,10 @@ 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' %
+        ', '.join(value.ifcond) if value.ifcond else '')
 
 
 def texi_member(member, suffix=''):
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index 984cd8ed06..c7fe08c530 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -55,7 +55,9 @@
 #
 # @two is undocumented
 ##
-{ 'enum': 'Enum', 'data': [ 'one', 'two' ], 'if': 'defined(IFCOND)' }
+{ 'enum': 'Enum', 'data':
+  [ { 'name': 'one', 'if': 'defined(IFENUM)' }, 'two' ],
+  'if': 'defined(IFCOND)' }
 
 ##
 # @Base:
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 8c75da180c..74bf60bb83 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -2,6 +2,7 @@ object Base
     member base1: Enum optional=False
 enum Enum
     member one
+        if ['defined(IFENUM)']
     member two
     if ['defined(IFCOND)']
 object Object
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index cd422f8a8f..c9988c1305 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -81,6 +81,8 @@ Examples:
 @b{Values:}
 @table @asis
 @item @code{one}
+@b{If:} @code{defined(IFENUM)}
+
 The @emph{one} @{and only@}
 @item @code{two}
 Not documented
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 35/51] qapi2texi: add 'If:' condition to struct members
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (33 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 34/51] qapi2texi: add 'If:' condition to enum values Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 36/51] qapi2texi: add condition to variants Marc-André Lureau
                   ` (15 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi2texi.py            | 4 +++-
 tests/qapi-schema/doc-good.json | 3 ++-
 tests/qapi-schema/doc-good.out  | 1 +
 tests/qapi-schema/doc-good.texi | 2 ++
 4 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index d1e69358f6..d760596ce0 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -138,9 +138,11 @@ 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' %
+        ', '.join(member.ifcond) if member.ifcond else '',
         suffix)
 
 
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index c7fe08c530..158443b1a3 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -72,7 +72,8 @@
 #
 # Another paragraph (but no @var: line)
 ##
-{ 'struct': 'Variant1', 'data': { 'var1': 'str' } }
+{ 'struct': 'Variant1',
+  'data': { 'var1': { 'type': 'str', 'if': 'defined(IFSTR)' } } }
 
 ##
 # @Variant2:
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 74bf60bb83..972b58c815 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -29,6 +29,7 @@ enum SugaredUnionKind
     member two
 object Variant1
     member var1: str optional=False
+        if ['defined(IFSTR)']
 object Variant2
 command cmd q_obj_cmd-arg -> Object
    gen=True success_response=True boxed=False
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index c9988c1305..f2a902a06b 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -118,6 +118,8 @@ Another paragraph (but no @code{var}: line)
 @b{Members:}
 @table @asis
 @item @code{var1: string}
+@b{If:} @code{defined(IFSTR)}
+
 Not documented
 @end table
 
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 36/51] qapi2texi: add condition to variants
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (34 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 35/51] qapi2texi: add 'If:' condition to struct members Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 37/51] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
                   ` (14 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi2texi.py            | 5 +++--
 tests/qapi-schema/doc-good.json | 4 ++--
 tests/qapi-schema/doc-good.out  | 3 +++
 tests/qapi-schema/doc-good.texi | 4 ++--
 4 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index d760596ce0..d8a0379c52 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -165,8 +165,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,
+                ' (@b{If:} @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:
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index 158443b1a3..afe46d93f0 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -86,13 +86,13 @@
 { 'union': 'Object',
   'base': 'Base',
   'discriminator': 'base1',
-  'data': { 'one': 'Variant1', 'two': 'Variant2' } }
+  'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
 
 ##
 # @SugaredUnion:
 ##
 { 'union': 'SugaredUnion',
-  'data': { 'one': 'Variant1', 'two': 'Variant2' } }
+  'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
 
 ##
 # == Another subsection
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 972b58c815..9a9d745f8e 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -10,6 +10,7 @@ object Object
     tag base1
     case one: Variant1
     case two: Variant2
+        if ['IFTWO']
 enum QType
     prefix QTYPE
     member none
@@ -24,9 +25,11 @@ object SugaredUnion
     tag type
     case one: q_obj_Variant1-wrapper
     case two: q_obj_Variant2-wrapper
+        if ['IFTWO']
 enum SugaredUnionKind
     member one
     member two
+        if ['IFTWO']
 object Variant1
     member var1: str optional=False
         if ['defined(IFSTR)']
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index f2a902a06b..3d513a89b7 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -143,7 +143,7 @@ Not documented
 @table @asis
 @item The members of @code{Base}
 @item The members of @code{Variant1} when @code{base1} is @t{"one"}
-@item The members of @code{Variant2} when @code{base1} is @t{"two"}
+@item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{['IFTWO']})
 @end table
 
 @end deftp
@@ -159,7 +159,7 @@ Not documented
 @item @code{type}
 One of @t{"one"}, @t{"two"}
 @item @code{data: Variant1} when @code{type} is @t{"one"}
-@item @code{data: Variant2} when @code{type} is @t{"two"}
+@item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{['IFTWO']})
 @end table
 
 @end deftp
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 37/51] qapi: add conditions to VNC type/commands/events on the schema
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (35 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 36/51] qapi2texi: add condition to variants Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-12 13:04   ` Gerd Hoffmann
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 38/51] qapi: add conditions to SPICE " Marc-André Lureau
                   ` (13 subsequent siblings)
  50 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Gerd Hoffmann

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

query-qmp-schema no longer reports the command/events etc as
available when disabled at compile.

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

HMP change:

* info vnc

  Will return "unknown command: 'info vnc'" when VNC is compiled
  out (same as error for spice when --disable-spice)

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/ui.json         | 45 ++++++++++++++++++++++++++++-----------------
 ui/vnc.h             |  2 ++
 hmp.c                |  9 ++++++++-
 qmp.c                | 30 ++++--------------------------
 hmp-commands-info.hx |  2 ++
 5 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/qapi/ui.json b/qapi/ui.json
index 07b468f625..05f1db27c8 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/hmp.c b/hmp.c
index 2d72f94193..0612ddc621 100644
--- a/hmp.c
+++ b/hmp.c
@@ -613,6 +613,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)
@@ -700,6 +701,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)
@@ -1738,12 +1740,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)
 {
@@ -1754,6 +1758,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,
@@ -1768,7 +1773,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 52cfd2d81c..d26debcd75 100644
--- a/qmp.c
+++ b/qmp.c
@@ -125,22 +125,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
@@ -398,23 +382,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/hmp-commands-info.hx b/hmp-commands-info.hx
index 54c3e5eac6..ea5733918b 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -421,6 +421,7 @@ STEXI
 Show which guest mouse is receiving events.
 ETEXI
 
+#if defined(CONFIG_VNC)
     {
         .name       = "vnc",
         .args_type  = "",
@@ -428,6 +429,7 @@ ETEXI
         .help       = "show the vnc server status",
         .cmd        = hmp_info_vnc,
     },
+#endif
 
 STEXI
 @item info vnc
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 38/51] qapi: add conditions to SPICE type/commands/events on the schema
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (36 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 37/51] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-12 13:09   ` Gerd Hoffmann
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 39/51] qapi: add conditions to REPLICATION type/commands " Marc-André Lureau
                   ` (12 subsequent siblings)
  50 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Paolo Bonzini, Gerd Hoffmann

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

query-qmp-schema no longer reports the command/events etc as
available when disabled at compile time.

Commands made conditional:

* query-spice

  Before the patch, the command for !CONFIG_SPICE is unregistered. It
  will fail with the same error.

Events made conditional:

* SPICE_CONNECTED, SPICE_INITIALIZED, SPICE_DISCONNECTED,
  SPICE_MIGRATE_COMPLETED

Chardev made conditional:

* spiceport, spicevmc

  Before and after the patch for !CONFIG_SPICE, the error is the
  same ('spiceport' is not a valid char driver name).

No HMP change, the code was already conditional.

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 05f1db27c8..17f673d7d1 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 b8931364f2..9dd1ee3c86 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 d26debcd75..2a8dfa5058 100644
--- a/qmp.c
+++ b/qmp.c
@@ -125,22 +125,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 39/51] qapi: add conditions to REPLICATION type/commands on the schema
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (37 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 38/51] qapi: add conditions to SPICE " Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 40/51] qapi-commands: don't initialize command list in qmp_init_marshall() Marc-André Lureau
                   ` (11 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, zhanghailiang,
	Juan Quintela, Dr. David Alan Gilbert

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 closer to killing qmp_unregister_commands_hack().

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

* BlockdevOptions variant @replication

And related structures.

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 e94a6881b2..cc1d495dda 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2238,8 +2238,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:
@@ -2874,7 +2876,8 @@
 #
 # Since: 2.9
 ##
-{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] }
+{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ],
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @BlockdevOptionsReplication:
@@ -2892,7 +2895,8 @@
 { 'struct': 'BlockdevOptionsReplication',
   'base': 'BlockdevOptionsGenericFormat',
   'data': { 'mode': 'ReplicationMode',
-            '*top-id': 'str' } }
+            '*top-id': 'str' },
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @NFSTransport:
@@ -3190,7 +3194,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 03f57c9616..fc80fc751c 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1115,7 +1115,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:
@@ -1130,7 +1131,8 @@
 # Since: 2.9
 ##
 { 'struct': 'ReplicationStatus',
-  'data': { 'error': 'bool', '*desc': 'str' } }
+  'data': { 'error': 'bool', '*desc': 'str' },
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @query-xen-replication-status:
@@ -1147,7 +1149,8 @@
 # Since: 2.9
 ##
 { 'command': 'query-xen-replication-status',
-  'returns': 'ReplicationStatus' }
+  'returns': 'ReplicationStatus',
+  'if': 'defined(CONFIG_REPLICATION)' }
 
 ##
 # @xen-colo-do-checkpoint:
@@ -1163,4 +1166,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 9dd1ee3c86..c3a1a4ea6c 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 40/51] qapi-commands: don't initialize command list in qmp_init_marshall()
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (38 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 39/51] qapi: add conditions to REPLICATION type/commands " Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 41/51] qapi: add -i/--include filename.h Marc-André Lureau
                   ` (10 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Michael Roth, Eduardo Habkost, Cleber Rosa

This will let the caller add several list of commands coming from
different schemas (the following patches split the schemas for common
and arch-specific parts).

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 c3a1a4ea6c..f5ffffa786 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 41/51] qapi: add -i/--include filename.h
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (39 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 40/51] qapi-commands: don't initialize command list in qmp_init_marshall() Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-02-05 16:58   ` Markus Armbruster
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma Marc-André Lureau
                   ` (9 subsequent siblings)
  50 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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.

Fix some pycodestyle on the way.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py            | 15 ++++++++++-----
 scripts/qapi-commands.py   |  7 +++++--
 scripts/qapi-event.py      |  6 ++++--
 scripts/qapi-introspect.py |  6 ++++--
 scripts/qapi-types.py      |  7 +++++--
 scripts/qapi-visit.py      |  6 ++++--
 tests/Makefile.include     |  4 +++-
 7 files changed, 35 insertions(+), 16 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 1668a6da6c..f56460d028 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -2125,10 +2125,10 @@ def build_params(arg_type, boxed, extra):
 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)
+        opts, args = getopt.gnu_getopt(
+            sys.argv[1:], '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)
@@ -2137,6 +2137,7 @@ def parse_command_line(extra_options='', extra_long_options=[]):
     prefix = ''
     do_c = False
     do_h = False
+    includes = []
     extra_opts = []
 
     for oa in opts:
@@ -2155,6 +2156,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)
 
@@ -2167,7 +2170,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 6a66047243..65277e98fd 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -192,11 +192,12 @@ const QLitObject %(c_name)s = %(c_string)s;
         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
 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:
@@ -239,10 +240,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..cc42447bc4 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -260,13 +260,14 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
         self._gen_object(name, info, ifcond, 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
 # do_builtins, enabled by command line option -b.  See also
 # 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 +318,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 48ac1c9a42..bcbd62b32d 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -332,13 +332,14 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
         self.decl += gen_visit_decl(name)
         self.defn += gen_visit_alternate(name, 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
 # do_builtins, enabled by command line option -b.  See also
 # 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 +388,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()
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3aec5b0874..2b83f05954 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -648,8 +648,10 @@ tests/test-replication$(EXESUF): tests/test-replication.o $(test-util-obj-y) \
 tests/test-qapi-types.c tests/test-qapi-types.h :\
 $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
-		$(gen-out-type) -o tests -p "test-" $<, \
+		$(gen-out-type) -o tests -p "test-" -i tests/test-qapi-types.h $<, \
 		"GEN","$@")
+# check that -i includes worked with a silly self-include
+	$(call quiet-command,[ $(gen-out-type) == -c ] || grep -q '#include "tests/test-qapi-types.h"' $@,"TEST","$@")
 tests/test-qapi-visit.c tests/test-qapi-visit.h :\
 $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (40 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 41/51] qapi: add -i/--include filename.h Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-12 11:54   ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 43/51] build-sys: move qmp-introspect per target Marc-André Lureau
                   ` (8 subsequent siblings)
  50 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Michael Roth,
	Eduardo Habkost, Cleber Rosa

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

See the docs/devel/qapi-code-gen.txt for more details.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py                            | 22 +++++++++++++++++++---
 docs/devel/qapi-code-gen.txt               |  4 ++++
 tests/Makefile.include                     |  7 ++++++-
 tests/qapi-schema/pragma-unit-invalid.err  |  1 +
 tests/qapi-schema/pragma-unit-invalid.exit |  1 +
 tests/qapi-schema/pragma-unit-invalid.json |  3 +++
 tests/qapi-schema/pragma-unit-invalid.out  |  0
 tests/qapi-schema/qapi-schema-test.json    |  6 +++++-
 tests/qapi-schema/qapi-schema-test.out     |  2 ++
 9 files changed, 41 insertions(+), 5 deletions(-)
 create mode 100644 tests/qapi-schema/pragma-unit-invalid.err
 create mode 100644 tests/qapi-schema/pragma-unit-invalid.exit
 create mode 100644 tests/qapi-schema/pragma-unit-invalid.json
 create mode 100644 tests/qapi-schema/pragma-unit-invalid.out

diff --git a/scripts/qapi.py b/scripts/qapi.py
index f56460d028..07e738c3f1 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 names to include for the visit (default to all units)
+visit_units = []
+
 enum_types = {}
 struct_types = {}
 union_types = {}
@@ -269,11 +272,12 @@ class QAPISchemaParser(object):
         self.exprs = []
         self.docs = []
         self.accept()
+        self.unit = None
         cur_doc = None
 
         while self.tok is not None:
             info = {'file': self.fname, 'line': self.line,
-                    'parent': self.incl_info}
+                    'parent': self.incl_info, 'unit': self.unit}
             if self.tok == '#':
                 self.reject_expr_doc(cur_doc)
                 cur_doc = self.get_doc(info)
@@ -362,6 +366,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)
 
@@ -1827,6 +1836,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_units and unit not in visit_units:
+                continue
             if visitor.visit_needed(entity):
                 entity.visit(visitor)
         visitor.visit_end()
@@ -2126,13 +2139,14 @@ def parse_command_line(extra_options='', extra_long_options=[]):
 
     try:
         opts, args = getopt.gnu_getopt(
-            sys.argv[1:], 'chp:o:i:' + extra_options,
+            sys.argv[1:], '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_units
     output_dir = ''
     prefix = ''
     do_c = False
@@ -2152,6 +2166,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_units.append(a)
         elif o in ('-c', '--source'):
             do_c = True
         elif o in ('-h', '--header'):
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 479b755609..31bcbdac58 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -326,6 +326,10 @@ 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 generators can filter
+based on a unit name.  This allows to select a subset of the
+expressions.  Default is none.
 
 === Struct types ===
 
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 2b83f05954..2f39e2d5aa 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -510,6 +510,7 @@ qapi-schema += pragma-extra-junk.json
 qapi-schema += pragma-name-case-whitelist-crap.json
 qapi-schema += pragma-non-dict.json
 qapi-schema += pragma-returns-whitelist-crap.json
+qapi-schema += pragma-unit-invalid.json
 qapi-schema += qapi-schema-test.json
 qapi-schema += quoted-structural-chars.json
 qapi-schema += redefined-builtin.json
@@ -665,13 +666,17 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-com
 tests/test-qapi-event.c tests/test-qapi-event.h :\
 $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
-		$(gen-out-type) -o tests -p "test-" $<, \
+		$(gen-out-type) -o tests -p "test-" -u test-unit $<, \
 		"GEN","$@")
+# check that another-unit is not included
+	$(call quiet-command,[ $(gen-out-type) == -h ] || grep -v -q ANOTHER_EVENT $@,"TEST","$@")
 tests/test-qmp-introspect.c tests/test-qmp-introspect.h :\
 $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
 		$(gen-out-type) -o tests -p "test-" $<, \
 		"GEN","$@")
+# check all units are included
+	$(call quiet-command,[ $(gen-out-type) == -h ] || grep -q ANOTHER_EVENT $@,"TEST","$@")
 
 tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.json $(SRC_PATH)/scripts/qapi2texi.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
diff --git a/tests/qapi-schema/pragma-unit-invalid.err b/tests/qapi-schema/pragma-unit-invalid.err
new file mode 100644
index 0000000000..e22176d42e
--- /dev/null
+++ b/tests/qapi-schema/pragma-unit-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/pragma-unit-invalid.json:3: Pragma 'unit' must be string
diff --git a/tests/qapi-schema/pragma-unit-invalid.exit b/tests/qapi-schema/pragma-unit-invalid.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/pragma-unit-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/pragma-unit-invalid.json b/tests/qapi-schema/pragma-unit-invalid.json
new file mode 100644
index 0000000000..636b53939a
--- /dev/null
+++ b/tests/qapi-schema/pragma-unit-invalid.json
@@ -0,0 +1,3 @@
+# Value of 'unit' pragma must be a string
+
+{ 'pragma': { 'unit': {} } }
diff --git a/tests/qapi-schema/pragma-unit-invalid.out b/tests/qapi-schema/pragma-unit-invalid.out
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index cd33c084cb..2fb1d3449c 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -8,7 +8,8 @@
     # Commands allowed to return a non-dictionary:
     'returns-whitelist': [
         'guest-get-time',
-        'guest-sync' ] } }
+        'guest-sync' ],
+    'unit': 'test-unit' } }
 
 { 'struct': 'TestStruct',
   'data': { 'integer': {'type': 'int'}, 'boolean': 'bool', 'string': 'str' } }
@@ -224,3 +225,6 @@
   { 'foo': 'TestIfStruct',
     'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_EVT_BAR)' } },
   'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
+
+{ 'pragma': { 'unit': 'another-unit' } }
+{ 'event': 'ANOTHER_EVENT' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 7215aeb4a6..cbc61fc3a2 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -1,3 +1,5 @@
+event ANOTHER_EVENT None
+   boxed=False
 alternate AltEnumBool
     tag type
     case e: EnumOne
-- 
2.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 43/51] build-sys: move qmp-introspect per target
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (41 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 44/51] build-sys: add a target schema Marc-André Lureau
                   ` (7 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau, Michael Roth

The following patches are going to introduce per-target #ifdef in the
schemas.

The introspection data is statically generated once, and must thus be
built per-target to reflect target-specific configuration.

Drop "do_test_visitor_in_qmp_introspect(&qmp_schema_qlit)" since the
schema is no longer in a common object. It is covered by the per-target
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 c8b1bba593..1b4d0ecfbc 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/
 
@@ -79,7 +79,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 f9a9da7e7c..35108c6caf 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -150,6 +150,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 44/51] build-sys: add a target schema
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (42 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 43/51] build-sys: move qmp-introspect per target Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 45/51] qapi: make rtc-reset-reinjection depend on TARGET_I386 Marc-André Lureau
                   ` (6 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau, Dr. David Alan Gilbert

This schema is going to contain target-specific commands/events &
types, that can be conditionnally guarded with poisoned defines.

And new rules to compile the schema generated files per-target, using
the 'target' unit name filter.

This new schema is now the top-level schema to generate the
documentation (to include also target-specific commands/types).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/target.json |  5 +++++
 monitor.c        |  2 ++
 Makefile         | 45 +++++++++++++++++++++++++++++++++++++--------
 Makefile.target  |  2 ++
 4 files changed, 46 insertions(+), 8 deletions(-)
 create mode 100644 qapi/target.json

diff --git a/qapi/target.json b/qapi/target.json
new file mode 100644
index 0000000000..6cac484f68
--- /dev/null
+++ b/qapi/target.json
@@ -0,0 +1,5 @@
+# -*- Mode: Python -*-
+
+{ 'include': '../qapi-schema.json' }
+
+{ 'pragma': { 'unit': 'target' } }
diff --git a/monitor.c b/monitor.c
index f5ffffa786..8a4fbdd09b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -67,6 +67,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 d86ecd2dd4..8a8ae4ce3c 100644
--- a/Makefile
+++ b/Makefile
@@ -87,6 +87,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
 
@@ -485,7 +487,7 @@ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
 		$(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \
 		"GEN","$@")
 
-qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
+common-qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
                $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
                $(SRC_PATH)/qapi/char.json \
                $(SRC_PATH)/qapi/crypto.json \
@@ -500,30 +502,57 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
                $(SRC_PATH)/qapi/transaction.json \
                $(SRC_PATH)/qapi/ui.json
 
+target-qapi-modules = $(SRC_PATH)/qapi/target.json \
+               $(common-qapi-modules)
+
 qapi-types.c qapi-types.h :\
-$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
+$(common-qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
 		$(gen-out-type) -o "." -b $<, \
 		"GEN","$@")
 qapi-visit.c qapi-visit.h :\
-$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
+$(common-qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
 		$(gen-out-type) -o "." -b $<, \
 		"GEN","$@")
 qapi-event.c qapi-event.h :\
-$(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
+$(common-qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
 		$(gen-out-type) -o "." $<, \
 		"GEN","$@")
 qmp-commands.h qmp-marshal.c :\
-$(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
+$(common-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 :\
+$(target-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 :\
+$(target-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 :\
+$(target-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 :\
+$(target-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)
+$(target-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)
@@ -791,7 +820,7 @@ qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
 
 docs/interop/qemu-qmp-qapi.texi docs/interop/qemu-ga-qapi.texi: $(SRC_PATH)/scripts/qapi2texi.py $(qapi-py)
 
-docs/interop/qemu-qmp-qapi.texi: $(qapi-modules)
+docs/interop/qemu-qmp-qapi.texi: $(target-qapi-modules)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
 
 docs/interop/qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json
diff --git a/Makefile.target b/Makefile.target
index 35108c6caf..110d4a9911 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -150,6 +150,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.16.0.rc1.1.gef27df75a1

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

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

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 5c06745c79..2cd13a07c4 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2939,24 +2939,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 6cac484f68..9bfbb54276 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -3,3 +3,22 @@
 { 'include': '../qapi-schema.json' }
 
 { '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 35a05a64cc..49bcf21099 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 8a4fbdd09b..f78a3aee9e 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
@@ -4145,13 +4142,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 46/51] qapi: make s390 commands depend on TARGET_S390X
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (44 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 45/51] qapi: make rtc-reset-reinjection depend on TARGET_I386 Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 47/51] target.json: add a note about query-cpu* not being s390x-specific Marc-André Lureau
                   ` (4 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Cornelia Huck,
	Christian Borntraeger, Alexander Graf, Richard Henderson,
	Dr. David Alan Gilbert, Paolo Bonzini, open list:S390 Virtio-ccw

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Cornelia Huck <cohuck@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 2cd13a07c4..ee9b2f53ff 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1759,27 +1759,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:
 #
@@ -2146,46 +2125,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:
 #
@@ -2198,46 +2137,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 9bfbb54276..776f2da5e1 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -22,3 +22,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 f78a3aee9e..5d1ae89421 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");
@@ -4142,13 +4135,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 2a8dfa5058..5824ac793b 100644
--- a/qmp.c
+++ b/qmp.c
@@ -548,20 +548,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 212a5f0697..acd9b9698e 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -24,6 +24,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) \
     {                                                                    \
@@ -596,7 +597,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)
 {
@@ -669,7 +670,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 8cfe34328a..8288a27e34 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 47/51] target.json: add a note about query-cpu* not being s390x-specific
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (45 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 46/51] qapi: make s390 commands depend on TARGET_S390X Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 48/51] qapi: make query-gic-capabilities depend on TARGET_ARM Marc-André Lureau
                   ` (3 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

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

diff --git a/qapi/target.json b/qapi/target.json
index 776f2da5e1..ca463a0854 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -79,6 +79,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',
@@ -119,6 +122,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 48/51] qapi: make query-gic-capabilities depend on TARGET_ARM
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (46 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 47/51] target.json: add a note about query-cpu* not being s390x-specific Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 49/51] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
                   ` (2 subsequent siblings)
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	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 ee9b2f53ff..f444e684c0 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2899,49 +2899,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 ca463a0854..7494a7e58f 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -132,3 +132,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 5d1ae89421..ed719651d9 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
@@ -4135,14 +4132,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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 49/51] qapi: make query-cpu-model-expansion depend on s390 or x86
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (47 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 48/51] qapi: make query-gic-capabilities depend on TARGET_ARM Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 50/51] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 51/51] qapi: remove qmp_unregister_command() Marc-André Lureau
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost,
	Alexander Graf, open list:S390

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Acked-by: Cornelia Huck <cohuck@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 f444e684c0..b5b9103180 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2040,44 +2040,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 7494a7e58f..abf1423fba 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -177,3 +177,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 ed719651d9..707cc49385 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 5824ac793b..a1f42bcac8 100644
--- a/qmp.c
+++ b/qmp.c
@@ -541,13 +541,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 3818d72831..99f3688060 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -37,6 +37,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>
@@ -2645,7 +2646,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 acd9b9698e..8b83cc9cf9 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -558,7 +558,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 8288a27e34..b35bc8e473 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 50/51] qapi: make query-cpu-definitions depend on specific targets
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (48 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 49/51] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 51/51] qapi: remove qmp_unregister_command() Marc-André Lureau
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: eblake, armbru, Marc-André Lureau, Dr. David Alan Gilbert,
	Paolo Bonzini, Peter Maydell, Richard Henderson, Eduardo Habkost,
	David Gibson, Alexander Graf, open list:ARM, open list:PowerPC,
	open list:S390

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>
Acked-by: Cornelia Huck <cohuck@redhat.com>
---
 qapi-schema.json            | 10 ----------
 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(+), 53 deletions(-)
 delete mode 100644 stubs/arch-query-cpu-def.c

diff --git a/qapi-schema.json b/qapi-schema.json
index b5b9103180..b0b8e2806d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1965,16 +1965,6 @@
 ##
 { 'command': 'query-memory-size-summary', 'returns': 'MemoryInfo' }
 
-##
-# @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 abf1423fba..973da4a849 100644
--- a/qapi/target.json
+++ b/qapi/target.json
@@ -216,3 +216,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 707cc49385..a8d5af70ad 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 a1f42bcac8..4acf693edf 100644
--- a/qmp.c
+++ b/qmp.c
@@ -536,11 +536,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 d1395f9b73..eafa640687 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 */
 
@@ -5420,7 +5421,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 99f3688060..82c5d140bd 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -2385,7 +2385,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 70ff15a51a..b56218bb84 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -36,6 +36,7 @@
 #include "sysemu/qtest.h"
 #include "qemu/cutils.h"
 #include "disas/capstone.h"
+#include "target-qmp-commands.h"
 
 //#define PPC_DUMP_CPU
 //#define PPC_DEBUG_SPR
@@ -10293,7 +10294,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 8b83cc9cf9..52615b9f1b 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -424,7 +424,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 b35bc8e473..642584f26d 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.16.0.rc1.1.gef27df75a1

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

* [Qemu-devel] [PATCH v4 51/51] qapi: remove qmp_unregister_command()
  2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
                   ` (49 preceding siblings ...)
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 50/51] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
@ 2018-01-11 21:32 ` Marc-André Lureau
  50 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-11 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau, Michael Roth

This command is no longer needed after the schema is made conditional.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qapi/qmp/dispatch.h | 1 -
 qapi/qmp-registry.c         | 8 --------
 2 files changed, 9 deletions(-)

diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 20578dcd48..b2c8d2041c 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -38,7 +38,6 @@ typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList;
 
 void qmp_register_command(QmpCommandList *cmds, const char *name,
                           QmpCommandFunc *fn, QmpCommandOptions options);
-void qmp_unregister_command(QmpCommandList *cmds, const char *name);
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
 QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request);
 void qmp_disable_command(QmpCommandList *cmds, const char *name);
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
index 5af484cd9a..ca00f74795 100644
--- a/qapi/qmp-registry.c
+++ b/qapi/qmp-registry.c
@@ -27,14 +27,6 @@ void qmp_register_command(QmpCommandList *cmds, const char *name,
     QTAILQ_INSERT_TAIL(cmds, cmd, node);
 }
 
-void qmp_unregister_command(QmpCommandList *cmds, const char *name)
-{
-    QmpCommand *cmd = qmp_find_command(cmds, name);
-
-    QTAILQ_REMOVE(cmds, cmd, node);
-    g_free(cmd);
-}
-
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name)
 {
     QmpCommand *cmd;
-- 
2.16.0.rc1.1.gef27df75a1

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

* Re: [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int Marc-André Lureau
@ 2018-01-11 22:52   ` Eric Blake
  2018-02-05  6:05   ` Markus Armbruster
  1 sibling, 0 replies; 74+ messages in thread
From: Eric Blake @ 2018-01-11 22:52 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: armbru

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

On 01/11/2018 03:32 PM, Marc-André Lureau wrote:
> Suggested-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  include/qapi/qmp/qlit.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

> diff --git a/include/qapi/qmp/qlit.h b/include/qapi/qmp/qlit.h
> index b18406bce9..0c6809ef3c 100644
> --- a/include/qapi/qmp/qlit.h
> +++ b/include/qapi/qmp/qlit.h
> @@ -21,7 +21,7 @@ typedef struct QLitDictEntry QLitDictEntry;
>  typedef struct QLitObject QLitObject;
>  
>  struct QLitObject {
> -    int type;
> +    QType type;
>      union {
>          bool qbool;
>          int64_t qnum;
> 

-- 
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] 74+ messages in thread

* Re: [Qemu-devel] [PATCH v4 12/51] qapi-introspect: add preprocessor conditions to generated QLit
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 12/51] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
@ 2018-01-12 10:27   ` Marc-André Lureau
  0 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-12 10:27 UTC (permalink / raw)
  To: QEMU
  Cc: Eduardo Habkost, Michael Roth, Markus Armbruster, Cleber Rosa,
	Marc-André Lureau

Hi

On Thu, Jan 11, 2018 at 10:32 PM, Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
> The generator will take (obj, condition) tuples to wrap generated QLit
> objects for 'obj' with #if/#endif conditions.
>
> This commit adds 'ifcond' condition to top-level QLit objects.
>
> See generated tests/test-qmp-introspect.c. Example diff after this patch:
>
> --- before      2018-01-08 11:55:24.757083654 +0100
> +++ tests/test-qmp-introspect.c 2018-01-08 13:08:44.477641629 +0100
> @@ -51,6 +51,8 @@
>          { "name", QLIT_QSTR("EVENT_F"), },
>          {}
>      })),
> +#if defined(TEST_IF_CMD)
> +#if defined(TEST_IF_STRUCT)
>      QLIT_QDICT(((QLitDictEntry[]) {
>          { "arg-type", QLIT_QSTR("5"), },
>          { "meta-type", QLIT_QSTR("command"), },
> @@ -58,12 +60,16 @@
>          { "ret-type", QLIT_QSTR("0"), },
>          {}
>      })),
> +#endif /* defined(TEST_IF_STRUCT) */
> +#endif /* defined(TEST_IF_CMD) */
>

My bad, this comment causes git am (and patchew) to fail to apply. FIxed.

The series is also available on https://github.com/elmarco/qemu/commits/qapi-if

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi-introspect.py | 31 +++++++++++++++++++++----------
>  1 file changed, 21 insertions(+), 10 deletions(-)
>
> diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
> index b1d08ec97b..7d3a5c37fd 100644
> --- a/scripts/qapi-introspect.py
> +++ b/scripts/qapi-introspect.py
> @@ -17,6 +17,15 @@ 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)
> +        endif = gen_endif(ifcond)
> +        if endif:
> +            ret += '\n' + endif
> +        return ret
> +
>      ret = ''
>      if not suppress_first_indent:
>          ret += indent(level)
> @@ -25,7 +34,7 @@ def to_qlit(obj, level=0, suppress_first_indent=False):
>      elif isinstance(obj, str):
>          ret += 'QLIT_QSTR(' + to_c_string(obj) + ')'
>      elif isinstance(obj, list):
> -        elts = [to_qlit(elt, level + 1)
> +        elts = [to_qlit(elt, level + 1).strip('\n')
>                  for elt in obj]
>          elts.append(indent(level + 1) + "{}")
>          ret += 'QLIT_QLIST(((QLitObject[]) {\n'
> @@ -121,12 +130,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)}
> @@ -142,26 +151,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}, [])
>
>      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):
> @@ -169,11 +179,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.16.0.rc1.1.gef27df75a1
>
>



-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma Marc-André Lureau
@ 2018-01-12 11:54   ` Marc-André Lureau
  2018-02-05 18:13     ` Markus Armbruster
  0 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-12 11:54 UTC (permalink / raw)
  To: QEMU
  Cc: Eduardo Habkost, Markus Armbruster, Michael Roth, Cleber Rosa,
	Marc-André Lureau

Hi

On Thu, Jan 11, 2018 at 10:32 PM, Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
> Add a pragma that allows to tag the following expressions in the
> schema with a unit name. By default, an expression has no unit name.
>
> See the docs/devel/qapi-code-gen.txt for more details.
>

I inadvertently merged the following patch "qapi: add a -u/--unit
option to specify which unit to visit" with this one.

Fixed in the github branch: https://github.com/elmarco/qemu/commits/qapi-if


> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py                            | 22 +++++++++++++++++++---
>  docs/devel/qapi-code-gen.txt               |  4 ++++
>  tests/Makefile.include                     |  7 ++++++-
>  tests/qapi-schema/pragma-unit-invalid.err  |  1 +
>  tests/qapi-schema/pragma-unit-invalid.exit |  1 +
>  tests/qapi-schema/pragma-unit-invalid.json |  3 +++
>  tests/qapi-schema/pragma-unit-invalid.out  |  0
>  tests/qapi-schema/qapi-schema-test.json    |  6 +++++-
>  tests/qapi-schema/qapi-schema-test.out     |  2 ++
>  9 files changed, 41 insertions(+), 5 deletions(-)
>  create mode 100644 tests/qapi-schema/pragma-unit-invalid.err
>  create mode 100644 tests/qapi-schema/pragma-unit-invalid.exit
>  create mode 100644 tests/qapi-schema/pragma-unit-invalid.json
>  create mode 100644 tests/qapi-schema/pragma-unit-invalid.out
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index f56460d028..07e738c3f1 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 names to include for the visit (default to all units)
> +visit_units = []
> +
>  enum_types = {}
>  struct_types = {}
>  union_types = {}
> @@ -269,11 +272,12 @@ class QAPISchemaParser(object):
>          self.exprs = []
>          self.docs = []
>          self.accept()
> +        self.unit = None
>          cur_doc = None
>
>          while self.tok is not None:
>              info = {'file': self.fname, 'line': self.line,
> -                    'parent': self.incl_info}
> +                    'parent': self.incl_info, 'unit': self.unit}
>              if self.tok == '#':
>                  self.reject_expr_doc(cur_doc)
>                  cur_doc = self.get_doc(info)
> @@ -362,6 +366,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)
>
> @@ -1827,6 +1836,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_units and unit not in visit_units:
> +                continue
>              if visitor.visit_needed(entity):
>                  entity.visit(visitor)
>          visitor.visit_end()
> @@ -2126,13 +2139,14 @@ def parse_command_line(extra_options='', extra_long_options=[]):
>
>      try:
>          opts, args = getopt.gnu_getopt(
> -            sys.argv[1:], 'chp:o:i:' + extra_options,
> +            sys.argv[1:], '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_units
>      output_dir = ''
>      prefix = ''
>      do_c = False
> @@ -2152,6 +2166,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_units.append(a)
>          elif o in ('-c', '--source'):
>              do_c = True
>          elif o in ('-h', '--header'):
> diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
> index 479b755609..31bcbdac58 100644
> --- a/docs/devel/qapi-code-gen.txt
> +++ b/docs/devel/qapi-code-gen.txt
> @@ -326,6 +326,10 @@ 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 generators can filter
> +based on a unit name.  This allows to select a subset of the
> +expressions.  Default is none.
>
>  === Struct types ===
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 2b83f05954..2f39e2d5aa 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -510,6 +510,7 @@ qapi-schema += pragma-extra-junk.json
>  qapi-schema += pragma-name-case-whitelist-crap.json
>  qapi-schema += pragma-non-dict.json
>  qapi-schema += pragma-returns-whitelist-crap.json
> +qapi-schema += pragma-unit-invalid.json
>  qapi-schema += qapi-schema-test.json
>  qapi-schema += quoted-structural-chars.json
>  qapi-schema += redefined-builtin.json
> @@ -665,13 +666,17 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-com
>  tests/test-qapi-event.c tests/test-qapi-event.h :\
>  $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py $(qapi-py)
>         $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
> -               $(gen-out-type) -o tests -p "test-" $<, \
> +               $(gen-out-type) -o tests -p "test-" -u test-unit $<, \
>                 "GEN","$@")
> +# check that another-unit is not included
> +       $(call quiet-command,[ $(gen-out-type) == -h ] || grep -v -q ANOTHER_EVENT $@,"TEST","$@")
>  tests/test-qmp-introspect.c tests/test-qmp-introspect.h :\
>  $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
>         $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
>                 $(gen-out-type) -o tests -p "test-" $<, \
>                 "GEN","$@")
> +# check all units are included
> +       $(call quiet-command,[ $(gen-out-type) == -h ] || grep -q ANOTHER_EVENT $@,"TEST","$@")
>
>  tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.json $(SRC_PATH)/scripts/qapi2texi.py $(qapi-py)
>         $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
> diff --git a/tests/qapi-schema/pragma-unit-invalid.err b/tests/qapi-schema/pragma-unit-invalid.err
> new file mode 100644
> index 0000000000..e22176d42e
> --- /dev/null
> +++ b/tests/qapi-schema/pragma-unit-invalid.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/pragma-unit-invalid.json:3: Pragma 'unit' must be string
> diff --git a/tests/qapi-schema/pragma-unit-invalid.exit b/tests/qapi-schema/pragma-unit-invalid.exit
> new file mode 100644
> index 0000000000..d00491fd7e
> --- /dev/null
> +++ b/tests/qapi-schema/pragma-unit-invalid.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/pragma-unit-invalid.json b/tests/qapi-schema/pragma-unit-invalid.json
> new file mode 100644
> index 0000000000..636b53939a
> --- /dev/null
> +++ b/tests/qapi-schema/pragma-unit-invalid.json
> @@ -0,0 +1,3 @@
> +# Value of 'unit' pragma must be a string
> +
> +{ 'pragma': { 'unit': {} } }
> diff --git a/tests/qapi-schema/pragma-unit-invalid.out b/tests/qapi-schema/pragma-unit-invalid.out
> new file mode 100644
> index 0000000000..e69de29bb2
> diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
> index cd33c084cb..2fb1d3449c 100644
> --- a/tests/qapi-schema/qapi-schema-test.json
> +++ b/tests/qapi-schema/qapi-schema-test.json
> @@ -8,7 +8,8 @@
>      # Commands allowed to return a non-dictionary:
>      'returns-whitelist': [
>          'guest-get-time',
> -        'guest-sync' ] } }
> +        'guest-sync' ],
> +    'unit': 'test-unit' } }
>
>  { 'struct': 'TestStruct',
>    'data': { 'integer': {'type': 'int'}, 'boolean': 'bool', 'string': 'str' } }
> @@ -224,3 +225,6 @@
>    { 'foo': 'TestIfStruct',
>      'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_EVT_BAR)' } },
>    'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
> +
> +{ 'pragma': { 'unit': 'another-unit' } }
> +{ 'event': 'ANOTHER_EVENT' }
> diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
> index 7215aeb4a6..cbc61fc3a2 100644
> --- a/tests/qapi-schema/qapi-schema-test.out
> +++ b/tests/qapi-schema/qapi-schema-test.out
> @@ -1,3 +1,5 @@
> +event ANOTHER_EVENT None
> +   boxed=False
>  alternate AltEnumBool
>      tag type
>      case e: EnumOne
> --
> 2.16.0.rc1.1.gef27df75a1
>
>



-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v4 37/51] qapi: add conditions to VNC type/commands/events on the schema
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 37/51] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
@ 2018-01-12 13:04   ` Gerd Hoffmann
  2018-01-12 13:22     ` Marc-André Lureau
  0 siblings, 1 reply; 74+ messages in thread
From: Gerd Hoffmann @ 2018-01-12 13:04 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, eblake, armbru, Dr. David Alan Gilbert

> 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

Is this header files used even on !vnc builds?

> diff --git a/hmp.c b/hmp.c
> index 2d72f94193..0612ddc621 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -613,6 +613,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)
> @@ -700,6 +701,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict)
>      qapi_free_VncInfo2List(info2l);
>  
>  }
> +#endif

Move to ui/vnc.c, so we don't need #ifdef here?

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v4 38/51] qapi: add conditions to SPICE type/commands/events on the schema
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 38/51] qapi: add conditions to SPICE " Marc-André Lureau
@ 2018-01-12 13:09   ` Gerd Hoffmann
  0 siblings, 0 replies; 74+ messages in thread
From: Gerd Hoffmann @ 2018-01-12 13:09 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, eblake, armbru, Dr. David Alan Gilbert, Paolo Bonzini

On Thu, Jan 11, 2018 at 10:32:37PM +0100, Marc-André Lureau wrote:
> Add #if defined(CONFIG_SPICE) in generated code, and adjust the
> qmp/hmp code accordingly.
> 
> query-qmp-schema no longer reports the command/events etc as
> available when disabled at compile time.
> 
> Commands made conditional:
> 
> * query-spice
> 
>   Before the patch, the command for !CONFIG_SPICE is unregistered. It
>   will fail with the same error.
> 
> Events made conditional:
> 
> * SPICE_CONNECTED, SPICE_INITIALIZED, SPICE_DISCONNECTED,
>   SPICE_MIGRATE_COMPLETED
> 
> Chardev made conditional:
> 
> * spiceport, spicevmc
> 
>   Before and after the patch for !CONFIG_SPICE, the error is the
>   same ('spiceport' is not a valid char driver name).
> 
> No HMP change, the code was already conditional.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Looks good to me.

Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v4 37/51] qapi: add conditions to VNC type/commands/events on the schema
  2018-01-12 13:04   ` Gerd Hoffmann
@ 2018-01-12 13:22     ` Marc-André Lureau
  2018-01-12 13:55       ` Gerd Hoffmann
  0 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-01-12 13:22 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, eblake, armbru, Dr. David Alan Gilbert

Hi

----- Original Message -----
> > 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
> 
> Is this header files used even on !vnc builds?

Yes, in qmp.c.

it looks like it is possible to cleanup the code to not include it (same for spice etc), but I would rather keep this for a future TODO.

> 
> > diff --git a/hmp.c b/hmp.c
> > index 2d72f94193..0612ddc621 100644
> > --- a/hmp.c
> > +++ b/hmp.c
> > @@ -613,6 +613,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)
> > @@ -700,6 +701,7 @@ void hmp_info_vnc(Monitor *mon, const QDict *qdict)
> >      qapi_free_VncInfo2List(info2l);
> >  
> >  }
> > +#endif
> 
> Move to ui/vnc.c, so we don't need #ifdef here?

Not so simple either. hmp-commands-info.h (needed for the function declaration) is built per target, but not ui/vnc.c. Again, some future cleanup?

thanks

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

* Re: [Qemu-devel] [PATCH v4 37/51] qapi: add conditions to VNC type/commands/events on the schema
  2018-01-12 13:22     ` Marc-André Lureau
@ 2018-01-12 13:55       ` Gerd Hoffmann
  0 siblings, 0 replies; 74+ messages in thread
From: Gerd Hoffmann @ 2018-01-12 13:55 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, eblake, armbru, Dr. David Alan Gilbert

  Hi,

> > Move to ui/vnc.c, so we don't need #ifdef here?
> 
> Not so simple either. hmp-commands-info.h (needed for the function
> declaration) is built per target, but not ui/vnc.c.

Ok, thanks for checking.

> Again, some future cleanup?

Fine with me.

Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>

cheers,
  Gerd

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

* Re: [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int Marc-André Lureau
  2018-01-11 22:52   ` Eric Blake
@ 2018-02-05  6:05   ` Markus Armbruster
  1 sibling, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-05  6:05 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

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

> Suggested-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  include/qapi/qmp/qlit.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/qapi/qmp/qlit.h b/include/qapi/qmp/qlit.h
> index b18406bce9..0c6809ef3c 100644
> --- a/include/qapi/qmp/qlit.h
> +++ b/include/qapi/qmp/qlit.h
> @@ -21,7 +21,7 @@ typedef struct QLitDictEntry QLitDictEntry;
>  typedef struct QLitObject QLitObject;
>  
>  struct QLitObject {
> -    int type;
> +    QType type;
>      union {
>          bool qbool;
>          int64_t qnum;

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

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

* Re: [Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions Marc-André Lureau
@ 2018-02-05  6:12   ` Markus Armbruster
  0 siblings, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-05  6:12 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Michael Roth, Cleber Rosa

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>
> ---
>  scripts/qapi.py                          | 36 ++++++++++++++++++++++++++------
>  tests/test-qmp-commands.c                |  6 ++++++
>  tests/Makefile.include                   |  4 ++++
>  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-list.err        |  1 +
>  tests/qapi-schema/bad-if-list.exit       |  1 +
>  tests/qapi-schema/bad-if-list.json       |  3 +++
>  tests/qapi-schema/bad-if-list.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/qapi-schema-test.json  | 20 ++++++++++++++++++
>  tests/qapi-schema/qapi-schema-test.out   | 22 +++++++++++++++++++
>  21 files changed, 102 insertions(+), 6 deletions(-)
>  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-list.err
>  create mode 100644 tests/qapi-schema/bad-if-list.exit
>  create mode 100644 tests/qapi-schema/bad-if-list.json
>  create mode 100644 tests/qapi-schema/bad-if-list.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/scripts/qapi.py b/scripts/qapi.py
> index 43a54bf40f..27df0fcf48 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -630,6 +630,27 @@ def add_name(name, info, meta, implicit=False):
>      all_names[name] = meta
>  
>  
> +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.get('if')
> +    if ifcond is None:
> +        return
> +    elif isinstance(ifcond, list):

Suggest s/elif/if/

> +        if ifcond == []:
> +            raise QAPISemError(info, "'if' condition [] is useless")
> +        for elt in ifcond:
> +            check_if_str(elt, info)
> +    else:
> +        check_if_str(ifcond, info)
> +
> +
>  def check_type(info, source, value, allow_array=False,
>                 allow_dict=False, allow_optional=False,
>                 allow_metas=[]):

R-by stands.

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

* Re: [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
@ 2018-02-05  6:16   ` Markus Armbruster
  2018-02-06 10:12   ` Markus Armbruster
  1 sibling, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-05  6:16 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Michael Roth, Cleber Rosa

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 wrapped type's generated for simple union variants,

Editing accident: you changed "is the wrapper types" to "is the wrapped
type's" here instead of

> 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

changing "use wrapped type's"  to "use the wrapped type's" here.  Can
touch up on commit.

> simpler and good enough for now.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> Reviewed-by: Markus Armbruster <armbru@redhat.com>

R-by stands.

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

* Re: [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check()
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check() Marc-André Lureau
@ 2018-02-05  6:22   ` Markus Armbruster
  2018-02-06 11:20   ` Markus Armbruster
  1 sibling, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-05  6:22 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Michael Roth, Cleber Rosa

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

> 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.
>
> Leave the ifcond attribute undefined until check().
>
> Suggested-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Shouldn't this be squashed into the previous patch?

> ---
>  scripts/qapi.py | 21 +++++++++++++++++----
>  1 file changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 8f54dead8d..4d2c214f19 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1011,13 +1011,19 @@ class QAPISchemaEntity(object):
>          # such place).
>          self.info = info
>          self.doc = doc
> -        self.ifcond = listify_cond(ifcond)
> +        self._ifcond = ifcond  # self.ifcond is set after check()

Suggest either "only after .check" or "in .check()".

>  
>      def c_name(self):
>          return c_name(self.name)
>  
>      def check(self, schema):
> -        pass
> +        if isinstance(self._ifcond, QAPISchemaType):
> +            # inherit the condition from a type
> +            typ = self._ifcond
> +            typ.check(schema)
> +            self.ifcond = typ.ifcond
> +        else:
> +            self.ifcond = listify_cond(self._ifcond)
>  
>      def is_implicit(self):
>          return not self.info
> @@ -1138,6 +1144,7 @@ class QAPISchemaEnumType(QAPISchemaType):
>          self.prefix = prefix
>  
>      def check(self, schema):
> +        QAPISchemaType.check(self, schema)
>          seen = {}
>          for v in self.values:
>              v.check_clash(self.info, seen)
> @@ -1170,8 +1177,10 @@ class QAPISchemaArrayType(QAPISchemaType):
>          self.element_type = None
>  
>      def check(self, schema):
> +        QAPISchemaType.check(self, schema)
>          self.element_type = schema.lookup_type(self._element_type_name)
>          assert self.element_type
> +        self.element_type.check(schema)
>          self.ifcond = self.element_type.ifcond
>  
>      def is_implicit(self):
> @@ -1214,6 +1223,7 @@ class QAPISchemaObjectType(QAPISchemaType):
>          self.members = None
>  
>      def check(self, schema):
> +        QAPISchemaType.check(self, schema)
>          if self.members is False:               # check for cycles
>              raise QAPISemError(self.info,
>                                 "Object %s contains itself" % self.name)
> @@ -1396,6 +1406,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
>          self.variants = variants
>  
>      def check(self, schema):
> +        QAPISchemaType.check(self, schema)
>          self.variants.tag_member.check(schema)
>          # Not calling self.variants.check_clash(), because there's nothing
>          # to clash with
> @@ -1438,6 +1449,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
>          self.boxed = boxed
>  
>      def check(self, schema):
> +        QAPISchemaEntity.check(self, schema)
>          if self._arg_type_name:
>              self.arg_type = schema.lookup_type(self._arg_type_name)
>              assert (isinstance(self.arg_type, QAPISchemaObjectType) or
> @@ -1471,6 +1483,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
>          self.boxed = boxed
>  
>      def check(self, schema):
> +        QAPISchemaEntity.check(self, schema)
>          if self._arg_type_name:
>              self.arg_type = schema.lookup_type(self._arg_type_name)
>              assert (isinstance(self.arg_type, QAPISchemaObjectType) or
> @@ -1589,7 +1602,7 @@ class QAPISchema(object):
>              # 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
> +            assert ifcond == typ._ifcond
>          else:
>              self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
>                                                    None, members, None))
> @@ -1635,7 +1648,7 @@ class QAPISchema(object):
>              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,
> +            typ, info, None, self.lookup_type(typ),
>              'wrapper', [self._make_member('data', typ, info)])
>          return QAPISchemaObjectTypeVariant(case, typ)

I figure other attributes that become valid only at .check() time should
receive the same treatment.  Not necessarily in this series, not
necessarily by you.  A TODO comment wouldn't hurt, though.

I have only comment improvements, so:
Reviewed-by: Markus Armbruster <armbru@redhat.com>

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

* Re: [Qemu-devel] [PATCH v4 10/51] qapi: add #if/#endif helpers
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 10/51] qapi: add #if/#endif helpers Marc-André Lureau
@ 2018-02-05  7:03   ` Markus Armbruster
  0 siblings, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-05  7:03 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Michael Roth, Cleber Rosa

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 | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 47 insertions(+)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 3d33ed7d76..71f28fc6d8 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1911,6 +1911,53 @@ def guardend(name):
>                   name=guardname(name))
>  
>  
> +def gen_if(ifcond):
> +    ret = ''
> +    for ifc in ifcond:
> +        ret += mcgen('''
> +#if %(cond)s
> +''', cond=ifc)
> +    return ret
> +
> +
> +def gen_endif(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('''

I dislike this as much as ever, but I lack the time to explore
alternatives right now, and I don't want to block your work.

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

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

* Re: [Qemu-devel] [PATCH v4 41/51] qapi: add -i/--include filename.h
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 41/51] qapi: add -i/--include filename.h Marc-André Lureau
@ 2018-02-05 16:58   ` Markus Armbruster
  0 siblings, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-05 16:58 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Michael Roth, Cleber Rosa

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.
>
> Fix some pycodestyle on the way.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

With my alternative way to split up the generated monolith[*], required
generated headers should be included without the user's help.

We might conceivably need an ability to add includes for other purposes.
As far as I can tell, this is not the case in your series.

If we need the ability, then I'd rather use a directive in the schema
than a command line option.


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

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

* Re: [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma
  2018-01-12 11:54   ` Marc-André Lureau
@ 2018-02-05 18:13     ` Markus Armbruster
  2018-02-06 11:01       ` Marc-André Lureau
  0 siblings, 1 reply; 74+ messages in thread
From: Markus Armbruster @ 2018-02-05 18:13 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: QEMU, Michael Roth, Marc-André Lureau, Cleber Rosa, Eduardo Habkost

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

> Hi
>
> On Thu, Jan 11, 2018 at 10:32 PM, Marc-André Lureau
> <marcandre.lureau@redhat.com> wrote:
>> Add a pragma that allows to tag the following expressions in the
>> schema with a unit name. By default, an expression has no unit name.
>>
>> See the docs/devel/qapi-code-gen.txt for more details.
>>
>
> I inadvertently merged the following patch "qapi: add a -u/--unit
> option to specify which unit to visit" with this one.
>
> Fixed in the github branch: https://github.com/elmarco/qemu/commits/qapi-if

Looks like it's still messed up: the patch there adds the pragma to
docs/devel/qapi-code-gen.txt, the test cases, but no code.  Make check
fails.  The code appears to be in the next patch.  Please advise.

[...]

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

* Re: [Qemu-devel] [PATCH v4 03/51] qapi: generate a literal qobject for introspection
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 03/51] qapi: generate a literal qobject for introspection Marc-André Lureau
@ 2018-02-06 10:04   ` Markus Armbruster
  2018-02-06 11:01     ` Marc-André Lureau
  0 siblings, 1 reply; 74+ messages in thread
From: Markus Armbruster @ 2018-02-06 10:04 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Dr. David Alan Gilbert, Cleber Rosa,
	Michael Roth

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>

I verified that the output of query-qmp-schema is not changed.
Mentioning that in the commit message wouldn't hurt.

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

* Re: [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
  2018-02-05  6:16   ` Markus Armbruster
@ 2018-02-06 10:12   ` Markus Armbruster
  2018-02-06 11:06     ` Marc-André Lureau
  1 sibling, 1 reply; 74+ messages in thread
From: Markus Armbruster @ 2018-02-06 10:12 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Michael Roth, Cleber Rosa

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 wrapped type's 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>
> Reviewed-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 98 ++++++++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 66 insertions(+), 32 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 27df0fcf48..8f54dead8d 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -991,8 +991,17 @@ def check_exprs(exprs):
>  # Schema compiler frontend
>  #
>  
> +def listify_cond(ifcond):
> +    if not ifcond:
> +        return []
> +    elif not isinstance(ifcond, list):
> +        return [ifcond]
> +    else:
> +        return ifcond

pylint complains:

    R:995, 4: Unnecessary "else" after "return" (no-else-return)

Matter of taste.  Mine happens to agree with pylint's.  Suggest:

   def listify_cond(ifcond):
       if not ifcond:
           return []
       if not isinstance(ifcond, list):
           return [ifcond]
       return ifcond

> +
> +
>  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)
[...]

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

* Re: [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma
  2018-02-05 18:13     ` Markus Armbruster
@ 2018-02-06 11:01       ` Marc-André Lureau
  2018-02-06 12:31         ` Markus Armbruster
  0 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-02-06 11:01 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: QEMU, Michael Roth, Cleber Rosa, Eduardo Habkost

On Mon, Feb 5, 2018 at 7:13 PM, Markus Armbruster <armbru@redhat.com> wrote:
> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>
>> Hi
>>
>> On Thu, Jan 11, 2018 at 10:32 PM, Marc-André Lureau
>> <marcandre.lureau@redhat.com> wrote:
>>> Add a pragma that allows to tag the following expressions in the
>>> schema with a unit name. By default, an expression has no unit name.
>>>
>>> See the docs/devel/qapi-code-gen.txt for more details.
>>>
>>
>> I inadvertently merged the following patch "qapi: add a -u/--unit
>> option to specify which unit to visit" with this one.
>>
>> Fixed in the github branch: https://github.com/elmarco/qemu/commits/qapi-if
>
> Looks like it's still messed up: the patch there adds the pragma to
> docs/devel/qapi-code-gen.txt, the test cases, but no code.  Make check
> fails.  The code appears to be in the next patch.  Please advise.
>

More rebase mistakes.. fixed in github.

How do you want to proceed? The -u/-i options from this series seems
unnecessary one we have the "modularize generated qapi code" you
proposed. But -i/-u can easily be removed too later on, depending on
what goes first.

If you can take the first patches of the series, and tell me based on
what I should rebase or what to expect, I can keep working on it. In
the meantime, I am a bit stuck.

-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v4 03/51] qapi: generate a literal qobject for introspection
  2018-02-06 10:04   ` Markus Armbruster
@ 2018-02-06 11:01     ` Marc-André Lureau
  0 siblings, 0 replies; 74+ messages in thread
From: Marc-André Lureau @ 2018-02-06 11:01 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Michael Roth, Cleber Rosa, QEMU, Dr. David Alan Gilbert, Eduardo Habkost

On Tue, Feb 6, 2018 at 11:04 AM, Markus Armbruster <armbru@redhat.com> wrote:
> 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>
>
> I verified that the output of query-qmp-schema is not changed.
> Mentioning that in the commit message wouldn't hurt.
>

Sure, feel free to touch if you pick it

-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects
  2018-02-06 10:12   ` Markus Armbruster
@ 2018-02-06 11:06     ` Marc-André Lureau
  2018-02-06 12:14       ` Markus Armbruster
  0 siblings, 1 reply; 74+ messages in thread
From: Marc-André Lureau @ 2018-02-06 11:06 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Michael Roth, Cleber Rosa, QEMU, Eduardo Habkost

Hi

On Tue, Feb 6, 2018 at 11:12 AM, Markus Armbruster <armbru@redhat.com> wrote:
> 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 wrapped type's 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>
>> Reviewed-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi.py | 98 ++++++++++++++++++++++++++++++++++++++-------------------
>>  1 file changed, 66 insertions(+), 32 deletions(-)
>>
>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>> index 27df0fcf48..8f54dead8d 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -991,8 +991,17 @@ def check_exprs(exprs):
>>  # Schema compiler frontend
>>  #
>>
>> +def listify_cond(ifcond):
>> +    if not ifcond:
>> +        return []
>> +    elif not isinstance(ifcond, list):
>> +        return [ifcond]
>> +    else:
>> +        return ifcond
>
> pylint complains:
>
>     R:995, 4: Unnecessary "else" after "return" (no-else-return)
>
> Matter of taste.  Mine happens to agree with pylint's.  Suggest:
>
>    def listify_cond(ifcond):
>        if not ifcond:
>            return []
>        if not isinstance(ifcond, list):
>            return [ifcond]
>        return ifcond
>

There are so many errors with pylint, that I don't bother running it.
How did you notice? you run diff of error output between commits?

pycodestyle --diff is more convenient, and silent on this code.

Feel free to touch if you pick the patch.

>> +
>> +
>>  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)
> [...]
>



-- 
Marc-André Lureau

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

* Re: [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check()
  2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check() Marc-André Lureau
  2018-02-05  6:22   ` Markus Armbruster
@ 2018-02-06 11:20   ` Markus Armbruster
  1 sibling, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-06 11:20 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Michael Roth, Cleber Rosa

Second thoughts...

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

> 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.
>
> Leave the ifcond attribute undefined until check().
>
> Suggested-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py | 21 +++++++++++++++++----
>  1 file changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 8f54dead8d..4d2c214f19 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1011,13 +1011,19 @@ class QAPISchemaEntity(object):
>          # such place).
>          self.info = info
>          self.doc = doc
> -        self.ifcond = listify_cond(ifcond)
> +        self._ifcond = ifcond  # self.ifcond is set after check()
>  
>      def c_name(self):
>          return c_name(self.name)
>  
>      def check(self, schema):
> -        pass
> +        if isinstance(self._ifcond, QAPISchemaType):
> +            # inherit the condition from a type
> +            typ = self._ifcond
> +            typ.check(schema)
> +            self.ifcond = typ.ifcond
> +        else:
> +            self.ifcond = listify_cond(self._ifcond)

Whenever we add a .check(), we need to prove QAPISchema.check()'s
recursion still terminates, and terminates the right way.

Argument before this patch: we recurse only into types contained in
types, e.g. an object type's base type, and we detect and report cycles
as "Object %s contains itself", in QAPISchemaObjectType.check().

The .check() added here recurses into a type.  If this creates a cycle,
it'll be caught and reported as "contains itself".  We still need to
show that the error message remains accurate.

We .check() here to inherit .ifcond from a type.  As far as I can tell,
we use this inheritance feature only to inherit an array's condition
from its element type.  That's safe, because an array does contain its
elements.

This is hardly a rigorous proof.  Just enough to make me believe your
code works.

However, I suspect adding the inheritance feature at the entity level
complicates the correctness argument without real need.  Can we restrict
it to array elements?  Have QAPISchemaArrayType.check() resolve
type-valued ._ifcond, and all the others choke on it?

>  
>      def is_implicit(self):
>          return not self.info
> @@ -1138,6 +1144,7 @@ class QAPISchemaEnumType(QAPISchemaType):
>          self.prefix = prefix
>  
>      def check(self, schema):
> +        QAPISchemaType.check(self, schema)
>          seen = {}
>          for v in self.values:
>              v.check_clash(self.info, seen)
> @@ -1170,8 +1177,10 @@ class QAPISchemaArrayType(QAPISchemaType):
>          self.element_type = None
>  
>      def check(self, schema):
> +        QAPISchemaType.check(self, schema)
>          self.element_type = schema.lookup_type(self._element_type_name)
>          assert self.element_type
> +        self.element_type.check(schema)

This .check is locally obvious: an array contains its elements.

>          self.ifcond = self.element_type.ifcond
>  
>      def is_implicit(self):
> @@ -1214,6 +1223,7 @@ class QAPISchemaObjectType(QAPISchemaType):
>          self.members = None
>  
>      def check(self, schema):
> +        QAPISchemaType.check(self, schema)
>          if self.members is False:               # check for cycles
>              raise QAPISemError(self.info,
>                                 "Object %s contains itself" % self.name)
> @@ -1396,6 +1406,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
>          self.variants = variants
>  
>      def check(self, schema):
> +        QAPISchemaType.check(self, schema)
>          self.variants.tag_member.check(schema)
>          # Not calling self.variants.check_clash(), because there's nothing
>          # to clash with
> @@ -1438,6 +1449,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
>          self.boxed = boxed
>  
>      def check(self, schema):
> +        QAPISchemaEntity.check(self, schema)
>          if self._arg_type_name:
>              self.arg_type = schema.lookup_type(self._arg_type_name)
>              assert (isinstance(self.arg_type, QAPISchemaObjectType) or
> @@ -1471,6 +1483,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
>          self.boxed = boxed
>  
>      def check(self, schema):
> +        QAPISchemaEntity.check(self, schema)
>          if self._arg_type_name:
>              self.arg_type = schema.lookup_type(self._arg_type_name)
>              assert (isinstance(self.arg_type, QAPISchemaObjectType) or
> @@ -1589,7 +1602,7 @@ class QAPISchema(object):
>              # 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
> +            assert ifcond == typ._ifcond

pylint complains

    W:1605,29: Access to a protected member _ifcond of a client class (protected-access)

Layering violation.  Tolerable, I think.

>          else:
>              self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
>                                                    None, members, None))
> @@ -1635,7 +1648,7 @@ class QAPISchema(object):
>              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,
> +            typ, info, None, self.lookup_type(typ),
>              'wrapper', [self._make_member('data', typ, info)])
>          return QAPISchemaObjectTypeVariant(case, typ)

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

* Re: [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects
  2018-02-06 11:06     ` Marc-André Lureau
@ 2018-02-06 12:14       ` Markus Armbruster
  0 siblings, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-06 12:14 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU, Michael Roth, Eduardo Habkost, Cleber Rosa

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

> Hi
>
> On Tue, Feb 6, 2018 at 11:12 AM, Markus Armbruster <armbru@redhat.com> wrote:
>> 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 wrapped type's 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>
>>> Reviewed-by: Markus Armbruster <armbru@redhat.com>
>>> ---
>>>  scripts/qapi.py | 98 ++++++++++++++++++++++++++++++++++++++-------------------
>>>  1 file changed, 66 insertions(+), 32 deletions(-)
>>>
>>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>>> index 27df0fcf48..8f54dead8d 100644
>>> --- a/scripts/qapi.py
>>> +++ b/scripts/qapi.py
>>> @@ -991,8 +991,17 @@ def check_exprs(exprs):
>>>  # Schema compiler frontend
>>>  #
>>>
>>> +def listify_cond(ifcond):
>>> +    if not ifcond:
>>> +        return []
>>> +    elif not isinstance(ifcond, list):
>>> +        return [ifcond]
>>> +    else:
>>> +        return ifcond
>>
>> pylint complains:
>>
>>     R:995, 4: Unnecessary "else" after "return" (no-else-return)
>>
>> Matter of taste.  Mine happens to agree with pylint's.  Suggest:
>>
>>    def listify_cond(ifcond):
>>        if not ifcond:
>>            return []
>>        if not isinstance(ifcond, list):
>>            return [ifcond]
>>        return ifcond
>>
>
> There are so many errors with pylint, that I don't bother running it.

pylint reports lots of stuff that is actually just fine.

> How did you notice? you run diff of error output between commits?

Yes.

> pycodestyle --diff is more convenient, and silent on this code.

Formerly known as pep8.  Confusingly, Fedora 26 packages both
separately.  Thanks for the pointer.

> Feel free to touch if you pick the patch.

Okay.

>>> +
>>> +
>>>  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)
>> [...]
>>

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

* Re: [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma
  2018-02-06 11:01       ` Marc-André Lureau
@ 2018-02-06 12:31         ` Markus Armbruster
  0 siblings, 0 replies; 74+ messages in thread
From: Markus Armbruster @ 2018-02-06 12:31 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: Cleber Rosa, QEMU, Eduardo Habkost, Michael Roth

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

> On Mon, Feb 5, 2018 at 7:13 PM, Markus Armbruster <armbru@redhat.com> wrote:
>> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>>
>>> Hi
>>>
>>> On Thu, Jan 11, 2018 at 10:32 PM, Marc-André Lureau
>>> <marcandre.lureau@redhat.com> wrote:
>>>> Add a pragma that allows to tag the following expressions in the
>>>> schema with a unit name. By default, an expression has no unit name.
>>>>
>>>> See the docs/devel/qapi-code-gen.txt for more details.
>>>>
>>>
>>> I inadvertently merged the following patch "qapi: add a -u/--unit
>>> option to specify which unit to visit" with this one.
>>>
>>> Fixed in the github branch: https://github.com/elmarco/qemu/commits/qapi-if
>>
>> Looks like it's still messed up: the patch there adds the pragma to
>> docs/devel/qapi-code-gen.txt, the test cases, but no code.  Make check
>> fails.  The code appears to be in the next patch.  Please advise.
>>
>
> More rebase mistakes.. fixed in github.
>
> How do you want to proceed? The -u/-i options from this series seems
> unnecessary one we have the "modularize generated qapi code" you
> proposed. But -i/-u can easily be removed too later on, depending on
> what goes first.

Modularization first would be less churn.  But it's not quite complete,
yet.

> If you can take the first patches of the series, and tell me based on
> what I should rebase or what to expect, I can keep working on it. In
> the meantime, I am a bit stuck.

This series' clash with my modularization patches should not interfere
much with reviewing it.  Let me try and see how far I get.

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

end of thread, other threads:[~2018-02-06 12:31 UTC | newest]

Thread overview: 74+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-11 21:31 [Qemu-devel] [PATCH v4 00/51] Hi, Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 01/51] qlit: use QType instead of int Marc-André Lureau
2018-01-11 22:52   ` Eric Blake
2018-02-05  6:05   ` Markus Armbruster
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 02/51] qlit: add qobject_from_qlit() Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 03/51] qapi: generate a literal qobject for introspection Marc-André Lureau
2018-02-06 10:04   ` Markus Armbruster
2018-02-06 11:01     ` Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 04/51] qapi2texi: minor python code simplification Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 05/51] qapi: add 'if' to top-level expressions Marc-André Lureau
2018-02-05  6:12   ` Markus Armbruster
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 06/51] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
2018-02-05  6:16   ` Markus Armbruster
2018-02-06 10:12   ` Markus Armbruster
2018-02-06 11:06     ` Marc-André Lureau
2018-02-06 12:14       ` Markus Armbruster
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 07/51] qapi: leave the ifcond attribute undefined until check() Marc-André Lureau
2018-02-05  6:22   ` Markus Armbruster
2018-02-06 11:20   ` Markus Armbruster
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 08/51] qapi: add 'ifcond' to visitor methods Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 09/51] qapi: mcgen() shouldn't indent # lines Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 10/51] qapi: add #if/#endif helpers Marc-André Lureau
2018-02-05  7:03   ` Markus Armbruster
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 11/51] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 12/51] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
2018-01-12 10:27   ` Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 13/51] qapi-commands: add #if conditions to commands Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 14/51] qapi-event: add #if conditions to events Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 15/51] qapi-types: refactor variants handling Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 16/51] qapi-types: add #if conditions to types & visitors Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 17/51] qapi: do not define enumeration value explicitely Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 18/51] qapi: rename QAPISchemaEnumType.values to .members Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 19/51] qapi: change enum visitor to take QAPISchemaMember Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 20/51] tests: modify visit_enum_type() in test-qapi to print members Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 21/51] qapi: factor out check_known_keys() Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 22/51] qapi: add a dictionnary form with 'name' key for enum members Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 23/51] qapi: add 'if' to " Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 24/51] qapi-event: add 'if' condition to implicit event enum Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 25/51] qapi: rename allow_dict to allow_implicit Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 26/51] qapi: add a dictionary form with 'type' key for members Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 27/51] qapi: add 'if' to implicit struct members Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 28/51] qapi: add an error in case a discriminator is conditionnal Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 29/51] qapi: add 'if' on union members Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 30/51] qapi: add 'if' to alternate members Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 31/51] qapi: add #if conditions to generated code Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 32/51] docs: document schema configuration Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 33/51] qapi2texi: add 'If:' section to generated documentation Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 34/51] qapi2texi: add 'If:' condition to enum values Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 35/51] qapi2texi: add 'If:' condition to struct members Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 36/51] qapi2texi: add condition to variants Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 37/51] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
2018-01-12 13:04   ` Gerd Hoffmann
2018-01-12 13:22     ` Marc-André Lureau
2018-01-12 13:55       ` Gerd Hoffmann
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 38/51] qapi: add conditions to SPICE " Marc-André Lureau
2018-01-12 13:09   ` Gerd Hoffmann
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 39/51] qapi: add conditions to REPLICATION type/commands " Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 40/51] qapi-commands: don't initialize command list in qmp_init_marshall() Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 41/51] qapi: add -i/--include filename.h Marc-André Lureau
2018-02-05 16:58   ` Markus Armbruster
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 42/51] qapi: add a 'unit' pragma Marc-André Lureau
2018-01-12 11:54   ` Marc-André Lureau
2018-02-05 18:13     ` Markus Armbruster
2018-02-06 11:01       ` Marc-André Lureau
2018-02-06 12:31         ` Markus Armbruster
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 43/51] build-sys: move qmp-introspect per target Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 44/51] build-sys: add a target schema Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 45/51] qapi: make rtc-reset-reinjection depend on TARGET_I386 Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 46/51] qapi: make s390 commands depend on TARGET_S390X Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 47/51] target.json: add a note about query-cpu* not being s390x-specific Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 48/51] qapi: make query-gic-capabilities depend on TARGET_ARM Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 49/51] qapi: make query-cpu-model-expansion depend on s390 or x86 Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 50/51] qapi: make query-cpu-definitions depend on specific targets Marc-André Lureau
2018-01-11 21:32 ` [Qemu-devel] [PATCH v4 51/51] qapi: remove qmp_unregister_command() Marc-André Lureau

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.