mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-28 00:16:15 +01:00
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:
parent
ea99326529
commit
728beb0424
6
ginfo.c
6
ginfo.c
@ -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) ();
|
||||||
|
40
ginvoke.c
40
ginvoke.c
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
217
gtypelib.c
217
gtypelib.c
@ -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;
|
||||||
|
}
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user