blob: 9c19899da570be1b6685aca5b6b1da57f8122ab5 [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
Steve Dower65e4cb12014-11-22 12:54:57 -080022 if majorVersion >= 13:
23 majorVersion += 1
Thomas Heller3eaaeb42008-05-23 17:26:46 +000024 minorVersion = int(s[2:3]) / 10.0
25 # I don't think paths are affected by minor version in version 6
26 if majorVersion == 6:
27 minorVersion = 0
28 if majorVersion >= 6:
29 return majorVersion + minorVersion
30 # else we don't know what version of the compiler this is
31 return None
32
33 def find_msvcrt():
34 """Return the name of the VC runtime dll"""
35 version = _get_build_version()
36 if version is None:
37 # better be safe than sorry
38 return None
39 if version <= 6:
40 clibname = 'msvcrt'
Steve Dower65e4cb12014-11-22 12:54:57 -080041 elif version <= 13:
Thomas Heller3eaaeb42008-05-23 17:26:46 +000042 clibname = 'msvcr%d' % (version * 10)
Steve Dower65e4cb12014-11-22 12:54:57 -080043 else:
44 clibname = 'appcrt%d' % (version * 10)
Thomas Heller3eaaeb42008-05-23 17:26:46 +000045
46 # If python was built with in debug mode
Brett Cannoncb66eb02012-05-11 12:58:42 -040047 import importlib.machinery
48 if '_d.pyd' in importlib.machinery.EXTENSION_SUFFIXES:
Thomas Heller3eaaeb42008-05-23 17:26:46 +000049 clibname += 'd'
50 return clibname+'.dll'
51
Thomas Wouters477c8d52006-05-27 19:21:47 +000052 def find_library(name):
Thomas Heller3eaaeb42008-05-23 17:26:46 +000053 if name in ('c', 'm'):
54 return find_msvcrt()
Thomas Wouters477c8d52006-05-27 19:21:47 +000055 # See MSDN for the REAL search order.
56 for directory in os.environ['PATH'].split(os.pathsep):
57 fname = os.path.join(directory, name)
Thomas Heller00cfc372009-05-05 19:04:40 +000058 if os.path.isfile(fname):
Thomas Wouters477c8d52006-05-27 19:21:47 +000059 return fname
60 if fname.lower().endswith(".dll"):
61 continue
62 fname = fname + ".dll"
Thomas Heller00cfc372009-05-05 19:04:40 +000063 if os.path.isfile(fname):
Thomas Wouters477c8d52006-05-27 19:21:47 +000064 return fname
65 return None
66
67if os.name == "ce":
68 # search path according to MSDN:
69 # - absolute path specified by filename
70 # - The .exe launch directory
71 # - the Windows directory
72 # - ROM dll files (where are they?)
73 # - OEM specified search path: HKLM\Loader\SystemPath
74 def find_library(name):
75 return name
76
77if os.name == "posix" and sys.platform == "darwin":
78 from ctypes.macholib.dyld import dyld_find as _dyld_find
79 def find_library(name):
80 possible = ['lib%s.dylib' % name,
81 '%s.dylib' % name,
82 '%s.framework/%s' % (name, name)]
83 for name in possible:
84 try:
85 return _dyld_find(name)
86 except ValueError:
87 continue
88 return None
89
90elif os.name == "posix":
91 # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
Victor Stinner7fa767e2014-03-20 09:16:38 +010092 import re, tempfile
Thomas Wouters477c8d52006-05-27 19:21:47 +000093
94 def _findLib_gcc(name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000095 expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096 fdout, ccout = tempfile.mkstemp()
97 os.close(fdout)
Matthias Klose2c7e3ee2009-01-10 17:08:25 +000098 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 +020099 'LANG=C LC_ALL=C $CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name
Thomas Wouters477c8d52006-05-27 19:21:47 +0000100 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000101 f = os.popen(cmd)
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000102 try:
103 trace = f.read()
104 finally:
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000105 rv = f.close()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000106 finally:
107 try:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000108 os.unlink(ccout)
Giampaolo Rodola'0166a282013-02-12 15:14:17 +0100109 except FileNotFoundError:
110 pass
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000111 if rv == 10:
Benjamin Peterson17bf0822009-01-10 22:37:11 +0000112 raise OSError('gcc or cc command not found')
Thomas Wouters477c8d52006-05-27 19:21:47 +0000113 res = re.search(expr, trace)
114 if not res:
115 return None
116 return res.group(0)
117
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000118
119 if sys.platform == "sunos5":
120 # use /usr/ccs/bin/dump on solaris
121 def _get_soname(f):
122 if not f:
123 return None
124 cmd = "/usr/ccs/bin/dump -Lpv 2>/dev/null " + f
Eric Smith5ccfa292009-10-23 12:56:11 +0000125 with contextlib.closing(os.popen(cmd)) as f:
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000126 data = f.read()
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000127 res = re.search(r'\[.*\]\sSONAME\s+([^\s]+)', data)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000128 if not res:
129 return None
130 return res.group(1)
131 else:
132 def _get_soname(f):
133 # assuming GNU binutils / ELF
134 if not f:
135 return None
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000136 cmd = 'if ! type objdump >/dev/null 2>&1; then exit 10; fi;' \
137 "objdump -p -j .dynamic 2>/dev/null " + f
138 f = os.popen(cmd)
Nick Coghlan18896232013-11-24 12:53:50 +1000139 try:
140 dump = f.read()
141 finally:
142 rv = f.close()
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000143 if rv == 10:
Benjamin Peterson17bf0822009-01-10 22:37:11 +0000144 raise OSError('objdump command not found')
Antoine Pitroub46004c2011-05-25 18:17:25 +0200145 res = re.search(r'\sSONAME\s+([^\s]+)', dump)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000146 if not res:
147 return None
148 return res.group(1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000149
Victor Stinnere6747472011-08-21 00:39:18 +0200150 if sys.platform.startswith(("freebsd", "openbsd", "dragonfly")):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000151
152 def _num_version(libname):
153 # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ]
154 parts = libname.split(".")
155 nums = []
156 try:
157 while parts:
158 nums.insert(0, int(parts.pop()))
159 except ValueError:
160 pass
Christian Heimesa37d4c62007-12-04 23:02:19 +0000161 return nums or [ sys.maxsize ]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000162
163 def find_library(name):
164 ename = re.escape(name)
165 expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename)
Eric Smith5ccfa292009-10-23 12:56:11 +0000166 with contextlib.closing(os.popen('/sbin/ldconfig -r 2>/dev/null')) as f:
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000167 data = f.read()
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000168 res = re.findall(expr, data)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000169 if not res:
170 return _get_soname(_findLib_gcc(name))
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000171 res.sort(key=_num_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000172 return res[-1]
173
Benjamin Petersoncfe34742013-02-03 19:25:11 -0500174 elif sys.platform == "sunos5":
175
176 def _findLib_crle(name, is64):
177 if not os.path.exists('/usr/bin/crle'):
178 return None
179
180 if is64:
181 cmd = 'env LC_ALL=C /usr/bin/crle -64 2>/dev/null'
182 else:
183 cmd = 'env LC_ALL=C /usr/bin/crle 2>/dev/null'
184
Nick Coghlan18896232013-11-24 12:53:50 +1000185 with contextlib.closing(os.popen(cmd)) as f:
186 for line in f.readlines():
187 line = line.strip()
188 if line.startswith('Default Library Path (ELF):'):
189 paths = line.split()[4]
Benjamin Petersoncfe34742013-02-03 19:25:11 -0500190
191 if not paths:
192 return None
193
194 for dir in paths.split(":"):
195 libfile = os.path.join(dir, "lib%s.so" % name)
196 if os.path.exists(libfile):
197 return libfile
198
199 return None
200
201 def find_library(name, is64 = False):
202 return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
203
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000204 else:
205
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000206 def _findSoname_ldconfig(name):
207 import struct
208 if struct.calcsize('l') == 4:
Larry Hastings605a62d2012-06-24 04:33:36 -0700209 machine = os.uname().machine + '-32'
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000210 else:
Larry Hastings605a62d2012-06-24 04:33:36 -0700211 machine = os.uname().machine + '-64'
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000212 mach_map = {
213 'x86_64-64': 'libc6,x86-64',
214 'ppc64-64': 'libc6,64bit',
215 'sparc64-64': 'libc6,64bit',
216 's390x-64': 'libc6,64bit',
217 'ia64-64': 'libc6,IA-64',
218 }
219 abi_type = mach_map.get(machine, 'libc6')
220
221 # XXX assuming GLIBC's ldconfig (with option -p)
Antoine Pitrou8c520272011-04-23 17:51:04 +0200222 regex = os.fsencode(
223 '\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type))
224 try:
225 with subprocess.Popen(['/sbin/ldconfig', '-p'],
226 stdin=subprocess.DEVNULL,
227 stderr=subprocess.DEVNULL,
228 stdout=subprocess.PIPE,
229 env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
230 res = re.search(regex, p.stdout.read())
231 if res:
232 return os.fsdecode(res.group(1))
233 except OSError:
234 pass
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000235
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000236 def find_library(name):
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000237 return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000238
239################################################################
240# test code
241
242def test():
243 from ctypes import cdll
244 if os.name == "nt":
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000245 print(cdll.msvcrt)
246 print(cdll.load("msvcrt"))
247 print(find_library("msvcrt"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000248
249 if os.name == "posix":
250 # find and load_version
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000251 print(find_library("m"))
252 print(find_library("c"))
253 print(find_library("bz2"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000254
255 # getattr
256## print cdll.m
257## print cdll.bz2
258
259 # load
260 if sys.platform == "darwin":
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000261 print(cdll.LoadLibrary("libm.dylib"))
262 print(cdll.LoadLibrary("libcrypto.dylib"))
263 print(cdll.LoadLibrary("libSystem.dylib"))
264 print(cdll.LoadLibrary("System.framework/System"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000265 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000266 print(cdll.LoadLibrary("libm.so"))
267 print(cdll.LoadLibrary("libcrypt.so"))
268 print(find_library("crypt"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000269
270if __name__ == "__main__":
271 test()