diff --git a/girepository/girepository.c b/girepository/girepository.c index 16118f341..f216f6cc4 100644 --- a/girepository/girepository.c +++ b/girepository/girepository.c @@ -59,10 +59,10 @@ * standard Linux system this will end up being `/usr/lib/girepository-1.0`. * * It is possible to control the search paths programmatically, using - * [func@GIRepository.Repository.prepend_search_path]. It is also possible to + * [method@GIRepository.Repository.prepend_search_path]. It is also possible to * modify the search paths by using the `GI_TYPELIB_PATH` environment variable. * The environment variable takes precedence over the default search path - * and the [func@GIRepository.Repository.prepend_search_path] calls. + * and the [method@GIRepository.Repository.prepend_search_path] calls. * * Since: 2.80 */ @@ -76,8 +76,6 @@ GIREPOSITORY_TYPELIB_NAME "-" GIREPOSITORY_TYPELIB_VERSION ".typelib" static GIRepository *default_repository = NULL; -static GPtrArray *typelib_search_path = NULL; -static GPtrArray *library_paths = NULL; /* (element-type filename) (owned) */ typedef struct { size_t n_interfaces; @@ -98,6 +96,9 @@ struct _GIRepository { GObject parent; + GPtrArray *typelib_search_path; /* (element-type filename) (owned) */ + GPtrArray *library_paths; /* (element-type filename) (owned) */ + GHashTable *typelibs; /* (string) namespace -> GITypelib */ GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */ GHashTable *info_by_gtype; /* GType -> GIBaseInfo */ @@ -149,6 +150,40 @@ DllMain (HINSTANCE hinstDLL, static void gi_repository_init (GIRepository *repository) { + /* typelib search path */ + { + const char *libdir; + char *typelib_dir; + const char *type_lib_path_env; + + /* This variable is intended to take precedence over both: + * - the default search path; + * - all gi_repository_prepend_search_path() calls. + */ + type_lib_path_env = g_getenv ("GI_TYPELIB_PATH"); + + if (type_lib_path_env) + { + char **custom_dirs; + + custom_dirs = g_strsplit (type_lib_path_env, G_SEARCHPATH_SEPARATOR_S, 0); + repository->typelib_search_path = + g_ptr_array_new_take_null_terminated ((gpointer) g_steal_pointer (&custom_dirs), g_free); + } + else + { + repository->typelib_search_path = g_ptr_array_new_null_terminated (1, g_free, TRUE); + } + + libdir = GOBJECT_INTROSPECTION_LIBDIR; + + typelib_dir = g_build_filename (libdir, "girepository-1.0", NULL); + + g_ptr_array_add (repository->typelib_search_path, g_steal_pointer (&typelib_dir)); + } + + repository->library_paths = g_ptr_array_new_null_terminated (1, g_free, TRUE); + repository->typelibs = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, @@ -186,6 +221,9 @@ gi_repository_finalize (GObject *object) g_clear_pointer (&repository->cached_shared_libraries, g_strfreev); + g_clear_pointer (&repository->library_paths, g_ptr_array_unref); + g_clear_pointer (&repository->typelib_search_path, g_ptr_array_unref); + (* G_OBJECT_CLASS (gi_repository_parent_class)->finalize) (G_OBJECT (repository)); } @@ -210,41 +248,6 @@ init_globals (void) if (default_repository == NULL) default_repository = gi_repository_new (); - if (typelib_search_path == NULL) - { - const char *libdir; - char *typelib_dir; - const char *type_lib_path_env; - - /* This variable is intended to take precedence over both: - * - the default search path; - * - all gi_repository_prepend_search_path() calls. - */ - type_lib_path_env = g_getenv ("GI_TYPELIB_PATH"); - - if (type_lib_path_env) - { - char **custom_dirs; - - custom_dirs = g_strsplit (type_lib_path_env, G_SEARCHPATH_SEPARATOR_S, 0); - typelib_search_path = - g_ptr_array_new_take_null_terminated ((gpointer) g_steal_pointer (&custom_dirs), g_free); - } - else - { - typelib_search_path = g_ptr_array_new_null_terminated (1, g_free, TRUE); - } - - libdir = GOBJECT_INTROSPECTION_LIBDIR; - - typelib_dir = g_build_filename (libdir, "girepository-1.0", NULL); - - g_ptr_array_add (typelib_search_path, g_steal_pointer (&typelib_dir)); - } - - if (library_paths == NULL) - library_paths = g_ptr_array_new_null_terminated (1, g_free, TRUE); - g_once_init_leave (&initialized, 1); } @@ -261,6 +264,8 @@ get_repository (GIRepository *repository) /** * gi_repository_prepend_search_path: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository * @directory: (type filename): directory name to prepend to the typelib * search path * @@ -271,14 +276,18 @@ get_repository (GIRepository *repository) * Since: 2.80 */ void -gi_repository_prepend_search_path (const char *directory) +gi_repository_prepend_search_path (GIRepository *repository, + const char *directory) { init_globals (); - g_ptr_array_insert (typelib_search_path, 0, g_strdup (directory)); + repository = get_repository (repository); + g_ptr_array_insert (repository->typelib_search_path, 0, g_strdup (directory)); } /** * gi_repository_get_search_path: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository * @n_paths_out: (optional) (out): The number of search paths returned. * * Returns the current search path [class@GIRepository.Repository] will use when @@ -292,9 +301,13 @@ gi_repository_prepend_search_path (const char *directory) * Since: 2.80 */ const char * const * -gi_repository_get_search_path (size_t *n_paths_out) +gi_repository_get_search_path (GIRepository *repository, + size_t *n_paths_out) { - if G_UNLIKELY (!typelib_search_path || !typelib_search_path->pdata) + repository = get_repository (repository); + + if G_UNLIKELY (!repository->typelib_search_path || + !repository->typelib_search_path->pdata) { static const char * const empty_search_path[] = {NULL}; @@ -305,13 +318,15 @@ gi_repository_get_search_path (size_t *n_paths_out) } if (n_paths_out) - *n_paths_out = typelib_search_path->len; + *n_paths_out = repository->typelib_search_path->len; - return (const char * const *) typelib_search_path->pdata; + return (const char * const *) repository->typelib_search_path->pdata; } /** * gi_repository_prepend_library_path: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository * @directory: (type filename): a single directory to scan for shared libraries * * Prepends @directory to the search path that is used to @@ -320,9 +335,9 @@ gi_repository_get_search_path (size_t *n_paths_out) * Multiple calls to this function all contribute to the final * list of paths. * - * The list of paths is unique and shared for all - * [class@GIRepository.Repository] instances across the process, but it doesn’t - * affect namespaces imported before the call. + * The list of paths is unique to @repository. When a typelib is loaded by the + * repository, the list of paths from the @repository at that instant is used + * by the typelib for loading its modules. * * If the library is not found in the directories configured * in this way, loading will fall back to the system library @@ -332,14 +347,18 @@ gi_repository_get_search_path (size_t *n_paths_out) * Since: 2.80 */ void -gi_repository_prepend_library_path (const char *directory) +gi_repository_prepend_library_path (GIRepository *repository, + const char *directory) { init_globals (); - g_ptr_array_insert (library_paths, 0, g_strdup (directory)); + repository = get_repository (repository); + g_ptr_array_insert (repository->library_paths, 0, g_strdup (directory)); } /** * gi_repository_get_library_path: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository * @n_paths_out: (optional) (out): The number of library paths returned. * * Returns the current search path [class@GIRepository.Repository] will use when @@ -353,9 +372,12 @@ gi_repository_prepend_library_path (const char *directory) * Since: 2.80 */ const char * const * -gi_repository_get_library_path (size_t *n_paths_out) +gi_repository_get_library_path (GIRepository *repository, + size_t *n_paths_out) { - if G_UNLIKELY (!library_paths || !library_paths->pdata) + repository = get_repository (repository); + + if G_UNLIKELY (!repository->library_paths || !repository->library_paths->pdata) { static const char * const empty_search_path[] = {NULL}; @@ -366,9 +388,9 @@ gi_repository_get_library_path (size_t *n_paths_out) } if (n_paths_out) - *n_paths_out = library_paths->len; + *n_paths_out = repository->library_paths->len; - return (const char * const *) library_paths->pdata; + return (const char * const *) repository->library_paths->pdata; } static char * @@ -1714,8 +1736,8 @@ gi_repository_enumerate_versions (GIRepository *repository, init_globals (); candidates = enumerate_namespace_versions (namespace_, - (const char * const *) typelib_search_path->pdata, - typelib_search_path->len); + (const char * const *) repository->typelib_search_path->pdata, + repository->typelib_search_path->len); if (!candidates) { @@ -1833,6 +1855,8 @@ require_internal (GIRepository *repository, g_clear_error (&temp_error); goto out; } + + typelib->library_paths = (repository->library_paths != NULL) ? g_ptr_array_ref (repository->library_paths) : NULL; } header = (Header *) typelib->data; typelib_namespace = gi_typelib_get_string (typelib, header->namespace); @@ -1903,8 +1927,8 @@ gi_repository_require (GIRepository *repository, init_globals (); typelib = require_internal (repository, namespace, version, flags, - (const char * const *) typelib_search_path->pdata, - typelib_search_path->len, error); + (const char * const *) repository->typelib_search_path->pdata, + repository->typelib_search_path->len, error); return typelib; } diff --git a/girepository/girepository.h b/girepository/girepository.h index c6feeee65..9f05f6ae5 100644 --- a/girepository/girepository.h +++ b/girepository/girepository.h @@ -83,16 +83,20 @@ GI_AVAILABLE_IN_ALL GIRepository *gi_repository_new (void); GI_AVAILABLE_IN_ALL -void gi_repository_prepend_search_path (const char *directory); +void gi_repository_prepend_search_path (GIRepository *repository, + const char *directory); GI_AVAILABLE_IN_ALL -void gi_repository_prepend_library_path (const char *directory); +void gi_repository_prepend_library_path (GIRepository *repository, + const char *directory); GI_AVAILABLE_IN_ALL -const char * const * gi_repository_get_search_path (size_t *n_paths_out); +const char * const * gi_repository_get_search_path (GIRepository *repository, + size_t *n_paths_out); GI_AVAILABLE_IN_ALL -const char * const *gi_repository_get_library_path (size_t *n_paths_out); +const char * const *gi_repository_get_library_path (GIRepository *repository, + size_t *n_paths_out); GI_AVAILABLE_IN_ALL const char * gi_repository_load_typelib (GIRepository *repository, diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h index 271a17967..2639c0e1f 100644 --- a/girepository/gitypelib-internal.h +++ b/girepository/gitypelib-internal.h @@ -1318,6 +1318,7 @@ struct _GITypelib { GBytes *bytes; /* (owned) */ GList *modules; gboolean open_attempted; + GPtrArray *library_paths; /* (element-type filename) (owned) (nullable) */ }; DirEntry *gi_typelib_get_dir_entry (GITypelib *typelib, diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c index 66a4d2ec8..b47c1015f 100644 --- a/girepository/gitypelib.c +++ b/girepository/gitypelib.c @@ -2224,7 +2224,8 @@ gi_typelib_error_quark (void) * load modules globally for now. */ static GModule * -load_one_shared_library (const char *shlib) +load_one_shared_library (GITypelib *typelib, + const char *shlib) { GModule *m; @@ -2241,11 +2242,9 @@ load_one_shared_library (const char *shlib) #endif { /* First try in configured library paths */ - const char * const *library_paths = gi_repository_get_library_path (NULL); - - for (unsigned int i = 0; library_paths[i] != NULL; i++) + for (unsigned int i = 0; typelib->library_paths != NULL && i < typelib->library_paths->len; i++) { - char *path = g_build_filename (library_paths[i], shlib, NULL); + char *path = g_build_filename (typelib->library_paths->pdata[i], shlib, NULL); m = g_module_open (path, G_MODULE_BIND_LAZY); @@ -2290,7 +2289,7 @@ gi_typelib_do_dlopen (GITypelib *typelib) { GModule *module; - module = load_one_shared_library (shlibs[i]); + module = load_one_shared_library (typelib, shlibs[i]); if (module == NULL) { @@ -2375,6 +2374,8 @@ gi_typelib_free (GITypelib *typelib) { g_clear_pointer (&typelib->bytes, g_bytes_unref); + g_clear_pointer (&typelib->library_paths, g_ptr_array_unref); + if (typelib->modules) { g_list_foreach (typelib->modules, (GFunc) (void *) g_module_close, NULL); diff --git a/girepository/tests/repository-search-paths.c b/girepository/tests/repository-search-paths.c index c1bc6723b..e8e7c8b21 100644 --- a/girepository/tests/repository-search-paths.c +++ b/girepository/tests/repository-search-paths.c @@ -22,35 +22,22 @@ #include "glib.h" #include "girepository.h" -/* Keep this test first, not to add search paths to other tests */ -static void -test_repository_search_paths_unset (void) -{ - const char * const *search_paths; - size_t n_search_paths; - - search_paths = gi_repository_get_search_path (&n_search_paths); - g_assert_nonnull (search_paths); - g_assert_cmpstrv (search_paths, ((char *[]){NULL})); - g_assert_cmpuint (n_search_paths, ==, 0); - - search_paths = gi_repository_get_search_path (NULL); - g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 0); -} - static void test_repository_search_paths_default (void) { const char * const *search_paths; size_t n_search_paths; + GIRepository *repository = NULL; - search_paths = gi_repository_get_search_path (&n_search_paths); + repository = gi_repository_new (); + + search_paths = gi_repository_get_search_path (repository, &n_search_paths); g_assert_nonnull (search_paths); /* Init default paths */ g_assert_nonnull (gi_repository_get_default ()); - search_paths = gi_repository_get_search_path (&n_search_paths); + search_paths = gi_repository_get_search_path (repository, &n_search_paths); g_assert_nonnull (search_paths); g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 2); @@ -61,6 +48,8 @@ test_repository_search_paths_default (void) g_assert_cmpstr (search_paths[1], ==, expected_path); g_clear_pointer (&expected_path, g_free); #endif + + g_clear_object (&repository); } static void @@ -68,9 +57,12 @@ test_repository_search_paths_prepend (void) { const char * const *search_paths; size_t n_search_paths; + GIRepository *repository = NULL; - gi_repository_prepend_search_path (g_test_get_dir (G_TEST_BUILT)); - search_paths = gi_repository_get_search_path (&n_search_paths); + repository = gi_repository_new (); + + gi_repository_prepend_search_path (repository, g_test_get_dir (G_TEST_BUILT)); + search_paths = gi_repository_get_search_path (repository, &n_search_paths); g_assert_nonnull (search_paths); g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 3); @@ -83,8 +75,8 @@ test_repository_search_paths_prepend (void) g_clear_pointer (&expected_path, g_free); #endif - gi_repository_prepend_search_path (g_test_get_dir (G_TEST_DIST)); - search_paths = gi_repository_get_search_path (&n_search_paths); + gi_repository_prepend_search_path (repository, g_test_get_dir (G_TEST_DIST)); + search_paths = gi_repository_get_search_path (repository, &n_search_paths); g_assert_nonnull (search_paths); g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 4); @@ -97,6 +89,8 @@ test_repository_search_paths_prepend (void) g_assert_cmpstr (search_paths[3], ==, expected_path); g_clear_pointer (&expected_path, g_free); #endif + + g_clear_object (&repository); } static void @@ -104,10 +98,15 @@ test_repository_library_paths_default (void) { const char * const *library_paths; size_t n_library_paths; + GIRepository *repository = NULL; - library_paths = gi_repository_get_library_path (&n_library_paths); + repository = gi_repository_new (); + + library_paths = gi_repository_get_library_path (repository, &n_library_paths); g_assert_nonnull (library_paths); g_assert_cmpuint (g_strv_length ((char **) library_paths), ==, 0); + + g_clear_object (&repository); } static void @@ -115,21 +114,26 @@ test_repository_library_paths_prepend (void) { const char * const *library_paths; size_t n_library_paths; + GIRepository *repository = NULL; - gi_repository_prepend_library_path (g_test_get_dir (G_TEST_BUILT)); - library_paths = gi_repository_get_library_path (&n_library_paths); + repository = gi_repository_new (); + + gi_repository_prepend_library_path (repository, g_test_get_dir (G_TEST_BUILT)); + library_paths = gi_repository_get_library_path (repository, &n_library_paths); g_assert_nonnull (library_paths); g_assert_cmpuint (g_strv_length ((char **) library_paths), ==, 1); g_assert_cmpstr (library_paths[0], ==, g_test_get_dir (G_TEST_BUILT)); - gi_repository_prepend_library_path (g_test_get_dir (G_TEST_DIST)); - library_paths = gi_repository_get_library_path (&n_library_paths); + gi_repository_prepend_library_path (repository, g_test_get_dir (G_TEST_DIST)); + library_paths = gi_repository_get_library_path (repository, &n_library_paths); g_assert_nonnull (library_paths); g_assert_cmpuint (g_strv_length ((char **) library_paths), ==, 2); g_assert_cmpstr (library_paths[0], ==, g_test_get_dir (G_TEST_DIST)); g_assert_cmpstr (library_paths[1], ==, g_test_get_dir (G_TEST_BUILT)); + + g_clear_object (&repository); } int @@ -142,7 +146,6 @@ main (int argc, g_setenv ("GI_TYPELIB_PATH", g_get_tmp_dir (), TRUE); g_setenv ("GI_GIR_PATH", g_get_user_cache_dir (), TRUE); - g_test_add_func ("/repository/search-paths/unset", test_repository_search_paths_unset); g_test_add_func ("/repository/search-paths/default", test_repository_search_paths_default); g_test_add_func ("/repository/search-paths/prepend", test_repository_search_paths_prepend); g_test_add_func ("/repository/library-paths/default", test_repository_library_paths_default); diff --git a/girepository/tests/repository.c b/girepository/tests/repository.c index beb84a5c0..f8d8c3085 100644 --- a/girepository/tests/repository.c +++ b/girepository/tests/repository.c @@ -59,7 +59,7 @@ test_repository_basic (RepositoryFixture *fx, g_assert_cmpstrv (versions, ((char *[]){"2.0", NULL})); g_clear_pointer (&versions, g_strfreev); - search_paths = gi_repository_get_search_path (NULL); + search_paths = gi_repository_get_search_path (fx->repository, NULL); g_assert_nonnull (search_paths); g_assert_cmpuint (g_strv_length ((char **) search_paths), >, 0); g_assert_cmpstr (search_paths[0], ==, fx->gobject_typelib_dir); diff --git a/girepository/tests/test-common.c b/girepository/tests/test-common.c index b6edc07f8..08c3424e7 100644 --- a/girepository/tests/test-common.c +++ b/girepository/tests/test-common.c @@ -43,13 +43,13 @@ repository_setup (RepositoryFixture *fx, GError *local_error = NULL; TypelibLoadSpec *load_spec = (TypelibLoadSpec *) data; - fx->gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); - g_test_message ("Using GI_TYPELIB_DIR = %s", fx->gobject_typelib_dir); - gi_repository_prepend_search_path (fx->gobject_typelib_dir); - fx->repository = gi_repository_new (); g_assert_nonnull (fx->repository); + fx->gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); + g_test_message ("Using GI_TYPELIB_DIR = %s", fx->gobject_typelib_dir); + gi_repository_prepend_search_path (fx->repository, fx->gobject_typelib_dir); + if (load_spec) { typelib = gi_repository_require (fx->repository, load_spec->name, load_spec->version, 0, &local_error);