qemu-devel
[Top][All Lists]
Advanced

[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>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]