Put dependencies in typelibs, resolve them when loading

* gir/Makefile.am: Dep on Makefile
	* girepository/ginfo.c: Print out a nicer error
	message if we failed to load something.
	* girepository/girepository.c: Clean up
	default typelib handling; remove global
	default_typelib variable.  Ensure we handle
	NULL repository in more places.
	Support dependency resolution.
	* tests/Makefile.am: Kill off gobject.gir,
	it conflicts with the real one.
	* tests/Object.gir: Depend on GObject.
	* tools/generate.c: Take --includedir
	argument to say which directories to search
	for typelibs.  Print out dependencies.

svn path=/trunk/; revision=541
This commit is contained in:
Colin Walters 2008-08-30 20:31:07 +00:00
parent 2ee1470611
commit 6e656b4498
8 changed files with 203 additions and 115 deletions

33
ginfo.c
View File

@ -174,18 +174,14 @@ g_info_from_entry (GTypelib *typelib,
result = g_irepository_find_by_name (repository, namespace, name);
if (result == NULL)
{
GIUnresolvedInfo *unresolved;
unresolved = g_new0 (GIUnresolvedInfo, 1);
unresolved->type = GI_INFO_TYPE_UNRESOLVED;
unresolved->ref_count = 1;
unresolved->container = NULL;
unresolved->name = name;
unresolved->namespace = namespace;
result = (GIBaseInfo*)unresolved;
char **all_namespaces = g_irepository_get_namespaces (repository);
char *namespaces_str = g_strjoinv (", ", all_namespaces);
g_critical ("Failed to find namespace: %s name: %s (currently loaded namespaces: %s)", namespace,
name, namespaces_str);
g_strfreev (all_namespaces);
g_free (namespaces_str);
}
return result;
}
return result;
@ -294,14 +290,6 @@ g_base_info_get_name (GIBaseInfo *info)
}
break;
case GI_INFO_TYPE_UNRESOLVED:
{
GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info;
return unresolved->name;
}
break;
case GI_INFO_TYPE_TYPE:
default: ;
g_assert_not_reached ();
@ -318,13 +306,6 @@ g_base_info_get_namespace (GIBaseInfo *info)
g_assert (info->ref_count > 0);
if (info->type == GI_INFO_TYPE_UNRESOLVED)
{
GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info;
return unresolved->namespace;
}
return g_typelib_get_string (info->typelib, header->namespace);
}

View File

