From: Anthony Liguori <anthony@codemonkey.ws>
To: Markus Armbruster <armbru@redhat.com>
Cc: amit.shah@redhat.com, Gerd Hoffmann <kraxel@redhat.com>,
Brad Hards <bradh@frogmouth.net>,
qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] qdev device documentation (Re: [PATCH 0/2] usb-linux: physical port handling.)
Date: Fri, 13 May 2011 09:30:09 -0500 [thread overview]
Message-ID: <4DCD4071.4040403@codemonkey.ws> (raw)
In-Reply-To: <m3zkmryrvx.fsf@blackfin.pond.sub.org>
[-- Attachment #1: Type: text/plain, Size: 496 bytes --]
On 05/13/2011 02:35 AM, Markus Armbruster wrote:
> Anthony Liguori<anthony@codemonkey.ws> writes:
>
>> That's fine. But what better way to ensure a consistent and stable UI
>> than having it centralized in one place.
>
> Consistent, stable, and bit-rotten. Unless you come up with a way to
> catch bit-rot immediately. That means on "make", not on "make docs".
>
> Extra points if the error message points right to the offending source
> line.
Er, hit send too fast. Here's the next patch.
[-- Attachment #2: 0001-qdev-add-centralized-documentation-for-qdev-v2.patch --]
[-- Type: text/x-patch, Size: 9450 bytes --]
>From f5c30c922ce1cf755ef78887f4015c131d8d6841 Mon Sep 17 00:00:00 2001
From: Anthony Liguori <aliguori@us.ibm.com>
Date: Thu, 12 May 2011 10:56:29 -0500
Subject: [PATCH 1/1] qdev: add centralized documentation for qdev (v2)
This adds a -qdev-verify option that will confirm that the documentation matches
the code. It returns a non-zero exit status if any errors are detected.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
Makefile | 2 +
Makefile.doc | 5 ++
Makefile.objs | 2 +-
qdev-doc.h | 23 +++++++++++
qdev-doc.json | 16 ++++++++
qemu-options.hx | 10 +++++
scripts/qdev-doc-to-c.py | 30 ++++++++++++++
scripts/qdev-doc-to-html.py | 40 +++++++++++++++++++
vl.c | 89 +++++++++++++++++++++++++++++++++++++++++++
9 files changed, 216 insertions(+), 1 deletions(-)
create mode 100644 Makefile.doc
create mode 100644 qdev-doc.h
create mode 100644 qdev-doc.json
create mode 100644 scripts/qdev-doc-to-c.py
create mode 100644 scripts/qdev-doc-to-html.py
diff --git a/Makefile b/Makefile
index 2b0438c..fddb261 100644
--- a/Makefile
+++ b/Makefile
@@ -341,5 +341,7 @@ tarbin:
$(mandir)/man1/qemu-img.1 \
$(mandir)/man8/qemu-nbd.8
+include $(SRC_PATH)/Makefile.doc
+
# Include automatically generated dependency files
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d)
diff --git a/Makefile.doc b/Makefile.doc
new file mode 100644
index 0000000..c1cf74a
--- /dev/null
+++ b/Makefile.doc
@@ -0,0 +1,5 @@
+qdev-doc.html: $(SRC_PATH)/qdev-doc.json $(SRC_PATH)/scripts/qdev-doc-to-html.py
+ python $(SRC_PATH)/scripts/qdev-doc-to-html.py < $< > $@
+
+qdev-doc.c: $(SRC_PATH)/qdev-doc.json $(SRC_PATH)/scripts/qdev-doc-to-c.py
+ python $(SRC_PATH)/scripts/qdev-doc-to-c.py < $< > $@
diff --git a/Makefile.objs b/Makefile.objs
index 4478c61..9547ab1 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -97,7 +97,7 @@ common-obj-y += bt-hci-csr.o
common-obj-y += buffered_file.o migration.o migration-tcp.o
common-obj-y += qemu-char.o savevm.o #aio.o
common-obj-y += msmouse.o ps2.o
-common-obj-y += qdev.o qdev-properties.o
+common-obj-y += qdev.o qdev-properties.o qdev-doc.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += pflib.o
common-obj-y += bitmap.o bitops.o
diff --git a/qdev-doc.h b/qdev-doc.h
new file mode 100644
index 0000000..401e03e
--- /dev/null
+++ b/qdev-doc.h
@@ -0,0 +1,23 @@
+#ifndef QDEV_DOC_H
+#define QDEV_DOC_H
+
+#include "qemu-common.h"
+
+typedef struct PropertyDocumentation
+{
+ const char *name;
+ const char *type;
+ const char *docs;
+} PropertyDocumentation;
+
+typedef struct DeviceStateDocumentation
+{
+ const char *name;
+ PropertyDocumentation *properties;
+} DeviceStateDocumentation;
+
+extern DeviceStateDocumentation device_docs[];
+
+bool qdev_verify_docs(void);
+
+#endif
diff --git a/qdev-doc.json b/qdev-doc.json
new file mode 100644
index 0000000..a798bff
--- /dev/null
+++ b/qdev-doc.json
@@ -0,0 +1,16 @@
+# -*- Mode: Python -*-
+
+[ { "device": "isa-serial",
+ "parent": "ISADevice",
+ "properties": {
+ "index": { "type": "uint32",
+ "doc": "A value from 0-3 that describes which IO regions to expose the device on. This sets appropriate values for iobase and irq." },
+ "iobase": { "type": "hex32",
+ "doc": "The base IO address to expose the device on." },
+ "irq": { "type": "uint32",
+ "doc": "The IRQ to use for the device." },
+ "chardev": { "type": "chr",
+ "doc": "The name of a character device to specify." }
+ }
+ }
+ ]
diff --git a/qemu-options.hx b/qemu-options.hx
index 9f121ad..a6abab4 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2378,6 +2378,16 @@ Specify a trace file to log output traces to.
ETEXI
#endif
+DEF("qdev-verify", 0, QEMU_OPTION_qdev_verify,
+ "-qdev-verify\n"
+ " Verify qdev properties match documentation\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -qdev-verify
+@findex -qdev-verify
+Verify qdev properties match documentation.
+ETEXI
+
HXCOMM This is the last statement. Insert new options before this line!
STEXI
@end table
diff --git a/scripts/qdev-doc-to-c.py b/scripts/qdev-doc-to-c.py
new file mode 100644
index 0000000..eb7ee59
--- /dev/null
+++ b/scripts/qdev-doc-to-c.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+
+import sys
+
+data = sys.stdin.read()
+
+docs = eval(data)
+
+sys.stdout.write('''
+#include "qdev-doc.h"
+
+DeviceStateDocumentation device_docs[] = {''')
+
+for item in docs:
+ sys.stdout.write('''
+ {
+ .name = "%(device)s",
+ .properties = (PropertyDocumentation[]){''' % item)
+ for prop in item["properties"]:
+ sys.stdout.write('''
+ { "%s", "%s", "%s" },''' % (prop, item["properties"][prop]['type'], item["properties"][prop]['doc']))
+
+ sys.stdout.write('''
+ { } },
+ },''')
+
+sys.stdout.write('''
+ { }
+};
+''')
diff --git a/scripts/qdev-doc-to-html.py b/scripts/qdev-doc-to-html.py
new file mode 100644
index 0000000..a25fe35
--- /dev/null
+++ b/scripts/qdev-doc-to-html.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+import sys
+
+data = sys.stdin.read()
+
+docs = eval(data)
+
+sys.stdout.write('''
+<html>
+<head>
+<title>QEMU device documentation</title>
+</head>
+<body>
+''')
+
+for item in docs:
+ sys.stdout.write('''
+<h2>%(device)s :: %(parent)s</h2>
+
+<table border="1">
+<tr>
+<th>Name</th><th>Type</th><th>Comments</th>
+</tr>
+''' % item)
+ for prop in item["properties"]:
+ sys.stdout.write('''
+<tr>
+<td>%s</td><td>%s</td><td>%s</td>
+</tr>
+''' % (prop, item["properties"][prop]['type'], item["properties"][prop]['doc']))
+
+ sys.stdout.write('''
+</table>
+''')
+
+sys.stdout.write('''
+</body>
+</html>
+''')
diff --git a/vl.c b/vl.c
index bffba69..b9f6e63 100644
--- a/vl.c
+++ b/vl.c
@@ -163,6 +163,8 @@ int main(int argc, char **argv)
#include "ui/qemu-spice.h"
+#include "qdev-doc.h"
+
//#define DEBUG_NET
//#define DEBUG_SLIRP
@@ -1298,6 +1300,82 @@ void qemu_system_vmstop_request(int reason)
qemu_notify_event();
}
+bool qdev_verify_docs(void)
+{
+ DeviceStateDocumentation *doc;
+ DeviceInfo *dev;
+ int errors = 0;
+ int warnings = 0;
+
+ for (dev = device_info_list; dev; dev = dev->next) {
+ PropertyDocumentation *prop_doc;
+ Property *prop;
+
+ for (doc = device_docs; doc->name; doc++) {
+ if (strcmp(doc->name, dev->name) == 0) {
+ break;
+ }
+ }
+
+ if (doc->name == NULL) {
+ fprintf(stderr, "Warning: device `%s' is undocumented\n",
+ dev->name);
+ warnings++;
+ continue;
+ }
+
+ for (prop = dev->props; prop->name; prop++) {
+ for (prop_doc = doc->properties; prop_doc->name; prop_doc++) {
+ if (strcmp(prop->name, prop_doc->name) == 0) {
+ break;
+ }
+ }
+
+ if (prop_doc->name == NULL) {
+ fprintf(stderr, "Warning: device `%s' has undocumented property `%s'\n",
+ dev->name, prop->name);
+ warnings++;
+ }
+ }
+
+ for (prop_doc = doc->properties; prop_doc->name; prop_doc++) {
+ for (prop = dev->props; prop->name; prop++) {
+ if (strcmp(prop->name, prop_doc->name) == 0) {
+ break;
+ }
+ }
+
+ if (prop->name == NULL) {
+ fprintf(stderr, "Error: device `%s' has documented property `%s' with no definition\n",
+ dev->name, prop_doc->name);
+ errors++;
+ }
+ }
+ }
+
+ for (doc = device_docs; doc->name; doc++) {
+ for (dev = device_info_list; dev; dev = dev->next) {
+ if (strcmp(doc->name, dev->name) == 0) {
+ break;
+ }
+ }
+
+ if (dev == NULL) {
+ fprintf(stderr, "Error: documented device `%s' has no definition\n",
+ doc->name);
+ errors++;
+ }
+ }
+
+ fprintf(stderr, "%d warnings, %d errors.\n", warnings, errors);
+
+ if (errors > 0) {
+ return true;
+ }
+
+ return false;
+}
+
void main_loop_wait(int nonblocking)
{
fd_set rfds, wfds, xfds;
@@ -2057,6 +2135,7 @@ int main(int argc, char **argv, char **envp)
#endif
int defconfig = 1;
const char *trace_file = NULL;
+ bool do_qdev_verify = false;
atexit(qemu_run_exit_notifiers);
error_set_progname(argv[0]);
@@ -2890,6 +2969,9 @@ int main(int argc, char **argv, char **envp)
fclose(fp);
break;
}
+ case QEMU_OPTION_qdev_verify:
+ do_qdev_verify = true;
+ break;
default:
os_parse_cmd_args(popt->index, optarg);
}
@@ -3136,6 +3218,13 @@ int main(int argc, char **argv, char **envp)
module_call_init(MODULE_INIT_DEVICE);
+ if (do_qdev_verify) {
+ if (qdev_verify_docs()) {
+ exit(1);
+ }
+ exit(0);
+ }
+
if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
exit(0);
--
1.7.4.1
next prev parent reply other threads:[~2011-05-13 14:30 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-05-10 10:30 [Qemu-devel] [PATCH 0/2] usb-linux: physical port handling Gerd Hoffmann
2011-05-10 10:30 ` [Qemu-devel] [PATCH 1/2] usb-linux: fix device path aka " Gerd Hoffmann
2011-05-11 8:52 ` Markus Armbruster
2011-05-12 9:17 ` Gerd Hoffmann
2011-05-10 10:30 ` [Qemu-devel] [PATCH 2/2] usb-linux: add hostport property Gerd Hoffmann
2011-05-10 14:24 ` [Qemu-devel] [PATCH 0/2] usb-linux: physical port handling Brad Hards
2011-05-12 9:25 ` [Qemu-devel] qdev device documentation (Re: [PATCH 0/2] usb-linux: physical port handling.) Gerd Hoffmann
2011-05-12 11:09 ` Markus Armbruster
2011-05-12 15:25 ` Gerd Hoffmann
2011-05-12 15:35 ` Anthony Liguori
2011-05-12 16:08 ` Markus Armbruster
2011-05-12 16:23 ` Anthony Liguori
2011-05-12 17:58 ` Markus Armbruster
2011-05-12 18:07 ` Anthony Liguori
2011-05-13 7:35 ` Markus Armbruster
2011-05-13 14:29 ` Anthony Liguori
2011-05-13 14:30 ` Anthony Liguori [this message]
2011-05-12 18:15 ` Peter Maydell
2011-05-12 19:32 ` Alon Levy
2011-05-12 20:08 ` Anthony Liguori
2011-05-13 7:13 ` Markus Armbruster
2011-05-12 15:56 ` Markus Armbruster
2011-05-12 16:05 ` Anthony Liguori
2011-05-12 15:58 ` Anthony Liguori
2011-05-12 16:18 ` Markus Armbruster
2011-05-12 16:25 ` Anthony Liguori
2011-05-12 18:00 ` Markus Armbruster
2011-05-12 17:21 ` Anthony Liguori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4DCD4071.4040403@codemonkey.ws \
--to=anthony@codemonkey.ws \
--cc=amit.shah@redhat.com \
--cc=armbru@redhat.com \
--cc=bradh@frogmouth.net \
--cc=kraxel@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).