提交 967c8851 编写于 作者: M Marc-André Lureau 提交者: Markus Armbruster

qapi: add 'if' to top-level expressions

Accept 'if' key in top-level elements, accepted as string or list of
string type. The following patches will modify the test visitor to
check the value is correctly saved, and generate #if/#endif code (as a
single #if/endif line or a series for a list).

Example of 'if' key:
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
  'if': 'defined(TEST_IF_STRUCT)' }

The generated code is for now *unconditional*. Later patches generate
the conditionals.
Signed-off-by: NMarc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: NMarkus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-2-marcandre.lureau@redhat.com>
[Commit message and Documentation improved]
Signed-off-by: NMarkus Armbruster <armbru@redhat.com>
上级 b07cd3e7
......@@ -744,6 +744,35 @@ Example: Red Hat, Inc. controls redhat.com, and may therefore add a
downstream command __com.redhat_drive-mirror.
=== Configuring the schema ===
The 'struct', 'enum', 'union', 'alternate', 'command' and 'event'
top-level expressions can take an 'if' key. Its value must be a string
or a list of strings. A string is shorthand for a list containing just
that string. The code generated for the top-level expression will then
be guarded by #if COND for each COND in the list.
Example: a conditional struct
{ 'struct': 'IfStruct', 'data': { 'foo': 'int' },
'if': ['defined(CONFIG_FOO)', 'defined(HAVE_BAR)'] }
gets its generated code guarded like this:
#if defined(CONFIG_FOO)
#if defined(HAVE_BAR)
... generated code ...
#endif /* defined(HAVE_BAR) */
#endif /* defined(CONFIG_FOO) */
Please note that you are responsible to ensure that the C code will
compile with an arbitrary combination of conditions, since the
generators are unable to check it at this point.
The presence of 'if' keys in the schema is reflected through to the
introspection output depending on the build configuration.
== Client JSON Protocol introspection ==
Clients of a Client JSON Protocol commonly need to figure out what
......
......@@ -638,6 +638,27 @@ def add_name(name, info, meta, implicit=False):
all_names[name] = meta
def check_if(expr, info):
def check_if_str(ifcond, info):
if not isinstance(ifcond, str):
raise QAPISemError(
info, "'if' condition must be a string or a list of strings")
if ifcond == '':
raise QAPISemError(info, "'if' condition '' makes no sense")
ifcond = expr.get('if')
if ifcond is None:
return
if isinstance(ifcond, list):
if ifcond == []:
raise QAPISemError(info, "'if' condition [] is useless")
for elt in ifcond:
check_if_str(elt, info)
else:
check_if_str(ifcond, info)
def check_type(info, source, value, allow_array=False,
allow_dict=False, allow_optional=False,
allow_metas=[]):
......@@ -871,6 +892,8 @@ def check_keys(expr_elem, meta, required, optional=[]):
raise QAPISemError(info,
"'%s' of %s '%s' should only use true value"
% (key, meta, name))
if key == 'if':
check_if(expr, info)
for key in required:
if key not in expr:
raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
......@@ -899,28 +922,28 @@ def check_exprs(exprs):
if 'enum' in expr:
meta = 'enum'
check_keys(expr_elem, 'enum', ['data'], ['prefix'])
check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix'])
enum_types[expr[meta]] = expr
elif 'union' in expr:
meta = 'union'
check_keys(expr_elem, 'union', ['data'],
['base', 'discriminator'])
['base', 'discriminator', 'if'])
union_types[expr[meta]] = expr
elif 'alternate' in expr:
meta = 'alternate'
check_keys(expr_elem, 'alternate', ['data'])
check_keys(expr_elem, 'alternate', ['data'], ['if'])
elif 'struct' in expr:
meta = 'struct'
check_keys(expr_elem, 'struct', ['data'], ['base'])
check_keys(expr_elem, 'struct', ['data'], ['base', 'if'])
struct_types[expr[meta]] = expr
elif 'command' in expr:
meta = 'command'
check_keys(expr_elem, 'command', [],
['data', 'returns', 'gen', 'success-response',
'boxed', 'allow-oob', 'allow-preconfig'])
'boxed', 'allow-oob', 'allow-preconfig', 'if'])
elif 'event' in expr:
meta = 'event'
check_keys(expr_elem, 'event', [], ['data', 'boxed'])
check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
else:
raise QAPISemError(expr_elem['info'],
"Expression is missing metatype")
......
......@@ -442,6 +442,10 @@ qapi-schema += args-unknown.json
qapi-schema += bad-base.json
qapi-schema += bad-data.json
qapi-schema += bad-ident.json
qapi-schema += bad-if.json
qapi-schema += bad-if-empty.json
qapi-schema += bad-if-empty-list.json
qapi-schema += bad-if-list.json
qapi-schema += bad-type-bool.json
qapi-schema += bad-type-dict.json
qapi-schema += bad-type-int.json
......
tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
# check empty 'if' list
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
'if': [] }
tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense
# check empty 'if'
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
'if': '' }
tests/qapi-schema/bad-if-list.json:2: 'if' condition '' makes no sense
# check invalid 'if' content
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
'if': ['foo', ''] }
tests/qapi-schema/bad-if.json:2: 'if' condition must be a string or a list of strings
# check invalid 'if' type
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
'if': { 'value': 'defined(TEST_IF_STRUCT)' } }
......@@ -56,6 +56,9 @@
'data': { 'string0': 'str',
'dict1': 'UserDefTwoDict' } }
{ 'struct': 'UserDefThree',
'data': { 'string0': 'str' } }
# dummy struct to force generation of array types not otherwise mentioned
{ 'struct': 'ForceArrays',
'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'],
......@@ -193,3 +196,26 @@
'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
'returns': '__org.qemu_x-Union1' }
# test 'if' condition handling
{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
'if': 'defined(TEST_IF_STRUCT)' }
{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
'if': 'defined(TEST_IF_ENUM)' }
{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
'returns': 'UserDefThree',
'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] }
{ 'command': 'TestCmdReturnDefThree', 'returns': 'UserDefThree' }
{ 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
......@@ -36,6 +36,8 @@ object UserDefTwoDict
object UserDefTwo
member string0: str optional=False
member dict1: UserDefTwoDict optional=False
object UserDefThree
member string0: str optional=False
object ForceArrays
member unused1: UserDefOneList optional=False
member unused2: UserDefTwoList optional=False
......@@ -233,3 +235,27 @@ object q_obj___org.qemu_x-command-arg
member d: __org.qemu_x-Alt optional=False
command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
gen=True success_response=True boxed=False oob=False preconfig=False
object TestIfStruct
member foo: int optional=False
enum TestIfEnum ['foo', 'bar']
object q_obj_TestStruct-wrapper
member data: TestStruct optional=False
enum TestIfUnionKind ['foo']
object TestIfUnion
member type: TestIfUnionKind optional=False
tag type
case foo: q_obj_TestStruct-wrapper
alternate TestIfAlternate
tag type
case foo: int
case bar: TestStruct
object q_obj_TestIfCmd-arg
member foo: TestIfStruct optional=False
command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
command TestCmdReturnDefThree None -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
object q_obj_TestIfEvent-arg
member foo: TestIfStruct optional=False
event TestIfEvent q_obj_TestIfEvent-arg
boxed=False
......@@ -12,6 +12,18 @@
static QmpCommandList qmp_commands;
/* #if defined(TEST_IF_STRUCT) && defined(TEST_IF_CMD) */
UserDefThree *qmp_TestIfCmd(TestIfStruct *foo, Error **errp)
{
return NULL;
}
/* #endif */
UserDefThree *qmp_TestCmdReturnDefThree(Error **errp)
{
return NULL;
}
void qmp_user_def_cmd(Error **errp)
{
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册