qemu-devel
[Top][All Lists]
Advanced

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

Re: [PATCH v3 0/8] qapi-go: add generator for Golang interfaces


From: Markus Armbruster
Subject: Re: [PATCH v3 0/8] qapi-go: add generator for Golang interfaces
Date: Fri, 17 Jan 2025 11:44:21 +0100
User-agent: Gnus/5.13 (Gnus v5.13)

Daniel P. Berrangé <berrange@redhat.com> writes:

> On Fri, Jan 10, 2025 at 11:49:38AM +0100, Victor Toso wrote:
>> I've pushed this series in my gitlab fork:
>> https://gitlab.com/victortoso/qapi-go/
>> 
>> The fork contains some tests, including tests that were generated from
>> QAPI's own examples from another generator created for testing, if you
>> are interested in it:
>> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg04946.html
>> 
>> I've generated the qapi-go module over each commit of this series, see:
>> https://gitlab.com/victortoso/qapi-go/-/commits/qapi-golang-v3-by-patch
>> 
>> I've also generated the qapi-go module over QEMU tags: v9.1.0, v9.2.0:
>> https://gitlab.com/victortoso/qapi-go/-/commits/qapi-golang-v3-by-tags
>
> Apologies in advance for what will be a long mail.....

I decline the opportunity for the pot to call the kettle black ;)

[...]

> NB What I've not especially considered in any of this is the impact of
> differing QEMU versions & their schema changes. The easy way out is to
> just re-run the generator for each version, putting them in a separate
> Go package. So you can do 'import' of "qapi/qemu/abi920" for 9.2.0
> schema APIs, or "qapi/qemu/910" for 9.1.0 schema APIs. The app dev would
> have to choose which version (or versions) they consume & implement
> against. Splitting versions across the whole package, avoids having to
> consider versioning within parameters of a single command/event.

I endorse this approach.

First, a practical point.  We want to generate bindings from the schema.
The generator we have works on the current version of the schema.  To
generate something spanning versions, we would have to make it work on
several versions, wouldn't we?  I don't think we can afford such
ambition.

Next, some supporting thoughts on interfaces and why bindings spanning
versions feels like way too much trouble to me.

QMP was designed for compatible schema evolution: we can evolve the
schema without breaking clients of the wire interface as long as they
stick to certain rules, such as "ignore unknown members in client
input".

Occasionally, the schema needs to change in ways that can affect such
clients.  We promise to give clients notice and time to adjust: we
formally deprecate the old interface, but keep it working for a grace
period, namely the release it was deprecated and one further release.

So, if your QMP client targets a specific version of the wire interface,
and avoids deprecated stuff, it'll be fine for at least two more
releases.  After that, you better upgrade the client.

This is a moderately flexible coupling between QMP client and server.

When you stretch it beyond the limit, things for the most part continue
to work.  Only the things we changed incompatibly can break.

If you need more flexible coupling, you can use QMP introspection to
target a *range* of wire interfaces.  The price is additional complexity
in the client.

Downstreams complicate this story a bit, but not in interesting ways, I
believe.

The existing C bindings are for the current schema version only.  That's
fine, because the only customer (QEMU) only cares for the current
version.

It would also be fine for external customers as long as they only need
the moderately flexible coupling described above.

Bindings spanning schema versions are significantly harder.

Do our rules for compatible schema evolution transfer from the
JSON-based wire interface to the bindings?  Not necessarily.  May
require acrobatics that make the bindings ugly.

Example: adding an argument to an event is compatible evolution.

Adding it to the C function to send the event is not compatible: it
breaks the build, and all callers need to be adjusted to fix it.  Yes,
this may not be an issue with certain other languages, but my point
stands: not necessarily.

Example: adding a member to an object type is compatible evolution.

Adding it to the type in the ABI is not compatible: mixing ABI before
and after won't link if you're lucky, and run amok at run time if you're
not.




reply via email to

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