From 9045f204f1f911867c2dae885904f13f83b9ddab Mon Sep 17 00:00:00 2001 From: Lucas Rocha Date: Tue, 7 Oct 2008 21:25:01 +0000 Subject: [PATCH] Bug 555294: Add support for multiple shared libraries per typelib. 2008-10-06 Lucas Rocha Bug 555294: Add support for multiple shared libraries per typelib. * girepository/ginvoke.c (g_function_info_invoke), girepository/ginfo.c(g_registered_type_info_get_g_type): use g_typelib_symbol instead of g_module_symbol. * girepository/girepository.h: remove g_typelib_set_module and add g_typelib_symbol. * girepository/gtypelib.[ch] (find_some_symbol, _g_typelib_init, g_typelib_new_from_memory, g_typelib_new_from_const_memory, g_typelib_free, g_typelib_symbol): chnage GTypeLib to hold a list of modules instead of just one. The symbol lookup is now abstracted behind g_typelib_symbol which tries to find the passed symbol name in one of its modules. * giscanner/girwriter.py, tools/g-ir-scanner: change scanner to read and write shared_library attribute as a comma-separated list of libs. svn path=/trunk/; revision=660 --- ChangeLog | 18 ++++ girepository/ginfo.c | 6 +- girepository/ginvoke.c | 40 ++------ girepository/girepository.c | 3 - girepository/girepository.h | 5 +- girepository/gtypelib.c | 217 +++++++++++++++++++++----------------------- girepository/gtypelib.h | 2 +- giscanner/girwriter.py | 16 ++-- tools/g-ir-scanner | 6 +- 9 files changed, 150 insertions(+), 163 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9a14d0d..5ea9d11 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2008-10-06 Lucas Rocha + + Bug 555294: Add support for multiple shared libraries per typelib. + + * girepository/ginvoke.c (g_function_info_invoke), + girepository/ginfo.c(g_registered_type_info_get_g_type): use + g_typelib_symbol instead of g_module_symbol. + * girepository/girepository.h: remove g_typelib_set_module and add + g_typelib_symbol. + * girepository/gtypelib.[ch] (find_some_symbol, _g_typelib_init, + g_typelib_new_from_memory, g_typelib_new_from_const_memory, + g_typelib_free, g_typelib_symbol): chnage GTypeLib to hold a list of + modules instead of just one. The symbol lookup is now abstracted + behind g_typelib_symbol which tries to find the passed symbol name in + one of its modules. + * giscanner/girwriter.py, tools/g-ir-scanner: change scanner to read + and write shared_library attribute as a comma-separated list of libs. + 2008-10-06 Colin Walters * giscanner/transformer.py: Parse length= annotation as diff --git a/girepository/ginfo.c b/girepository/ginfo.c index bc38472..75ced84 100644 --- a/girepository/ginfo.c +++ b/girepository/ginfo.c @@ -992,9 +992,9 @@ g_registered_type_info_get_g_type (GIRegisteredTypeInfo *info) return G_TYPE_NONE; get_type_func = NULL; - if (!g_module_symbol (((GIBaseInfo*)info)->typelib->module, - type_init, - (void**) &get_type_func)) + if (!g_typelib_symbol (((GIBaseInfo*)info)->typelib, + type_init, + (void**) &get_type_func)) return G_TYPE_NONE; return (* get_type_func) (); diff --git a/girepository/ginvoke.c b/girepository/ginvoke.c index c9180d9..d5182db 100644 --- a/girepository/ginvoke.c +++ b/girepository/ginvoke.c @@ -162,42 +162,18 @@ g_function_info_invoke (GIFunctionInfo *info, gint n_args, n_invoke_args, in_pos, out_pos, i; gpointer *args; gboolean success = FALSE; - + symbol = g_function_info_get_symbol (info); - if (!g_module_symbol (g_base_info_get_typelib((GIBaseInfo *) info)->module, - symbol, &func)) + if (!g_typelib_symbol (g_base_info_get_typelib((GIBaseInfo *) info), + symbol, &func)) { - GModule *entire_app; + g_set_error (error, + G_INVOKE_ERROR, + G_INVOKE_ERROR_SYMBOL_NOT_FOUND, + "Could not locate %s: %s", symbol, g_module_error ()); - /* - * We want to be able to add symbols to an app or an auxiliary - * library to fill in gaps in an introspected library. However, - * normally we would only look for symbols in the main library - * (typelib->module). - * - * A more elaborate solution is probably possible, but as a - * simple approach for now, if we fail to find a symbol we look - * for it in the global module. - * - * This would not be very efficient if it happened often, since - * we always do the failed lookup above first, but very few - * symbols should be outside of typelib->module so it doesn't - * matter. - */ - entire_app = g_module_open (NULL, 0); - if (!g_module_symbol (entire_app, symbol, &func)) - { - g_set_error (error, - G_INVOKE_ERROR, - G_INVOKE_ERROR_SYMBOL_NOT_FOUND, - "Could not locate %s: %s", symbol, g_module_error ()); - - g_module_close (entire_app); - - return FALSE; - } - g_module_close (entire_app); + return FALSE; } is_method = (g_function_info_get_flags (info) & GI_FUNCTION_IS_METHOD) != 0 diff --git a/girepository/girepository.c b/girepository/girepository.c index 3bde15b..15e0435 100644 --- a/girepository/girepository.c +++ b/girepository/girepository.c @@ -252,9 +252,6 @@ register_internal (GIRepository *repository, g_hash_table_insert (repository->priv->typelibs, key, (void *)typelib); } - if (typelib->module == NULL) - typelib->module = g_module_open (NULL, 0); - return namespace; } diff --git a/girepository/girepository.h b/girepository/girepository.h index 54baab4..28848d5 100644 --- a/girepository/girepository.h +++ b/girepository/girepository.h @@ -112,8 +112,9 @@ GTypelib * g_typelib_new_from_const_memory (const guchar *memory, gsize len); GTypelib * g_typelib_new_from_mapped_file (GMappedFile *mfile); void g_typelib_free (GTypelib *typelib); -void g_typelib_set_module (GTypelib *typelib, - GModule *module); +gboolean g_typelib_symbol (GTypelib *typelib, + const gchar *symbol_name, + gpointer *symbol); const gchar * g_typelib_get_namespace (GTypelib *typelib); typedef enum diff --git a/girepository/gtypelib.c b/girepository/gtypelib.c index 9a2e73c..34a65e8 100644 --- a/girepository/gtypelib.c +++ b/girepository/gtypelib.c @@ -1886,44 +1886,6 @@ g_typelib_error_quark (void) return quark; } -static const char* -find_some_symbol (GTypelib *typelib) -{ - Header *header = (Header *) typelib->data; - gint i; - - for (i = 0; i < header->n_entries; i++) - { - DirEntry *entry; - - entry = g_typelib_get_dir_entry (typelib, i + 1); - - switch (entry->blob_type) - { - case BLOB_TYPE_FUNCTION: - { - FunctionBlob *blob = (FunctionBlob *) &typelib->data[entry->offset]; - - if (blob->symbol) - return g_typelib_get_string (typelib, blob->symbol); - } - break; - case BLOB_TYPE_OBJECT: - { - RegisteredTypeBlob *blob = (RegisteredTypeBlob *) &typelib->data[entry->offset]; - - if (blob->gtype_init) - return g_typelib_get_string (typelib, blob->gtype_init); - } - break; - default: - break; - } - } - - return NULL; -} - static inline void _g_typelib_init (GTypelib *typelib) { @@ -1932,76 +1894,75 @@ _g_typelib_init (GTypelib *typelib) header = (Header *) typelib->data; if (header->shared_library) { - const gchar *shlib; + const gchar *shlib_str; + GModule *app_module = NULL; - shlib = g_typelib_get_string (typelib, header->shared_library); + shlib_str = g_typelib_get_string (typelib, header->shared_library); /* note that NULL shlib means to open the main app, which is allowed */ - /* If we do have a shared lib, first be sure the main app isn't already linked to it */ - if (shlib != NULL) + if (shlib_str != NULL) { - const char *symbol_in_module; - - symbol_in_module = find_some_symbol (typelib); - if (symbol_in_module != NULL) + gchar **shlibs; + gint i; + + /* shared-library is a comma-separated list of libraries */ + shlibs = g_strsplit (shlib_str, ",", 0); + + /* We load all passed libs unconditionally as if the same library is loaded + * again with dlopen(), the same file handle will be returned. See bug: + * http://bugzilla.gnome.org/show_bug.cgi?id=555294 + */ + for (i = 0; shlibs[i]; i++) { - typelib->module = g_module_open (NULL, G_MODULE_BIND_LAZY); - if (typelib->module == NULL) + GModule *module; + + /* Glade's autoconnect feature and OpenGL's extension mechanism + * as used by Clutter rely on dlopen(NULL) to work as a means of + * accessing the app's symbols. This keeps us from using + * G_MODULE_BIND_LOCAL. BIND_LOCAL may have other issues as well; + * in general libraries are not expecting multiple copies of + * themselves and are not expecting to be unloaded. So we just + * load modules globally for now. + */ + + module = g_module_open (shlibs[i], G_MODULE_BIND_LAZY); + + if (module == NULL) + { + GString *shlib_full = g_string_new (shlibs[i]); + + /* Prefix with "lib", try both .la and .so */ + if (!g_str_has_prefix (shlib_full->str, "lib")) + g_string_prepend (shlib_full, "lib"); + g_string_append (shlib_full, ".la"); + module = g_module_open (shlib_full->str, G_MODULE_BIND_LAZY); + if (module == NULL) + g_string_overwrite (shlib_full, strlen (shlib_full->str)-2, SHLIB_SUFFIX); + module = g_module_open (shlib_full->str, G_MODULE_BIND_LAZY); + + g_string_free (shlib_full, TRUE); + } + + if (module == NULL) { - g_warning ("Could not open main app as GModule: %s", - g_module_error ()); + g_warning ("Failed to load shared library '%s' referenced by the typelib: %s", + shlibs[i], g_module_error ()); } else { - void *sym; - if (!g_module_symbol (typelib->module, symbol_in_module, &sym)) - { - /* we will try opening the shlib, symbol is not in app already */ - g_module_close (typelib->module); - typelib->module = NULL; - } + typelib->modules = g_list_append (typelib->modules, module); } - } - else - { - g_warning ("Could not find any symbols in typelib"); - } - } - - if (typelib->module == NULL && shlib != NULL) - { - GString *shlib_full; - - /* Glade's autoconnect feature and OpenGL's extension mechanism - * as used by Clutter rely on dlopen(NULL) to work as a means of - * accessing the app's symbols. This keeps us from using - * G_MODULE_BIND_LOCAL. BIND_LOCAL may have other issues as well; - * in general libraries are not expecting multiple copies of - * themselves and are not expecting to be unloaded. So we just - * load modules globally for now. - */ - - typelib->module = g_module_open (shlib, G_MODULE_BIND_LAZY); + } - if (typelib->module == NULL) - { - shlib_full = g_string_new (shlib); - - /* Prefix with "lib", try both .la and .so */ - if (!g_str_has_prefix (shlib_full->str, "lib")) - g_string_prepend (shlib_full, "lib"); - g_string_append (shlib_full, ".la"); - typelib->module = g_module_open (shlib_full->str, G_MODULE_BIND_LAZY); - if (typelib->module == NULL) - g_string_overwrite (shlib_full, strlen (shlib_full->str)-2, SHLIB_SUFFIX); - typelib->module = g_module_open (shlib_full->str, G_MODULE_BIND_LAZY); - - g_string_free (shlib_full, TRUE); - } - if (typelib->module == NULL) - g_warning ("Failed to load shared library '%s' referenced by the typelib: %s", - shlib, g_module_error ()); + g_strfreev (shlibs); } + + /* we should make sure the app_module in the end of list so that + * it's last symbol source when loading any symbols from modules. + * See comments in g_typelib_symbol */ + app_module = g_module_open (NULL, G_MODULE_BIND_LAZY); + if (app_module) + typelib->modules = g_list_append (typelib->modules, app_module); } } @@ -2025,6 +1986,7 @@ g_typelib_new_from_memory (guchar *memory, gsize len) meta->data = memory; meta->len = len; meta->owns_memory = TRUE; + meta->modules = NULL; _g_typelib_init (meta); return meta; } @@ -2047,6 +2009,7 @@ g_typelib_new_from_const_memory (const guchar *memory, gsize len) meta->data = (guchar *) memory; meta->len = len; meta->owns_memory = FALSE; + meta->modules = NULL; _g_typelib_init (meta); return meta; } @@ -2087,28 +2050,56 @@ g_typelib_free (GTypelib *typelib) else if (typelib->owns_memory) g_free (typelib->data); - if (typelib->module) - g_module_close (typelib->module); + if (typelib->modules) + { + g_list_foreach (typelib->modules, (GFunc) g_module_close, NULL); + g_list_free (typelib->modules); + } g_free (typelib); } -/** - * g_typelib_set_module: - * @typelib: a #GTypelib instance - * @module: a #GModule; takes ownership of this module - * - * Sets the target module for all symbols referenced by the typelib. - **/ -void -g_typelib_set_module (GTypelib *typelib, GModule *module) -{ - if (typelib->module) - g_module_close (typelib->module); - typelib->module = module; -} - const gchar * g_typelib_get_namespace(GTypelib *typelib) { return g_typelib_get_string (typelib, ((Header *) typelib->data)->namespace); } + +/** + * g_typelib_symbol: + * @symbol_name: name of symbol to be loaded + * @symbol: returns a pointer to the symbol value + * + * Loads a symbol from #GTypelib. + * + * Return value: #TRUE on success + **/ +gboolean +g_typelib_symbol(GTypelib *typelib, const char *symbol_name, gpointer *symbol) +{ + GList *l; + + /* + * We want to be able to add symbols to an app or an auxiliary + * library to fill in gaps in an introspected library. However, + * normally we would only look for symbols in the main library + * (the first items in typelib->modules). + * + * A more elaborate solution is probably possible, but as a + * simple approach for now, if we fail to find a symbol we look + * for it in the global module (the last item in type->modules). + * + * This would not be very efficient if it happened often, since + * we always do the failed lookup above first, but very few + * symbols should be outside of the main libraries in + * typelib->modules so it doesn't matter. + */ + for (l = typelib->modules; l; l = l->next) + { + GModule *module = l->data; + + if (g_module_symbol (module, symbol_name, symbol)) + return TRUE; + } + + return FALSE; +} diff --git a/girepository/gtypelib.h b/girepository/gtypelib.h index 31c484d..823e8a2 100644 --- a/girepository/gtypelib.h +++ b/girepository/gtypelib.h @@ -484,7 +484,7 @@ struct _GTypelib { gsize len; gboolean owns_memory; GMappedFile *mfile; - GModule *module; + GList *modules; }; DirEntry *g_typelib_get_dir_entry (GTypelib *typelib, diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index fa7c0e5..ed4e596 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -31,11 +31,11 @@ from .xmlwriter import XMLWriter class GIRWriter(XMLWriter): - def __init__(self, namespace, shlib, includes): + def __init__(self, namespace, shlibs, includes): super(GIRWriter, self).__init__() - self._write_repository(namespace, shlib, includes) + self._write_repository(namespace, shlibs, includes) - def _write_repository(self, namespace, shlib, includes=set()): + def _write_repository(self, namespace, shlibs, includes=set()): attrs = [ ('version', '1.0'), ('xmlns', 'http://www.gtk.org/introspection/core/1.0'), @@ -45,15 +45,19 @@ class GIRWriter(XMLWriter): with self.tagcontext('repository', attrs): for include in includes: self._write_include(include) - self._write_namespace(namespace, shlib) + self._write_namespace(namespace, shlibs) def _write_include(self, include): attrs = [('name', include)] self.write_tag('include', attrs) - def _write_namespace(self, namespace, shlib): + def _write_namespace(self, namespace, shlibs): + libraries = [] + for l in shlibs: + libraries.append(os.path.basename(l)) + attrs = [('name', namespace.name), - ('shared-library', os.path.basename(shlib))] + ('shared-library', ','.join(libraries))] with self.tagcontext('namespace', attrs): for node in namespace.nodes: self._write_node(node) diff --git a/tools/g-ir-scanner b/tools/g-ir-scanner index 667a9ac..63f71c2 100755 --- a/tools/g-ir-scanner +++ b/tools/g-ir-scanner @@ -175,8 +175,8 @@ def main(args): _error("Unknown format: %s" % (options.format, )) if not options.libraries: - _error("Must specify --library for primary library") - primary_library = options.libraries[0] + _error("Must specify --library at least one primary library") + libraries = options.libraries for package in options.packages: output = subprocess.Popen(['pkg-config', '--cflags', package], @@ -236,7 +236,7 @@ def main(args): namespace = glibtransformer.parse() # Write out AST - writer = Writer(namespace, primary_library, transformer.get_includes()) + writer = Writer(namespace, libraries, transformer.get_includes()) data = writer.get_xml() if options.output: fd = open(options.output, "w") -- 2.7.4