GTK and dlopen issue

Well I asked about that issue already 3 years ago, but got no really helpful answer.

The problem is, that some languages like Nim loads dynamic libs with dlopen(). Python seems to have done it also some years ago, I found a related issue with google, but again no solution.

I hacked together some C code to show the issue:

It is based on

http://tldp.org/HOWTO/Program-Library-HOWTO/dl-libraries.html

// gcc -o foo foo.c -ldl
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char **argv) {
    void *handle;
    void *handle2;
    long (*gtype)(char*);
    char *error;

    handle = dlopen ("/usr/lib64/libgobject-2.0.so", RTLD_LAZY);
    if (!handle) {
        fputs (dlerror(), stderr);
        exit(1);
    }
    handle2 = dlopen ("/usr/lib64/libgtk-3.so", RTLD_LAZY | RTLD_GLOBAL);
    if (!handle2) {
        fputs (dlerror(), stderr);
        exit(1);
    }

    gtype = dlsym(handle, "g_type_from_name");
    if ((error = dlerror()) != NULL)  {
        fputs(error, stderr);
        exit(1);
    }

    printf ("%ld\n", (*gtype)("gfloat"));
    printf ("%ld\n", (*gtype)("gchararray"));
    printf ("%ld\n", (*gtype)("guint"));
    printf ("%ld\n", (*gtype)("GtkGradient"));
    dlclose(handle);
}

Output is

stefan@nuc /tmp/gtk3 $ gcc -o foo foo.c -ldl
stefan@nuc /tmp/gtk3 $ ./foo 
56
64
28
0

The last line should be not zero. (I added RTLD_GLOBAL flag, which google told me, but that makes no difference.) My impression is, that for the “fundamental” gtypes all is OK, but the other (boxed) are not initialized with dlopen(). There is one fix: Call gtk_gradient_get_type() once before calling g_type_from_name(). That seems to work reliable, users have done that in the past for all the gtksourceview types which have the same issue. For (some) gtksourceview types a call of _new() seemed also to work.

So calling _get_type() for all the not fundamental types at program startup seems to be a solution, but an ugly one. I assume that the gtk related libs contain some startup code, which is executed when libs are linked regulary, but not when only dlopen() is called. So can there be a solution for this issue?

Normally the types are retrieved through C macros, such as GTK_TYPE_GRADIENT, which calls gtk_gradient_get_type(). So I don’t think statically linked libs run into this situation.

I know that from C macros like GTK_TYPE_GRADIENT are generally used, so no need for
g_type_from_name(). But for language bindings generated by gobject-introspection we generally do not have the C macros. But sometimes we need GTypes.

[EDIT]

Well, from

https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#G-DEFINE-TYPE-EXTENDED:CAPS

it is clear that gtk_gadget_get_type() registers the gtypes. But how to call it automatically?

Or may it be not an dlopen() issue at all – may it be that g_type_from_name() generally does only work for fundamental types, and that we have to call _get_type() to make it work for that type? I can not really believe that, but have to test.

This is really outside of my knowledge area, but this sounds like what libgirepository is designed for.


// gcc -o t t.c pkg-config --libs --cflags gtk+-3.0
// http://zetcode.com/gui/gtk2/introduction/
#include <gtk/gtk.h>

int main(int argc, char *argv[]) {

gtk_init(&argc, &argv);

g_print("GTK+ version: %d.%d.%d\n", gtk_major_version, 
    gtk_minor_version, gtk_micro_version);
g_print("Glib version: %d.%d.%d\n", glib_major_version,
    glib_minor_version, glib_micro_version);    
    
g_print("%ld\n", g_type_from_name("gfloat"));

g_print("%ld\n", g_type_from_name("GtkGradient"));

return 0;

}

stefan@nuc /tmp/gtk3 $ gcc -o t t.c `pkg-config --libs --cflags gtk+-3.0`
stefan@nuc /tmp/gtk3 $ ./t
GTK+ version: 3.24.10
Glib version: 2.60.7
56
0

So it seems to be not related to dlopen() at all! Well at least I have learned how to use dlopen now.

And to be sure:

#include <gtk/gtk.h>

int main(int argc, char *argv[]) {

    gtk_init(&argc, &argv);

    g_print("GTK+ version: %d.%d.%d\n", gtk_major_version, 
        gtk_minor_version, gtk_micro_version);
    g_print("Glib version: %d.%d.%d\n", glib_major_version,
        glib_minor_version, glib_micro_version);    
        
    g_print("%ld\n", g_type_from_name("gfloat"));

    g_print("%ld\n", g_type_from_name("GtkGradient"));

    if (gtk_gradient_get_type())
      g_print("ok\n");


    g_print("%ld\n", g_type_from_name("GtkGradient"));

    return 0;
}
$ ./t
GTK+ version: 3.24.10
Glib version: 2.60.7
56
0
ok
93938907029952

So I will have to generate calls of type _get_type() for all the gtypes?

Yes. Before the get_type() call, the type is unknown to the type system. You cannot use g_type_from_name() to create a type because the type system doesn’t know how to map a type name to a type until the type registers itself. The GType type system is a run time type system, not a compile time one.

That’s why each typed entry in the introspection data has a get_type() function associated with it.

Additionally, you cannot ever unload a shared library that registers GTypes. Trying to unload libgobject, for instance, will typically result in an error.

Some fundamental types are initialised by GLib itself as soon as it’s loaded, using a static constructor; it does not mean all types are initialised automatically by all GObject-based libraries at loading time.

You simply cannot rely on the type system initialising all types.

I don’t know much about the GType low-level stuff, but isn’t g_type_ensure () a relevant function for this case?

Thank you for your comment Andy, but g_type_ensure() we did test early this year already, see

That function does not help, we tested it, and the fact that it does not help was obvious indeed from its source code or maybe even from its documentation, despite its name.

I will simple generate get_type() functions for all the types now, then we do not need g_type_from_name() at all. The funny fact is, that g_type_from_name() is provided by gobject-introspection, but the get_type() functions not. But get_type() is offered from the libraries, so the solution is: When we process a type with valid gtype in bindings generation, than we can be sure that a get_type() is provided by library, and we can generate and use that function. Unfortunately I have spent the whole last day by looking for the issue at dlopen, which is totally unrelated.

g_type_ensure() is just a way to write:

(void) your_class_get_type ();

without the compiler optimising it away. You’re still required to call the get_type() function, especially if you’re going to reference the type internally in a dlsym() situation—for instance, if you have a GtkBuilder template that contains a reference to a private class.

1 Like

I’m excited that this seems to have been worked out. Just want to thank everybody for their input!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.