|
@@ -1,3 +1,6 @@
|
|
|
|
+"""
|
|
|
|
+Load libraries - appropriately for all our supported platforms
|
|
|
|
+"""
|
|
# ----------------------------------------------------------------------------
|
|
# ----------------------------------------------------------------------------
|
|
# Copyright (c) 2008 David James
|
|
# Copyright (c) 2008 David James
|
|
# Copyright (c) 2006-2008 Alex Holkner
|
|
# Copyright (c) 2006-2008 Alex Holkner
|
|
@@ -32,24 +35,34 @@
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
# ----------------------------------------------------------------------------
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
|
-import os.path, re, sys, glob
|
|
|
|
-import platform
|
|
|
|
import ctypes
|
|
import ctypes
|
|
import ctypes.util
|
|
import ctypes.util
|
|
|
|
+import glob
|
|
|
|
+import os.path
|
|
|
|
+import platform
|
|
|
|
+import re
|
|
|
|
+import sys
|
|
|
|
|
|
|
|
|
|
def _environ_path(name):
|
|
def _environ_path(name):
|
|
|
|
+ """Split an environment variable into a path-like list elements"""
|
|
if name in os.environ:
|
|
if name in os.environ:
|
|
return os.environ[name].split(":")
|
|
return os.environ[name].split(":")
|
|
- else:
|
|
|
|
- return []
|
|
|
|
|
|
+ return []
|
|
|
|
|
|
|
|
|
|
-class LibraryLoader(object):
|
|
|
|
|
|
+class LibraryLoader:
|
|
|
|
+ """
|
|
|
|
+ A base class For loading of libraries ;-)
|
|
|
|
+ Subclasses load libraries for specific platforms.
|
|
|
|
+ """
|
|
|
|
+
|
|
# library names formatted specifically for platforms
|
|
# library names formatted specifically for platforms
|
|
name_formats = ["%s"]
|
|
name_formats = ["%s"]
|
|
|
|
|
|
- class Lookup(object):
|
|
|
|
|
|
+ class Lookup:
|
|
|
|
+ """Looking up calling conventions for a platform"""
|
|
|
|
+
|
|
mode = ctypes.DEFAULT_MODE
|
|
mode = ctypes.DEFAULT_MODE
|
|
|
|
|
|
def __init__(self, path):
|
|
def __init__(self, path):
|
|
@@ -57,6 +70,7 @@ class LibraryLoader(object):
|
|
self.access = dict(cdecl=ctypes.CDLL(path, self.mode))
|
|
self.access = dict(cdecl=ctypes.CDLL(path, self.mode))
|
|
|
|
|
|
def get(self, name, calling_convention="cdecl"):
|
|
def get(self, name, calling_convention="cdecl"):
|
|
|
|
+ """Return the given name according to the selected calling convention"""
|
|
if calling_convention not in self.access:
|
|
if calling_convention not in self.access:
|
|
raise LookupError(
|
|
raise LookupError(
|
|
"Unknown calling convention '{}' for function '{}'".format(
|
|
"Unknown calling convention '{}' for function '{}'".format(
|
|
@@ -66,6 +80,7 @@ class LibraryLoader(object):
|
|
return getattr(self.access[calling_convention], name)
|
|
return getattr(self.access[calling_convention], name)
|
|
|
|
|
|
def has(self, name, calling_convention="cdecl"):
|
|
def has(self, name, calling_convention="cdecl"):
|
|
|
|
+ """Return True if this given calling convention finds the given 'name'"""
|
|
if calling_convention not in self.access:
|
|
if calling_convention not in self.access:
|
|
return False
|
|
return False
|
|
return hasattr(self.access[calling_convention], name)
|
|
return hasattr(self.access[calling_convention], name)
|
|
@@ -81,9 +96,10 @@ class LibraryLoader(object):
|
|
paths = self.getpaths(libname)
|
|
paths = self.getpaths(libname)
|
|
|
|
|
|
for path in paths:
|
|
for path in paths:
|
|
|
|
+ # noinspection PyBroadException
|
|
try:
|
|
try:
|
|
return self.Lookup(path)
|
|
return self.Lookup(path)
|
|
- except:
|
|
|
|
|
|
+ except Exception: # pylint: disable=broad-except
|
|
pass
|
|
pass
|
|
|
|
|
|
raise ImportError("Could not load %s." % libname)
|
|
raise ImportError("Could not load %s." % libname)
|
|
@@ -101,9 +117,16 @@ class LibraryLoader(object):
|
|
# dir_i should be absolute already
|
|
# dir_i should be absolute already
|
|
yield os.path.join(dir_i, fmt % libname)
|
|
yield os.path.join(dir_i, fmt % libname)
|
|
|
|
|
|
|
|
+ # check if this code is even stored in a physical file
|
|
|
|
+ try:
|
|
|
|
+ this_file = __file__
|
|
|
|
+ except NameError:
|
|
|
|
+ this_file = None
|
|
|
|
+
|
|
# then we search the directory where the generated python interface is stored
|
|
# then we search the directory where the generated python interface is stored
|
|
- for fmt in self.name_formats:
|
|
|
|
- yield os.path.abspath(os.path.join(os.path.dirname(__file__), fmt % libname))
|
|
|
|
|
|
+ if this_file is not None:
|
|
|
|
+ for fmt in self.name_formats:
|
|
|
|
+ yield os.path.abspath(os.path.join(os.path.dirname(__file__), fmt % libname))
|
|
|
|
|
|
# now, use the ctypes tools to try to find the library
|
|
# now, use the ctypes tools to try to find the library
|
|
for fmt in self.name_formats:
|
|
for fmt in self.name_formats:
|
|
@@ -119,7 +142,8 @@ class LibraryLoader(object):
|
|
for fmt in self.name_formats:
|
|
for fmt in self.name_formats:
|
|
yield os.path.abspath(os.path.join(os.path.curdir, fmt % libname))
|
|
yield os.path.abspath(os.path.join(os.path.curdir, fmt % libname))
|
|
|
|
|
|
- def getplatformpaths(self, libname):
|
|
|
|
|
|
+ def getplatformpaths(self, _libname): # pylint: disable=no-self-use
|
|
|
|
+ """Return all the library paths available in this platform"""
|
|
return []
|
|
return []
|
|
|
|
|
|
|
|
|
|
@@ -127,6 +151,8 @@ class LibraryLoader(object):
|
|
|
|
|
|
|
|
|
|
class DarwinLibraryLoader(LibraryLoader):
|
|
class DarwinLibraryLoader(LibraryLoader):
|
|
|
|
+ """Library loader for MacOS"""
|
|
|
|
+
|
|
name_formats = [
|
|
name_formats = [
|
|
"lib%s.dylib",
|
|
"lib%s.dylib",
|
|
"lib%s.so",
|
|
"lib%s.so",
|
|
@@ -138,6 +164,10 @@ class DarwinLibraryLoader(LibraryLoader):
|
|
]
|
|
]
|
|
|
|
|
|
class Lookup(LibraryLoader.Lookup):
|
|
class Lookup(LibraryLoader.Lookup):
|
|
|
|
+ """
|
|
|
|
+ Looking up library files for this platform (Darwin aka MacOS)
|
|
|
|
+ """
|
|
|
|
+
|
|
# Darwin requires dlopen to be called with mode RTLD_GLOBAL instead
|
|
# Darwin requires dlopen to be called with mode RTLD_GLOBAL instead
|
|
# of the default RTLD_LOCAL. Without this, you end up with
|
|
# of the default RTLD_LOCAL. Without this, you end up with
|
|
# libraries not being loadable, resulting in "Symbol not found"
|
|
# libraries not being loadable, resulting in "Symbol not found"
|
|
@@ -148,13 +178,14 @@ class DarwinLibraryLoader(LibraryLoader):
|
|
if os.path.pathsep in libname:
|
|
if os.path.pathsep in libname:
|
|
names = [libname]
|
|
names = [libname]
|
|
else:
|
|
else:
|
|
- names = [format % libname for format in self.name_formats]
|
|
|
|
|
|
+ names = [fmt % libname for fmt in self.name_formats]
|
|
|
|
|
|
- for dir in self.getdirs(libname):
|
|
|
|
|
|
+ for directory in self.getdirs(libname):
|
|
for name in names:
|
|
for name in names:
|
|
- yield os.path.join(dir, name)
|
|
|
|
|
|
+ yield os.path.join(directory, name)
|
|
|
|
|
|
- def getdirs(self, libname):
|
|
|
|
|
|
+ @staticmethod
|
|
|
|
+ def getdirs(libname):
|
|
"""Implements the dylib search as specified in Apple documentation:
|
|
"""Implements the dylib search as specified in Apple documentation:
|
|
|
|
|
|
http://developer.apple.com/documentation/DeveloperTools/Conceptual/
|
|
http://developer.apple.com/documentation/DeveloperTools/Conceptual/
|
|
@@ -167,8 +198,11 @@ class DarwinLibraryLoader(LibraryLoader):
|
|
|
|
|
|
dyld_fallback_library_path = _environ_path("DYLD_FALLBACK_LIBRARY_PATH")
|
|
dyld_fallback_library_path = _environ_path("DYLD_FALLBACK_LIBRARY_PATH")
|
|
if not dyld_fallback_library_path:
|
|
if not dyld_fallback_library_path:
|
|
- dyld_fallback_library_path = [os.path.expanduser("~/lib"), "/usr/local/lib", "/usr/lib"]
|
|
|
|
- dyld_fallback_library_path.extend(_environ_path('LD_RUN_PATH'))
|
|
|
|
|
|
+ dyld_fallback_library_path = [
|
|
|
|
+ os.path.expanduser("~/lib"),
|
|
|
|
+ "/usr/local/lib",
|
|
|
|
+ "/usr/lib",
|
|
|
|
+ ]
|
|
|
|
|
|
dirs = []
|
|
dirs = []
|
|
|
|
|
|
@@ -177,8 +211,9 @@ class DarwinLibraryLoader(LibraryLoader):
|
|
else:
|
|
else:
|
|
dirs.extend(_environ_path("LD_LIBRARY_PATH"))
|
|
dirs.extend(_environ_path("LD_LIBRARY_PATH"))
|
|
dirs.extend(_environ_path("DYLD_LIBRARY_PATH"))
|
|
dirs.extend(_environ_path("DYLD_LIBRARY_PATH"))
|
|
|
|
+ dirs.extend(_environ_path("LD_RUN_PATH"))
|
|
|
|
|
|
- if hasattr(sys, "frozen") and sys.frozen == "macosx_app":
|
|
|
|
|
|
+ if hasattr(sys, "frozen") and getattr(sys, "frozen") == "macosx_app":
|
|
dirs.append(os.path.join(os.environ["RESOURCEPATH"], "..", "Frameworks"))
|
|
dirs.append(os.path.join(os.environ["RESOURCEPATH"], "..", "Frameworks"))
|
|
|
|
|
|
dirs.extend(dyld_fallback_library_path)
|
|
dirs.extend(dyld_fallback_library_path)
|
|
@@ -190,50 +225,60 @@ class DarwinLibraryLoader(LibraryLoader):
|
|
|
|
|
|
|
|
|
|
class PosixLibraryLoader(LibraryLoader):
|
|
class PosixLibraryLoader(LibraryLoader):
|
|
|
|
+ """Library loader for POSIX-like systems (including Linux)"""
|
|
|
|
+
|
|
_ld_so_cache = None
|
|
_ld_so_cache = None
|
|
|
|
|
|
_include = re.compile(r"^\s*include\s+(?P<pattern>.*)")
|
|
_include = re.compile(r"^\s*include\s+(?P<pattern>.*)")
|
|
|
|
|
|
|
|
+ name_formats = ["lib%s.so", "%s.so", "%s"]
|
|
|
|
+
|
|
class _Directories(dict):
|
|
class _Directories(dict):
|
|
|
|
+ """Deal with directories"""
|
|
|
|
+
|
|
def __init__(self):
|
|
def __init__(self):
|
|
|
|
+ dict.__init__(self)
|
|
self.order = 0
|
|
self.order = 0
|
|
|
|
|
|
def add(self, directory):
|
|
def add(self, directory):
|
|
|
|
+ """Add a directory to our current set of directories"""
|
|
if len(directory) > 1:
|
|
if len(directory) > 1:
|
|
directory = directory.rstrip(os.path.sep)
|
|
directory = directory.rstrip(os.path.sep)
|
|
# only adds and updates order if exists and not already in set
|
|
# only adds and updates order if exists and not already in set
|
|
if not os.path.exists(directory):
|
|
if not os.path.exists(directory):
|
|
return
|
|
return
|
|
- o = self.setdefault(directory, self.order)
|
|
|
|
- if o == self.order:
|
|
|
|
|
|
+ order = self.setdefault(directory, self.order)
|
|
|
|
+ if order == self.order:
|
|
self.order += 1
|
|
self.order += 1
|
|
|
|
|
|
def extend(self, directories):
|
|
def extend(self, directories):
|
|
- for d in directories:
|
|
|
|
- self.add(d)
|
|
|
|
|
|
+ """Add a list of directories to our set"""
|
|
|
|
+ for a_dir in directories:
|
|
|
|
+ self.add(a_dir)
|
|
|
|
|
|
def ordered(self):
|
|
def ordered(self):
|
|
- return (i[0] for i in sorted(self.items(), key=lambda D: D[1]))
|
|
|
|
|
|
+ """Sort the list of directories"""
|
|
|
|
+ return (i[0] for i in sorted(self.items(), key=lambda d: d[1]))
|
|
|
|
|
|
def _get_ld_so_conf_dirs(self, conf, dirs):
|
|
def _get_ld_so_conf_dirs(self, conf, dirs):
|
|
"""
|
|
"""
|
|
- Recursive funtion to help parse all ld.so.conf files, including proper
|
|
|
|
|
|
+ Recursive function to help parse all ld.so.conf files, including proper
|
|
handling of the `include` directive.
|
|
handling of the `include` directive.
|
|
"""
|
|
"""
|
|
|
|
|
|
try:
|
|
try:
|
|
- with open(conf) as f:
|
|
|
|
- for D in f:
|
|
|
|
- D = D.strip()
|
|
|
|
- if not D:
|
|
|
|
|
|
+ with open(conf) as fileobj:
|
|
|
|
+ for dirname in fileobj:
|
|
|
|
+ dirname = dirname.strip()
|
|
|
|
+ if not dirname:
|
|
continue
|
|
continue
|
|
|
|
|
|
- m = self._include.match(D)
|
|
|
|
- if not m:
|
|
|
|
- dirs.add(D)
|
|
|
|
|
|
+ match = self._include.match(dirname)
|
|
|
|
+ if not match:
|
|
|
|
+ dirs.add(dirname)
|
|
else:
|
|
else:
|
|
- for D2 in glob.glob(m.group("pattern")):
|
|
|
|
- self._get_ld_so_conf_dirs(D2, dirs)
|
|
|
|
|
|
+ for dir2 in glob.glob(match.group("pattern")):
|
|
|
|
+ self._get_ld_so_conf_dirs(dir2, dirs)
|
|
except IOError:
|
|
except IOError:
|
|
pass
|
|
pass
|
|
|
|
|
|
@@ -248,7 +293,7 @@ class PosixLibraryLoader(LibraryLoader):
|
|
directories = self._Directories()
|
|
directories = self._Directories()
|
|
for name in (
|
|
for name in (
|
|
"LD_LIBRARY_PATH",
|
|
"LD_LIBRARY_PATH",
|
|
- "SHLIB_PATH", # HPUX
|
|
|
|
|
|
+ "SHLIB_PATH", # HP-UX
|
|
"LIBPATH", # OS/2, AIX
|
|
"LIBPATH", # OS/2, AIX
|
|
"LIBRARY_PATH", # BE/OS
|
|
"LIBRARY_PATH", # BE/OS
|
|
):
|
|
):
|
|
@@ -274,8 +319,11 @@ class PosixLibraryLoader(LibraryLoader):
|
|
# Assume Intel/AMD x86 compat
|
|
# Assume Intel/AMD x86 compat
|
|
unix_lib_dirs_list += ["/lib/i386-linux-gnu", "/usr/lib/i386-linux-gnu"]
|
|
unix_lib_dirs_list += ["/lib/i386-linux-gnu", "/usr/lib/i386-linux-gnu"]
|
|
elif bitage.startswith("64"):
|
|
elif bitage.startswith("64"):
|
|
- # Assume Intel/AMD x86 compat
|
|
|
|
- unix_lib_dirs_list += ["/lib/x86_64-linux-gnu", "/usr/lib/x86_64-linux-gnu"]
|
|
|
|
|
|
+ # Assume Intel/AMD x86 compatible
|
|
|
|
+ unix_lib_dirs_list += [
|
|
|
|
+ "/lib/x86_64-linux-gnu",
|
|
|
|
+ "/usr/lib/x86_64-linux-gnu",
|
|
|
|
+ ]
|
|
else:
|
|
else:
|
|
# guess...
|
|
# guess...
|
|
unix_lib_dirs_list += glob.glob("/lib/*linux-gnu")
|
|
unix_lib_dirs_list += glob.glob("/lib/*linux-gnu")
|
|
@@ -283,10 +331,10 @@ class PosixLibraryLoader(LibraryLoader):
|
|
|
|
|
|
cache = {}
|
|
cache = {}
|
|
lib_re = re.compile(r"lib(.*)\.s[ol]")
|
|
lib_re = re.compile(r"lib(.*)\.s[ol]")
|
|
- ext_re = re.compile(r"\.s[ol]$")
|
|
|
|
- for dir in directories.ordered():
|
|
|
|
|
|
+ # ext_re = re.compile(r"\.s[ol]$")
|
|
|
|
+ for our_dir in directories.ordered():
|
|
try:
|
|
try:
|
|
- for path in glob.glob("%s/*.s[ol]*" % dir):
|
|
|
|
|
|
+ for path in glob.glob("%s/*.s[ol]*" % our_dir):
|
|
file = os.path.basename(path)
|
|
file = os.path.basename(path)
|
|
|
|
|
|
# Index by filename
|
|
# Index by filename
|
|
@@ -320,6 +368,8 @@ class PosixLibraryLoader(LibraryLoader):
|
|
|
|
|
|
|
|
|
|
class WindowsLibraryLoader(LibraryLoader):
|
|
class WindowsLibraryLoader(LibraryLoader):
|
|
|
|
+ """Library loader for Microsoft Windows"""
|
|
|
|
+
|
|
name_formats = ["%s.dll", "lib%s.dll", "%slib.dll", "%s"]
|
|
name_formats = ["%s.dll", "lib%s.dll", "%slib.dll", "%s"]
|
|
|
|
|
|
def __init__(self):
|
|
def __init__(self):
|
|
@@ -329,6 +379,8 @@ class WindowsLibraryLoader(LibraryLoader):
|
|
os.add_dll_directory(p)
|
|
os.add_dll_directory(p)
|
|
|
|
|
|
class Lookup(LibraryLoader.Lookup):
|
|
class Lookup(LibraryLoader.Lookup):
|
|
|
|
+ """Lookup class for Windows libraries..."""
|
|
|
|
+
|
|
def __init__(self, path):
|
|
def __init__(self, path):
|
|
super(WindowsLibraryLoader.Lookup, self).__init__(path)
|
|
super(WindowsLibraryLoader.Lookup, self).__init__(path)
|
|
self.access["stdcall"] = ctypes.windll.LoadLibrary(path)
|
|
self.access["stdcall"] = ctypes.windll.LoadLibrary(path)
|
|
@@ -355,10 +407,10 @@ def add_library_search_dirs(other_dirs):
|
|
If library paths are relative, convert them to absolute with respect to this
|
|
If library paths are relative, convert them to absolute with respect to this
|
|
file's directory
|
|
file's directory
|
|
"""
|
|
"""
|
|
- for F in other_dirs:
|
|
|
|
- if not os.path.isabs(F):
|
|
|
|
- F = os.path.abspath(F)
|
|
|
|
- load_library.other_dirs.append(F)
|
|
|
|
|
|
+ for path in other_dirs:
|
|
|
|
+ if not os.path.isabs(path):
|
|
|
|
+ path = os.path.abspath(path)
|
|
|
|
+ load_library.other_dirs.append(path)
|
|
|
|
|
|
|
|
|
|
del loaderclass
|
|
del loaderclass
|