Revision b84da831
b/docs/qapi-code-gen.txt | ||
---|---|---|
1 |
= How to use the QAPI code generator = |
|
2 |
|
|
3 |
* Note: as of this writing, QMP does not use QAPI. Eventually QMP |
|
4 |
commands will be converted to use QAPI internally. The following |
|
5 |
information describes QMP/QAPI as it will exist after the |
|
6 |
conversion. |
|
7 |
|
|
8 |
QAPI is a native C API within QEMU which provides management-level |
|
9 |
functionality to internal/external users. For external |
|
10 |
users/processes, this interface is made available by a JSON-based |
|
11 |
QEMU Monitor protocol that is provided by the QMP server. |
|
12 |
|
|
13 |
To map QMP-defined interfaces to the native C QAPI implementations, |
|
14 |
a JSON-based schema is used to define types and function |
|
15 |
signatures, and a set of scripts is used to generate types/signatures, |
|
16 |
and marshaling/dispatch code. The QEMU Guest Agent also uses these |
|
17 |
scripts, paired with a seperate schema, to generate |
|
18 |
marshaling/dispatch code for the guest agent server running in the |
|
19 |
guest. |
|
20 |
|
|
21 |
This document will describe how the schemas, scripts, and resulting |
|
22 |
code is used. |
|
23 |
|
|
24 |
|
|
25 |
== QMP/Guest agent schema == |
|
26 |
|
|
27 |
This file defines the types, commands, and events used by QMP. It should |
|
28 |
fully describe the interface used by QMP. |
|
29 |
|
|
30 |
This file is designed to be loosely based on JSON although it's technically |
|
31 |
executable Python. While dictionaries are used, they are parsed as |
|
32 |
OrderedDicts so that ordering is preserved. |
|
33 |
|
|
34 |
There are two basic syntaxes used, type definitions and command definitions. |
|
35 |
|
|
36 |
The first syntax defines a type and is represented by a dictionary. There are |
|
37 |
two kinds of types that are supported: complex user-defined types, and enums. |
|
38 |
|
|
39 |
A complex type is a dictionary containing a single key who's value is a |
|
40 |
dictionary. This corresponds to a struct in C or an Object in JSON. An |
|
41 |
example of a complex type is: |
|
42 |
|
|
43 |
{ 'type': 'MyType', |
|
44 |
'data' { 'member1': 'str', 'member2': 'int', '*member3': 'str } } |
|
45 |
|
|
46 |
The use of '*' as a prefix to the name means the member is optional. Optional |
|
47 |
members should always be added to the end of the dictionary to preserve |
|
48 |
backwards compatibility. |
|
49 |
|
|
50 |
An enumeration type is a dictionary containing a single key who's value is a |
|
51 |
list of strings. An example enumeration is: |
|
52 |
|
|
53 |
{ 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] } |
|
54 |
|
|
55 |
Generally speaking, complex types and enums should always use CamelCase for |
|
56 |
the type names. |
|
57 |
|
|
58 |
Commands are defined by using a list containing three members. The first |
|
59 |
member is the command name, the second member is a dictionary containing |
|
60 |
arguments, and the third member is the return type. |
|
61 |
|
|
62 |
An example command is: |
|
63 |
|
|
64 |
{ 'command': 'my-command', |
|
65 |
'data': { 'arg1': 'str', '*arg2': 'str' }, |
|
66 |
'returns': 'str' ] |
|
67 |
|
|
68 |
Command names should be all lower case with words separated by a hyphen. |
|
69 |
|
|
70 |
|
|
71 |
== Code generation == |
|
72 |
|
|
73 |
Schemas are fed into 3 scripts to generate all the code/files that, paired |
|
74 |
with the core QAPI libraries, comprise everything required to take JSON |
|
75 |
commands read in by a QMP/guest agent server, unmarshal the arguments into |
|
76 |
the underlying C types, call into the corresponding C function, and map the |
|
77 |
response back to a QMP/guest agent response to be returned to the user. |
|
78 |
|
|
79 |
As an example, we'll use the following schema, which describes a single |
|
80 |
complex user-defined type (which will produce a C struct, along with a list |
|
81 |
node structure that can be used to chain together a list of such types in |
|
82 |
case we want to accept/return a list of this type with a command), and a |
|
83 |
command which takes that type as a parameter and returns the same type: |
|
84 |
|
|
85 |
mdroth@illuin:~/w/qemu2.git$ cat example-schema.json |
|
86 |
{ 'type': 'UserDefOne', |
|
87 |
'data': { 'integer': 'int', 'string': 'str' } } |
|
88 |
|
|
89 |
{ 'command': 'my-command', |
|
90 |
'data': {'arg1': 'UserDefOne'}, |
|
91 |
'returns': 'UserDefOne' } |
|
92 |
mdroth@illuin:~/w/qemu2.git$ |
|
93 |
|
|
94 |
=== scripts/qapi-types.py === |
|
95 |
|
|
96 |
Used to generate the C types defined by a schema. The following files are |
|
97 |
created: |
|
98 |
|
|
99 |
$(prefix)qapi-types.h - C types corresponding to types defined in |
|
100 |
the schema you pass in |
|
101 |
$(prefix)qapi-types.c - Cleanup functions for the above C types |
|
102 |
|
|
103 |
The $(prefix) is an optional parameter used as a namespace to keep the |
|
104 |
generated code from one schema/code-generation separated from others so code |
|
105 |
can be generated/used from multiple schemas without clobbering previously |
|
106 |
created code. |
|
107 |
|
|
108 |
Example: |
|
109 |
|
|
110 |
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \ |
|
111 |
--output-dir="qapi-generated" --prefix="example-" < example-schema.json |
|
112 |
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c |
|
113 |
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ |
|
114 |
|
|
115 |
#include "qapi/qapi-dealloc-visitor.h" |
|
116 |
#include "example-qapi-types.h" |
|
117 |
#include "example-qapi-visit.h" |
|
118 |
|
|
119 |
void qapi_free_UserDefOne(UserDefOne * obj) |
|
120 |
{ |
|
121 |
QapiDeallocVisitor *md; |
|
122 |
Visitor *v; |
|
123 |
|
|
124 |
if (!obj) { |
|
125 |
return; |
|
126 |
} |
|
127 |
|
|
128 |
md = qapi_dealloc_visitor_new(); |
|
129 |
v = qapi_dealloc_get_visitor(md); |
|
130 |
visit_type_UserDefOne(v, &obj, NULL, NULL); |
|
131 |
qapi_dealloc_visitor_cleanup(md); |
|
132 |
} |
|
133 |
|
|
134 |
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h |
|
135 |
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ |
|
136 |
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES |
|
137 |
#define QAPI_GENERATED_EXAMPLE_QAPI_TYPES |
|
138 |
|
|
139 |
#include "qapi/qapi-types-core.h" |
|
140 |
|
|
141 |
typedef struct UserDefOne UserDefOne; |
|
142 |
|
|
143 |
typedef struct UserDefOneList |
|
144 |
{ |
|
145 |
UserDefOne *value; |
|
146 |
struct UserDefOneList *next; |
|
147 |
} UserDefOneList; |
|
148 |
|
|
149 |
struct UserDefOne |
|
150 |
{ |
|
151 |
int64_t integer; |
|
152 |
char * string; |
|
153 |
}; |
|
154 |
|
|
155 |
void qapi_free_UserDefOne(UserDefOne * obj); |
|
156 |
|
|
157 |
#endif |
|
158 |
|
|
159 |
|
|
160 |
=== scripts/qapi-visit.py === |
|
161 |
|
|
162 |
Used to generate the visitor functions used to walk through and convert |
|
163 |
a QObject (as provided by QMP) to a native C data structure and |
|
164 |
vice-versa, as well as the visitor function used to dealloc a complex |
|
165 |
schema-defined C type. |
|
166 |
|
|
167 |
The following files are generated: |
|
168 |
|
|
169 |
$(prefix)qapi-visit.c: visitor function for a particular C type, used |
|
170 |
to automagically convert QObjects into the |
|
171 |
corresponding C type and vice-versa, as well |
|
172 |
as for deallocating memory for an existing C |
|
173 |
type |
|
174 |
|
|
175 |
$(prefix)qapi-visit.h: declarations for previously mentioned visitor |
|
176 |
functions |
|
177 |
|
|
178 |
Example: |
|
179 |
|
|
180 |
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \ |
|
181 |
--output-dir="qapi-generated" --prefix="example-" < example-schema.json |
|
182 |
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c |
|
183 |
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ |
|
184 |
|
|
185 |
#include "example-qapi-visit.h" |
|
186 |
|
|
187 |
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp) |
|
188 |
{ |
|
189 |
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp); |
|
190 |
visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp); |
|
191 |
visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp); |
|
192 |
visit_end_struct(m, errp); |
|
193 |
} |
|
194 |
|
|
195 |
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp) |
|
196 |
{ |
|
197 |
GenericList *i; |
|
198 |
|
|
199 |
visit_start_list(m, name, errp); |
|
200 |
|
|
201 |
for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) { |
|
202 |
UserDefOneList *native_i = (UserDefOneList *)i; |
|
203 |
visit_type_UserDefOne(m, &native_i->value, NULL, errp); |
|
204 |
} |
|
205 |
|
|
206 |
visit_end_list(m, errp); |
|
207 |
} |
|
208 |
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h |
|
209 |
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ |
|
210 |
|
|
211 |
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT |
|
212 |
#define QAPI_GENERATED_EXAMPLE_QAPI_VISIT |
|
213 |
|
|
214 |
#include "qapi/qapi-visit-core.h" |
|
215 |
#include "example-qapi-types.h" |
|
216 |
|
|
217 |
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp); |
|
218 |
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp); |
|
219 |
|
|
220 |
#endif |
|
221 |
mdroth@illuin:~/w/qemu2.git$ |
|
222 |
|
|
223 |
|
|
224 |
=== scripts/qapi-commands.py === |
|
225 |
|
|
226 |
Used to generate the marshaling/dispatch functions for the commands defined |
|
227 |
in the schema. The following files are generated: |
|
228 |
|
|
229 |
$(prefix)qmp-marshal.c: command marshal/dispatch functions for each |
|
230 |
QMP command defined in the schema. Functions |
|
231 |
generated by qapi-visit.py are used to |
|
232 |
convert QObjects recieved from the wire into |
|
233 |
function parameters, and uses the same |
|
234 |
visitor functions to convert native C return |
|
235 |
values to QObjects from transmission back |
|
236 |
over the wire. |
|
237 |
|
|
238 |
$(prefix)qmp-commands.h: Function prototypes for the QMP commands |
|
239 |
specified in the schema. |
|
240 |
|
|
241 |
Example: |
|
242 |
|
|
243 |
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c |
|
244 |
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ |
|
245 |
|
|
246 |
#include "qemu-objects.h" |
|
247 |
#include "qapi/qmp-core.h" |
|
248 |
#include "qapi/qapi-visit-core.h" |
|
249 |
#include "qapi/qmp-output-visitor.h" |
|
250 |
#include "qapi/qmp-input-visitor.h" |
|
251 |
#include "qapi/qapi-dealloc-visitor.h" |
|
252 |
#include "example-qapi-types.h" |
|
253 |
#include "example-qapi-visit.h" |
|
254 |
|
|
255 |
#include "example-qmp-commands.h" |
|
256 |
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp) |
|
257 |
{ |
|
258 |
QapiDeallocVisitor *md = qapi_dealloc_visitor_new(); |
|
259 |
QmpOutputVisitor *mo = qmp_output_visitor_new(); |
|
260 |
Visitor *v; |
|
261 |
|
|
262 |
v = qmp_output_get_visitor(mo); |
|
263 |
visit_type_UserDefOne(v, &ret_in, "unused", errp); |
|
264 |
v = qapi_dealloc_get_visitor(md); |
|
265 |
visit_type_UserDefOne(v, &ret_in, "unused", errp); |
|
266 |
qapi_dealloc_visitor_cleanup(md); |
|
267 |
|
|
268 |
|
|
269 |
*ret_out = qmp_output_get_qobject(mo); |
|
270 |
} |
|
271 |
|
|
272 |
static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp) |
|
273 |
{ |
|
274 |
UserDefOne * retval = NULL; |
|
275 |
QmpInputVisitor *mi; |
|
276 |
QapiDeallocVisitor *md; |
|
277 |
Visitor *v; |
|
278 |
UserDefOne * arg1 = NULL; |
|
279 |
|
|
280 |
mi = qmp_input_visitor_new(QOBJECT(args)); |
|
281 |
v = qmp_input_get_visitor(mi); |
|
282 |
visit_type_UserDefOne(v, &arg1, "arg1", errp); |
|
283 |
|
|
284 |
if (error_is_set(errp)) { |
|
285 |
goto out; |
|
286 |
} |
|
287 |
retval = qmp_my_command(arg1, errp); |
|
288 |
qmp_marshal_output_my_command(retval, ret, errp); |
|
289 |
|
|
290 |
out: |
|
291 |
md = qapi_dealloc_visitor_new(); |
|
292 |
v = qapi_dealloc_get_visitor(md); |
|
293 |
visit_type_UserDefOne(v, &arg1, "arg1", errp); |
|
294 |
qapi_dealloc_visitor_cleanup(md); |
|
295 |
return; |
|
296 |
} |
|
297 |
|
|
298 |
static void qmp_init_marshal(void) |
|
299 |
{ |
|
300 |
qmp_register_command("my-command", qmp_marshal_input_my_command); |
|
301 |
} |
|
302 |
|
|
303 |
qapi_init(qmp_init_marshal); |
|
304 |
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h |
|
305 |
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ |
|
306 |
|
|
307 |
#ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS |
|
308 |
#define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS |
|
309 |
|
|
310 |
#include "example-qapi-types.h" |
|
311 |
#include "error.h" |
|
312 |
|
|
313 |
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp); |
|
314 |
|
|
315 |
#endif |
|
316 |
mdroth@illuin:~/w/qemu2.git$ |
Also available in: Unified diff