summaryrefslogtreecommitdiffstats
path: root/OSX-package/linktools/MachO.py
diff options
context:
space:
mode:
authorcraig <craig@11d20701-8431-0410-a711-e3c959e3b870>2012-01-01 11:40:09 +0000
committercraig <craig@11d20701-8431-0410-a711-e3c959e3b870>2012-01-01 11:40:09 +0000
commit7ed83b6c6666eb8b6b104c211ae7e52907350372 (patch)
tree4430b556abac0ad660a0aacf1887d77f85d8be02 /OSX-package/linktools/MachO.py
downloadscribus-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.py215
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