1
|
#!/usr/bin/python
|
2
|
|
3
|
r"""depends.py - find the ordered dependancies of a library/executable (deepest first)
|
4
|
|
5
|
To use this:
|
6
|
depends.py <pathtolibrary/pathtoexecutable>
|
7
|
|
8
|
"""
|
9
|
__author__ = "Robin Mills <robin@clanmills.com>"
|
10
|
|
11
|
import string
|
12
|
import os
|
13
|
import sys
|
14
|
from sets import Set
|
15
|
|
16
|
##
|
17
|
# recursively update dependdict for libname (which can be @executable_path etc)
|
18
|
# execdir is the directory of @executable_path
|
19
|
# loaddir is the directory of @loader_path
|
20
|
# returns path to libname or '' (empty string)
|
21
|
def depend(execdir,loaddir,libname,dependdict):
|
22
|
""" recursive descent of the libraries """
|
23
|
# print "depend: execdir=%s, loadpath=%s, libname=%s" % (execdir,loadpath,libname)
|
24
|
|
25
|
##
|
26
|
# discover libpath for libname
|
27
|
epath='@executable_path/'
|
28
|
lpath='@loader_path/'
|
29
|
libpath=libname
|
30
|
if libname[:len(epath)] == epath:
|
31
|
libpath=os.path.join(execdir,libname[len(epath):])
|
32
|
if libname[:len(lpath)] == lpath:
|
33
|
libpath=os.path.join(loadpath,libname[len(lpath):])
|
34
|
libpath=os.path.abspath(libpath)
|
35
|
|
36
|
if os.path.isfile(libpath):
|
37
|
if not dependdict.has_key(libpath):
|
38
|
dependdict[libpath]=Set([]) # push now to prevent infinite loop in recursion
|
39
|
cmd = 'otool -L "%s"' % libpath # otool -L prints library dependancies:
|
40
|
# libpath:
|
41
|
# <tab>dependancy (metadata) ...
|
42
|
for line in os.popen(cmd).readlines(): # run cmd
|
43
|
if line[:1]=='\t': # parse <tab>dependancy (metadata)
|
44
|
dependancy=line.split()[0]
|
45
|
# print libpath,' => ',dependancy
|
46
|
# recurse to find dependancies of dependancy
|
47
|
dpath=depend(execdir,libpath,dependancy,dependdict)
|
48
|
dependdict[libpath].add(dpath) # update dependdict from recursion
|
49
|
else:
|
50
|
print "*** error NOT a FILE libname=%s libpath=%s ***" % (libname,libpath)
|
51
|
libpath=''
|
52
|
|
53
|
return libpath
|
54
|
|
55
|
##
|
56
|
#
|
57
|
def tsort(dependdict): # returns (ordered) array of libraries
|
58
|
filename='/tmp/tsortXX.txt'
|
59
|
file=open(filename,'w')
|
60
|
for key in dependdict.keys():
|
61
|
depends=dependdict[key]
|
62
|
for d in depends:
|
63
|
if len(d) > 0:
|
64
|
file.write( '%s %s\n' % (key,d) )
|
65
|
file.close()
|
66
|
cmd='tsort "%s" 2>/dev/null' % (filename)
|
67
|
lines=os.popen(cmd).readlines()
|
68
|
lines.reverse()
|
69
|
|
70
|
result=[]
|
71
|
for line in lines:
|
72
|
result.append(line[:-1])
|
73
|
return result;
|
74
|
#
|
75
|
##
|
76
|
|
77
|
##
|
78
|
#
|
79
|
def main(argv):
|
80
|
##
|
81
|
# dependdict key is a library path. Value is a set of dependant library paths
|
82
|
dependdict = {} # dependdict['/usr/lib/foo.dylib'] = Set([ '/usr/lib/a.dylib', ... ])
|
83
|
libname = argv[0]
|
84
|
execdir = os.path.abspath(os.path.join(libname,'..'))
|
85
|
|
86
|
##
|
87
|
# recursively build the dependency dictionary
|
88
|
depend(execdir,execdir,libname,dependdict)
|
89
|
|
90
|
##
|
91
|
# sort and report
|
92
|
results=tsort(dependdict)
|
93
|
for result in results:
|
94
|
print result
|
95
|
#
|
96
|
##
|
97
|
|
98
|
if __name__ == '__main__':
|
99
|
main(sys.argv[1:])
|
100
|
|
101
|
# That's all Folks!
|
102
|
##
|