mirror of https://gitee.com/openkylin/qemu.git
qapi-introspect: Hide type names
To eliminate the temptation for clients to look up types by name (which are not ABI), replace all type names by meaningless strings. Reduces output of query-schema by 13 out of 85KiB. As a debugging aid, provide option -u to suppress the hiding. Signed-off-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-Id: <1442401589-24189-27-git-send-email-armbru@redhat.com>
This commit is contained in:
parent
39a1815816
commit
1a9a507b2e
|
@ -530,13 +530,16 @@ additional variant members depending on the value of meta-type.
|
||||||
Each SchemaInfo object describes a wire ABI entity of a certain
|
Each SchemaInfo object describes a wire ABI entity of a certain
|
||||||
meta-type: a command, event or one of several kinds of type.
|
meta-type: a command, event or one of several kinds of type.
|
||||||
|
|
||||||
SchemaInfo for entities defined in the QAPI schema have the same name
|
SchemaInfo for commands and events have the same name as in the QAPI
|
||||||
as in the schema. This is the case for all commands and events, and
|
schema.
|
||||||
most types.
|
|
||||||
|
|
||||||
Command and event names are part of the wire ABI, but type names are
|
Command and event names are part of the wire ABI, but type names are
|
||||||
not. Therefore, looking up a type by its name in the QAPI schema is
|
not. Therefore, the SchemaInfo for types have auto-generated
|
||||||
wrong. Look up the command or event, then follow references by name.
|
meaningless names. For readability, the examples in this section use
|
||||||
|
meaningful type names instead.
|
||||||
|
|
||||||
|
To examine a type, start with a command or event using it, then follow
|
||||||
|
references by name.
|
||||||
|
|
||||||
QAPI schema definitions not reachable that way are omitted.
|
QAPI schema definitions not reachable that way are omitted.
|
||||||
|
|
||||||
|
@ -567,8 +570,7 @@ object type without members. The event may not have a data member on
|
||||||
the wire then.
|
the wire then.
|
||||||
|
|
||||||
Each command or event defined with dictionary-valued 'data' in the
|
Each command or event defined with dictionary-valued 'data' in the
|
||||||
QAPI schema implicitly defines an object type called ":obj-NAME-arg",
|
QAPI schema implicitly defines an object type.
|
||||||
where NAME is the command or event's name.
|
|
||||||
|
|
||||||
Example: the SchemaInfo for EVENT_C from section Events
|
Example: the SchemaInfo for EVENT_C from section Events
|
||||||
|
|
||||||
|
@ -623,12 +625,9 @@ Note that base types are "flattened": its members are included in the
|
||||||
|
|
||||||
A simple union implicitly defines an enumeration type for its implicit
|
A simple union implicitly defines an enumeration type for its implicit
|
||||||
discriminator (called "type" on the wire, see section Union types).
|
discriminator (called "type" on the wire, see section Union types).
|
||||||
Such a type's name is made by appending "Kind" to the simple union's
|
|
||||||
name.
|
|
||||||
|
|
||||||
A simple union implicitly defines an object type for each of its
|
A simple union implicitly defines an object type for each of its
|
||||||
variants. The type's name is ":obj-NAME-wrapper", where NAME is the
|
variants.
|
||||||
name of the name of the variant's type.
|
|
||||||
|
|
||||||
Example: the SchemaInfo for simple union BlockdevOptions from section
|
Example: the SchemaInfo for simple union BlockdevOptions from section
|
||||||
Union types
|
Union types
|
||||||
|
@ -659,8 +658,7 @@ Example: the SchemaInfo for BlockRef from section Alternate types
|
||||||
|
|
||||||
The SchemaInfo for an array type has meta-type "array", and variant
|
The SchemaInfo for an array type has meta-type "array", and variant
|
||||||
member "element-type", which names the array's element type. Array
|
member "element-type", which names the array's element type. Array
|
||||||
types are implicitly defined. An array type's name is made by
|
types are implicitly defined.
|
||||||
appending "List" to its element type's name.
|
|
||||||
|
|
||||||
Example: the SchemaInfo for ['str']
|
Example: the SchemaInfo for ['str']
|
||||||
|
|
||||||
|
@ -1067,13 +1065,13 @@ Example:
|
||||||
[Uninteresting stuff omitted...]
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
const char example_qmp_schema_json[] = "["
|
const char example_qmp_schema_json[] = "["
|
||||||
"{\"arg-type\": \":empty\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
|
"{\"arg-type\": \"0\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
|
||||||
|
"{\"arg-type\": \"1\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"2\"}, "
|
||||||
|
"{\"members\": [], \"meta-type\": \"object\", \"name\": \"0\"}, "
|
||||||
|
"{\"members\": [{\"name\": \"arg1\", \"type\": \"2\"}], \"meta-type\": \"object\", \"name\": \"1\"}, "
|
||||||
|
"{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, "
|
||||||
"{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, "
|
"{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, "
|
||||||
"{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}, "
|
"{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]";
|
||||||
"{\"members\": [], \"meta-type\": \"object\", \"name\": \":empty\"}, "
|
|
||||||
"{\"members\": [{\"name\": \"arg1\", \"type\": \"UserDefOne\"}], \"meta-type\": \"object\", \"name\": \":obj-my-command-arg\"}, "
|
|
||||||
"{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"UserDefOne\"}, "
|
|
||||||
"{\"arg-type\": \":obj-my-command-arg\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"UserDefOne\"}]";
|
|
||||||
$ cat qapi-generated/example-qmp-introspect.h
|
$ cat qapi-generated/example-qmp-introspect.h
|
||||||
[Uninteresting stuff omitted...]
|
[Uninteresting stuff omitted...]
|
||||||
|
|
||||||
|
|
|
@ -75,17 +75,13 @@
|
||||||
# @SchemaInfo
|
# @SchemaInfo
|
||||||
#
|
#
|
||||||
# @name: the entity's name, inherited from @base.
|
# @name: the entity's name, inherited from @base.
|
||||||
# Entities defined in the QAPI schema have the name defined in
|
# Commands and events have the name defined in the QAPI schema.
|
||||||
# the schema. Implicitly defined entities have generated
|
# Unlike command and event names, type names are not part of
|
||||||
# names. See docs/qapi-code-gen.txt section "Client JSON
|
# the wire ABI. Consequently, type names are meaningless
|
||||||
# Protocol introspection" for details.
|
# strings here.
|
||||||
#
|
#
|
||||||
# All references to other SchemaInfo are by name.
|
# All references to other SchemaInfo are by name.
|
||||||
#
|
#
|
||||||
# Command and event names are part of the wire ABI, but type names are
|
|
||||||
# not. Therefore, looking up a type by "well-known" name is wrong.
|
|
||||||
# Look up the command or event, then follow the references.
|
|
||||||
#
|
|
||||||
# @meta-type: the entity's meta type, inherited from @base.
|
# @meta-type: the entity's meta type, inherited from @base.
|
||||||
#
|
#
|
||||||
# Additional members depend on the value of @meta-type.
|
# Additional members depend on the value of @meta-type.
|
||||||
|
|
|
@ -40,32 +40,37 @@ def to_c_string(string):
|
||||||
|
|
||||||
|
|
||||||
class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
|
class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
|
||||||
def __init__(self):
|
def __init__(self, unmask):
|
||||||
|
self._unmask = unmask
|
||||||
self.defn = None
|
self.defn = None
|
||||||
self.decl = None
|
self.decl = None
|
||||||
self._schema = None
|
self._schema = None
|
||||||
self._jsons = None
|
self._jsons = None
|
||||||
self._used_types = None
|
self._used_types = None
|
||||||
|
self._name_map = None
|
||||||
|
|
||||||
def visit_begin(self, schema):
|
def visit_begin(self, schema):
|
||||||
self._schema = schema
|
self._schema = schema
|
||||||
self._jsons = []
|
self._jsons = []
|
||||||
self._used_types = []
|
self._used_types = []
|
||||||
|
self._name_map = {}
|
||||||
return QAPISchemaType # don't visit types for now
|
return QAPISchemaType # don't visit types for now
|
||||||
|
|
||||||
def visit_end(self):
|
def visit_end(self):
|
||||||
# visit the types that are actually used
|
# visit the types that are actually used
|
||||||
|
jsons = self._jsons
|
||||||
|
self._jsons = []
|
||||||
for typ in self._used_types:
|
for typ in self._used_types:
|
||||||
typ.visit(self)
|
typ.visit(self)
|
||||||
self._jsons.sort()
|
|
||||||
# generate C
|
# generate C
|
||||||
# TODO can generate awfully long lines
|
# TODO can generate awfully long lines
|
||||||
|
jsons.extend(self._jsons)
|
||||||
name = prefix + 'qmp_schema_json'
|
name = prefix + 'qmp_schema_json'
|
||||||
self.decl = mcgen('''
|
self.decl = mcgen('''
|
||||||
extern const char %(c_name)s[];
|
extern const char %(c_name)s[];
|
||||||
''',
|
''',
|
||||||
c_name=c_name(name))
|
c_name=c_name(name))
|
||||||
lines = to_json(self._jsons).split('\n')
|
lines = to_json(jsons).split('\n')
|
||||||
c_string = '\n '.join([to_c_string(line) for line in lines])
|
c_string = '\n '.join([to_c_string(line) for line in lines])
|
||||||
self.defn = mcgen('''
|
self.defn = mcgen('''
|
||||||
const char %(c_name)s[] = %(c_string)s;
|
const char %(c_name)s[] = %(c_string)s;
|
||||||
|
@ -75,6 +80,14 @@ def visit_end(self):
|
||||||
self._schema = None
|
self._schema = None
|
||||||
self._jsons = None
|
self._jsons = None
|
||||||
self._used_types = None
|
self._used_types = None
|
||||||
|
self._name_map = None
|
||||||
|
|
||||||
|
def _name(self, name):
|
||||||
|
if self._unmask:
|
||||||
|
return name
|
||||||
|
if name not in self._name_map:
|
||||||
|
self._name_map[name] = '%d' % len(self._name_map)
|
||||||
|
return self._name_map[name]
|
||||||
|
|
||||||
def _use_type(self, typ):
|
def _use_type(self, typ):
|
||||||
# Map the various integer types to plain int
|
# Map the various integer types to plain int
|
||||||
|
@ -86,9 +99,16 @@ def _use_type(self, typ):
|
||||||
# Add type to work queue if new
|
# Add type to work queue if new
|
||||||
if typ not in self._used_types:
|
if typ not in self._used_types:
|
||||||
self._used_types.append(typ)
|
self._used_types.append(typ)
|
||||||
return typ.name
|
# Clients should examine commands and events, not types. Hide
|
||||||
|
# type names to reduce the temptation. Also saves a few
|
||||||
|
# characters.
|
||||||
|
if isinstance(typ, QAPISchemaBuiltinType):
|
||||||
|
return typ.name
|
||||||
|
return self._name(typ.name)
|
||||||
|
|
||||||
def _gen_json(self, name, mtype, obj):
|
def _gen_json(self, name, mtype, obj):
|
||||||
|
if mtype != 'command' and mtype != 'event' and mtype != 'builtin':
|
||||||
|
name = self._name(name)
|
||||||
obj['name'] = name
|
obj['name'] = name
|
||||||
obj['meta-type'] = mtype
|
obj['meta-type'] = mtype
|
||||||
self._jsons.append(obj)
|
self._jsons.append(obj)
|
||||||
|
@ -140,7 +160,16 @@ def visit_event(self, name, info, arg_type):
|
||||||
arg_type = arg_type or self._schema.the_empty_object_type
|
arg_type = arg_type or self._schema.the_empty_object_type
|
||||||
self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
|
self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
|
||||||
|
|
||||||
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
|
# Debugging aid: unmask QAPI schema's type names
|
||||||
|
# We normally mask them, because they're not QMP wire ABI
|
||||||
|
opt_unmask = False
|
||||||
|
|
||||||
|
(input_file, output_dir, do_c, do_h, prefix, opts) = \
|
||||||
|
parse_command_line("u", ["unmask-non-abi-names"])
|
||||||
|
|
||||||
|
for o, a in opts:
|
||||||
|
if o in ("-u", "--unmask-non-abi-names"):
|
||||||
|
opt_unmask = True
|
||||||
|
|
||||||
c_comment = '''
|
c_comment = '''
|
||||||
/*
|
/*
|
||||||
|
@ -176,7 +205,7 @@ def visit_event(self, name, info, arg_type):
|
||||||
prefix=prefix))
|
prefix=prefix))
|
||||||
|
|
||||||
schema = QAPISchema(input_file)
|
schema = QAPISchema(input_file)
|
||||||
gen = QAPISchemaGenIntrospectVisitor()
|
gen = QAPISchemaGenIntrospectVisitor(opt_unmask)
|
||||||
schema.visit(gen)
|
schema.visit(gen)
|
||||||
fdef.write(gen.defn)
|
fdef.write(gen.defn)
|
||||||
fdecl.write(gen.decl)
|
fdecl.write(gen.decl)
|
||||||
|
|
Loading…
Reference in New Issue