libtoolimporter.py \
minixpath.py \
odict.py \
+ shlibs.py \
scannermain.py \
sourcescanner.py \
transformer.py \
import tempfile
from .glibtransformer import IntrospectionBinary
+from .utils import get_libtool_command
# bugzilla.gnome.org/558436
# Compile a binary program which is then linked to a library
stdout=subprocess.PIPE)
return proc.communicate()[0].split()
- def _use_libtool_infection(self):
- libtool_infection = not self._options.nolibtool
- if not libtool_infection:
- return None
-
- libtool_path = self._options.libtool_path
- if libtool_path:
- # Automake by default sets:
- # LIBTOOL = $(SHELL) $(top_builddir)/libtool
- # To be strictly correct we would have to parse shell. For now
- # we simply split().
- return libtool_path.split(' ')
-
- try:
- subprocess.check_call(['libtool', '--version'])
- except subprocess.CalledProcessError, e:
- # If libtool's not installed, assume we don't need it
- return None
-
- return ['libtool']
-
def _compile(self, output, *sources):
# Not strictly speaking correct, but easier than parsing shell
args = self._compiler_cmd.split()
def _link(self, output, *sources):
args = []
- libtool = self._use_libtool_infection()
+ libtool = get_libtool_command(self._options)
if libtool:
args.extend(libtool)
args.append('--mode=link')
from __future__ import with_statement
import os
-from ctypes.util import find_library
from .ast import (Alias, Array, Bitfield, Callback, Class, Constant, Enum,
Function, Interface, List, Map, Member, Struct, Union,
self.write_tag('c:include', attrs)
def _write_namespace(self, namespace, shlibs, cprefix):
- libraries = []
- for l in shlibs:
- found_libname = find_library(l)
- if not found_libname:
- found_libname = l
- libraries.append(os.path.basename(found_libname))
-
attrs = [('name', namespace.name),
('version', namespace.version),
- ('shared-library', ','.join(libraries)),
+ ('shared-library', ','.join(shlibs)),
('c:prefix', cprefix)]
with self.tagcontext('namespace', attrs):
# We define a custom sorting function here because
from giscanner.glibtransformer import GLibTransformer, IntrospectionBinary
from giscanner.minixpath import myxpath, xpath_assert
from giscanner.sourcescanner import SourceScanner
+from giscanner.shlibs import resolve_shlibs
from giscanner.transformer import Transformer
def _get_option_parser():
binary = compile_introspection_binary(options,
glibtransformer.get_get_type_functions())
+ shlibs = resolve_shlibs(options, binary, libraries)
+
glibtransformer.set_introspection_binary(binary)
namespace = glibtransformer.parse()
raise SystemExit("ERROR in annotation: %s" % (str(e), ))
# Write out AST
- writer = Writer(namespace, libraries, transformer.get_includes(),
+ writer = Writer(namespace, shlibs, transformer.get_includes(),
options.packages, options.c_includes,
transformer.get_strip_prefix())
data = writer.get_xml()
--- /dev/null
+#!/usr/bin/env python
+# -*- Mode: Python -*-
+# GObject-Introspection - a framework for introspecting GObject libraries
+# Copyright (C) 2009 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+import re
+import subprocess
+
+from .utils import get_libtool_command
+
+# Assume ldd output is something vaguely like
+#
+# libpangoft2-1.0.so.0 => /usr/lib/libpangoft2-1.0.so.0 (0x006c1000)
+#
+# We say that if something in the output looks like libpangoft2<blah>
+# then the *first* such in the output is the soname. We require <blah>
+# to start with [^A-Za-z0-9_-] to avoid problems with libpango vs libpangoft2
+#
+# The negative lookbehind at the start is to avoid problems if someone
+# is crazy enough to name a library liblib<foo> when lib<foo> exists.
+#
+def _library_pattern(library_name):
+ return re.compile("(?<![A-Za-z0-9_-])(lib*%s[^A-Za-z0-9_-][^\s\(\)]*)"
+ % re.escape(library_name))
+
+# We want to resolve a set of library names (the <foo> of -l<foo>)
+# against a library to find the shared library name. The shared
+# library name is suppose to be what you pass to dlopen() (or
+# equivalent). And we want to do this using the libraries that 'binary'
+# is linking against. The implementation below assumes that we are on an
+# ELF-like system where ldd exists and the soname extracted with ldd is
+# a filename that can be opened with dlopen(). Alternate implementations
+# could be added here.
+#
+def resolve_shlibs(options, binary, libraries):
+ args = []
+ libtool = get_libtool_command(options)
+ if libtool:
+ args.extend(libtool)
+ args.append('--mode=execute')
+ args.extend(['ldd', binary.args[0]])
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ patterns = {}
+ for library in libraries:
+ patterns[library] = _library_pattern(library)
+
+ shlibs = []
+ for line in proc.stdout:
+ for library, pattern in patterns.iteritems():
+ m = pattern.search(line)
+ if m:
+ del patterns[library]
+ shlibs.append(m.group(1))
+ break
+
+ if len(patterns) > 0:
+ raise SystemExit(
+ "ERROR: can't resolve libraries to shared libraries: " +
+ ", ".join(patterns.keys()))
+
+ return shlibs
# and pre-2.2. Johan 2008-10-21
libname = libname.replace('.libs/.libs', '.libs')
return libname
+
+# Returns arguments for invoking libtool, if applicable, otherwise None
+def get_libtool_command(options):
+ libtool_infection = not options.nolibtool
+ if not libtool_infection:
+ return None
+
+ libtool_path = options.libtool_path
+ if libtool_path:
+ # Automake by default sets:
+ # LIBTOOL = $(SHELL) $(top_builddir)/libtool
+ # To be strictly correct we would have to parse shell. For now
+ # we simply split().
+ return libtool_path.split(' ')
+
+ try:
+ subprocess.check_call(['libtool', '--version'])
+ except subprocess.CalledProcessError, e:
+ # If libtool's not installed, assume we don't need it
+ return None
+
+ return ['libtool']
@true
%.typelib: %.gir $(top_builddir)/tools/g-ir-compiler$(EXEEXT) Makefile
- LD_LIBRARY_PATH=$(top_builddir)/girepository/.libs$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} $(top_builddir)/tools/g-ir-compiler --includedir=. --includedir=$(top_builddir)/gir $< -o $@
+ LD_LIBRARY_PATH=$(top_builddir)/girepository/.libs:$(builddir)/.libs$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} $(top_builddir)/tools/g-ir-compiler --includedir=. --includedir=$(top_builddir)/gir $< -o $@
%.tgir: %.typelib $(top_builddir)/tools/g-ir-generate$(EXEEXT) Makefile
- LD_LIBRARY_PATH=$(top_builddir)/girepository/.libs$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} $(top_builddir)/tools/g-ir-generate --includedir=. --includedir=$(top_builddir)/gir $< -o $@
+ LD_LIBRARY_PATH=$(top_builddir)/girepository/.libs:$(builddir)/.libs$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} $(top_builddir)/tools/g-ir-generate --includedir=. --includedir=$(top_builddir)/gir $< -o $@
%.tgir.check: %.tgir
@diff -u -U 10 $(srcdir)/$*-expected.tgir $*.tgir; \