From f970327f8d40a81d4801918d3e6cb1fc44ff2292 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Fri, 3 Nov 2017 16:46:17 +0100 Subject: Make standalone option work on Linux Changes were made to copy the correct Qt shared libraries into the package (updated to Qt5 naming). A new rpath value will be inserted alongside $ORIGIN, to point to the copied over libraries. Also because symlinks are not supported by wheels, the actual Qt libraries have to be copied instead of the symlinks. Change-Id: I656a89a0b0136a290752bca141125bdeb5bb44d5 Task-number: PYSIDE-558 Reviewed-by: Christian Tismer --- setup.py | 99 +++++++++++++++++++++++++++++++++++++++++----------------------- utils.py | 10 +++---- 2 files changed, 69 insertions(+), 40 deletions(-) diff --git a/setup.py b/setup.py index c484c62d3..5d525226e 100644 --- a/setup.py +++ b/setup.py @@ -953,6 +953,21 @@ class pyside_build(_build): print('setup.py/prepare_packages: ', e) raise + def get_built_pyside_modules(self, 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") + + try: + with open(built_modules_path) as f: + scoped_locals = {} + code = compile(f.read(), built_modules_path, 'exec') + exec(code, scoped_locals, scoped_locals) + return scoped_locals['built_modules'] + except IOError as e: + print("get_built_pyside_modules: Couldn't find file: {}.".format(built_modules_path)) + raise + def prepare_packages_posix(self, vars): executables = [] if sys.platform.startswith('linux'): @@ -1050,34 +1065,12 @@ class pyside_build(_build): pyside_rcc_options) # Copy Qt libs to package if OPTION_STANDALONE: + vars['built_modules'] = self.get_built_pyside_modules(vars) if sys.platform == 'darwin': self.prepare_standalone_package_osx(executables, vars) else: - # /bin/* -> /PySide2 - executables.extend(copydir("{qt_bin_dir}", "{dist_dir}/PySide2", - filter=[ - "designer", - "linguist", - "lrelease", - "lupdate", - "lconvert", - ], - recursive=False, vars=vars)) - # /lib/* -> /PySide2 - copydir("{qt_lib_dir}", "{dist_dir}/PySide2", - filter=[ - "libQt*.so.?", - "libphonon.so.?", - ], - recursive=False, vars=vars) - # /plugins/* -> /PySide2/plugins - copydir("{qt_plugins_dir}", "{dist_dir}/PySide2/plugins", - filter=["*.so"], - vars=vars) - # /translations/* -> /PySide2/translations - copydir("{qt_translations_dir}", "{dist_dir}/PySide2/translations", - filter=["*.qm"], - vars=vars) + self.prepare_standalone_package_linux(executables, vars) + # Update rpath to $ORIGIN if sys.platform.startswith('linux') or sys.platform.startswith('darwin'): self.update_rpath("{dist_dir}/PySide2".format(**vars), executables) @@ -1087,16 +1080,50 @@ class pyside_build(_build): 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") + def prepare_standalone_package_linux(self, executables, vars): + built_modules = vars['built_modules'] + + # /lib/* -> /PySide2/Qt/lib + copydir("{qt_lib_dir}", "{dist_dir}/PySide2/Qt/lib", + filter=[ + "libQt5*.so.?", + "libicu*.so.??", + ], + recursive=False, vars=vars, force_copy_symlinks=True) + + 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) - 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'] + # /plugins/* -> /PySide2/Qt/plugins + copydir("{qt_plugins_dir}", "{dist_dir}/PySide2/Qt/plugins", + filter=["*.so"], + recursive=True, + vars=vars) + + # /qml/* -> /PySide2/Qt/qml + copydir("{qt_qml_dir}", "{dist_dir}/PySide2/Qt/qml", + filter=None, + force=False, + recursive=True, + vars=vars) + + # /translations/* -> /PySide2/Qt/translations + + copydir("{qt_translations_dir}", "{dist_dir}/PySide2/Qt/translations", + filter=["*.qm"], + force=False, + vars=vars) + + def prepare_standalone_package_osx(self, executables, vars): + built_modules = vars['built_modules'] # Directory filter for skipping unnecessary files. def general_dir_filter(dir_name, parent_full_path, dir_full_path): @@ -1363,7 +1390,9 @@ class pyside_build(_build): # Add rpath values pointing to $ORIGIN and the installed qt lib directory. local_rpath = '$ORIGIN/' qt_lib_dir = self.qtinfo.libs_dir - final_rpath = local_rpath + ':' + qt_lib_dir + if OPTION_STANDALONE: + qt_lib_dir = "$ORIGIN/Qt/lib" + final_rpath = local_rpath + ':' + qt_lib_dir cmd = [patchelf_path, '--set-rpath', final_rpath, srcpath] if run_process(cmd) != 0: raise RuntimeError("Error patching rpath in " + srcpath) diff --git a/utils.py b/utils.py index 98410838e..444cbfbfa 100644 --- a/utils.py +++ b/utils.py @@ -222,7 +222,7 @@ def init_msvc_env(platform_arch, build_type): log.info("Done initializing MSVC env") -def copyfile(src, dst, force=True, vars=None): +def copyfile(src, dst, force=True, vars=None, force_copy_symlink=False): if vars is not None: src = src.format(**vars) dst = dst.format(**vars) @@ -231,7 +231,7 @@ def copyfile(src, dst, force=True, vars=None): log.info("**Skiping copy file %s to %s. Source does not exists." % (src, dst)) return - if not os.path.islink(src): + if not os.path.islink(src) or force_copy_symlink: log.info("Copying file %s to %s." % (src, dst)) shutil.copy2(src, dst) else: @@ -276,7 +276,7 @@ def makefile(dst, content=None, vars=None): def copydir(src, dst, filter=None, ignore=None, force=True, recursive=True, vars=None, - dir_filter_function=None): + dir_filter_function=None, force_copy_symlinks=False): if vars is not None: src = src.format(**vars) @@ -310,14 +310,14 @@ def copydir(src, dst, filter=None, ignore=None, force=True, recursive=True, vars if recursive: results.extend( copydir(srcname, dstname, filter, ignore, force, recursive, - vars, dir_filter_function)) + vars, dir_filter_function, force_copy_symlinks)) else: if (filter is not None and not filter_match(name, filter)) or \ (ignore is not None and filter_match(name, ignore)): continue if not os.path.exists(dst): os.makedirs(dst) - results.append(copyfile(srcname, dstname, True, vars)) + results.append(copyfile(srcname, dstname, True, vars, force_copy_symlinks)) # catch the Error from the recursive copytree so that we can # continue with other files except shutil.Error as err: -- cgit v1.2.3