diff options
author | Alexandru Croitor <alexandru.croitor@qt.io> | 2017-11-02 11:50:25 +0100 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2017-11-15 15:47:02 +0000 |
commit | 8815ef1cfddd79b99314a8e8e351b1a2235afc26 (patch) | |
tree | 99aad14c7f58c3be9141cbc4d7a8c9ff806e9ab5 /setup.py | |
parent | cadc370720773b4372496fafc40b34f604da6f9b (diff) |
Make standalone option work on macOS
Implements standalone option on macOS, both for .dylib Qt build and
framework build. Multiple rules are applied to figure out which files
need to be copied into the final package.
We also take care to embed a proper LC_RPATH for the PySide libraries,
so that they point to the copied over Qt libraries.
Change-Id: I442749e7c2318a66a22e3a1dd0ae703fb8943acf
Task-number: PYSIDE-558
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'setup.py')
-rw-r--r-- | setup.py | 161 |
1 files changed, 130 insertions, 31 deletions
@@ -151,6 +151,7 @@ import sys import platform import time import re +import fnmatch import difflib # for a close match of dirname and module @@ -301,10 +302,6 @@ if OPTION_JOBS: else: OPTION_JOBS = '' -if sys.platform == 'darwin' and OPTION_STANDALONE: - print("--standalone option does not yet work on OSX") - - # Show available versions if OPTION_LISTVERSIONS: for v in submodules: @@ -938,11 +935,15 @@ class pyside_build(_build): "qt_bin_dir": self.qtinfo.bins_dir, "qt_doc_dir": self.qtinfo.docs_dir, "qt_lib_dir": self.qtinfo.libs_dir, + "qt_lib_execs_dir": self.qtinfo.lib_execs_dir, "qt_plugins_dir": self.qtinfo.plugins_dir, + "qt_prefix_dir": self.qtinfo.prefix_dir, "qt_translations_dir": self.qtinfo.translations_dir, + "qt_qml_dir": self.qtinfo.qml_dir, "version": version_str, } os.chdir(self.script_dir) + if sys.platform == "win32": vars['dbgPostfix'] = OPTION_DEBUG and "_d" or "" return self.prepare_packages_win32(vars) @@ -1050,36 +1051,131 @@ class pyside_build(_build): # Copy Qt libs to package if OPTION_STANDALONE: if sys.platform == 'darwin': - raise RuntimeError('--standalone not yet supported for OSX') - # <qt>/bin/* -> <setup>/PySide2 - executables.extend(copydir("{qt_bin_dir}", "{dist_dir}/PySide2", - filter=[ - "designer", - "linguist", - "lrelease", - "lupdate", - "lconvert", - ], - recursive=False, vars=vars)) - # <qt>/lib/* -> <setup>/PySide2 - copydir("{qt_lib_dir}", "{dist_dir}/PySide2", - filter=[ - "libQt*.so.?", - "libphonon.so.?", - ], - recursive=False, vars=vars) - # <qt>/plugins/* -> <setup>/PySide2/plugins - copydir("{qt_plugins_dir}", "{dist_dir}/PySide2/plugins", - filter=["*.so"], - vars=vars) - # <qt>/translations/* -> <setup>/PySide2/translations - copydir("{qt_translations_dir}", "{dist_dir}/PySide2/translations", - filter=["*.qm"], - vars=vars) + self.prepare_standalone_package_osx(executables, vars) + else: + # <qt>/bin/* -> <setup>/PySide2 + executables.extend(copydir("{qt_bin_dir}", "{dist_dir}/PySide2", + filter=[ + "designer", + "linguist", + "lrelease", + "lupdate", + "lconvert", + ], + recursive=False, vars=vars)) + # <qt>/lib/* -> <setup>/PySide2 + copydir("{qt_lib_dir}", "{dist_dir}/PySide2", + filter=[ + "libQt*.so.?", + "libphonon.so.?", + ], + recursive=False, vars=vars) + # <qt>/plugins/* -> <setup>/PySide2/plugins + copydir("{qt_plugins_dir}", "{dist_dir}/PySide2/plugins", + filter=["*.so"], + vars=vars) + # <qt>/translations/* -> <setup>/PySide2/translations + copydir("{qt_translations_dir}", "{dist_dir}/PySide2/translations", + filter=["*.qm"], + vars=vars) # Update rpath to $ORIGIN if sys.platform.startswith('linux') or sys.platform.startswith('darwin'): self.update_rpath("{dist_dir}/PySide2".format(**vars), executables) + def qt_is_framework_build(self): + if os.path.isdir(self.qtinfo.headers_dir + "/../lib/QtCore.framework"): + return True + return False + + def prepare_standalone_package_osx(self, executables, vars): + # Get list of built modules, so that we copy only required Qt libraries. + pyside_package_dir = vars['dist_dir'] + built_modules_path = os.path.join(pyside_package_dir, "PySide2", "_built_modules.py") + + with open(built_modules_path) as f: + scoped_locals = {} + code = compile(f.read(), built_modules_path, 'exec') + exec(code, scoped_locals, scoped_locals) + built_modules = scoped_locals['built_modules'] + + # Directory filter for skipping unnecessary files. + def general_dir_filter(dir_name, parent_full_path, dir_full_path): + if fnmatch.fnmatch(dir_name, "*.dSYM"): + return False + return True + + # <qt>/lib/* -> <setup>/PySide2/Qt/lib + if self.qt_is_framework_build(): + framework_built_modules = ['Qt' + name + '.framework' for name in built_modules] + + def framework_dir_filter(dir_name, parent_full_path, dir_full_path): + if '.framework' in dir_name: + if dir_name in ['QtWebEngine.framework', 'QtWebEngineCore.framework', \ + 'QtPositioning.framework', 'QtLocation.framework'] and \ + 'QtWebEngineWidgets.framework' in framework_built_modules: + return True + if dir_name in ['QtCLucene.framework'] and \ + 'QtHelp.framework' in framework_built_modules: + return True + if dir_name not in framework_built_modules: + return False + if dir_name in ['Headers', 'fonts']: + return False + if dir_full_path.endswith('Versions/Current'): + return False + if dir_full_path.endswith('Versions/5/Resources'): + return False + if dir_full_path.endswith('Versions/5/Helpers'): + return False + return general_dir_filter(dir_name, parent_full_path, dir_full_path) + + copydir("{qt_lib_dir}", "{dist_dir}/PySide2/Qt/lib", + recursive=True, vars=vars, + ignore=["*.la", "*.a", "*.cmake", "*.pc", "*.prl"], + dir_filter_function=framework_dir_filter) + else: + if 'WebEngineWidgets' in built_modules: + built_modules.extend(['WebEngine', 'WebEngineCore', 'Positioning', 'Location']) + if 'Help' in built_modules: + built_modules.extend(['CLucene']) + prefixed_built_modules = ['*Qt5' + name + '*.dylib' for name in built_modules] + + copydir("{qt_lib_dir}", "{dist_dir}/PySide2/Qt/lib", + filter=prefixed_built_modules, + recursive=True, vars=vars) + + if 'WebEngineWidgets' in built_modules: + copydir("{qt_lib_execs_dir}", "{dist_dir}/PySide2/Qt/libexec", + filter=None, + recursive=False, + vars=vars) + + copydir("{qt_prefix_dir}/resources", "{dist_dir}/PySide2/Qt/resources", + filter=None, + recursive=False, + vars=vars) + + # <qt>/plugins/* -> <setup>/PySide2/Qt/plugins + copydir("{qt_plugins_dir}", "{dist_dir}/PySide2/Qt/plugins", + filter=["*.dylib"], + recursive=True, + dir_filter_function=general_dir_filter, + vars=vars) + + # <qt>/qml/* -> <setup>/PySide2/Qt/qml + copydir("{qt_qml_dir}", "{dist_dir}/PySide2/Qt/qml", + filter=None, + recursive=True, + force=False, + dir_filter_function=general_dir_filter, + vars=vars) + + # <qt>/translations/* -> <setup>/PySide2/Qt/translations + copydir("{qt_translations_dir}", "{dist_dir}/PySide2/Qt/translations", + filter=["*.qm"], + force=False, + vars=vars) + def prepare_packages_win32(self, vars): pdbs = ['*.pdb'] if self.debug or self.build_type == 'RelWithDebInfo' else [] # <install>/lib/site-packages/PySide2/* -> <setup>/PySide2 @@ -1272,7 +1368,10 @@ class pyside_build(_build): if OPTION_RPATH_VALUES: final_rpath = OPTION_RPATH_VALUES else: - final_rpath = self.qtinfo.libs_dir + if OPTION_STANDALONE: + final_rpath = "@loader_path/Qt/lib" + else: + final_rpath = self.qtinfo.libs_dir osx_fix_rpaths_for_library(srcpath, final_rpath) else: |