From 58f88d4b7e9e5578b8dd2c5acfe555b85b35af88 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 8 May 2015 16:04:22 -0300 Subject: [PATCH 01/26] qmp: Add qom_path field to query-cpus command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow clients to query additional information directly using qom-get on the CPU objects. Reviewed-by: David Gibson Reviewed-by: Andreas Färber Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Markus Armbruster --- cpus.c | 1 + qapi-schema.json | 8 ++++++-- qmp-commands.hx | 7 +++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cpus.c b/cpus.c index 62d157a85c..de6469fa8d 100644 --- a/cpus.c +++ b/cpus.c @@ -1435,6 +1435,7 @@ CpuInfoList *qmp_query_cpus(Error **errp) info->value->CPU = cpu->cpu_index; info->value->current = (cpu == first_cpu); info->value->halted = cpu->halted; + info->value->qom_path = object_get_canonical_path(OBJECT(cpu)); info->value->thread_id = cpu->thread_id; #if defined(TARGET_I386) info->value->has_pc = true; diff --git a/qapi-schema.json b/qapi-schema.json index 9c92482898..f97ffa1132 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -679,6 +679,8 @@ # @halted: true if the virtual CPU is in the halt state. Halt usually refers # to a processor specific low power mode. # +# @qom_path: path to the CPU object in the QOM tree (since 2.4) +# # @pc: #optional If the target is i386 or x86_64, this is the 64-bit instruction # pointer. # If the target is Sparc, this is the PC component of the @@ -699,8 +701,10 @@ # data is sent to the client, the guest may no longer be halted. ## { 'struct': 'CpuInfo', - 'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', '*pc': 'int', - '*nip': 'int', '*npc': 'int', '*PC': 'int', 'thread_id': 'int'} } + 'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool', + 'qom_path': 'str', + '*pc': 'int', '*nip': 'int', '*npc': 'int', '*PC': 'int', + 'thread_id': 'int'} } ## # @query-cpus: diff --git a/qmp-commands.hx b/qmp-commands.hx index 7506774afb..14e109eb5c 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2569,6 +2569,7 @@ Return a json-array. Each CPU is represented by a json-object, which contains: - "CPU": CPU index (json-int) - "current": true if this is the current CPU, false otherwise (json-bool) - "halted": true if the cpu is halted, false otherwise (json-bool) +- "qom_path": path to the CPU object in the QOM tree (json-str) - Current program counter. The key's name depends on the architecture: "pc": i386/x86_64 (json-int) "nip": PPC (json-int) @@ -2585,14 +2586,16 @@ Example: "CPU":0, "current":true, "halted":false, - "pc":3227107138 + "qom_path":"/machine/unattached/device[0]", + "pc":3227107138, "thread_id":3134 }, { "CPU":1, "current":false, "halted":true, - "pc":7108165 + "qom_path":"/machine/unattached/device[2]", + "pc":7108165, "thread_id":3135 } ] From 777abdfe7bb47e582c8eb87dd6cecdf3fd9f86fc Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 11 May 2015 17:17:49 +0200 Subject: [PATCH 02/26] doc: fix qmp event type Event name for hot unplug errors was wrong. Make doc match code. Cc: Zhu Guihua Reported-by: Eric Blake Signed-off-by: Michael S. Tsirkin Reviewed-by: Eric Blake Signed-off-by: Markus Armbruster --- docs/qmp/qmp-events.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt index 6dc2cca7de..4c13d48726 100644 --- a/docs/qmp/qmp-events.txt +++ b/docs/qmp/qmp-events.txt @@ -232,7 +232,7 @@ Example: { "event": "GUEST_PANICKED", "data": { "action": "pause" } } -MEM_HOT_UNPLUG_ERROR +MEM_UNPLUG_ERROR -------------------- Emitted when memory hot unplug error occurs. @@ -243,7 +243,7 @@ Data: Example: -{ "event": "MEM_HOT_UNPLUG_ERROR" +{ "event": "MEM_UNPLUG_ERROR" "data": { "device": "dimm1", "msg": "acpi: device unplug for unsupported device" }, From 47299262de424af0cb69965d082e5e70b2314183 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 14 May 2015 06:50:47 -0600 Subject: [PATCH 03/26] qapi: Fix C identifiers generated for names containing '.' c_fun() maps '.' to '_', c_var() doesn't. Nothing prevents '.' in QAPI names that get passed to c_var(). Which QAPI names get passed to c_fun(), to c_var(), or to both is not obvious. Names of command parameters and struct type members get passed to c_var(). c_var() strips a leading '*', but this cannot happen. c_fun() doesn't. Fix c_var() to work exactly like c_fun(). Perhaps they should be replaced by a single mapping function. Signed-off-by: Markus Armbruster [add 'import string'] Signed-off-by: Eric Blake Reviewed-by: Alberto Garcia --- scripts/qapi.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 166b74f644..4b07805d72 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -15,6 +15,7 @@ import re from ordereddict import OrderedDict import os import sys +import string builtin_types = { 'str': 'QTYPE_QSTRING', @@ -752,6 +753,8 @@ def camel_case(name): new_name += ch.lower() return new_name +c_var_trans = string.maketrans('.-', '__') + def c_var(name, protect=True): # ANSI X3J11/88-090, 3.1.1 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue', @@ -781,10 +784,10 @@ def c_var(name, protect=True): polluted_words = set(['unix', 'errno']) if protect and (name in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words): return "q_" + name - return name.replace('-', '_').lstrip("*") + return name.translate(c_var_trans) def c_fun(name, protect=True): - return c_var(name, protect).replace('.', '_') + return c_var(name, protect) def c_list_type(name): return '%sList' % name From 18df515ebbefa9f13474b128b8050d5fa346ea1e Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:50:48 -0600 Subject: [PATCH 04/26] qapi: Rename identical c_fun()/c_var() into c_name() Now that the two functions are identical, we only need one of them, and we might as well give it a more descriptive name. Basically, the function serves as the translation from a QAPI name into a (portion of a) C identifier, without regards to whether it is a variable or function name. Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi-commands.py | 35 ++++++++++++++++++----------------- scripts/qapi-event.py | 10 +++++----- scripts/qapi-types.py | 8 ++++---- scripts/qapi-visit.py | 10 +++++----- scripts/qapi.py | 11 ++++------- 5 files changed, 36 insertions(+), 38 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 93e43f0e48..8c125cac1f 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -31,12 +31,13 @@ def generate_command_decl(name, args, ret_type): for argname, argtype, optional in parse_args(args): argtype = c_type(argtype, is_param=True) if optional: - arglist += "bool has_%s, " % c_var(argname) - arglist += "%s %s, " % (argtype, c_var(argname)) + arglist += "bool has_%s, " % c_name(argname) + arglist += "%s %s, " % (argtype, c_name(argname)) return mcgen(''' %(ret_type)s qmp_%(name)s(%(args)sError **errp); ''', - ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip() + ret_type=c_type(ret_type), name=c_name(name), + args=arglist).strip() def gen_err_check(errvar): if errvar: @@ -55,14 +56,14 @@ def gen_sync_call(name, args, ret_type, indent=0): retval = "retval = " for argname, argtype, optional in parse_args(args): if optional: - arglist += "has_%s, " % c_var(argname) - arglist += "%s, " % (c_var(argname)) + arglist += "has_%s, " % c_name(argname) + arglist += "%s, " % (c_name(argname)) push_indent(indent) ret = mcgen(''' %(retval)sqmp_%(name)s(%(args)s&local_err); ''', - name=c_fun(name), args=arglist, retval=retval).rstrip() + name=c_name(name), args=arglist, retval=retval).rstrip() if ret_type: ret += "\n" + gen_err_check('local_err') ret += "\n" + mcgen('''' @@ -76,7 +77,7 @@ def gen_sync_call(name, args, ret_type, indent=0): def gen_marshal_output_call(name, ret_type): if not ret_type: return "" - return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_fun(name) + return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_name(name) def gen_visitor_input_containers_decl(args, obj): ret = "" @@ -101,17 +102,17 @@ def gen_visitor_input_vars_decl(args): ret += mcgen(''' bool has_%(argname)s = false; ''', - argname=c_var(argname)) + argname=c_name(argname)) if is_c_ptr(argtype): ret += mcgen(''' %(argtype)s %(argname)s = NULL; ''', - argname=c_var(argname), argtype=c_type(argtype)) + argname=c_name(argname), argtype=c_type(argtype)) else: ret += mcgen(''' %(argtype)s %(argname)s = {0}; ''', - argname=c_var(argname), argtype=c_type(argtype)) + argname=c_name(argname), argtype=c_type(argtype)) pop_indent() return ret.rstrip() @@ -144,17 +145,17 @@ v = qmp_input_get_visitor(mi); ret += mcgen(''' visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); ''', - c_name=c_var(argname), name=argname, errp=errparg) + c_name=c_name(argname), name=argname, errp=errparg) ret += gen_err_check(errarg) ret += mcgen(''' if (has_%(c_name)s) { ''', - c_name=c_var(argname)) + c_name=c_name(argname)) push_indent() ret += mcgen(''' %(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); ''', - c_name=c_var(argname), name=argname, argtype=argtype, + c_name=c_name(argname), name=argname, argtype=argtype, visitor=type_visitor(argtype), errp=errparg) ret += gen_err_check(errarg) if optional: @@ -198,16 +199,16 @@ out: qapi_dealloc_visitor_cleanup(md); } ''', - c_ret_type=c_type(ret_type), c_name=c_fun(name), + c_ret_type=c_type(ret_type), c_name=c_name(name), visitor=type_visitor(ret_type)) return ret def gen_marshal_input_decl(name, args, ret_type, middle_mode): if middle_mode: - return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_fun(name) + return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_name(name) else: - return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_fun(name) + return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name) @@ -304,7 +305,7 @@ def gen_registry(commands): registry += mcgen(''' qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s); ''', - name=cmd['command'], c_name=c_fun(cmd['command']), + name=cmd['command'], c_name=c_name(cmd['command']), opts=options) pop_indent() ret = mcgen(''' diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index 47dc041805..c4612e396e 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -17,17 +17,17 @@ import getopt import errno def _generate_event_api_name(event_name, params): - api_name = "void qapi_event_send_%s(" % c_fun(event_name).lower(); + api_name = "void qapi_event_send_%s(" % c_name(event_name).lower(); l = len(api_name) if params: for argname, argentry, optional in parse_args(params): if optional: - api_name += "bool has_%s,\n" % c_var(argname) + api_name += "bool has_%s,\n" % c_name(argname) api_name += "".ljust(l) api_name += "%s %s,\n" % (c_type(argentry, is_param=True), - c_var(argname)) + c_name(argname)) api_name += "".ljust(l) api_name += "Error **errp)" @@ -98,7 +98,7 @@ def generate_event_implement(api_name, event_name, params): ret += mcgen(""" if (has_%(var)s) { """, - var = c_var(argname)) + var = c_name(argname)) push_indent() if argentry == "str": @@ -113,7 +113,7 @@ def generate_event_implement(api_name, event_name, params): } """, var_type = var_type, - var = c_var(argname), + var = c_name(argname), type = type_name(argentry), name = argname) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 2bf8145076..e74cabece0 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -68,11 +68,11 @@ def generate_struct_fields(members): ret += mcgen(''' bool has_%(c_name)s; ''', - c_name=c_var(argname)) + c_name=c_name(argname)) ret += mcgen(''' %(c_type)s %(c_name)s; ''', - c_type=c_type(argentry), c_name=c_var(argname)) + c_type=c_type(argentry), c_name=c_name(argname)) return ret @@ -184,7 +184,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = { ''', qtype = qtype, abbrev = de_camel_case(name).upper(), - enum = c_fun(de_camel_case(key),False).upper()) + enum = c_name(de_camel_case(key),False).upper()) ret += mcgen(''' }; @@ -221,7 +221,7 @@ struct %(name)s %(c_type)s %(c_name)s; ''', c_type=c_type(typeinfo[key]), - c_name=c_fun(key)) + c_name=c_name(key)) ret += mcgen(''' }; diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 0e67b336fc..ba623b10b8 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -66,7 +66,7 @@ if (err) { goto out; } ''', - type=type_name(base), c_name=c_var('base')) + type=type_name(base), c_name=c_name('base')) for argname, argentry, optional in parse_args(members): if optional: @@ -74,13 +74,13 @@ if (err) { visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err); if (!err && (*obj)->has_%(c_name)s) { ''', - c_name=c_var(argname), name=argname) + c_name=c_name(argname), name=argname) push_indent() ret += mcgen(''' visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err); ''', - type=type_name(argentry), c_name=c_var(argname), + type=type_name(argentry), c_name=c_name(argname), name=argname) if optional: @@ -222,7 +222,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e ''', enum_full_value = enum_full_value, c_type = type_name(members[key]), - c_name = c_fun(key)) + c_name = c_name(key)) ret += mcgen(''' default: @@ -323,7 +323,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e ''', enum_full_value = enum_full_value, c_type=type_name(members[key]), - c_name=c_fun(key)) + c_name=c_name(key)) ret += mcgen(''' default: diff --git a/scripts/qapi.py b/scripts/qapi.py index 4b07805d72..a4701ca4ed 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -753,9 +753,9 @@ def camel_case(name): new_name += ch.lower() return new_name -c_var_trans = string.maketrans('.-', '__') +c_name_trans = string.maketrans('.-', '__') -def c_var(name, protect=True): +def c_name(name, protect=True): # ANSI X3J11/88-090, 3.1.1 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double', 'else', 'enum', 'extern', 'float', @@ -784,10 +784,7 @@ def c_var(name, protect=True): polluted_words = set(['unix', 'errno']) if protect and (name in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words): return "q_" + name - return name.translate(c_var_trans) - -def c_fun(name, protect=True): - return c_var(name, protect) + return name.translate(c_name_trans) def c_list_type(name): return '%sList' % name @@ -945,7 +942,7 @@ def guardend(name): # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 # ENUM24_Name -> ENUM24_NAME def _generate_enum_string(value): - c_fun_str = c_fun(value, False) + c_fun_str = c_name(value, False) if value.isupper(): return c_fun_str From fa6068a1e8ef3c878ac9ee2399bb01eeaf61c366 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 14 May 2015 06:50:49 -0600 Subject: [PATCH 05/26] qapi: Rename _generate_enum_string() to camel_to_upper() Signed-off-by: Markus Armbruster Signed-off-by: Eric Blake --- scripts/qapi.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index a4701ca4ed..7330f7cc64 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -538,7 +538,7 @@ def check_union(expr, expr_info): # Otherwise, check for conflicts in the generated enum else: - c_key = _generate_enum_string(key) + c_key = camel_to_upper(key) if c_key in values: raise QAPIExprError(expr_info, "Union '%s' member '%s' clashes with '%s'" @@ -556,7 +556,7 @@ def check_alternate(expr, expr_info): check_name(expr_info, "Member of alternate '%s'" % name, key) # Check for conflicts in the generated enum - c_key = _generate_enum_string(key) + c_key = camel_to_upper(key) if c_key in values: raise QAPIExprError(expr_info, "Alternate '%s' member '%s' clashes with '%s'" @@ -587,7 +587,7 @@ def check_enum(expr, expr_info): for member in members: check_name(expr_info, "Member of enum '%s'" %name, member, enum_member=True) - key = _generate_enum_string(member) + key = camel_to_upper(member) if key in values: raise QAPIExprError(expr_info, "Enum '%s' member '%s' clashes with '%s'" @@ -941,7 +941,7 @@ def guardend(name): # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 # ENUM24_Name -> ENUM24_NAME -def _generate_enum_string(value): +def camel_to_upper(value): c_fun_str = c_name(value, False) if value.isupper(): return c_fun_str @@ -961,6 +961,6 @@ def _generate_enum_string(value): return new_name.lstrip('_').upper() def generate_enum_full_value(enum_name, enum_value): - abbrev_string = _generate_enum_string(enum_name) - value_string = _generate_enum_string(enum_value) + abbrev_string = camel_to_upper(enum_name) + value_string = camel_to_upper(enum_value) return "%s_%s" % (abbrev_string, value_string) From 7c81c61f9c2274f66ba947eafd9618d60da838a6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 14 May 2015 06:50:50 -0600 Subject: [PATCH 06/26] qapi: Rename generate_enum_full_value() to c_enum_const() Signed-off-by: Markus Armbruster Signed-off-by: Eric Blake --- scripts/qapi-event.py | 5 ++--- scripts/qapi-types.py | 6 +++--- scripts/qapi-visit.py | 4 ++-- scripts/qapi.py | 6 +++--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index c4612e396e..a7e0033cc1 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -177,7 +177,7 @@ typedef enum %(event_enum_name)s event_enum_name = event_enum_name) # append automatically generated _MAX value - enum_max_value = generate_enum_full_value(event_enum_name, "MAX") + enum_max_value = c_enum_const(event_enum_name, "MAX") enum_values = event_enum_values + [ enum_max_value ] i = 0 @@ -343,8 +343,7 @@ for expr in exprs: fdecl.write(ret) # We need an enum value per event - event_enum_value = generate_enum_full_value(event_enum_name, - event_name) + event_enum_value = c_enum_const(event_enum_name, event_name) ret = generate_event_implement(api_name, event_name, params) fdef.write(ret) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index e74cabece0..6ca48c11c0 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -118,13 +118,13 @@ const char *%(name)s_lookup[] = { name=name) i = 0 for value in values: - index = generate_enum_full_value(name, value) + index = c_enum_const(name, value) ret += mcgen(''' [%(index)s] = "%(value)s", ''', index = index, value = value) - max_index = generate_enum_full_value(name, 'MAX') + max_index = c_enum_const(name, 'MAX') ret += mcgen(''' [%(max_index)s] = NULL, }; @@ -150,7 +150,7 @@ typedef enum %(name)s i = 0 for value in enum_values: - enum_full_value = generate_enum_full_value(name, value) + enum_full_value = c_enum_const(name, value) enum_decl += mcgen(''' %(enum_full_value)s = %(i)d, ''', diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index ba623b10b8..0368e62d23 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -214,7 +214,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e or find_union(members[key]) or find_enum(members[key])), "Invalid alternate member" - enum_full_value = generate_enum_full_value(disc_type, key) + enum_full_value = c_enum_const(disc_type, key) ret += mcgen(''' case %(enum_full_value)s: visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); @@ -315,7 +315,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e else: fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);' - enum_full_value = generate_enum_full_value(disc_type, key) + enum_full_value = c_enum_const(disc_type, key) ret += mcgen(''' case %(enum_full_value)s: ''' + fmt + ''' diff --git a/scripts/qapi.py b/scripts/qapi.py index 7330f7cc64..1258f762ba 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -960,7 +960,7 @@ def camel_to_upper(value): new_name += c return new_name.lstrip('_').upper() -def generate_enum_full_value(enum_name, enum_value): - abbrev_string = camel_to_upper(enum_name) - value_string = camel_to_upper(enum_value) +def c_enum_const(type_name, const_name): + abbrev_string = camel_to_upper(type_name) + value_string = camel_to_upper(const_name) return "%s_%s" % (abbrev_string, value_string) From 02e20c7e593363c564aae96e3c5bdc58630ce584 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 14 May 2015 06:50:51 -0600 Subject: [PATCH 07/26] qapi: Simplify c_enum_const() Signed-off-by: Markus Armbruster Signed-off-by: Eric Blake --- scripts/qapi.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 1258f762ba..b917cadf75 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -961,6 +961,4 @@ def camel_to_upper(value): return new_name.lstrip('_').upper() def c_enum_const(type_name, const_name): - abbrev_string = camel_to_upper(type_name) - value_string = camel_to_upper(const_name) - return "%s_%s" % (abbrev_string, value_string) + return camel_to_upper(type_name + '_' + const_name) From b42e91484df9772bb0c26aa0f05390a92d564d6f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 14 May 2015 06:50:52 -0600 Subject: [PATCH 08/26] qapi: Use c_enum_const() in generate_alternate_qtypes() Missed in commit b0b5819. Signed-off-by: Markus Armbruster Signed-off-by: Eric Blake --- scripts/qapi-types.py | 6 ++---- scripts/qapi.py | 11 ----------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 6ca48c11c0..9eb08a6266 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -180,11 +180,9 @@ const int %(name)s_qtypes[QTYPE_MAX] = { assert qtype, "Invalid alternate member" ret += mcgen(''' - [ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s, + [ %(qtype)s ] = %(enum_const)s, ''', - qtype = qtype, - abbrev = de_camel_case(name).upper(), - enum = c_name(de_camel_case(key),False).upper()) + qtype = qtype, enum_const = c_enum_const(name + 'Kind', key)) ret += mcgen(''' }; diff --git a/scripts/qapi.py b/scripts/qapi.py index b917cadf75..3757a91346 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -729,17 +729,6 @@ def parse_args(typeinfo): # value of an optional argument. yield (argname, argentry, optional) -def de_camel_case(name): - new_name = '' - for ch in name: - if ch.isupper() and new_name: - new_name += '_' - if ch == '-': - new_name += '_' - else: - new_name += ch.lower() - return new_name - def camel_case(name): new_name = '' first = True From 849bc5382e42b3b9590c6a50ba30c2fd2450308c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 14 May 2015 06:50:53 -0600 Subject: [PATCH 09/26] qapi: Move camel_to_upper(), c_enum_const() to closely related code Signed-off-by: Markus Armbruster Signed-off-by: Eric Blake --- scripts/qapi.py | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 3757a91346..cc33355a91 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -742,6 +742,31 @@ def camel_case(name): new_name += ch.lower() return new_name +# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1 +# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 +# ENUM24_Name -> ENUM24_NAME +def camel_to_upper(value): + c_fun_str = c_name(value, False) + if value.isupper(): + return c_fun_str + + new_name = '' + l = len(c_fun_str) + for i in range(l): + c = c_fun_str[i] + # When c is upper and no "_" appears before, do more checks + if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_": + # Case 1: next string is lower + # Case 2: previous string is digit + if (i < (l - 1) and c_fun_str[i + 1].islower()) or \ + c_fun_str[i - 1].isdigit(): + new_name += '_' + new_name += c + return new_name.lstrip('_').upper() + +def c_enum_const(type_name, const_name): + return camel_to_upper(type_name + '_' + const_name) + c_name_trans = string.maketrans('.-', '__') def c_name(name, protect=True): @@ -926,28 +951,3 @@ def guardend(name): ''', name=guardname(name)) - -# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1 -# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 -# ENUM24_Name -> ENUM24_NAME -def camel_to_upper(value): - c_fun_str = c_name(value, False) - if value.isupper(): - return c_fun_str - - new_name = '' - l = len(c_fun_str) - for i in range(l): - c = c_fun_str[i] - # When c is upper and no "_" appears before, do more checks - if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_": - # Case 1: next string is lower - # Case 2: previous string is digit - if (i < (l - 1) and c_fun_str[i + 1].islower()) or \ - c_fun_str[i - 1].isdigit(): - new_name += '_' - new_name += c - return new_name.lstrip('_').upper() - -def c_enum_const(type_name, const_name): - return camel_to_upper(type_name + '_' + const_name) From d557344628e32771f07e5b6a2a818ee3d8e7a65f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:50:54 -0600 Subject: [PATCH 10/26] qapi: Tidy c_type() logic c_type() is designed to be called on both string names and on array designations, so 'name' is a bit misleading because it operates on more than strings. Also, no caller ever passes an empty string. Finally, + notation is a bit nicer to read than '%s' % value for string concatenation. Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi.py | 58 +++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index cc33355a91..ecab87907c 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -801,12 +801,12 @@ def c_name(name, protect=True): return name.translate(c_name_trans) def c_list_type(name): - return '%sList' % name + return name + 'List' -def type_name(name): - if type(name) == list: - return c_list_type(name[0]) - return name +def type_name(value): + if type(value) == list: + return c_list_type(value[0]) + return value def add_name(name, info, meta, implicit = False): global all_names @@ -863,42 +863,44 @@ def is_enum(name): return find_enum(name) != None eatspace = '\033EATSPACE.' +pointer_suffix = ' *' + eatspace # A special suffix is added in c_type() for pointer types, and it's # stripped in mcgen(). So please notice this when you check the return # value of c_type() outside mcgen(). -def c_type(name, is_param=False): - if name == 'str': +def c_type(value, is_param=False): + if value == 'str': if is_param: - return 'const char *' + eatspace - return 'char *' + eatspace + return 'const char' + pointer_suffix + return 'char' + pointer_suffix - elif name == 'int': + elif value == 'int': return 'int64_t' - elif (name == 'int8' or name == 'int16' or name == 'int32' or - name == 'int64' or name == 'uint8' or name == 'uint16' or - name == 'uint32' or name == 'uint64'): - return name + '_t' - elif name == 'size': + elif (value == 'int8' or value == 'int16' or value == 'int32' or + value == 'int64' or value == 'uint8' or value == 'uint16' or + value == 'uint32' or value == 'uint64'): + return value + '_t' + elif value == 'size': return 'uint64_t' - elif name == 'bool': + elif value == 'bool': return 'bool' - elif name == 'number': + elif value == 'number': return 'double' - elif type(name) == list: - return '%s *%s' % (c_list_type(name[0]), eatspace) - elif is_enum(name): - return name - elif name == None or len(name) == 0: + elif type(value) == list: + return c_list_type(value[0]) + pointer_suffix + elif is_enum(value): + return value + elif value == None: return 'void' - elif name in events: - return '%sEvent *%s' % (camel_case(name), eatspace) + elif value in events: + return camel_case(value) + 'Event' + pointer_suffix else: - return '%s *%s' % (name, eatspace) + # complex type name + assert isinstance(value, str) and value != "" + return value + pointer_suffix -def is_c_ptr(name): - suffix = "*" + eatspace - return c_type(name).endswith(suffix) +def is_c_ptr(value): + return c_type(value).endswith(pointer_suffix) def genindent(count): ret = "" From c6405b54b7b09a876f2f2fba2aa6f8ac87189cb9 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:50:55 -0600 Subject: [PATCH 11/26] qapi: Make c_type() consistently convert qapi names Continuing the string of cleanups for supporting downstream names containing '.', this patch focuses on ensuring c_type() can handle a downstream name. This patch alone does not fix the places where generator output should be calling this function but was open-coding things instead, but it gets us a step closer. In particular, the changes to c_list_type() and type_name() mean that type_name(FOO) now handles the case when FOO contains '.', '-', or is a ticklish identifier other than a builtin (builtins are exempted because ['int'] must remain mapped to 'intList' and not 'q_intList'). Meanwhile, ['unix'] now maps to 'q_unixList' rather than 'unixList', to match the fact that 'unix' is ticklish; however, our naming conventions state that complex types should start with a capital, so no type name following conventions will ever have the 'q_' prepended. Likewise, changes to c_type() mean that c_type(FOO) properly handles an enum or complex type FOO with '.' or '-' in the name, or is a ticklish identifier (again, a ticklish identifier as a type name violates conventions). Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index ecab87907c..273afedc3d 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -769,6 +769,15 @@ def c_enum_const(type_name, const_name): c_name_trans = string.maketrans('.-', '__') +# Map @name to a valid C identifier. +# If @protect, avoid returning certain ticklish identifiers (like +# C keywords) by prepending "q_". +# +# Used for converting 'name' from a 'name':'type' qapi definition +# into a generated struct member, as well as converting type names +# into substrings of a generated C function name. +# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo' +# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int' def c_name(name, protect=True): # ANSI X3J11/88-090, 3.1.1 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue', @@ -800,13 +809,25 @@ def c_name(name, protect=True): return "q_" + name return name.translate(c_name_trans) +# Map type @name to the C typedef name for the list form. +# +# ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList' def c_list_type(name): - return name + 'List' + return type_name(name) + 'List' +# Map type @value to the C typedef form. +# +# Used for converting 'type' from a 'member':'type' qapi definition +# into the alphanumeric portion of the type for a generated C parameter, +# as well as generated C function names. See c_type() for the rest of +# the conversion such as adding '*' on pointer types. +# 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c' def type_name(value): if type(value) == list: return c_list_type(value[0]) - return value + if value in builtin_types.keys(): + return value + return c_name(value) def add_name(name, info, meta, implicit = False): global all_names @@ -865,6 +886,10 @@ def is_enum(name): eatspace = '\033EATSPACE.' pointer_suffix = ' *' + eatspace +# Map type @name to its C type expression. +# If @is_param, const-qualify the string type. +# +# This function is used for computing the full C type of 'member':'name'. # A special suffix is added in c_type() for pointer types, and it's # stripped in mcgen(). So please notice this when you check the return # value of c_type() outside mcgen(). @@ -889,7 +914,7 @@ def c_type(value, is_param=False): elif type(value) == list: return c_list_type(value[0]) + pointer_suffix elif is_enum(value): - return value + return c_name(value) elif value == None: return 'void' elif value in events: @@ -897,7 +922,7 @@ def c_type(value, is_param=False): else: # complex type name assert isinstance(value, str) and value != "" - return value + pointer_suffix + return c_name(value) + pointer_suffix def is_c_ptr(value): return c_type(value).endswith(pointer_suffix) From fce384b8e5193e02421f6b2c2880f3684abcbdc0 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:50:56 -0600 Subject: [PATCH 12/26] qapi: Support downstream enums Enhance the testsuite to cover a downstream enum type and enum string. Update the generator to mangle the enum name in the appropriate places. Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi-types.py | 15 ++++++++------- scripts/qapi-visit.py | 8 ++++---- tests/qapi-schema/qapi-schema-test.json | 3 +++ tests/qapi-schema/qapi-schema-test.out | 4 +++- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 9eb08a6266..1593fc6561 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -58,7 +58,7 @@ typedef struct %(name)sList struct %(name)sList *next; } %(name)sList; ''', - name=name) + name=c_name(name)) def generate_struct_fields(members): ret = '' @@ -115,7 +115,7 @@ def generate_enum_lookup(name, values): ret = mcgen(''' const char *%(name)s_lookup[] = { ''', - name=name) + name=c_name(name)) i = 0 for value in values: index = c_enum_const(name, value) @@ -134,6 +134,7 @@ const char *%(name)s_lookup[] = { return ret def generate_enum(name, values): + name = c_name(name) lookup_decl = mcgen(''' extern const char *%(name)s_lookup[]; ''', @@ -247,15 +248,15 @@ extern const int %(name)s_qtypes[]; def generate_type_cleanup_decl(name): ret = mcgen(''' -void qapi_free_%(type)s(%(c_type)s obj); +void qapi_free_%(name)s(%(c_type)s obj); ''', - c_type=c_type(name),type=name) + c_type=c_type(name), name=c_name(name)) return ret def generate_type_cleanup(name): ret = mcgen(''' -void qapi_free_%(type)s(%(c_type)s obj) +void qapi_free_%(name)s(%(c_type)s obj) { QapiDeallocVisitor *md; Visitor *v; @@ -266,11 +267,11 @@ void qapi_free_%(type)s(%(c_type)s obj) md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); - visit_type_%(type)s(v, &obj, NULL, NULL); + visit_type_%(name)s(v, &obj, NULL, NULL); qapi_dealloc_visitor_cleanup(md); } ''', - c_type=c_type(name),type=name) + c_type=c_type(name), name=c_name(name)) return ret diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 0368e62d23..7697ec65cc 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -173,7 +173,7 @@ out: error_propagate(errp, err); } ''', - name=name) + name=type_name(name)) def generate_visit_enum(name, members): return mcgen(''' @@ -183,7 +183,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **er visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp); } ''', - name=name) + name=c_name(name)) def generate_visit_alternate(name, members): ret = mcgen(''' @@ -364,7 +364,7 @@ def generate_enum_declaration(name, members): ret = mcgen(''' void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp); ''', - name=name) + name=c_name(name)) return ret @@ -373,7 +373,7 @@ def generate_decl_enum(name, members): void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp); ''', - name=name) + name=c_name(name)) try: opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 8193dc13a9..5f9af66764 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -107,3 +107,6 @@ 'data': { '*a': 'int', '*b': 'UserDefOne', 'c': 'str' } } { 'event': 'EVENT_D', 'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } } + +# test that we correctly compile downstream extensions +{ 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 93c49635eb..40f0f20ed6 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -22,8 +22,10 @@ OrderedDict([('event', 'EVENT_A')]), OrderedDict([('event', 'EVENT_B'), ('data', OrderedDict())]), OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]), - OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))])] + OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))]), + OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, + {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']}, {'enum_name': 'UserDefAlternateKind', 'enum_values': None}, {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}] [OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), From 83a02706bb1fd31c93eab755de543dfe228682d4 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:50:57 -0600 Subject: [PATCH 13/26] qapi: Support downstream structs Enhance the testsuite to cover downstream structs, including struct members and base structs. Update the generator to mangle the struct names in the appropriate places. Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi-types.py | 4 ++-- scripts/qapi-visit.py | 11 ++++++----- tests/qapi-schema/qapi-schema-test.json | 4 ++++ tests/qapi-schema/qapi-schema-test.out | 8 ++++++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 1593fc6561..51181512bf 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -45,7 +45,7 @@ typedef struct %(name)sList struct %(name)sList *next; } %(name)sList; ''', - name=name) + name=c_name(name)) def generate_fwd_enum_struct(name, members): return mcgen(''' @@ -87,7 +87,7 @@ def generate_struct(expr): struct %(name)s { ''', - name=structname) + name=c_name(structname)) if base: ret += generate_struct_fields({'base': base}) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 7697ec65cc..b50072425e 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -56,7 +56,7 @@ static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp) { Error *err = NULL; ''', - name=name) + name=c_name(name)) push_indent() if base: @@ -111,16 +111,16 @@ def generate_visit_struct_body(name, members): ret = mcgen(''' Error *err = NULL; - visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); + visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err); if (!err) { if (*obj) { - visit_type_%(name)s_fields(m, obj, errp); + visit_type_%(c_name)s_fields(m, obj, errp); } visit_end_struct(m, &err); } error_propagate(errp, err); ''', - name=name) + name=name, c_name=c_name(name)) return ret @@ -137,7 +137,7 @@ def generate_visit_struct(expr): void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp) { ''', - name=name) + name=c_name(name)) ret += generate_visit_struct_body(name, members) @@ -347,6 +347,7 @@ out: def generate_declaration(name, members, builtin_type=False): ret = "" if not builtin_type: + name = c_name(name) ret += mcgen(''' void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp); diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 5f9af66764..ca9b34ce38 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -110,3 +110,7 @@ # test that we correctly compile downstream extensions { 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] } +{ 'struct': '__org.qemu_x-Base', + 'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } } +{ 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base', + 'data': { '__org.qemu_x-member2': 'str' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 40f0f20ed6..6ab4f00185 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -23,7 +23,9 @@ OrderedDict([('event', 'EVENT_B'), ('data', OrderedDict())]), OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]), OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))]), - OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])])] + OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])]), + OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), + OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']}, {'enum_name': 'UserDefAlternateKind', 'enum_values': None}, @@ -39,4 +41,6 @@ OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]), OrderedDict([('struct', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), - OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))])] + OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]), + OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), + OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))])] From bb33729043ceda56b4068db13bdc17786ebd0ed0 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:50:58 -0600 Subject: [PATCH 14/26] qapi: Support downstream simple unions Enhance the testsuite to cover downstream simple unions, including when a union branch is a downstream name. Update the generator to mangle the union names in the appropriate places. Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi-types.py | 2 +- scripts/qapi-visit.py | 8 ++++---- tests/qapi-schema/qapi-schema-test.json | 1 + tests/qapi-schema/qapi-schema-test.out | 6 ++++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 51181512bf..5b0bc5d353 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -193,7 +193,7 @@ const int %(name)s_qtypes[QTYPE_MAX] = { def generate_union(expr, meta): - name = expr[meta] + name = c_name(expr[meta]) typeinfo = expr['data'] base = expr.get('base') diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index b50072425e..d1ec70b964 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -255,9 +255,9 @@ def generate_visit_union(expr): disc_type = enum_define['enum_name'] else: # There will always be a discriminator in the C switch code, by default - # it is an enum type generated silently as "'%sKind' % (name)" - ret = generate_visit_enum('%sKind' % name, members.keys()) - disc_type = '%sKind' % (name) + # it is an enum type generated silently + ret = generate_visit_enum(name + 'Kind', members.keys()) + disc_type = c_name(name) + 'Kind' if base: assert discriminator @@ -281,7 +281,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e } if (*obj) { ''', - name=name) + name=c_name(name)) if base: ret += mcgen(''' diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index ca9b34ce38..6416d85757 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -114,3 +114,4 @@ 'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } } { 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base', 'data': { '__org.qemu_x-member2': 'str' } } +{ 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 6ab4f00185..f9ebe08471 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -25,11 +25,13 @@ OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))]), OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])]), OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), - OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))])] + OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]), + OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']}, {'enum_name': 'UserDefAlternateKind', 'enum_values': None}, - {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}] + {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}, + {'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None}] [OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), From 857af5f06c3fb097d1bb6bc8a23b9992aac99e75 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:50:59 -0600 Subject: [PATCH 15/26] qapi: Support downstream flat unions Enhance the testsuite to cover downstream flat unions, including the base type, discriminator name and type, and branch name and type. Update the generator to mangle the union names in the appropriate places. Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi-types.py | 2 +- scripts/qapi-visit.py | 4 ++-- tests/qapi-schema/qapi-schema-test.json | 5 +++++ tests/qapi-schema/qapi-schema-test.out | 7 +++++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 5b0bc5d353..13e4b530f9 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -213,7 +213,7 @@ struct %(name)s void *data; ''', name=name, - discriminator_type_name=discriminator_type_name) + discriminator_type_name=c_name(discriminator_type_name)) for key in typeinfo: ret += mcgen(''' diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index d1ec70b964..c15305ffac 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -252,7 +252,7 @@ def generate_visit_union(expr): if enum_define: # Use the enum type as discriminator ret = "" - disc_type = enum_define['enum_name'] + disc_type = c_name(enum_define['enum_name']) else: # There will always be a discriminator in the C switch code, by default # it is an enum type generated silently @@ -290,7 +290,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e goto out_obj; } ''', - name=name) + name=c_name(name)) if not discriminator: disc_key = "type" diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 6416d85757..ac236e343e 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -115,3 +115,8 @@ { 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base', 'data': { '__org.qemu_x-member2': 'str' } } { 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } } +{ 'struct': '__org.qemu_x-Struct2', + 'data': { 'array': ['__org.qemu_x-Union1'] } } +{ 'union': '__org.qemu_x-Union2', 'base': '__org.qemu_x-Base', + 'discriminator': '__org.qemu_x-member1', + 'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index f9ebe08471..3fc24e8c76 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -26,7 +26,9 @@ OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])]), OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]), - OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))])] + OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))]), + OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))]), + OrderedDict([('union', '__org.qemu_x-Union2'), ('base', '__org.qemu_x-Base'), ('discriminator', '__org.qemu_x-member1'), ('data', OrderedDict([('__org.qemu_x-value', '__org.qemu_x-Struct2')]))])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']}, {'enum_name': 'UserDefAlternateKind', 'enum_values': None}, @@ -45,4 +47,5 @@ OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]), OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), - OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))])] + OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]), + OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))])] From d1f07c86c05706facf950b0b0dba370f71fd5ef6 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:51:00 -0600 Subject: [PATCH 16/26] qapi: Support downstream alternates Enhance the testsuite to cover downstream alternates, including whether the branch name or type is downstream. Update the generator to mangle alternate names in the appropriate places. Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi-types.py | 7 ++++--- scripts/qapi-visit.py | 6 +++--- tests/qapi-schema/qapi-schema-test.json | 2 ++ tests/qapi-schema/qapi-schema-test.out | 6 ++++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 13e4b530f9..56651451c9 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -174,16 +174,17 @@ def generate_alternate_qtypes(expr): ret = mcgen(''' const int %(name)s_qtypes[QTYPE_MAX] = { ''', - name=name) + name=c_name(name)) for key in members: qtype = find_alternate_member_qtype(members[key]) assert qtype, "Invalid alternate member" ret += mcgen(''' - [ %(qtype)s ] = %(enum_const)s, + [%(qtype)s] = %(enum_const)s, ''', - qtype = qtype, enum_const = c_enum_const(name + 'Kind', key)) + qtype = qtype, + enum_const = c_enum_const(name + 'Kind', key)) ret += mcgen(''' }; diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index c15305ffac..e511be357d 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -202,11 +202,11 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e } switch ((*obj)->kind) { ''', - name=name) + name=c_name(name)) # For alternate, always use the default enum type automatically generated - # as "'%sKind' % (name)" - disc_type = '%sKind' % (name) + # as name + 'Kind' + disc_type = c_name(name) + 'Kind' for key in members: assert (members[key] in builtin_types.keys() diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index ac236e343e..d586b56954 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -120,3 +120,5 @@ { 'union': '__org.qemu_x-Union2', 'base': '__org.qemu_x-Base', 'discriminator': '__org.qemu_x-member1', 'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } } +{ 'alternate': '__org.qemu_x-Alt', + 'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 3fc24e8c76..2161a90fce 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -28,12 +28,14 @@ OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]), OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))]), OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))]), - OrderedDict([('union', '__org.qemu_x-Union2'), ('base', '__org.qemu_x-Base'), ('discriminator', '__org.qemu_x-member1'), ('data', OrderedDict([('__org.qemu_x-value', '__org.qemu_x-Struct2')]))])] + OrderedDict([('union', '__org.qemu_x-Union2'), ('base', '__org.qemu_x-Base'), ('discriminator', '__org.qemu_x-member1'), ('data', OrderedDict([('__org.qemu_x-value', '__org.qemu_x-Struct2')]))]), + OrderedDict([('alternate', '__org.qemu_x-Alt'), ('data', OrderedDict([('__org.qemu_x-branch', 'str'), ('b', '__org.qemu_x-Base')]))])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']}, {'enum_name': 'UserDefAlternateKind', 'enum_values': None}, {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}, - {'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None}] + {'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None}, + {'enum_name': '__org.qemu_x-AltKind', 'enum_values': None}] [OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), From e3c4c3d796c1147d32f66fa1413d5d7c49d5aa37 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 14 May 2015 06:51:01 -0600 Subject: [PATCH 17/26] qapi: Support downstream events and commands Enhance the testsuite to cover downstream events and commands. Events worked without more tweaks, but commands needed a few final updates in the generator to mangle names in the appropriate places. In making those tweaks, it was easier to drop type_visitor() and inline its actions instead. Signed-off-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qapi-commands.py | 16 +++++----------- tests/qapi-schema/qapi-schema-test.json | 5 +++++ tests/qapi-schema/qapi-schema-test.out | 4 +++- tests/test-qmp-commands.c | 15 +++++++++++++++ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 8c125cac1f..0a1d636b18 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -20,12 +20,6 @@ import os import getopt import errno -def type_visitor(name): - if type(name) == list: - return 'visit_type_%sList' % name[0] - else: - return 'visit_type_%s' % name - def generate_command_decl(name, args, ret_type): arglist="" for argname, argtype, optional in parse_args(args): @@ -153,10 +147,10 @@ if (has_%(c_name)s) { c_name=c_name(argname)) push_indent() ret += mcgen(''' -%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); +visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); ''', c_name=c_name(argname), name=argname, argtype=argtype, - visitor=type_visitor(argtype), errp=errparg) + visitor=type_name(argtype), errp=errparg) ret += gen_err_check(errarg) if optional: pop_indent() @@ -184,7 +178,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o Visitor *v; v = qmp_output_get_visitor(mo); - %(visitor)s(v, &ret_in, "unused", &local_err); + visit_type_%(visitor)s(v, &ret_in, "unused", &local_err); if (local_err) { goto out; } @@ -195,12 +189,12 @@ out: qmp_output_visitor_cleanup(mo); md = qapi_dealloc_visitor_new(); v = qapi_dealloc_get_visitor(md); - %(visitor)s(v, &ret_in, "unused", NULL); + visit_type_%(visitor)s(v, &ret_in, "unused", NULL); qapi_dealloc_visitor_cleanup(md); } ''', c_ret_type=c_type(ret_type), c_name=c_name(name), - visitor=type_visitor(ret_type)) + visitor=type_name(ret_type)) return ret diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index d586b56954..c7eaa865da 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -122,3 +122,8 @@ 'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } } { 'alternate': '__org.qemu_x-Alt', 'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } } +{ 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' } +{ 'command': '__org.qemu_x-command', + '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' } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 2161a90fce..cf0ccc4025 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -29,7 +29,9 @@ OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))]), OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))]), OrderedDict([('union', '__org.qemu_x-Union2'), ('base', '__org.qemu_x-Base'), ('discriminator', '__org.qemu_x-member1'), ('data', OrderedDict([('__org.qemu_x-value', '__org.qemu_x-Struct2')]))]), - OrderedDict([('alternate', '__org.qemu_x-Alt'), ('data', OrderedDict([('__org.qemu_x-branch', 'str'), ('b', '__org.qemu_x-Base')]))])] + OrderedDict([('alternate', '__org.qemu_x-Alt'), ('data', OrderedDict([('__org.qemu_x-branch', 'str'), ('b', '__org.qemu_x-Base')]))]), + OrderedDict([('event', '__ORG.QEMU_X-EVENT'), ('data', '__org.qemu_x-Struct')]), + OrderedDict([('command', '__org.qemu_x-command'), ('data', OrderedDict([('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')])] [{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']}, {'enum_name': 'UserDefAlternateKind', 'enum_values': None}, diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index ad2e4030b2..9918f23062 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -51,6 +51,21 @@ int64_t qmp_user_def_cmd3(int64_t a, bool has_b, int64_t b, Error **errp) return a + (has_b ? b : 0); } +__org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, + __org_qemu_x_StructList *b, + __org_qemu_x_Union2 *c, + __org_qemu_x_Alt *d, + Error **errp) +{ + __org_qemu_x_Union1 *ret = g_new0(__org_qemu_x_Union1, 1); + + ret->kind = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH; + ret->__org_qemu_x_branch = strdup("blah1"); + + return ret; +} + + /* test commands with no input and no return value */ static void test_dispatch_cmd(void) { From df3e21a0e0edd30ea2e7c9b09b05feaaa297c718 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 13:38:48 +0200 Subject: [PATCH 18/26] tests: Add missing dependencies on $(qapi-py) Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- tests/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 666aee2ac3..6d2f2e5b9a 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -301,22 +301,22 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ libqemuutil.a libqemustub.a tests/test-qapi-types.c tests/test-qapi-types.h :\ -$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ $(gen-out-type) -o tests -p "test-" -i $<, \ " GEN $@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ -$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ $(gen-out-type) -o tests -p "test-" -i $<, \ " GEN $@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ -$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ $(gen-out-type) -o tests -p "test-" -i $<, \ " GEN $@") tests/test-qapi-event.c tests/test-qapi-event.h :\ -$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ $(gen-out-type) -o tests -p "test-" -i $<, \ " GEN $@") From c70cef5bd48c7be603f75a7b5346db032a31b470 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 11:40:21 +0200 Subject: [PATCH 19/26] qapi: qapi-event.py option -b does nothing, drop it Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- Makefile | 2 +- scripts/qapi-event.py | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index f032158645..bfa5dab4cd 100644 --- a/Makefile +++ b/Makefile @@ -273,7 +273,7 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) qapi-event.c qapi-event.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ - $(gen-out-type) -o "." -b -i $<, \ + $(gen-out-type) -o "." -i $<, \ " GEN $@") qmp-commands.h qmp-marshal.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index a7e0033cc1..3e1f4cf0fd 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -220,8 +220,8 @@ const char *%(event_enum_name)s_lookup[] = { # Start the real job try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", - ["source", "header", "builtins", "prefix=", + opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:i:o:", + ["source", "header", "prefix=", "input-file=", "output-dir="]) except getopt.GetoptError, err: print str(err) @@ -235,7 +235,6 @@ h_file = 'qapi-event.h' do_c = False do_h = False -do_builtins = False for o, a in opts: if o in ("-p", "--prefix"): @@ -248,8 +247,6 @@ for o, a in opts: do_c = True elif o in ("-h", "--header"): do_h = True - elif o in ("-b", "--builtins"): - do_builtins = True if not do_c and not do_h: do_c = True From 72aaa73a4acef06bfaed750064c40a597f0cf745 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 11:41:22 +0200 Subject: [PATCH 20/26] qapi: qapi-commands.py option --type is unused, drop it Anything but --type sync (which is the default) suppresses output entirely, which makes no sense. Dates back to the initial commit c17d990. Commit message says "Currently only generators for synchronous qapi/qmp functions are supported", so maybe output other than "synchronous qapi/qmp" was planned at the time, to be selected with --type. Should other kinds of output ever materialize, we can put the option back. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- scripts/qapi-commands.py | 68 +++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 0a1d636b18..c94a19b91d 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -381,14 +381,13 @@ try: opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:i:o:m", ["source", "header", "prefix=", "input-file=", "output-dir=", - "type=", "middle"]) + "middle"]) except getopt.GetoptError, err: print str(err) sys.exit(1) output_dir = "" prefix = "" -dispatch_type = "sync" c_file = 'qmp-marshal.c' h_file = 'qmp-commands.h' middle_mode = False @@ -403,8 +402,6 @@ for o, a in opts: input_file = a elif o in ("-o", "--output-dir"): output_dir = a + "/" - elif o in ("-t", "--type"): - dispatch_type = a elif o in ("-m", "--middle"): middle_mode = True elif o in ("-c", "--source"): @@ -436,40 +433,39 @@ exprs = parse_schema(input_file) commands = filter(lambda expr: expr.has_key('command'), exprs) commands = filter(lambda expr: not expr.has_key('gen'), commands) -if dispatch_type == "sync": - fdecl = maybe_open(do_h, h_file, 'w') - fdef = maybe_open(do_c, c_file, 'w') - ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix) +fdecl = maybe_open(do_h, h_file, 'w') +fdef = maybe_open(do_c, c_file, 'w') +ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix) +fdecl.write(ret) +ret = gen_command_def_prologue(prefix=prefix) +fdef.write(ret) + +for cmd in commands: + arglist = [] + ret_type = None + if cmd.has_key('data'): + arglist = cmd['data'] + if cmd.has_key('returns'): + ret_type = cmd['returns'] + ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" fdecl.write(ret) - ret = gen_command_def_prologue(prefix=prefix) + if ret_type: + ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n" + fdef.write(ret) + + if middle_mode: + fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode)) + + ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" fdef.write(ret) - for cmd in commands: - arglist = [] - ret_type = None - if cmd.has_key('data'): - arglist = cmd['data'] - if cmd.has_key('returns'): - ret_type = cmd['returns'] - ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n" - fdecl.write(ret) - if ret_type: - ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n" - fdef.write(ret) +fdecl.write("\n#endif\n"); - if middle_mode: - fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode)) +if not middle_mode: + ret = gen_registry(commands) + fdef.write(ret) - ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" - fdef.write(ret) - - fdecl.write("\n#endif\n"); - - if not middle_mode: - ret = gen_registry(commands) - fdef.write(ret) - - fdef.flush() - fdef.close() - fdecl.flush() - fdecl.close() +fdef.flush() +fdef.close() +fdecl.flush() +fdecl.close() From 2114f5a98d0d80774306279e1694de074ca86aa0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 13:12:21 +0200 Subject: [PATCH 21/26] qapi: Factor parse_command_line() out of the generators Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- scripts/qapi-commands.py | 34 +++------------------------------- scripts/qapi-event.py | 32 +------------------------------- scripts/qapi-types.py | 38 +++++--------------------------------- scripts/qapi-visit.py | 37 +++++-------------------------------- scripts/qapi.py | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 127 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index c94a19b91d..2889877680 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -15,9 +15,7 @@ from ordereddict import OrderedDict from qapi import * import re -import sys import os -import getopt import errno def generate_command_decl(name, args, ret_type): @@ -376,42 +374,16 @@ def gen_command_def_prologue(prefix="", proxy=False): ret += '#include "%sqmp-commands.h"' % prefix return ret + "\n\n" - -try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:i:o:m", - ["source", "header", "prefix=", - "input-file=", "output-dir=", - "middle"]) -except getopt.GetoptError, err: - print str(err) - sys.exit(1) - -output_dir = "" -prefix = "" c_file = 'qmp-marshal.c' h_file = 'qmp-commands.h' middle_mode = False -do_c = False -do_h = False +(input_file, output_dir, do_c, do_h, prefix, opts) = \ + parse_command_line("m", ["middle"]) for o, a in opts: - if o in ("-p", "--prefix"): - prefix = a - elif o in ("-i", "--input-file"): - input_file = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-m", "--middle"): + if o in ("-m", "--middle"): middle_mode = True - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - -if not do_c and not do_h: - do_c = True - do_h = True c_file = output_dir + prefix + c_file h_file = output_dir + prefix + h_file diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index 3e1f4cf0fd..bc5ca4ad11 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -11,9 +11,7 @@ from ordereddict import OrderedDict from qapi import * -import sys import os -import getopt import errno def _generate_event_api_name(event_name, params): @@ -219,38 +217,10 @@ const char *%(event_enum_name)s_lookup[] = { # Start the real job -try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:i:o:", - ["source", "header", "prefix=", - "input-file=", "output-dir="]) -except getopt.GetoptError, err: - print str(err) - sys.exit(1) - -input_file = "" -output_dir = "" -prefix = "" c_file = 'qapi-event.c' h_file = 'qapi-event.h' -do_c = False -do_h = False - -for o, a in opts: - if o in ("-p", "--prefix"): - prefix = a - elif o in ("-i", "--input-file"): - input_file = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - -if not do_c and not do_h: - do_c = True - do_h = True +(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line() c_file = output_dir + prefix + c_file h_file = output_dir + prefix + h_file diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 56651451c9..62044c11cb 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -11,9 +11,7 @@ from ordereddict import OrderedDict from qapi import * -import sys import os -import getopt import errno def generate_fwd_struct(name, members, builtin_type=False): @@ -275,42 +273,16 @@ void qapi_free_%(name)s(%(c_type)s obj) c_type=c_type(name), name=c_name(name)) return ret - -try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", - ["source", "header", "builtins", - "prefix=", "input-file=", "output-dir="]) -except getopt.GetoptError, err: - print str(err) - sys.exit(1) - -output_dir = "" -input_file = "" -prefix = "" c_file = 'qapi-types.c' h_file = 'qapi-types.h' - -do_c = False -do_h = False do_builtins = False -for o, a in opts: - if o in ("-p", "--prefix"): - prefix = a - elif o in ("-i", "--input-file"): - input_file = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - elif o in ("-b", "--builtins"): - do_builtins = True +(input_file, output_dir, do_c, do_h, prefix, opts) = \ + parse_command_line("b", ["builtins"]) -if not do_c and not do_h: - do_c = True - do_h = True +for o, a in opts: + if o in ("-b", "--builtins"): + do_builtins = True c_file = output_dir + prefix + c_file h_file = output_dir + prefix + h_file diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index e511be357d..75f0cf3db5 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -15,9 +15,7 @@ from ordereddict import OrderedDict from qapi import * import re -import sys import os -import getopt import errno implicit_structs = [] @@ -376,41 +374,16 @@ void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **er ''', name=c_name(name)) -try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:", - ["source", "header", "builtins", "prefix=", - "input-file=", "output-dir="]) -except getopt.GetoptError, err: - print str(err) - sys.exit(1) - -input_file = "" -output_dir = "" -prefix = "" c_file = 'qapi-visit.c' h_file = 'qapi-visit.h' - -do_c = False -do_h = False do_builtins = False -for o, a in opts: - if o in ("-p", "--prefix"): - prefix = a - elif o in ("-i", "--input-file"): - input_file = a - elif o in ("-o", "--output-dir"): - output_dir = a + "/" - elif o in ("-c", "--source"): - do_c = True - elif o in ("-h", "--header"): - do_h = True - elif o in ("-b", "--builtins"): - do_builtins = True +(input_file, output_dir, do_c, do_h, prefix, opts) = \ + parse_command_line("b", ["builtins"]) -if not do_c and not do_h: - do_c = True - do_h = True +for o, a in opts: + if o in ("-b", "--builtins"): + do_builtins = True c_file = output_dir + prefix + c_file h_file = output_dir + prefix + h_file diff --git a/scripts/qapi.py b/scripts/qapi.py index 273afedc3d..b97dd0b14a 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -13,6 +13,7 @@ import re from ordereddict import OrderedDict +import getopt import os import sys import string @@ -978,3 +979,42 @@ def guardend(name): ''', name=guardname(name)) + +def parse_command_line(extra_options = "", extra_long_options = []): + + try: + opts, args = getopt.gnu_getopt(sys.argv[1:], + "chp:i:o:" + extra_options, + ["source", "header", "prefix=", + "input-file=", "output-dir="] + + extra_long_options) + except getopt.GetoptError, err: + print str(err) + sys.exit(1) + + output_dir = "" + prefix = "" + do_c = False + do_h = False + extra_opts = [] + + for oa in opts: + o, a = oa + if o in ("-p", "--prefix"): + prefix = a + elif o in ("-i", "--input-file"): + input_file = a + elif o in ("-o", "--output-dir"): + output_dir = a + "/" + elif o in ("-c", "--source"): + do_c = True + elif o in ("-h", "--header"): + do_h = True + else: + extra_opts.append(oa) + + if not do_c and not do_h: + do_c = True + do_h = True + + return (input_file, output_dir, do_c, do_h, prefix, extra_opts) From b45409683e829770000a4560ed21e704f87df74c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 13:17:34 +0200 Subject: [PATCH 22/26] qapi: Fix generators to report command line errors decently Report to stderr, prefix with the program name. Also reject extra arguments. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- scripts/qapi.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index b97dd0b14a..df6e5aa381 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -989,7 +989,7 @@ def parse_command_line(extra_options = "", extra_long_options = []): "input-file=", "output-dir="] + extra_long_options) except getopt.GetoptError, err: - print str(err) + print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err)) sys.exit(1) output_dir = "" @@ -1017,4 +1017,8 @@ def parse_command_line(extra_options = "", extra_long_options = []): do_c = True do_h = True + if len(args) != 0: + print >>sys.stderr, "%s: too many arguments" % sys.argv[0] + sys.exit(1) + return (input_file, output_dir, do_c, do_h, prefix, extra_opts) From 16d80f61814745bd3f5bb9f47ae3b00edf9e1e45 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 13:32:16 +0200 Subject: [PATCH 23/26] qapi: Turn generators' mandatory option -i into an argument Mandatory option is silly, and the error handling is missing: the programs crash when -i isn't supplied. Make it an argument, and check it properly. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- Makefile | 14 +++++++------- docs/qapi-code-gen.txt | 10 +++++----- scripts/qapi.py | 12 +++++------- tests/Makefile | 8 ++++---- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index bfa5dab4cd..d94580404c 100644 --- a/Makefile +++ b/Makefile @@ -243,17 +243,17 @@ qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ - $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ " GEN $@") qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ - $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ " GEN $@") qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ - $(gen-out-type) -o qga/qapi-generated -p "qga-" -i $<, \ + $(gen-out-type) -o qga/qapi-generated -p "qga-" $<, \ " GEN $@") qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ @@ -263,22 +263,22 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ qapi-types.c qapi-types.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ - $(gen-out-type) -o "." -b -i $<, \ + $(gen-out-type) -o "." -b $<, \ " GEN $@") qapi-visit.c qapi-visit.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ - $(gen-out-type) -o "." -b -i $<, \ + $(gen-out-type) -o "." -b $<, \ " GEN $@") qapi-event.c qapi-event.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ - $(gen-out-type) -o "." -i $<, \ + $(gen-out-type) -o "." $<, \ " GEN $@") qmp-commands.h qmp-marshal.c :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ - $(gen-out-type) -o "." -m -i $<, \ + $(gen-out-type) -o "." -m $<, \ " GEN $@") QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 269a1f3d27..3f0522ea0f 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -536,7 +536,7 @@ created code. Example: $ python scripts/qapi-types.py --output-dir="qapi-generated" \ - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qapi-types.c [Uninteresting stuff omitted...] @@ -623,7 +623,7 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor Example: $ python scripts/qapi-visit.py --output-dir="qapi-generated" - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qapi-visit.c [Uninteresting stuff omitted...] @@ -681,7 +681,7 @@ Example: error_propagate(errp, err); } $ python scripts/qapi-commands.py --output-dir="qapi-generated" \ - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qapi-visit.h [Uninteresting stuff omitted...] @@ -715,7 +715,7 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands Example: $ python scripts/qapi-commands.py --output-dir="qapi-generated" - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qmp-marshal.c [Uninteresting stuff omitted...] @@ -806,7 +806,7 @@ $(prefix)qapi-event.c - Implementation of functions to send an event Example: $ python scripts/qapi-event.py --output-dir="qapi-generated" - --prefix="example-" --input-file=example-schema.json + --prefix="example-" example-schema.json $ cat qapi-generated/example-qapi-event.c [Uninteresting stuff omitted...] diff --git a/scripts/qapi.py b/scripts/qapi.py index df6e5aa381..186ec3b39f 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -984,10 +984,9 @@ def parse_command_line(extra_options = "", extra_long_options = []): try: opts, args = getopt.gnu_getopt(sys.argv[1:], - "chp:i:o:" + extra_options, + "chp:o:" + extra_options, ["source", "header", "prefix=", - "input-file=", "output-dir="] - + extra_long_options) + "output-dir="] + extra_long_options) except getopt.GetoptError, err: print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err)) sys.exit(1) @@ -1002,8 +1001,6 @@ def parse_command_line(extra_options = "", extra_long_options = []): o, a = oa if o in ("-p", "--prefix"): prefix = a - elif o in ("-i", "--input-file"): - input_file = a elif o in ("-o", "--output-dir"): output_dir = a + "/" elif o in ("-c", "--source"): @@ -1017,8 +1014,9 @@ def parse_command_line(extra_options = "", extra_long_options = []): do_c = True do_h = True - if len(args) != 0: - print >>sys.stderr, "%s: too many arguments" % sys.argv[0] + if len(args) != 1: + print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0] sys.exit(1) + input_file = args[0] return (input_file, output_dir, do_c, do_h, prefix, extra_opts) diff --git a/tests/Makefile b/tests/Makefile index 6d2f2e5b9a..729b9694cf 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -303,22 +303,22 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ - $(gen-out-type) -o tests -p "test-" -i $<, \ + $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \ - $(gen-out-type) -o tests -p "test-" -i $<, \ + $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \ - $(gen-out-type) -o tests -p "test-" -i $<, \ + $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") tests/test-qapi-event.c tests/test-qapi-event.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-event.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ - $(gen-out-type) -o tests -p "test-" -i $<, \ + $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a From 12f8e1b9ff57e99dafbb13f89cd5a99ad5c28527 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 14:46:39 +0200 Subject: [PATCH 24/26] qapi: Factor open_output(), close_output() out of generators Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- scripts/qapi-commands.py | 101 ++++++++++++++------------------------- scripts/qapi-event.py | 75 ++++++++--------------------- scripts/qapi-types.py | 67 +++++++------------------- scripts/qapi-visit.py | 101 ++++++++++++++------------------------- scripts/qapi.py | 50 +++++++++++++++++++ 5 files changed, 160 insertions(+), 234 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 2889877680..c3e420e6c9 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -15,8 +15,6 @@ from ordereddict import OrderedDict from qapi import * import re -import os -import errno def generate_command_decl(name, args, ret_type): arglist="" @@ -311,51 +309,18 @@ qapi_init(qmp_init_marshal); registry=registry.rstrip()) return ret -def gen_command_decl_prologue(header, guard, prefix=""): +def gen_command_decl_prologue(prefix=""): ret = mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - -/* - * schema-defined QAPI function prototypes - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - -#ifndef %(guard)s -#define %(guard)s - #include "%(prefix)sqapi-types.h" #include "qapi/qmp/qdict.h" #include "qapi/error.h" ''', - header=basename(header), guard=guardname(header), prefix=prefix) + prefix=prefix) return ret def gen_command_def_prologue(prefix="", proxy=False): ret = mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - -/* - * schema-defined QMP->QAPI command dispatch - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - #include "qemu-common.h" #include "qemu/module.h" #include "qapi/qmp/qerror.h" @@ -374,8 +339,6 @@ def gen_command_def_prologue(prefix="", proxy=False): ret += '#include "%sqmp-commands.h"' % prefix return ret + "\n\n" -c_file = 'qmp-marshal.c' -h_file = 'qmp-commands.h' middle_mode = False (input_file, output_dir, do_c, do_h, prefix, opts) = \ @@ -385,29 +348,44 @@ for o, a in opts: if o in ("-m", "--middle"): middle_mode = True -c_file = output_dir + prefix + c_file -h_file = output_dir + prefix + h_file - -def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - -try: - os.makedirs(output_dir) -except os.error, e: - if e.errno != errno.EEXIST: - raise - exprs = parse_schema(input_file) commands = filter(lambda expr: expr.has_key('command'), exprs) commands = filter(lambda expr: not expr.has_key('gen'), commands) -fdecl = maybe_open(do_h, h_file, 'w') -fdef = maybe_open(do_c, c_file, 'w') -ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix) +c_comment = ''' +/* + * schema-defined QMP->QAPI command dispatch + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ +''' +h_comment = ''' +/* + * schema-defined QAPI function prototypes + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ +''' + +(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, + 'qmp-marshal.c', 'qmp-commands.h', + c_comment, h_comment) + +ret = gen_command_decl_prologue(prefix=prefix) fdecl.write(ret) ret = gen_command_def_prologue(prefix=prefix) fdef.write(ret) @@ -431,13 +409,8 @@ for cmd in commands: ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n" fdef.write(ret) -fdecl.write("\n#endif\n"); - if not middle_mode: ret = gen_registry(commands) fdef.write(ret) -fdef.flush() -fdef.close() -fdecl.flush() -fdecl.close() +close_output(fdef, fdecl) diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index bc5ca4ad11..56bc602a6d 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -11,8 +11,6 @@ from ordereddict import OrderedDict from qapi import * -import os -import errno def _generate_event_api_name(event_name, params): api_name = "void qapi_event_send_%s(" % c_name(event_name).lower(); @@ -214,36 +212,9 @@ const char *%(event_enum_name)s_lookup[] = { ''') return ret - -# Start the real job - -c_file = 'qapi-event.c' -h_file = 'qapi-event.h' - (input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line() -c_file = output_dir + prefix + c_file -h_file = output_dir + prefix + h_file - -try: - os.makedirs(output_dir) -except os.error, e: - if e.errno != errno.EEXIST: - raise - -def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - -fdef = maybe_open(do_c, c_file, 'w') -fdecl = maybe_open(do_h, h_file, 'w') - -fdef.write(mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +c_comment = ''' /* * schema-defined QAPI event functions * @@ -256,19 +227,8 @@ fdef.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ - -#include "qemu-common.h" -#include "%(header)s" -#include "%(prefix)sqapi-visit.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/qmp-event.h" - -''', - prefix=prefix, header=basename(h_file))) - -fdecl.write(mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +''' +h_comment = ''' /* * schema-defined QAPI event functions * @@ -281,16 +241,29 @@ fdecl.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ +''' -#ifndef %(guard)s -#define %(guard)s +(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, + 'qapi-event.c', 'qapi-event.h', + c_comment, h_comment) +fdef.write(mcgen(''' +#include "qemu-common.h" +#include "%(prefix)sqapi-event.h" +#include "%(prefix)sqapi-visit.h" +#include "qapi/qmp-output-visitor.h" +#include "qapi/qmp-event.h" + +''', + prefix=prefix)) + +fdecl.write(mcgen(''' #include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "%(prefix)sqapi-types.h" ''', - prefix=prefix, guard=guardname(h_file))) + prefix=prefix)) exprs = parse_schema(input_file) @@ -323,12 +296,4 @@ fdecl.write(ret) ret = generate_event_enum_lookup(event_enum_name, event_enum_strings) fdef.write(ret) -fdecl.write(''' -#endif -''') - -fdecl.flush() -fdecl.close() - -fdef.flush() -fdef.close() +close_output(fdef, fdecl) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 62044c11cb..6bd0b13759 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -11,8 +11,6 @@ from ordereddict import OrderedDict from qapi import * -import os -import errno def generate_fwd_struct(name, members, builtin_type=False): if builtin_type: @@ -273,8 +271,6 @@ void qapi_free_%(name)s(%(c_type)s obj) c_type=c_type(name), name=c_name(name)) return ret -c_file = 'qapi-types.c' -h_file = 'qapi-types.h' do_builtins = False (input_file, output_dir, do_c, do_h, prefix, opts) = \ @@ -284,28 +280,7 @@ for o, a in opts: if o in ("-b", "--builtins"): do_builtins = True -c_file = output_dir + prefix + c_file -h_file = output_dir + prefix + h_file - -try: - os.makedirs(output_dir) -except os.error, e: - if e.errno != errno.EEXIST: - raise - -def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - -fdef = maybe_open(do_c, c_file, 'w') -fdecl = maybe_open(do_h, h_file, 'w') - -fdef.write(mcgen(''' -/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +c_comment = ''' /* * deallocation functions for schema-defined QAPI types * @@ -319,16 +294,8 @@ fdef.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ - -#include "qapi/dealloc-visitor.h" -#include "%(prefix)sqapi-types.h" -#include "%(prefix)sqapi-visit.h" - -''', prefix=prefix)) - -fdecl.write(mcgen(''' -/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ - +''' +h_comment = ''' /* * schema-defined QAPI types * @@ -341,15 +308,25 @@ fdecl.write(mcgen(''' * See the COPYING.LIB file in the top-level directory. * */ +''' -#ifndef %(guard)s -#define %(guard)s +(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, + 'qapi-types.c', 'qapi-types.h', + c_comment, h_comment) +fdef.write(mcgen(''' +#include "qapi/dealloc-visitor.h" +#include "%(prefix)sqapi-types.h" +#include "%(prefix)sqapi-visit.h" + +''', + prefix=prefix)) + +fdecl.write(mcgen(''' #include #include -''', - guard=guardname(h_file))) +''')) exprs = parse_schema(input_file) exprs = filter(lambda expr: not expr.has_key('gen'), exprs) @@ -427,12 +404,4 @@ for expr in exprs: continue fdecl.write(ret) -fdecl.write(''' -#endif -''') - -fdecl.flush() -fdecl.close() - -fdef.flush() -fdef.close() +close_output(fdef, fdecl) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 75f0cf3db5..5b99336488 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -15,8 +15,6 @@ from ordereddict import OrderedDict from qapi import * import re -import os -import errno implicit_structs = [] @@ -374,8 +372,6 @@ void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **er ''', name=c_name(name)) -c_file = 'qapi-visit.c' -h_file = 'qapi-visit.h' do_builtins = False (input_file, output_dir, do_c, do_h, prefix, opts) = \ @@ -385,70 +381,51 @@ for o, a in opts: if o in ("-b", "--builtins"): do_builtins = True -c_file = output_dir + prefix + c_file -h_file = output_dir + prefix + h_file +c_comment = ''' +/* + * schema-defined QAPI visitor functions + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ +''' +h_comment = ''' +/* + * schema-defined QAPI visitor functions + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ +''' -try: - os.makedirs(output_dir) -except os.error, e: - if e.errno != errno.EEXIST: - raise - -def maybe_open(really, name, opt): - if really: - return open(name, opt) - else: - import StringIO - return StringIO.StringIO() - -fdef = maybe_open(do_c, c_file, 'w') -fdecl = maybe_open(do_h, h_file, 'w') +(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix, + 'qapi-visit.c', 'qapi-visit.h', + c_comment, h_comment) fdef.write(mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - -/* - * schema-defined QAPI visitor functions - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - #include "qemu-common.h" -#include "%(header)s" +#include "%(prefix)sqapi-visit.h" ''', - header=basename(h_file))) + prefix = prefix)) fdecl.write(mcgen(''' -/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ - -/* - * schema-defined QAPI visitor functions - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - -#ifndef %(guard)s -#define %(guard)s - #include "qapi/visitor.h" #include "%(prefix)sqapi-types.h" ''', - prefix=prefix, guard=guardname(h_file))) + prefix=prefix)) exprs = parse_schema(input_file) @@ -504,12 +481,4 @@ for expr in exprs: ret += generate_enum_declaration(expr['enum'], expr['data']) fdecl.write(ret) -fdecl.write(''' -#endif -''') - -fdecl.flush() -fdecl.close() - -fdef.flush() -fdef.close() +close_output(fdef, fdecl) diff --git a/scripts/qapi.py b/scripts/qapi.py index 186ec3b39f..fbfe0508a0 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -13,6 +13,7 @@ import re from ordereddict import OrderedDict +import errno import getopt import os import sys @@ -1020,3 +1021,52 @@ def parse_command_line(extra_options = "", extra_long_options = []): input_file = args[0] return (input_file, output_dir, do_c, do_h, prefix, extra_opts) + +def open_output(output_dir, do_c, do_h, prefix, c_file, h_file, + c_comment, h_comment): + c_file = output_dir + prefix + c_file + h_file = output_dir + prefix + h_file + + try: + os.makedirs(output_dir) + except os.error, e: + if e.errno != errno.EEXIST: + raise + + def maybe_open(really, name, opt): + if really: + return open(name, opt) + else: + import StringIO + return StringIO.StringIO() + + fdef = maybe_open(do_c, c_file, 'w') + fdecl = maybe_open(do_h, h_file, 'w') + + fdef.write(mcgen(''' +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ +%(comment)s +''', + comment = c_comment)) + + fdecl.write(mcgen(''' +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ +%(comment)s +#ifndef %(guard)s +#define %(guard)s + +''', + comment = h_comment, guard = guardname(h_file))) + + return (fdef, fdecl) + +def close_output(fdef, fdecl): + fdecl.write(''' +#endif +''') + + fdecl.flush() + fdecl.close() + + fdef.flush() + fdef.close() From 09896d3f48078a93e3d2dbd8ef86436b85ebda7c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 14:49:29 +0200 Subject: [PATCH 25/26] qapi: Drop pointless flush() before close() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- scripts/qapi.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index fbfe0508a0..f96a7772e5 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -1064,9 +1064,5 @@ def close_output(fdef, fdecl): fdecl.write(''' #endif ''') - - fdecl.flush() fdecl.close() - - fdef.flush() fdef.close() From 4180978c9205c50acd2d6c385def9b3e81911696 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 2 Apr 2015 14:52:55 +0200 Subject: [PATCH 26/26] qapi: Inline gen_command_decl_prologue(), gen_command_def_prologue() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- scripts/qapi-commands.py | 58 +++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index c3e420e6c9..1c1d3aa029 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -309,36 +309,6 @@ qapi_init(qmp_init_marshal); registry=registry.rstrip()) return ret -def gen_command_decl_prologue(prefix=""): - ret = mcgen(''' -#include "%(prefix)sqapi-types.h" -#include "qapi/qmp/qdict.h" -#include "qapi/error.h" - -''', - prefix=prefix) - return ret - -def gen_command_def_prologue(prefix="", proxy=False): - ret = mcgen(''' -#include "qemu-common.h" -#include "qemu/module.h" -#include "qapi/qmp/qerror.h" -#include "qapi/qmp/types.h" -#include "qapi/qmp/dispatch.h" -#include "qapi/visitor.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi/dealloc-visitor.h" -#include "%(prefix)sqapi-types.h" -#include "%(prefix)sqapi-visit.h" - -''', - prefix=prefix) - if not proxy: - ret += '#include "%sqmp-commands.h"' % prefix - return ret + "\n\n" - middle_mode = False (input_file, output_dir, do_c, do_h, prefix, opts) = \ @@ -385,10 +355,30 @@ h_comment = ''' 'qmp-marshal.c', 'qmp-commands.h', c_comment, h_comment) -ret = gen_command_decl_prologue(prefix=prefix) -fdecl.write(ret) -ret = gen_command_def_prologue(prefix=prefix) -fdef.write(ret) +fdef.write(mcgen(''' +#include "qemu-common.h" +#include "qemu/module.h" +#include "qapi/qmp/qerror.h" +#include "qapi/qmp/types.h" +#include "qapi/qmp/dispatch.h" +#include "qapi/visitor.h" +#include "qapi/qmp-output-visitor.h" +#include "qapi/qmp-input-visitor.h" +#include "qapi/dealloc-visitor.h" +#include "%(prefix)sqapi-types.h" +#include "%(prefix)sqapi-visit.h" +#include "%(prefix)sqmp-commands.h" + +''', + prefix=prefix)) + +fdecl.write(mcgen(''' +#include "%(prefix)sqapi-types.h" +#include "qapi/qmp/qdict.h" +#include "qapi/error.h" + +''', + prefix=prefix)) for cmd in commands: arglist = []