diff options
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | docs/g-ir-scanner.1 | 15 | ||||
-rw-r--r-- | gir/Makefile.am | 44 | ||||
-rw-r--r-- | giscanner/Makefile.am | 2 | ||||
-rw-r--r-- | giscanner/cgobject.py | 303 | ||||
-rw-r--r-- | giscanner/glibtransformer.py | 335 | ||||
-rw-r--r-- | giscanner/transformer.py | 19 | ||||
-rw-r--r-- | tests/everything/Makefile.am | 11 | ||||
-rw-r--r-- | tests/offsets/Makefile.am | 15 | ||||
-rw-r--r-- | tests/scanner/Makefile.am | 60 | ||||
-rw-r--r-- | tests/scanner/annotation-1.0-expected.gir | 2 | ||||
-rw-r--r-- | tests/scanner/annotation-1.0-expected.tgir | 2 | ||||
-rw-r--r-- | tests/scanner/annotation.c | 2 | ||||
-rw-r--r-- | tests/scanner/annotation.h | 2 | ||||
-rw-r--r-- | tests/scanner/foo-1.0-expected.gir | 2 | ||||
-rw-r--r-- | tests/scanner/foo-1.0-expected.tgir | 2 | ||||
-rwxr-xr-x | tools/g-ir-scanner | 32 |
17 files changed, 290 insertions, 578 deletions
@@ -1,5 +1,25 @@ 2008-11-13 Colin Walters <walters@verbum.org> + Bug 558436 - avoid having scanner load app code + + * giscanner/cgobject.py: Delete; we no longer load shared + libraries directly. + * giscanner/dumper.py: Support for linking a library to + a stub binary for introspection. + * giscanner/glibtransformer.py: Rewrite to use gdump XML + from invocation of child binary. + * giscanner/transformer.py: Fix up to use fully qualified + name in parse tree. Make parse_ctype public so we can use + it inside glibtransformer. + * tests/scanner/barapp.c: New test, using --program arg + for g-ir-scanner. + * tests/*: Update to use common.mk for invoking scanner. + * tools/g-ir-scanner: Add options --program, --program-arg, + and --no-libtool. + * docs/g-ir-scanner.1: Update. + +2008-11-13 Colin Walters <walters@verbum.org> + * configure.ac: Depend on Gio, we use it in gdump.c. * girepository/gdump.c: Code to dump GType data to XML. * girepository/girepository.c: Add option group for dumping. diff --git a/docs/g-ir-scanner.1 b/docs/g-ir-scanner.1 index 9148a359..315f678e 100644 --- a/docs/g-ir-scanner.1 +++ b/docs/g-ir-scanner.1 @@ -43,14 +43,27 @@ Include this directory when searching for a library. This option can be specified multiple times to include more than one directory to look for libraries in. .TP -.B \-n, ---namspace=NAME +.B \-n, ---namespace=NAME The namespace name. This name should be capitalized, eg the first letter should be upper case. Examples: Gtk, Clutter, WebKit. .TP +.B \---no-libtool +Disable usage of libtool for compiling stub introspection binary. Use this +if your build system does not require libtool. +.TP .B ---nsversion=VERSION The namespace version. For instance 1.0. This is usually the platform version, eg 2.0 for Gtk+, not 2.12.7. .TP +.B \-p, ---program=PROGRAM +Specifies a binary that will be introspected. This means that the +*_get_type() functions in it will be called for GObject data types. +The binary must be modified to take a --introspect= option, and +to pass the argument to this function to g_irepository_dump. +.TP +.B \---program-arg=ARG +Additional argument to pass to program for introspection. +.TP .B \, ---strip-prefix=PREFIX If this option is specified a prefix will be stripped from all functions. If not specified, the lower case version of the namespace will be used. diff --git a/gir/Makefile.am b/gir/Makefile.am index 0e213912..6b48b313 100644 --- a/gir/Makefile.am +++ b/gir/Makefile.am @@ -1,11 +1,8 @@ +include $(top_srcdir)/common.mk + BUILT_SOURCES = EXTRA_DIST = -G_IR_SCANNER = $(top_srcdir)/tools/g-ir-scanner -G_IR_SCANNER_PYTHONPATH = $(top_builddir):$(top_srcdir):$$PYTHONPATH -G_IR_SCANNER_FILES = $(top_srcdir)/giscanner/*.py \ - $(top_builddir)/giscanner/libgiscanner.la - # glib GLIB_INCLUDEDIR=`pkg-config --variable=includedir glib-2.0`/glib-2.0 GLIB_LIBDIR=`pkg-config --variable=libdir glib-2.0` @@ -16,10 +13,9 @@ else GLIB_LIBRARY=glib-2.0 endif -GLib-2.0.gir: $(G_IR_SCANNER) $(G_IR_SCANNER_FILES) glib-2.0.c - PYTHONPATH=$(G_IR_SCANNER_PYTHONPATH) $(G_IR_SCANNER) \ - -v --namespace GLib --nsversion=2.0 \ - --add-include-path=. \ +GLib-2.0.gir: $(SCANNER_BIN) $(SCANNER_LIBS) Makefile glib-2.0.c + $(SCANNER) \ + --namespace GLib --nsversion=2.0 \ --noclosure \ --output $@ \ --strip-prefix=g \ @@ -32,7 +28,7 @@ GLib-2.0.gir: $(G_IR_SCANNER) $(G_IR_SCANNER_FILES) glib-2.0.c $(GLIB_LIBDIR)/glib-2.0/include/glibconfig.h \ $(srcdir)/glib-2.0.c \ $(GLIB_INCLUDEDIR)/glib/*.h - PYTHONPATH=$(G_IR_SCANNER_PYTHONPATH) $(G_IR_SCANNER) \ + $(SCANNER) $(SCANNER_ARGS) \ --xpath-assertions=$(srcdir)/GLib-2.0.xpath GLib-2.0.gir BUILT_SOURCES += GLib-2.0.gir EXTRA_DIST += glib-2.0.c GLib-2.0.xpath @@ -47,10 +43,9 @@ else GOBJECT_LIBRARY=gobject-2.0 endif -GObject-2.0.gir: GLib-2.0.gir $(G_IR_SCANNER) $(G_IR_SCANNER_FILES) - PYTHONPATH=$(G_IR_SCANNER_PYTHONPATH) $(G_IR_SCANNER) \ - -v --namespace GObject --nsversion=2.0 \ - --add-include-path=. \ +GObject-2.0.gir: GLib-2.0.gir $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(SCANNER) \ + --namespace GObject --nsversion=2.0 \ --noclosure \ --output $@ \ --strip-prefix=g \ @@ -73,9 +68,9 @@ else GMODULE_LIBRARY=gmodule-2.0 endif -GModule-2.0.gir: GLib-2.0.gir $(G_IR_SCANNER) $(G_IR_SCANNER_FILES) - PYTHONPATH=$(G_IR_SCANNER_PYTHONPATH) $(G_IR_SCANNER) \ - -v --namespace GModule --nsversion=2.0 \ +GModule-2.0.gir: GLib-2.0.gir $(SCANNER_BIN) $(SCANNER_LIBS) + $(SCANNER) \ + --namespace GModule --nsversion=2.0 \ --add-include-path=. \ --noclosure \ --output $@ \ @@ -98,9 +93,9 @@ else GIO_LIBRARY=gio-2.0 endif -Gio-2.0.gir: GObject-2.0.gir $(G_IR_SCANNER) $(G_IR_SCANNER_FILES) $(srcdir)/gio-2.0.c - PYTHONPATH=$(G_IR_SCANNER_PYTHONPATH) $(G_IR_SCANNER) \ - -v --namespace Gio --nsversion=2.0 \ +Gio-2.0.gir: GObject-2.0.gir $(SCANNER_BIN) $(SCANNER_LIBS) Makefile $(srcdir)/gio-2.0.c + $(SCANNER) \ + --namespace Gio --nsversion=2.0 \ --add-include-path=. \ --noclosure \ --output $@ \ @@ -122,15 +117,14 @@ GIREPOSITORY_FILES = \ $(top_srcdir)/girepository/girepository.c \ $(top_srcdir)/girepository/girepository.h -GIRepository-2.0.gir: GObject-2.0.gir $(G_IR_SCANNER) $(G_IR_SCANNER_FILES) $(GIREPOSITORY_FILES) - PYTHONPATH=$(G_IR_SCANNER_PYTHONPATH) $(G_IR_SCANNER) \ - -v --namespace GIRepository --nsversion=1.0\ - --add-include-path=. \ +GIRepository-2.0.gir: GObject-2.0.gir $(SCANNER_BIN) $(SCANNER_LIBS) $(GIREPOSITORY_FILES) + $(SCANNER) \ + --namespace GIRepository --nsversion=1.0\ --noclosure \ --output $@ \ --strip-prefix=g \ --include=GObject-2.0 \ - --library=$(top_builddir)/girepository/libgirepository.la \ + --library=girepository \ -I$(srcdir)/girepository \ --pkg glib-2.0 \ --pkg gobject-2.0 \ diff --git a/giscanner/Makefile.am b/giscanner/Makefile.am index c9d23e58..1d6942b4 100644 --- a/giscanner/Makefile.am +++ b/giscanner/Makefile.am @@ -37,8 +37,8 @@ pkgpyexec_PYTHON = \ __init__.py \ ast.py \ cachestore.py \ - cgobject.py \ config.py \ + dumper.py \ girparser.py \ girwriter.py \ glibast.py \ diff --git a/giscanner/cgobject.py b/giscanner/cgobject.py deleted file mode 100644 index 308ebf49..00000000 --- a/giscanner/cgobject.py +++ /dev/null @@ -1,303 +0,0 @@ -# -*- Mode: Python -*- -# GObject-Introspection - a framework for introspecting GObject libraries -# Copyright (C) 2008 Johan Dahlin -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. -# - -# Poor mans GObject python bindings -# Incidentally portable beyond CPython, due to usage of ctypes -# Why not PyGObject? -# - 1) Avoid PyGObject dependency -# - 2) Low-level binding -# - 3) Implementation independent -# - 4) Usage lower in the stack -# -# based on defsgen.py (C) 2006 John Finlay -# - -import os -import ctypes -from ctypes.util import find_library - - -# Constants - -# from gobject/gtype.h - - -def _make_fundamental(x): - G_TYPE_FUNDAMENTAL_SHIFT = 2 - return x << G_TYPE_FUNDAMENTAL_SHIFT - - -TYPE_INVALID = _make_fundamental(0) -TYPE_NONE = _make_fundamental(1) -TYPE_INTERFACE = _make_fundamental(2) -TYPE_CHAR = _make_fundamental(3) -TYPE_UCHAR = _make_fundamental(4) -TYPE_BOOLEAN = _make_fundamental(5) -TYPE_INT = _make_fundamental(6) -TYPE_UINT = _make_fundamental(7) -TYPE_LONG = _make_fundamental(8) -TYPE_ULONG = _make_fundamental(9) -TYPE_INT64 = _make_fundamental(10) -TYPE_UINT64 = _make_fundamental(11) -TYPE_ENUM = _make_fundamental(12) -TYPE_FLAGS = _make_fundamental(13) -TYPE_FLOAT = _make_fundamental(14) -TYPE_DOUBLE = _make_fundamental(15) -TYPE_STRING = _make_fundamental(16) -TYPE_POINTER = _make_fundamental(17) -TYPE_BOXED = _make_fundamental(18) -TYPE_PARAM = _make_fundamental(19) -TYPE_OBJECT = _make_fundamental(20) - -# Typedefs - -# FIXME - this is wrong on win64, where long == 32 but size_t == 64 -GType = ctypes.c_ulong - -TYPE_FLAG_ABSTRACT = 1 << 4 - -# Structs - - -class GTypeClass(ctypes.Structure): - _fields_ = [('g_type', GType)] - - -class GTypeInstance(ctypes.Structure): - _fields_ = [('g_class', ctypes.POINTER(GTypeClass))] - - -class GEnumValue(ctypes.Structure): - _fields_ = [('value', ctypes.c_int), - ('value_name', ctypes.c_char_p), - ('value_nick', ctypes.c_char_p)] - - -class GFlagsValue(ctypes.Structure): - _fields_ = [('value', ctypes.c_uint), - ('value_name', ctypes.c_char_p), - ('value_nick', ctypes.c_char_p)] - - -class GEnumClass(ctypes.Structure): - _fields_ = [('g_type_class', GTypeClass), - ('minimum', ctypes.c_int), - ('maximum', ctypes.c_int), - ('n_values', ctypes.c_uint), - ('values', ctypes.POINTER(GEnumValue))] - - def get_values(self): - for i in range(self.n_values): - yield self.values[i] - - -class GFlagsClass(ctypes.Structure): - _fields_ = [('g_type_class', GTypeClass), - ('mask', ctypes.c_uint), - ('n_values', ctypes.c_uint), - ('values', ctypes.POINTER(GFlagsValue))] - - def get_values(self): - for i in range(self.n_values): - yield self.values[i] - - -class GTypeInterface(ctypes.Structure): - _fields_ = [('g_type', GType), - ('g_instance_type', GType)] - - -class GParamSpec(ctypes.Structure): - _fields_ = [('g_type_instance', GTypeInstance), - ('name', ctypes.c_char_p), - ('flags', ctypes.c_uint), - ('value_type', GType), - ('owner_type', GType)] - - -class GSignalInfo(ctypes.Structure): - _fields_ = [('signal_id', ctypes.c_uint), - ('signal_name', ctypes.c_char_p), - ('itype', GType), - ('signal_flags', ctypes.c_uint), - ('return_type', GType), - ('n_params', ctypes.c_uint), - ('param_types', ctypes.POINTER(GType))] - - def get_params(self): - for i in range(self.n_params): - yield self.param_types[i] - - -if os.name == 'nt': - _library_path = find_library('libgobject-2.0-0') -else: - _library_path = find_library('gobject-2.0') -if not _library_path: - raise ImportError("Could not find gobject-2.0 library") -_gobj = ctypes.CDLL(_library_path, ctypes.RTLD_GLOBAL) -_gobj.g_type_init() - -# We need to initialize threads just in case part of the library -# wants to use gthreads; libsoup seems to use g_once for its -# type init functions. -if os.name == 'nt': - _threads_library_path = find_library('libgthread-2.0-0') -else: - _threads_library_path = find_library('gthread-2.0') -if not _threads_library_path: - raise ImportError("Could not find gthread-2.0 library") -_gthreads = ctypes.CDLL(_threads_library_path, ctypes.RTLD_GLOBAL) -_gthreads.g_thread_init.argtypes = [ctypes.c_void_p] -_gthreads.g_thread_init(None) - -# Functions - - -def _gwrap(fname, ret, *argtypes): - - def _deco(f): - f._cfunc = getattr(_gobj, fname) - f._cfunc.restype = ret - f._cfunc.argtypes = argtypes - return f - return _deco - - -@_gwrap('g_object_new', ctypes.c_void_p, GType) -def object_new(type_id): - return _gobj.g_object_new(type_id, None) - - -# Workaround this error: -# GLib-GObject-CRITICAL **: g_param_spec_pool_list: -# assertion `pool != NULL' failed -# which happens when trying to introspect an interface before instantiating -# a GObject. - -object_new(TYPE_OBJECT) -_gobj.g_initially_unowned_get_type() - - -@_gwrap('g_type_name', ctypes.c_char_p, GType) -def type_name(type_id): - return _gobj.g_type_name(type_id) - - -@_gwrap('g_type_from_name', GType, ctypes.c_char_p) -def type_from_name(name): - return _gobj.g_type_from_name(name) - - -@_gwrap('g_type_fundamental', GType, GType) -def type_fundamental(type_id): - return _gobj.g_type_fundamental(type_id) - - -@_gwrap('g_type_test_flags', ctypes.c_int, GType, ctypes.c_int) -def type_test_flags(type_id, flag): - return _gobj.g_type_test_flags(type_id, flag) - - -def type_is_abstract(type_id): - return type_test_flags(type_id, TYPE_FLAG_ABSTRACT) != 0 - - -@_gwrap('g_type_parent', GType, GType) -def type_parent(type_id): - return _gobj.g_type_parent(type_id) - - -@_gwrap('g_type_class_ref', ctypes.POINTER(GTypeClass), GType) -def type_class_ref(type_id): - fundamental_type = type_fundamental(type_id) - if fundamental_type == TYPE_INVALID: - return None - if fundamental_type == TYPE_ENUM: - typeclass = GEnumClass - elif fundamental_type == TYPE_FLAGS: - typeclass = GFlagsClass - else: - raise NotImplementedError(fundamental_type) - ptr = _gobj.g_type_class_ref(type_id) - return ctypes.cast(ptr, ctypes.POINTER(typeclass)).contents - - -@_gwrap('g_object_class_list_properties', - ctypes.POINTER(ctypes.POINTER(GParamSpec)), - ctypes.POINTER(GTypeClass), ctypes.POINTER(ctypes.c_uint)) -def object_class_list_properties(type_id): - klass = _gobj.g_type_class_ref(type_id) - n = ctypes.c_uint() - pspecs = _gobj.g_object_class_list_properties(klass, ctypes.byref(n)) - for i in range(n.value): - yield ctypes.cast(pspecs[i], ctypes.POINTER(GParamSpec)).contents - - -@_gwrap('g_type_default_interface_ref', ctypes.c_void_p, GType) -def type_default_interface_ref(type_id): - return _gobj.g_type_default_interface_ref(type_id) - - -@_gwrap('g_object_interface_list_properties', - ctypes.POINTER(ctypes.POINTER(GParamSpec)), - ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint)) -def object_interface_list_properties(type_id): - iface = type_default_interface_ref(type_id) - n = ctypes.c_uint() - pspecs = _gobj.g_object_interface_list_properties(iface, ctypes.byref(n)) - for i in range(n.value): - yield ctypes.cast(pspecs[i], ctypes.POINTER(GParamSpec)).contents - - -@_gwrap('g_type_interfaces', ctypes.POINTER(GType), GType, - ctypes.POINTER(ctypes.c_uint)) -def type_interfaces(type_id): - n = ctypes.c_uint() - type_ids = _gobj.g_type_interfaces(type_id, ctypes.byref(n)) - for i in range(n.value): - yield type_ids[i] - - -@_gwrap('g_type_interface_prerequisites', ctypes.POINTER(GType), GType, - ctypes.POINTER(ctypes.c_uint)) -def type_interface_prerequisites(type_id): - n = ctypes.c_uint() - type_ids = _gobj.g_type_interface_prerequisites(type_id, ctypes.byref(n)) - for i in range(n.value): - yield type_ids[i] - - -@_gwrap('g_signal_query', None, ctypes.c_uint, ctypes.POINTER(GSignalInfo)) -def signal_query(sigid, qptr): - _gobj.g_signal_query(sigid, qptr) - - -@_gwrap('g_signal_list_ids', ctypes.POINTER(ctypes.c_uint), - GType, ctypes.POINTER(ctypes.c_uint)) -def signal_list(type_id): - n = ctypes.c_uint() - signal_ids = _gobj.g_signal_list_ids(type_id, ctypes.byref(n)) - for i in range(n.value): - info = GSignalInfo() - signal_query(signal_ids[i], ctypes.byref(info)) - yield info - -TYPE_GTYPE = type_from_name('GType') diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py index f97af9fa..a414078e 100644 --- a/giscanner/glibtransformer.py +++ b/giscanner/glibtransformer.py @@ -19,11 +19,12 @@ # import os +import sys import re -import ctypes -from ctypes.util import find_library +import tempfile +import shutil +import subprocess -from . import cgobject from .ast import (Callback, Constant, Enum, Function, Member, Namespace, Parameter, Property, Return, Struct, Type, Alias, Union, Field, type_name_from_ctype, @@ -32,10 +33,20 @@ from .transformer import Names from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags, GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct, GLibBoxedUnion, GLibBoxedOther, type_names) -from .utils import extract_libtool, to_underscores, to_underscores_noprefix +from .utils import to_underscores, to_underscores_noprefix default_array_types['guchar*'] = TYPE_UINT8 +# GParamFlags +G_PARAM_READABLE = 1 << 0 +G_PARAM_WRITABLE = 1 << 1 +G_PARAM_CONSTRUCT = 1 << 2 +G_PARAM_CONSTRUCT_ONLY = 1 << 3 +G_PARAM_LAX_VALIDATION = 1 << 4 +G_PARAM_STATIC_NAME = 1 << 5 +G_PARAM_STATIC_NICK = 1 << 6 +G_PARAM_STATIC_BLURB = 1 << 7 + SYMBOL_BLACKLIST = [ # These ones break GError conventions 'g_simple_async_result_new_from_error', @@ -49,6 +60,16 @@ SYMBOL_BLACKLIST_RE = [re.compile(x) for x in \ [r'\w+_marshal_[A-Z]+__', ]] +class IntrospectionBinary(object): + + def __init__(self, args, tmpdir=None): + self.args = args + if tmpdir is None: + self.tmpdir = tempfile.mkdtemp('', 'tmp-introspect') + else: + self.tmpdir = tmpdir + + class Unresolved(object): def __init__(self, target): @@ -68,7 +89,9 @@ class GLibTransformer(object): self._namespace_name = None self._names = Names() self._uscore_type_names = {} - self._libraries = [] + self._binary = None + self._get_type_functions = [] + self._gtype_data = {} self._failed_types = {} self._boxed_types = {} self._private_internal_types = {} @@ -77,23 +100,8 @@ class GLibTransformer(object): # Public API - def add_library(self, libname): - # For testing mainly. - libtool_libname = 'lib' + libname + '.la' - if os.path.exists(libname): - found_libname = os.path.abspath(libname) - elif os.path.exists(libtool_libname): - found_libname = extract_libtool(libtool_libname) - else: - found_libname = find_library(libname) - - if libname.endswith('.la'): - found_libname = extract_libtool(libname) - libname = os.path.basename(found_libname) - if not found_libname: - raise ValueError("Failed to find library: %r" % (libname, )) - self._libraries.append(ctypes.cdll.LoadLibrary(found_libname)) - return libname + def set_introspection_binary(self, binary): + self._binary = binary def _print_statistics(self): nodes = list(self._names.names.itervalues()) @@ -120,6 +128,11 @@ class GLibTransformer(object): if namespace.name == 'GObject': del self._names.aliases['Type'] + # Get all the GObject data by passing our list of get_type + # functions to the compiled binary + + self._execute_binary() + # Introspection is done from within parsing # Second pass: pair boxed structures @@ -169,6 +182,16 @@ class GLibTransformer(object): return node[1] return None + def _lookup_node(self, name): + if name in type_names: + return None + node = self._get_attribute(name) + if node is None: + node = self._transformer.get_names().names.get(name) + if node: + return node[1] + return node + def _register_internal_type(self, type_name, node): self._names.type_names[type_name] = (None, node) uscored = to_underscores(type_name).lower() @@ -183,16 +206,6 @@ class GLibTransformer(object): # Helper functions - def _type_from_gtype(self, type_id): - ctype = cgobject.type_name(type_id) - type_name = type_name_from_ctype(ctype) - type_name = type_name.replace('*', '') - type_name = self._resolve_type_name(type_name) - - type = Type(type_name, ctype) - type._gtype = type_id - return type - def _resolve_gtypename(self, gtype_name): try: return self._transformer.gtypename_to_giname(gtype_name, @@ -200,21 +213,45 @@ class GLibTransformer(object): except KeyError, e: return Unresolved(gtype_name) + def _execute_binary(self): + in_path = os.path.join(self._binary.tmpdir, 'types.txt') + f = open(in_path, 'w') + for func in self._get_type_functions: + f.write(func) + f.write('\n') + f.close() + out_path = os.path.join(self._binary.tmpdir, 'dump.xml') + + introspect_arg = '--introspect-dump=%s,%s' % (in_path, out_path) + args = self._binary.args + args.append(introspect_arg) + # Invoke the binary, having written our get_type functions to types.txt + print args + subprocess.check_call(args, stdout=sys.stdout, stderr=sys.stderr) + self._read_introspect_dump(out_path) + + # Clean up temporaries + shutil.rmtree(self._binary.tmpdir) + + def _read_introspect_dump(self, xmlpath): + from xml.etree.cElementTree import parse + tree = parse(xmlpath) + root = tree.getroot() + for child in root: + self._gtype_data[child.attrib['name']] = child + for child in root: + self._introspect_type(child) + def _create_gobject(self, node): type_name = 'G' + node.name if type_name == 'GObject': parent_gitype = None symbol = 'intern' - else: - type_id = cgobject.type_from_name(type_name) - parent_type_name = cgobject.type_name( - cgobject.type_parent(type_id)) + elif type_name == 'GInitiallyUnowned': + parent_type_name = 'GObject' parent_gitype = self._resolve_gtypename(parent_type_name) - symbol = to_underscores(type_name).lower() + '_get_type' + symbol = 'g_initially_unowned_get_type' node = GLibObject(node.name, parent_gitype, type_name, symbol, True) - type_id = cgobject.TYPE_OBJECT - self._introspect_properties(node, type_id) - self._introspect_signals(node, type_id) self._add_attribute(node) self._register_internal_type(type_name, node) @@ -281,26 +318,7 @@ class GLibTransformer(object): ", not GObject.Type") % (func.retval.type.name, ) return False - if not self._libraries: - print "Warning: No libraries loaded, cannot call %s" % (symbol, ) - return False - - for library in self._libraries: - try: - func = getattr(library, symbol) - break - except AttributeError: - continue - else: - print 'Warning: could not find symbol: %s' % symbol - name = symbol.replace('_get_type', '') - self._failed_types[name] = True - return False - - func.restype = cgobject.GType - func.argtypes = [] - type_id = func() - self._introspect_type(type_id, symbol) + self._get_type_functions.append(symbol) return True def _name_is_internal_gtype(self, giname): @@ -491,65 +509,51 @@ class GLibTransformer(object): # Introspection - def _introspect_type(self, type_id, symbol): - fundamental_type_id = cgobject.type_fundamental(type_id) - if (fundamental_type_id == cgobject.TYPE_ENUM or - fundamental_type_id == cgobject.TYPE_FLAGS): - self._introspect_enum(fundamental_type_id, type_id, symbol) - elif fundamental_type_id == cgobject.TYPE_OBJECT: - self._introspect_object(type_id, symbol) - elif fundamental_type_id == cgobject.TYPE_INTERFACE: - self._introspect_interface(type_id, symbol) - elif fundamental_type_id == cgobject.TYPE_BOXED: - self._introspect_boxed(type_id, symbol) - elif fundamental_type_id == cgobject.TYPE_BOXED: - self._introspect_boxed(type_id, symbol) - elif fundamental_type_id == cgobject.TYPE_POINTER: - # FIXME: Should we do something about these? - # GHashTable, GValue and a few other fundamentals are - # covered here - return + def _introspect_type(self, xmlnode): + if xmlnode.tag in ('enum', 'flags'): + self._introspect_enum(xmlnode) + elif xmlnode.tag == 'class': + self._introspect_object(xmlnode) + elif xmlnode.tag == 'interface': + self._introspect_interface(xmlnode) + elif xmlnode.tag == 'boxed': + self._introspect_boxed(xmlnode) else: - print 'unhandled GType: %s(%d)' % (cgobject.type_name(type_id), - type_id) - - def _introspect_enum(self, ftype_id, type_id, symbol): - type_class = cgobject.type_class_ref(type_id) - if type_class is None: - return + raise ValueError("Unhandled introspection XML tag %s", xmlnode.tag) + def _introspect_enum(self, node): members = [] - for enum_value in type_class.get_values(): - members.append(GLibEnumMember(enum_value.value_nick, - enum_value.value, - enum_value.value_name, - enum_value.value_nick)) - - klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum) - type_name = cgobject.type_name(type_id) + for member in node.findall('member'): + members.append(GLibEnumMember(member.attrib['nick'], + member.attrib['value'], + member.attrib['name'], + member.attrib['nick'])) + + klass = (GLibFlags if node.tag == 'flags' else GLibEnum) + type_name = node.attrib['name'] enum_name = self._transformer.remove_prefix(type_name) - node = klass(enum_name, type_name, members, symbol) + node = klass(enum_name, type_name, members, node.attrib['get-type']) self._add_attribute(node, replace=True) self._register_internal_type(type_name, node) - def _introspect_object(self, type_id, symbol): - type_name = cgobject.type_name(type_id) + def _introspect_object(self, xmlnode): + type_name = xmlnode.attrib['name'] # We handle this specially above; in 2.16 and below there # was no g_object_get_type, for later versions we need # to skip it if type_name == 'GObject': return - parent_type_name = cgobject.type_name(cgobject.type_parent(type_id)) + parent_type_name = xmlnode.attrib['parent'] parent_gitype = self._resolve_gtypename(parent_type_name) - is_abstract = cgobject.type_is_abstract(type_id) + is_abstract = not not xmlnode.attrib.get('abstract', False) node = GLibObject( self._transformer.remove_prefix(type_name), parent_gitype, type_name, - symbol, is_abstract) - self._introspect_properties(node, type_id) - self._introspect_signals(node, type_id) - self._introspect_implemented_interfaces(node, type_id) + xmlnode.attrib['get-type'], is_abstract) + self._introspect_properties(node, xmlnode) + self._introspect_signals(node, xmlnode) + self._introspect_implemented_interfaces(node, xmlnode) # add struct fields struct = self._get_attribute(node.name) @@ -564,84 +568,69 @@ class GLibTransformer(object): self._add_attribute(node, replace=True) self._register_internal_type(type_name, node) - def _introspect_interface(self, type_id, symbol): - type_name = cgobject.type_name(type_id) - parent_type_name = cgobject.type_name(cgobject.type_parent(type_id)) - if parent_type_name == 'GInterface': - parent_gitype = None - else: - parent_gitype = self._resolve_gtypename(parent_type_name) + def _introspect_interface(self, xmlnode): + type_name = xmlnode.attrib['name'] node = GLibInterface( self._transformer.remove_prefix(type_name), - parent_gitype, - type_name, symbol) - self._introspect_properties(node, type_id) - self._introspect_signals(node, type_id) + None, + type_name, xmlnode.attrib['get-type']) + self._introspect_properties(node, xmlnode) + self._introspect_signals(node, xmlnode) # GtkFileChooserEmbed is an example of a private interface, we # just filter them out - if symbol.startswith('_'): + if xmlnode.attrib['get-type'].startswith('_'): print "NOTICE: Marking %s as internal type" % (type_name, ) self._private_internal_types[type_name] = node else: self._add_attribute(node, replace=True) self._register_internal_type(type_name, node) - def _introspect_boxed(self, type_id, symbol): - type_name = cgobject.type_name(type_id) + def _introspect_boxed(self, xmlnode): + type_name = xmlnode.attrib['name'] # This one doesn't go in the main namespace; we associate it with # the struct or union - node = GLibBoxed(type_name, symbol) + node = GLibBoxed(type_name, xmlnode.attrib['get-type']) self._boxed_types[node.type_name] = node self._register_internal_type(type_name, node) - def _introspect_implemented_interfaces(self, node, type_id): - fundamental_type_id = cgobject.type_fundamental(type_id) - if fundamental_type_id != cgobject.TYPE_OBJECT: - raise AssertionError - interfaces = cgobject.type_interfaces(type_id) + def _introspect_implemented_interfaces(self, node, xmlnode): gt_interfaces = [] - for interface_typeid in interfaces: - iname = cgobject.type_name(interface_typeid) - gitype = self._resolve_gtypename(iname) + for interface in xmlnode.findall('implements'): + gitype = self._resolve_gtypename(interface.attrib['name']) gt_interfaces.append(gitype) node.interfaces = gt_interfaces - def _introspect_properties(self, node, type_id): - fundamental_type_id = cgobject.type_fundamental(type_id) - if fundamental_type_id == cgobject.TYPE_OBJECT: - pspecs = cgobject.object_class_list_properties(type_id) - elif fundamental_type_id == cgobject.TYPE_INTERFACE: - pspecs = cgobject.object_interface_list_properties(type_id) - else: - raise AssertionError - - for pspec in pspecs: - if pspec.owner_type != type_id: - continue - ctype = cgobject.type_name(pspec.value_type) - readable = (pspec.flags & 1) != 0 - writable = (pspec.flags & 2) != 0 - construct = (pspec.flags & 4) != 0 - construct_only = (pspec.flags & 8) != 0 + def _introspect_properties(self, node, xmlnode): + for pspec in xmlnode.findall('property'): + ctype = pspec.attrib['type'] + flags = int(pspec.attrib['flags']) + readable = (flags & G_PARAM_READABLE) != 0 + writable = (flags & G_PARAM_WRITABLE) != 0 + construct = (flags & G_PARAM_CONSTRUCT) != 0 + construct_only = (flags & G_PARAM_CONSTRUCT_ONLY) != 0 node.properties.append(Property( - pspec.name, + pspec.attrib['name'], type_name_from_ctype(ctype), readable, writable, construct, construct_only, ctype, )) - def _introspect_signals(self, node, type_id): - for signal_info in cgobject.signal_list(type_id): - rtype = self._type_from_gtype(signal_info.return_type) - return_ = Return(rtype) - signal = GLibSignal(signal_info.signal_name, return_) - for i, parameter in enumerate(signal_info.get_params()): + def _introspect_signals(self, node, xmlnode): + for signal_info in xmlnode.findall('signal'): + rctype = signal_info.attrib['return'] + rtype = Type(self._transformer.parse_ctype(rctype), rctype) + return_ = Return(rtype, signal_info.attrib['return']) + return_.transfer = 'full' + signal = GLibSignal(signal_info.attrib['name'], return_) + for i, parameter in enumerate(signal_info.findall('param')): if i == 0: name = 'object' else: name = 'p%s' % (i-1, ) - ptype = self._type_from_gtype(parameter) + pctype = parameter.attrib['type'] + ptype = Type(self._transformer.parse_ctype(pctype), pctype) param = Parameter(name, ptype) + param.transfer = 'none' signal.parameters.append(param) node.signals.append(signal) @@ -651,7 +640,6 @@ class GLibTransformer(object): # Workaround glib bug #548689, to be included in 2.18.0 if type_name == "GParam": type_name = "GObject.ParamSpec" - res = self._transformer.resolve_type_name_full try: return res(type_name, ctype, self._names) @@ -659,6 +647,9 @@ class GLibTransformer(object): return self._transformer.resolve_type_name(type_name, ctype) def _resolve_param_type(self, ptype, **kwargs): + # Workaround glib bug #548689, to be included in 2.18.0 + if ptype.name == "GParam": + ptype.name = "GObject.ParamSpec" return self._transformer.resolve_param_type_full(ptype, self._names, **kwargs) @@ -783,43 +774,23 @@ class GLibTransformer(object): prop.type = self._resolve_param_type(prop.type, allow_invalid=False) def _adjust_transfer(self, param): - # Do GLib/GObject-specific type transformations here - - transfer = None - is_object = None - if hasattr(param.type, '_gtype'): - ftype = cgobject.type_fundamental(param.type._gtype) - assert ftype != cgobject.TYPE_INVALID, param.type._gtype + if not (param.transfer is None or param.transfer_inferred): + return - is_object = ftype in [cgobject.TYPE_OBJECT, - cgobject.TYPE_INTERFACE] + # Do GLib/GObject-specific type transformations here + node = self._lookup_node(param.type.name) + if node is None: + return - if ftype in [cgobject.TYPE_OBJECT, - cgobject.TYPE_INTERFACE, - cgobject.TYPE_STRING, - cgobject.TYPE_BOXED, - cgobject.TYPE_PARAM]: + if isinstance(param, Parameter): + if param.direction != PARAM_DIRECTION_IN: transfer = 'full' else: - # if type is a cgobject.TYPE_POINTER we could require direction - # and transfer-ownership annotations transfer = 'none' - - if is_object is None: - is_object = (param.type.name == 'GObject.Object' or - (self._namespace_name == 'GObject' and - param.type.name == 'Object')) - - # Default to full transfer for GObjects - if isinstance(param, Parameter): - is_out = (param.direction != PARAM_DIRECTION_IN) else: - is_out = True - if param.transfer is None or param.transfer_inferred: - if is_out and is_object: - param.transfer = 'full' - elif transfer is not None: - param.transfer = transfer + transfer = 'full' + + param.transfer = transfer def _adjust_throws(self, func): if func.parameters == []: diff --git a/giscanner/transformer.py b/giscanner/transformer.py index c512f7a4..fbf82ffd 100644 --- a/giscanner/transformer.py +++ b/giscanner/transformer.py @@ -142,7 +142,8 @@ class Transformer(object): self._names.aliases[node.name] = (nsname, node) elif isinstance(node, (GLibBoxed, Interface, Class)): self._names.type_names[node.type_name] = (nsname, node) - self._names.names[node.name] = (nsname, node) + giname = '%s.%s' % (nsname, node.name) + self._names.names[giname] = (nsname, node) if hasattr(node, 'ctype'): self._names.ctypes[node.ctype] = (nsname, node) elif hasattr(node, 'symbol'): @@ -370,7 +371,7 @@ class Transformer(object): "symbol %r of type %s" % (symbol.ident, ctype_name(ctype))) return node - def _parse_ctype(self, ctype): + def parse_ctype(self, ctype): # First look up the ctype including any pointers; # a few type names like 'char*' have their own aliases # and we need pointer information for those. @@ -398,29 +399,29 @@ class Transformer(object): if ctype in self._list_ctypes: param = options.get('element-type') if param: - contained_type = self._parse_ctype(param[0]) + contained_type = self.parse_ctype(param[0]) else: contained_type = None - derefed_name = self._parse_ctype(ctype) + derefed_name = self.parse_ctype(ctype) rettype = List(derefed_name, ctype, contained_type) elif ctype in self._map_ctypes: param = options.get('element-type') if param: - key_type = self._parse_ctype(param[0]) - value_type = self._parse_ctype(param[1]) + key_type = self.parse_ctype(param[0]) + value_type = self.parse_ctype(param[1]) else: key_type = None value_type = None - derefed_name = self._parse_ctype(ctype) + derefed_name = self.parse_ctype(ctype) rettype = Map(derefed_name, ctype, key_type, value_type) elif (ctype in default_array_types) or ('array' in options): derefed_name = ctype[:-1] if ctype[-1] == '*' else ctype rettype = Array(ctype, - self._parse_ctype(derefed_name)) + self.parse_ctype(derefed_name)) array_opts = dict([opt.split('=') for opt in options.get('array', [])]) if 'length' in array_opts: @@ -429,7 +430,7 @@ class Transformer(object): rettype.size = array_opts['fixed-size'] rettype.zeroterminated = False else: - derefed_name = self._parse_ctype(ctype) + derefed_name = self.parse_ctype(ctype) rettype = Type(derefed_name, ctype) # Deduce direction for some types passed by reference that diff --git a/tests/everything/Makefile.am b/tests/everything/Makefile.am index 8f3eceb6..ec209d51 100644 --- a/tests/everything/Makefile.am +++ b/tests/everything/Makefile.am @@ -1,3 +1,5 @@ +include $(top_srcdir)/common.mk + LT_CURRENT = 1 LT_REVISION = 0 LT_AGE = 0 @@ -23,18 +25,13 @@ AM_LDFLAGS += -no-undefined endif GIRS = -SCANNER = $(top_srcdir)/tools/g-ir-scanner -SCANNER_PYTHONPATH = $(top_builddir):$(top_srcdir):$$PYTHONPATH -SCANNER_LIBS = $(top_srcdir)/giscanner/*.py \ - $(top_builddir)/giscanner/libgiscanner.la TYPELIBS = $(GIRS:.gir=.typelib) TXMLS = $(GIRS:.gir=.gir.txml) CLEANFILES = $(TYPELIBS) $(TXMLS) $(GIRS) BUILT_SOURCES = $(TYPELIBS) $(TXMLS) $(GIRS) -Everything-$(TYPELIB_VERSION).gir: libgirepository-everything.la gitesttypes.c gitesttypes.h $(SCANNER) $(SCANNER_LIBS) - PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \ - --add-include-path=$(top_builddir)/gir \ +Everything-$(TYPELIB_VERSION).gir: libgirepository-everything.la gitesttypes.c gitesttypes.h $(SCANNER_BIN) $(SCANNER_LIBS) + $(CHECK_DEBUG) $(SCANNER) \ --include=GObject-2.0 \ --library=girepository-everything \ --namespace=Everything --nsversion=$(TYPELIB_VERSION) \ diff --git a/tests/offsets/Makefile.am b/tests/offsets/Makefile.am index 57cfdfb7..2c3cae20 100644 --- a/tests/offsets/Makefile.am +++ b/tests/offsets/Makefile.am @@ -1,3 +1,5 @@ +include $(top_srcdir)/common.mk + BUILT_SOURCES = CLEANFILES = EXTRA_DIST = @@ -5,12 +7,6 @@ EXTRA_DIST = check_LTLIBRARIES = check_PROGRAMS = -SCANNER = $(top_srcdir)/tools/g-ir-scanner -SCANNER_PYTHONPATH = $(top_builddir):$(top_srcdir):$$PYTHONPATH -SCANNER_LIBS = \ - $(top_srcdir)/giscanner/*.py \ - $(top_builddir)/giscanner/libgiscanner.la - ############################################################ check_LTLIBRARIES += liboffsets.la @@ -20,11 +16,10 @@ liboffsets_la_SOURCES = \ offsets.c liboffsets_la_CPPFLAGS = $(GIREPO_CFLAGS) # dummy rpath to get built dynamically (huh?) -liboffsets_la_LDFLAGS = -module -avoid-version -rpath $(libdir) +liboffsets_la_LDFLAGS = -avoid-version -rpath $(libdir) -offsets-1.0.gir: liboffsets.la offsets.h $(SCANNER) $(SCANNER_LIBS) Makefile - PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \ - --add-include-path=$(top_builddir)/gir --add-include-path=. \ +offsets-1.0.gir: liboffsets.la offsets.h $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(CHECK_DEBUG) $(SCANNER) \ --library=offsets \ --namespace=offsets \ --nsversion=1.0 \ diff --git a/tests/scanner/Makefile.am b/tests/scanner/Makefile.am index 9fba3b0f..ae42ccea 100644 --- a/tests/scanner/Makefile.am +++ b/tests/scanner/Makefile.am @@ -1,3 +1,5 @@ +include $(top_srcdir)/common.mk + # We need to build a shared library, which can be dlopened # it does not work with noinst_LTLIBRARIES testlib_LTLIBRARIES = \ @@ -9,9 +11,10 @@ testlib_LTLIBRARIES = \ testlibdir = $(prefix)/unused install-testlibLTLIBRARIES: # prevent it from being installed -AM_CFLAGS = $(GOBJECT_CFLAGS) -AM_LDFLAGS = -module -avoid-version -LIBS = $(GOBJECT_LIBS) +AM_CPPFLAGS = -I$(top_srcdir)/girepository +AM_CFLAGS = $(GOBJECT_CFLAGS) $(GTHREAD_CFLAGS) +AM_LDFLAGS = -avoid-version +LIBS = $(GOBJECT_LIBS) $(GTHREAD_LIBS) libannotation_la_SOURCES = $(srcdir)/annotation.c $(srcdir)/annotation.h libdrawable_la_SOURCES = $(srcdir)/drawable.c $(srcdir)/drawable.h @@ -25,11 +28,6 @@ endif # .gir --[scanner]-> .typelib --[generate]-> .tgir GIRS = -SCANNER = $(top_srcdir)/tools/g-ir-scanner -SCANNER_PYTHONPATH = $(top_builddir):$(top_srcdir):$$PYTHONPATH -SCANNER_LIBS = \ - $(top_srcdir)/giscanner/*.py \ - $(top_builddir)/giscanner/libgiscanner.la TYPELIBS = $(GIRS:.gir=.typelib) CHECKGIRS = $(GIRS:.gir=.gir.check) EXPECTEDGIRS = $(GIRS:.gir=-expected.gir) @@ -40,9 +38,8 @@ CLEANFILES = $(TYPELIBS) $(GIRS) $(TGIRS) BUILT_SOURCES = $(TYPELIBS) $(GIRS) EXTRA_DIST = $(EXPECTEDGIRS) $(EXPECTEDTGIRS) -annotation-1.0.gir: libannotation.la annotation.c annotation.h utility-1.0.gir $(SCANNER) $(SCANNER_LIBS) Makefile - PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \ - --add-include-path=$(top_builddir)/gir --add-include-path=. \ +annotation-1.0.gir: libannotation.la annotation.c annotation.h utility-1.0.gir $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(CHECK_DEBUG) $(SCANNER) \ --include=GObject-2.0 \ --include=utility-1.0 \ --library=annotation \ @@ -53,9 +50,8 @@ annotation-1.0.gir: libannotation.la annotation.c annotation.h utility-1.0.gir $ --output $@ GIRS += annotation-1.0.gir -drawable-1.0.gir: libdrawable.la drawable.c drawable.h utility-1.0.gir $(SCANNER) $(SCANNER_LIBS) Makefile - PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \ - --add-include-path=$(top_builddir)/gir --add-include-path=. \ +drawable-1.0.gir: libdrawable.la drawable.c drawable.h utility-1.0.gir $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(CHECK_DEBUG) $(SCANNER) \ --include=GObject-2.0 \ --include=utility-1.0 \ --library=drawable \ @@ -66,15 +62,14 @@ drawable-1.0.gir: libdrawable.la drawable.c drawable.h utility-1.0.gir $(SCANNER --output $@ GIRS += drawable-1.0.gir -drawable-injected-1.0.gir: drawable-1.0.gir $(SCANNER) $(SCANNER_LIBS) Makefile - PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \ +drawable-injected-1.0.gir: drawable-1.0.gir $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(CHECK_DEBUG) $(SCANNER) -v \ --inject drawable-1.0.gir $(srcdir)/DrawableAdditions.xml $@ GIRS += drawable-injected-1.0.gir EXTRA_DIST += DrawableAdditions.xml -foo-1.0.gir: libfoo.la foo.c foo.h utility-1.0.gir $(SCANNER) $(SCANNER_LIBS) Makefile - PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \ - --add-include-path=$(top_builddir)/gir --add-include-path=. \ +foo-1.0.gir: libfoo.la foo.c foo.h utility-1.0.gir $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(CHECK_DEBUG) $(SCANNER) \ --include=GObject-2.0 \ --include=utility-1.0 \ --library=foo \ @@ -85,9 +80,8 @@ foo-1.0.gir: libfoo.la foo.c foo.h utility-1.0.gir $(SCANNER) $(SCANNER_LIBS) Ma --output $@ GIRS += foo-1.0.gir -utility-1.0.gir: libutility.la utility.h $(SCANNER) $(SCANNER_LIBS) Makefile - PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \ - --add-include-path=$(top_builddir)/gir --add-include-path=. \ +utility-1.0.gir: libutility.la utility.h $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(CHECK_DEBUG) $(SCANNER) \ --include=GObject-2.0 \ --library=utility \ --namespace=utility \ @@ -98,9 +92,8 @@ utility-1.0.gir: libutility.la utility.h $(SCANNER) $(SCANNER_LIBS) Makefile GIRS += utility-1.0.gir # This one tests different --namespace and --strip-prefix -GtkFrob-1.0.gir: libgtkfrob.la gtkfrob.h $(SCANNER) $(SCANNER_LIBS) Makefile - PYTHONPATH=$(SCANNER_PYTHONPATH) $(CHECK_DEBUG) $(SCANNER) -v \ - --add-include-path=$(top_builddir)/gir --add-include-path=. \ +GtkFrob-1.0.gir: libgtkfrob.la gtkfrob.h $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(CHECK_DEBUG) $(SCANNER) \ --include=GObject-2.0 \ --library=gtkfrob \ --namespace=GtkFrob \ @@ -111,6 +104,23 @@ GtkFrob-1.0.gir: libgtkfrob.la gtkfrob.h $(SCANNER) $(SCANNER_LIBS) Makefile --output $@ GIRS += GtkFrob-1.0.gir +bin_PROGRAMS = barapp + +barapp_SOURCES = barapp.c barapp.h +barapp_LDADD = $(top_builddir)/girepository/libgirepository.la +barapp_LDFLAGS = -export-dynamic +BarApp-1.0.gir: barapp $(SCANNER_BIN) $(SCANNER_LIBS) Makefile + $(SCANNER) \ + --include=GObject-2.0 \ + --program=./barapp \ + --namespace=BarApp \ + --strip-prefix=Bar \ + --nsversion=1.0 \ + --pkg gobject-2.0 \ + $(barapp_SOURCES) \ + --output $@ +GIRS += BarApp-1.0.gir + pre-check: @if test "$(top_builddir)" != "$(top_srcdir)"; then \ cp -f $(top_srcdir)/giscanner/*.py $(top_builddir)/giscanner; \ diff --git a/tests/scanner/annotation-1.0-expected.gir b/tests/scanner/annotation-1.0-expected.gir index 4f080dc0..1a859b3c 100644 --- a/tests/scanner/annotation-1.0-expected.gir +++ b/tests/scanner/annotation-1.0-expected.gir @@ -62,7 +62,7 @@ <type name="GObject.Object" c:type="GObject*"/> </return-value> <parameters> - <parameter name="somearg" transfer-ownership="full" allow-none="1"> + <parameter name="somearg" transfer-ownership="none" allow-none="1"> <type name="utf8" c:type="gchar*"/> </parameter> </parameters> diff --git a/tests/scanner/annotation-1.0-expected.tgir b/tests/scanner/annotation-1.0-expected.tgir index e6f3a18f..3a4067be 100644 --- a/tests/scanner/annotation-1.0-expected.tgir +++ b/tests/scanner/annotation-1.0-expected.tgir @@ -60,7 +60,7 @@ <type name="GObject.Object"/> </return-value> <parameters> - <parameter name="somearg" transfer-ownership="full" allow-none="1"> + <parameter name="somearg" transfer-ownership="none" allow-none="1"> <type name="utf8"/> </parameter> </parameters> diff --git a/tests/scanner/annotation.c b/tests/scanner/annotation.c index bcfe55fa..ef521a23 100644 --- a/tests/scanner/annotation.c +++ b/tests/scanner/annotation.c @@ -247,7 +247,7 @@ annotation_object_compute_sum_n(AnnotationObject *object, * @somearg: (allow-none): **/ GObject* -annotation_object_allow_none (AnnotationObject *object, gchar *somearg) +annotation_object_allow_none (AnnotationObject *object, const gchar *somearg) { return NULL; } diff --git a/tests/scanner/annotation.h b/tests/scanner/annotation.h index ea78786a..3eb9fcb8 100644 --- a/tests/scanner/annotation.h +++ b/tests/scanner/annotation.h @@ -39,7 +39,7 @@ gint annotation_object_out (AnnotationObject *object, int *outarg); GObject* annotation_object_create_object(AnnotationObject *object); GObject* annotation_object_allow_none (AnnotationObject *object, - gchar *somearg); + const gchar *somearg); GObject* annotation_object_notrans (AnnotationObject *object); gint annotation_object_inout (AnnotationObject *object, int *inoutarg); diff --git a/tests/scanner/foo-1.0-expected.gir b/tests/scanner/foo-1.0-expected.gir index d55bc8dd..312db61e 100644 --- a/tests/scanner/foo-1.0-expected.gir +++ b/tests/scanner/foo-1.0-expected.gir @@ -157,7 +157,7 @@ <type name="utf8" c:type="gchararray"/> </return-value> <parameters> - <parameter name="object" transfer-ownership="full"> + <parameter name="object" transfer-ownership="none"> <type name="GObject.Object" c:type="GObject"/> </parameter> <parameter name="p0" transfer-ownership="none"> diff --git a/tests/scanner/foo-1.0-expected.tgir b/tests/scanner/foo-1.0-expected.tgir index d3e82e1a..5a457f89 100644 --- a/tests/scanner/foo-1.0-expected.tgir +++ b/tests/scanner/foo-1.0-expected.tgir @@ -101,7 +101,7 @@ <type name="utf8"/> </return-value> <parameters> - <parameter name="object" transfer-ownership="full"> + <parameter name="object" transfer-ownership="none"> <type name="GObject.Object"/> </parameter> <parameter name="p0" transfer-ownership="none"> diff --git a/tools/g-ir-scanner b/tools/g-ir-scanner index 337f9b6e..0f460183 100755 --- a/tools/g-ir-scanner +++ b/tools/g-ir-scanner @@ -43,12 +43,12 @@ sys.path.insert(0, path) from giscanner.ast import Include from giscanner.cachestore import CacheStore -from giscanner.glibtransformer import GLibTransformer +from giscanner.dumper import compile_introspection_binary +from giscanner.glibtransformer import GLibTransformer, IntrospectionBinary from giscanner.minixpath import myxpath, xpath_assert from giscanner.sourcescanner import SourceScanner from giscanner.transformer import Transformer - def _get_option_parser(): parser = optparse.OptionParser('%prog [options] sources') parser.add_option("", "--format", @@ -58,9 +58,18 @@ def _get_option_parser(): parser.add_option("-i", "--include", action="append", dest="includes", default=[], help="include types for other gidls") - parser.add_option("--add-include-path", + parser.add_option("", "--add-include-path", action="append", dest="include_paths", default=[], help="include paths for other GIR files") + parser.add_option("", "--program", + action="store", dest="program", default=None, + help="program to execute") + parser.add_option("", "--program-arg", + action="append", dest="program_args", default=[], + help="extra arguments to program") + parser.add_option("", "--no-libtool", + action="store_true", dest="nolibtool", default=False, + help="use libtool") parser.add_option("-l", "--library", action="append", dest="libraries", default=[], help="libraries of this unit") @@ -209,8 +218,9 @@ def main(args): else: _error("Unknown format: %s" % (options.format, )) - if not options.libraries: - _error("Must specify --library at least one primary library") + if not (options.libraries or options.program): + _error("Must specify --program or --library") + libraries = options.libraries for package in options.packages: output = subprocess.Popen(['pkg-config', '--cflags', package], @@ -285,13 +295,17 @@ def main(args): include_obj = Include.from_string(include) transformer.register_include(include_obj) + if options.program: + args=[options.program] + args.extend(options.program_args) + binary = IntrospectionBinary(args) + else: + binary = compile_introspection_binary(options) + # Transform the C AST nodes into higher level # GLib/GObject nodes glibtransformer = GLibTransformer(transformer, noclosure=options.noclosure) - libraries = [] - if options.libraries: - for library in options.libraries: - libraries.append(glibtransformer.add_library(library)) + glibtransformer.set_introspection_binary(binary) namespace = glibtransformer.parse() |