diff options
-rw-r--r-- | gir/Makefile.am | 1 | ||||
-rw-r--r-- | girepository/girparser.c | 60 | ||||
-rw-r--r-- | giscanner/girparser.py | 10 | ||||
-rw-r--r-- | giscanner/girwriter.py | 19 | ||||
-rw-r--r-- | giscanner/transformer.py | 19 | ||||
-rw-r--r-- | tests/scanner/BarApp-1.0-expected.gir | 1 | ||||
-rw-r--r-- | tests/scanner/GtkFrob-1.0-expected.gir | 1 | ||||
-rw-r--r-- | tests/scanner/annotation-1.0-expected.gir | 1 | ||||
-rw-r--r-- | tests/scanner/drawable-1.0-expected.gir | 1 | ||||
-rw-r--r-- | tests/scanner/foo-1.0-expected.gir | 1 | ||||
-rw-r--r-- | tests/scanner/utility-1.0-expected.gir | 1 | ||||
-rwxr-xr-x | tools/g-ir-scanner | 95 |
12 files changed, 138 insertions, 72 deletions
diff --git a/gir/Makefile.am b/gir/Makefile.am index 1adccd5a..f74de6d0 100644 --- a/gir/Makefile.am +++ b/gir/Makefile.am @@ -33,6 +33,7 @@ GLib-2.0.gir: $(SCANNER_BIN) $(SCANNER_LIBS) Makefile glib-2.0.c --strip-prefix=g \ --libtool="$(LIBTOOL)" \ --library=$(GLIB_LIBRARY) \ + --pkg glib-2.0 \ $(CPPFLAGS) \ -I$(GLIB_INCLUDEDIR) \ -I$(GLIB_LIBDIR)/glib-2.0/include \ diff --git a/girepository/girparser.c b/girepository/girparser.c index 97e3a1e0..fe2f7627 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -36,34 +36,35 @@ struct _GIrParser typedef enum { - STATE_START, - STATE_END, - STATE_REPOSITORY, - STATE_INCLUDE, - STATE_NAMESPACE, - STATE_ENUM, /* 5 */ - STATE_BITFIELD, - STATE_FUNCTION, - STATE_FUNCTION_RETURN, - STATE_FUNCTION_PARAMETERS, - STATE_FUNCTION_PARAMETER, /* 10 */ - STATE_CLASS, + STATE_START, + STATE_END, + STATE_REPOSITORY, + STATE_INCLUDE, + STATE_PACKAGE, + STATE_NAMESPACE, /* 5 */ + STATE_ENUM, + STATE_BITFIELD, + STATE_FUNCTION, + STATE_FUNCTION_RETURN, + STATE_FUNCTION_PARAMETERS, /* 10 */ + STATE_FUNCTION_PARAMETER, + STATE_CLASS, STATE_CLASS_FIELD, STATE_CLASS_PROPERTY, - STATE_INTERFACE, - STATE_INTERFACE_PROPERTY, /* 15 */ + STATE_INTERFACE, /* 15 */ + STATE_INTERFACE_PROPERTY, STATE_INTERFACE_FIELD, - STATE_IMPLEMENTS, + STATE_IMPLEMENTS, STATE_PREREQUISITE, - STATE_BOXED, - STATE_BOXED_FIELD, /* 20 */ - STATE_STRUCT, + STATE_BOXED, /* 20 */ + STATE_BOXED_FIELD, + STATE_STRUCT, STATE_STRUCT_FIELD, - STATE_ERRORDOMAIN, - STATE_UNION, - STATE_UNION_FIELD, /* 25 */ - STATE_NAMESPACE_CONSTANT, - STATE_CLASS_CONSTANT, + STATE_ERRORDOMAIN, + STATE_UNION, /* 25 */ + STATE_UNION_FIELD, + STATE_NAMESPACE_CONSTANT, + STATE_CLASS_CONSTANT, STATE_INTERFACE_CONSTANT, STATE_ALIAS, STATE_TYPE, @@ -2584,6 +2585,12 @@ start_element_handler (GMarkupParseContext *context, } goto out; } + else if (strcmp (element_name, "package") == 0 && + ctx->state == STATE_REPOSITORY) + { + state_switch (ctx, STATE_PACKAGE); + goto out; + } break; case 'r': @@ -2773,6 +2780,13 @@ end_element_handler (GMarkupParseContext *context, state_switch (ctx, STATE_REPOSITORY); } break; + + case STATE_PACKAGE: + if (require_end_element (context, ctx, "package", element_name, error)) + { + state_switch (ctx, STATE_REPOSITORY); + } + break; case STATE_NAMESPACE: if (require_end_element (context, ctx, "namespace", element_name, error)) diff --git a/giscanner/girparser.py b/giscanner/girparser.py index 3e2432ed..62db3e98 100644 --- a/giscanner/girparser.py +++ b/giscanner/girparser.py @@ -50,6 +50,7 @@ class GIRParser(object): self._include_parsing = False self._shared_libraries = [] self._includes = set() + self._pkgconfig_packages = set() self._namespace = None # Public API @@ -62,6 +63,7 @@ class GIRParser(object): self._includes.clear() self._namespace = None self._shared_libraries = [] + self._pkgconfig_packages = set() self._parse_api(tree.getroot()) def get_namespace(self): @@ -73,6 +75,9 @@ class GIRParser(object): def get_includes(self): return self._includes + def get_pkgconfig_packages(self): + return self._pkgconfig_packages + def get_doc(self): return parse(self._filename) @@ -89,6 +94,8 @@ class GIRParser(object): for node in root.getchildren(): if node.tag == _corens('include'): self._parse_include(node) + elif node.tag == _corens('package'): + self._parse_pkgconfig_package(node) ns = root.find(_corens('namespace')) assert ns is not None @@ -122,6 +129,9 @@ class GIRParser(object): node.attrib['version']) self._includes.add(include) + def _parse_pkgconfig_package(self, node): + self._pkgconfig_packages.add(node.attrib['name']) + def _parse_alias(self, node): alias = Alias(node.attrib['name'], node.attrib['target'], diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index 657063e6..35c9b35e 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -33,15 +33,20 @@ from .xmlwriter import XMLWriter class GIRWriter(XMLWriter): - def __init__(self, namespace, shlibs, includes): + def __init__(self, namespace, shlibs, includes, pkgs): super(GIRWriter, self).__init__() self.write_comment( '''This file was automatically generated from C sources - DO NOT EDIT! To affect the contents of this file, edit the original C definitions, and/or use gtk-doc annotations. ''') - self._write_repository(namespace, shlibs, includes) - - def _write_repository(self, namespace, shlibs, includes=set()): + self._write_repository(namespace, shlibs, includes, pkgs) + + def _write_repository(self, namespace, shlibs, includes=None, + packages=None): + if includes is None: + includes = frozenset() + if packages is None: + packages = frozenset() attrs = [ ('version', '1.0'), ('xmlns', 'http://www.gtk.org/introspection/core/1.0'), @@ -51,12 +56,18 @@ and/or use gtk-doc annotations. ''') with self.tagcontext('repository', attrs): for include in sorted(includes): self._write_include(include) + for pkg in sorted(set(packages)): + self._write_pkgconfig_pkg(pkg) self._write_namespace(namespace, shlibs) def _write_include(self, include): attrs = [('name', include.name), ('version', include.version)] self.write_tag('include', attrs) + def _write_pkgconfig_pkg(self, package): + attrs = [('name', package)] + self.write_tag('package', attrs) + def _write_namespace(self, namespace, shlibs): libraries = [] for l in shlibs: diff --git a/giscanner/transformer.py b/giscanner/transformer.py index f6e89ce1..6f9207a1 100644 --- a/giscanner/transformer.py +++ b/giscanner/transformer.py @@ -63,12 +63,12 @@ class Names(object): class Transformer(object): - def __init__(self, cachestore, generator, - namespace_name, namespace_version): + def __init__(self, cachestore, namespace_name, namespace_version): self._cachestore = cachestore - self.generator = generator + self.generator = None self._namespace = Namespace(namespace_name, namespace_version) self._names = Names() + self._pkg_config_packages = set() self._typedefs_ns = {} self._strip_prefix = '' self._includes = set() @@ -83,6 +83,12 @@ class Transformer(object): def set_strip_prefix(self, strip_prefix): self._strip_prefix = strip_prefix + def get_pkgconfig_packages(self): + return self._pkg_config_packages + + def set_source_ast(self, src_ast): + self.generator = src_ast + def parse(self): nodes = [] for symbol in self.generator.get_symbols(): @@ -115,9 +121,8 @@ class Transformer(object): path = os.path.join(d, girname) if os.path.exists(path): return path - else: - raise ValueError("Couldn't find include %r (search path: %r)"\ - % (girname, searchdirs)) + raise ValueError("Couldn't find include %r (search path: %r)"\ + % (girname, searchdirs)) def _parse_include(self, filename): parser = self._cachestore.load(filename) @@ -130,6 +135,8 @@ class Transformer(object): for include in parser.get_includes(): self.register_include(include) + for pkg in parser.get_pkgconfig_packages(): + self._pkg_config_packages.add(pkg) namespace = parser.get_namespace() nsname = namespace.name for node in namespace.nodes: diff --git a/tests/scanner/BarApp-1.0-expected.gir b/tests/scanner/BarApp-1.0-expected.gir index 209f0622..91b044dd 100644 --- a/tests/scanner/BarApp-1.0-expected.gir +++ b/tests/scanner/BarApp-1.0-expected.gir @@ -8,6 +8,7 @@ and/or use gtk-doc annotations. --> xmlns:glib="http://www.gtk.org/introspection/glib/1.0"> <include name="GLib" version="2.0"/> <include name="GObject" version="2.0"/> + <package name="gobject-2.0"/> <namespace name="BarApp" version="1.0" shared-library=""> <class name="Baz" c:type="BarBaz" diff --git a/tests/scanner/GtkFrob-1.0-expected.gir b/tests/scanner/GtkFrob-1.0-expected.gir index fb2cbcba..fa4b3ed2 100644 --- a/tests/scanner/GtkFrob-1.0-expected.gir +++ b/tests/scanner/GtkFrob-1.0-expected.gir @@ -8,6 +8,7 @@ and/or use gtk-doc annotations. --> xmlns:glib="http://www.gtk.org/introspection/glib/1.0"> <include name="GLib" version="2.0"/> <include name="GObject" version="2.0"/> + <package name="gobject-2.0"/> <namespace name="GtkFrob" version="1.0" shared-library="gtkfrob"> <function name="language_manager_get_default" c:identifier="gtk_frob_language_manager_get_default"> diff --git a/tests/scanner/annotation-1.0-expected.gir b/tests/scanner/annotation-1.0-expected.gir index 11ee31e1..16d8ea43 100644 --- a/tests/scanner/annotation-1.0-expected.gir +++ b/tests/scanner/annotation-1.0-expected.gir @@ -9,6 +9,7 @@ and/or use gtk-doc annotations. --> <include name="GLib" version="2.0"/> <include name="GObject" version="2.0"/> <include name="utility" version="1.0"/> + <package name="gobject-2.0"/> <namespace name="annotation" version="1.0" shared-library="annotation"> <callback name="Callback" c:type="AnnotationCallback" diff --git a/tests/scanner/drawable-1.0-expected.gir b/tests/scanner/drawable-1.0-expected.gir index 738296ff..4affc68e 100644 --- a/tests/scanner/drawable-1.0-expected.gir +++ b/tests/scanner/drawable-1.0-expected.gir @@ -9,6 +9,7 @@ and/or use gtk-doc annotations. --> <include name="GLib" version="2.0"/> <include name="GObject" version="2.0"/> <include name="utility" version="1.0"/> + <package name="gobject-2.0"/> <namespace name="drawable" version="1.0" shared-library="drawable"> <class name="TestDrawable" c:type="TestDrawable" diff --git a/tests/scanner/foo-1.0-expected.gir b/tests/scanner/foo-1.0-expected.gir index a76fa4ee..8a36791b 100644 --- a/tests/scanner/foo-1.0-expected.gir +++ b/tests/scanner/foo-1.0-expected.gir @@ -9,6 +9,7 @@ and/or use gtk-doc annotations. --> <include name="GLib" version="2.0"/> <include name="GObject" version="2.0"/> <include name="utility" version="1.0"/> + <package name="gobject-2.0"/> <namespace name="foo" version="1.0" shared-library="foo"> <alias name="List" target="GLib.SList" c:type="FooList"/> <alias name="XEvent" target="none" c:type="FooXEvent"/> diff --git a/tests/scanner/utility-1.0-expected.gir b/tests/scanner/utility-1.0-expected.gir index c04d984d..2848d14f 100644 --- a/tests/scanner/utility-1.0-expected.gir +++ b/tests/scanner/utility-1.0-expected.gir @@ -8,6 +8,7 @@ and/or use gtk-doc annotations. --> xmlns:glib="http://www.gtk.org/introspection/glib/1.0"> <include name="GLib" version="2.0"/> <include name="GObject" version="2.0"/> + <package name="gobject-2.0"/> <namespace name="utility" version="1.0" shared-library="utility"> <alias name="Glyph" target="uint32" c:type="UtilityGlyph"/> <class name="Object" diff --git a/tools/g-ir-scanner b/tools/g-ir-scanner index 2152611d..6b319258 100755 --- a/tools/g-ir-scanner +++ b/tools/g-ir-scanner @@ -195,6 +195,41 @@ def validate(assertions, path): print "=== PASSED %s ===" % (assertions, ) return 0 +def process_packages(parser, options, packages): + args = ['pkg-config', '--cflags'] + args.extend(packages) + output = subprocess.Popen(args, + stdout=subprocess.PIPE).communicate()[0] + if output is None: + # the error output should have already appeared on our stderr, + # so we just exit + sys.exit(1) + # Some pkg-config files on Windows have options we don't understand, + # so we explicitly filter to only the ones we need. + options_whitelist = ['-I', '-D', '-U', '-l', '-L'] + def filter_option(opt): + for optstart in options_whitelist: + if opt.startswith(optstart): + return True + return False + output = output.split() + filtered_output = filter(filter_option, output) + pkg_options, unused = parser.parse_args(filtered_output) + options.cpp_includes.extend(pkg_options.cpp_includes) + options.cpp_defines.extend(pkg_options.cpp_defines) + options.cpp_undefines.extend(pkg_options.cpp_undefines) + + args = ['pkg-config', '--libs-only-L'] + args.extend(packages) + output = subprocess.Popen(args, + stdout=subprocess.PIPE).communicate()[0] + if output is None: + sys.exit(1) + output = output.split() + filtered_output = filter(filter_option, output) + pkg_options, unused = parser.parse_args(filtered_output) + options.library_paths.extend(pkg_options.library_paths) + def main(args): parser = _get_option_parser() (options, args) = parser.parse_args(args) @@ -226,31 +261,6 @@ def main(args): _error("Must specify --program or --library") libraries = options.libraries - for package in options.packages: - output = subprocess.Popen(['pkg-config', '--cflags', package], - stdout=subprocess.PIPE).communicate()[0] - # Some pkg-config files on Windows have options we don't understand, - # so we explicitly filter to only the ones we need. - options_whitelist = ['-I', '-D', '-U', '-l', '-L'] - def filter_option(opt): - for optstart in options_whitelist: - if opt.startswith(optstart): - return True - return False - output = output.split() - filtered_output = filter(filter_option, output) - pkg_options, unused = parser.parse_args(filtered_output) - options.cpp_includes.extend(pkg_options.cpp_includes) - options.cpp_defines.extend(pkg_options.cpp_defines) - options.cpp_undefines.extend(pkg_options.cpp_undefines) - - output = subprocess.Popen(['pkg-config', '--libs-only-L', package], - stdout=subprocess.PIPE).communicate()[0] - output = output.split() - filtered_output = filter(filter_option, output) - pkg_options, unused = parser.parse_args(filtered_output) - options.library_paths.extend(pkg_options.library_paths) - # FIXME: using LPATH is definitely not portable enough. Using Python's # find_library for finding our shared libraries is not a portable enough # anyway as it behaves differently depending on the OS @@ -272,19 +282,9 @@ def main(args): if not os.path.exists(arg): _error('%s: no such a file or directory' % (arg, )) filenames.append(arg) - - cachestore = CacheStore() - # Run the preprocessor, tokenize and construct simple - # objects representing the raw C symbols - ss = SourceScanner() - ss.set_cpp_options(options.cpp_includes, - options.cpp_defines, - options.cpp_undefines) - ss.parse_files(filenames) - ss.parse_macros(filenames) - - # Transform the C symbols into AST nodes - transformer = Transformer(cachestore, ss, + + cachestore = CacheStore() + transformer = Transformer(cachestore, options.namespace_name, options.namespace_version) if options.strip_prefix: @@ -298,6 +298,22 @@ def main(args): raise ValueError("Invalid include path %r" % (include, )) include_obj = Include.from_string(include) transformer.register_include(include_obj) + + packages = set(options.packages) + packages.update(transformer.get_pkgconfig_packages()) + process_packages(parser, options, packages) + + # Run the preprocessor, tokenize and construct simple + # objects representing the raw C symbols + ss = SourceScanner() + ss.set_cpp_options(options.cpp_includes, + options.cpp_defines, + options.cpp_undefines) + ss.parse_files(filenames) + ss.parse_macros(filenames) + + # Transform the C symbols into AST nodes + transformer.set_source_ast(ss) if options.program: args=[options.program] @@ -321,7 +337,8 @@ def main(args): raise SystemExit("ERROR in annotation: %s" % (str(e), )) # Write out AST - writer = Writer(namespace, libraries, transformer.get_includes()) + writer = Writer(namespace, libraries, transformer.get_includes(), + options.packages) data = writer.get_xml() if options.output: fd = open(options.output, "w") |