blob: 595113bffdec2219848476ef7a6d36e7b1fce13f [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
Victor Stinner7fa767e2014-03-20 09:16:38 +010088 import re, tempfile
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;' \
doko@ubuntu.comef535582013-05-15 18:02:13 +020095 'LANG=C LC_ALL=C $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)
Giampaolo Rodola'0166a282013-02-12 15:14:17 +0100105 except FileNotFoundError:
106 pass
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000107 if rv == 10:
Benjamin Peterson17bf0822009-01-10 22:37:11 +0000108 raise OSError('gcc or cc command not found')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000109 res = re.search(expr, trace)
110 if not res:
111 return None
112 return res.group(0)
113
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000114
115 if sys.platform == "sunos5":
116 # use /usr/ccs/bin/dump on solaris
117 def _get_soname(f):
118 if not f:
119 return None
120 cmd = "/usr/ccs/bin/dump -Lpv 2>/dev/null " + f
Eric Smith5ccfa292009-10-23 12:56:11 +0000121 with contextlib.closing(os.popen(cmd)) as f:
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000122 data = f.read()
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000123 res = re.search(r'\[.*\]\sSONAME\s+([^\s]+)', data)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000124 if not res:
125 return None
126 return res.group(1)
127 else:
128 def _get_soname(f):
129 # assuming GNU binutils / ELF
130 if not f:
131 return None
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000132 cmd = 'if ! type objdump >/dev/null 2>&1; then exit 10; fi;' \
133 "objdump -p -j .dynamic 2>/dev/null " + f
134 f = os.popen(cmd)
Nick Coghlan18896232013-11-24 12:53:50 +1000135 try:
136 dump = f.read()
137 finally:
138 rv = f.close()
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000139 if rv == 10:
Benjamin Peterson17bf0822009-01-10 22:37:11 +0000140 raise OSError('objdump command not found')
Antoine Pitroub46004c2011-05-25 18:17:25 +0200141 res = re.search(r'\sSONAME\s+([^\s]+)', dump)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000142 if not res:
143 return None
144 return res.group(1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000145
Victor Stinnere6747472011-08-21 00:39:18 +0200146 if sys.platform.startswith(("freebsd", "openbsd", "dragonfly")):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000147
148 def _num_version(libname):
149 # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ]
150 parts = libname.split(".")
151 nums = []
152 try:
153 while parts:
154 nums.insert(0, int(parts.pop()))
155 except ValueError:
156 pass
Christian Heimesa37d4c62007-12-04 23:02:19 +0000157 return nums or [ sys.maxsize ]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000158
159 def find_library(name):
160 ename = re.escape(name)
161 expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename)
Eric Smith5ccfa292009-10-23 12:56:11 +0000162 with contextlib.closing(os.popen('/sbin/ldconfig -r 2>/dev/null')) as f:
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000163 data = f.read()
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000164 res = re.findall(expr, data)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000165 if not res:
166 return _get_soname(_findLib_gcc(name))
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000167 res.sort(key=_num_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000168 return res[-1]
169
Benjamin Petersoncfe34742013-02-03 19:25:11 -0500170 elif sys.platform == "sunos5":
171
172 def _findLib_crle(name, is64):
173 if not os.path.exists('/usr/bin/crle'):
174 return None
175
176 if is64:
177 cmd = 'env LC_ALL=C /usr/bin/crle -64 2>/dev/null'
178 else:
179 cmd = 'env LC_ALL=C /usr/bin/crle 2>/dev/null'
180
Nick Coghlan18896232013-11-24 12:53:50 +1000181 with contextlib.closing(os.popen(cmd)) as f:
182 for line in f.readlines():
183 line = line.strip()
184 if line.startswith('Default Library Path (ELF):'):
185 paths = line.split()[4]
Benjamin Petersoncfe34742013-02-03 19:25:11 -0500186
187 if not paths:
188 return None
189
190 for dir in paths.split(":"):
191 libfile = os.path.join(dir, "lib%s.so" % name)
192 if os.path.exists(libfile):
193 return libfile
194
195 return None
196
197 def find_library(name, is64 = False):
198 return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
199
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000200 else:
201
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000202 def _findSoname_ldconfig(name):
203 import struct
204 if struct.calcsize('l') == 4:
Larry Hastings605a62d2012-06-24 04:33:36 -0700205 machine = os.uname().machine + '-32'
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000206 else:
Larry Hastings605a62d2012-06-24 04:33:36 -0700207 machine = os.uname().machine + '-64'
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000208 mach_map = {
209 'x86_64-64': 'libc6,x86-64',
210 'ppc64-64': 'libc6,64bit',
211 'sparc64-64': 'libc6,64bit',
212 's390x-64': 'libc6,64bit',
213 'ia64-64': 'libc6,IA-64',
214 }
215 abi_type = mach_map.get(machine, 'libc6')
216
217 # XXX assuming GLIBC's ldconfig (with option -p)
Antoine Pitrou8c520272011-04-23 17:51:04 +0200218 regex = os.fsencode(
219 '\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type))
220 try:
221 with subprocess.Popen(['/sbin/ldconfig', '-p'],
222 stdin=subprocess.DEVNULL,
223 stderr=subprocess.DEVNULL,
224 stdout=subprocess.PIPE,
225 env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
226 res = re.search(regex, p.stdout.read())
227 if res:
228 return os.fsdecode(res.group(1))
229 except OSError:
230 pass
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000231
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000232 def find_library(name):
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000233 return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000234
235################################################################
236# test code
237
238def test():
239 from ctypes import cdll
240 if os.name == "nt":
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000241 print(cdll.msvcrt)
242 print(cdll.load("msvcrt"))
243 print(find_library("msvcrt"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000244
245 if os.name == "posix":
246 # find and load_version
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000247 print(find_library("m"))
248 print(find_library("c"))
249 print(find_library("bz2"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000250
251 # getattr
252## print cdll.m
253## print cdll.bz2
254
255 # load
256 if sys.platform == "darwin":
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000257 print(cdll.LoadLibrary("libm.dylib"))
258 print(cdll.LoadLibrary("libcrypto.dylib"))
259 print(cdll.LoadLibrary("libSystem.dylib"))
260 print(cdll.LoadLibrary("System.framework/System"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000261 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000262 print(cdll.LoadLibrary("libm.so"))
263 print(cdll.LoadLibrary("libcrypt.so"))
264 print(find_library("crypt"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000265
266if __name__ == "__main__":
267 test()