1 import os 2 import subprocess 3 import sys 4 5 # find_library(name) returns the pathname of a library, or None. 6 if os.name == "nt": 7 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 43 import imp 44 if imp.get_suffixes()[0][0] == '_d.pyd': 45 clibname += 'd' 46 return clibname+'.dll' 47 48 def find_library(name): 49 if name in ('c', 'm'): 50 return find_msvcrt() 51 # See MSDN for the REAL search order. 52 for directory in os.environ['PATH'].split(os.pathsep): 53 fname = os.path.join(directory, name) 54 if os.path.isfile(fname): 55 return fname 56 if fname.lower().endswith(".dll"): 57 continue 58 fname = fname + ".dll" 59 if os.path.isfile(fname): 60 return fname 61 return None 62 63 if 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 73 if 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 86 elif os.name == "posix": 87 # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump 88 import re, tempfile, errno 89 90 def _findLib_gcc(name): 91 # Run GCC's linker with the -t (aka --trace) option and examine the 92 # library name it prints out. The GCC command will fail because we 93 # haven't supplied a proper program with main(), but that does not 94 # matter. 95 expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name) 96 cmd = 'if type gcc >/dev/null 2>&1; then CC=gcc; elif type cc >/dev/null 2>&1; then CC=cc;else exit; fi;' \ 97 'LANG=C LC_ALL=C $CC -Wl,-t -o "$2" 2>&1 -l"$1"' 98 99 temp = tempfile.NamedTemporaryFile() 100 try: 101 proc = subprocess.Popen((cmd, '_findLib_gcc', name, temp.name), 102 shell=True, 103 stdout=subprocess.PIPE) 104 [trace, _] = proc.communicate() 105 finally: 106 try: 107 temp.close() 108 except OSError, e: 109 # ENOENT is raised if the file was already removed, which is 110 # the normal behaviour of GCC if linking fails 111 if e.errno != errno.ENOENT: 112 raise 113 res = re.search(expr, trace) 114 if not res: 115 return None 116 return res.group(0) 117 118 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 125 null = open(os.devnull, "wb") 126 try: 127 with null: 128 proc = subprocess.Popen(("/usr/ccs/bin/dump", "-Lpv", f), 129 stdout=subprocess.PIPE, 130 stderr=null) 131 except OSError: # E.g. command not found 132 return None 133 [data, _] = proc.communicate() 134 res = re.search(br'\[.*\]\sSONAME\s+([^\s]+)', data) 135 if not res: 136 return None 137 return res.group(1) 138 else: 139 def _get_soname(f): 140 # assuming GNU binutils / ELF 141 if not f: 142 return None 143 cmd = 'if ! type objdump >/dev/null 2>&1; then exit; fi;' \ 144 'objdump -p -j .dynamic 2>/dev/null "$1"' 145 proc = subprocess.Popen((cmd, '_get_soname', f), shell=True, 146 stdout=subprocess.PIPE) 147 [dump, _] = proc.communicate() 148 res = re.search(br'\sSONAME\s+([^\s]+)', dump) 149 if not res: 150 return None 151 return res.group(1) 152 153 if (sys.platform.startswith("freebsd") 154 or sys.platform.startswith("openbsd") 155 or sys.platform.startswith("dragonfly")): 156 157 def _num_version(libname): 158 # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ] 159 parts = libname.split(b".") 160 nums = [] 161 try: 162 while parts: 163 nums.insert(0, int(parts.pop())) 164 except ValueError: 165 pass 166 return nums or [sys.maxint] 167 168 def find_library(name): 169 ename = re.escape(name) 170 expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename) 171 172 null = open(os.devnull, 'wb') 173 try: 174 with null: 175 proc = subprocess.Popen(('/sbin/ldconfig', '-r'), 176 stdout=subprocess.PIPE, 177 stderr=null) 178 except OSError: # E.g. command not found 179 data = b'' 180 else: 181 [data, _] = proc.communicate() 182 183 res = re.findall(expr, data) 184 if not res: 185 return _get_soname(_findLib_gcc(name)) 186 res.sort(key=_num_version) 187 return res[-1] 188 189 elif sys.platform == "sunos5": 190 191 def _findLib_crle(name, is64): 192 if not os.path.exists('/usr/bin/crle'): 193 return None 194 195 env = dict(os.environ) 196 env['LC_ALL'] = 'C' 197 198 if is64: 199 args = ('/usr/bin/crle', '-64') 200 else: 201 args = ('/usr/bin/crle',) 202 203 paths = None 204 null = open(os.devnull, 'wb') 205 try: 206 with null: 207 proc = subprocess.Popen(args, 208 stdout=subprocess.PIPE, 209 stderr=null, 210 env=env) 211 except OSError: # E.g. bad executable 212 return None 213 try: 214 for line in proc.stdout: 215 line = line.strip() 216 if line.startswith(b'Default Library Path (ELF):'): 217 paths = line.split()[4] 218 finally: 219 proc.stdout.close() 220 proc.wait() 221 222 if not paths: 223 return None 224 225 for dir in paths.split(":"): 226 libfile = os.path.join(dir, "lib%s.so" % name) 227 if os.path.exists(libfile): 228 return libfile 229 230 return None 231 232 def find_library(name, is64 = False): 233 return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name)) 234 235 else: 236 237 def _findSoname_ldconfig(name): 238 import struct 239 if struct.calcsize('l') == 4: 240 machine = os.uname()[4] + '-32' 241 else: 242 machine = os.uname()[4] + '-64' 243 mach_map = { 244 'x86_64-64': 'libc6,x86-64', 245 'ppc64-64': 'libc6,64bit', 246 'sparc64-64': 'libc6,64bit', 247 's390x-64': 'libc6,64bit', 248 'ia64-64': 'libc6,IA-64', 249 } 250 abi_type = mach_map.get(machine, 'libc6') 251 252 # XXX assuming GLIBC's ldconfig (with option -p) 253 expr = r'\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type) 254 255 env = dict(os.environ) 256 env['LC_ALL'] = 'C' 257 env['LANG'] = 'C' 258 null = open(os.devnull, 'wb') 259 try: 260 with null: 261 p = subprocess.Popen(['/sbin/ldconfig', '-p'], 262 stderr=null, 263 stdout=subprocess.PIPE, 264 env=env) 265 except OSError: # E.g. command not found 266 return None 267 [data, _] = p.communicate() 268 res = re.search(expr, data) 269 if not res: 270 return None 271 return res.group(1) 272 273 def find_library(name): 274 return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name)) 275 276 ################################################################ 277 # test code 278 279 def test(): 280 from ctypes import cdll 281 if os.name == "nt": 282 print cdll.msvcrt 283 print cdll.load("msvcrt") 284 print find_library("msvcrt") 285 286 if os.name == "posix": 287 # find and load_version 288 print find_library("m") 289 print find_library("c") 290 print find_library("bz2") 291 292 # getattr 293 ## print cdll.m 294 ## print cdll.bz2 295 296 # load 297 if sys.platform == "darwin": 298 print cdll.LoadLibrary("libm.dylib") 299 print cdll.LoadLibrary("libcrypto.dylib") 300 print cdll.LoadLibrary("libSystem.dylib") 301 print cdll.LoadLibrary("System.framework/System") 302 else: 303 print cdll.LoadLibrary("libm.so") 304 print cdll.LoadLibrary("libcrypt.so") 305 print find_library("crypt") 306 307 if __name__ == "__main__": 308 test() 309