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