From f7f2f1d67449da1ef52ef72d68d319fb504228fb Mon Sep 17 00:00:00 2001 From: giovannibajo Date: Sun, 1 Mar 2009 12:13:57 +0000 Subject: [PATCH] Fix ctypes support on Linux. find_library() is not the correct function to resolve the full path, at least not on Linux. git-svn-id: http://svn.pyinstaller.org/trunk@632 8dd32b29-ccff-0310-8a9a-9233e24343b1 --- buildtests/test15.spec | 33 +++++++++++++++++++++++---------- buildtests/test15a.py | 11 +++++++++-- mf.py | 28 ++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/buildtests/test15.spec b/buildtests/test15.spec index e36a787..867b1bf 100644 --- a/buildtests/test15.spec +++ b/buildtests/test15.spec @@ -1,22 +1,35 @@ # -*- mode: python -*- - import sys -if not sys.platform.startswith("darwin"): - raise RuntimeError("please port test15 under linux2 and win32") - import os +CTYPES_DIR = "ctypes" +TEST_LIB = os.path.join(CTYPES_DIR, "testctypes") +if sys.platform == "linux2": + TEST_LIB += ".so" +elif sys.platform == "darwin2": + TEST_LIB += ".dylib" +elif sys.platform == "win32": + TEST_LIB += ".dll" +else: + raise NotImplentedError + # If the required dylib does not reside in the current directory, the Analysis # class machinery, based on ctypes.util.find_library, will not find it. This was # done on purpose for this test, to show how to give Analysis class a clue. -os.environ["DYLD_LIBRARY_PATH"] = "ctypes/" +os.environ["DYLD_LIBRARY_PATH"] = CTYPES_DIR +os.environ["LD_LIBRARY_PATH"] = CTYPES_DIR # Check for presence of testctypes shared library, build it if not present -if not os.path.exists("ctypes/testctypes.dylib"): - os.chdir("ctypes") - os.system("gcc -Wall -dynamiclib testctypes.c -o testctypes.dylib -headerpad_max_install_names") - id_dylib = os.path.abspath("testctypes.dylib") - os.system("install_name_tool -id %s testctypes.dylib" % (id_dylib,)) +if not os.path.exists(TEST_LIB): + os.chdir(CTYPES_DIR) + if sys.platform == "darwin2": + os.system("gcc -Wall -dynamiclib testctypes.c -o testctypes.dylib -headerpad_max_install_names") + id_dylib = os.path.abspath("testctypes.dylib") + os.system("install_name_tool -id %s testctypes.dylib" % (id_dylib,)) + elif sys.platform == "linux2": + os.system("gcc -fPIC -shared testctypes.c -o testctypes.so") + else: + raise NotImplementedError os.chdir("..") __testname__ = 'test15' diff --git a/buildtests/test15a.py b/buildtests/test15a.py index c8a0e97..962bfd2 100644 --- a/buildtests/test15a.py +++ b/buildtests/test15a.py @@ -1,7 +1,14 @@ #!/usr/bin/env python - +import sys from ctypes import * def dummy(arg): - tct = CDLL("testctypes.dylib") + if sys.platform == "linux2": + tct = CDLL("testctypes.so") + elif sys.platform == "darwin": + tct = CDLL("testctypes.dylib") + elif sys.platform == "win32": + tct = CDLL("testctypes.dll") + else: + raise NotImplementedError return tct.dummy(arg) diff --git a/mf.py b/mf.py index d3e01c0..a22ffba 100644 --- a/mf.py +++ b/mf.py @@ -539,11 +539,35 @@ class ImportTracker: cbinaries = list(mod.binaries) mod.binaries = [] - # Executes find_library prepending ImportTracker's local paths to - # library search paths, then replaces original values. + + # Try to locate the shared library on disk. This is done by + # executing ctypes.utile.find_library prepending ImportTracker's + # local paths to library search paths, then replaces original values. old = _savePaths() for cbin in cbinaries: cpath = find_library(os.path.splitext(cbin)[0]) + if sys.platform == "linux2": + # CAVEAT: find_library() is not the correct function. Ctype's + # documentation says that it is meant to resolve only the filename + # (as a *compiler* does) not the full path. Anyway, it works well + # enough on Windows and Mac. On Linux, we need to implement + # more code to find out the full path. + if cpath is None: + cpath = cbin + # "man ld.so" says that we should first search LD_LIBRARY_PATH + # and then the ldcache + for d in os.environ["LD_LIBRARY_PATH"].split(":"): + if os.path.isfile(d + "/" + cpath): + cpath = d + "/" + cpath + break + else: + for L in os.popen("ldconfig -p").read().splitlines(): + if cpath in L: + cpath = L.split("=>", 1)[1].strip() + assert os.path.isfile(cpath) + break + else: + cpath = None if cpath is None: print "W: library %s required via ctypes not found" % (cbin,) else: