From 9faf4b4e9eac13ceb9d8c214554d5ee2a384dc28 Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Fri, 22 Feb 2013 01:50:48 +0100 Subject: GIRepository: add API for extending library paths Previously we would require applications that shipped with private typelibs to add the private path to LD_LIBRARY_PATH, or to have a launcher binary with the right RPATH. Now they can just call GIRepository.prepend_library_path() before they access the module. https://bugzilla.gnome.org/show_bug.cgi?id=694485 --- docs/reference/gi-sections.txt | 1 + girepository/girepository.h | 1 + girepository/girepository.symbols | 1 + girepository/gitypelib.c | 91 ++++++++++++++++++++++++++++----------- 4 files changed, 70 insertions(+), 24 deletions(-) diff --git a/docs/reference/gi-sections.txt b/docs/reference/gi-sections.txt index b7565a13..8b880cf8 100644 --- a/docs/reference/gi-sections.txt +++ b/docs/reference/gi-sections.txt @@ -7,6 +7,7 @@ GIRepositoryLoadFlags GITypelib g_irepository_get_default g_irepository_prepend_search_path +g_irepository_prepend_library_path g_irepository_get_search_path g_irepository_load_typelib g_irepository_is_registered diff --git a/girepository/girepository.h b/girepository/girepository.h index eb990a27..2b2b1713 100644 --- a/girepository/girepository.h +++ b/girepository/girepository.h @@ -90,6 +90,7 @@ typedef enum GType g_irepository_get_type (void) G_GNUC_CONST; GIRepository *g_irepository_get_default (void); void g_irepository_prepend_search_path (const char *directory); +void g_irepository_prepend_library_path (const char *directory); GSList * g_irepository_get_search_path (void); const char * g_irepository_load_typelib (GIRepository *repository, GITypelib *typelib, diff --git a/girepository/girepository.symbols b/girepository/girepository.symbols index 8cb6c839..5f01adff 100644 --- a/girepository/girepository.symbols +++ b/girepository/girepository.symbols @@ -134,6 +134,7 @@ g_irepository_get_typelib_path g_irepository_get_version g_irepository_is_registered g_irepository_load_typelib +g_irepository_prepend_library_path g_irepository_prepend_search_path g_irepository_require g_irepository_require_private diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c index 2af17e96..76a55de8 100644 --- a/girepository/gitypelib.c +++ b/girepository/gitypelib.c @@ -2062,6 +2062,72 @@ g_typelib_error_quark (void) return quark; } +static GSList *library_paths; + +/** + * g_irepository_prepend_library_path: + * @directory: (type filename): a single directory to scan for shared libraries + * + * Prepends @directory to the search path that is used to + * search shared libraries referenced by imported namespaces. + * Multiple calls to this function all contribute to the final + * list of paths. + * The list of paths is unique and shared for all #GIRepository + * instances across the process, but it doesn't affect namespaces + * imported before the call. + * + * If the library is not found in the directories configured + * in this way, loading will fall back to the system library + * path (ie. LD_LIBRARY_PATH and DT_RPATH in ELF systems). + * See the documentation of your dynamic linker for full details. + * + * Since: 1.35.8 + */ +void +g_irepository_prepend_library_path (const char *directory) +{ + library_paths = g_slist_prepend (library_paths, + g_strdup (directory)); +} + +/* Note on the GModule flags used by this function: + + * Glade's autoconnect feature and OpenGL's extension mechanism + * as used by Clutter rely on g_module_open(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. + */ +static GModule * +load_one_shared_library (const char *shlib) +{ + GSList *p; + GModule *m; + + if (!g_path_is_absolute (shlib)) + { + /* First try in configured library paths */ + for (p = library_paths; p; p = p->next) + { + char *path = g_build_filename (p->data, shlib, NULL); + + m = g_module_open (path, G_MODULE_BIND_LAZY); + + g_free (path); + if (m != NULL) + return m; + } + } + + /* Then try loading from standard paths */ + /* Do not attempt to fix up shlib to replace .la with .so: + it's done by GModule anyway. + */ + return g_module_open (shlib, G_MODULE_BIND_LAZY); +} + static void _g_typelib_do_dlopen (GITypelib *typelib) { @@ -2091,30 +2157,7 @@ _g_typelib_do_dlopen (GITypelib *typelib) { GModule *module; - /* Glade's autoconnect feature and OpenGL's extension mechanism - * as used by Clutter rely on g_module_open(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]); - - 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); - } + module = load_one_shared_library (shlibs[i]); if (module == NULL) { -- cgit v1.2.1