gir: Do not include generated gir files in the distribution
[gnome.gobject-introspection] / giscanner / shlibs.py
1 #!/usr/bin/env python
2 # -*- Mode: Python -*-
3 # GObject-Introspection - a framework for introspecting GObject libraries
4 # Copyright (C) 2009 Red Hat, Inc.
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20 #
21
22 import re
23 import subprocess
24
25 from .utils import get_libtool_command, extract_libtool_shlib
26
27 # For .la files, the situation is easy.
28 def _resolve_libtool(options, binary, libraries):
29     shlibs = []
30     for library in libraries:
31         shlib = extract_libtool_shlib(library)
32         if shlib:
33             shlibs.append(shlib)
34
35     return shlibs
36
37 # Assume ldd output is something vaguely like
38 #
39 #  libpangoft2-1.0.so.0 => /usr/lib/libpangoft2-1.0.so.0 (0x006c1000)
40 #
41 # We say that if something in the output looks like libpangoft2<blah>
42 # then the *first* such in the output is the soname. We require <blah>
43 # to start with [^A-Za-z0-9_-] to avoid problems with libpango vs libpangoft2
44 #
45 # The negative lookbehind at the start is to avoid problems if someone
46 # is crazy enough to name a library liblib<foo> when lib<foo> exists.
47 #
48 def _ldd_library_pattern(library_name):
49     return re.compile("(?<![A-Za-z0-9_-])(lib*%s[^A-Za-z0-9_-][^\s\(\)]*)"
50                       % re.escape(library_name))
51
52 # This is a what we do for non-la files. We assume that we are on an
53 # ELF-like system where ldd exists and the soname extracted with ldd is
54 # a filename that can be opened with dlopen().
55 #
56 # On OS X this will need a straightforward alternate implementation
57 # in terms of otool.
58 #
59 # Windows is more difficult, since there isn't always a straightforward
60 # translation between library name (.lib) and the name of the .dll, so
61 # extracting the dll names from the compiled app may not be sufficient.
62 # We might need to hunt down the .lib in the compile-time path and
63 # use that to figure out the name of the DLL.
64 #
65 def _resolve_non_libtool(options, binary, libraries):
66     if not libraries:
67         return []
68
69     args = []
70     libtool = get_libtool_command(options)
71     if libtool:
72         args.extend(libtool)
73         args.append('--mode=execute')
74     args.extend(['ldd', binary.args[0]])
75     proc = subprocess.Popen(args, stdout=subprocess.PIPE)
76     patterns = {}
77     for library in libraries:
78         patterns[library] = _ldd_library_pattern(library)
79
80     shlibs = []
81     for line in proc.stdout:
82         for library, pattern in patterns.iteritems():
83             m = pattern.search(line)
84             if m:
85                 del patterns[library]
86                 shlibs.append(m.group(1))
87                 break
88
89     if len(patterns) > 0:
90         raise SystemExit(
91             "ERROR: can't resolve libraries to shared libraries: " +
92             ", ".join(patterns.keys()))
93
94     return shlibs
95
96 # We want to resolve a set of library names (the <foo> of -l<foo>)
97 # against a library to find the shared library name. The shared
98 # library name is suppose to be what you pass to dlopen() (or
99 # equivalent). And we want to do this using the libraries that 'binary'
100 # is linking against.
101 #
102 def resolve_shlibs(options, binary, libraries):
103     libtool = filter(lambda x: x.endswith(".la"), libraries)
104     non_libtool = filter(lambda x: not x.endswith(".la"), libraries)
105
106     return (_resolve_libtool(options, binary, libtool) +
107             _resolve_non_libtool(options, binary, non_libtool))