Home | History | Annotate | Download | only in ctypes
      1 ######################################################################
      2 #  This file should be kept compatible with Python 2.3, see PEP 291. #
      3 ######################################################################
      4 import sys, os
      5 
      6 # find_library(name) returns the pathname of a library, or None.
      7 if os.name == "nt":
      8 
      9     def _get_build_version():
     10         #***********************************************************
     11         # NOTE: As example for GCC(mingw) build sys.version return:
     12         # '2.7a0 (trunk:<REVISION>M, <DATE>, <TIME>) \n[GCC 3.4.5 (mingw special)]'
     13         # '2.7a0 (trunk:<REVISION>M, <DATE>, <TIME>) \n[GCC 4.4.0]'
     14         #***********************************************************
     15         """Return the version of MSVC that was used to build Python.
     16 
     17         For Python 2.3 and up, the version number is included in
     18         sys.version.  For earlier versions, assume the compiler is MSVC 6.
     19         """
     20         # This function was copied from Lib/distutils/msvccompiler.py
     21         prefix = "MSC v."
     22         i = sys.version.find(prefix)
     23         if i == -1:
     24             return 6
     25         i = i + len(prefix)
     26         s, rest = sys.version[i:].split(" ", 1)
     27         majorVersion = int(s[:-2]) - 6
     28         minorVersion = int(s[2:3]) / 10.0
     29         # I don't think paths are affected by minor version in version 6
     30         if majorVersion == 6:
     31             minorVersion = 0
     32         if majorVersion >= 6:
     33             return majorVersion + minorVersion
     34         # else we don't know what version of the compiler this is
     35         return None
     36 
     37     def find_msvcrt():
     38         #************************************************************
     39         # FIXME: For GCC(mingw) runtime don't depend from compiler
     40         # version ;). We may use -D__MSVCRT_VERSION__ to detect which
     41         # verion is requested by user, but the name of the library
     42         # to be default.
     43         # As example WXP is with version 7.0 of msvcrt.dll.
     44         # Anyway since _get_build_version return 6 in most(standard)
     45         # cases this method will return msvcrt{d}. May be not so bad.
     46         #************************************************************
     47         """Return the name of the VC runtime dll"""
     48         version = _get_build_version()
     49         if version is None:
     50             # better be safe than sorry
     51             return None
     52         if version <= 6:
     53             clibname = 'msvcrt'
     54         else:
     55             clibname = 'msvcr%d' % (version * 10)
     56 
     57         # If python was built with in debug mode
     58         import imp
     59         if imp.get_suffixes()[0][0] == '_d.pyd':
     60             clibname += 'd'
     61         return clibname+'.dll'
     62 
     63     def find_library(name):
     64         if name in ('c', 'm'):
     65             return find_msvcrt()
     66         # See MSDN for the REAL search order.
     67         for directory in os.environ['PATH'].split(os.pathsep):
     68             fname = os.path.join(directory, name)
     69             if os.path.isfile(fname):
     70                 return fname
     71             if fname.lower().endswith(".dll"):
     72                 continue
     73             fname = fname + ".dll"
     74             if os.path.isfile(fname):
     75                 return fname
     76         return None
     77 
     78 if os.name == "ce":
     79     # search path according to MSDN:
     80     # - absolute path specified by filename
     81     # - The .exe launch directory
     82     # - the Windows directory
     83     # - ROM dll files (where are they?)
     84     # - OEM specified search path: HKLM\Loader\SystemPath
     85     def find_library(name):
     86         return name
     87 
     88 if os.name == "posix" and sys.platform == "darwin":
     89     from ctypes.macholib.dyld import dyld_find as _dyld_find
     90     def find_library(name):
     91         possible = ['lib%s.dylib' % name,
     92                     '%s.dylib' % name,
     93                     '%s.framework/%s' % (name, name)]
     94         for name in possible:
     95             try:
     96                 return _dyld_find(name)
     97             except ValueError:
     98                 continue
     99         return None
    100 
    101 elif os.name == "posix":
    102     # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
    103     import re, tempfile, errno
    104 
    105     def _findLib_gcc(name):
    106         expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)
    107         fdout, ccout = tempfile.mkstemp()
    108         os.close(fdout)
    109         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;' \
    110               '$CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name
    111         try:
    112             f = os.popen(cmd)
    113             try:
    114                 trace = f.read()
    115             finally:
    116                 rv = f.close()
    117         finally:
    118             try:
    119                 os.unlink(ccout)
    120             except OSError, e:
    121                 if e.errno != errno.ENOENT:
    122                     raise
    123         if rv == 10:
    124             raise OSError, 'gcc or cc command not found'
    125         res = re.search(expr, trace)
    126         if not res:
    127             return None
    128         return res.group(0)
    129 
    130 
    131     if sys.platform == "sunos5":
    132         # use /usr/ccs/bin/dump on solaris
    133         def _get_soname(f):
    134             if not f:
    135                 return None
    136             cmd = "/usr/ccs/bin/dump -Lpv 2>/dev/null " + f
    137             f = os.popen(cmd)
    138             try:
    139                 data = f.read()
    140             finally:
    141                 f.close()
    142             res = re.search(r'\[.*\]\sSONAME\s+([^\s]+)', data)
    143             if not res:
    144                 return None
    145             return res.group(1)
    146     else:
    147         def _get_soname(f):
    148             # assuming GNU binutils / ELF
    149             if not f:
    150                 return None
    151             cmd = 'if ! type objdump >/dev/null 2>&1; then exit 10; fi;' \
    152                   "objdump -p -j .dynamic 2>/dev/null " + f
    153             f = os.popen(cmd)
    154             dump = f.read()
    155             rv = f.close()
    156             if rv == 10:
    157                 raise OSError, 'objdump command not found'
    158             f = os.popen(cmd)
    159             try:
    160                 data = f.read()
    161             finally:
    162                 f.close()
    163             res = re.search(r'\sSONAME\s+([^\s]+)', data)
    164             if not res:
    165                 return None
    166             return res.group(1)
    167 
    168     if (sys.platform.startswith("freebsd")
    169         or sys.platform.startswith("openbsd")
    170         or sys.platform.startswith("dragonfly")):
    171 
    172         def _num_version(libname):
    173             # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ]
    174             parts = libname.split(".")
    175             nums = []
    176             try:
    177                 while parts:
    178                     nums.insert(0, int(parts.pop()))
    179             except ValueError:
    180                 pass
    181             return nums or [ sys.maxint ]
    182 
    183         def find_library(name):
    184             ename = re.escape(name)
    185             expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename)
    186             f = os.popen('/sbin/ldconfig -r 2>/dev/null')
    187             try:
    188                 data = f.read()
    189             finally:
    190                 f.close()
    191             res = re.findall(expr, data)
    192             if not res:
    193                 return _get_soname(_findLib_gcc(name))
    194             res.sort(cmp= lambda x,y: cmp(_num_version(x), _num_version(y)))
    195             return res[-1]
    196 
    197     elif sys.platform == "sunos5":
    198 
    199         def _findLib_crle(name, is64):
    200             if not os.path.exists('/usr/bin/crle'):
    201                 return None
    202 
    203             if is64:
    204                 cmd = 'env LC_ALL=C /usr/bin/crle -64 2>/dev/null'
    205             else:
    206                 cmd = 'env LC_ALL=C /usr/bin/crle 2>/dev/null'
    207 
    208             for line in os.popen(cmd).readlines():
    209                 line = line.strip()
    210                 if line.startswith('Default Library Path (ELF):'):
    211                     paths = line.split()[4]
    212 
    213             if not paths:
    214                 return None
    215 
    216             for dir in paths.split(":"):
    217                 libfile = os.path.join(dir, "lib%s.so" % name)
    218                 if os.path.exists(libfile):
    219                     return libfile
    220 
    221             return None
    222 
    223         def find_library(name, is64 = False):
    224             return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name))
    225 
    226     else:
    227 
    228         def _findSoname_ldconfig(name):
    229             import struct
    230             if struct.calcsize('l') == 4:
    231                 machine = os.uname()[4] + '-32'
    232             else:
    233                 machine = os.uname()[4] + '-64'
    234             mach_map = {
    235                 'x86_64-64': 'libc6,x86-64',
    236                 'ppc64-64': 'libc6,64bit',
    237                 'sparc64-64': 'libc6,64bit',
    238                 's390x-64': 'libc6,64bit',
    239                 'ia64-64': 'libc6,IA-64',
    240                 }
    241             abi_type = mach_map.get(machine, 'libc6')
    242 
    243             # XXX assuming GLIBC's ldconfig (with option -p)
    244             expr = r'\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type)
    245             f = os.popen('/sbin/ldconfig -p 2>/dev/null')
    246             try:
    247                 data = f.read()
    248             finally:
    249                 f.close()
    250             res = re.search(expr, data)
    251             if not res:
    252                 return None
    253             return res.group(1)
    254 
    255         def find_library(name):
    256             return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name))
    257 
    258 ################################################################
    259 # test code
    260 
    261 def test():
    262     from ctypes import cdll
    263     if os.name == "nt":
    264         print cdll.msvcrt
    265         print cdll.load("msvcrt")
    266         print find_library("msvcrt")
    267 
    268     if os.name == "posix":
    269         # find and load_version
    270         print find_library("m")
    271         print find_library("c")
    272         print find_library("bz2")
    273 
    274         # getattr
    275 ##        print cdll.m
    276 ##        print cdll.bz2
    277 
    278         # load
    279         if sys.platform == "darwin":
    280             print cdll.LoadLibrary("libm.dylib")
    281             print cdll.LoadLibrary("libcrypto.dylib")
    282             print cdll.LoadLibrary("libSystem.dylib")
    283             print cdll.LoadLibrary("System.framework/System")
    284         else:
    285             print cdll.LoadLibrary("libm.so")
    286             print cdll.LoadLibrary("libcrypt.so")
    287             print find_library("crypt")
    288 
    289 if __name__ == "__main__":
    290     test()
    291