aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2025-03-05 21:53:11 +0800
committerStefan Hajnoczi <stefanha@redhat.com>2025-03-05 21:53:12 +0800
commitb93c9dfd700ae91c0080694f53c281ef51b0d028 (patch)
tree83e1e427fbb01e09b71a6b55fe49e656d93e74df
parent661c2e1ab29cd9c4d268ae3f44712e8d421c0e56 (diff)
parentdde279925c97b614e45351400bfcf9efaf732f9d (diff)
downloadqemu-b93c9dfd700ae91c0080694f53c281ef51b0d028.zip
qemu-b93c9dfd700ae91c0080694f53c281ef51b0d028.tar.gz
qemu-b93c9dfd700ae91c0080694f53c281ef51b0d028.tar.bz2
Merge tag 'pull-qapi-2025-02-26-v2' of https://repo.or.cz/qemu/armbru into staging
QAPI patches patches for 2025-02-26 # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmfGpZsSHGFybWJydUBy # ZWRoYXQuY29tAAoJEDhwtADrkYZTGtQQAKmLIHy1c1T1yU6G9MFrAaFvH0n10UnB # mQGOvcV+8f01KxUUIvVRBD9DyRl+kJGMelZoYuMpt+vNiO5XDMqZarJUYFOYukMW # 6e/qrD3AMeyI0HGZYtELUENmuKLeAhhdE9d1PO56owR2jiFDxdzW+9TXkEXa1NHS # c54v1y5HPgIdTXd11aXWI+06S6OVSpBteUOQTiSLowBq5BC28DoFAgViA1jZ1qM+ # 1PxL4IV4QkYXfEW2ORt/auamxFWuLNBYNWnyqhR+OYeQjWWAe2A0cmcoLIHVKFwE # zcuVCXt9+8nZi3Fyx24yOineAhAi29qWxRnbXLrfa4y8OF3cihY0ZNYxvJF61iel # Wis9WM78OcuQrHCF3BNPqBm9rrac5mQf5mMk4V75Yc+I4oeJeoDG8cLZF1HMpoBT # iZAl4aW2aa7JQ778c4RxzuCWQSVzOzm5T72Ez9VDJRAWHxoiumoaIOPW9wDi7jWL # 2P/XxyVCIMsuNLsxkFQEcHwtyK5BYqSf6gCpCbbzTW1YdfDzXQIvrRx4AEuClQvP # yoLhpv3HjaomWEZbY26gJq1ImSF4uIaLbdOAvAub9wuZWCW0qd/j8PkU/xy0Q0Jx # gNoNymbRdN5v3eekcZr7L96ILzwMDp2d+zS3q+YgpYUf30INfC7LyTCg6BZ7b06r # zT05GmiP5DqS # =LNhH # -----END PGP SIGNATURE----- # gpg: Signature made Tue 04 Mar 2025 15:02:51 HKT # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * tag 'pull-qapi-2025-02-26-v2' of https://repo.or.cz/qemu/armbru: qapi: pluggable backend code generators docs/qapidoc: remove example section support docs/qapidoc: support header-less freeform sections qapi: update pylintrc config qapi/char.json: minor doc rewording for `hub` device Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r--docs/sphinx/qapidoc.py11
-rw-r--r--qapi/char.json2
-rw-r--r--scripts/qapi/backend.py63
-rw-r--r--scripts/qapi/main.py80
-rw-r--r--scripts/qapi/pylintrc1
-rw-r--r--tests/qapi-schema/doc-good.json4
-rw-r--r--tests/qapi-schema/doc-good.out3
7 files changed, 120 insertions, 44 deletions
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
index 5f96b46..61997fd 100644
--- a/docs/sphinx/qapidoc.py
+++ b/docs/sphinx/qapidoc.py
@@ -254,10 +254,6 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
section += dlnode
return [section]
- def _nodes_for_example(self, exampletext):
- """Return list of doctree nodes for a code example snippet"""
- return [nodes.literal_block(exampletext, exampletext)]
-
def _nodes_for_sections(self, doc):
"""Return list of doctree nodes for additional sections"""
nodelist = []
@@ -275,10 +271,7 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
continue
snode = self._make_section(section.tag)
- if section.tag.startswith('Example'):
- snode += self._nodes_for_example(dedent(section.text))
- else:
- self._parse_text_into_node(dedent(section.text), snode)
+ self._parse_text_into_node(dedent(section.text), snode)
nodelist.append(snode)
return nodelist
@@ -421,6 +414,8 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
node = self._start_new_heading(heading, len(leader))
if text == '':
return
+ else:
+ node = nodes.container()
self._parse_text_into_node(text, node)
self._cur_doc = None
diff --git a/qapi/char.json b/qapi/char.json
index f02b66c..dde2f95 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -337,7 +337,7 @@
#
# Configuration info for hub chardevs.
#
-# @chardevs: List of chardev IDs, which should be added to this hub
+# @chardevs: IDs to be added to this hub (maximum 4 devices).
#
# Since: 10.0
##
diff --git a/scripts/qapi/backend.py b/scripts/qapi/backend.py
new file mode 100644
index 0000000..14e60aa6
--- /dev/null
+++ b/scripts/qapi/backend.py
@@ -0,0 +1,63 @@
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+from abc import ABC, abstractmethod
+
+from .commands import gen_commands
+from .events import gen_events
+from .features import gen_features
+from .introspect import gen_introspect
+from .schema import QAPISchema
+from .types import gen_types
+from .visit import gen_visit
+
+
+class QAPIBackend(ABC):
+
+ @abstractmethod
+ def generate(self,
+ schema: QAPISchema,
+ output_dir: str,
+ prefix: str,
+ unmask: bool,
+ builtins: bool,
+ gen_tracing: bool) -> None:
+ """
+ Generate code for the given schema into the target directory.
+
+ :param schema: The primary QAPI schema object.
+ :param output_dir: The output directory to store generated code.
+ :param prefix: Optional C-code prefix for symbol names.
+ :param unmask: Expose non-ABI names through introspection?
+ :param builtins: Generate code for built-in types?
+
+ :raise QAPIError: On failures.
+ """
+
+
+class QAPICBackend(QAPIBackend):
+
+ def generate(self,
+ schema: QAPISchema,
+ output_dir: str,
+ prefix: str,
+ unmask: bool,
+ builtins: bool,
+ gen_tracing: bool) -> None:
+ """
+ Generate C code for the given schema into the target directory.
+
+ :param schema_file: The primary QAPI schema file.
+ :param output_dir: The output directory to store generated code.
+ :param prefix: Optional C-code prefix for symbol names.
+ :param unmask: Expose non-ABI names through introspection?
+ :param builtins: Generate code for built-in types?
+
+ :raise QAPIError: On failures.
+ """
+ gen_types(schema, output_dir, prefix, builtins)
+ gen_features(schema, output_dir, prefix)
+ gen_visit(schema, output_dir, prefix, builtins)
+ gen_commands(schema, output_dir, prefix, gen_tracing)
+ gen_events(schema, output_dir, prefix)
+ gen_introspect(schema, output_dir, prefix, unmask)
diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py
index 324081b..5b4679a 100644
--- a/scripts/qapi/main.py
+++ b/scripts/qapi/main.py
@@ -8,18 +8,14 @@ This is the main entry point for generating C code from the QAPI schema.
"""
import argparse
+from importlib import import_module
import sys
from typing import Optional
-from .commands import gen_commands
+from .backend import QAPIBackend, QAPICBackend
from .common import must_match
from .error import QAPIError
-from .events import gen_events
-from .features import gen_features
-from .introspect import gen_introspect
from .schema import QAPISchema
-from .types import gen_types
-from .visit import gen_visit
def invalid_prefix_char(prefix: str) -> Optional[str]:
@@ -29,32 +25,42 @@ def invalid_prefix_char(prefix: str) -> Optional[str]:
return None
-def generate(schema_file: str,
- output_dir: str,
- prefix: str,
- unmask: bool = False,
- builtins: bool = False,
- gen_tracing: bool = False) -> None:
- """
- Generate C code for the given schema into the target directory.
+def create_backend(path: str) -> QAPIBackend:
+ if path is None:
+ return QAPICBackend()
- :param schema_file: The primary QAPI schema file.
- :param output_dir: The output directory to store generated code.
- :param prefix: Optional C-code prefix for symbol names.
- :param unmask: Expose non-ABI names through introspection?
- :param builtins: Generate code for built-in types?
+ module_path, dot, class_name = path.rpartition('.')
+ if not dot:
+ print("argument of -B must be of the form MODULE.CLASS",
+ file=sys.stderr)
+ sys.exit(1)
- :raise QAPIError: On failures.
- """
- assert invalid_prefix_char(prefix) is None
+ try:
+ mod = import_module(module_path)
+ except Exception as ex:
+ print(f"unable to import '{module_path}': {ex}", file=sys.stderr)
+ sys.exit(1)
+
+ try:
+ klass = getattr(mod, class_name)
+ except AttributeError:
+ print(f"module '{module_path}' has no class '{class_name}'",
+ file=sys.stderr)
+ sys.exit(1)
+
+ try:
+ backend = klass()
+ except Exception as ex:
+ print(f"backend '{path}' cannot be instantiated: {ex}",
+ file=sys.stderr)
+ sys.exit(1)
+
+ if not isinstance(backend, QAPIBackend):
+ print(f"backend '{path}' must be an instance of QAPIBackend",
+ file=sys.stderr)
+ sys.exit(1)
- schema = QAPISchema(schema_file)
- gen_types(schema, output_dir, prefix, builtins)
- gen_features(schema, output_dir, prefix)
- gen_visit(schema, output_dir, prefix, builtins)
- gen_commands(schema, output_dir, prefix, gen_tracing)
- gen_events(schema, output_dir, prefix)
- gen_introspect(schema, output_dir, prefix, unmask)
+ return backend
def main() -> int:
@@ -77,6 +83,8 @@ def main() -> int:
parser.add_argument('-u', '--unmask-non-abi-names', action='store_true',
dest='unmask',
help="expose non-ABI names in introspection")
+ parser.add_argument('-B', '--backend', default=None,
+ help="Python module name for code generator")
# Option --suppress-tracing exists so we can avoid solving build system
# problems. TODO Drop it when we no longer need it.
@@ -93,12 +101,14 @@ def main() -> int:
return 1
try:
- generate(args.schema,
- output_dir=args.output_dir,
- prefix=args.prefix,
- unmask=args.unmask,
- builtins=args.builtins,
- gen_tracing=not args.suppress_tracing)
+ schema = QAPISchema(args.schema)
+ backend = create_backend(args.backend)
+ backend.generate(schema,
+ output_dir=args.output_dir,
+ prefix=args.prefix,
+ unmask=args.unmask,
+ builtins=args.builtins,
+ gen_tracing=not args.suppress_tracing)
except QAPIError as err:
print(err, file=sys.stderr)
return 1
diff --git a/scripts/qapi/pylintrc b/scripts/qapi/pylintrc
index c028a1f..d24eece 100644
--- a/scripts/qapi/pylintrc
+++ b/scripts/qapi/pylintrc
@@ -17,6 +17,7 @@ disable=consider-using-f-string,
too-many-arguments,
too-many-branches,
too-many-instance-attributes,
+ too-many-positional-arguments,
too-many-statements,
useless-option-value,
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index f64bf38..0a4f139 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -12,6 +12,10 @@
##
##
+# Just text, no heading.
+##
+
+##
# == Subsection
#
# *with emphasis*
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index ec277be..0a9da3e 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -58,6 +58,9 @@ doc freeform
= Section
doc freeform
body=
+Just text, no heading.
+doc freeform
+ body=
== Subsection
*with emphasis*