One of the nice features of the C programming language is that all the other languages are doing their best to allow easy creation of bindings for a code written in C. Thus when I was thinking about the choice of programming language for a new library (the libblockdev library) C was the answer because I wanted to make the new library usable from as many programming languages as possible. 1 The next question was how to write to code so that it would be really easy to create bindings for other languages and since I’ve now been fighting with Gtk for more than 3 years at work I knew that GObject introspection is a powerful mechanism providing number of bindings basically for free.
How does it work?
I’m not going to describe the details of how GObject introspection works, but the basic idea is that if one writes nice GObject-based C code and adds some little pieces of metadata in few specific places, two tools can be used to produce an XML and a .typelib (binary) files providing enough information for many other languages to use the compiled C code just like the native code. That is achieved by the existence of those XML and .typelib files in connection with a code that can parse and use them. You may remark that many programming languages have tools for generating bindings for C code. The difference here is that with GObject introspection it’s only necessary to run two tools to generate two files that can then be used by numbers of languages. The best thing is that the resulting XML and .typelib files (let’s call them introspection data) are declarative and contain only metadata for the compiled C code. So no additional tweaks of any "native" code is required.
Can I tweak the details?
On the other hand, the GObject introspection and introspection data were designed in a way that they could be used from a wide variety of programming languages ranging from compiled, strong-typed functional programming language Haskell to interpreted, dynamic and very benevolent language Python and many others. For this reason languages supporting GObject introspection usually also support a way to define thin wrappers (so called overrides) providing even easier usage of the C code. For example Python has a nice feature of defining default parameter values allowing the caller code to omit such parameters and let the callee use the default values. However, this is still quite rare in the area of programming languages so the GObject introspection doesn’t build on this principle (even though it is planned for some future releases ). By providing an easy way for defining overrides Python allows creation of simple file defining new functions/classes/methods wrapping the C/GObject functions/classes adding the default parameter values. More complex examples are overrides allowing native iteration over items in containers, raising exceptions per return values, etc.
But…., or not?
So far so good, right? Looks like there really is an easy way to write code reusable from many other programming languages. But…, there always is some "but", you know. But (pun intended) this time it’s only a "first glance but" –all this is GObject introspection and writing proper GObject code is a real pain, although there are some tools generating the basic structure, it’s still a lot of work to do. However, if you are curious enough, at least as much as I am, you can find out that the g-ir-scanner tool that is used to generate the XML file doesn’t complain if you run it on a non-GObject, "plain C", code! Although the GObject introspection developers will argue, say that it is not supported and nobody uses it this way (which can be proven wrong) and explain that it’s really easy and much better to write GObject code with all that boilerplate code it requires, generating introspection data for non-GObject code works just fine. One needs to give all introspected symbols a common project prefix, write gtk-doc documentation comments (similar to doxygen) with some introspection-related additional fields (e.g. documenting whether the caller should free the returned value or it is owned by the callee), but that is required for proper GObject-based code anyway. Running g-ir-scanner then produces nice XML edible by g-ir-compile producing the .typelib file. By moving them to their right places or telling e.g. Python where to find them, it’s super-easy to use the C code from Python: from gi.repository import Foo and here you go using your libfoo.so as Foo.bar(), etc.!
To be continued…
Things might get a bit tricky on the way if you want to use GObject introspection in some more or really complex situations, but I haven’t encountered any such that I’d decide to give it up and stop using GObject introspection or that I’d have to resign on functionality or API of the library and I’ll share the tips and tricks I’ve discovered so far here on this blog in following articles.
Not that I haven’t cursed myself many times for this decision.↩
Posted from GScribble.