blob: c427d319a7d3ee3c0a729ea9e94cc146950e1ad1 [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)
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)
135 dump = f.read()
136 rv = f.close()
137 if rv == 10:
Benjamin Peterson17bf0822009-01-10 22:37:11 +0000138 raise OSError('objdump command not found')
Antoine Pitroub46004c2011-05-25 18:17:25 +0200139 res = re.search(r'\sSONAME\s+([^\s]+)', dump)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000140 if not res:
141 return None
142 return res.group(1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000143
Victor Stinnere6747472011-08-21 00:39:18 +0200144 if sys.platform.startswith(("freebsd", "openbsd", "dragonfly")):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000145
146 def _num_version(libname):
147 # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ]
148 parts = libname.split(".")
149 nums = []
150 try:
151 while parts:
152 nums.insert(0, int(parts.pop()))
153 except ValueError:
154 pass
Christian Heimesa37d4c62007-12-04 23:02:19 +0000155 return nums or [ sys.maxsize ]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000156
157 def find_library(name):
158 ename = re.escape(name)
159 expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename)
Eric Smith5ccfa292009-10-23 12:56:11 +0000160 with contextlib.closing(os.popen('/sbin/ldconfig -r 2>/dev/null')) as f:
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000161 data = f.read()
Guido van Rossumf4d4f8b2007-12-12 20:26:00 +0000162 res = re.findall(expr, data)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000163 if not res:
164 return _get_soname(_findLib_gcc(name))
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000165 res.sort(key=_num_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000166 return res[-1]
167
Benjamin Petersoncfe34742013-02-03 19:25:11 -0500168 elif sys.platform == "sunos5":
169
170 def _findLib_crle(name, is64):
171 if not os.path.exists('/usr/bin/crle'):
172 return None
173
174 if is64:
175 cmd = 'env LC_ALL=C /usr/bin/crle -64 2>/dev/null'
176 else:
177 cmd = 'env LC_ALL=C /usr/bin/crle 2>/dev/null'
178
179 for line in os.popen(cmd).readlines():
180 line = line.strip()
181 if line.startswith('Default Library Path (ELF):'):
182 paths = line.split()[4]
183
184 if not paths:
185 return None
186
187 for dir in paths.split(":"):
188 libfile = os.path.join(dir, "lib%s.so" % name)
189 if os.path.exists(libfile):
190 return libfile
191
192 return None
193
194 def find_library(name, is64 = False):
195 return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
196
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000197 else:
198
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000199 def _findSoname_ldconfig(name):
200 import struct
201 if struct.calcsize('l') == 4:
Larry Hastings605a62d2012-06-24 04:33:36 -0700202 machine = os.uname().machine + '-32'
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000203 else:
Larry Hastings605a62d2012-06-24 04:33:36 -0700204 machine = os.uname().machine + '-64'
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000205 mach_map = {
206 'x86_64-64': 'libc6,x86-64',
207 'ppc64-64': 'libc6,64bit',
208 'sparc64-64': 'libc6,64bit',
209 's390x-64': 'libc6,64bit',
210 'ia64-64': 'libc6,IA-64',
211 }
212 abi_type = mach_map.get(machine, 'libc6')
213
214 # XXX assuming GLIBC's ldconfig (with option -p)
Antoine Pitrou8c520272011-04-23 17:51:04 +0200215 regex = os.fsencode(
216 '\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type))
217 try:
218 with subprocess.Popen(['/sbin/ldconfig', '-p'],
219 stdin=subprocess.DEVNULL,
220 stderr=subprocess.DEVNULL,
221 stdout=subprocess.PIPE,
222 env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
223 res = re.search(regex, p.stdout.read())
224 if res:
225 return os.fsdecode(res.group(1))
226 except OSError:
227 pass
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000228
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000229 def find_library(name):
Matthias Klose2c7e3ee2009-01-10 17:08:25 +0000230 return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000231
232################################################################
233# test code
234
235def test():
236 from ctypes import cdll
237 if os.name == "nt":
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000238 print(cdll.msvcrt)
239 print(cdll.load("msvcrt"))
240 print(find_library("msvcrt"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000241
242 if os.name == "posix":
243 # find and load_version
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000244 print(find_library("m"))
245 print(find_library("c"))
246 print(find_library("bz2"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000247
248 # getattr
249## print cdll.m
250## print cdll.bz2
251
252 # load
253 if sys.platform == "darwin":
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000254 print(cdll.LoadLibrary("libm.dylib"))
255 print(cdll.LoadLibrary("libcrypto.dylib"))
256 print(cdll.LoadLibrary("libSystem.dylib"))
257 print(cdll.LoadLibrary("System.framework/System"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000258 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000259 print(cdll.LoadLibrary("libm.so"))
260 print(cdll.LoadLibrary("libcrypt.so"))
261 print(find_library("crypt"))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000262
263if __name__ == "__main__":
264 test()