diff options
Diffstat (limited to 'build_scripts/platforms')
-rw-r--r-- | build_scripts/platforms/__init__.py | 40 | ||||
-rw-r--r-- | build_scripts/platforms/linux.py | 181 | ||||
-rw-r--r-- | build_scripts/platforms/macos.py | 185 | ||||
-rw-r--r-- | build_scripts/platforms/unix.py | 339 | ||||
-rw-r--r-- | build_scripts/platforms/windows_desktop.py | 485 |
5 files changed, 594 insertions, 636 deletions
diff --git a/build_scripts/platforms/__init__.py b/build_scripts/platforms/__init__.py index 571d37492..853aaad7b 100644 --- a/build_scripts/platforms/__init__.py +++ b/build_scripts/platforms/__init__.py @@ -1,38 +1,2 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $QT_BEGIN_LICENSE:LGPL$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 3 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL3 included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 3 requirements -## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 2.0 or (at your option) the GNU General -## Public license version 3 or any later version approved by the KDE Free -## Qt Foundation. The licenses are as published by the Free Software -## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-2.0.html and -## https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only diff --git a/build_scripts/platforms/linux.py b/build_scripts/platforms/linux.py index 712739e05..b4c66d94e 100644 --- a/build_scripts/platforms/linux.py +++ b/build_scripts/platforms/linux.py @@ -1,57 +1,26 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $QT_BEGIN_LICENSE:LGPL$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 3 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL3 included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 3 requirements -## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 2.0 or (at your option) the GNU General -## Public license version 3 or any later version approved by the KDE Free -## Qt Foundation. The licenses are as published by the Free Software -## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-2.0.html and -## https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# - -from ..utils import (copydir, copyfile, copy_icu_libs, find_files_using_glob, - linux_set_rpaths, linux_run_read_elf, linux_get_rpaths, - rpaths_has_origin) +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +from pathlib import Path + +from ..log import log from ..config import config +from ..options import OPTION +from ..utils import (copy_icu_libs, copydir, copyfile, find_files_using_glob, + linux_patch_executable) +from .. import PYSIDE, PYSIDE_UNIX_BUNDLED_TOOLS -def prepare_standalone_package_linux(self, vars): - built_modules = vars['built_modules'] +def prepare_standalone_package_linux(pyside_build, _vars, cross_build=False, is_android=False): + built_modules = _vars['built_modules'] constrain_modules = None copy_plugins = True copy_qml = True copy_translations = True copy_qt_conf = True - should_copy_icu_libs = True + + log.info("Copying files...") if config.is_internal_shiboken_generator_build(): constrain_modules = ["Core", "Network", "Xml", "XmlPatterns"] @@ -59,88 +28,116 @@ def prepare_standalone_package_linux(self, vars): copy_qml = False copy_translations = False copy_qt_conf = False - should_copy_icu_libs = False # <qt>/lib/* -> <setup>/{st_package_name}/Qt/lib - destination_lib_dir = "{st_build_dir}/{st_package_name}/Qt/lib" + destination_dir = Path("{st_build_dir}/{st_package_name}".format(**_vars)) + destination_qt_dir = destination_dir / "Qt" + destination_qt_lib_dir = destination_qt_dir / "lib" + + # android libs does not have the Qt major version + if is_android: + lib_regex = 'libQt6*.so*' + else: + lib_regex = 'libQt6*.so.?' - accepted_modules = ['libQt5*.so.?'] + accepted_modules = [lib_regex] if constrain_modules: - accepted_modules = ["libQt5" + module + "*.so.?" for module in constrain_modules] + accepted_modules = [f"libQt6{module}*.so.?" if not is_android else f"libQt6{module}*.so*" + for module in constrain_modules] accepted_modules.append("libicu*.so.??") - copydir("{qt_lib_dir}", destination_lib_dir, - filter=accepted_modules, - recursive=False, vars=vars, force_copy_symlinks=True) + if is_android: + accepted_modules.append("*-android-dependencies.xml") - if should_copy_icu_libs: + copydir("{qt_lib_dir}", destination_qt_lib_dir, + _filter=accepted_modules, + recursive=False, _vars=_vars, force_copy_symlinks=True) + + if not cross_build and not is_android: # Check if ICU libraries were copied over to the destination # Qt libdir. - resolved_destination_lib_dir = destination_lib_dir.format(**vars) - maybe_icu_libs = find_files_using_glob(resolved_destination_lib_dir, "libicu*") + maybe_icu_libs = find_files_using_glob(destination_qt_lib_dir, "libicu*") # If no ICU libraries are present in the Qt libdir (like when # Qt is built against system ICU, or in the Coin CI where ICU # libs are in a different directory) try to find out / resolve # which ICU libs are used by QtCore (if used at all) using a - # custom written ldd, and copy the ICU libs to the Pyside Qt - # dir if necessary. We choose the QtCore lib to inspect, by - # checking which QtCore library the shiboken2 executable uses. + # custom written ldd (non-cross build only), and copy the ICU + # libs to the Pyside Qt dir if necessary. + # We choose the QtCore lib to inspect, by + # checking which QtCore library the shiboken6 executable uses. if not maybe_icu_libs: - copy_icu_libs(self._patchelf_path, resolved_destination_lib_dir) + copy_icu_libs(pyside_build._patchelf_path, destination_qt_lib_dir) + + # Set RPATH for Qt libs. + if not is_android: + pyside_build.update_rpath_for_linux_qt_libraries(destination_qt_lib_dir) # Patching designer to use the Qt libraries provided in the wheel - if config.is_internal_pyside_build(): - designer_path = "{st_build_dir}/{st_package_name}/designer".format(**vars) - rpaths = linux_get_rpaths(designer_path) - if not rpaths or not rpaths_has_origin(rpaths): - rpaths.insert(0, '$ORIGIN/../lib') - new_rpaths_string = ":".join(rpaths) - linux_set_rpaths(self._patchelf_path, designer_path, new_rpaths_string) - - if self.is_webengine_built(built_modules): - copydir("{qt_lib_execs_dir}", - "{st_build_dir}/{st_package_name}/Qt/libexec", - filter=None, - recursive=False, - vars=vars) + if config.is_internal_pyside_build() and not OPTION['NO_QT_TOOLS']: + + for tool in PYSIDE_UNIX_BUNDLED_TOOLS: + tool_path = destination_dir / tool + linux_patch_executable(pyside_build._patchelf_path, tool_path) - copydir("{qt_prefix_dir}/resources", - "{st_build_dir}/{st_package_name}/Qt/resources", - filter=None, + if pyside_build.is_webengine_built(built_modules): + copydir("{qt_data_dir}/resources", + destination_qt_dir / "resources", + _filter=None, recursive=False, - vars=vars) + _vars=_vars) if copy_plugins: + is_pypy = "pypy" in pyside_build.build_classifiers # <qt>/plugins/* -> <setup>/{st_package_name}/Qt/plugins - copydir("{qt_plugins_dir}", - "{st_build_dir}/{st_package_name}/Qt/plugins", - filter=["*.so"], + plugins_target = destination_qt_dir / "plugins" + copydir("{qt_plugins_dir}", plugins_target, + _filter=["*.so"], recursive=True, - vars=vars) + _vars=_vars) + if not is_pypy and not is_android: + copydir("{install_dir}/plugins/designer", + plugins_target / "designer", + _filter=["*.so"], + recursive=False, + _vars=_vars) + + copied_plugins = pyside_build.get_shared_libraries_in_path_recursively( + plugins_target) + if not is_android: + pyside_build.update_rpath_for_linux_plugins(copied_plugins) if copy_qml: # <qt>/qml/* -> <setup>/{st_package_name}/Qt/qml + qml_plugins_target = destination_qt_dir / "qml" copydir("{qt_qml_dir}", - "{st_build_dir}/{st_package_name}/Qt/qml", - filter=None, + qml_plugins_target, + _filter=None, force=False, recursive=True, - ignore=["*.so.debug"], - vars=vars) + ignore=["*.debug"], + _vars=_vars) + copied_plugins = pyside_build.get_shared_libraries_in_path_recursively( + qml_plugins_target) + if not is_android: + pyside_build.update_rpath_for_linux_plugins( + copied_plugins, + qt_lib_dir=destination_qt_lib_dir, + is_qml_plugin=True) if copy_translations: # <qt>/translations/* -> # <setup>/{st_package_name}/Qt/translations copydir("{qt_translations_dir}", - "{st_build_dir}/{st_package_name}/Qt/translations", - filter=["*.qm", "*.pak"], + destination_qt_dir / "translations", + _filter=["*.qm", "*.pak"], force=False, - vars=vars) + _vars=_vars) if copy_qt_conf: # Copy the qt.conf file to libexec. - copyfile( - "{build_dir}/pyside2/{st_package_name}/qt.conf", - "{st_build_dir}/{st_package_name}/Qt/libexec", - vars=vars) + qt_libexec_path = destination_qt_dir / "libexec" + if not qt_libexec_path.is_dir(): + qt_libexec_path.mkdir(parents=True) + copyfile(f"{{build_dir}}/{PYSIDE}/{{st_package_name}}/qt.conf", + qt_libexec_path, _vars=_vars) diff --git a/build_scripts/platforms/macos.py b/build_scripts/platforms/macos.py index 614d6acbc..505573e0b 100644 --- a/build_scripts/platforms/macos.py +++ b/build_scripts/platforms/macos.py @@ -1,50 +1,28 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $QT_BEGIN_LICENSE:LGPL$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 3 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL3 included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 3 requirements -## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 2.0 or (at your option) the GNU General -## Public license version 3 or any later version approved by the KDE Free -## Qt Foundation. The licenses are as published by the Free Software -## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-2.0.html and -## https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only import fnmatch -import os -from ..utils import copydir, copyfile, macos_fix_rpaths_for_library, macos_add_rpath +from pathlib import Path + +from ..log import log from ..config import config +from ..options import OPTION +from ..utils import (copydir, copyfile, macos_add_rpath, + macos_fix_rpaths_for_library) +from .. import PYSIDE, PYSIDE_UNIX_BUNDLED_TOOLS + + +def _macos_patch_executable(name, _vars=None): + """ Patch an executable to run with the Qt libraries. """ + upper_name = name.capitalize() + bundle = f"{{st_build_dir}}/{{st_package_name}}/{upper_name}.app".format(**_vars) + binary = f"{bundle}/Contents/MacOS/{upper_name}" + rpath = "@loader_path/../../../Qt/lib" + macos_add_rpath(rpath, binary) -def prepare_standalone_package_macos(self, vars): - built_modules = vars['built_modules'] +def prepare_standalone_package_macos(pyside_build, _vars, is_android=False): + built_modules = _vars['built_modules'] constrain_modules = None copy_plugins = True @@ -52,9 +30,14 @@ def prepare_standalone_package_macos(self, vars): copy_translations = True copy_qt_conf = True + destination_dir = Path("{st_build_dir}/{st_package_name}".format(**_vars)) + destination_qt_dir = destination_dir / "Qt" + destination_qt_lib_dir = destination_qt_dir / "lib" + log.info("Copying files...") + if config.is_internal_shiboken_generator_build(): constrain_modules = ["Core", "Network", "Xml", "XmlPatterns"] - constrain_frameworks = ['Qt' + name + '.framework' for name in constrain_modules] + constrain_frameworks = [f"Qt{name}.framework" for name in constrain_modules] copy_plugins = False copy_qml = False copy_translations = False @@ -71,36 +54,34 @@ def prepare_standalone_package_macos(self, vars): no_copy_debug = True def file_variant_filter(file_name, file_full_path): - if self.qtinfo.build_type != 'debug_and_release': + if pyside_build.qtinfo.build_type != 'debug_and_release': return True if file_name.endswith('_debug.dylib') and no_copy_debug: return False return True # Patching designer to use the Qt libraries provided in the wheel - if config.is_internal_pyside_build(): - designer_bundle = "{st_build_dir}/{st_package_name}/Designer.app".format(**vars) - designer_binary = "{}/Contents/MacOS/Designer".format(designer_bundle) - rpath = "@loader_path/../../../Qt/lib" - macos_add_rpath(rpath, designer_binary) + if config.is_internal_pyside_build() and not OPTION['NO_QT_TOOLS']: + for tool in PYSIDE_UNIX_BUNDLED_TOOLS: + _macos_patch_executable(tool, _vars) # <qt>/lib/* -> <setup>/{st_package_name}/Qt/lib - if self.qt_is_framework_build(): + if pyside_build.qt_is_framework_build(): def framework_dir_filter(dir_name, parent_full_path, dir_full_path): if '.framework' in dir_name: if (dir_name.startswith('QtWebEngine') - and not self.is_webengine_built(built_modules)): + and not pyside_build.is_webengine_built(built_modules)): return False if constrain_modules and dir_name not in constrain_frameworks: return False if dir_name in ['Headers', 'fonts']: return False - if dir_full_path.endswith('Versions/Current'): + if str(dir_full_path).endswith('Versions/Current'): return False - if dir_full_path.endswith('Versions/5/Resources'): + if str(dir_full_path).endswith('Versions/5/Resources'): return False - if dir_full_path.endswith('Versions/5/Helpers'): + if str(dir_full_path).endswith('Versions/5/Helpers'): return False return general_dir_filter(dir_name, parent_full_path, dir_full_path) @@ -109,16 +90,16 @@ def prepare_standalone_package_macos(self, vars): no_copy_debug = True def framework_variant_filter(file_name, file_full_path): - if self.qtinfo.build_type != 'debug_and_release': + if pyside_build.qtinfo.build_type != 'debug_and_release': return True - dir_path = os.path.dirname(file_full_path) + dir_path = Path(file_full_path).parent in_framework = dir_path.endswith("Versions/5") if file_name.endswith('_debug') and in_framework and no_copy_debug: return False return True - copydir("{qt_lib_dir}", "{st_build_dir}/{st_package_name}/Qt/lib", - recursive=True, vars=vars, + copydir("{qt_lib_dir}", destination_qt_lib_dir, + recursive=True, _vars=_vars, ignore=["*.la", "*.a", "*.cmake", "*.pc", "*.prl"], dir_filter_function=framework_dir_filter, file_filter_function=framework_variant_filter) @@ -127,83 +108,87 @@ def prepare_standalone_package_macos(self, vars): # present rpath does not work because it assumes a symlink # from Versions/5/Helpers, thus adding two more levels of # directory hierarchy. - if self.is_webengine_built(built_modules): - qt_lib_path = "{st_build_dir}/{st_package_name}/Qt/lib".format(**vars) - bundle = "QtWebEngineCore.framework/Helpers/" - bundle += "QtWebEngineProcess.app" + if pyside_build.is_webengine_built(built_modules): + bundle = Path("QtWebEngineCore.framework/Helpers/") / "QtWebEngineProcess.app" binary = "Contents/MacOS/QtWebEngineProcess" - webengine_process_path = os.path.join(bundle, binary) - final_path = os.path.join(qt_lib_path, webengine_process_path) + webengine_process_path = bundle / binary + final_path = destination_qt_lib_dir / webengine_process_path rpath = "@loader_path/../../../../../" macos_fix_rpaths_for_library(final_path, rpath) else: ignored_modules = [] - if not self.is_webengine_built(built_modules): - ignored_modules.extend(['libQt5WebEngine*.dylib']) - accepted_modules = ['libQt5*.5.dylib'] + if not pyside_build.is_webengine_built(built_modules): + ignored_modules.extend(['libQt6WebEngine*.dylib']) + + accepted_modules = ['libQt6*.6.dylib'] + if is_android: + accepted_modules = ['libQt6*.so', '*-android-dependencies.xml'] + if constrain_modules: - accepted_modules = ["libQt5" + module + "*.5.dylib" for module in constrain_modules] + accepted_modules = [f"libQt6{module}*.6.dylib" for module in constrain_modules] - copydir("{qt_lib_dir}", - "{st_build_dir}/{st_package_name}/Qt/lib", - filter=accepted_modules, + copydir("{qt_lib_dir}", destination_qt_lib_dir, + _filter=accepted_modules, ignore=ignored_modules, file_filter_function=file_variant_filter, - recursive=True, vars=vars, force_copy_symlinks=True) - - if self.is_webengine_built(built_modules): - copydir("{qt_lib_execs_dir}", - "{st_build_dir}/{st_package_name}/Qt/libexec", - filter=None, - recursive=False, - vars=vars) + recursive=True, _vars=_vars, force_copy_symlinks=True) - copydir("{qt_prefix_dir}/resources", - "{st_build_dir}/{st_package_name}/Qt/resources", - filter=None, + if pyside_build.is_webengine_built(built_modules): + copydir("{qt_data_dir}/resources", + destination_qt_dir / "resources", + _filter=None, recursive=False, - vars=vars) + _vars=_vars) # Fix rpath for WebEngine process executable. - qt_libexec_path = "{st_build_dir}/{st_package_name}/Qt/libexec".format(**vars) + qt_libexec_path = Path(destination_qt_dir) / "libexec" binary = "QtWebEngineProcess" - final_path = os.path.join(qt_libexec_path, binary) + final_path = qt_libexec_path / binary rpath = "@loader_path/../lib" macos_fix_rpaths_for_library(final_path, rpath) if copy_qt_conf: # Copy the qt.conf file to libexec. + if not qt_libexec_path.is_dir(): + qt_libexec_path.mkdir(parents=True) copyfile( - "{build_dir}/pyside2/{st_package_name}/qt.conf", - "{st_build_dir}/{st_package_name}/Qt/libexec", - vars=vars) + f"{{build_dir}}/{PYSIDE}/{{st_package_name}}/qt.conf", + qt_libexec_path, _vars=_vars) if copy_plugins: + is_pypy = "pypy" in pyside_build.build_classifiers # <qt>/plugins/* -> <setup>/{st_package_name}/Qt/plugins - copydir("{qt_plugins_dir}", - "{st_build_dir}/{st_package_name}/Qt/plugins", - filter=["*.dylib"], + plugins_target = destination_qt_dir / "plugins" + filters = ["*.dylib"] + if is_android: + filters = ["*.so"] + copydir("{qt_plugins_dir}", plugins_target, + _filter=filters, recursive=True, dir_filter_function=general_dir_filter, file_filter_function=file_variant_filter, - vars=vars) + _vars=_vars) + if not is_pypy: + copydir("{install_dir}/plugins/designer", + plugins_target / "designer", + _filter=filters, + recursive=False, + _vars=_vars) if copy_qml: # <qt>/qml/* -> <setup>/{st_package_name}/Qt/qml - copydir("{qt_qml_dir}", - "{st_build_dir}/{st_package_name}/Qt/qml", - filter=None, + copydir("{qt_qml_dir}", destination_qt_dir / "qml", + _filter=None, recursive=True, force=False, dir_filter_function=general_dir_filter, file_filter_function=file_variant_filter, - vars=vars) + _vars=_vars) if copy_translations: # <qt>/translations/* -> # <setup>/{st_package_name}/Qt/translations - copydir("{qt_translations_dir}", - "{st_build_dir}/{st_package_name}/Qt/translations", - filter=["*.qm", "*.pak"], + copydir("{qt_translations_dir}", destination_qt_dir / "translations", + _filter=["*.qm", "*.pak"], force=False, - vars=vars) + _vars=_vars) diff --git a/build_scripts/platforms/unix.py b/build_scripts/platforms/unix.py index 30fa237c7..8378d42be 100644 --- a/build_scripts/platforms/unix.py +++ b/build_scripts/platforms/unix.py @@ -1,226 +1,253 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $QT_BEGIN_LICENSE:LGPL$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 3 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL3 included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 3 requirements -## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 2.0 or (at your option) the GNU General -## Public license version 3 or any later version approved by the KDE Free -## Qt Foundation. The licenses are as published by the Free Software -## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-2.0.html and -## https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# - -import os +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + import sys -import fnmatch -from .linux import prepare_standalone_package_linux -from .macos import prepare_standalone_package_macos +from pathlib import Path +from ..log import log from ..config import config from ..options import OPTION -from ..utils import copydir, copyfile, makefile -from ..utils import regenerate_qt_resources +from ..utils import copydir, copyfile, copy_qt_metatypes, makefile +from .. import PYSIDE, SHIBOKEN +from .linux import prepare_standalone_package_linux +from .macos import prepare_standalone_package_macos +from .. import PYSIDE_UNIX_BIN_TOOLS, PYSIDE_UNIX_LIBEXEC_TOOLS, PYSIDE_UNIX_BUNDLED_TOOLS + + +def _macos_copy_gui_executable(name, _vars=None): + """macOS helper: Copy a GUI executable from the .app folder and return the + files""" + app_name = f"{name.capitalize()}.app" + return copydir(f"{{install_dir}}/bin/{app_name}", + f"{{st_build_dir}}/{{st_package_name}}/{app_name}", + _filter=None, recursive=True, + force=False, _vars=_vars) -def prepare_packages_posix(self, vars): +def _unix_copy_gui_executable(name, _vars=None): + """UNIX helper: Copy a GUI executable and return the files""" + return copydir("{install_dir}/bin/", + "{st_build_dir}/{st_package_name}/", + _filter=[name], + force=False, _vars=_vars) + + +def _copy_gui_executable(name, _vars=None): + """Copy a GUI executable and return the files""" + if sys.platform == 'darwin': + return _macos_copy_gui_executable(name, _vars) + return _unix_copy_gui_executable(name, _vars) + + +def prepare_packages_posix(pyside_build, _vars, cross_build=False): + is_android = False + if str(OPTION['PLAT_NAME']).startswith('android'): + is_android = True + executables = [] + libexec_executables = [] + log.info("Copying files...") + + destination_dir = Path("{st_build_dir}/{st_package_name}".format(**_vars)) + destination_qt_dir = destination_dir / "Qt" # <install>/lib/site-packages/{st_package_name}/* -> # <setup>/{st_package_name} # This copies the module .so/.dylib files and various .py files # (__init__, config, git version, etc.) copydir( - "{site_packages_dir}/{st_package_name}", - "{st_build_dir}/{st_package_name}", - vars=vars) + "{site_packages_dir}/{st_package_name}", destination_dir, + _vars=_vars) - generated_config = self.get_built_pyside_config(vars) + generated_config = pyside_build.get_built_pyside_config(_vars) def adjusted_lib_name(name, version): postfix = '' - if sys.platform.startswith('linux'): - postfix = '.so.' + version + if config.is_cross_compile() and is_android: + postfix = ".so" + elif sys.platform.startswith('linux'): + postfix = f".so.{version}" elif sys.platform == 'darwin': - postfix = '.' + version + '.dylib' + postfix = f".{version}.dylib" return name + postfix if config.is_internal_shiboken_module_build(): - # <build>/shiboken2/doc/html/* -> - # <setup>/{st_package_name}/docs/shiboken2 + # <build>/shiboken6/doc/html/* -> + # <setup>/{st_package_name}/docs/shiboken6 copydir( - "{build_dir}/shiboken2/doc/html", - "{st_build_dir}/{st_package_name}/docs/shiboken2", - force=False, vars=vars) + f"{{build_dir}}/{SHIBOKEN}/doc/html", + f"{{st_build_dir}}/{{st_package_name}}/docs/{SHIBOKEN}", + force=False, _vars=_vars) # <install>/lib/lib* -> {st_package_name}/ copydir( - "{install_dir}/lib/", - "{st_build_dir}/{st_package_name}", - filter=[ + "{install_dir}/lib/", destination_dir, + _filter=[ adjusted_lib_name("libshiboken*", generated_config['shiboken_library_soversion']), ], - recursive=False, vars=vars, force_copy_symlinks=True) + recursive=False, _vars=_vars, force_copy_symlinks=True) if config.is_internal_shiboken_generator_build(): # <install>/bin/* -> {st_package_name}/ - executables.extend(copydir( - "{install_dir}/bin/", - "{st_build_dir}/{st_package_name}", - filter=[ - "shiboken2", - ], - recursive=False, vars=vars)) + copydir( + "{install_dir}/bin/", destination_dir, + _filter=[SHIBOKEN], + recursive=False, _vars=_vars) # Used to create scripts directory. makefile( "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py", - vars=vars) + _vars=_vars) # For setting up setuptools entry points. copyfile( "{install_dir}/bin/shiboken_tool.py", "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py", - force=False, vars=vars) + force=False, _vars=_vars) if config.is_internal_shiboken_generator_build() or config.is_internal_pyside_build(): # <install>/include/* -> <setup>/{st_package_name}/include copydir( "{install_dir}/include/{cmake_package_name}", "{st_build_dir}/{st_package_name}/include", - vars=vars) + _vars=_vars) if config.is_internal_pyside_build(): - makefile( - "{st_build_dir}/{st_package_name}/scripts/__init__.py", - vars=vars) - - # For setting up setuptools entry points - copyfile( - "{install_dir}/bin/pyside_tool.py", - "{st_build_dir}/{st_package_name}/scripts/pyside_tool.py", - force=False, vars=vars) - - # <install>/bin/* -> {st_package_name}/ - executables.extend(copydir( - "{install_dir}/bin/", - "{st_build_dir}/{st_package_name}", - filter=[ - "pyside2-lupdate", - "uic", - "rcc", - ], - recursive=False, vars=vars)) - - # Copying designer - if sys.platform == "darwin": + if not is_android: + makefile( + "{st_build_dir}/{st_package_name}/scripts/__init__.py", + _vars=_vars) + + scripts = ["pyside_tool.py", "metaobjectdump.py", "project.py", "qml.py", + "qtpy2cpp.py", "deploy.py"] + + script_dirs = ["qtpy2cpp_lib", "deploy_lib", "project"] + + if sys.platform.startswith("linux"): + scripts.append("android_deploy.py") + scripts.append("requirements-android.txt") + script_dirs.extend(["deploy_lib/android", + "deploy_lib/android/recipes/PySide6", + "deploy_lib/android/recipes/shiboken6",]) + + # For setting up setuptools entry points + for script in scripts: + src = f"{{install_dir}}/bin/{script}" + target = f"{{st_build_dir}}/{{st_package_name}}/scripts/{script}" + copyfile(src, target, force=False, _vars=_vars) + + for script_dir in script_dirs: + src = f"{{install_dir}}/bin/{script_dir}" + target = f"{{st_build_dir}}/{{st_package_name}}/scripts/{script_dir}" + # Exclude subdirectory tests + copydir(src, target, _filter=["*.py", "*.spec", "*.jpg", "*.icns", "*.ico"], + recursive=False, _vars=_vars) + + # <install>/bin/* -> {st_package_name}/ executables.extend(copydir( - "{install_dir}/bin/Designer.app", - "{st_build_dir}/{st_package_name}/Designer.app", - filter=None, recursive=True, - force=False, vars=vars)) - else: - copyfile( - "{install_dir}/bin/designer", - "{st_build_dir}/{st_package_name}/designer", - force=False, vars=vars) + "{install_dir}/bin/", destination_dir, + _filter=[f"{PYSIDE}-lupdate"], + recursive=False, _vars=_vars)) + + lib_exec_filters = [] + if not OPTION['NO_QT_TOOLS']: + lib_exec_filters.extend(PYSIDE_UNIX_LIBEXEC_TOOLS) + executables.extend(copydir( + "{install_dir}/bin/", destination_dir, + _filter=PYSIDE_UNIX_BIN_TOOLS, + recursive=False, _vars=_vars)) + + # Copying assistant/designer/linguist + for tool in PYSIDE_UNIX_BUNDLED_TOOLS: + executables.extend(_copy_gui_executable(tool, _vars=_vars)) + + copy_qt_metatypes(destination_qt_dir, _vars) + + # Copy libexec + built_modules = pyside_build.get_built_pyside_config(_vars)['built_modules'] + if pyside_build.is_webengine_built(built_modules): + lib_exec_filters.append('QtWebEngineProcess') + if lib_exec_filters: + libexec_executables.extend(copydir("{qt_lib_execs_dir}", + destination_qt_dir / "libexec", + _filter=lib_exec_filters, + recursive=False, + _vars=_vars)) # <install>/lib/lib* -> {st_package_name}/ copydir( - "{install_dir}/lib/", - "{st_build_dir}/{st_package_name}", - filter=[ + "{install_dir}/lib", destination_dir, + _filter=[ adjusted_lib_name("libpyside*", generated_config['pyside_library_soversion']), ], - recursive=False, vars=vars, force_copy_symlinks=True) - - # <install>/share/{st_package_name}/typesystems/* -> - # <setup>/{st_package_name}/typesystems - copydir( - "{install_dir}/share/{st_package_name}/typesystems", - "{st_build_dir}/{st_package_name}/typesystems", - vars=vars) - - # <install>/share/{st_package_name}/glue/* -> - # <setup>/{st_package_name}/glue + recursive=False, _vars=_vars, force_copy_symlinks=True) + + copydir("{qt_module_json_files_dir}", + destination_qt_dir / "modules", + _filter=["*.json"], _vars=_vars) + + if not config.is_cross_compile(): + # <install>/share/{st_package_name}/typesystems/* -> + # <setup>/{st_package_name}/typesystems + copydir( + "{install_dir}/share/{st_package_name}/typesystems", + "{st_build_dir}/{st_package_name}/typesystems", + _vars=_vars) + + # <install>/share/{st_package_name}/glue/* -> + # <setup>/{st_package_name}/glue + copydir( + "{install_dir}/share/{st_package_name}/glue", + "{st_build_dir}/{st_package_name}/glue", + _vars=_vars) + + if not is_android: + # <source>/pyside6/{st_package_name}/support/* -> + # <setup>/{st_package_name}/support/* + copydir( + f"{{build_dir}}/{PYSIDE}/{{st_package_name}}/support", + "{st_build_dir}/{st_package_name}/support", + _vars=_vars) + + # <source>/pyside6/{st_package_name}/QtAsyncio/* -> + # <setup>/{st_package_name}/QtAsyncio/* copydir( - "{install_dir}/share/{st_package_name}/glue", - "{st_build_dir}/{st_package_name}/glue", - vars=vars) + "{site_packages_dir}/{st_package_name}/QtAsyncio", + "{st_build_dir}/{st_package_name}/QtAsyncio", + _vars=_vars) - # <source>/pyside2/{st_package_name}/support/* -> - # <setup>/{st_package_name}/support/* - copydir( - "{build_dir}/pyside2/{st_package_name}/support", - "{st_build_dir}/{st_package_name}/support", - vars=vars) - - # <source>/pyside2/{st_package_name}/*.pyi -> + # <source>/pyside6/{st_package_name}/*.pyi -> # <setup>/{st_package_name}/*.pyi copydir( - "{build_dir}/pyside2/{st_package_name}", - "{st_build_dir}/{st_package_name}", - filter=["*.pyi", "py.typed"], - vars=vars) - - if not OPTION["NOEXAMPLES"]: - def pycache_dir_filter(dir_name, parent_full_path, dir_full_path): - if fnmatch.fnmatch(dir_name, "__pycache__"): - return False - return True - # examples/* -> <setup>/{st_package_name}/examples - copydir(os.path.join(self.script_dir, "examples"), - "{st_build_dir}/{st_package_name}/examples", - force=False, vars=vars, dir_filter_function=pycache_dir_filter) - # Re-generate examples Qt resource files for Python 3 - # compatibility - examples_path = "{st_build_dir}/{st_package_name}/examples".format(**vars) - pyside_rcc_path = "rcc" - pyside_rcc_options = ['-g', 'python'] - regenerate_qt_resources(examples_path, pyside_rcc_path, pyside_rcc_options) + f"{{build_dir}}/{PYSIDE}/{{st_package_name}}", destination_dir, + _filter=["*.pyi", "py.typed"], + _vars=_vars) + + # copy the jar files + if is_android: + copydir( + "{install_dir}/lib/jar", + "{st_build_dir}/{st_package_name}/jar", + _vars=_vars) # Copy Qt libs to package if OPTION["STANDALONE"]: if config.is_internal_pyside_build() or config.is_internal_shiboken_generator_build(): - vars['built_modules'] = generated_config['built_modules'] + _vars['built_modules'] = generated_config['built_modules'] if sys.platform == 'darwin': - prepare_standalone_package_macos(self, vars) + prepare_standalone_package_macos(pyside_build, _vars, is_android=is_android) else: - prepare_standalone_package_linux(self, vars) + prepare_standalone_package_linux(pyside_build, _vars, cross_build, + is_android=is_android) if config.is_internal_shiboken_generator_build(): # Copy over clang before rpath patching. - self.prepare_standalone_clang(is_win=False) + pyside_build.prepare_standalone_clang(is_win=False) # Update rpath to $ORIGIN - if sys.platform.startswith('linux') or sys.platform.startswith('darwin'): - rpath_path = "{st_build_dir}/{st_package_name}".format(**vars) - self.update_rpath(rpath_path, executables) + if (sys.platform.startswith('linux') or sys.platform.startswith('darwin')) and not is_android: + pyside_build.update_rpath(executables) + if libexec_executables: + pyside_build.update_rpath(libexec_executables, libexec=True) diff --git a/build_scripts/platforms/windows_desktop.py b/build_scripts/platforms/windows_desktop.py index 77bf9bfd2..9c29953be 100644 --- a/build_scripts/platforms/windows_desktop.py +++ b/build_scripts/platforms/windows_desktop.py @@ -1,284 +1,273 @@ -############################################################################# -## -## Copyright (C) 2018 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is part of Qt for Python. -## -## $QT_BEGIN_LICENSE:LGPL$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU Lesser General Public License Usage -## Alternatively, this file may be used under the terms of the GNU Lesser -## General Public License version 3 as published by the Free Software -## Foundation and appearing in the file LICENSE.LGPL3 included in the -## packaging of this file. Please review the following information to -## ensure the GNU Lesser General Public License version 3 requirements -## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 2.0 or (at your option) the GNU General -## Public license version 3 or any later version approved by the KDE Free -## Qt Foundation. The licenses are as published by the Free Software -## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-2.0.html and -## https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2018 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only import functools import os -import sys -import fnmatch +import tempfile +from pathlib import Path + +from ..log import log from ..config import config from ..options import OPTION -from ..utils import copydir, copyfile, makefile -from ..utils import regenerate_qt_resources, filter_match -from ..utils import download_and_extract_7z +from ..utils import (copydir, copyfile, copy_qt_metatypes, + download_and_extract_7z, filter_match, makefile) +from .. import PYSIDE, SHIBOKEN, PYSIDE_WINDOWS_BIN_TOOLS -def prepare_packages_win32(self, vars): +def prepare_packages_win32(pyside_build, _vars): # For now, debug symbols will not be shipped into the package. copy_pdbs = False pdbs = [] - if (self.debug or self.build_type == 'RelWithDebInfo') and copy_pdbs: + if (pyside_build.debug or pyside_build.build_type == 'RelWithDebInfo') and copy_pdbs: pdbs = ['*.pdb'] + destination_dir = Path("{st_build_dir}/{st_package_name}".format(**_vars)) + destination_qt_dir = destination_dir + log.info("Copying files...") + # <install>/lib/site-packages/{st_package_name}/* -> # <setup>/{st_package_name} # This copies the module .pyd files and various .py files # (__init__, config, git version, etc.) copydir( - "{site_packages_dir}/{st_package_name}", - "{st_build_dir}/{st_package_name}", - vars=vars) + "{site_packages_dir}/{st_package_name}", destination_dir, + _vars=_vars) if config.is_internal_shiboken_module_build(): - # <build>/shiboken2/doc/html/* -> - # <setup>/{st_package_name}/docs/shiboken2 + # <build>/shiboken6/doc/html/* -> + # <setup>/{st_package_name}/docs/shiboken6 copydir( - "{build_dir}/shiboken2/doc/html", - "{st_build_dir}/{st_package_name}/docs/shiboken2", - force=False, vars=vars) + f"{{build_dir}}/{SHIBOKEN}/doc/html", + f"{{st_build_dir}}/{{st_package_name}}/docs/{SHIBOKEN}", + force=False, _vars=_vars) # <install>/bin/*.dll -> {st_package_name}/ copydir( - "{install_dir}/bin/", - "{st_build_dir}/{st_package_name}", - filter=["shiboken*.dll"], - recursive=False, vars=vars) + "{install_dir}/bin/", destination_qt_dir, + _filter=["shiboken*.dll"], + recursive=False, _vars=_vars) # <install>/lib/*.lib -> {st_package_name}/ copydir( - "{install_dir}/lib/", - "{st_build_dir}/{st_package_name}", - filter=["shiboken*.lib"], - recursive=False, vars=vars) + "{install_dir}/lib/", destination_qt_dir, + _filter=["shiboken*.lib"], + recursive=False, _vars=_vars) # @TODO: Fix this .pdb file not to overwrite release # {shibokengenerator}.pdb file. # Task-number: PYSIDE-615 copydir( - "{build_dir}/shiboken2/shibokenmodule", - "{st_build_dir}/{st_package_name}", - filter=pdbs, - recursive=False, vars=vars) + f"{{build_dir}}/{SHIBOKEN}/shibokenmodule", destination_dir, + _filter=pdbs, + recursive=False, _vars=_vars) # pdb files for libshiboken and libpyside copydir( - "{build_dir}/shiboken2/libshiboken", - "{st_build_dir}/{st_package_name}", - filter=pdbs, - recursive=False, vars=vars) + f"{{build_dir}}/{SHIBOKEN}/libshiboken", destination_dir, + _filter=pdbs, + recursive=False, _vars=_vars) if config.is_internal_shiboken_generator_build(): # <install>/bin/*.dll -> {st_package_name}/ copydir( - "{install_dir}/bin/", - "{st_build_dir}/{st_package_name}", - filter=["shiboken*.exe"], - recursive=False, vars=vars) + "{install_dir}/bin/", destination_dir, + _filter=["shiboken*.exe"], + recursive=False, _vars=_vars) # Used to create scripts directory. - makefile( - "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py", - vars=vars) + makefile(f"{destination_dir}/scripts/shiboken_tool.py", _vars=_vars) # For setting up setuptools entry points. copyfile( "{install_dir}/bin/shiboken_tool.py", - "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py", - force=False, vars=vars) + f"{destination_dir}/scripts/shiboken_tool.py", + force=False, _vars=_vars) # @TODO: Fix this .pdb file not to overwrite release # {shibokenmodule}.pdb file. # Task-number: PYSIDE-615 copydir( - "{build_dir}/shiboken2/generator", - "{st_build_dir}/{st_package_name}", - filter=pdbs, - recursive=False, vars=vars) + f"{{build_dir}}/{SHIBOKEN}/generator", destination_dir, + _filter=pdbs, + recursive=False, _vars=_vars) if config.is_internal_shiboken_generator_build() or config.is_internal_pyside_build(): # <install>/include/* -> <setup>/{st_package_name}/include copydir( "{install_dir}/include/{cmake_package_name}", - "{st_build_dir}/{st_package_name}/include", - vars=vars) + destination_dir / "include", + _vars=_vars) if config.is_internal_pyside_build(): - # <build>/pyside2/{st_package_name}/*.pdb -> + # <build>/pyside6/{st_package_name}/*.pdb -> # <setup>/{st_package_name} copydir( - "{build_dir}/pyside2/{st_package_name}", - "{st_build_dir}/{st_package_name}", - filter=pdbs, - recursive=False, vars=vars) + f"{{build_dir}}/{PYSIDE}/{{st_package_name}}", destination_dir, + _filter=pdbs, + recursive=False, _vars=_vars) - makefile( - "{st_build_dir}/{st_package_name}/scripts/__init__.py", - vars=vars) + makefile(f"{destination_dir}/scripts/__init__.py", _vars=_vars) # For setting up setuptools entry points - copyfile( - "{install_dir}/bin/pyside_tool.py", - "{st_build_dir}/{st_package_name}/scripts/pyside_tool.py", - force=False, vars=vars) + for script in ("pyside_tool.py", "metaobjectdump.py", "project.py", "qml.py", + "qtpy2cpp.py", "deploy.py"): + src = f"{{install_dir}}/bin/{script}" + target = f"{{st_build_dir}}/{{st_package_name}}/scripts/{script}" + copyfile(src, target, force=False, _vars=_vars) + + for script_dir in ("qtpy2cpp_lib", "deploy_lib", "project"): + src = f"{{install_dir}}/bin/{script_dir}" + target = f"{{st_build_dir}}/{{st_package_name}}/scripts/{script_dir}" + # Exclude subdirectory tests + copydir(src, target, _filter=["*.py", "*.spec", "*.jpg", "*.icns", "*.ico"], + recursive=False, _vars=_vars) # <install>/bin/*.exe,*.dll -> {st_package_name}/ - copydir( - "{install_dir}/bin/", - "{st_build_dir}/{st_package_name}", - filter=["pyside*.exe", "pyside*.dll", "uic.exe", "rcc.exe", "designer.exe"], - recursive=False, vars=vars) + filters = ["pyside*.exe", "pyside*.dll"] + if not OPTION['NO_QT_TOOLS']: + filters.extend([f"{tool}.exe" for tool in PYSIDE_WINDOWS_BIN_TOOLS]) + copydir("{install_dir}/bin/", destination_qt_dir, + _filter=filters, + recursive=False, _vars=_vars) + + copy_qt_metatypes(destination_qt_dir, _vars) # <install>/lib/*.lib -> {st_package_name}/ copydir( - "{install_dir}/lib/", - "{st_build_dir}/{st_package_name}", - filter=["pyside*.lib"], - recursive=False, vars=vars) + "{install_dir}/lib/", destination_dir, + _filter=["pyside*.lib"], + recursive=False, _vars=_vars) + + copydir("{qt_module_json_files_dir}", + destination_qt_dir / "modules", + _filter=["*.json"], _vars=_vars) # <install>/share/{st_package_name}/typesystems/* -> # <setup>/{st_package_name}/typesystems copydir( "{install_dir}/share/{st_package_name}/typesystems", - "{st_build_dir}/{st_package_name}/typesystems", - vars=vars) + destination_dir / "typesystems", + _vars=_vars) # <install>/share/{st_package_name}/glue/* -> # <setup>/{st_package_name}/glue copydir( "{install_dir}/share/{st_package_name}/glue", - "{st_build_dir}/{st_package_name}/glue", - vars=vars) + destination_dir / "glue", + _vars=_vars) - # <source>/pyside2/{st_package_name}/support/* -> + # <source>/pyside6/{st_package_name}/support/* -> # <setup>/{st_package_name}/support/* copydir( - "{build_dir}/pyside2/{st_package_name}/support", - "{st_build_dir}/{st_package_name}/support", - vars=vars) + f"{{build_dir}}/{PYSIDE}/{{st_package_name}}/support", + destination_dir / "support", + _vars=_vars) + + # <source>/pyside6/{st_package_name}/QtAsyncio/* -> + # <setup>/{st_package_name}/QtAsyncio/* + copydir( + "{site_packages_dir}/{st_package_name}/QtAsyncio", + "{st_build_dir}/{st_package_name}/QtAsyncio", + _vars=_vars) - # <source>/pyside2/{st_package_name}/*.pyi -> + # <source>/pyside6/{st_package_name}/*.pyi -> # <setup>/{st_package_name}/*.pyi copydir( - "{build_dir}/pyside2/{st_package_name}", - "{st_build_dir}/{st_package_name}", - filter=["*.pyi", "py.typed"], - vars=vars) + f"{{build_dir}}/{PYSIDE}/{{st_package_name}}", destination_dir, + _filter=["*.pyi", "py.typed"], + _vars=_vars) copydir( - "{build_dir}/pyside2/libpyside", - "{st_build_dir}/{st_package_name}", - filter=pdbs, - recursive=False, vars=vars) - - if not OPTION["NOEXAMPLES"]: - def pycache_dir_filter(dir_name, parent_full_path, dir_full_path): - if fnmatch.fnmatch(dir_name, "__pycache__"): - return False - return True - # examples/* -> <setup>/{st_package_name}/examples - copydir(os.path.join(self.script_dir, "examples"), - "{st_build_dir}/{st_package_name}/examples", - force=False, vars=vars, dir_filter_function=pycache_dir_filter) - # Re-generate examples Qt resource files for Python 3 - # compatibility - examples_path = "{st_build_dir}/{st_package_name}/examples".format( - **vars) - pyside_rcc_path = "rcc.exe" - pyside_rcc_options = ['-g', 'python'] - regenerate_qt_resources(examples_path, pyside_rcc_path, pyside_rcc_options) - - if vars['ssl_libs_dir']: + f"{{build_dir}}/{PYSIDE}/libpyside", destination_dir, + _filter=pdbs, + recursive=False, _vars=_vars) + + if _vars['ssl_libs_dir']: # <ssl_libs>/* -> <setup>/{st_package_name}/openssl - copydir("{ssl_libs_dir}", "{st_build_dir}/{st_package_name}/openssl", - filter=[ + copydir("{ssl_libs_dir}", destination_dir / "openssl", + _filter=[ "libeay32.dll", "ssleay32.dll"], - force=False, vars=vars) + force=False, _vars=_vars) if config.is_internal_shiboken_module_build(): # The C++ std library dlls need to be packaged with the # shiboken module, because libshiboken uses C++ code. - copy_msvc_redist_files(vars, "{build_dir}/msvc_redist".format(**vars)) + copy_msvc_redist_files(destination_dir) if config.is_internal_pyside_build() or config.is_internal_shiboken_generator_build(): - copy_qt_artifacts(self, copy_pdbs, vars) - copy_msvc_redist_files(vars, "{build_dir}/msvc_redist".format(**vars)) - - -def copy_msvc_redist_files(vars, redist_target_path): - # MSVC redistributable file list. - msvc_redist = [ - "concrt140.dll", - "msvcp140.dll", - "ucrtbase.dll", - "vcamp140.dll", - "vccorlib140.dll", - "vcomp140.dll", - "vcruntime140.dll", - "vcruntime140_1.dll", - "msvcp140_1.dll", - "msvcp140_2.dll", - "msvcp140_codecvt_ids.dll" - ] + copy_qt_artifacts(pyside_build, destination_qt_dir, copy_pdbs, _vars) + copy_msvc_redist_files(destination_dir) + + +# MSVC redistributable file list. +msvc_redist = [ + "concrt140.dll", + "msvcp140.dll", + "vcamp140.dll", + "vccorlib140.dll", + "vcomp140.dll", + "vcruntime140.dll", + "vcruntime140_1.dll", + "msvcp140_1.dll", + "msvcp140_2.dll", + "msvcp140_codecvt_ids.dll" +] + + +def copy_msvc_redist_files(destination_dir): + in_coin = os.environ.get('COIN_LAUNCH_PARAMETERS', None) + if in_coin is None: + log.info("Qt dependency DLLs (MSVC redist) will not be copied.") + return # Make a directory where the files should be extracted. - if not os.path.exists(redist_target_path): - os.makedirs(redist_target_path) - + if not destination_dir.exists(): + destination_dir.mkdir(parents=True) + + # Copy Qt dependency DLLs (MSVC) from PATH when building on Qt CI. + paths = os.environ["PATH"].split(os.pathsep) + for path in paths: + try: + for f in Path(path).glob("*140*.dll"): + if f.name in msvc_redist: + copyfile(f, Path(destination_dir) / f.name) + msvc_redist.remove(f.name) + if not msvc_redist: + break + except WindowsError: + continue + + if msvc_redist: + msg = "The following Qt dependency DLLs (MSVC redist) were not found: {msvc_redist}" + raise FileNotFoundError(msg) + + +def copy_qt_dependency_dlls(_vars, destination_qt_dir, artifacts): # Extract Qt dependency dlls when building on Qt CI. in_coin = os.environ.get('COIN_LAUNCH_PARAMETERS', None) - if in_coin is not None: - redist_url = "http://download.qt.io/development_releases/prebuilt/vcredist/" + if in_coin is None: + log.info("Qt dependency DLLs will not be downloaded and extracted.") + return + + with tempfile.TemporaryDirectory() as temp_path: + redist_url = "https://download.qt.io/development_releases/prebuilt/vcredist/" zip_file = "pyside_qt_deps_64_2019.7z" - if "{target_arch}".format(**vars) == "32": + if "{target_arch}".format(**_vars) == "32": zip_file = "pyside_qt_deps_32_2019.7z" - download_and_extract_7z(redist_url + zip_file, redist_target_path) - else: - print("Qt dependency DLLs (MSVC redist) will not be downloaded and extracted.") + try: + download_and_extract_7z(redist_url + zip_file, temp_path) + except Exception as e: + log.warning(f"Download failed: {type(e).__name__}: {e}") + log.warning("download.qt.io is down, try with mirror") + redist_url = "https://master.qt.io/development_releases/prebuilt/vcredist/" + download_and_extract_7z(redist_url + zip_file, temp_path) + copydir(temp_path, destination_qt_dir, _filter=artifacts, recursive=False, _vars=_vars) - copydir(redist_target_path, - "{st_build_dir}/{st_package_name}", - filter=msvc_redist, recursive=False, vars=vars) - -def copy_qt_artifacts(self, copy_pdbs, vars): - built_modules = self.get_built_pyside_config(vars)['built_modules'] +def copy_qt_artifacts(pyside_build, destination_qt_dir, copy_pdbs, _vars): + built_modules = pyside_build.get_built_pyside_config(_vars)['built_modules'] constrain_modules = None copy_plugins = True @@ -286,7 +275,6 @@ def copy_qt_artifacts(self, copy_pdbs, vars): copy_translations = True copy_qt_conf = True copy_qt_permanent_artifacts = True - copy_msvc_redist = False copy_clang = False if config.is_internal_shiboken_generator_build(): @@ -296,13 +284,16 @@ def copy_qt_artifacts(self, copy_pdbs, vars): copy_translations = False copy_qt_conf = False copy_qt_permanent_artifacts = False - copy_msvc_redist = True copy_clang = True # <qt>/bin/*.dll and Qt *.exe -> <setup>/{st_package_name} qt_artifacts_permanent = [ + "avcodec-60.dll", + "avformat-60.dll", + "avutil-58.dll", + "swresample-4.dll", + "swscale-7.dll", "opengl*.dll", - "d3d*.dll", "designer.exe", "linguist.exe", "lrelease.exe", @@ -316,41 +307,28 @@ def copy_qt_artifacts(self, copy_pdbs, vars): "libEGL{}.dll", "libGLESv2{}.dll" ] - if self.qtinfo.build_type != 'debug_and_release': + if pyside_build.qtinfo.build_type != 'debug_and_release': egl_suffix = '*' - elif self.debug: + elif pyside_build.debug: egl_suffix = 'd' else: egl_suffix = '' qt_artifacts_egl = [a.format(egl_suffix) for a in qt_artifacts_egl] - artifacts = [] if copy_qt_permanent_artifacts: - artifacts += qt_artifacts_permanent - artifacts += qt_artifacts_egl - - if copy_msvc_redist: - # The target path has to be qt_bin_dir at the moment, - # because the extracted archive also contains the opengl32sw - # and the d3dcompiler dlls, which are copied not by this - # function, but by the copydir below. - copy_msvc_redist_files(vars, "{qt_bin_dir}".format(**vars)) - - if artifacts: - copydir("{qt_bin_dir}", - "{st_build_dir}/{st_package_name}", - filter=artifacts, recursive=False, vars=vars) + artifacts = qt_artifacts_permanent + qt_artifacts_egl + copy_qt_dependency_dlls(_vars, destination_qt_dir, artifacts) # <qt>/bin/*.dll and Qt *.pdbs -> <setup>/{st_package_name} part two # File filter to copy only debug or only release files. if constrain_modules: - qt_dll_patterns = ["Qt5" + x + "{}.dll" for x in constrain_modules] + qt_dll_patterns = [f"Qt6{x}{{}}.dll" for x in constrain_modules] if copy_pdbs: - qt_dll_patterns += ["Qt5" + x + "{}.pdb" for x in constrain_modules] + qt_dll_patterns += [f"Qt6{x}{{}}.pdb" for x in constrain_modules] else: - qt_dll_patterns = ["Qt5*{}.dll", "lib*{}.dll"] + qt_dll_patterns = ["Qt6*{}.dll", "lib*{}.dll"] if copy_pdbs: - qt_dll_patterns += ["Qt5*{}.pdb", "lib*{}.pdb"] + qt_dll_patterns += ["Qt6*{}.pdb", "lib*{}.pdb"] def qt_build_config_filter(patterns, file_name, file_full_path): release = [a.format('') for a in patterns] @@ -359,74 +337,83 @@ def copy_qt_artifacts(self, copy_pdbs, vars): # If qt is not a debug_and_release build, that means there # is only one set of shared libraries, so we can just copy # them. - if self.qtinfo.build_type != 'debug_and_release': + if pyside_build.qtinfo.build_type != 'debug_and_release': if filter_match(file_name, release): return True return False + # Setup Paths + file_name = Path(file_name) + file_full_path = Path(file_full_path) + # In debug_and_release case, choosing which files to copy # is more difficult. We want to copy only the files that - # match the PySide2 build type. So if PySide2 is built in + # match the PySide6 build type. So if PySide6 is built in # debug mode, we want to copy only Qt debug libraries # (ending with "d.dll"). Or vice versa. The problem is that # some libraries have "d" as the last character of the - # actual library name (for example Qt5Gamepad.dll and - # Qt5Gamepadd.dll). So we can't just match a pattern ending + # actual library name (for example Qt6Gamepad.dll and + # Qt6Gamepadd.dll). So we can't just match a pattern ending # in "d". Instead we check if there exists a file with the # same name plus an additional "d" at the end, and using # that information we can judge if the currently processed # file is a debug or release file. - # e.g. ["Qt5Cored", ".dll"] - file_split = os.path.splitext(file_name) - file_base_name = file_split[0] - file_ext = file_split[1] + # e.g. ["Qt6Cored", ".dll"] + file_base_name = file_name.stem + file_ext = file_name.suffix # e.g. "/home/work/qt/qtbase/bin" - file_path_dir_name = os.path.dirname(file_full_path) - # e.g. "Qt5Coredd" - maybe_debug_name = "{}d".format(file_base_name) - if self.debug: - filter = debug + file_path_dir_name = file_full_path.parent + # e.g. "Qt6Coredd" + maybe_debug_name = f"{file_base_name}d" + if pyside_build.debug: + _filter = debug def predicate(path): - return not os.path.exists(path) + return not path.exists() else: - filter = release + _filter = release def predicate(path): - return os.path.exists(path) - # e.g. "/home/work/qt/qtbase/bin/Qt5Coredd.dll" - other_config_path = os.path.join(file_path_dir_name, maybe_debug_name + file_ext) + return path.exists() + # e.g. "/home/work/qt/qtbase/bin/Qt6Coredd.dll" + other_config_path = file_path_dir_name / (maybe_debug_name + file_ext) - if (filter_match(file_name, filter) and predicate(other_config_path)): + if (filter_match(file_name, _filter) and predicate(other_config_path)): return True return False qt_dll_filter = functools.partial(qt_build_config_filter, qt_dll_patterns) - copydir("{qt_bin_dir}", - "{st_build_dir}/{st_package_name}", + copydir("{qt_bin_dir}", destination_qt_dir, file_filter_function=qt_dll_filter, - recursive=False, vars=vars) + recursive=False, _vars=_vars) if copy_plugins: + is_pypy = "pypy" in pyside_build.build_classifiers # <qt>/plugins/* -> <setup>/{st_package_name}/plugins + plugins_target = f"{destination_qt_dir}/plugins" plugin_dll_patterns = ["*{}.dll"] pdb_pattern = "*{}.pdb" if copy_pdbs: plugin_dll_patterns += [pdb_pattern] plugin_dll_filter = functools.partial(qt_build_config_filter, plugin_dll_patterns) - copydir("{qt_plugins_dir}", "{st_build_dir}/{st_package_name}/plugins", + copydir("{qt_plugins_dir}", plugins_target, file_filter_function=plugin_dll_filter, - vars=vars) + _vars=_vars) + if not is_pypy: + copydir("{install_dir}/plugins/designer", + f"{plugins_target}/designer", + _filter=["*.dll"], + recursive=False, + _vars=_vars) if copy_translations: # <qt>/translations/* -> <setup>/{st_package_name}/translations - copydir("{qt_translations_dir}", - "{st_build_dir}/{st_package_name}/translations", - filter=["*.qm", "*.pak"], + copydir("{qt_translations_dir}", f"{destination_qt_dir}/translations", + _filter=["*.qm", "*.pak"], force=False, - vars=vars) + _vars=_vars) if copy_qml: # <qt>/qml/* -> <setup>/{st_package_name}/qml @@ -435,42 +422,40 @@ def copy_qt_artifacts(self, copy_pdbs, vars): qml_ignore = [a.format('') for a in qml_ignore_patterns] # Copy all files that are not dlls and pdbs (.qml, qmldir). - copydir("{qt_qml_dir}", "{st_build_dir}/{st_package_name}/qml", + copydir("{qt_qml_dir}", f"{destination_qt_dir}/qml", ignore=qml_ignore, force=False, recursive=True, - vars=vars) + _vars=_vars) if copy_pdbs: qml_dll_patterns += [pdb_pattern] qml_dll_filter = functools.partial(qt_build_config_filter, qml_dll_patterns) # Copy all dlls (and possibly pdbs). - copydir("{qt_qml_dir}", "{st_build_dir}/{st_package_name}/qml", + copydir("{qt_qml_dir}", f"{destination_qt_dir}/qml", file_filter_function=qml_dll_filter, force=False, recursive=True, - vars=vars) + _vars=_vars) - if self.is_webengine_built(built_modules): - copydir("{qt_prefix_dir}/resources", - "{st_build_dir}/{st_package_name}/resources", - filter=None, + if pyside_build.is_webengine_built(built_modules): + copydir("{qt_data_dir}/resources", f"{destination_qt_dir}/resources", + _filter=None, recursive=False, - vars=vars) + _vars=_vars) - filter = 'QtWebEngineProcess{}.exe'.format( - 'd' if self.debug else '') - copydir("{qt_bin_dir}", - "{st_build_dir}/{st_package_name}", - filter=[filter], - recursive=False, vars=vars) + _ext = "d" if pyside_build.debug else "" + _filter = [f"QtWebEngineProcess{_ext}.exe"] + copydir("{qt_bin_dir}", destination_qt_dir, + _filter=_filter, + recursive=False, _vars=_vars) if copy_qt_conf: # Copy the qt.conf file to prefix dir. - copyfile("{build_dir}/pyside2/{st_package_name}/qt.conf", - "{st_build_dir}/{st_package_name}", - vars=vars) + copyfile(f"{{build_dir}}/{PYSIDE}/{{st_package_name}}/qt.conf", + destination_qt_dir, + _vars=_vars) if copy_clang: - self.prepare_standalone_clang(is_win=True) + pyside_build.prepare_standalone_clang(is_win=True) |