[gobject-introspection/wip/sam/multiple-girs-one-typelib] Add support for merging multiple .gir files into a single .typelib



commit 2c2fa66655538628374cdbff407308dafaa36fb3
Author: Sam Thursfield <sam afuera me uk>
Date:   Sun May 21 23:36:11 2017 +0100

    Add support for merging multiple .gir files into a single .typelib
    
    This is needed for libraries which are implemented in multiple
    languages, for example libtracker-sparql which partly C and partly Vala.
    The Vala compiler cannot generate a .gir for the C code, and
    g-ir-scanner cannot effectively scan the C code generated by `valac`
    (see https://bugzilla.gnome.org/show_bug.cgi?id=781354)
    
    Requires tests.

 girepository/girmodule.c |   34 ++++++++++++++++++
 girepository/girmodule.h |    2 +
 tools/compiler.c         |   86 ++++++++++++++++++++++++++++++++++++----------
 3 files changed, 104 insertions(+), 18 deletions(-)
---
diff --git a/girepository/girmodule.c b/girepository/girmodule.c
index 66b33fa..e166bed 100644
--- a/girepository/girmodule.c
+++ b/girepository/girmodule.c
@@ -79,6 +79,40 @@ _g_ir_module_free (GIrModule *module)
   g_slice_free (GIrModule, module);
 }
 
+void
+_g_ir_module_merge (GIrModule  *left,
+                    GIrModule *right)
+{
+  GHashTableIter iter;
+  gpointer key, value;
+
+  g_assert (strcmp (left->name, right->name) == 0);
+  g_assert (strcmp (left->version, right->version) == 0);
+  g_assert (strcmp (left->shared_library, right->shared_library) == 0);
+  g_assert (strcmp (left->c_prefix, right->c_prefix) == 0);
+
+  /* FIXME: dedup */
+  left->dependencies = g_list_concat (left->dependencies, right->dependencies);
+
+  left->entries = g_list_concat (left->entries, right->entries);
+
+  left->include_modules = g_list_concat (left->include_modules, right->include_modules);
+
+  g_hash_table_iter_init (&iter, right->aliases);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      /* FIXME: check for conflicts */
+      g_hash_table_insert (left->aliases, key, value);
+    }
+
+  g_hash_table_iter_init (&iter, right->disguised_structures);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      /* FIXME: check for conflicts */
+      g_hash_table_insert (left->disguised_structures, key, value);
+    }
+}
+
 /**
  * _g_ir_module_fatal:
  * @build: Current build
diff --git a/girepository/girmodule.h b/girepository/girmodule.h
index 7837f2c..657a0c2 100644
--- a/girepository/girmodule.h
+++ b/girepository/girmodule.h
@@ -66,6 +66,8 @@ GIrModule *_g_ir_module_new            (const gchar *name,
                                        const gchar *c_prefix);
 void       _g_ir_module_free           (GIrModule  *module);
 
+void       _g_ir_module_merge          (GIrModule  *left, GIrModule *right);
+
 void       _g_ir_module_add_include_module (GIrModule  *module,
                                           GIrModule  *include_module);
 
diff --git a/tools/compiler.c b/tools/compiler.c
index 9485761..787c5df 100644
--- a/tools/compiler.c
+++ b/tools/compiler.c
@@ -45,6 +45,71 @@ gboolean include_cwd = FALSE;
 gboolean debug = FALSE;
 gboolean verbose = FALSE;
 
+static GIrModule *
+parse_modules () {
+  GIrParser *parser;
+  GIrModule *current_module, *first_module = NULL;
+  gchar **module_filename_ptr;
+  gint i;
+  GError *error = NULL;
+
+  if (includedirs != NULL)
+    for (i = 0; includedirs[i]; i++)
+      g_irepository_prepend_search_path (includedirs[i]);
+
+  parser = _g_ir_parser_new ();
+  _g_ir_parser_set_includes (parser, (const char*const*) includedirs);
+
+  for (module_filename_ptr = input; *module_filename_ptr != NULL; module_filename_ptr ++)
+    {
+      current_module = _g_ir_parser_parse_file (parser, *module_filename_ptr, &error);
+
+      if (current_module == NULL) 
+        {
+          g_fprintf (stderr, "error parsing file %s: %s\n",
+                     *module_filename_ptr, error->message);
+          return NULL;
+        }
+
+      if (first_module == NULL)
+        {
+          first_module = current_module;
+        }
+      else
+        {
+          if (strcmp (current_module->name, first_module->name) != 0)
+            {
+              g_fprintf (stderr, "All current_modules must have the same namespace name. "
+                                 "Got %s and %s.", first_module->name, current_module->name);
+              return NULL;
+            }
+          if (strcmp (current_module->version, first_module->version) != 0)
+            {
+              g_fprintf (stderr, "All current_modules must have the same namespace version. "
+                                 "Got %s and %s.", first_module->version, current_module->version);
+              return NULL;
+            }
+          if (strcmp (current_module->shared_library, first_module->shared_library) != 0)
+            {
+              g_fprintf (stderr, "All current_modules must be in the same shared library. "
+                                 "Got %s and %s.", first_module->shared_library, 
current_module->shared_library);
+              return NULL;
+            }
+          if (strcmp (current_module->c_prefix, first_module->c_prefix) != 0)
+            {
+              g_fprintf (stderr, "All current_modules must be in the same C prefix. "
+                                 "Got %s and %s.", first_module->c_prefix, current_module->c_prefix);
+              return NULL;
+            }
+
+          _g_ir_module_merge (first_module, current_module);
+          _g_ir_module_free (current_module);
+        }
+    }
+
+  return first_module;
+};
+
 static gboolean
 write_out_typelib (gchar *prefix,
                   GITypelib *typelib)
@@ -143,9 +208,7 @@ main (int argc, char ** argv)
 {
   GOptionContext *context;
   GError *error = NULL;
-  GIrParser *parser;
   GIrModule *module;
-  gint i;
   g_typelib_check_sanity ();
 
   context = g_option_context_new ("");
@@ -181,22 +244,9 @@ main (int argc, char ** argv)
   g_debug ("[parsing] start, %d includes", 
           includedirs ? g_strv_length (includedirs) : 0);
 
-  if (includedirs != NULL)
-    for (i = 0; includedirs[i]; i++)
-      g_irepository_prepend_search_path (includedirs[i]);
-
-  parser = _g_ir_parser_new ();
-
-  _g_ir_parser_set_includes (parser, (const char*const*) includedirs);
-
-  module = _g_ir_parser_parse_file (parser, input[0], &error);
-  if (module == NULL) 
-    {
-      g_fprintf (stderr, "error parsing file %s: %s\n", 
-                input[0], error->message);
-      
-      return 1;
-    }
+  module = parse_modules ();
+  if (!module)
+    return 1;
 
   g_debug ("[parsing] done");
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]