@ -30,12 +30,11 @@
static GStaticMutex globals_lock = G_STATIC_MUTEX_INIT;
static GIRepository *default_repository = NULL;
static GHashTable *default_typelib = NULL;
static GSList *search_path = NULL;
struct _GIRepositoryPrivate
{
GHashTable *typelib; /* (string) namespace -> GTypelib */
GHashTable *typelibs; /* (string) namespace -> GTypelib */
};
G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT);
@ -52,7 +51,7 @@ g_irepository_finalize (GObject *object)
{
GIRepository *repository = G_IREPOSITORY (object);
g_hash_table_destroy (repository->priv->typelib);
g_hash_table_destroy (repository->priv->typelibs);
(* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository));
}
@ -77,11 +76,10 @@ init_globals ()
if (default_repository == NULL)
{
default_repository = g_object_new (G_TYPE_IREPOSITORY, NULL);
if (default_typelib == NULL)
default_typelib = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) NULL,
(GDestroyNotify) g_typelib_free);
default_repository->priv->typelib = default_typelib;
default_repository->priv->typelibs
= g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) NULL,
(GDestroyNotify) g_typelib_free);
}
if (search_path == NULL)
@ -102,6 +100,13 @@ init_globals ()
g_static_mutex_unlock (&globals_lock);
}
void
g_irepository_prepend_search_path (const char *directory)
{
init_globals ();
search_path = g_slist_prepend (search_path, g_strdup (directory));
}
static char *
build_typelib_key (const char *name, const char *source)
{
@ -111,46 +116,79 @@ build_typelib_key (const char *name, const char *source)
return g_string_free (str, FALSE);
}
static const gchar *
register_internal (GIRepository *repository,
const char *source,
GTypelib *typelib)
static char **
get_typelib_dependencies (GTypelib *typelib)
{
Header *header;
const gchar *name;
GHashTable *table;
GError *error = NULL;
g_return_val_if_fail (typelib != NULL, NULL);
const char *dependencies_glob;
header = (Header *)typelib->data;
g_return_val_if_fail (header != NULL, NULL);
if (header->dependencies == 0)
return NULL;
dependencies_glob = g_typelib_get_string (typelib, header->dependencies);
return g_strsplit (dependencies_glob, "|", 0);
}
static GIRepository *
get_repository (GIRepository *repository)
{
if (repository != NULL)
{
if (repository->priv->typelib == NULL)
repository->priv->typelib = g_hash_table_new_full (g_str_hash, g_str_equal,
if (repository->priv->typelibs == NULL)
repository->priv->typelibs = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) NULL,
(GDestroyNotify) g_typelib_free);
table = repository->priv->typelib;
return repository;
}
else
{
init_globals ();
table = default_typelib;
return default_repository;
}
}
static const char *
register_internal (GIRepository *repository,
const char *source,
GTypelib *typelib,
GError **error)
{
Header *header;
const gchar *name;
const char *dependencies_glob;
char **dependencies;
g_return_val_if_fail (typelib != NULL, FALSE);
header = (Header *)typelib->data;
g_return_val_if_fail (header != NULL, FALSE);
name = g_typelib_get_string (typelib, header->namespace);
if (g_hash_table_lookup (table, name))
dependencies = get_typelib_dependencies (typelib);
if (dependencies != NULL)
{
g_printerr ("typelib (%p) for '%s' already registered\n",
typelib, name);
return NULL;
int i;
for (i = 0; dependencies[i]; i++)
{
char *dependency = dependencies[i];
if (!g_irepository_require (repository, dependency, error))
{
g_strfreev (dependencies);
return NULL;
}
}
g_strfreev (dependencies);
}
g_hash_table_insert (table, build_typelib_key (name, source), (void *)typelib);
g_assert (g_hash_table_lookup (repository->priv->typelibs, name) == NULL);
g_hash_table_insert (repository->priv->typelibs,
build_typelib_key (name, source), (void *)typelib);
if (typelib->module == NULL)
typelib->module = g_module_open (NULL, 0);
@ -158,28 +196,47 @@ register_internal (GIRepository *repository,
return name;
}
const gchar *
g_irepository_register (GIRepository *repository,
GTypelib *typelib)
char **
g_irepository_get_dependencies (GIRepository *repository,
const char *namespace)
{
return register_internal (repository, "<builtin>", typelib);
GTypelib *typelib;
g_return_val_if_fail (namespace != NULL, NULL);
repository = get_repository (repository);
typelib = g_hash_table_lookup (repository->priv->typelibs, namespace);
g_return_val_if_fail (typelib != NULL, NULL);
return get_typelib_dependencies (typelib);
}
const char *
g_irepository_load_typelib (GIRepository *repository,
GTypelib *typelib,
GError **error)
{
Header *header;
const char *namespace;
repository = get_repository (repository);
header = (Header *) typelib->data;
namespace = g_typelib_get_string (typelib, header->namespace);
if (g_hash_table_lookup (repository->priv->typelibs, namespace))
return namespace;
return register_internal (repository, "<builtin>", typelib, error);
}
void
g_irepository_unregister (GIRepository *repository,
const gchar *namespace)
{
GHashTable *table;
repository = get_repository (repository);
if (repository != NULL)
table = repository->priv->typelib;
else
{
init_globals ();
table = default_typelib;
}
if (!g_hash_table_remove (table, namespace))
if (!g_hash_table_remove (repository->priv->typelibs, namespace))
{
g_printerr ("namespace '%s' not registered\n", namespace);
}
@ -189,24 +246,15 @@ gboolean
g_irepository_is_registered (GIRepository *repository,
const gchar *namespace)
{
GHashTable *table;
repository = get_repository (repository);
if (repository != NULL)
table = repository->priv->typelib;
else
{
init_globals ();
table = default_typelib;
}
return g_hash_table_lookup (table, namespace) != NULL;
return g_hash_table_lookup (repository->priv->typelibs, namespace) != NULL;
}
GIRepository *
g_irepository_get_default (void)
{
init_globals ();
return default_repository;
return get_repository (NULL);
}
static void
@ -225,19 +273,21 @@ g_irepository_get_n_infos (GIRepository *repository,
const gchar *namespace)
{
gint n_interfaces = 0;
repository = get_repository (repository);
if (namespace)
{
GTypelib *typelib;
typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
typelib = g_hash_table_lookup (repository->priv->typelibs, namespace);
if (typelib)
n_interfaces = ((Header *)typelib->data)->n_local_entries;
}
else
{
g_hash_table_foreach (repository->priv->typelib,
g_hash_table_foreach (repository->priv->typelibs,
count_interfaces, &n_interfaces);
}
@ -323,6 +373,8 @@ g_irepository_get_info (GIRepository *repository,
{
IfaceData data;
repository = get_repository (repository);
data.name = NULL;
data.type = NULL;
data.index = index + 1;
@ -332,13 +384,13 @@ g_irepository_get_info (GIRepository *repository,
{
GTypelib *typelib;
typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
typelib = g_hash_table_lookup (repository->priv->typelibs, namespace);
if (typelib)
find_interface ((void *)namespace, typelib, &data);
}
else
g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
g_hash_table_foreach (repository->priv->typelibs, find_interface, &data);
return data.iface;
}
@ -349,12 +401,14 @@ g_irepository_find_by_gtype (GIRepository *repository,
{
IfaceData data;
repository = get_repository (repository);
data.name = NULL;
data.type = g_type_name (type);
data.index = -1;
data.iface = NULL;
g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
g_hash_table_foreach (repository->priv->typelibs, find_interface, &data);
return data.iface;
}
@ -377,6 +431,8 @@ g_irepository_find_by_name (GIRepository *repository,
{
IfaceData data;
repository = get_repository (repository);
data.name = name;
data.type = NULL;
data.index = -1;
@ -386,13 +442,13 @@ g_irepository_find_by_name (GIRepository *repository,
{
GTypelib *typelib;
typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
typelib = g_hash_table_lookup (repository->priv->typelibs, namespace);
if (typelib)
find_interface ((void *)namespace, typelib, &data);
}
else
g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
g_hash_table_foreach (repository->priv->typelibs, find_interface, &data);
return data.iface;
}
@ -424,7 +480,9 @@ g_irepository_get_namespaces (GIRepository *repository)
gchar **names;
gint i;
g_hash_table_foreach (repository->priv->typelib, collect_namespaces, &list);
repository = get_repository (repository);
g_hash_table_foreach (repository->priv->typelibs, collect_namespaces, &list);
names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1));
i = 0;
@ -442,7 +500,9 @@ g_irepository_get_shared_library (GIRepository *repository,
GTypelib *typelib;
Header *header;
typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
repository = get_repository (repository);
typelib = g_hash_table_lookup (repository->priv->typelibs, namespace);
if (!typelib)
return NULL;
header = (Header *) typelib->data;
@ -471,7 +531,9 @@ g_irepository_get_typelib_path (GIRepository *repository,
{
gpointer orig_key, value;
if (!g_hash_table_lookup_extended (repository->priv->typelib, namespace,
repository = get_repository (repository);
if (!g_hash_table_lookup_extended (repository->priv->typelibs, namespace,
&orig_key, &value))
return NULL;
return ((char*)orig_key) + strlen ((char *) orig_key) + 1;
@ -488,9 +550,9 @@ g_irepository_get_typelib_path (GIRepository *repository,
* search for a ".typelib" file using the repository search
* path.
*
* Returns: Namespace if successful, NULL otherwise
* Returns: %TRUE if successful, %NULL otherwise
*/
const gchar *
gboolean
g_irepository_require (GIRepository *repository,
const gchar *namespace,
GError **error)
@ -506,17 +568,12 @@ g_irepository_require (GIRepository *repository,
guint32 shlib;
GHashTable *table;
if (repository != NULL)
table = repository->priv->typelib;
else
{
init_globals ();
table = default_typelib;
}
repository = get_repository (repository);
table = repository->priv->typelibs;
/* don't bother loading a namespace if already registered */
if (g_hash_table_lookup (table, namespace))
return namespace;
return TRUE;
fname = g_strconcat (namespace, ".typelib", NULL);
@ -544,7 +601,7 @@ g_irepository_require (GIRepository *repository,
"namespace '%s' which doesn't match the file name",
full_path, namespace, typelib_namespace);
g_free (full_path);
return NULL;
return FALSE;
}
break;
}
@ -556,14 +613,18 @@ g_irepository_require (GIRepository *repository,
"Typelib file for namespace '%s' was not found in search"
" path or could not be openened", namespace);
g_free (full_path);
return NULL;
return FALSE;
}
g_free (fname);
g_hash_table_remove (table, namespace);
register_internal (repository, full_path, typelib);
if (!register_internal (repository, full_path, typelib, error))
{
g_typelib_free (typelib);
g_free (full_path);
return FALSE;
}
g_free (full_path);
return namespace;
return TRUE;
}

View File

@ -72,8 +72,10 @@ struct _GIRepositoryClass
GType g_irepository_get_type (void) G_GNUC_CONST;
GIRepository *g_irepository_get_default (void);
const gchar * g_irepository_register (GIRepository *repository,
GTypelib *typelib);
void g_irepository_prepend_search_path (const char *directory);
const char * g_irepository_load_typelib (GIRepository *repository,
GTypelib *typelib,
GError **error);
void g_irepository_unregister (GIRepository *repository,
const gchar *namespace);
gboolean g_irepository_is_registered (GIRepository *repository,
@ -81,9 +83,11 @@ gboolean g_irepository_is_registered (GIRepository *repository,
GIBaseInfo * g_irepository_find_by_name (GIRepository *repository,
const gchar *namespace,
const gchar *name);
const char * g_irepository_require (GIRepository *repository,
gboolean g_irepository_require (GIRepository *repository,
const char *namespace,
GError **error);
gchar ** g_irepository_get_dependencies (GIRepository *repository,
const char *namespace);
gchar ** g_irepository_get_namespaces (GIRepository *repository);
GIBaseInfo * g_irepository_find_by_gtype (GIRepository *repository,
GType gtype);
@ -142,8 +146,7 @@ typedef enum
GI_INFO_TYPE_PROPERTY,
GI_INFO_TYPE_FIELD,
GI_INFO_TYPE_ARG,
GI_INFO_TYPE_TYPE,
GI_INFO_TYPE_UNRESOLVED
GI_INFO_TYPE_TYPE
} GIInfoType;

View File

@ -33,13 +33,14 @@ g_ir_module_new (const gchar *name, const gchar *shared_library)
{
GIrModule *module;
module = g_new (GIrModule, 1);
module = g_new0 (GIrModule, 1);
module->name = g_strdup (name);
if (shared_library)
module->shared_library = g_strdup (shared_library);
else
module->shared_library = NULL;
module->dependencies = NULL;
module->entries = NULL;
return module;
@ -56,6 +57,7 @@ g_ir_module_free (GIrModule *module)
g_ir_node_free ((GIrNode *)e->data);
g_list_free (module->entries);
/* Don't free dependencies, we inherit that from the parser */
g_free (module);
}
@ -77,18 +79,42 @@ g_ir_module_build_typelib (GIrModule *module,
guint32 size, offset, offset2, old_offset;
GHashTable *strings;
GHashTable *types;
char *dependencies;
guchar *data;
header_size = ALIGN_VALUE (sizeof (Header), 4);
n_local_entries = g_list_length (module->entries);
/* Serialize dependencies into one string; this is convenient
* and not a major change to the typelib format. */
{
GString *dependencies_str = g_string_new ("");
GList *link;
for (link = module->dependencies; link; link = link->next)
{
const char *dependency = link->data;
if (!strcmp (dependency, module->name))
continue;
g_string_append (dependencies_str, dependency);
if (link->next)
g_string_append_c (dependencies_str, '|');
}
dependencies = g_string_free (dependencies_str, FALSE);
if (!dependencies[0])
{
g_free (dependencies);
dependencies = NULL;
}
}
restart:
init_stats ();
strings = g_hash_table_new (g_str_hash, g_str_equal);
types = g_hash_table_new (g_str_hash, g_str_equal);
n_entries = g_list_length (module->entries);
g_message ("%d entries (%d local)\n", n_entries, n_local_entries);
g_message ("%d entries (%d local), %d dependencies\n", n_entries, n_local_entries,
g_list_length (module->dependencies));
dir_size = n_entries * 12;
size = header_size + dir_size;
@ -106,6 +132,8 @@ g_ir_module_build_typelib (GIrModule *module,
size += strlen (module->name);
if (module->shared_library)
size += strlen (module->shared_library);
if (dependencies != NULL)
size += strlen (dependencies);
g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n",
size, header_size, dir_size, size - header_size - dir_size);
@ -122,6 +150,10 @@ g_ir_module_build_typelib (GIrModule *module,
header->n_local_entries = n_local_entries;
header->n_annotations = 0;
header->annotations = 0; /* filled in later */
if (dependencies != NULL)
header->dependencies = write_string (dependencies, strings, data, &header_size);
else
header->dependencies = 0;
header->size = 0; /* filled in later */
header->namespace = write_string (module->name, strings, data, &header_size);
header->shared_library = (module->shared_library?
@ -180,9 +212,11 @@ g_ir_module_build_typelib (GIrModule *module,
if (node->type == G_IR_NODE_XREF)
{
const char *namespace = ((GIrNodeXRef*)node)->namespace;
entry->blob_type = 0;
entry->local = FALSE;
entry->offset = write_string (((GIrNodeXRef*)node)->namespace, strings, data, &offset2);
entry->offset = write_string (namespace, strings, data, &offset2);
entry->name = write_string (node->name, strings, data, &offset2);
}
else

View File

@ -33,6 +33,7 @@ struct _GIrModule
{
gchar *name;
gchar *shared_library;
GList *dependencies;
GList *entries;
};

View File

@ -72,6 +72,7 @@ struct _ParseContext
GList *modules;
gboolean prefix_aliases;
GList *dependencies;
GHashTable *aliases;
const char *namespace;
@ -2188,6 +2189,9 @@ start_element_handler (GMarkupParseContext *context,
if (!parse_include (context, ctx, name, error))
break;
ctx->dependencies = g_list_prepend (ctx->dependencies, g_strdup (name));
state_switch (ctx, STATE_INCLUDE);
goto out;
}
@ -2226,6 +2230,7 @@ start_element_handler (GMarkupParseContext *context,
{
ctx->current_module = g_ir_module_new (name, shared_library);
ctx->modules = g_list_append (ctx->modules, ctx->current_module);
ctx->current_module->dependencies = ctx->dependencies;
state_switch (ctx, STATE_NAMESPACE);
goto out;
@ -2704,6 +2709,7 @@ g_ir_parse_string (const gchar *namespace,
ctx.namespace = namespace;
ctx.aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
ctx.type_depth = 0;
ctx.dependencies = NULL;
ctx.current_module = NULL;
context = g_markup_parse_context_new (&firstpass_parser, 0, &ctx, NULL);

View File

@ -152,7 +152,7 @@ g_typelib_check_sanity (void)
size_check_ok = FALSE; \
}
CHECK_SIZE (Header, 100);
CHECK_SIZE (Header, 104);
CHECK_SIZE (DirEntry, 12);
CHECK_SIZE (SimpleTypeBlob, 4);
CHECK_SIZE (ArgBlob, 12);

View File

@ -57,6 +57,8 @@ typedef struct
guint32 n_annotations;
guint32 annotations;
guint32 dependencies;
guint32 size;
guint32 namespace;
guint32 shared_library;