qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v4 2/5] qapi: add qapi-introspect.py code generator


From: Amos Kong
Subject: [Qemu-devel] [PATCH v4 2/5] qapi: add qapi-introspect.py code generator
Date: Thu, 23 Jan 2014 22:46:33 +0800

This is a code generator for qapi introspection. It will parse
qapi-schema.json, extend schema definitions and generate a schema
table with metadata, it references to the new structs which we used
to describe dynamic data structs.  The metadata will help C code to
allocate right structs and provide useful information to management
to checking suported feature and QMP commandline detail. The schema
table will be saved to qapi-introspect.h.

The $(prefix) is used to as a namespace to keep the generated code
from one schema/code-generation separated from others so code and
be generated from multiple schemas with clobbering previously
created code.

Signed-off-by: Amos Kong <address@hidden>
---
 .gitignore                      |   1 +
 Makefile                        |   5 +-
 docs/qmp-full-introspection.txt |  17 ++++
 scripts/qapi-introspect.py      | 172 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 194 insertions(+), 1 deletion(-)
 create mode 100644 scripts/qapi-introspect.py

diff --git a/.gitignore b/.gitignore
index 1c9d63d..de3cb80 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@ linux-headers/asm
 qapi-generated
 qapi-types.[ch]
 qapi-visit.[ch]
+qapi-introspect.h
 qmp-commands.h
 qmp-marshal.c
 qemu-doc.html
diff --git a/Makefile b/Makefile
index bdff4e4..1dac5e7 100644
--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,7 @@ endif
 endif
 
 GENERATED_HEADERS = config-host.h qemu-options.def
-GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
+GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h qapi-introspect.h
 GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
 
 GENERATED_HEADERS += trace/generated-events.h
@@ -229,6 +229,9 @@ $(SRC_PATH)/qapi-schema.json 
$(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
 qmp-commands.h qmp-marshal.c :\
 $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
        $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py 
$(gen-out-type) -m -o "." < $<, "  GEN   $@")
+qapi-introspect.h:\
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
+       $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py 
$(gen-out-type) -o "." < $<, "  GEN   $@")
 
 QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h 
qga-qmp-commands.h)
 $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
diff --git a/docs/qmp-full-introspection.txt b/docs/qmp-full-introspection.txt
index d2cf7b3..8ecbc0c 100644
--- a/docs/qmp-full-introspection.txt
+++ b/docs/qmp-full-introspection.txt
@@ -42,3 +42,20 @@ types.
 
 'anonymous-struct' will be used to describe arbitrary structs
 (dictionary, list or string).
+
+== Avoid dead loop in recursive extending ==
+
+We have four types (ImageInfo, BlockStats, PciDeviceInfo, ObjectData)
+that uses themself in their own define data directly or indirectly,
+we will not repeatedly extend them to avoid dead loop.
+
+We use a 'parents List' to record the visit path, type name of each
+extended node will be saved to the List.
+
+Append type name to the list before extending, and remove type name
+from the list after extending.
+
+If the type name is already extended in parents List, we won't extend
+it repeatedly for avoiding dead loop.
+
+'recursive' indicates if the type is extended or not.
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
new file mode 100644
index 0000000..03179fa
--- /dev/null
+++ b/scripts/qapi-introspect.py
@@ -0,0 +1,172 @@
+#
+# QAPI introspection info generator
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# Authors:
+#  Amos Kong <address@hidden>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING.LIB file in the top-level directory.
+
+from ordereddict import OrderedDict
+from qapi import *
+import sys
+import os
+import getopt
+import errno
+
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], "hp:o:",
+                                   ["header", "prefix=", "output-dir="])
+except getopt.GetoptError, err:
+    print str(err)
+    sys.exit(1)
+
+output_dir = ""
+prefix = ""
+h_file = 'qapi-introspect.h'
+
+do_h = False
+
+for o, a in opts:
+    if o in ("-p", "--prefix"):
+        prefix = a
+    elif o in ("-o", "--output-dir"):
+        output_dir = a + "/"
+    elif o in ("-h", "--header"):
+        do_h = True
+
+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()
+
+fdecl = maybe_open(do_h, h_file, 'w')
+
+fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+
+/*
+ * Head file to store parsed information of QAPI schema
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Authors:
+ *  Amos Kong <address@hidden>
+ *
+ * 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
+
+''',
+                  guard=guardname(h_file)))
+
+def extend_schema(expr, parents=[], member=True):
+    ret = {}
+    recu = 'False'
+    name = ""
+
+    if type(expr) is OrderedDict:
+        if not member:
+            e = expr.popitem(last=False)
+            typ = e[0]
+            name = e[1]
+        else:
+            typ = "anonymous-struct"
+
+        if typ == 'enum':
+            for key in expr.keys():
+                ret[key] = expr[key]
+        else:
+            ret = {}
+            for key in expr.keys():
+                ret[key], parents = extend_schema(expr[key], parents)
+
+    elif type(expr) is list:
+        typ = 'anonymous-struct'
+        ret = []
+        for i in expr:
+            tmp, parents = extend_schema(i, parents)
+            ret.append(tmp)
+    elif type(expr) is str:
+        name = expr
+        if schema_dict.has_key(expr) and expr not in parents:
+            parents.append(expr)
+            typ = schema_dict[expr][1]
+            recu = 'True'
+            ret, parents = extend_schema(schema_dict[expr][0].copy(),
+                                         parents, False)
+            parents.remove(expr)
+            ret['_obj_recursive'] = 'True'
+            return ret, parents
+        else:
+            return expr, parents
+
+    return {'_obj_member': "%s" % member, '_obj_type': typ,
+            '_obj_name': name, '_obj_recursive': recu,
+            '_obj_data': ret}, parents
+
+
+exprs = parse_schema(sys.stdin)
+schema_dict = {}
+
+for expr in exprs:
+    if expr.has_key('type') or expr.has_key('enum') or expr.has_key('union'):
+        e = expr.copy()
+
+        first = e.popitem(last=False)
+        schema_dict[first[1]] = [expr.copy(), first[0]]
+
+fdecl.write('''const char *const qmp_schema_table[] = {
+''')
+
+def convert(odict):
+    d = {}
+    for k, v in odict.items():
+        if type(v) is OrderedDict:
+            d[k] = convert(v)
+        elif type(v) is list:
+            l = []
+            for j in v:
+                if type(j) is OrderedDict:
+                    l.append(convert(j))
+                else:
+                    l.append(j)
+            d[k] = l
+        else:
+            d[k] = v
+    return d
+
+count = 0
+for expr in exprs:
+    fdecl.write('''    /* %s */
+''' % expr)
+
+    expr, parents = extend_schema(expr, [], False)
+    fdecl.write('''    "%s",
+
+''' % convert(expr))
+
+fdecl.write('''    NULL };
+
+#endif
+''')
+
+fdecl.flush()
+fdecl.close()
-- 
1.8.4.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]