@@ -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,38 @@ 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, 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 +768,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 +782,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_members().
The following files are generated:
@@ -848,41 +851,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_members(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_members(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_members(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 +917,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 +952,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 +976,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 +987,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 +998,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_UserDefOneList(v, "arg1", &arg1, &err);
if (err) {
goto out;
}
@@ -992,7 +1018,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_UserDefOneList(v, "arg1", &arg1, NULL);
qapi_dealloc_visitor_cleanup(qdv);
}
@@ -1002,24 +1028,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 +1043,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 +1089,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 +1103,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 +1119,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