[gobject-introspection] Resolve library names to shared libraries ourselves
- From: Colin Walters <walters src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gobject-introspection] Resolve library names to shared libraries ourselves
- Date: Mon, 17 Aug 2009 04:24:52 +0000 (UTC)
commit af6bcb48d777f683384d9b8497e1b0edba5b16e7
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Thu Aug 13 16:09:27 2009 -0400
Resolve library names to shared libraries ourselves
Using ctypes.util.find_library() to resolve library names to
sonames causes problems with dealing with uninstalled libtool
operation properly. We're unlikely to find any way of combining
the two that will be robust against future changes in both
facilities.
Switch to a different approach - run 'ldd' on the compiled
introspection binary and extract sonames from there This is
less portable but should be quite robust where it works.
utils.py dumper.py: Move libtool-command-line finding into utils.py
girwriter.py: Remove library name resolution from here, expect libraries
to be passed in preresolved.
shlibs.py scannermain.py: New file including resolve_shlibs() to resolve
library names using the introspection binary.
tests/scanner/Makefile.am: Add .libs to LD_LIBRARY_PATH
http://bugzilla.gnome.org/show_bug.cgi?id=591669
giscanner/Makefile.am | 1 +
giscanner/dumper.py | 24 +-------------
giscanner/girwriter.py | 10 +-----
giscanner/scannermain.py | 5 ++-
giscanner/shlibs.py | 77 +++++++++++++++++++++++++++++++++++++++++++++
giscanner/utils.py | 22 +++++++++++++
tests/scanner/Makefile.am | 4 +-
7 files changed, 109 insertions(+), 34 deletions(-)
---
diff --git a/giscanner/Makefile.am b/giscanner/Makefile.am
index 1ecd977..098235b 100644
--- a/giscanner/Makefile.am
+++ b/giscanner/Makefile.am
@@ -47,6 +47,7 @@ pkgpyexec_PYTHON = \
libtoolimporter.py \
minixpath.py \
odict.py \
+ shlibs.py \
scannermain.py \
sourcescanner.py \
transformer.py \
diff --git a/giscanner/dumper.py b/giscanner/dumper.py
index 622b252..b8f16c9 100644
--- a/giscanner/dumper.py
+++ b/giscanner/dumper.py
@@ -24,6 +24,7 @@ import subprocess
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
@@ -146,27 +147,6 @@ class DumpCompiler(object):
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()
@@ -189,7 +169,7 @@ class DumpCompiler(object):
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')
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index ddd562c..aad55ef 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -22,7 +22,6 @@
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,
@@ -80,16 +79,9 @@ and/or use gtk-doc annotations. ''')
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
diff --git a/giscanner/scannermain.py b/giscanner/scannermain.py
index e280159..4b74253 100644
--- a/giscanner/scannermain.py
+++ b/giscanner/scannermain.py
@@ -32,6 +32,7 @@ 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.shlibs import resolve_shlibs
from giscanner.transformer import Transformer
def _get_option_parser():
@@ -319,6 +320,8 @@ def scanner_main(args):
binary = compile_introspection_binary(options,
glibtransformer.get_get_type_functions())
+ shlibs = resolve_shlibs(options, binary, libraries)
+
glibtransformer.set_introspection_binary(binary)
namespace = glibtransformer.parse()
@@ -330,7 +333,7 @@ def scanner_main(args):
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()
diff --git a/giscanner/shlibs.py b/giscanner/shlibs.py
new file mode 100644
index 0000000..38a89e2
--- /dev/null
+++ b/giscanner/shlibs.py
@@ -0,0 +1,77 @@
+#!/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
diff --git a/giscanner/utils.py b/giscanner/utils.py
index d2752e7..3a26a1e 100644
--- a/giscanner/utils.py
+++ b/giscanner/utils.py
@@ -57,3 +57,25 @@ def extract_libtool(libname):
# 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']
diff --git a/tests/scanner/Makefile.am b/tests/scanner/Makefile.am
index ed8d396..36aedbf 100644
--- a/tests/scanner/Makefile.am
+++ b/tests/scanner/Makefile.am
@@ -143,10 +143,10 @@ post-check:
@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; \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]