[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 3/3] qapi: Update docs to match recent generator
From: |
Markus Armbruster |
Subject: |
Re: [Qemu-devel] [PATCH 3/3] qapi: Update docs to match recent generator changes |
Date: |
Wed, 24 Feb 2016 13:53:37 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) |
Eric Blake <address@hidden> writes:
> Several commits have been changing the generator, but not updating
> the docs to match:
> - The implicit tag member is named "type", not "kind". Screwed up in
> commit 39a1815.
> - Commit 9f08c8ec made list types lazy, and thereby dropped
> UserDefOneList if nothing explicitly uses the list type.
> - Commit 51e72bc1 switched the parameter order with 'name' occurring
> earlier.
> - Commit e65d89bf changed the layout of UserDefOneList.
> - We now expose visit_type_FOO_fields() for objects.
> - etc.
>
> Rework the examples to show slightly more output (we don't want to
> show too much; that's what the testsuite is for), and regenerate the
> output to match all recent changes. Also, rearrange output to show
> .h files before .c (understanding the interface first often makes
> the implementation easier to follow).
>
> Reported-by: Marc-André Lureau <address@hidden>
> Signed-off-by: Eric Blake <address@hidden>
> Signed-off-by: Markus Armbruster <address@hidden>
>
> ---
> Some content from Markus, hence his S-o-b.
> A former version of this patch was posted with subset E v9.
> ---
> docs/qapi-code-gen.txt | 308
> ++++++++++++++++++++++++++-----------------------
> 1 file changed, 162 insertions(+), 146 deletions(-)
>
> diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> index 999f3b9..e1dde87 100644
> --- a/docs/qapi-code-gen.txt
> +++ b/docs/qapi-code-gen.txt
> @@ -1,7 +1,7 @@
> = How to use the QAPI code generator =
>
> Copyright IBM Corp. 2011
> -Copyright (C) 2012-2015 Red Hat, Inc.
> +Copyright (C) 2012-2016 Red Hat, Inc.
>
> This work is licensed under the terms of the GNU GPL, version 2 or
> later. See the COPYING file in the top-level directory.
> @@ -656,7 +656,7 @@ Union types
>
> { "name": "BlockdevOptions", "meta-type": "object",
> "members": [
> - { "name": "kind", "type": "BlockdevOptionsKind" } ],
> + { "name": "type", "type": "BlockdevOptionsKind" } ],
> "tag": "type",
> "variants": [
> { "case": "file", "type": ":obj-FileOptions-wrapper" },
> @@ -722,33 +722,39 @@ the names of built-in types. Clients should examine
> member
>
> == Code generation ==
>
> -Schemas are fed into four scripts to generate all the code/files that,
> +Schemas are fed into five scripts to generate all the code/files that,
> paired with the core QAPI libraries, comprise everything required to
> take JSON commands read in by a Client JSON Protocol server, unmarshal
> the arguments into the underlying C types, call into the corresponding
> -C function, and map the response back to a Client JSON Protocol
> -response to be returned to the user.
> +C function, map the response back to a Client JSON Protocol response
> +to be returned to the user, and introspect the commands.
>
> -As an example, we'll use the following schema, which describes a single
> -complex user-defined type (which will produce a C struct, along with a list
> -node structure that can be used to chain together a list of such types in
> -case we want to accept/return a list of this type with a command), and a
> -command which takes that type as a parameter and returns the same type:
> +As an example, we'll use the following schema, which describes a
> +single complex user-defined type, along with command which takes a
> +list of that type as a parameter, and returns a single element of that
> +type. The user is responsible for writing the implementation of
> +qmp_my_command(); everything else is produced by the generator.
>
> $ cat example-schema.json
> { 'struct': 'UserDefOne',
> - 'data': { 'integer': 'int', 'string': 'str' } }
> + 'data': { 'integer': 'int', '*string': 'str' } }
>
> { 'command': 'my-command',
> - 'data': {'arg1': 'UserDefOne'},
> + 'data': { 'arg1': ['UserDefOne'] },
> 'returns': 'UserDefOne' }
>
> { 'event': 'MY_EVENT' }
>
> +For a more thorough look at generated code, the testsuite includes
> +tests/qapi-schema/qapi-schema-tests.json that covers more examples of
> +what the generator will accept, and compiles the resulting C code as
> +part of 'make check-unit'.
> +
> === scripts/qapi-types.py ===
>
> -Used to generate the C types defined by a schema. The following files are
> -created:
> +Used to generate the C types defined by a schema, as well as the
> +functions for recursively cleaning up their resources, as
> +qapi_free_FOO(). The following files are created:
Actually, it also creates conversion functions and enum lookup tables.
Suggest to be less specific:
Used to generate the C types defined by a schema, along with
supporting code. The following files are created:
>
> $(prefix)qapi-types.h - C types corresponding to types defined in
> the schema you pass in
> @@ -763,38 +769,6 @@ Example:
>
> $ python scripts/qapi-types.py --output-dir="qapi-generated" \
> --prefix="example-" example-schema.json
> - $ cat qapi-generated/example-qapi-types.c
> -[Uninteresting stuff omitted...]
> -
> - void qapi_free_UserDefOne(UserDefOne *obj)
> - {
> - QapiDeallocVisitor *qdv;
> - Visitor *v;
> -
> - if (!obj) {
> - return;
> - }
> -
> - qdv = qapi_dealloc_visitor_new();
> - v = qapi_dealloc_get_visitor(qdv);
> - visit_type_UserDefOne(v, &obj, NULL, NULL);
> - qapi_dealloc_visitor_cleanup(qdv);
> - }
> -
> - void qapi_free_UserDefOneList(UserDefOneList *obj)
> - {
> - QapiDeallocVisitor *qdv;
> - Visitor *v;
> -
> - if (!obj) {
> - return;
> - }
> -
> - qdv = qapi_dealloc_visitor_new();
> - v = qapi_dealloc_get_visitor(qdv);
> - visit_type_UserDefOneList(v, &obj, NULL, NULL);
> - qapi_dealloc_visitor_cleanup(qdv);
> - }
> $ cat qapi-generated/example-qapi-types.h
> [Uninteresting stuff omitted...]
>
> @@ -809,29 +783,59 @@ Example:
>
> struct UserDefOne {
> int64_t integer;
> + bool has_string;
> char *string;
> };
>
> void qapi_free_UserDefOne(UserDefOne *obj);
>
> struct UserDefOneList {
> - union {
> - UserDefOne *value;
> - uint64_t padding;
> - };
> UserDefOneList *next;
> + UserDefOne *value;
> };
>
> void qapi_free_UserDefOneList(UserDefOneList *obj);
>
> #endif
> + $ cat qapi-generated/example-qapi-types.c
> +[Uninteresting stuff omitted...]
> +
> + void qapi_free_UserDefOne(UserDefOne *obj)
> + {
> + QapiDeallocVisitor *qdv;
> + Visitor *v;
> +
> + if (!obj) {
> + return;
> + }
> +
> + qdv = qapi_dealloc_visitor_new();
> + v = qapi_dealloc_get_visitor(qdv);
> + visit_type_UserDefOne(v, NULL, &obj, NULL);
> + qapi_dealloc_visitor_cleanup(qdv);
> + }
> +
> + void qapi_free_UserDefOneList(UserDefOneList *obj)
> + {
> + QapiDeallocVisitor *qdv;
> + Visitor *v;
> +
> + if (!obj) {
> + return;
> + }
> +
> + qdv = qapi_dealloc_visitor_new();
> + v = qapi_dealloc_get_visitor(qdv);
> + visit_type_UserDefOneList(v, NULL, &obj, NULL);
> + qapi_dealloc_visitor_cleanup(qdv);
> + }
>
> === scripts/qapi-visit.py ===
>
> -Used to generate the visitor functions used to walk through and convert
> -a QObject (as provided by QMP) to a native C data structure and
> -vice-versa, as well as the visitor function used to dealloc a complex
> -schema-defined C type.
> +Used to generate the visitor functions used to walk through and
> +convert between a native QAPI C data structure and some other format
> +(such as QObject); the generated functions are named visit_type_FOO()
> +and visit_type_FOO_fields().
>
> The following files are generated:
>
> @@ -848,41 +852,62 @@ Example:
>
> $ python scripts/qapi-visit.py --output-dir="qapi-generated"
> --prefix="example-" example-schema.json
> + $ cat qapi-generated/example-qapi-visit.h
> +[Uninteresting stuff omitted...]
> +
> + #ifndef EXAMPLE_QAPI_VISIT_H
> + #define EXAMPLE_QAPI_VISIT_H
> +
> +[Visitors for built-in types omitted...]
> +
> + void visit_type_UserDefOne_fields(Visitor *v, UserDefOne *obj, Error
> **errp);
> + void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne
> **obj, Error **errp);
> + void visit_type_UserDefOneList(Visitor *v, const char *name,
> UserDefOneList **obj, Error **errp);
> +
> + #endif
> $ cat qapi-generated/example-qapi-visit.c
> [Uninteresting stuff omitted...]
>
> - static void visit_type_UserDefOne_fields(Visitor *v, UserDefOne **obj,
> Error **errp)
> + void visit_type_UserDefOne_fields(Visitor *v, UserDefOne *obj, Error
> **errp)
> {
> Error *err = NULL;
>
> - visit_type_int(v, &(*obj)->integer, "integer", &err);
> + visit_type_int(v, "integer", &obj->integer, &err);
> if (err) {
> goto out;
> }
> - visit_type_str(v, &(*obj)->string, "string", &err);
> - if (err) {
> - goto out;
> - }
> -
> - out:
> - error_propagate(errp, err);
> - }
> -
> - void visit_type_UserDefOne(Visitor *v, UserDefOne **obj, const char
> *name, Error **errp)
> - {
> - Error *err = NULL;
> -
> - visit_start_struct(v, (void **)obj, "UserDefOne", name,
> sizeof(UserDefOne), &err);
> - if (!err) {
> - if (*obj) {
> - visit_type_UserDefOne_fields(v, obj, errp);
> + if (visit_optional(v, "string", &obj->has_string)) {
> + visit_type_str(v, "string", &obj->string, &err);
> + if (err) {
> + goto out;
> }
> - visit_end_struct(v, &err);
> }
> +
> + out:
> + error_propagate(errp, err);
> + }
> +
> + void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne
> **obj, Error **errp)
> + {
> + Error *err = NULL;
> +
> + visit_start_struct(v, name, (void **)obj, sizeof(UserDefOne), &err);
> + if (err) {
> + goto out;
> + }
> + if (!*obj) {
> + goto out_obj;
> + }
> + visit_type_UserDefOne_fields(v, *obj, &err);
> + error_propagate(errp, err);
> + err = NULL;
> + out_obj:
> + visit_end_struct(v, &err);
> + out:
> error_propagate(errp, err);
> }
>
> - void visit_type_UserDefOneList(Visitor *v, UserDefOneList **obj, const
> char *name, Error **errp)
> + void visit_type_UserDefOneList(Visitor *v, const char *name,
> UserDefOneList **obj, Error **errp)
> {
> Error *err = NULL;
> GenericList *i, **prev;
> @@ -893,35 +918,24 @@ Example:
> }
>
> for (prev = (GenericList **)obj;
> - !err && (i = visit_next_list(v, prev, &err)) != NULL;
> + !err && (i = visit_next_list(v, prev, sizeof(**obj))) != NULL;
> prev = &i) {
> UserDefOneList *native_i = (UserDefOneList *)i;
> - visit_type_UserDefOne(v, &native_i->value, NULL, &err);
> + visit_type_UserDefOne(v, NULL, &native_i->value, &err);
> }
>
> - error_propagate(errp, err);
> - err = NULL;
> - visit_end_list(v, &err);
> + visit_end_list(v);
> out:
> error_propagate(errp, err);
> }
> - $ cat qapi-generated/example-qapi-visit.h
> -[Uninteresting stuff omitted...]
> -
> - #ifndef EXAMPLE_QAPI_VISIT_H
> - #define EXAMPLE_QAPI_VISIT_H
> -
> -[Visitors for built-in types omitted...]
> -
> - void visit_type_UserDefOne(Visitor *v, UserDefOne **obj, const char
> *name, Error **errp);
> - void visit_type_UserDefOneList(Visitor *v, UserDefOneList **obj, const
> char *name, Error **errp);
> -
> - #endif
>
> === scripts/qapi-commands.py ===
>
> -Used to generate the marshaling/dispatch functions for the commands defined
> -in the schema. The following files are generated:
> +Used to generate the marshaling/dispatch functions for the commands
> +defined in the schema. The generated code implements
> +qmp_marshal_COMMAND() (mentioned in qmp-commands.hx, and registered
> +automatically), and declares qmp_COMMAND() that the user must
> +implement. The following files are generated:
>
> $(prefix)qmp-marshal.c: command marshal/dispatch functions for each
> QMP command defined in the schema. Functions
> @@ -939,6 +953,19 @@ Example:
>
> $ python scripts/qapi-commands.py --output-dir="qapi-generated"
> --prefix="example-" example-schema.json
> + $ cat qapi-generated/example-qmp-commands.h
> +[Uninteresting stuff omitted...]
> +
> + #ifndef EXAMPLE_QMP_COMMANDS_H
> + #define EXAMPLE_QMP_COMMANDS_H
> +
> + #include "example-qapi-types.h"
> + #include "qapi/qmp/qdict.h"
> + #include "qapi/error.h"
> +
> + UserDefOne *qmp_my_command(UserDefOneList *arg1, Error **errp);
> +
> + #endif
> $ cat qapi-generated/example-qmp-marshal.c
> [Uninteresting stuff omitted...]
>
> @@ -950,7 +977,7 @@ Example:
> Visitor *v;
>
> v = qmp_output_get_visitor(qov);
> - visit_type_UserDefOne(v, &ret_in, "unused", &err);
> + visit_type_UserDefOne(v, "unused", &ret_in, &err);
> if (err) {
> goto out;
> }
> @@ -961,7 +988,7 @@ Example:
> qmp_output_visitor_cleanup(qov);
> qdv = qapi_dealloc_visitor_new();
> v = qapi_dealloc_get_visitor(qdv);
> - visit_type_UserDefOne(v, &ret_in, "unused", NULL);
> + visit_type_UserDefOne(v, "unused", &ret_in, NULL);
> qapi_dealloc_visitor_cleanup(qdv);
> }
>
> @@ -972,10 +999,10 @@ Example:
> QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args));
> QapiDeallocVisitor *qdv;
> Visitor *v;
> - UserDefOne *arg1 = NULL;
> + UserDefOneList *arg1 = NULL;
>
> v = qmp_input_get_visitor(qiv);
> - visit_type_UserDefOne(v, &arg1, "arg1", &err);
> + visit_type_UserDefOne(v, "arg1", &arg1, &err);
UserDefOneList
> if (err) {
> goto out;
> }
> @@ -992,7 +1019,7 @@ Example:
> qmp_input_visitor_cleanup(qiv);
> qdv = qapi_dealloc_visitor_new();
> v = qapi_dealloc_get_visitor(qdv);
> - visit_type_UserDefOne(v, &arg1, "arg1", NULL);
> + visit_type_UserDefOne(v, "arg1", &arg1, NULL);
UserDefOneList
> qapi_dealloc_visitor_cleanup(qdv);
> }
>
> @@ -1002,24 +1029,12 @@ Example:
> }
>
> qapi_init(qmp_init_marshal);
> - $ cat qapi-generated/example-qmp-commands.h
> -[Uninteresting stuff omitted...]
> -
> - #ifndef EXAMPLE_QMP_COMMANDS_H
> - #define EXAMPLE_QMP_COMMANDS_H
> -
> - #include "example-qapi-types.h"
> - #include "qapi/qmp/qdict.h"
> - #include "qapi/error.h"
> -
> - UserDefOne *qmp_my_command(UserDefOne *arg1, Error **errp);
> -
> - #endif
>
> === scripts/qapi-event.py ===
>
> -Used to generate the event-related C code defined by a schema. The
> -following files are created:
> +Used to generate the event-related C code defined by a schema, with
> +implementations for qapi_event_send_FOO(). The following files are
> +created:
>
> $(prefix)qapi-event.h - Function prototypes for each event type, plus an
> enumeration of all event names
> @@ -1029,6 +1044,27 @@ Example:
>
> $ python scripts/qapi-event.py --output-dir="qapi-generated"
> --prefix="example-" example-schema.json
> + $ cat qapi-generated/example-qapi-event.h
> +[Uninteresting stuff omitted...]
> +
> + #ifndef EXAMPLE_QAPI_EVENT_H
> + #define EXAMPLE_QAPI_EVENT_H
> +
> + #include "qapi/error.h"
> + #include "qapi/qmp/qdict.h"
> + #include "example-qapi-types.h"
> +
> +
> + void qapi_event_send_my_event(Error **errp);
> +
> + typedef enum example_QAPIEvent {
> + EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
> + EXAMPLE_QAPI_EVENT__MAX = 1,
> + } example_QAPIEvent;
> +
> + extern const char *const example_QAPIEvent_lookup[];
> +
> + #endif
> $ cat qapi-generated/example-qapi-event.c
> [Uninteresting stuff omitted...]
>
> @@ -1054,27 +1090,6 @@ Example:
> [EXAMPLE_QAPI_EVENT_MY_EVENT] = "MY_EVENT",
> [EXAMPLE_QAPI_EVENT__MAX] = NULL,
> };
> - $ cat qapi-generated/example-qapi-event.h
> -[Uninteresting stuff omitted...]
> -
> - #ifndef EXAMPLE_QAPI_EVENT_H
> - #define EXAMPLE_QAPI_EVENT_H
> -
> - #include "qapi/error.h"
> - #include "qapi/qmp/qdict.h"
> - #include "example-qapi-types.h"
> -
> -
> - void qapi_event_send_my_event(Error **errp);
> -
> - typedef enum example_QAPIEvent {
> - EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
> - EXAMPLE_QAPI_EVENT__MAX = 1,
> - } example_QAPIEvent;
> -
> - extern const char *const example_QAPIEvent_lookup[];
> -
> - #endif
>
> === scripts/qapi-introspect.py ===
>
> @@ -1089,6 +1104,15 @@ Example:
>
> $ python scripts/qapi-introspect.py --output-dir="qapi-generated"
> --prefix="example-" example-schema.json
> + $ cat qapi-generated/example-qmp-introspect.h
> +[Uninteresting stuff omitted...]
> +
> + #ifndef EXAMPLE_QMP_INTROSPECT_H
> + #define EXAMPLE_QMP_INTROSPECT_H
> +
> + extern const char example_qmp_schema_json[];
> +
> + #endif
> $ cat qapi-generated/example-qmp-introspect.c
> [Uninteresting stuff omitted...]
>
> @@ -1096,16 +1120,8 @@ Example:
> "{\"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\"},
> {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\",
> \"name\": \"2\"}, "
> + "{\"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\"}]";
> - $ cat qapi-generated/example-qmp-introspect.h
> -[Uninteresting stuff omitted...]
> -
> - #ifndef EXAMPLE_QMP_INTROSPECT_H
> - #define EXAMPLE_QMP_INTROSPECT_H
> -
> - extern const char example_qmp_schema_json[];
> -
> - #endif
With my three remarks addressed:
Reviewed-by: Markus Armbruster <address@hidden>