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. - The parameter order has switched 'name' to occur earlier. - The generated code now checks for partial allocations. - 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. Reported-by: Marc-André Lureau <[email protected]> Signed-off-by: Eric Blake <[email protected]> Signed-off-by: Markus Armbruster <[email protected]> --- v9: new patch --- docs/qapi-code-gen.txt | 130 +++++++++++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 52 deletions(-) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 128f074..ae7b1a5 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. @@ -655,7 +655,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" }, @@ -721,29 +721,34 @@ 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. 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 @@ -776,7 +781,7 @@ Example: qdv = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(qdv); - visit_type_UserDefOne(v, &obj, NULL, NULL); + visit_type_UserDefOne(v, NULL, &obj, NULL); qapi_dealloc_visitor_cleanup(qdv); } @@ -791,7 +796,7 @@ Example: qdv = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(qdv); - visit_type_UserDefOneList(v, &obj, NULL, NULL); + visit_type_UserDefOneList(v, NULL, &obj, NULL); qapi_dealloc_visitor_cleanup(qdv); } $ cat qapi-generated/example-qapi-types.h @@ -808,17 +813,15 @@ 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); @@ -854,54 +857,76 @@ Example: { 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; + if (visit_optional(v, "string", &(*obj)->has_string)) { + visit_type_str(v, "string", &(*obj)->string, &err); + if (err) { + goto out; + } } out: error_propagate(errp, err); } - void visit_type_UserDefOne(Visitor *v, UserDefOne **obj, const char *name, Error **errp) + void visit_type_UserDefOne(Visitor *v, const char *name, UserDefOne **obj, Error **errp) { Error *err = NULL; + bool allocated; - visit_start_struct(v, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err); - if (!err) { - if (*obj) { - visit_type_UserDefOne_fields(v, obj, errp); - } - visit_end_struct(v, &err); + allocated = 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); + if (err) { + goto out_obj; } + visit_check_struct(v, &err); + out_obj: + visit_end_struct(v); + if (allocated && err) { + qapi_free_UserDefOne(*obj); + *obj = NULL; + } + 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; + UserDefOneList *eld; + bool allocated; - visit_start_list(v, name, &err); + allocated = visit_start_list(v, name, (GenericList **)obj, sizeof(UserDefOneList), &err); if (err) { goto out; } - - for (prev = (GenericList **)obj; - !err && (i = visit_next_list(v, prev, &err)) != NULL; - prev = &i) { - UserDefOneList *native_i = (UserDefOneList *)i; - visit_type_UserDefOne(v, &native_i->value, NULL, &err); + elt = *obj; + while (elt) { + visit_type_UserDefOne(v, NULL, &elt->value, &err); + if (err) { + break; + } + elt = (UserDefOneList *)visit_next_list(v, (GenericList *)elt, sizeof(UserDefOneList), &err); + if (err) { + break; + } } - - error_propagate(errp, err); - err = NULL; - visit_end_list(v, &err); + visit_end_list(v); out: + if (allocated && err) { + qapi_free_UserDefOneList(*obj); + *obj = NULL; + } error_propagate(errp, err); } $ cat qapi-generated/example-qapi-visit.h @@ -912,8 +937,8 @@ Example: [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); + 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 @@ -949,7 +974,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; } @@ -960,7 +985,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); } @@ -971,10 +996,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; } @@ -991,7 +1016,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); } @@ -1011,7 +1036,7 @@ Example: #include "qapi/qmp/qdict.h" #include "qapi/error.h" - UserDefOne *qmp_my_command(UserDefOne *arg1, Error **errp); + UserDefOne *qmp_my_command(UserDefOneList *arg1, Error **errp); #endif @@ -1095,8 +1120,9 @@ 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 -- 2.5.0
