6
def findFramework(path, name = None):
7
"find the framework folder for FW name"
8
if path == "" or path == "@executable_path" or path == "/":
11
return findFramework(os.path.dirname(path),
12
os.path.basename(path))
13
elif os.path.basename(path) == name + ".framework":
15
elif len(os.path.dirname(path)) >= len(path):
16
print "MachO.findFramework: Oops '" + path + "', '" + name + "'"
19
return findFramework(os.path.dirname(path), name)
23
def stripPrefix(prefix, path):
24
"Returns the relative path r such that os.path.join(prefix, r) == path"
25
prefix = os.path.normpath(prefix)
26
prefixLen = len(prefix)
27
path = os.path.normpath(path)
28
if path[0 : prefixLen] == prefix:
29
if path[prefixLen] == os.sep:
30
return path[prefixLen+1 : ]
32
return path[prefixLen : ]
38
"Represents an Mach-O executable."
40
def __init__(self, path, kind):
46
return self.Location + " (" + self.Kind + ")"
49
def getDependencies(self):
50
"Return a list of MachO.Fixes describing the dependencies."
52
f = os.popen("otool -L " + self.Location, "r")
54
pat = re.compile("\s*([^(]*)\s\((.+)\)")
58
result.append(Fix(m.group(1), m.group(2)))
62
def applyFixes(self, changes, log):
63
"Uses install_name_tool to change the links to dependencies."
64
"changes is a dictionary mapping links (as strings) to Fixes."
66
for dep in self.getDependencies():
67
if dep.Link in changes:
68
args = args + changes[dep.Link].getChange()
69
log.append(">> " + "install_name_tool " + args + self.Location)
71
os.system("install_name_tool " + args + self.Location)
72
pat = re.compile("(library)|(universal binary)")
73
if pat.search(self.Kind):
74
relName = os.path.basename(self.Location) # FIXME: rel to fw
75
log.append(">> " + "install_name_tool -id " + relName +
77
os.system("install_name_tool -id " + relName +
81
def findExecutables(bundleDir):
82
"Return a list of MachO.Executables found in bundleDir"
84
pat = re.compile("Mach-O (.+)")
85
for root, dirs, files in os.walk(bundleDir):
87
p = os.path.join(root, n)
88
f = os.popen("file -b " + p, "r")
89
m = pat.match(f.readline())
91
result.append(Executable(p, m.group(1)))
92
print "found " + m.group(1) + ": " + n
99
"Represents a fix for a library link."
101
def __init__(self, dependency, versionString="?"):
102
self.Link = dependency
103
self.Location = dependency
104
self.NewLink = dependency
105
self.NewLocation = dependency
106
self.versionString = versionString # not used yet
111
return (self.Link + " (" + self.versionString + ")")
113
def isAbsolute(self):
114
return os.path.isabs(self.Link)
116
def isBundleRelative(self):
117
return self.Link[0:17] == "@executable_path/"
120
return (self.Location[0:8] == "/usr/lib" # also matches libexec
121
or self.Location[0:8] == "/usr/X11" # also matches X11R6
122
or self.Location[0:8] == "/System/")
125
"Returns argument for install_name_tool."
126
if self.Link == self.NewLink:
129
return "-change " + self.Link + " " + self.NewLink + " "
131
def findLocation(self, exePath=None):
132
if self.isBundleRelative():
134
self.Location = os.path.normpath(
135
os.path.join(exePath, self.Link[17:]))
137
self.Location = self.Link[17:]
139
self.Location = self.Link
142
if (os.path.isabs(self.Location) and
143
os.path.isfile(self.Location)):
144
self.NewLocation = self.Location
147
# search for frameworks in /System/Library and /Library
148
fwPath = findFramework(self.Location)
150
fwdir = os.path.dirname(fwPath)
151
self.relPath = stripPrefix(fwdir, self.Location)
152
for d in ["/Library/Frameworks",
153
"/System/Library/Frameworks"]:
154
if os.path.isfile(os.path.join(d, self.relPath)):
155
# self.Location = os.path.join(d, self.relPath)
156
self.Location = os.path.join(d, self.relPath)
157
self.NewLocation = self.Location
158
self.fwPath = os.path.join(d, os.path.basename(fwPath))
159
self.relPath = stripPrefix(self.fwPath, self.Location)
163
lib = os.path.basename(self.Location)
165
for d in ["/usr/local/lib", "/opt/local/lib",
166
"/usr/lib", "/opt/lib"]:
167
if os.path.isfile(os.path.join(d, lib)):
168
self.Location = os.path.join(d, lib)
169
self.NewLocation = self.Location
176
def moveLibrary(self, destBundlePath, stripFW, log):
177
"Copies the library or fw to destBundlePath."
178
"Also sets NewLink and NewLocation properties"
179
"Returns a list of copied executables"
181
# dont do this if we are already inside the bundle:
182
if stripPrefix(destBundlePath, self.Location) != self.Location:
183
log.append("-- ignoring " + self.Location)
186
if self.relPath != None and not stripFW:
188
newFwPath = os.path.join(destBundlePath,
189
"Contents/Frameworks",
190
os.path.basename(self.fwPath))
191
log.append(">> " + self.fwPath + " ===> " + newFwPath)
192
if (os.path.exists(destBundlePath) and
193
not os.path.exists(newFwPath)):
194
shutil.copytree(self.fwPath, newFwPath, True)
195
self.NewLocation = os.path.join(newFwPath, self.relPath)
196
self.NewLink = ("@executable_path/"
197
+ os.path.join("../Frameworks",
198
os.path.basename(self.fwPath),
200
return findExecutables(newFwPath)
202
# copy lib to bundle.app/Contents/Frameworks/
203
self.NewLocation = os.path.join(destBundlePath,
204
"Contents/Frameworks",
205
os.path.basename(self.Location))
206
self.NewLink = ("@executable_path/"
207
+ os.path.join("../Frameworks",
208
os.path.basename(self.Location)))
209
log.append(">> " + self.Location + " ---> " + self.NewLocation)
210
if (os.path.exists(destBundlePath) and
211
not os.path.exists(self.NewLocation)):
212
shutil.copy(self.Location, self.NewLocation)
213
return [Executable(self.NewLocation, "lib")]
b'\\ No newline at end of file'