blob: 151560427272a2496e7d88dbefe4988c09cc61ac [file] [log] [blame]
Thomas Wouters477c8d52006-05-27 19:21:47 +00001import sys, os
Eric Smith5ccfa292009-10-23 12:56:11 +00002import contextlib
Antoine Pitrou8c520272011-04-23 17:51:04 +02003import subprocess
Thomas Wouters477c8d52006-05-27 19:21:47 +00004
5# find_library(name) returns the pathname of a library, or None.
6if os.name == "nt":
Thomas Heller3eaaeb42008-05-23 17:26:46 +00007
8 def _get_build_version():
9 """Return the version of MSVC that was used to build Python.
10
11 For Python 2.3 and up, the version number is included in
12 sys.version. For earlier versions, assume the compiler is MSVC 6.
13 """
14 # This function was copied from Lib/distutils/msvccompiler.py
15 prefix = "MSC v."
16 i = sys.version.find(prefix)
17 if i == -1:
18 return 6
19 i = i + len(prefix)
20 s, rest = sys.version[i:].split(" ", 1)
21 majorVersion = int(s[:-2]) - 6
22 minorVersion = int(s[2:3]) / 10.0
23 # I don't think paths are affected by minor version in version 6
24 if majorVersion == 6:
25 minorVersion = 0
26 if majorVersion >= 6:
27 return majorVersion + minorVersion
28 # else we don't know what version of the compiler this is
29 return None
30
31 def find_msvcrt():
32 """Return the name of the VC runtime dll"""
33 version = _get_build_version()
34 if version is None:
35 # better be safe than sorry
36 return None
37 if version <= 6:
38 clibname = 'msvcrt'
39 else:
40 clibname = 'msvcr%d' % (version * 10)
41
42 # If python was built with in debug mode
Brett Cannoncb66eb02012-05-11 12:58:42 -040043 import importlib.machinery
44 if '_d.pyd' in importlib.machinery.EXTENSION_SUFFIXES:
Thomas Heller3eaaeb42008-05-23 17:26:46 +000045 clibname += 'd'
46 return clibname+'.dll'
47
Thomas Wouters477c8d52006-05-27 19:21:47 +000048 def find_library(name):
Thomas Heller3eaaeb42008-05-23 17:26:46 +000049 if name in ('c', 'm'):
50 return find_msvcrt()
Thomas Wouters477c8d52006-05-27 19:21:47 +000051 # See MSDN for the REAL search order.
52 for directory in os.environ['PATH'].split(os.pathsep):
53 fname = os.path.join(directory, name)
Thomas Heller00cfc372009-05-05 19:04:40 +000054 if os.path.isfile(fname):
Thomas Wouters477c8d52006-05-27 19:21:47 +000055 return fname
56 if fname.lower().endswith(".dll"):
57 continue
58 fname = fname + ".dll"
Thomas Heller00cfc372009-05-05 19:04:40 +000059 if os.path.isfile(fname):
Thomas Wouters477c8d52006-05-27 19:21:47 +000060 return fname
61 return None
62
63if os.name == "ce":
64 # search path according to MSDN:
65 # - absolute path specified by filename
66 # - The .exe launch directory
67 # - the Windows directory
68 # - ROM dll files (where are they?)
69 # - OEM specified search path: HKLM\Loader\SystemPath
70 def find_library(name):
71 return name
72
73if os.name == "posix" and sys.platform == "darwin":
74 from ctypes.macholib.dyld import dyld_find as _dyld_find
75 def find_library(name):
76 possible = ['lib%s.dylib' % name,
77 '%s.dylib' % name,
78 '%s.framework/%s' % (name, name)]
79 for name in possible:
80 try:
81 return _dyld_find(name)
82 except ValueError:
83 continue
84 return None
85
86elif os.name == "posix":
87 # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
Thomas Wouters0e3f5912006-08-11 14:57:12 +000088 import re, tempfile, errno
Thomas Wouters477c8d52006-05-27 19:21:47 +000089
90 def _findLib_gcc(name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000091 expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000092 fdout, ccout = tempfile.mkstemp()
93 os.close(fdout)
Matthias Klose2c7e3ee2009-01-10 17:08:25 +000094 cmd = 'if type gcc >/dev/null 2>&1; then CC=gcc; elif type cc >/dev/null 2>&1; then CC=cc;else exit 10; fi;' \
Thomas Wouters0e3f5912006-08-11 14:57:12 +000095 '$CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name
Thomas Wouters477c8d52006-05-27 19:21:47 +000096 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000097 f = os.popen(cmd)
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +000098 try:
99 trace = f.read()
100 finally:
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000101 rv = f.close()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000102 finally:
103 try:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000104 os.unlink(ccout)
Guido van Rossumb940e112007-01-10 16:19:56 +0000105 except OSError as e:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000106 if e.errno != errno.ENOENT:
107 raise
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000108 if rv == 10:
Benjamin Peterson17bf0822009-01-10 22:37:11 +0000109 raise OSError('gcc or cc command not found')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000110 res = re.search(expr, trace)
111 if not res:
112 return None
113 return res.group(0)
114
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000115
116 if sys.platform == "sunos5":
117 # use /usr/ccs/bin/dump on solaris
118 def _get_soname(f):
119 if not f:
120 return None
121 cmd = "/usr/ccs/bin/dump -Lpv 2>/dev/null " + f
Eric Smith5ccfa292009-10-23 12:56:11 +0000122 with contextlib.closing(os.popen(cmd)) as f:
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000123 data = f.read()
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000124 res = re.search(r'\[.*\]\sSONAME\s+([^\s]+)', data)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000125 if not res:
126 return None
127 return res.group(1)
128 else:
129 def _get_soname(f):
130 # assuming GNU binutils / ELF
131 if not f:
132 return None
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000133 cmd = 'if ! type objdump >/dev/null 2>&1; then exit 10; fi;' \
134 "objdump -p -j .dynamic 2>/dev/null " + f
135 f = os.popen(cmd)
136 dump = f.read()
137 rv = f.close()
138 if rv == 10:
Benjamin Peterson17bf0822009-01-10 22:37:11 +0000139 raise OSError('objdump command not found')
Antoine Pitroub46004c2011-05-25 18:17:25 +0200140 res = re.search(r'\sSONAME\s+([^\s]+)', dump)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000141 if not res:
142 return None
143 return res.group(1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000144
Victor Stinnere6747472011-08-21 00:39:18 +0200145 if sys.platform.startswith(("freebsd", "openbsd", "dragonfly")):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000146
147 def _num_version(libname):
148 # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ]
149 parts = libname.split(".")
150 nums = []
151 try:
152 while parts:
153 nums.insert(0, int(parts.pop()))
154 except ValueError:
155 pass
Christian Heimesa37d4c62007-12-04 23:02:19 +0000156 return nums or [ sys.maxsize ]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000157
158 def find_library(name):
159 ename = re.escape(name)
160 expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename)
Eric Smith5ccfa292009-10-23 12:56:11 +0000161 with contextlib.closing(os.popen('/sbin/ldconfig -r 2>/dev/null')) as f:
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000162 data = f.read()
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000163 res = re.findall(expr, data)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000164 if not res:
165 return _get_soname(_findLib_gcc(name))
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000166 res.sort(key=_num_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000167 return res[-1]
168
Benjamin Petersoncfe34742013-02-03 19:25:11 -0500169 elif sys.platform == "sunos5":
170
171 def _findLib_crle(name, is64):
172 if not os.path.exists('/usr/bin/crle'):
173 return None
174
175 if is64:
176 cmd = 'env LC_ALL=C /usr/bin/crle -64 2>/dev/null'
177 else:
178 cmd = 'env LC_ALL=C /usr/bin/crle 2>/dev/null'
179
180 for line in os.popen(cmd).readlines():
181 line = line.strip()
182 if line.startswith('Default Library Path (ELF):'):
183 paths = line.split()[4]
184
185 if not paths:
186 return None
187
188 for dir in paths.split(":"):
189 libfile = os.path.join(dir, "lib%s.so" % name)
190 if os.path.exists(libfile):
191 return libfile
192
193 return None
194
195 def find_library(name, is64 = False):
196 return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
197
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000198 else:
199
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000200 def _findSoname_ldconfig(name):
201 import struct
202 if struct.calcsize('l') == 4:
Larry Hastings605a62d2012-06-24 04:33:36 -0700203 machine = os.uname().machine + '-32'
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000204 else:
Larry Hastings605a62d2012-06-24 04:33:36 -0700205 machine = os.uname().machine + '-64'
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000206 mach_map = {
207 'x86_64-64': 'libc6,x86-64',
208 'ppc64-64': 'libc6,64bit',
209 'sparc64-64': 'libc6,64bit',
210 's390x-64': 'libc6,64bit',
211 'ia64-64': 'libc6,IA-64',
212 }
213 abi_type = mach_map.get(machine, 'libc6')
214
215 # XXX assuming GLIBC's ldconfig (with option -p)
Antoine Pitrou8c520272011-04-23 17:51:04 +0200216 regex = os.fsencode(
217 '\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type))
218 try:
219 with subprocess.Popen(['/sbin/ldconfig', '-p'],
220 stdin=subprocess.DEVNULL,
221 stderr=subprocess.DEVNULL,
222 stdout=subprocess.PIPE,
223 env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
224 res = re.search(regex, p.stdout.read())
225 if res:
226 return os.fsdecode(res.group(1))
227 except OSError:
228 pass
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000229
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000230 def find_library(name):
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000231 return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000232
233################################################################
234# test code
235
236def test():
237 from ctypes import cdll
238 if os.name == "nt":
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000239 print(cdll.msvcrt)
240 print(cdll.load("msvcrt"))
241 print(find_library("msvcrt"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000242
243 if os.name == "posix":
244 # find and load_version
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000245 print(find_library("m"))
246 print(find_library("c"))
247 print(find_library("bz2"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000248
249 # getattr
250## print cdll.m
251## print cdll.bz2
252
253 # load
254 if sys.platform == "darwin":
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000255 print(cdll.LoadLibrary("libm.dylib"))
256 print(cdll.LoadLibrary("libcrypto.dylib"))
257 print(cdll.LoadLibrary("libSystem.dylib"))
258 print(cdll.LoadLibrary("System.framework/System"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000259 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000260 print(cdll.LoadLibrary("libm.so"))
261 print(cdll.LoadLibrary("libcrypt.so"))
262 print(find_library("crypt"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000263
264if __name__ == "__main__":
265 test()