diff options
author | craig <craig@11d20701-8431-0410-a711-e3c959e3b870> | 2012-01-01 11:40:09 +0000 |
---|---|---|
committer | craig <craig@11d20701-8431-0410-a711-e3c959e3b870> | 2012-01-01 11:40:09 +0000 |
commit | 7ed83b6c6666eb8b6b104c211ae7e52907350372 (patch) | |
tree | 4430b556abac0ad660a0aacf1887d77f85d8be02 /OSX-package/linktools/MachO.py | |
download | scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.tar.gz scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.tar.xz scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.zip |
Branch 1.3.5 tree to 1.4.x tree, goodbye 1.3.x
git-svn-id: svn://scribus.net/branches/Version14x/Scribus@17163 11d20701-8431-0410-a711-e3c959e3b870
Diffstat (limited to 'OSX-package/linktools/MachO.py')
-rw-r--r-- | OSX-package/linktools/MachO.py | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/OSX-package/linktools/MachO.py b/OSX-package/linktools/MachO.py new file mode 100644 index 0000000..847d539 --- /dev/null +++ b/OSX-package/linktools/MachO.py @@ -0,0 +1,215 @@ +import os +import re +import shutil + + +def findFramework(path, name = None): + "find the framework folder for FW name" + if path == "" or path == "@executable_path" or path == "/": + return None + elif name == None: + return findFramework(os.path.dirname(path), + os.path.basename(path)) + elif os.path.basename(path) == name + ".framework": + return path + elif len(os.path.dirname(path)) >= len(path): + print "MachO.findFramework: Oops '" + path + "', '" + name + "'" + return None + else: + return findFramework(os.path.dirname(path), name) + + + +def stripPrefix(prefix, path): + "Returns the relative path r such that os.path.join(prefix, r) == path" + prefix = os.path.normpath(prefix) + prefixLen = len(prefix) + path = os.path.normpath(path) + if path[0 : prefixLen] == prefix: + if path[prefixLen] == os.sep: + return path[prefixLen+1 : ] + else: + return path[prefixLen : ] + else: + return path + + +class Executable: + "Represents an Mach-O executable." + + def __init__(self, path, kind): + self.Location = path + self.Kind = kind + + + def __repr__(self): + return self.Location + " (" + self.Kind + ")" + + + def getDependencies(self): + "Return a list of MachO.Fixes describing the dependencies." + "Uses otool -L" + f = os.popen("otool -L " + self.Location, "r") + result = [] + pat = re.compile("\s*([^(]*)\s\((.+)\)") + for line in f: + m = pat.match(line) + if m != None: + result.append(Fix(m.group(1), m.group(2))) + status = f.close() + return result + + def applyFixes(self, changes, log): + "Uses install_name_tool to change the links to dependencies." + "changes is a dictionary mapping links (as strings) to Fixes." + args = "" + for dep in self.getDependencies(): + if dep.Link in changes: + args = args + changes[dep.Link].getChange() + log.append(">> " + "install_name_tool " + args + self.Location) + if len(args) > 0: + os.system("install_name_tool " + args + self.Location) + pat = re.compile("(library)|(universal binary)") + if pat.search(self.Kind): + relName = os.path.basename(self.Location) # FIXME: rel to fw + log.append(">> " + "install_name_tool -id " + relName + + " " + self.Location) + os.system("install_name_tool -id " + relName + + " " + self.Location) + + +def findExecutables(bundleDir): + "Return a list of MachO.Executables found in bundleDir" + result = [] + pat = re.compile("Mach-O (.+)") + for root, dirs, files in os.walk(bundleDir): + for n in files: + p = os.path.join(root, n) + f = os.popen("file -b " + p, "r") + m = pat.match(f.readline()) + if m != None: + result.append(Executable(p, m.group(1))) + print "found " + m.group(1) + ": " + n + f.close() + return result
+ + + +class Fix: + "Represents a fix for a library link." + + def __init__(self, dependency, versionString="?"): + self.Link = dependency + self.Location = dependency + self.NewLink = dependency + self.NewLocation = dependency + self.versionString = versionString # not used yet + self.fwPath = None + self.relPath = None + + def __repr__(self): + return (self.Link + " (" + self.versionString + ")") + + def isAbsolute(self): + return os.path.isabs(self.Link) + + def isBundleRelative(self): + return self.Link[0:17] == "@executable_path/" + + def isSystem(self): + return (self.Location[0:8] == "/usr/lib" # also matches libexec + or self.Location[0:8] == "/usr/X11" # also matches X11R6 + or self.Location[0:8] == "/System/") + + def getChange(self): + "Returns argument for install_name_tool." + if self.Link == self.NewLink: + return "" + else: + return "-change " + self.Link + " " + self.NewLink + " " + + def findLocation(self, exePath=None): + if self.isBundleRelative(): + if exePath != None: + self.Location = os.path.normpath( + os.path.join(exePath, self.Link[17:])) + else: + self.Location = self.Link[17:] + else: + self.Location = self.Link + + # check if done + if (os.path.isabs(self.Location) and + os.path.isfile(self.Location)): + self.NewLocation = self.Location + return True + + # search for frameworks in /System/Library and /Library + fwPath = findFramework(self.Location) + if fwPath: + fwdir = os.path.dirname(fwPath) + self.relPath = stripPrefix(fwdir, self.Location) + for d in ["/Library/Frameworks", + "/System/Library/Frameworks"]: + if os.path.isfile(os.path.join(d, self.relPath)): +# self.Location = os.path.join(d, self.relPath) + self.Location = os.path.join(d, self.relPath) + self.NewLocation = self.Location + self.fwPath = os.path.join(d, os.path.basename(fwPath)) + self.relPath = stripPrefix(self.fwPath, self.Location) + return True + + # ok, try libs + lib = os.path.basename(self.Location) + self.relPath = None + for d in ["/usr/local/lib", "/opt/local/lib", + "/usr/lib", "/opt/lib"]: + if os.path.isfile(os.path.join(d, lib)): + self.Location = os.path.join(d, lib) + self.NewLocation = self.Location + return True + + # not found + return False + + + def moveLibrary(self, destBundlePath, stripFW, log): + "Copies the library or fw to destBundlePath." + "Also sets NewLink and NewLocation properties" + "Returns a list of copied executables" + + # dont do this if we are already inside the bundle: + if stripPrefix(destBundlePath, self.Location) != self.Location: + log.append("-- ignoring " + self.Location) + return [] + + if self.relPath != None and not stripFW: + # copy framework + newFwPath = os.path.join(destBundlePath, + "Contents/Frameworks", + os.path.basename(self.fwPath)) + log.append(">> " + self.fwPath + " ===> " + newFwPath) + if (os.path.exists(destBundlePath) and + not os.path.exists(newFwPath)): + shutil.copytree(self.fwPath, newFwPath, True) + self.NewLocation = os.path.join(newFwPath, self.relPath) + self.NewLink = ("@executable_path/" + + os.path.join("../Frameworks", + os.path.basename(self.fwPath), + self.relPath)) + return findExecutables(newFwPath) + else: + # copy lib to bundle.app/Contents/Frameworks/ + self.NewLocation = os.path.join(destBundlePath, + "Contents/Frameworks", + os.path.basename(self.Location)) + self.NewLink = ("@executable_path/" + + os.path.join("../Frameworks", + os.path.basename(self.Location))) + log.append(">> " + self.Location + " ---> " + self.NewLocation) + if (os.path.exists(destBundlePath) and + not os.path.exists(self.NewLocation)): + shutil.copy(self.Location, self.NewLocation) + return [Executable(self.NewLocation, "lib")] + +
\ No newline at end of file |