Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2009-02-05 22:36:35 (GMT)
committer Colin Walters <walters@verbum.org>2009-02-11 20:03:16 (GMT)
commit44ea75378eb33fa6386e66e9e5a55f3122363fb8 (patch)
tree27385b5c523f7390193dba950df134540aabd838
parent1b5e689fe2fc105725fe71051c184e0f1c461223 (diff)
Bug 567906 - Put pkg-config dependencies in .gir files
When generating a .gir file, we now first parse all of our .gir includes to pick up their <package> headers. Then, we merge that with the set of --pkg arguments passed to us, run pkg-config to gather the arguments, and finally save the merged pkg-config list to our new .gir file. This is useful for software which needs to map from .gir to pkg-config in a programmatic way.
-rw-r--r--gir/Makefile.am1
-rw-r--r--girepository/girparser.c60
-rw-r--r--giscanner/girparser.py10
-rw-r--r--giscanner/girwriter.py19
-rw-r--r--giscanner/transformer.py19
-rw-r--r--tests/scanner/BarApp-1.0-expected.gir1
-rw-r--r--tests/scanner/GtkFrob-1.0-expected.gir1
-rw-r--r--tests/scanner/annotation-1.0-expected.gir1
-rw-r--r--tests/scanner/drawable-1.0-expected.gir1
-rw-r--r--tests/scanner/foo-1.0-expected.gir1
-rw-r--r--tests/scanner/utility-1.0-expected.gir1
-rwxr-xr-xtools/g-ir-scanner95
12 files changed, 138 insertions, 72 deletions
diff --git a/gir/Makefile.am b/gir/Makefile.am
index 1adccd5..f74de6d 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 97e3a1e..fe2f762 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 3e2432e..62db3e9 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 657063e..35c9b35 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 f6e89ce..6f9207a 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 209f062..91b044d 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 fb2cbcb..fa4b3ed 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 11ee31e..16d8ea4 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 738296f..4affc68 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 a76fa4e..8a36791 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 c04d984..2848d14 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 2152611..6b31925 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")