Message ID | 1456262075-3311-4-git-send-email-eblake@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Eric Blake <eblake@redhat.com> 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 <marcandre.lureau@redhat.com> > Signed-off-by: Eric Blake <eblake@redhat.com> > Signed-off-by: Markus Armbruster <armbru@redhat.com> > > --- > 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 <armbru@redhat.com>
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: $(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); 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); 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