call_end

    • Pl chevron_right

      Christian Hergert: Libpeas and Introspection

      news.movim.eu / PlanetGnome • 24 October • 5 minutes

    One of the unintended side-effects of writing applications using language bindings is that you inherit the dependencies of the binding.

    This made things a bit complicated when GIRepository moved from gobject-introspection-1.0 to girepository-2.0 as we very much want language bindings to move to the new API.

    Where this adds great difficulty on maintainers is in projects like Libpeas which provides plug-in capabilities for GTK application developers across multiple programming languages.

    In practice this has allowed applications like Gedit, Rhythmbox, and GNOME Builder to be written in C but load plugins from languages such as Python, Lua, JavaScript, Rust, C, C++, Vala, or any other language capable of producing a .so / .dylib / .dll .

    A very early version of Libpeas, years before I took over maintaining the library, had support for GObject Introspection baked in. This allowed really interesting (at the time) tooling to perform dynamic method call dispatching using a sort of proxy object implemented at runtime. Practically nobody is using this feature from what I can tell.

    But maintaining ABI being what it is, the support for it has long been part of the libpeas-1.x ABI.

    A couple years ago I finally released a fresh libpeas-2.x ABI which removed a lot of legacy API. With objects implementing GListModel and PleasPluginInfo becoming a GObject , the need for libpeas-gtk dwindled. It’s extremely easy for your application to do everything provided by the library. Additionally, I removed the unused GObject Introspection support which means that libpeas-2.x no longer needs to link against gobject-introspection-1.0 (nor girepository-2.0 ).

    One area where those are still used is the testsuite. This can complicate testing because we want to make sure that APIs work across language bindings but if the language binding uses a specific version of GObject Introspection that does not align with what the libpeas project is using for tests, it will of course lead to runtime disasters.

    Such is the case with some language bindings. The Lua LGI project is scarcely maintained right now and still uses gobject-introspection-1.0 instead of girepository-2.0 . I submitted patches upstream to port it over, but without an official maintainer well versed in C and language bindings there isn’t anyone to review and say “yes merge this”.

    There is a fork now that includes some of the patches I submitted upstream, but the namespace is different so it isn’t a 1:1 replacement.

    The PyGObject project has moved to girepository-2.0 upstream and that caused some breakage with applications in Fedora 42 that were still using the legacy libpeas-1.x ABI. For that reason, I believe the older PyGObject was released With Fedora 42.

    If you are using libpeas-2.x in your application, you have nothing to fear with any of the language runtimes integrated with libpeas. Since libpeas doesn’t link against either introspection libraries, it can’t hurt you. Just make sure your dependencies and language bindings are all in sync and you should be fine.

    If you are using libpeas-1.x still (2.x was released a little over 2 years ago) then you are in a much worse shape. Language bindings are moving (or have moved) to girepository-2.0 while libpeas cannot realistically be ported and maintain ABI. Too much is exposed as part of the library itself.

    It is imperative that if you want to keep your application working that you are either on libpeas-2.x or you’re bundling your application in such a way that you can guarantee your dependencies are all on the same version of GObject Introspection.

    Halfway ABI

    There exists a sort of “half-way-ABI” that someone could work on with enough motivation which is to break ABI as a sort of libpeas-1.38 . It would move to girepository-2.0 and all the ABI side-effects that come with it. Since the introspection support in libpeas-1.x is rarely used there should be little side-effects other than recompiling against the new ABI (and the build system transitions that go along with that).

    In my experience maintaining the largest application using libpeas (being Builder), that is really a lot more effort than porting your applications to libpeas-2.x .

    Is my app effected?

    So in short, here are a few questions to ask yourself to know if you’re affected by this.

    • Does my application only use embedded plug-ins or plug-ins from shared-modules such as *.so ? If so, then you are all set!
    • Do I use libpeas-1.x? If no, then great!
    • Does my libpeas-1.x project use Python for plug-ins? If yes, port to libpeas-2.x (or alternatively work suggested halfway-ABI for libpeas).
    • Does my libpeas-1.x or libpeas-2.x project use Lua for plug-ins? If yes, make sure all your dependencies are using gobject-introspection-1.0 only. Any use of girepository-2.0 will end in doom.

    Since JavaScript support with GJS/MozJS was added in libpeas-2.x , if you’re using JavaScript plug-ins you’re already good. GJS recently transitioned to girepository-2.0 already and continues to integrate well with libpeas. But do make sure your other dependencies have made the transition.

    How this could have been avoided?

    Without a time machine there are only three options besides what was done and they all create their own painful side-effects for the ecosystem.

    1. Never break ABI even if your library was a stop gap, never change dependencies, never let dependencies change dependencies, never fix anything.
    2. When pulling GObject Introspection into the GLib project, rename all symbols to a new namespace so that both libraries may co-exist in process at the same time. Symbol multi-versioning can’t fix overlapping type name registration in GType.
    3. Don’t fix any of the glaring issues or inconsistencies when pulling GObject Introspection into GLib. Make gobject-introspection-1.0 map to the same thing that girepository-2.0 does.

    All of those have serious side-effects that are equal to if not worse than the status-quo.

    Those that want to “ do nothing ” as maintainers of their applications can really just keep shipping them on Flatpak but with the Runtime pinned to their golden age of choice.

    Moral of the story is that ABI’s are hard even when you’re good at it. Doubly so if your library does anything non-trivial.