X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=scripts%2Fbuild%2Fmacosx_DeployApp.py;h=e6cfc1d189ac29f4acc49fbf8133789fb40c81b2;hp=4be32f7fdd0efd79a7c8c14dfae446838e08fd0e;hb=f89390a2e9ba9a4a64f3a545c147c046fbe07a16;hpb=335e3cf6203327b3ce1ee6e47c09a8139232317c diff --git a/scripts/build/macosx_DeployApp.py b/scripts/build/macosx_DeployApp.py index 4be32f7f..e6cfc1d1 100755 --- a/scripts/build/macosx_DeployApp.py +++ b/scripts/build/macosx_DeployApp.py @@ -15,37 +15,153 @@ # ============================== import sys import os +import os.path + +from subprocess import Popen, PIPE + +# ============================== +# Constants +# ============================== +QT_CONFIG = """[Paths] + Plugins = plugins +""" + +QT_CONFIG_NOBUNDLE = """[Paths] + Prefix = ../ + Plugins = plugins +""" + class InstallQt(object): - def __init__(self, appdir, bundle = True): + def __init__(self, appdir, bundle=True, requestedPlugins=[]): self.appDir = appdir self.bundle = bundle + self.frameworkDir = self.appDir + "/Frameworks" + self.pluginDir = self.appDir + "/plugins" self.executableDir = self.appDir if bundle: self.executableDir += "/MacOS" - if bundle: - self.frameworkDir = self.appDir + "/Frameworks" - else: - self.frameworkDir = self.executableDir + "/Frameworks" + self.installedFrameworks = set() - self.needFrameworks = [] + self.findFrameworkPath() executables = [self.executableDir + "/" + executable for executable in os.listdir(self.executableDir)] - for executable in executables: - for framework,lib in self.determineDependancies(executable): - if framework not in self.needFrameworks: - self.needFrameworks.append(framework) - self.installFramework(framework) - self.changeDylPath(executable) + self.resolveDependancies(executable) + + self.findPluginsPath() + self.installPlugins(requestedPlugins) + self.installQtConf() + + def qtProperty(self, qtProperty): + """ + Query persistent property of Qt via qmake + """ + VALID_PROPERTIES = ['QT_INSTALL_PREFIX', + 'QT_INSTALL_DATA', + 'QT_INSTALL_DOCS', + 'QT_INSTALL_HEADERS', + 'QT_INSTALL_LIBS', + 'QT_INSTALL_BINS', + 'QT_INSTALL_PLUGINS', + 'QT_INSTALL_IMPORTS', + 'QT_INSTALL_TRANSLATIONS', + 'QT_INSTALL_CONFIGURATION', + 'QT_INSTALL_EXAMPLES', + 'QT_INSTALL_DEMOS', + 'QMAKE_MKSPECS', + 'QMAKE_VERSION', + 'QT_VERSION' + ] + if qtProperty not in VALID_PROPERTIES: + return None + + qmakeProcess = Popen('qmake -query %s' % qtProperty, shell=True, stdout=PIPE, stderr=PIPE) + result = qmakeProcess.stdout.read().strip() + qmakeProcess.stdout.close() + qmakeProcess.wait() + return result + + def findFrameworkPath(self): + self.sourceFrameworkPath = self.qtProperty('QT_INSTALL_LIBS') + + def findPluginsPath(self): + self.sourcePluginsPath = self.qtProperty('QT_INSTALL_PLUGINS') + + def findPlugin(self, pluginname): + qmakeProcess = Popen('find %s -name %s' % (self.sourcePluginsPath, pluginname), shell=True, stdout=PIPE, stderr=PIPE) + result = qmakeProcess.stdout.read().strip() + qmakeProcess.stdout.close() + qmakeProcess.wait() + if not result: + raise OSError + return result + + def installPlugins(self, requestedPlugins): + try: + os.mkdir(self.pluginDir) + except: + pass + + for plugin in requestedPlugins: + if not plugin.isalnum(): + print "Skipping library '%s'..." % plugin + continue + + pluginName = "lib%s.dylib" % plugin + pluginSource = '' + try: + pluginSource = self.findPlugin(pluginName) + except OSError: + print "WARNING: Requested library does not exist: '%s'" % plugin + continue + + pluginSubDir = os.path.dirname(pluginSource) + pluginSubDir = pluginSubDir.replace(self.sourcePluginsPath, '').strip('/') + try: + os.mkdir("%s/%s" % (self.pluginDir, pluginSubDir)) + except OSError: + pass + + os.system('cp "%s" "%s/%s"' % (pluginSource, self.pluginDir, pluginSubDir)) + + self.resolveDependancies("%s/%s/%s" % (self.pluginDir, pluginSubDir, pluginName)) + + def installQtConf(self): + qtConfName = self.appDir + "/qt.conf" + qtConfContent = QT_CONFIG_NOBUNDLE + if self.bundle: + qtConfContent = QT_CONFIG + qtConfName = self.appDir + "/Resources/qt.conf" + + qtConf = open(qtConfName, 'w') + qtConf.write(qtConfContent) + qtConf.close() + + def resolveDependancies(self, obj): + # obj must be either an application binary or a framework library + # print "resolving deps for:", obj + for framework, lib in self.determineDependancies(obj): + self.installFramework(framework) + self.changeDylPath(obj, framework, lib) def installFramework(self, framework): + # skip if framework is already installed. + if framework in self.installedFrameworks: + return + + self.installedFrameworks.add(framework) + + # ensure that the framework directory exists try: os.mkdir(self.frameworkDir) except: pass + if not framework.startswith('/'): + framework = "%s/%s" % (self.sourceFrameworkPath, framework) + # Copy Framework os.system('cp -R "%s" "%s"' % (framework, self.frameworkDir)) @@ -59,55 +175,63 @@ class InstallQt(object): # Install new Lib ID and Change Path to Frameworks for the Dynamic linker for lib in os.listdir(localframework + "/Versions/Current"): lib = "%s/Versions/Current/%s" % (localframework, lib) - otoolpipe = os.popen('otool -D "%s"' % lib) - libname = [line for line in otoolpipe][1].strip() - otoolpipe.close() + otoolProcess = Popen('otool -D "%s"' % lib, shell=True, stdout=PIPE, stderr=PIPE) + try: + libname = [line for line in otoolProcess.stdout][1].strip() + except: + libname = '' + otoolProcess.stdout.close() + if otoolProcess.wait() == 1: # we found some Resource dir or similar -> skip + continue frameworkpath, libpath = libname.split(frameworkname) if self.bundle: newlibname = "@executable_path/../%s%s" % (frameworkname, libpath) else: newlibname = "@executable_path/%s%s" % (frameworkname, libpath) - #print 'install_name_tool -id "%s" "%s"' % (newlibname, lib) + # print 'install_name_tool -id "%s" "%s"' % (newlibname, lib) os.system('install_name_tool -id "%s" "%s"' % (newlibname, lib)) - self.changeDylPath(lib) - + + self.resolveDependancies(lib) + def determineDependancies(self, app): - otoolPipe = os.popen('otool -L "%s"' % app) + otoolPipe = Popen('otool -L "%s"' % app, shell=True, stdout=PIPE).stdout otoolOutput = [line for line in otoolPipe] otoolPipe.close() - libs = [line.split()[0] for line in otoolOutput[1:] if "Qt" in line and not "@executable_path" in line] - frameworks = [lib[:lib.find(".framework")+len(".framework")] for lib in libs] + libs = [line.split()[0] for line in otoolOutput[1:] if ("Qt" in line or "phonon" in line) and "@executable_path" not in line] + frameworks = [lib[:lib.find(".framework") + len(".framework")] for lib in libs] + frameworks = [framework[framework.rfind('/') + 1:] for framework in frameworks] return zip(frameworks, libs) - def changeDylPath(self, obj): - for framework, lib in self.determineDependancies(obj): - frameworkname = framework.split('/')[-1] - frameworkpath, libpath = lib.split(frameworkname) - if self.bundle: - newlibname = "@executable_path/../Frameworks/%s%s" % (frameworkname, libpath) - else: - newlibname = "@executable_path/Frameworks/%s%s" % (frameworkname, libpath) + def changeDylPath(self, obj, framework, lib): + newlibname = framework + lib.split(framework)[1] + if self.bundle: + newlibname = "@executable_path/../Frameworks/%s" % newlibname + else: + newlibname = "@executable_path/Frameworks/%s" % newlibname - #print 'install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj) - os.system('install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj)) + # print 'install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj) + os.system('install_name_tool -change "%s" "%s" "%s"' % (lib, newlibname, obj)) if __name__ == "__main__": if len(sys.argv) < 2: - print "Wrong Argument Count (Syntax: %s [--nobundle] $TARGET_APP)" % sys.argv[0] + print "Wrong Argument Count (Syntax: %s [--nobundle] [--plugins=plugin1,plugin2,...] $TARGET_APP)" % sys.argv[0] sys.exit(1) else: bundle = True + plugins = [] offset = 1 - if sys.argv[1].startswith("--"): - offset = 2 - if sys.argv[1] == "--nobundle": + while offset < len(sys.argv) and sys.argv[offset].startswith("--"): + if sys.argv[offset] == "--nobundle": bundle = False + if sys.argv[offset].startswith("--plugins="): + plugins = sys.argv[offset].split('=')[1].split(',') + + offset += 1 + targetDir = sys.argv[offset] if bundle: targetDir += "/Contents" - InstallQt(targetDir, bundle) - - + InstallQt(targetDir, bundle, plugins)