Bug 572075 - Make the scanner work with static and convenience libraries
authorOwen W. Taylor <otaylor@fishsoup.net>
Mon, 16 Feb 2009 21:52:52 +0000 (16:52 -0500)
committerOwen W. Taylor <otaylor@fishsoup.net>
Thu, 19 Feb 2009 17:05:10 +0000 (12:05 -0500)
We need to reference the get_type() functions we are going to dlsym
or otherwise the linker may not include them in the introspection
binary.

giscanner/dumper.py: Accept a list of _get_type() functions
  and write an array referencing them into the introspection
  binary.
giscanner/glibtransformer.py: Break parsing into too stages -
 the stage where we compute the _get_type() functions and the
 stage where we invoke the introspection binary.
tools/g-ir-scanner: Pass _get_type() functions from the
 scanner when creating the introspection binary.

http://bugzilla.gnome.org/show_bug.cgi?id=572075

giscanner/dumper.py
giscanner/glibtransformer.py
tools/g-ir-scanner

index 6b78568..e487c12 100644 (file)
@@ -73,8 +73,9 @@ class LinkerError(Exception):
 
 class DumpCompiler(object):
 
-    def __init__(self, options):
+    def __init__(self, options, get_type_functions):
         self._options = options
+        self._get_type_functions = get_type_functions
         self._tmpdir = tempfile.mkdtemp('', 'tmp-introspect')
 
         self._compiler_cmd = os.environ.get('CC', 'gcc')
@@ -93,6 +94,22 @@ class DumpCompiler(object):
         c_path = self._generate_tempfile('.c')
         f = open(c_path, 'w')
         f.write(_PROGRAM_TEMPLATE)
+
+        # We need to reference our get_type functions to make sure they are
+        # pulled in at the linking stage if the library is a static library
+        # rather than a shared library.
+        for func in self._get_type_functions:
+            f.write("extern GType " + func + "(void);\n")
+        f.write("GType (*GI_GET_TYPE_FUNCS_[])(void) = {\n")
+        first = True
+        for func in self._get_type_functions:
+            if first:
+                first = False
+            else:
+                f.write(",\n")
+            f.write("  " + func)
+        f.write("\n};\n")
+
         f.close()
 
         o_path = self._generate_tempfile('.o')
@@ -208,6 +225,6 @@ class DumpCompiler(object):
         subprocess.check_call(args)
 
 
-def compile_introspection_binary(options):
-    dc = DumpCompiler(options)
+def compile_introspection_binary(options, get_type_functions):
+    dc = DumpCompiler(options, get_type_functions)
     return dc.run()
index f05ce65..c39ce64 100644 (file)
@@ -99,9 +99,6 @@ class GLibTransformer(object):
 
     # Public API
 
-    def set_introspection_binary(self, binary):
-        self._binary = binary
-
     def _print_statistics(self):
         nodes = list(self._names.names.itervalues())
 
@@ -114,9 +111,16 @@ class GLibTransformer(object):
         print " %d nodes; %d objects, %d interfaces, %d enums" \
             % (len(nodes), objectcount, ifacecount, enumcount)
 
-    def parse(self):
+    def init_parse(self):
+        """Do parsing steps that don't involve the introspection binary
+
+        This does enough work that get_type_functions() can be called.
+
+        """
+
         namespace = self._transformer.parse()
         self._namespace_name = namespace.name
+        self._namespace_version = namespace.version
 
         # First pass: parsing
         for node in namespace.nodes:
@@ -127,6 +131,15 @@ class GLibTransformer(object):
         if namespace.name == 'GObject':
             del self._names.aliases['Type']
 
+    def get_get_type_functions(self):
+        return self._get_type_functions
+
+    def set_introspection_binary(self, binary):
+        self._binary = binary
+
+    def parse(self):
+        """Do remaining parsing steps requiring introspection binary"""
+
         # Get all the GObject data by passing our list of get_type
         # functions to the compiled binary
 
@@ -158,7 +171,7 @@ class GLibTransformer(object):
             self._validate(nodes)
 
         # Create a new namespace with what we found
-        namespace = Namespace(namespace.name, namespace.version)
+        namespace = Namespace(self._namespace_name, self._namespace_version)
         namespace.nodes = map(lambda x: x[1], self._names.aliases.itervalues())
         for (ns, x) in self._names.names.itervalues():
             namespace.nodes.append(x)
index 0cf54ce..f53f7fc 100755 (executable)
@@ -316,17 +316,23 @@ def main(args):
     # Transform the C symbols into AST nodes
     transformer.set_source_ast(ss)
 
+    # Transform the C AST nodes into higher level
+    # GLib/GObject nodes
+    glibtransformer = GLibTransformer(transformer,
+                                      noclosure=options.noclosure)
+
+    # Do enough parsing that we have the get_type() functions to reference
+    # when creating the introspection binary
+    glibtransformer.init_parse()
+
     if options.program:
         args=[options.program]
         args.extend(options.program_args)
         binary = IntrospectionBinary(args)
     else:
-        binary = compile_introspection_binary(options)
+        binary = compile_introspection_binary(options,
+                                              glibtransformer.get_get_type_functions())
 
-    # Transform the C AST nodes into higher level
-    # GLib/GObject nodes
-    glibtransformer = GLibTransformer(transformer,
-                                      noclosure=options.noclosure)
     glibtransformer.set_introspection_binary(binary)
 
     namespace = glibtransformer.parse()