= 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.
the first line names the expression, an optional overview is provided,
then individual documentation about each member of 'data' is provided,
and finally, a 'Since: x.y.z' tag lists the release that introduced
-the expression. Optional fields are tagged with the phrase
+the expression. Optional members are tagged with the phrase
'#optional', often with their default value; and extensions added
after the expression was first released are also given a '(since
x.y.z)' comment. For example:
definitions should not end in 'Kind', as this namespace is used for
creating implicit C enums for visiting union types, or in 'List', as
this namespace is used for creating array types. Command names,
-and field names within a type, should be all lower case with words
+and member names within a type, should be all lower case with words
separated by a hyphen. However, some existing older commands and
complex types use underscore; when extending such expressions,
consistency is preferred over blindly avoiding underscore. Event
-names should be ALL_CAPS with words separated by underscore. Field
+names should be ALL_CAPS with words separated by underscore. Member
names cannot start with 'has-' or 'has_', as this is reserved for
-tracking optional fields.
+tracking optional members.
-Any name (command, event, type, field, or enum value) beginning with
+Any name (command, event, type, member, or enum value) beginning with
"x-" is marked experimental, and may be withdrawn or changed
-incompatibly in a future release. Downstream vendors may add
-extensions; such extensions should begin with a prefix matching
-"__RFQDN_" (for the reverse-fully-qualified-domain-name of the
-vendor), even if the rest of the name uses dash (example:
-__com.redhat_drive-mirror). Other than downstream extensions (with
-leading underscore and the use of dots), all names should begin with a
-letter, and contain only ASCII letters, digits, dash, and underscore.
-Names beginning with 'q_' are reserved for the generator: QMP names
-that resemble C keywords or other problematic strings will be munged
-in C to use this prefix. For example, a field named "default" in
-qapi becomes "q_default" in the generated C code.
+incompatibly in a future release. All names must begin with a letter,
+and contain only ASCII letters, digits, dash, and underscore. There
+are two exceptions: enum values may start with a digit, and any
+extensions added by downstream vendors should start with a prefix
+matching "__RFQDN_" (for the reverse-fully-qualified-domain-name of
+the vendor), even if the rest of the name uses dash (example:
+__com.redhat_drive-mirror). Names beginning with 'q_' are reserved
+for the generator: QMP names that resemble C keywords or other
+problematic strings will be munged in C to use this prefix. For
+example, a member named "default" in qapi becomes "q_default" in the
+generated C code.
In the rest of this document, usage lines are given for each
expression type, with literal strings written in lower case and
accepts size suffixes
bool bool JSON true or false
any QObject * any JSON value
+ QType QType JSON string matching enum QType values
=== Includes ===
Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME }
-A struct is a dictionary containing a single 'data' key whose
-value is a dictionary. This corresponds to a struct in C or an Object
-in JSON. Each value of the 'data' dictionary must be the name of a
-type, or a one-element array containing a type name. An example of a
-struct is:
+A struct is a dictionary containing a single 'data' key whose value is
+a dictionary; the dictionary may be empty. This corresponds to a
+struct in C or an Object in JSON. Each value of the 'data' dictionary
+must be the name of a type, or a one-element array containing a type
+name. An example of a struct is:
{ 'struct': 'MyType',
'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
On output structures (only mentioned in the 'returns' side of a command),
changing from mandatory to optional is in general unsafe (older clients may be
-expecting the field, and could crash if it is missing), although it can be done
-if the only way that the optional argument will be omitted is when it is
-triggered by the presence of a new input flag to the command that older clients
-don't know to send. Changing from optional to mandatory is safe.
+expecting the member, and could crash if it is missing), although it
+can be done if the only way that the optional argument will be omitted
+is when it is triggered by the presence of a new input flag to the
+command that older clients don't know to send. Changing from optional
+to mandatory is safe.
A structure that is used in both input and output of various commands
must consider the backwards compatibility constraints of both directions
of use.
A struct definition can specify another struct as its base.
-In this case, the fields of the base type are included as top-level fields
+In this case, the members of the base type are included as top-level members
of the new struct's dictionary in the Client JSON Protocol wire
format. An example definition is:
'data': { '*backing': 'str' } }
An example BlockdevOptionsGenericCOWFormat object on the wire could use
-both fields like this:
+both members like this:
{ "file": "/some/place/my-image",
"backing": "/some/place/my-backing-file" }
type name into a set of underscore separated words. For the example
above, 'MyEnum' will turn into 'MY_ENUM' giving a constant name
of 'MY_ENUM_VALUE1' for the first value. If the default heuristic
-does not result in a desirable name, the optional 'prefix' field
+does not result in a desirable name, the optional 'prefix' member
can be used when defining the enum.
The enumeration values are passed as strings over the Client JSON
always passes by name, it is acceptable to reorder or add new
enumeration members in any location without breaking clients of Client
JSON Protocol; however, removing enum values would break
-compatibility. For any struct that has a field that will only contain
-a finite set of string values, using an enum type for that field is
-better than open-coding the field to be type 'str'.
+compatibility. For any struct that has a member that will only contain
+a finite set of string values, using an enum type for that member is
+better than open-coding the member to be type 'str'.
=== Union types ===
Usage: { 'union': STRING, 'data': DICT }
-or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME,
+or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME-OR-DICT,
'discriminator': ENUM-MEMBER-OF-BASE }
Union types are used to let the user choose between several different
variants for an object. There are two flavors: simple (no
-discriminator or base), flat (both discriminator and base). A union
+discriminator or base), and flat (both discriminator and base). A union
type is defined using a data dictionary as explained in the following
-paragraphs.
+paragraphs. The data dictionary for either type of union must not
+be empty.
A simple union type defines a mapping from automatic discriminator
values to data types like in this example:
- { 'struct': 'FileOptions', 'data': { 'filename': 'str' } }
- { 'struct': 'Qcow2Options',
- 'data': { 'backing-file': 'str', 'lazy-refcounts': 'bool' } }
+ { 'struct': 'BlockdevOptionsFile', 'data': { 'filename': 'str' } }
+ { 'struct': 'BlockdevOptionsQcow2',
+ 'data': { 'backing': 'str', '*lazy-refcounts': 'bool' } }
- { 'union': 'BlockdevOptions',
- 'data': { 'file': 'FileOptions',
- 'qcow2': 'Qcow2Options' } }
+ { 'union': 'BlockdevOptionsSimple',
+ 'data': { 'file': 'BlockdevOptionsFile',
+ 'qcow2': 'BlockdevOptionsQcow2' } }
In the Client JSON Protocol, a simple union is represented by a
-dictionary that contains the 'type' field as a discriminator, and a
-'data' field that is of the specified data type corresponding to the
+dictionary that contains the 'type' member as a discriminator, and a
+'data' member that is of the specified data type corresponding to the
discriminator value, as in these examples:
- { "type": "file", "data" : { "filename": "/some/place/my-image" } }
- { "type": "qcow2", "data" : { "backing-file": "/some/place/my-image",
- "lazy-refcounts": true } }
+ { "type": "file", "data": { "filename": "/some/place/my-image" } }
+ { "type": "qcow2", "data": { "backing": "/some/place/my-image",
+ "lazy-refcounts": true } }
The generated C code uses a struct containing a union. Additionally,
an implicit C enum 'NameKind' is created, corresponding to the union
the union can be named 'max', as this would collide with the implicit
enum. The value for each branch can be of any type.
-A flat union definition specifies a struct as its base, and
-avoids nesting on the wire. All branches of the union must be
-complex types, and the top-level fields of the union dictionary on
-the wire will be combination of fields from both the base type and the
-appropriate branch type (when merging two dictionaries, there must be
-no keys in common). The 'discriminator' field must be the name of an
-enum-typed member of the base struct.
+A flat union definition avoids nesting on the wire, and specifies a
+set of common members that occur in all variants of the union. The
+'base' key must specify either a type name (the type must be a
+struct, not a union), or a dictionary representing an anonymous type.
+All branches of the union must be complex types, and the top-level
+members of the union dictionary on the wire will be combination of
+members from both the base type and the appropriate branch type (when
+merging two dictionaries, there must be no keys in common). The
+'discriminator' member must be the name of a non-optional enum-typed
+member of the base struct.
The following example enhances the above simple union example by
-adding a common field 'readonly', renaming the discriminator to
-something more applicable, and reducing the number of {} required on
-the wire:
+adding an optional common member 'read-only', renaming the
+discriminator to something more applicable than the simple union's
+default of 'type', and reducing the number of {} required on the wire:
{ 'enum': 'BlockdevDriver', 'data': [ 'file', 'qcow2' ] }
- { 'struct': 'BlockdevCommonOptions',
- 'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
{ 'union': 'BlockdevOptions',
- 'base': 'BlockdevCommonOptions',
+ 'base': { 'driver': 'BlockdevDriver', '*read-only': 'bool' },
'discriminator': 'driver',
- 'data': { 'file': 'FileOptions',
- 'qcow2': 'Qcow2Options' } }
+ 'data': { 'file': 'BlockdevOptionsFile',
+ 'qcow2': 'BlockdevOptionsQcow2' } }
Resulting in these JSON objects:
- { "driver": "file", "readonly": true,
+ { "driver": "file", "read-only": true,
"filename": "/some/place/my-image" }
- { "driver": "qcow2", "readonly": false,
- "backing-file": "/some/place/my-image", "lazy-refcounts": true }
+ { "driver": "qcow2", "read-only": false,
+ "backing": "/some/place/my-image", "lazy-refcounts": true }
Notice that in a flat union, the discriminator name is controlled by
the user, but because it must map to a base member with enum type, the
code generator can ensure that branches exist for all values of the
enum (although the order of the keys need not match the declaration of
the enum). In the resulting generated C data types, a flat union is
-represented as a struct with the base member fields included directly,
-and then a union of structures for each branch of the struct.
+represented as a struct with the base members included directly, and
+then a union of structures for each branch of the struct.
A simple union can always be re-written as a flat union where the base
class has a single member named 'type', and where each branch of the
is identical on the wire to:
{ 'enum': 'Enum', 'data': ['one', 'two'] }
- { 'struct': 'Base', 'data': { 'type': 'Enum' } }
{ 'struct': 'Branch1', 'data': { 'data': 'str' } }
{ 'struct': 'Branch2', 'data': { 'data': 'int' } }
- { 'union': 'Flat', 'base': 'Base', 'discriminator': 'type',
+ { 'union': 'Flat': 'base': { 'type': 'Enum' }, 'discriminator': 'type',
'data': { 'one': 'Branch1', 'two': 'Branch2' } }
array) on the wire. The definition is similar to a simple union type,
where each branch of the union names a QAPI type. For example:
- { 'alternate': 'BlockRef',
+ { 'alternate': 'BlockdevRef',
'data': { 'definition': 'BlockdevOptions',
'reference': 'str' } }
-Just like for a simple union, an implicit C enum 'NameKind' is created
-to enumerate the branches for the alternate 'Name'.
-
Unlike a union, the discriminator string is never passed on the wire
for the Client JSON Protocol. Instead, the value's JSON type serves
as an implicit discriminator, which in turn means that an alternate
{ "file": "my_existing_block_device_id" }
{ "file": { "driver": "file",
- "readonly": false,
+ "read-only": false,
"filename": "/tmp/mydisk.qcow2" } }
=== Commands ===
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
- '*returns': TYPE-NAME,
+ '*returns': TYPE-NAME, '*boxed': true,
'*gen': false, '*success-response': false }
Commands are defined by using a dictionary containing several members,
anonymous type with the same semantics as a 'struct' expression, with
one exception noted below when 'gen' is used.
-The 'returns' member describes what will appear in the "return" field
+The 'returns' member describes what will appear in the "return" member
of a Client JSON Protocol reply on successful completion of a command.
The member is optional from the command declaration; if absent, the
-"return" field will be an empty dictionary. If 'returns' is present,
+"return" member will be an empty dictionary. If 'returns' is present,
it must be the string name of a complex or built-in type, a
one-element array containing the name of a complex or built-in type,
with one exception noted below when 'gen' is used. Although it is
array of built-in types, any command that does this cannot be extended
to return additional information in the future; thus, new commands
should strongly consider returning a dictionary-based type or an array
-of dictionaries, even if the dictionary only contains one field at the
+of dictionaries, even if the dictionary only contains one member at the
present.
All commands in Client JSON Protocol use a dictionary to report
=> { "execute": "my-second-command" }
<= { "return": [ { "value": "one" }, { } ] }
+The generator emits a prototype for the user's function implementing
+the command. Normally, 'data' is a dictionary for an anonymous type,
+or names a struct type (possibly empty, but not a union), and its
+members are passed as separate arguments to this function. If the
+command definition includes a key 'boxed' with the boolean value true,
+then 'data' is instead the name of any non-empty complex type
+(struct, union, or alternate), and a pointer to that QAPI type is
+passed as a single argument.
+
+The generator also emits a marshalling function that extracts
+arguments for the user's function out of an input QDict, calls the
+user's function, and if it succeeded, builds an output QObject from
+its return value.
+
In rare cases, QAPI cannot express a type-safe representation of a
corresponding Client JSON Protocol command. You then have to suppress
generation of a marshalling function by including a key 'gen' with
normal dictionary error on failure). When a successful reply is not
possible, the command expression should include the optional key
'success-response' with boolean value false. So far, only QGA makes
-use of this field.
+use of this member.
=== Events ===
-Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT }
+Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
+ '*boxed': true }
Events are defined with the keyword 'event'. It is not allowed to
name an event 'MAX', since the generator also produces a C enumeration
"data": { "b": "test string" },
"timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+The generator emits a function to send the event. Normally, 'data' is
+a dictionary for an anonymous type, or names a struct type (possibly
+empty, but not a union), and its members are passed as separate
+arguments to this function. If the event definition includes a key
+'boxed' with the boolean value true, then 'data' is instead the name of
+any non-empty complex type (struct, union, or alternate), and a
+pointer to that QAPI type is passed as a single argument.
+
== Client JSON Protocol introspection ==
For this purpose, QMP provides introspection via command
query-qmp-schema. QGA currently doesn't support introspection.
+While Client JSON Protocol wire compatibility should be maintained
+between qemu versions, we cannot make the same guarantees for
+introspection stability. For example, one version of qemu may provide
+a non-variant optional member of a struct, and a later version rework
+the member to instead be non-optional and associated with a variant.
+Likewise, one version of qemu may list a member with open-ended type
+'str', and a later version could convert it to a finite set of strings
+via an enum type; or a member may be converted from a specific type to
+an alternate that represents a choice between the original type and
+something else.
+
query-qmp-schema returns a JSON array of SchemaInfo objects. These
objects together describe the wire ABI, as defined in the QAPI schema.
+There is no specified order to the SchemaInfo objects returned; a
+client must search for a particular name throughout the entire array
+to learn more about that name, but is at least guaranteed that there
+will be no collisions between type, command, and event names.
However, the SchemaInfo can't reflect all the rules and restrictions
that apply to QMP. It's interface introspection (figuring out what's
Example: the SchemaInfo for command query-qmp-schema
{ "name": "query-qmp-schema", "meta-type": "command",
- "arg-type": ":empty", "ret-type": "SchemaInfoList" }
+ "arg-type": "q_empty", "ret-type": "SchemaInfoList" }
- Type ":empty" is an object type without members, and type
+ Type "q_empty" is an automatic object type without members, and type
"SchemaInfoList" is the array of SchemaInfo type.
The SchemaInfo for an event has meta-type "event", and variant member
Example: the SchemaInfo for EVENT_C from section Events
{ "name": "EVENT_C", "meta-type": "event",
- "arg-type": ":obj-EVENT_C-arg" }
+ "arg-type": "q_obj-EVENT_C-arg" }
- Type ":obj-EVENT_C-arg" is an implicitly defined object type with
+ Type "q_obj-EVENT_C-arg" is an implicitly defined object type with
the two members from the event's definition.
The SchemaInfo for struct and union types has meta-type "object".
name), "type" (the name of its type), and optionally "default". The
member is optional if "default" is present. Currently, "default" can
only have value null. Other values are reserved for future
-extensions.
+extensions. The "members" array is in no particular order; clients
+must search the entire object when learning whether a particular
+member is supported.
Example: the SchemaInfo for MyType from section Struct types
"variants" is a JSON array describing the object's variant members.
Each element is a JSON object with members "case" (the value of type
tag this element applies to) and "type" (the name of an object type
-that provides the variant members for this type tag value).
+that provides the variant members for this type tag value). The
+"variants" array is in no particular order, and is not guaranteed to
+list cases in the same order as the corresponding "tag" enum type.
Example: the SchemaInfo for flat union BlockdevOptions from section
Union types
{ "name": "BlockdevOptions", "meta-type": "object",
"members": [
{ "name": "driver", "type": "BlockdevDriver" },
- { "name": "readonly", "type": "bool"} ],
+ { "name": "read-only", "type": "bool", "default": null } ],
"tag": "driver",
"variants": [
- { "case": "file", "type": "FileOptions" },
- { "case": "qcow2", "type": "Qcow2Options" } ] }
+ { "case": "file", "type": "BlockdevOptionsFile" },
+ { "case": "qcow2", "type": "BlockdevOptionsQcow2" } ] }
Note that base types are "flattened": its members are included in the
"members" array.
A simple union implicitly defines an object type for each of its
variants.
-Example: the SchemaInfo for simple union BlockdevOptions from section
+Example: the SchemaInfo for simple union BlockdevOptionsSimple from section
Union types
- { "name": "BlockdevOptions", "meta-type": "object",
+ { "name": "BlockdevOptionsSimple", "meta-type": "object",
"members": [
- { "name": "kind", "type": "BlockdevOptionsKind" } ],
+ { "name": "type", "type": "BlockdevOptionsSimpleKind" } ],
"tag": "type",
"variants": [
- { "case": "file", "type": ":obj-FileOptions-wrapper" },
- { "case": "qcow2", "type": ":obj-Qcow2Options-wrapper" } ] }
+ { "case": "file", "type": "q_obj-BlockdevOptionsFile-wrapper" },
+ { "case": "qcow2", "type": "q_obj-BlockdevOptionsQcow2-wrapper" } ] }
- Enumeration type "BlockdevOptionsKind" and the object types
- ":obj-FileOptions-wrapper", ":obj-Qcow2Options-wrapper" are
- implicitly defined.
+ Enumeration type "BlockdevOptionsSimpleKind" and the object types
+ "q_obj-BlockdevOptionsFile-wrapper", "q_obj-BlockdevOptionsQcow2-wrapper"
+ are implicitly defined.
The SchemaInfo for an alternate type has meta-type "alternate", and
variant member "members". "members" is a JSON array. Each element is
a JSON object with member "type", which names a type. Values of the
-alternate type conform to exactly one of its member types.
+alternate type conform to exactly one of its member types. There is
+no guarantee on the order in which "members" will be listed.
-Example: the SchemaInfo for BlockRef from section Alternate types
+Example: the SchemaInfo for BlockdevRef from section Alternate types
- { "name": "BlockRef", "meta-type": "alternate",
+ { "name": "BlockdevRef", "meta-type": "alternate",
"members": [
{ "type": "BlockdevOptions" },
{ "type": "str" } ] }
The SchemaInfo for an array type has meta-type "array", and variant
member "element-type", which names the array's element type. Array
-types are implicitly defined.
+types are implicitly defined. For convenience, the array's name may
+resemble the element type; however, clients should examine member
+"element-type" instead of making assumptions based on parsing member
+"name".
Example: the SchemaInfo for ['str']
- { "name": "strList", "meta-type": "array",
+ { "name": "[str]", "meta-type": "array",
"element-type": "str" }
The SchemaInfo for an enumeration type has meta-type "enum" and
-variant member "values".
+variant member "values". The values are listed in no particular
+order; clients must search the entire enum when learning whether a
+particular value is supported.
Example: the SchemaInfo for MyEnum from section Enumeration types
== 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
$ 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...]
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)
+ {
+ Visitor *v;
+
+ if (!obj) {
+ return;
+ }
+
+ v = qapi_dealloc_visitor_new();
+ visit_type_UserDefOne(v, NULL, &obj, NULL);
+ visit_free(v);
+ }
+
+ void qapi_free_UserDefOneList(UserDefOneList *obj)
+ {
+ Visitor *v;
+
+ if (!obj) {
+ return;
+ }
+
+ v = qapi_dealloc_visitor_new();
+ visit_type_UserDefOneList(v, NULL, &obj, NULL);
+ visit_free(v);
+ }
=== 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:
$ 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;
+ 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;
- 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);
+ 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);
+ if (err) {
+ goto out_obj;
+ }
+ visit_check_struct(v, &err);
+ out_obj:
+ visit_end_struct(v, (void **)obj);
+ if (err && visit_is_input(v)) {
+ 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 *tail;
+ size_t size = sizeof(**obj);
- visit_start_list(v, name, &err);
+ visit_start_list(v, name, (GenericList **)obj, size, &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);
+ for (tail = *obj; tail;
+ tail = (UserDefOneList *)visit_next_list(v, (GenericList *)tail, size)) {
+ visit_type_UserDefOne(v, NULL, &tail->value, &err);
+ if (err) {
+ break;
+ }
}
- error_propagate(errp, err);
- err = NULL;
- visit_end_list(v, &err);
+ visit_end_list(v, (void **)obj);
+ if (err && visit_is_input(v)) {
+ qapi_free_UserDefOneList(*obj);
+ *obj = NULL;
+ }
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() (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
$ 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...]
static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp)
{
Error *err = NULL;
- QmpOutputVisitor *qov = qmp_output_visitor_new();
- QapiDeallocVisitor *qdv;
Visitor *v;
- v = qmp_output_get_visitor(qov);
- visit_type_UserDefOne(v, &ret_in, "unused", &err);
- if (err) {
- goto out;
+ v = qmp_output_visitor_new(ret_out);
+ visit_type_UserDefOne(v, "unused", &ret_in, &err);
+ if (!err) {
+ visit_complete(v, ret_out);
}
- *ret_out = qmp_output_get_qobject(qov);
-
- out:
error_propagate(errp, err);
- qmp_output_visitor_cleanup(qov);
- qdv = qapi_dealloc_visitor_new();
- v = qapi_dealloc_get_visitor(qdv);
- visit_type_UserDefOne(v, &ret_in, "unused", NULL);
- qapi_dealloc_visitor_cleanup(qdv);
+ visit_free(v);
+ v = qapi_dealloc_visitor_new();
+ visit_type_UserDefOne(v, "unused", &ret_in, NULL);
+ visit_free(v);
}
static void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp)
{
Error *err = NULL;
UserDefOne *retval;
- 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);
+ v = qmp_input_visitor_new(QOBJECT(args), true);
+ visit_start_struct(v, NULL, NULL, 0, &err);
+ if (err) {
+ goto out;
+ }
+ visit_type_UserDefOneList(v, "arg1", &arg1, &err);
+ if (!err) {
+ visit_check_struct(v, &err);
+ }
+ visit_end_struct(v, NULL);
if (err) {
goto out;
}
out:
error_propagate(errp, err);
- qmp_input_visitor_cleanup(qiv);
- qdv = qapi_dealloc_visitor_new();
- v = qapi_dealloc_get_visitor(qdv);
- visit_type_UserDefOne(v, &arg1, "arg1", NULL);
- qapi_dealloc_visitor_cleanup(qdv);
+ visit_free(v);
+ v = qapi_dealloc_visitor_new();
+ visit_start_struct(v, NULL, NULL, 0, NULL);
+ visit_type_UserDefOneList(v, "arg1", &arg1, NULL);
+ visit_end_struct(v, NULL);
+ visit_free(v);
}
static void qmp_init_marshal(void)
}
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
$ 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...]
const char *const example_QAPIEvent_lookup[] = {
[EXAMPLE_QAPI_EVENT_MY_EVENT] = "MY_EVENT",
- [EXAMPLE_QAPI_EVENT_MAX] = NULL,
+ [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 ===
$ python scripts/qapi-introspect.py --output-dir="qapi-generated"
--prefix="example-" example-schema.json
- $ cat qapi-generated/example-qmp-introspect.c
-[Uninteresting stuff omitted...]
-
- const char example_qmp_schema_json[] = "["
- "{\"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\"}, "
- "{\"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...]
extern const char example_qmp_schema_json[];
#endif
+ $ cat qapi-generated/example-qmp-introspect.c
+[Uninteresting stuff omitted...]
+
+ const char example_qmp_schema_json[] = "["
+ "{\"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\"}, {\"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\"}]";