GObject Introspection Tips
GObject comes with a well-thought introspection mechanism that helps building language bindings by adhering to certain conventions. Unfortunately, the documentation is lacking structure and some vital information. Here are some tips, to help you through the initial confusion, if you plan to make your library introspectable:
-
If possible and to avoid a lot of trouble, you should use the Autotools integration as described here. But if you have to use CMake, the following snippet should give you a good start (assuming Foo is your library’s namespacing prefix):
find_program(INTROSPECTION_SCANNER "g-ir-scanner") find_program(INTROSPECTION_COMPILER "g-ir-compiler") set(GIR_PREFIX "Foo-${FOO_API_VERSION}") set(GIR_XML "${GIR_PREFIX}.gir") set(GIR_TYPELIB "${GIR_PREFIX}.typelib") add_custom_command(OUTPUT ${GIR_XML} COMMAND ${INTROSPECTION_SCANNER} --namespace=Foo --nsversion=${FOO_API_VERSION} --library=foo --no-libtool --include=GObject-2.0 --include=GModule-2.0 --output ${GIR_XML} --warn-all ${FOO_SRCS} DEPENDS ${FOO_SRCS} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_command(OUTPUT ${GIR_TYPELIB} COMMAND ${INTROSPECTION_COMPILER} -o ${GIR_TYPELIB} ${GIR_XML} DEPENDS ${GIR_XML} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_target(gir ALL DEPENDS ${GIR_XML} ${GIR_TYPELIB}) add_dependencies(gir foo)
Unfortunately, the typelib is not found if it is installed into
/usr/local/lib/girepository-1.0
. You either need to install it into/usr/lib/girepository-1.0
or extendGI_TYPELIB_PATH
. -
If you write interfaces, make sure that the definitions of the “virtual” function pointers in the interface structure match the real functions used to call the actual implementation. In fact, the parameter names should not play a role, but
g-ir-scanner
is very finicky. Something like thisstruct _FooVehicle { void (*accelerate) (FooVehicle *vehicle, guint kmh); }; void foo_vehicle_accelerate (FooVehicle *vehicle, guint speed);
will give you a “Foo: Vehicle: Virtual function ‘accelerate’ has no known invoker” although the type signature is the same!
-
Non-GObject-based libraries cannot be inspected. If the user of the bindings does not have to care about interfacing with third-party libraries you can just type their data structures as
gpointer
but otherwise you must wrap the entire library. -
You must keep object references in mind and set the
transfer
annotation appropriately. If you see crashes at the end of a Python session, it’s very likely that the Python interpreter tries to unref an object that has already been destroyed by your library. -
Be aware of translations into the target language. In C, the canonical constructor would be something like
foo_vehicle_new (...)
orfoo_vehicle_new_with_gasoline (...)
. In Python,g_object_new
is used to instantiate the object thus bypassing any code in the_new
functions. Of course, you could still callFoo.Vehicle.new()
directly though.If you want to make sure that certain parameters are passed at construction time, you should add GObject properties with the
G_PARAM_CONSTRUCT
orG_PARAM_CONSTRUCT_ONLY
flag to your class. To initialize the object after all “constructable” properties are set, you can override the virtualconstructed
function of the GObject base class. -
Always put
GError
arguments at the end of the parameter list or before the final...
argument list. At least with Python, you can then benefit from automatic conversion to real Python exceptions.