1bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panterimport os
2bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panterimport shutil
38c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrouimport subprocess
4bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panterimport sys
5477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
6477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters# find_library(name) returns the pathname of a library, or None.
7477c8d5e70240744d24631b18341ad892c8a8e1cThomas Woutersif os.name == "nt":
83eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller
93eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller    def _get_build_version():
103eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        """Return the version of MSVC that was used to build Python.
113eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller
123eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        For Python 2.3 and up, the version number is included in
133eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        sys.version.  For earlier versions, assume the compiler is MSVC 6.
143eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        """
153eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        # This function was copied from Lib/distutils/msvccompiler.py
163eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        prefix = "MSC v."
173eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        i = sys.version.find(prefix)
183eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        if i == -1:
193eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            return 6
203eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        i = i + len(prefix)
213eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        s, rest = sys.version[i:].split(" ", 1)
223eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        majorVersion = int(s[:-2]) - 6
2365e4cb10d9d9964f30bc72561bf0e86833328a3bSteve Dower        if majorVersion >= 13:
2465e4cb10d9d9964f30bc72561bf0e86833328a3bSteve Dower            majorVersion += 1
253eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        minorVersion = int(s[2:3]) / 10.0
263eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        # I don't think paths are affected by minor version in version 6
273eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        if majorVersion == 6:
283eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            minorVersion = 0
293eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        if majorVersion >= 6:
303eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            return majorVersion + minorVersion
313eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        # else we don't know what version of the compiler this is
323eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        return None
333eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller
343eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller    def find_msvcrt():
353eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        """Return the name of the VC runtime dll"""
363eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        version = _get_build_version()
373eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        if version is None:
383eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            # better be safe than sorry
393eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            return None
403eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        if version <= 6:
413eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            clibname = 'msvcrt'
4265e4cb10d9d9964f30bc72561bf0e86833328a3bSteve Dower        elif version <= 13:
433eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            clibname = 'msvcr%d' % (version * 10)
4465e4cb10d9d9964f30bc72561bf0e86833328a3bSteve Dower        else:
45959ee7c200373e77cae445283016f2827147e96aSteve Dower            # CRT is no longer directly loadable. See issue23606 for the
46959ee7c200373e77cae445283016f2827147e96aSteve Dower            # discussion about alternative approaches.
47959ee7c200373e77cae445283016f2827147e96aSteve Dower            return None
483eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller
493eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        # If python was built with in debug mode
50cb66eb0deca1d5cd232f97c76a215ecaab958d30Brett Cannon        import importlib.machinery
51cb66eb0deca1d5cd232f97c76a215ecaab958d30Brett Cannon        if '_d.pyd' in importlib.machinery.EXTENSION_SUFFIXES:
523eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            clibname += 'd'
533eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        return clibname+'.dll'
543eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller
55477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    def find_library(name):
563eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller        if name in ('c', 'm'):
573eaaeb437f7283ef60ead8464d8da6bfac4f93aaThomas Heller            return find_msvcrt()
58477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        # See MSDN for the REAL search order.
59477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        for directory in os.environ['PATH'].split(os.pathsep):
60477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters            fname = os.path.join(directory, name)
6100cfc379d66c056ed5ac5a9df5b75c86f3fc7fbeThomas Heller            if os.path.isfile(fname):
62477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters                return fname
63477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters            if fname.lower().endswith(".dll"):
64477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters                continue
65477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters            fname = fname + ".dll"
6600cfc379d66c056ed5ac5a9df5b75c86f3fc7fbeThomas Heller            if os.path.isfile(fname):
67477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters                return fname
68477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        return None
69477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
70477c8d5e70240744d24631b18341ad892c8a8e1cThomas Woutersif os.name == "posix" and sys.platform == "darwin":
71477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    from ctypes.macholib.dyld import dyld_find as _dyld_find
72477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    def find_library(name):
73477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        possible = ['lib%s.dylib' % name,
74477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters                    '%s.dylib' % name,
75477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters                    '%s.framework/%s' % (name, name)]
76477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        for name in possible:
77477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters            try:
78477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters                return _dyld_find(name)
79477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters            except ValueError:
80477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters                continue
81477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        return None
82477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
83477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouterselif os.name == "posix":
84477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
857fa767e517882f4d3503d168d3a4d4caad317752Victor Stinner    import re, tempfile
86477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
87477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    def _findLib_gcc(name):
88bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        # Run GCC's linker with the -t (aka --trace) option and examine the
89bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        # library name it prints out. The GCC command will fail because we
90bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        # haven't supplied a proper program with main(), but that does not
91bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        # matter.
92bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        expr = os.fsencode(r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name))
93bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter
94bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        c_compiler = shutil.which('gcc')
95bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        if not c_compiler:
96bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            c_compiler = shutil.which('cc')
97bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        if not c_compiler:
98bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            # No C compiler available, give up
99bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            return None
100bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter
101bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        temp = tempfile.NamedTemporaryFile()
102477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        try:
103bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            args = [c_compiler, '-Wl,-t', '-o', temp.name, '-l' + name]
104bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter
105bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            env = dict(os.environ)
106bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            env['LC_ALL'] = 'C'
107bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            env['LANG'] = 'C'
108e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            try:
109e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                proc = subprocess.Popen(args,
110e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stdout=subprocess.PIPE,
111e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stderr=subprocess.STDOUT,
112e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        env=env)
113e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            except OSError:  # E.g. bad executable
114e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                return None
115bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            with proc:
116bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                trace = proc.stdout.read()
117477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        finally:
118477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters            try:
119bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                temp.close()
1200166a283f65b08ee2dddb1b075f86862b8c7e3e4Giampaolo Rodola'            except FileNotFoundError:
121bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                # Raised if the file was already removed, which is the normal
122bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                # behaviour of GCC if linking fails
1230166a283f65b08ee2dddb1b075f86862b8c7e3e4Giampaolo Rodola'                pass
124477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        res = re.search(expr, trace)
125477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        if not res:
126477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters            return None
127bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter        return os.fsdecode(res.group(0))
128477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
1291b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters
1301b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters    if sys.platform == "sunos5":
1311b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters        # use /usr/ccs/bin/dump on solaris
1321b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters        def _get_soname(f):
1331b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters            if not f:
1341b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters                return None
135bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter
136e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            try:
137e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                proc = subprocess.Popen(("/usr/ccs/bin/dump", "-Lpv", f),
138e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stdout=subprocess.PIPE,
139e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stderr=subprocess.DEVNULL)
140e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            except OSError:  # E.g. command not found
141e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                return None
142bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            with proc:
143bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                data = proc.stdout.read()
144bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            res = re.search(br'\[.*\]\sSONAME\s+([^\s]+)', data)
1451b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters            if not res:
1461b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters                return None
147bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            return os.fsdecode(res.group(1))
1481b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters    else:
1491b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters        def _get_soname(f):
1501b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters            # assuming GNU binutils / ELF
1511b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters            if not f:
1521b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters                return None
153bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            objdump = shutil.which('objdump')
154bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            if not objdump:
155bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                # objdump is not available, give up
156bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                return None
157bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter
158e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            try:
159e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                proc = subprocess.Popen((objdump, '-p', '-j', '.dynamic', f),
160e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stdout=subprocess.PIPE,
161e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stderr=subprocess.DEVNULL)
162e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            except OSError:  # E.g. bad executable
163e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                return None
164bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            with proc:
165bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                dump = proc.stdout.read()
166bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            res = re.search(br'\sSONAME\s+([^\s]+)', dump)
1671b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters            if not res:
1681b7f891f416830d0c46ca1c9e1bfe62f05cda655Thomas Wouters                return None
169bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            return os.fsdecode(res.group(1))
170477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
171e67474725b5b13b48ba0007e89314214a6bdca0bVictor Stinner    if sys.platform.startswith(("freebsd", "openbsd", "dragonfly")):
172fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters
173fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters        def _num_version(libname):
174fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters            # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ]
175bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            parts = libname.split(b".")
176fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters            nums = []
177fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters            try:
178fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters                while parts:
179fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters                    nums.insert(0, int(parts.pop()))
180fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters            except ValueError:
181fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters                pass
182bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            return nums or [sys.maxsize]
183fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters
184fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters        def find_library(name):
185fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters            ename = re.escape(name)
186fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters            expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename)
187bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            expr = os.fsencode(expr)
188bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter
189e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            try:
190e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                proc = subprocess.Popen(('/sbin/ldconfig', '-r'),
191e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stdout=subprocess.PIPE,
192e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stderr=subprocess.DEVNULL)
193e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            except OSError:  # E.g. command not found
194e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                data = b''
195e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            else:
196e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                with proc:
197e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                    data = proc.stdout.read()
198bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter
199f4d4f8b97fc2e5a59058c54abe6a23194c3d3116Guido van Rossum            res = re.findall(expr, data)
200fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters            if not res:
201fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters                return _get_soname(_findLib_gcc(name))
202d4cb56d4e88c7e001bbaba2c80953db47632f199Raymond Hettinger            res.sort(key=_num_version)
203bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            return os.fsdecode(res[-1])
204fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters
205cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson    elif sys.platform == "sunos5":
206cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson
207cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson        def _findLib_crle(name, is64):
208cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson            if not os.path.exists('/usr/bin/crle'):
209cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson                return None
210cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson
211bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            env = dict(os.environ)
212bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            env['LC_ALL'] = 'C'
213bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter
214cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson            if is64:
215bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                args = ('/usr/bin/crle', '-64')
216cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson            else:
217bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                args = ('/usr/bin/crle',)
218cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson
2198988ebf2a7a89620781feca39074f91469e7baf2Meador Inge            paths = None
220e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            try:
221e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                proc = subprocess.Popen(args,
222e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stdout=subprocess.PIPE,
223e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        stderr=subprocess.DEVNULL,
224e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                                        env=env)
225e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter            except OSError:  # E.g. bad executable
226e1b3431cef4873b2853199f4b5114de7e26de998Martin Panter                return None
227bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter            with proc:
228bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                for line in proc.stdout:
2291889623e1a49e38df6d10171e4a4256dfcb8916bNick Coghlan                    line = line.strip()
230bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                    if line.startswith(b'Default Library Path (ELF):'):
231bfb15ab71165ccdf65ed1243e80e7e293999f034Martin Panter                        paths = os.fsdecode(line).split()[4]
232cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson
233cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson            if not paths:
234cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson                return None
235cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson
236cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson            for dir in paths.split(":"):
237cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson                libfile = os.path.join(dir, "lib%s.so" % name)
238cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson                if os.path.exists(libfile):
239cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson                    return libfile
240cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson
241cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson            return None
242cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson
243cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson        def find_library(name, is64 = False):
244cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson            return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
245cfe34744e3c785a56525ab8a9473336206f5854dBenjamin Peterson
246fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters    else:
247fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters
2482c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose        def _findSoname_ldconfig(name):
2492c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose            import struct
2502c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose            if struct.calcsize('l') == 4:
251605a62ddb1c19978ee194a40a458f072e3242a31Larry Hastings                machine = os.uname().machine + '-32'
2522c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose            else:
253605a62ddb1c19978ee194a40a458f072e3242a31Larry Hastings                machine = os.uname().machine + '-64'
2542c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose            mach_map = {
2552c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose                'x86_64-64': 'libc6,x86-64',
2562c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose                'ppc64-64': 'libc6,64bit',
2572c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose                'sparc64-64': 'libc6,64bit',
2582c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose                's390x-64': 'libc6,64bit',
2592c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose                'ia64-64': 'libc6,IA-64',
2602c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose                }
2612c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose            abi_type = mach_map.get(machine, 'libc6')
2622c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose
2632c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose            # XXX assuming GLIBC's ldconfig (with option -p)
26432f2eb4941db115d4d5d0902ba086820406ef4b2Martin Panter            regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
265b9f3114d42601b07c9830af8b18330bff475bcfcMartin Panter            regex = os.fsencode(regex % (re.escape(name), abi_type))
2668c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou            try:
2678c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                with subprocess.Popen(['/sbin/ldconfig', '-p'],
2688c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                                      stdin=subprocess.DEVNULL,
2698c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                                      stderr=subprocess.DEVNULL,
2708c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                                      stdout=subprocess.PIPE,
2718c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                                      env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
2728c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                    res = re.search(regex, p.stdout.read())
2738c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                    if res:
2748c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                        return os.fsdecode(res.group(1))
2758c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou            except OSError:
2768c52027e2d8c4268d0d0e376948d3107576a4aa4Antoine Pitrou                pass
2772c7e3ee79b0a9bbcf0d67a3d788b31392e14dc15Matthias Klose
27882df3b3071bb003247c33eac4670775e9883c994Vinay Sajip        def _findLib_ld(name):
27982df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            # See issue #9998 for why this is needed
28082df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)
28182df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            cmd = ['ld', '-t']
28282df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            libpath = os.environ.get('LD_LIBRARY_PATH')
28382df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            if libpath:
28482df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                for d in libpath.split(':'):
28582df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                    cmd.extend(['-L', d])
28682df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            cmd.extend(['-o', os.devnull, '-l%s' % name])
28782df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            result = None
28882df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            try:
28982df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
29082df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                                     stderr=subprocess.PIPE,
29182df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                                     universal_newlines=True)
29282df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                out, _ = p.communicate()
29382df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                res = re.search(expr, os.fsdecode(out))
29482df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                if res:
29582df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                    result = res.group(0)
29682df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            except Exception as e:
29782df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                pass  # result will be None
29882df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            return result
29982df3b3071bb003247c33eac4670775e9883c994Vinay Sajip
300fc7bb8c786fd9cb3b1ab84e1976620d0ab545777Thomas Wouters        def find_library(name):
30182df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            # See issue #9998
30282df3b3071bb003247c33eac4670775e9883c994Vinay Sajip            return _findSoname_ldconfig(name) or \
30382df3b3071bb003247c33eac4670775e9883c994Vinay Sajip                   _get_soname(_findLib_gcc(name) or _findLib_ld(name))
304477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
305477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters################################################################
306477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters# test code
307477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
308477c8d5e70240744d24631b18341ad892c8a8e1cThomas Woutersdef test():
309477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    from ctypes import cdll
310477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    if os.name == "nt":
311be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum        print(cdll.msvcrt)
312be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum        print(cdll.load("msvcrt"))
313be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum        print(find_library("msvcrt"))
314477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
315477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    if os.name == "posix":
316477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        # find and load_version
317be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum        print(find_library("m"))
318be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum        print(find_library("c"))
319be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum        print(find_library("bz2"))
320477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
321477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        # getattr
322477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters##        print cdll.m
323477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters##        print cdll.bz2
324477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
325477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        # load
326477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        if sys.platform == "darwin":
327be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum            print(cdll.LoadLibrary("libm.dylib"))
328be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum            print(cdll.LoadLibrary("libcrypto.dylib"))
329be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum            print(cdll.LoadLibrary("libSystem.dylib"))
330be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum            print(cdll.LoadLibrary("System.framework/System"))
331477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters        else:
332be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum            print(cdll.LoadLibrary("libm.so"))
333be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum            print(cdll.LoadLibrary("libcrypt.so"))
334be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum            print(find_library("crypt"))
335477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters
336477c8d5e70240744d24631b18341ad892c8a8e1cThomas Woutersif __name__ == "__main__":
337477c8d5e70240744d24631b18341ad892c8a8e1cThomas Wouters    test()
338