Bug 555294: Add support for multiple shared libraries per typelib.

2008-10-06  Lucas Rocha  <lucasr@gnome.org>

	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
This commit is contained in:
Lucas Rocha 2008-10-07 21:25:01 +00:00 committed by Lucas Almeida Rocha
parent ea99326529
commit 728beb0424
6 changed files with 119 additions and 154 deletions

View File

@ -992,9 +992,9 @@ g_registered_type_info_get_g_type (GIRegisteredTypeInfo *info)
return G_TYPE_NONE; return G_TYPE_NONE;
get_type_func = NULL; get_type_func = NULL;
if (!g_module_symbol (((GIBaseInfo*)info)->typelib->module, if (!g_typelib_symbol (((GIBaseInfo*)info)->typelib,
type_init, type_init,
(void**) &get_type_func)) (void**) &get_type_func))
return G_TYPE_NONE; return G_TYPE_NONE;
return (* get_type_func) (); return (* get_type_func) ();

View File

@ -162,42 +162,18 @@ g_function_info_invoke (GIFunctionInfo *info,
gint n_args, n_invoke_args, in_pos, out_pos, i; gint n_args, n_invoke_args, in_pos, out_pos, i;
gpointer *args; gpointer *args;
gboolean success = FALSE; gboolean success = FALSE;
symbol = g_function_info_get_symbol (info); symbol = g_function_info_get_symbol (info);
if (!g_module_symbol (g_base_info_get_typelib((GIBaseInfo *) info)->module, if (!g_typelib_symbol (g_base_info_get_typelib((GIBaseInfo *) info),
symbol, &func)) 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 ());
/* return FALSE;
* 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);
} }
is_method = (g_function_info_get_flags (info) & GI_FUNCTION_IS_METHOD) != 0 is_method = (g_function_info_get_flags (info) & GI_FUNCTION_IS_METHOD) != 0

View File

@ -252,9 +252,6 @@ register_internal (GIRepository *repository,
g_hash_table_insert (repository->priv->typelibs, key, (void *)typelib); g_hash_table_insert (repository->priv->typelibs, key, (void *)typelib);
} }
if (typelib->module == NULL)
typelib->module = g_module_open (NULL, 0);
return namespace; return namespace;
} }

View File

@ -112,8 +112,9 @@ GTypelib * g_typelib_new_from_const_memory (const guchar *memory,
gsize len); gsize len);
GTypelib * g_typelib_new_from_mapped_file (GMappedFile *mfile); GTypelib * g_typelib_new_from_mapped_file (GMappedFile *mfile);
void g_typelib_free (GTypelib *typelib); void g_typelib_free (GTypelib *typelib);
void g_typelib_set_module (GTypelib *typelib, gboolean g_typelib_symbol (GTypelib *typelib,
GModule *module); const gchar *symbol_name,
gpointer *symbol);
const gchar * g_typelib_get_namespace (GTypelib *typelib); const gchar * g_typelib_get_namespace (GTypelib *typelib);
typedef enum typedef enum

View File

@ -1886,44 +1886,6 @@ g_typelib_error_quark (void)
return quark; 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 static inline void
_g_typelib_init (GTypelib *typelib) _g_typelib_init (GTypelib *typelib)
{ {
@ -1932,76 +1894,75 @@ _g_typelib_init (GTypelib *typelib)
header = (Header *) typelib->data; header = (Header *) typelib->data;
if (header->shared_library) 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 */ /* 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_str != NULL)
if (shlib != NULL)
{ {
const char *symbol_in_module; gchar **shlibs;
gint i;
symbol_in_module = find_some_symbol (typelib);
if (symbol_in_module != NULL) /* 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); GModule *module;
if (typelib->module == NULL)
/* 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_warning ("Failed to load shared library '%s' referenced by the typelib: %s",
g_module_error ()); shlibs[i], g_module_error ());
} }
else else
{ {
void *sym; typelib->modules = g_list_append (typelib->modules, module);
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;
}
} }
} }
else
{ g_strfreev (shlibs);
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 /* we should make sure the app_module in the end of list so that
* as used by Clutter rely on dlopen(NULL) to work as a means of * it's last symbol source when loading any symbols from modules.
* accessing the app's symbols. This keeps us from using * See comments in g_typelib_symbol */
* G_MODULE_BIND_LOCAL. BIND_LOCAL may have other issues as well; app_module = g_module_open (NULL, G_MODULE_BIND_LAZY);
* in general libraries are not expecting multiple copies of if (app_module)
* themselves and are not expecting to be unloaded. So we just typelib->modules = g_list_append (typelib->modules, app_module);
* 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 ());
}
} }
} }
@ -2025,6 +1986,7 @@ g_typelib_new_from_memory (guchar *memory, gsize len)
meta->data = memory; meta->data = memory;
meta->len = len; meta->len = len;
meta->owns_memory = TRUE; meta->owns_memory = TRUE;
meta->modules = NULL;
_g_typelib_init (meta); _g_typelib_init (meta);
return meta; return meta;
} }
@ -2047,6 +2009,7 @@ g_typelib_new_from_const_memory (const guchar *memory, gsize len)
meta->data = (guchar *) memory; meta->data = (guchar *) memory;
meta->len = len; meta->len = len;
meta->owns_memory = FALSE; meta->owns_memory = FALSE;
meta->modules = NULL;
_g_typelib_init (meta); _g_typelib_init (meta);
return meta; return meta;
} }
@ -2087,28 +2050,56 @@ g_typelib_free (GTypelib *typelib)
else else
if (typelib->owns_memory) if (typelib->owns_memory)
g_free (typelib->data); g_free (typelib->data);
if (typelib->module) if (typelib->modules)
g_module_close (typelib->module); {
g_list_foreach (typelib->modules, (GFunc) g_module_close, NULL);
g_list_free (typelib->modules);
}
g_free (typelib); 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 * const gchar *
g_typelib_get_namespace(GTypelib *typelib) g_typelib_get_namespace(GTypelib *typelib)
{ {
return g_typelib_get_string (typelib, ((Header *) typelib->data)->namespace); 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;
}

View File

@ -484,7 +484,7 @@ struct _GTypelib {
gsize len; gsize len;
gboolean owns_memory; gboolean owns_memory;
GMappedFile *mfile; GMappedFile *mfile;
GModule *module; GList *modules;
}; };
DirEntry *g_typelib_get_dir_entry (GTypelib *typelib, DirEntry *g_typelib_get_dir_entry (GTypelib *typelib,