2
# Copyright (C) 2005, Giovanni Bajo
4
# Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21
import sys, string, os, imp, marshal, dircache, glob
23
# zipimport is supported starting with Python 2.3
29
# if ctypes is present, we can enable specific dependency discovery
31
from ctypes.util import find_library
38
STRINGTYPE = basestring
42
if not os.environ.has_key('PYTHONCASEOK') and sys.version_info >= (2, 1):
44
files = dircache.listdir(os.path.dirname(filename))
45
return os.path.basename(filename) in files
52
Returns correct extension ending: 'c' or 'o'
59
#=======================Owners==========================#
60
# An Owner does imports from a particular piece of turf
61
# That is, there's an Owner for each thing on sys.path
62
# There are owners for directories and .pyz files.
63
# There could be owners for zip files, or even URLs.
64
# Note that they replace the string in sys.path,
65
# but str(sys.path[n]) should yield the original string.
67
class OwnerError(Exception):
71
def __init__(self, path, target_platform=None):
73
self.target_platform = target_platform
81
class BaseDirOwner(Owner):
82
def _getsuffixes(self):
83
return suffixes.get_suffixes(self.target_platform)
85
def getmod(self, nm, getsuffixes=None, loadco=marshal.loads):
86
if getsuffixes is None:
87
getsuffixes = self._getsuffixes
88
possibles = [(nm, 0, None)]
89
if self._isdir(nm) and self._caseok(nm):
90
possibles.insert(0, (os.path.join(nm, '__init__'), 1, nm))
92
for pth, ispkg, pkgpth in possibles:
93
for ext, mode, typ in getsuffixes():
95
modtime = self._modtime(attempt)
96
if modtime is not None:
98
if not self._caseok(attempt):
100
if typ == imp.C_EXTENSION:
101
#print "DirOwner.getmod -> ExtensionModule(%s, %s)" % (nm, attempt)
102
return ExtensionModule(nm, os.path.join(self.path,attempt))
103
elif typ == imp.PY_SOURCE:
104
py = (attempt, modtime)
106
pyc = (attempt, modtime)
109
if py is None and pyc is None:
110
#print "DirOwner.getmod -> (py == pyc == None)"
113
# If we have no pyc or py is newer
114
if pyc is None or py and pyc[1] < py[1]:
116
stuff = self._read(py[0])+'\n'
117
co = compile(string.replace(stuff, "\r\n", "\n"), py[0], 'exec')
120
except SyntaxError, e:
121
print "Syntax error in", py[0]
125
stuff = self._read(pyc[0])
127
co = loadco(stuff[8:])
130
except (ValueError, EOFError):
131
print "W: bad .pyc found (%s), will use .py" % pyc[0]
134
#print "DirOwner.getmod while 1 -> None"
136
pth = os.path.join(self.path, pth)
137
if not os.path.isabs(pth):
138
pth = os.path.abspath(pth)
140
mod = self._pkgclass()(nm, pth, co)
142
mod = self._modclass()(nm, pth, co)
143
#print "DirOwner.getmod -> %s" % mod
146
class DirOwner(BaseDirOwner):
147
def __init__(self, path, target_platform=None):
150
if not os.path.isdir(path):
151
raise OwnerError("%s is not a directory" % repr(path))
152
Owner.__init__(self, path, target_platform)
154
def _isdir(self, fn):
155
return os.path.isdir(os.path.join(self.path, fn))
156
def _modtime(self, fn):
158
return os.stat(os.path.join(self.path, fn))[8]
162
return open(os.path.join(self.path, fn), 'rb').read()
167
def _caseok(self, fn):
168
return caseOk(os.path.join(self.path, fn))
170
class PYZOwner(Owner):
171
def __init__(self, path, target_platform=None):
173
self.pyz = archive.ZlibArchive(path)
174
Owner.__init__(self, path, target_platform)
175
def getmod(self, nm):
176
rslt = self.pyz.extract(nm)
181
return PkgInPYZModule(nm, co, self)
182
return PyModule(nm, self.path, co)
187
# We cannot use zipimporter here because it has a stupid bug:
189
# >>> z.find_module("setuptools.setuptools.setuptools.setuptools.setuptools") is not None
192
# So mf will go into infinite recursion.
193
# Instead, we'll reuse the BaseDirOwner logic, simply changing
194
# the template methods.
195
class ZipOwner(BaseDirOwner):
196
def __init__(self, path, target_platform=None):
199
self.zf = zipfile.ZipFile(path, "r")
201
raise OwnerError("%s is not a zipfile" % path)
202
Owner.__init__(self, path, target_platform)
203
def getmod(self, fn):
204
fn = fn.replace(".", "/")
205
return BaseDirOwner.getmod(self, fn)
206
def _modtime(self, fn):
207
fn = fn.replace("\\","/")
209
dt = self.zf.getinfo(fn).date_time
213
def _isdir(self, fn):
214
# No way to find out if "fn" is a directory
215
# so just always look into it in case it is.
217
def _caseok(self, fn):
218
# zipfile is always case-sensitive, so surely
219
# there is no case mismatch.
222
# zipfiles always use forward slashes
223
fn = fn.replace("\\","/")
224
return self.zf.read(fn)
226
return lambda *args: PkgInZipModule(self, *args)
228
return lambda *args: PyInZipModule(self, *args)
230
_globalownertypes = filter(None, [
237
#===================Import Directors====================================#
238
# ImportDirectors live on the metapath
239
# There's one for builtins, one for frozen modules, and one for sys.path
240
# Windows gets one for modules gotten from the Registry
241
# There should be one for Frozen modules
242
# Mac would have them for PY_RESOURCE modules etc.
243
# A generalization of Owner - their concept of "turf" is broader
245
class ImportDirector(Owner):
248
class BuiltinImportDirector(ImportDirector):
250
self.path = 'Builtins'
252
def getmod(self, nm, isbuiltin=imp.is_builtin):
254
return BuiltinModule(nm)
257
class FrozenImportDirector(ImportDirector):
259
self.path = 'FrozenModules'
261
def getmod(self, nm, isfrozen=imp.is_frozen):
263
return FrozenModule(nm)
266
class RegistryImportDirector(ImportDirector):
269
self.path = "WindowsRegistry"
277
subkey = r"Software\Python\PythonCore\%s\Modules" % sys.winver
278
for root in (win32con.HKEY_CURRENT_USER, win32con.HKEY_LOCAL_MACHINE):
280
#hkey = win32api.RegOpenKeyEx(root, subkey, 0, win32con.KEY_ALL_ACCESS)
281
hkey = win32api.RegOpenKeyEx(root, subkey, 0, win32con.KEY_READ)
283
#print "RegistryImportDirector", e
286
numsubkeys, numvalues, lastmodified = win32api.RegQueryInfoKey(hkey)
287
for i in range(numsubkeys):
288
subkeyname = win32api.RegEnumKey(hkey, i)
289
#hskey = win32api.RegOpenKeyEx(hkey, subkeyname, 0, win32con.KEY_ALL_ACCESS)
290
hskey = win32api.RegOpenKeyEx(hkey, subkeyname, 0, win32con.KEY_READ)
291
val = win32api.RegQueryValueEx(hskey, '')
292
desc = getDescr(val[0])
293
#print " RegistryImportDirector got %s %s" % (val[0], desc) #XXX
294
self.map[subkeyname] = (val[0], desc)
299
def getmod(self, nm):
300
stuff = self.map.get(nm)
302
fnm, (suffix, mode, typ) = stuff
303
if typ == imp.C_EXTENSION:
304
return ExtensionModule(nm, fnm)
305
elif typ == imp.PY_SOURCE:
307
stuff = open(fnm, 'r').read()+'\n'
308
co = compile(string.replace(stuff, "\r\n", "\n"), fnm, 'exec')
309
except SyntaxError, e:
310
print "Invalid syntax in %s" % py[0]
314
stuff = open(fnm, 'rb').read()
315
co = loadco(stuff[8:])
316
return PyModule(nm, fnm, co)
319
class PathImportDirector(ImportDirector):
320
def __init__(self, pathlist=None, importers=None, ownertypes=None,
321
target_platform=None):
326
if ownertypes == None:
327
self.ownertypes = _globalownertypes
329
self.ownertypes = ownertypes
331
self.shadowpath = importers
336
self.target_platform = target_platform
339
return str(self.path)
341
def getmod(self, nm):
343
for thing in self.path:
344
if isinstance(thing, STRINGTYPE):
345
owner = self.shadowpath.get(thing, -1)
347
owner = self.shadowpath[thing] = self.makeOwner(thing)
349
mod = owner.getmod(nm)
351
mod = thing.getmod(nm)
356
def makeOwner(self, path):
357
if self.building.get(path):
359
self.building[path] = 1
361
for klass in self.ownertypes:
363
# this may cause an import, which may cause recursion
364
# hence the protection
365
owner = klass(path, self.target_platform)
369
#print "FIXME: Wrong exception", e
373
del self.building[path]
378
ext = os.path.splitext(fnm)[1]
379
for (suffix, mode, typ) in imp.get_suffixes():
381
return (suffix, mode, typ)
383
#=================Import Tracker============================#
384
# This one doesn't really import, just analyzes
385
# If it *were* importing, it would be the one-and-only ImportManager
386
# ie, the builtin import
390
imptyps = ['top-level', 'conditional', 'delayed', 'delayed, conditional']
396
class LogDict(UserDict.UserDict):
398
def __init__(self, *args):
399
UserDict.UserDict.__init__(self, *args)
401
self.logfile = open("logdict%s-%d.log" % (".".join(map(str, sys.version_info)),
403
def __setitem__(self, key, value):
404
self.logfile.write("%s: %s -> %s\n" % (key, self.data.get(key), value))
405
UserDict.UserDict.__setitem__(self, key, value)
406
def __delitem__(self, key):
407
self.logfile.write(" DEL %s\n" % key)
408
UserDict.UserDict.__delitem__(self, key)
414
# really the equivalent of builtin import
415
def __init__(self, xpath=None, hookspath=None, excludes=None,
416
target_platform=None):
421
self.path.extend(sys.path)
422
self.modules = LogDict()
424
BuiltinImportDirector(),
425
FrozenImportDirector(),
426
RegistryImportDirector(),
427
PathImportDirector(self.path, target_platform=target_platform)
430
hooks.__path__.extend(hookspath)
431
self.excludes = excludes
434
self.target_platform = target_platform
436
def analyze_r(self, nm, importernm=None):
437
importer = importernm
439
importer = '__main__'
441
nms = self.analyze_one(nm, importernm)
442
nms = map(None, nms, [importer]*len(nms))
445
nm, importer = nms[i]
448
mod = self.modules[nm]
455
mod = self.modules[nm]
458
for name, isdelayed, isconditional, level in mod.imports:
459
imptyp = isdelayed * 2 + isconditional
460
newnms = self.analyze_one(name, nm, imptyp, level)
461
newnms = map(None, newnms, [nm]*len(newnms))
464
return map(lambda a: a[0], nms)
466
def analyze_one(self, nm, importernm=None, imptyp=0, level=-1):
467
#print '## analyze_one', nm, importernm, imptyp, level
468
# break the name being imported up so we get:
469
# a.b.c -> [a, b, c] ; ..z -> ['', '', z]
474
nmparts = string.split(nm, '.')
477
# behaviour up to Python 2.4 (and default in Python 2.5)
478
# first see if we could be importing a relative name
481
if self.ispackage(importernm):
482
contexts.insert(0, importernm)
484
pkgnm = string.join(string.split(importernm, '.')[:-1], '.')
486
contexts.insert(0, pkgnm)
488
# absolute import, do not try relative
492
# relative import, do not try absolute
493
if self.ispackage(importernm):
496
importernm = string.join(string.split(importernm, '.')[:-level], ".")
497
contexts = [importernm, None]
504
# so contexts is [pkgnm, None] or just [None]
505
if nmparts[-1] == '*':
509
for context in contexts:
511
for i in range(len(nmparts)):
514
fqname = ctx + '.' + nm
517
mod = self.modules.get(fqname, UNTRIED)
519
mod = self.doimport(nm, ctx, fqname)
521
nms.append(mod.__name__)
526
# no break, point i beyond end
530
# now nms is the list of modules that went into sys.modules
531
# just as result of the structure of the name being imported
532
# however, each mod has been scanned and that list is in mod.imports
535
if hasattr(self.modules[ctx], nmparts[i]):
537
if not self.ispackage(ctx):
539
self.warnings["W: no module named %s (%s import by %s)" % (fqname, imptyps[imptyp], importernm or "__main__")] = 1
540
if self.modules.has_key(fqname):
541
del self.modules[fqname]
545
bottommod = self.modules[ctx]
546
if bottommod.ispackage():
547
for nm in bottommod._all:
548
if not hasattr(bottommod, nm):
549
mod = self.doimport(nm, ctx, ctx+'.'+nm)
551
nms.append(mod.__name__)
553
bottommod.warnings.append("W: name %s not found" % nm)
556
def analyze_script(self, fnm):
558
stuff = open(fnm, 'r').read()+'\n'
559
co = compile(string.replace(stuff, "\r\n", "\n"), fnm, 'exec')
560
except SyntaxError, e:
561
print "Invalid syntax in %s" % fnm
564
mod = PyScript(fnm, co)
565
self.modules['__main__'] = mod
566
return self.analyze_r('__main__')
569
def ispackage(self, nm):
570
return self.modules[nm].ispackage()
572
def doimport(self, nm, ctx, fqname):
573
#print "doimport", nm, ctx, fqname
574
# Not that nm is NEVER a dotted name at this point
575
assert ("." not in nm), nm
576
if fqname in self.excludes:
579
parent = self.modules[ctx]
580
if parent.ispackage():
581
mod = parent.doimport(nm)
583
# insert the new module in the parent package
585
setattr(parent, nm, mod)
587
# if parent is not a package, there is nothing more to do
590
# now we're dealing with an absolute import
591
# try to import nm using available directors
592
for director in self.metapath:
593
mod = director.getmod(nm)
596
# here we have `mod` from:
597
# mod = parent.doimport(nm)
599
# mod = director.getmod(nm)
601
mod.__name__ = fqname
602
self.modules[fqname] = mod
604
# this (and scan_code) are instead of doing "exec co in mod.__dict__"
606
hookmodnm = 'hook-'+fqname
607
hooks = __import__('hooks', globals(), locals(), [hookmodnm])
608
hook = getattr(hooks, hookmodnm)
609
except AttributeError:
612
# rearranged so that hook() has a chance to mess with hiddenimports & attrs
613
if hasattr(hook, 'hook'):
615
if hasattr(hook, 'hiddenimports'):
616
for impnm in hook.hiddenimports:
617
mod.imports.append((impnm, 0, 0, -1))
618
if hasattr(hook, 'attrs'):
619
for attr, val in hook.attrs:
620
setattr(mod, attr, val)
621
if hasattr(hook, 'datas'):
622
# hook.datas is a list of globs of files or directories to bundle
623
# as datafiles. For each glob, a destination directory is specified.
624
for g,dest_dir in hook.datas:
625
if dest_dir: dest_dir += "/"
626
for fn in glob.glob(g):
627
if os.path.isfile(fn):
628
mod.datas.append((dest_dir + os.path.basename(fn), fn, 'DATA'))
630
def visit((base,dest_dir,datas), dirname, names):
632
fn = os.path.join(dirname, fn)
633
if os.path.isfile(fn):
634
datas.append((dest_dir + fn[len(base)+1:], fn, 'DATA'))
635
os.path.walk(fn, visit, (os.path.dirname(fn),dest_dir,mod.datas))
636
if fqname != mod.__name__:
637
print "W: %s is changing it's name to %s" % (fqname, mod.__name__)
638
self.modules[mod.__name__] = mod
640
assert (mod == None), mod
641
self.modules[fqname] = None
642
# should be equivalent using only one
643
# self.modules[fqname] = mod
647
def getwarnings(self):
648
warnings = self.warnings.keys()
649
for nm,mod in self.modules.items():
651
for w in mod.warnings:
652
warnings.append(w+' - %s (%s)' % (mod.__name__, mod.__file__))
656
mods = self.modules.items() # (nm, mod)
661
importers = mod._xref.keys()
663
rslt.append((nm, importers))
666
#====================Modules============================#
667
# All we're doing here is tracking, not importing
668
# If we were importing, these would be hooked to the real module objects
674
def __init__(self, nm):
687
def doimport(self, nm):
694
return "<Module %s %s imports=%s binaries=%s datas=%s>" % \
695
(self.__name__, self.__file__, self.imports, self.binaries, self.datas)
697
class BuiltinModule(Module):
700
def __init__(self, nm):
701
Module.__init__(self, nm)
703
class ExtensionModule(Module):
706
def __init__(self, nm, pth):
707
Module.__init__(self, nm)
710
class PyModule(Module):
713
def __init__(self, nm, pth, co):
714
Module.__init__(self, nm)
717
if os.path.splitext(self.__file__)[1] == '.py':
718
self.__file__ = self.__file__ + pyco()
722
self.imports, self.warnings, self.binaries, allnms = scan_code(self.co)
725
if ctypes and self.binaries:
726
self.binaries = _resolveCtypesImports(self.binaries)
729
class PyScript(PyModule):
732
def __init__(self, pth, co):
733
Module.__init__(self, '__main__')
739
class PkgModule(PyModule):
742
def __init__(self, nm, pth, co):
743
PyModule.__init__(self, nm, pth, co)
745
pth = os.path.dirname(pth)
746
self.__path__ = [ pth ]
747
self._update_director(force=True)
749
def _update_director(self, force=False):
750
if force or self.subimporter.path != self.__path__:
751
self.subimporter = PathImportDirector(self.__path__)
753
def doimport(self, nm):
754
self._update_director()
755
mod = self.subimporter.getmod(nm)
757
mod.__name__ = self.__name__ + '.' + mod.__name__
760
class PkgInPYZModule(PyModule):
761
def __init__(self, nm, co, pyzowner):
762
PyModule.__init__(self, nm, co.co_filename, co)
764
self.__path__ = [ str(pyzowner) ]
765
self.owner = pyzowner
767
def doimport(self, nm):
768
mod = self.owner.getmod(self.__name__ + '.' + nm)
771
class PyInZipModule(PyModule):
773
def __init__(self, zipowner, nm, pth, co):
774
PyModule.__init__(self, nm, co.co_filename, co)
775
self.owner = zipowner
777
class PkgInZipModule(PyModule):
779
def __init__(self, zipowner, nm, pth, co):
780
PyModule.__init__(self, nm, co.co_filename, co)
782
self.__path__ = [ str(zipowner) ]
783
self.owner = zipowner
785
def doimport(self, nm):
786
mod = self.owner.getmod(self.__name__ + '.' + nm)
790
#======================== Utility ================================#
791
# Scan the code object for imports, __all__ and wierd stuff
794
IMPORT_NAME = dis.opname.index('IMPORT_NAME')
795
IMPORT_FROM = dis.opname.index('IMPORT_FROM')
797
IMPORT_STAR = dis.opname.index('IMPORT_STAR')
800
STORE_NAME = dis.opname.index('STORE_NAME')
801
STORE_FAST = dis.opname.index('STORE_FAST')
802
STORE_GLOBAL = dis.opname.index('STORE_GLOBAL')
803
LOAD_GLOBAL = dis.opname.index('LOAD_GLOBAL')
804
LOAD_ATTR = dis.opname.index('LOAD_ATTR')
805
LOAD_NAME = dis.opname.index('LOAD_NAME')
806
EXEC_STMT = dis.opname.index('EXEC_STMT')
808
SET_LINENO = dis.opname.index('SET_LINENO')
811
BUILD_LIST = dis.opname.index('BUILD_LIST')
812
LOAD_CONST = dis.opname.index('LOAD_CONST')
813
if getattr(sys, 'version_info', (0,0,0)) > (2,5,0):
814
LOAD_CONST_level = LOAD_CONST
816
LOAD_CONST_level = 999
817
JUMP_IF_FALSE = dis.opname.index('JUMP_IF_FALSE')
818
JUMP_IF_TRUE = dis.opname.index('JUMP_IF_TRUE')
819
JUMP_FORWARD = dis.opname.index('JUMP_FORWARD')
821
STORE_DEREF = dis.opname.index('STORE_DEREF')
824
COND_OPS = [JUMP_IF_TRUE, JUMP_IF_FALSE]
825
STORE_OPS = [STORE_NAME, STORE_FAST, STORE_GLOBAL, STORE_DEREF]
826
#IMPORT_STAR -> IMPORT_NAME mod ; IMPORT_STAR
827
#JUMP_IF_FALSE / JUMP_IF_TRUE / JUMP_FORWARD
842
if op >= dis.HAVE_ARGUMENT:
843
oparg = ord(code[i]) + ord(code[i+1])*256
847
if not incondition and op in COND_OPS:
850
elif incondition and op == JUMP_FORWARD:
851
out = max(out, i + oparg)
855
instrs.append((op, oparg, incondition, curline))
858
def scan_code(co, m=None, w=None, b=None, nested=0):
859
instrs = pass1(co.co_code)
868
level = -1 # import-level, same behaviour as up to Python 2.4
869
for i in range(len(instrs)):
870
op, oparg, conditional, curline = instrs[i]
871
if op == IMPORT_NAME:
873
name = lastname = co.co_names[oparg]
875
name = lastname = co.co_names[oparg]
876
#print 'import_name', name, `lastname`, level
877
m.append((name, nested, conditional, level))
878
elif op == IMPORT_FROM:
879
name = co.co_names[oparg]
880
#print 'import_from', name, `lastname`, level,
881
if level > 0 and (not lastname or lastname[-1:] == '.'):
882
name = lastname + name
884
name = lastname + '.' + name
886
m.append((name, nested, conditional, level))
887
assert lastname is not None
888
elif op == IMPORT_STAR:
889
m.append((lastname+'.*', nested, conditional, level))
890
elif op == STORE_NAME:
891
if co.co_names[oparg] == "__all__":
893
pop, poparg, pcondtl, pline = instrs[j]
894
if pop != BUILD_LIST:
895
w.append("W: __all__ is built strangely at line %s" % pline)
900
pop, poparg, pcondtl, pline = instrs[j]
901
if pop == LOAD_CONST:
902
all.append(co.co_consts[poparg])
905
elif op in STORE_OPS:
907
elif op == LOAD_CONST_level:
908
# starting with Python 2.5, _each_ import is preceeded with a
909
# LOAD_CONST to indicate the relative level.
910
if isinstance(co.co_consts[oparg], (int, long)):
911
level = co.co_consts[oparg]
912
elif op == LOAD_GLOBAL:
913
name = co.co_names[oparg]
914
cndtl = ['', 'conditional'][conditional]
915
lvl = ['top-level', 'delayed'][nested]
916
if name == "__import__":
917
w.append("W: %s %s __import__ hack detected at line %s" % (lvl, cndtl, curline))
919
w.append("W: %s %s eval hack detected at line %s" % (lvl, cndtl, curline))
920
elif op == EXEC_STMT:
921
cndtl = ['', 'conditional'][conditional]
922
lvl = ['top-level', 'delayed'][nested]
923
w.append("W: %s %s exec statement detected at line %s" % (lvl, cndtl, curline))
928
# ctypes scanning requires a scope wider than one bytecode instruction,
929
# so the code resides in a separate function for clarity.
930
ctypesb, ctypesw = scan_code_for_ctypes(co, instrs, i)
934
for c in co.co_consts:
935
if isinstance(c, type(co)):
936
# FIXME: "all" was not updated here nor returned. Was it the desired
938
_, _, _, all_nested = scan_code(c, m, w, b, 1)
940
all.extend(all_nested)
943
def scan_code_for_ctypes(co, instrs, i):
944
"""Detects ctypes dependencies, using reasonable heuristics that should
945
cover most common ctypes usages; returns a tuple of two lists, one
946
containing names of binaries detected as dependencies, the other containing
950
def _libFromConst(i):
951
"""Extracts library name from an expected LOAD_CONST instruction and
952
appends it to local binaries list.
954
op, oparg, conditional, curline = instrs[i]
956
soname = co.co_consts[oparg]
961
op, oparg, conditional, curline = instrs[i]
963
if op in (LOAD_GLOBAL, LOAD_NAME):
964
name = co.co_names[oparg]
966
if name in ("CDLL", "WinDLL"):
967
# Guesses ctypes imports of this type: CDLL("library.so")
969
# LOAD_GLOBAL 0 (CDLL) <--- we "are" here right now
970
# LOAD_CONST 1 ('library.so')
974
elif name == "ctypes":
975
# Guesses ctypes imports of this type: ctypes.DLL("library.so")
977
# LOAD_GLOBAL 0 (ctypes) <--- we "are" here right now
979
# LOAD_CONST 1 ('library.so')
981
op2, oparg2, conditional2, curline2 = instrs[i+1]
983
if co.co_names[oparg2] in ("CDLL", "WinDLL"):
984
# Fetch next, and finally get the library name
987
elif name == ("cdll", "windll"):
988
# Guesses ctypes imports of these types:
990
# * cdll.library (only valid on Windows)
992
# LOAD_GLOBAL 0 (cdll) <--- we "are" here right now
993
# LOAD_ATTR 1 (library)
995
# * cdll.LoadLibrary("library.so")
997
# LOAD_GLOBAL 0 (cdll) <--- we "are" here right now
998
# LOAD_ATTR 1 (LoadLibrary)
999
# LOAD_CONST 1 ('library.so')
1001
op2, oparg2, conditional2, curline2 = instrs[i+1]
1002
if op2 == LOAD_ATTR:
1003
if co.co_names[oparg2] != "LoadLibrary":
1005
soname = co.co_names[oparg2] + ".dll"
1008
# Second type, needs to fetch one more instruction
1011
# If any of the libraries has been requested with anything different from
1012
# the bare filename, drop that entry and warn the user - pyinstaller would
1013
# need to patch the compiled pyc file to make it work correctly!
1017
if bin != os.path.basename(bin):
1019
w.append("W: ignoring %s - ctypes imports only supported using bare filenames" % (bin,))
1024
def _resolveCtypesImports(cbinaries):
1025
"""Completes ctypes BINARY entries for modules with their full path.
1027
if sys.platform.startswith("linux"):
1028
envvar = "LD_LIBRARY_PATH"
1029
elif sys.platform.startswith("darwin"):
1030
envvar = "DYLD_LIBRARY_PATH"
1035
old = os.environ.get(envvar, None)
1036
os.environ[envvar] = os.pathsep.join(sys.pathex)
1038
os.environ[envvar] = os.pathsep.join([os.environ[envvar], old])
1041
def _restorePaths(old):
1042
del os.environ[envvar]
1044
os.environ[envvar] = old
1048
# Try to locate the shared library on disk. This is done by
1049
# executing ctypes.utile.find_library prepending ImportTracker's
1050
# local paths to library search paths, then replaces original values.
1052
for cbin in cbinaries:
1053
cpath = find_library(os.path.splitext(cbin)[0])
1054
if sys.platform == "linux2":
1055
# CAVEAT: find_library() is not the correct function. Ctype's
1056
# documentation says that it is meant to resolve only the filename
1057
# (as a *compiler* does) not the full path. Anyway, it works well
1058
# enough on Windows and Mac. On Linux, we need to implement
1059
# more code to find out the full path.
1062
# "man ld.so" says that we should first search LD_LIBRARY_PATH
1063
# and then the ldcache
1064
for d in os.environ["LD_LIBRARY_PATH"].split(":"):
1065
if os.path.isfile(d + "/" + cpath):
1066
cpath = d + "/" + cpath
1069
for L in os.popen("ldconfig -p").read().splitlines():
1071
cpath = L.split("=>", 1)[1].strip()
1072
assert os.path.isfile(cpath)
1077
print "W: library %s required via ctypes not found" % (cbin,)
1079
ret.append((cbin, cpath, "BINARY"))