From 407bc4bf9027f7ac4333e47cd900d773b99a23e3 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrangé" Date: Mon, 18 Nov 2024 16:12:34 +0100 Subject: qapi: Move include/qapi/qmp/ to include/qobject/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The general expectation is that header files should follow the same file/path naming scheme as the corresponding source file. There are various historical exceptions to this practice in QEMU, with one of the most notable being the include/qapi/qmp/ directory. Most of the headers there correspond to source files in qobject/. This patch corrects most of that inconsistency by creating include/qobject/ and moving the headers for qobject/ there. This also fixes MAINTAINERS for include/qapi/qmp/dispatch.h: scripts/get_maintainer.pl now reports "QAPI" instead of "No maintainers found". Signed-off-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Acked-by: Halil Pasic #s390x Signed-off-by: Markus Armbruster Message-ID: <20241118151235.2665921-2-armbru@redhat.com> [Rebased] --- scripts/qapi/commands.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts/qapi/commands.py') diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 79951a841f..f0aa13b5cf 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -320,7 +320,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): #include "qemu/osdep.h" #include "qapi/compat-policy.h" #include "qapi/visitor.h" -#include "qapi/qmp/qdict.h" +#include "qobject/qdict.h" #include "qapi/dealloc-visitor.h" #include "qapi/error.h" #include "%(visit)s.h" @@ -330,7 +330,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): if self._gen_tracing and commands != 'qapi-commands': self._genc.add(mcgen(''' -#include "qapi/qmp/qjson.h" +#include "qobject/qjson.h" #include "trace/trace-%(nm)s_trace_events.h" ''', nm=c_name(commands, protect=False))) -- cgit 1.4.1 From 153b0989d8ec7e8ef660ed9a614964f3dbdf231f Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrangé" Date: Mon, 18 Nov 2024 16:12:35 +0100 Subject: qapi: Move and rename qapi/qmp/dispatch.h to qapi/qmp-registry.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The general expectation is that header files should follow the same file/path naming scheme as the corresponding source file. There are various historical exceptions to this practice in QEMU, with one of the most notable being the include/qapi/qmp/ directory. include/qapi/qmp/dispatch.h corresponds mostly to qapi/qmp-registry.c. Move and rename it to include/qapi/qmp-registry.h. Now just qerror.h is left in include/qapi/qmp/. Since it's deprecated & (slowly) getting eliminated anyway, it isn't worth moving. Signed-off-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Signed-off-by: Markus Armbruster Message-ID: <20241118151235.2665921-3-armbru@redhat.com> --- docs/devel/qapi-code-gen.rst | 2 +- include/qapi/qmp-registry.h | 67 +++++++++++++++++++++++++++++++++++++++++++ include/qapi/qmp/dispatch.h | 67 ------------------------------------------- monitor/monitor-internal.h | 2 +- qapi/qmp-dispatch.c | 2 +- qapi/qmp-registry.c | 2 +- qga/guest-agent-core.h | 2 +- scripts/qapi/commands.py | 2 +- stubs/qmp-command-available.c | 2 +- stubs/qmp-quit.c | 2 +- system/qdev-monitor.c | 2 +- 11 files changed, 76 insertions(+), 76 deletions(-) create mode 100644 include/qapi/qmp-registry.h delete mode 100644 include/qapi/qmp/dispatch.h (limited to 'scripts/qapi/commands.py') diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst index 259d6b10c3..9fa94251b0 100644 --- a/docs/devel/qapi-code-gen.rst +++ b/docs/devel/qapi-code-gen.rst @@ -1855,7 +1855,7 @@ Example:: #ifndef EXAMPLE_QAPI_INIT_COMMANDS_H #define EXAMPLE_QAPI_INIT_COMMANDS_H - #include "qapi/qmp/dispatch.h" + #include "qapi/qmp-registry.h" void example_qmp_init_marshal(QmpCommandList *cmds); diff --git a/include/qapi/qmp-registry.h b/include/qapi/qmp-registry.h new file mode 100644 index 0000000000..f2e956813a --- /dev/null +++ b/include/qapi/qmp-registry.h @@ -0,0 +1,67 @@ +/* + * Core Definitions for QAPI/QMP 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. + * + */ + +#ifndef QAPI_QMP_DISPATCH_H +#define QAPI_QMP_DISPATCH_H + +#include "monitor/monitor.h" +#include "qemu/queue.h" + +typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); + +typedef enum QmpCommandOptions +{ + QCO_NO_SUCCESS_RESP = (1U << 0), + QCO_ALLOW_OOB = (1U << 1), + QCO_ALLOW_PRECONFIG = (1U << 2), + QCO_COROUTINE = (1U << 3), +} QmpCommandOptions; + +typedef struct QmpCommand +{ + const char *name; + /* Runs in coroutine context if QCO_COROUTINE is set */ + QmpCommandFunc *fn; + QmpCommandOptions options; + unsigned special_features; + QTAILQ_ENTRY(QmpCommand) node; + bool enabled; + const char *disable_reason; +} QmpCommand; + +typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList; + +void qmp_register_command(QmpCommandList *cmds, const char *name, + QmpCommandFunc *fn, QmpCommandOptions options, + unsigned special_features); +const QmpCommand *qmp_find_command(const QmpCommandList *cmds, + const char *name); +void qmp_disable_command(QmpCommandList *cmds, const char *name, + const char *err_msg); +void qmp_enable_command(QmpCommandList *cmds, const char *name); + +bool qmp_command_is_enabled(const QmpCommand *cmd); +bool qmp_command_available(const QmpCommand *cmd, Error **errp); +const char *qmp_command_name(const QmpCommand *cmd); +bool qmp_has_success_response(const QmpCommand *cmd); +QDict *qmp_error_response(Error *err); +QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *request, + bool allow_oob, Monitor *cur_mon); +bool qmp_is_oob(const QDict *dict); + +typedef void (*qmp_cmd_callback_fn)(const QmpCommand *cmd, void *opaque); + +void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn, + void *opaque); + +#endif diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h deleted file mode 100644 index f2e956813a..0000000000 --- a/include/qapi/qmp/dispatch.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Core Definitions for QAPI/QMP 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. - * - */ - -#ifndef QAPI_QMP_DISPATCH_H -#define QAPI_QMP_DISPATCH_H - -#include "monitor/monitor.h" -#include "qemu/queue.h" - -typedef void (QmpCommandFunc)(QDict *, QObject **, Error **); - -typedef enum QmpCommandOptions -{ - QCO_NO_SUCCESS_RESP = (1U << 0), - QCO_ALLOW_OOB = (1U << 1), - QCO_ALLOW_PRECONFIG = (1U << 2), - QCO_COROUTINE = (1U << 3), -} QmpCommandOptions; - -typedef struct QmpCommand -{ - const char *name; - /* Runs in coroutine context if QCO_COROUTINE is set */ - QmpCommandFunc *fn; - QmpCommandOptions options; - unsigned special_features; - QTAILQ_ENTRY(QmpCommand) node; - bool enabled; - const char *disable_reason; -} QmpCommand; - -typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList; - -void qmp_register_command(QmpCommandList *cmds, const char *name, - QmpCommandFunc *fn, QmpCommandOptions options, - unsigned special_features); -const QmpCommand *qmp_find_command(const QmpCommandList *cmds, - const char *name); -void qmp_disable_command(QmpCommandList *cmds, const char *name, - const char *err_msg); -void qmp_enable_command(QmpCommandList *cmds, const char *name); - -bool qmp_command_is_enabled(const QmpCommand *cmd); -bool qmp_command_available(const QmpCommand *cmd, Error **errp); -const char *qmp_command_name(const QmpCommand *cmd); -bool qmp_has_success_response(const QmpCommand *cmd); -QDict *qmp_error_response(Error *err); -QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *request, - bool allow_oob, Monitor *cur_mon); -bool qmp_is_oob(const QDict *dict); - -typedef void (*qmp_cmd_callback_fn)(const QmpCommand *cmd, void *opaque); - -void qmp_for_each_command(const QmpCommandList *cmds, qmp_cmd_callback_fn fn, - void *opaque); - -#endif diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h index 72cab703eb..5676eb334e 100644 --- a/monitor/monitor-internal.h +++ b/monitor/monitor-internal.h @@ -28,7 +28,7 @@ #include "chardev/char-fe.h" #include "monitor/monitor.h" #include "qapi/qapi-types-control.h" -#include "qapi/qmp/dispatch.h" +#include "qapi/qmp-registry.h" #include "qobject/json-parser.h" #include "qemu/readline.h" #include "system/iothread.h" diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index e24ba9f0b6..fa95fcceac 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -16,7 +16,7 @@ #include "block/aio.h" #include "qapi/compat-policy.h" #include "qapi/error.h" -#include "qapi/qmp/dispatch.h" +#include "qapi/qmp-registry.h" #include "qobject/qdict.h" #include "qobject/qjson.h" #include "qapi/qobject-input-visitor.h" diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index 485bc5e6fc..ac989074ed 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -13,7 +13,7 @@ */ #include "qemu/osdep.h" -#include "qapi/qmp/dispatch.h" +#include "qapi/qmp-registry.h" void qmp_register_command(QmpCommandList *cmds, const char *name, QmpCommandFunc *fn, QmpCommandOptions options, diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index b4e7c52c61..a536d07d0d 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -13,7 +13,7 @@ #ifndef GUEST_AGENT_CORE_H #define GUEST_AGENT_CORE_H -#include "qapi/qmp/dispatch.h" +#include "qapi/qmp-registry.h" #include "qga-qapi-types.h" #define QGA_READ_COUNT_DEFAULT 4096 diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index f0aa13b5cf..74f341b2c7 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -346,7 +346,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaModularCVisitor): def visit_begin(self, schema: QAPISchema) -> None: self._add_module('./init', ' * QAPI Commands initialization') self._genh.add(mcgen(''' -#include "qapi/qmp/dispatch.h" +#include "qapi/qmp-registry.h" void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); ''', diff --git a/stubs/qmp-command-available.c b/stubs/qmp-command-available.c index 46540af7bf..8851faced1 100644 --- a/stubs/qmp-command-available.c +++ b/stubs/qmp-command-available.c @@ -1,5 +1,5 @@ #include "qemu/osdep.h" -#include "qapi/qmp/dispatch.h" +#include "qapi/qmp-registry.h" bool qmp_command_available(const QmpCommand *cmd, Error **errp) { diff --git a/stubs/qmp-quit.c b/stubs/qmp-quit.c index a3ff47f7bd..8fb523e905 100644 --- a/stubs/qmp-quit.c +++ b/stubs/qmp-quit.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" #include "qapi/qapi-commands-control.h" -#include "qapi/qmp/dispatch.h" +#include "qapi/qmp-registry.h" void qmp_quit(Error **errp) { diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index 81fe531bd6..856c9e8c32 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -26,7 +26,7 @@ #include "system/runstate.h" #include "qapi/error.h" #include "qapi/qapi-commands-qdev.h" -#include "qapi/qmp/dispatch.h" +#include "qapi/qmp-registry.h" #include "qobject/qdict.h" #include "qapi/qmp/qerror.h" #include "qobject/qstring.h" -- cgit 1.4.1 From ba27dccc04f16e143cbf59afec5402198d69be30 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrangé" Date: Wed, 5 Feb 2025 12:35:49 +0000 Subject: qapi: rename 'special_features' to 'features' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This updates the QAPI code generation to refer to 'features' instead of 'special_features', in preparation for generalizing their exposure. Signed-off-by: Daniel P. Berrangé Message-ID: <20250205123550.2754387-4-berrange@redhat.com> Reviewed-by: Markus Armbruster [Imports tidied up with isort] Signed-off-by: Markus Armbruster --- scripts/qapi/commands.py | 4 ++-- scripts/qapi/gen.py | 8 ++++---- scripts/qapi/types.py | 14 +++++--------- scripts/qapi/visit.py | 18 +++++++----------- 4 files changed, 18 insertions(+), 26 deletions(-) (limited to 'scripts/qapi/commands.py') diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 74f341b2c7..9556af5416 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -25,7 +25,7 @@ from .gen import ( QAPIGenC, QAPISchemaModularCVisitor, build_params, - gen_special_features, + gen_features, ifcontext, ) from .schema import ( @@ -298,7 +298,7 @@ def gen_register_command(name: str, ''', name=name, c_name=c_name(name), opts=' | '.join(options) or 0, - feats=gen_special_features(features)) + feats=gen_features(features)) return ret diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index c53ca72950..b51f8d955e 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -41,10 +41,10 @@ from .schema import ( from .source import QAPISourceInfo -def gen_special_features(features: Sequence[QAPISchemaFeature]) -> str: - special_features = [f"1u << {c_enum_const('qapi', feat.name)}" - for feat in features if feat.is_special()] - return ' | '.join(special_features) or '0' +def gen_features(features: Sequence[QAPISchemaFeature]) -> str: + featenum = [f"1u << {c_enum_const('qapi', feat.name)}" + for feat in features if feat.is_special()] + return ' | '.join(featenum) or '0' class QAPIGen: diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index 7bc3f8241f..e4a1bb9f85 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -16,11 +16,7 @@ This work is licensed under the terms of the GNU GPL, version 2. from typing import List, Optional from .common import c_enum_const, c_name, mcgen -from .gen import ( - QAPISchemaModularCVisitor, - gen_special_features, - ifcontext, -) +from .gen import QAPISchemaModularCVisitor, gen_features, ifcontext from .schema import ( QAPISchema, QAPISchemaAlternatives, @@ -61,12 +57,12 @@ const QEnumLookup %(c_name)s_lookup = { index=index, name=memb.name) ret += memb.ifcond.gen_endif() - special_features = gen_special_features(memb.features) - if special_features != '0': + features = gen_features(memb.features) + if features != '0': feats += mcgen(''' - [%(index)s] = %(special_features)s, + [%(index)s] = %(features)s, ''', - index=index, special_features=special_features) + index=index, features=features) if feats: ret += mcgen(''' diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 12f92e429f..928273b9bb 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -21,11 +21,7 @@ from .common import ( indent, mcgen, ) -from .gen import ( - QAPISchemaModularCVisitor, - gen_special_features, - ifcontext, -) +from .gen import QAPISchemaModularCVisitor, gen_features, ifcontext from .schema import ( QAPISchema, QAPISchemaAlternatives, @@ -103,15 +99,15 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) ''', name=memb.name, has=has) indent.increase() - special_features = gen_special_features(memb.features) - if special_features != '0': + features = gen_features(memb.features) + if features != '0': ret += mcgen(''' - if (visit_policy_reject(v, "%(name)s", %(special_features)s, errp)) { + if (visit_policy_reject(v, "%(name)s", %(features)s, errp)) { return false; } - if (!visit_policy_skip(v, "%(name)s", %(special_features)s)) { + if (!visit_policy_skip(v, "%(name)s", %(features)s)) { ''', - name=memb.name, special_features=special_features) + name=memb.name, features=features) indent.increase() ret += mcgen(''' if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) { @@ -120,7 +116,7 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) ''', c_type=memb.type.c_name(), name=memb.name, c_name=c_name(memb.name)) - if special_features != '0': + if features != '0': indent.decrease() ret += mcgen(''' } -- cgit 1.4.1 From 2ebb09f34ffff152dda6d2b5d9a2348f3fefc6d3 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrangé" Date: Wed, 5 Feb 2025 12:35:50 +0000 Subject: qapi: expose all schema features to code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This replaces use of the constants from the QapiSpecialFeatures enum, with constants from the auto-generate QapiFeatures enum in qapi-features.h The 'deprecated' and 'unstable' features still have a little bit of special handling, being force defined to be the 1st + 2nd features in the enum, regardless of whether they're used in the schema. This retains compatibility with common code that references the features via the QapiSpecialFeatures constants. Signed-off-by: Daniel P. Berrangé Message-ID: <20250205123550.2754387-5-berrange@redhat.com> Reviewed-by: Markus Armbruster [Imports tidied up with isort] Signed-off-by: Markus Armbruster --- meson.build | 1 + scripts/qapi/commands.py | 1 + scripts/qapi/features.py | 48 ++++++++++++++++++++++++++++++++ scripts/qapi/gen.py | 6 ++-- scripts/qapi/main.py | 2 ++ scripts/qapi/schema.py | 31 ++++++++++++++++++++- scripts/qapi/types.py | 7 +++-- scripts/qapi/visit.py | 3 +- tests/meson.build | 2 ++ tests/qapi-schema/features-too-many.err | 2 ++ tests/qapi-schema/features-too-many.json | 13 +++++++++ tests/qapi-schema/features-too-many.out | 0 tests/qapi-schema/meson.build | 1 + 13 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 scripts/qapi/features.py create mode 100644 tests/qapi-schema/features-too-many.err create mode 100644 tests/qapi-schema/features-too-many.json create mode 100644 tests/qapi-schema/features-too-many.out (limited to 'scripts/qapi/commands.py') diff --git a/meson.build b/meson.build index 131b2225ab..ee59d647e4 100644 --- a/meson.build +++ b/meson.build @@ -3444,6 +3444,7 @@ qapi_gen_depends = [ meson.current_source_dir() / 'scripts/qapi/__init__.py', meson.current_source_dir() / 'scripts/qapi/schema.py', meson.current_source_dir() / 'scripts/qapi/source.py', meson.current_source_dir() / 'scripts/qapi/types.py', + meson.current_source_dir() / 'scripts/qapi/features.py', meson.current_source_dir() / 'scripts/qapi/visit.py', meson.current_source_dir() / 'scripts/qapi-gen.py' ] diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 9556af5416..7914227382 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -355,6 +355,7 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds); #include "qemu/osdep.h" #include "%(prefix)sqapi-commands.h" #include "%(prefix)sqapi-init-commands.h" +#include "%(prefix)sqapi-features.h" void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds) { diff --git a/scripts/qapi/features.py b/scripts/qapi/features.py new file mode 100644 index 0000000000..57563207a8 --- /dev/null +++ b/scripts/qapi/features.py @@ -0,0 +1,48 @@ +""" +QAPI features generator + +Copyright 2024 Red Hat + +This work is licensed under the terms of the GNU GPL, version 2. +# See the COPYING file in the top-level directory. +""" + +from typing import ValuesView + +from .common import c_enum_const, c_name +from .gen import QAPISchemaMonolithicCVisitor +from .schema import QAPISchema, QAPISchemaFeature + + +class QAPISchemaGenFeatureVisitor(QAPISchemaMonolithicCVisitor): + + def __init__(self, prefix: str): + super().__init__( + prefix, 'qapi-features', + ' * Schema-defined QAPI features', + __doc__) + + self.features: ValuesView[QAPISchemaFeature] + + def visit_begin(self, schema: QAPISchema) -> None: + self.features = schema.features() + self._genh.add("#include \"qapi/util.h\"\n\n") + + def visit_end(self) -> None: + self._genh.add("typedef enum {\n") + for f in self.features: + self._genh.add(f" {c_enum_const('qapi_feature', f.name)}") + if f.name in QAPISchemaFeature.SPECIAL_NAMES: + self._genh.add(f" = {c_enum_const('qapi', f.name)},\n") + else: + self._genh.add(",\n") + + self._genh.add("} " + c_name('QapiFeature') + ";\n") + + +def gen_features(schema: QAPISchema, + output_dir: str, + prefix: str) -> None: + vis = QAPISchemaGenFeatureVisitor(prefix) + schema.visit(vis) + vis.write(output_dir) diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index b51f8d955e..d3c56d45c8 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -42,9 +42,9 @@ from .source import QAPISourceInfo def gen_features(features: Sequence[QAPISchemaFeature]) -> str: - featenum = [f"1u << {c_enum_const('qapi', feat.name)}" - for feat in features if feat.is_special()] - return ' | '.join(featenum) or '0' + feats = [f"1u << {c_enum_const('qapi_feature', feat.name)}" + for feat in features] + return ' | '.join(feats) or '0' class QAPIGen: diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py index 316736b6a2..324081b9fc 100644 --- a/scripts/qapi/main.py +++ b/scripts/qapi/main.py @@ -15,6 +15,7 @@ from .commands import gen_commands 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 @@ -49,6 +50,7 @@ def generate(schema_file: str, 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) diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index e97c978d38..7f70969c09 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -29,6 +29,7 @@ from typing import ( List, Optional, Union, + ValuesView, cast, ) @@ -933,8 +934,11 @@ class QAPISchemaEnumMember(QAPISchemaMember): class QAPISchemaFeature(QAPISchemaMember): role = 'feature' + # Features which are standardized across all schemas + SPECIAL_NAMES = ['deprecated', 'unstable'] + def is_special(self) -> bool: - return self.name in ('deprecated', 'unstable') + return self.name in QAPISchemaFeature.SPECIAL_NAMES class QAPISchemaObjectTypeMember(QAPISchemaMember): @@ -1138,6 +1142,16 @@ class QAPISchema: self._entity_list: List[QAPISchemaEntity] = [] self._entity_dict: Dict[str, QAPISchemaDefinition] = {} self._module_dict: Dict[str, QAPISchemaModule] = OrderedDict() + # NB, values in the dict will identify the first encountered + # usage of a named feature only + self._feature_dict: Dict[str, QAPISchemaFeature] = OrderedDict() + + # All schemas get the names defined in the QapiSpecialFeature enum. + # Rely on dict iteration order matching insertion order so that + # the special names are emitted first when generating code. + for f in QAPISchemaFeature.SPECIAL_NAMES: + self._feature_dict[f] = QAPISchemaFeature(f, None) + self._schema_dir = os.path.dirname(fname) self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME) self._make_module(fname) @@ -1147,6 +1161,9 @@ class QAPISchema: self._def_exprs(exprs) self.check() + def features(self) -> ValuesView[QAPISchemaFeature]: + return self._feature_dict.values() + def _def_entity(self, ent: QAPISchemaEntity) -> None: self._entity_list.append(ent) @@ -1258,6 +1275,12 @@ class QAPISchema: ) -> List[QAPISchemaFeature]: if features is None: return [] + + for f in features: + feat = QAPISchemaFeature(f['name'], info) + if feat.name not in self._feature_dict: + self._feature_dict[feat.name] = feat + return [QAPISchemaFeature(f['name'], info, QAPISchemaIfCond(f.get('if'))) for f in features] @@ -1485,6 +1508,12 @@ class QAPISchema: for doc in self.docs: doc.check() + features = list(self._feature_dict.values()) + if len(features) > 64: + raise QAPISemError( + features[64].info, + "Maximum of 64 schema features is permitted") + def visit(self, visitor: QAPISchemaVisitor) -> None: visitor.visit_begin(self) for mod in self._module_dict.values(): diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index e4a1bb9f85..2bf7533828 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -304,11 +304,14 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor): #include "qapi/dealloc-visitor.h" #include "%(types)s.h" #include "%(visit)s.h" +#include "%(prefix)sqapi-features.h" ''', - types=types, visit=visit)) + types=types, visit=visit, + prefix=self._prefix)) self._genh.preamble_add(mcgen(''' #include "qapi/qapi-builtin-types.h" -''')) +''', + prefix=self._prefix)) def visit_begin(self, schema: QAPISchema) -> None: # gen_object() is recursive, ensure it doesn't visit the empty type diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 928273b9bb..36e240967b 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -356,8 +356,9 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor): #include "qemu/osdep.h" #include "qapi/error.h" #include "%(visit)s.h" +#include "%(prefix)sqapi-features.h" ''', - visit=visit)) + visit=visit, prefix=self._prefix)) self._genh.preamble_add(mcgen(''' #include "qapi/qapi-builtin-visit.h" #include "%(types)s.h" diff --git a/tests/meson.build b/tests/meson.build index f96c1be574..c59619220f 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -16,6 +16,8 @@ test_qapi_outputs = [ 'test-qapi-events-sub-sub-module.h', 'test-qapi-events.c', 'test-qapi-events.h', + 'test-qapi-features.c', + 'test-qapi-features.h', 'test-qapi-init-commands.c', 'test-qapi-init-commands.h', 'test-qapi-introspect.c', diff --git a/tests/qapi-schema/features-too-many.err b/tests/qapi-schema/features-too-many.err new file mode 100644 index 0000000000..bbbd6e5202 --- /dev/null +++ b/tests/qapi-schema/features-too-many.err @@ -0,0 +1,2 @@ +features-too-many.json: In command 'go-fish': +features-too-many.json:2: Maximum of 64 schema features is permitted diff --git a/tests/qapi-schema/features-too-many.json b/tests/qapi-schema/features-too-many.json new file mode 100644 index 0000000000..aab0a0b5f1 --- /dev/null +++ b/tests/qapi-schema/features-too-many.json @@ -0,0 +1,13 @@ +# Max 64 features, with 2 specials, so 63rd custom is invalid +{ 'command': 'go-fish', + 'features': [ + 'f00', 'f01', 'f02', 'f03', 'f04', 'f05', 'f06', 'f07', + 'f08', 'f09', 'f0a', 'f0b', 'f0c', 'f0d', 'f0e', 'f0f', + 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', + 'f18', 'f19', 'f1a', 'f1b', 'f1c', 'f1d', 'f1e', 'f1f', + 'f20', 'f21', 'f22', 'f23', 'f24', 'f25', 'f26', 'f27', + 'f28', 'f29', 'f2a', 'f2b', 'f2c', 'f2d', 'f2e', 'f2f', + 'f30', 'f31', 'f32', 'f33', 'f34', 'f35', 'f36', 'f37', + 'f38', 'f39', 'f3a', 'f3b', 'f3c', 'f3d', 'f3e' + ] +} diff --git a/tests/qapi-schema/features-too-many.out b/tests/qapi-schema/features-too-many.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index 0f479d9317..9577178b6f 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -105,6 +105,7 @@ schemas = [ 'event-case.json', 'event-member-invalid-dict.json', 'event-nest-struct.json', + 'features-too-many.json', 'features-bad-type.json', 'features-deprecated-type.json', 'features-duplicate-name.json', -- cgit 1.4.1