使用Python中的ctypes.util.find_library获取库的完整路径

时间:2014-03-22 15:05:45

标签: python linux macos shared-libraries ctypes

在Python中,ctypes.util.find_library可用于以类似于编译器的方式定位库。在Mac OSX中,该函数返回完整路径名。但在linux中,只返回文件名。 (这是docs

有没有办法在linux中获取完整路径?

2 个答案:

答案 0 :(得分:2)

您可以使用dl_iterate_phdr加载库和迭代加载的库:

#!python
from ctypes import *
from ctypes.util import find_library

# this struct will be passed as a ponter,
# so we don't have to worry about the right layout
class dl_phdr_info(Structure):
  _fields_ = [
    ('padding0', c_void_p), # ignore it
    ('dlpi_name', c_char_p),
                            # ignore the reset
  ]


# call back function, I changed c_void_p to c_char_p
callback_t = CFUNCTYPE(c_int,
                       POINTER(dl_phdr_info), 
                       POINTER(c_size_t), c_char_p)

dl_iterate_phdr = CDLL('libc.so.6').dl_iterate_phdr
# I changed c_void_p to c_char_p
dl_iterate_phdr.argtypes = [callback_t, c_char_p]
dl_iterate_phdr.restype = c_int


def callback(info, size, data):
  # simple search
  if data in info.contents.dlpi_name:
    print(info.contents.dlpi_name)
  return 0

if __name__ == '__main__':
  # the target lib we want to find
  target_lib = find_library('xml2')
  print(target_lib)
  # load it
  lib = CDLL(target_lib)
  # iterate over the loaded libs
  dl_iterate_phdr(callback_t(callback), target_lib)

例如:

$ python test.py 
libxml2.so.2
/usr/lib/libxml2.so.2
$ 

答案 1 :(得分:1)

Linux中的

find_library做这样的事情。为什么我们不应该这样做呢?

import struct
def myfind(name):
    # see ctypes.find_library code
    uname = os.uname()[4]
    if uname.startswith("arm"):
        uname = "arm"
    if struct.calcsize('l') == 4:
        machine = uname + '-32'
    else:
        machine = uname + '-64'
    mach_map = {
        'x86_64-64': 'libc6,x86-64',
        'ppc64-64': 'libc6,64bit',
        'sparc64-64': 'libc6,64bit',
        's390x-64': 'libc6,64bit',
        'ia64-64': 'libc6,IA-64',
        'arm-32': 'libc6(,hard-float)?',
        }
    abi_type = mach_map.get(machine, 'libc6')
    # Note, we search libXXX.so.XXX, not just libXXX.so (!)
    expr = re.compile(r'^\s+lib%s\.so.[^\s]+\s+\(%s.*=>\s+(.*)$' % (re.escape(name), abi_type))
    p = subprocess.Popen(['ldconfig', '-N', '-p'], stdout=subprocess.PIPE)
    result = None
    for line in p.stdout:
        res = expr.match(line)
        if res is None:
            continue
        if result is not None:
            raise RuntimeError('Duplicate library found for %s' % name)
        result = res.group(1)
    if p.wait():
        raise RuntimeError('"ldconfig -p" failed')
    if result is None:
        raise RuntimeError('Library %s not found' % name)
    return result