aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCristián Maureira-Fredes <Cristian.Maureira-Fredes@qt.io>2022-03-02 02:22:00 +0100
committerCristián Maureira-Fredes <Cristian.Maureira-Fredes@qt.io>2022-03-29 13:51:35 +0200
commitc565eada8ff164cff07566e1499992327c2536ba (patch)
treed4ea7d7728a8ff9f54459446c59194e39394b83e
parent72309bc9901c4e37ed7e0153668b8df3c52e458f (diff)
build: script to create wheels
This approach intends to avoid modifying the current structure we have in build_scripts, and can replace the call: python setup.py bdist_wheel mainly encouraged by PEP517, and the need of having incremental wheels, to replace the current single PySide6 one. The current configuration allows to create two new wheels: PySide6_Essentials, and PySide6_Addons that contain all the essential and addons Qt modules defined by the Qt Installer tool, with some modifications due to the dependencies of certain tools. Check the README files for more info. The known PySide6 wheel is also generated, but it's empty in favor of using the previous two wheels as requirements, installing them automatically, to avoid modifying the usage of 'pip install pyside6' The strategy is based on the current logic behing 'prepare_packages' that we have been using. Once the modules are built, instead of removing those directories currently in 'build/your_env/package', we rename them. Inside this new directory, one can have the 'shiboken6', 'shiboken6_generator', and 'PySide6' directories, with eveything already packed with the required wheel structure. The main difference is that instead of using the content of PySide6 to build one build, we select some files with the MANIFEST.in to create another wheel. The wheel tag drops the old assumption of needing: cp36.cp37.cp38.cp39.cp310-abi3 and only uses: cp36-abi3 Additionally, for Linux, we follow PEP600 to use the GLIBC version in the wheel name instead of manylinux1, manylinux2010, etc... For the current CI configuration, we know we are using 2.28, which is the minimum supported version for Qt6, so the wheel will look like: PySide6-6.3.0-cp36-abi3-manylinux_2_28_x86_64.whl The coin scripts were configured as well, to add the call of the new create_wheels.py script, and test them via wheel_tester.py Note: This script is not intended to be used as a general purpose wheel creation tool, and it's purely focused on the current Qt CI. There are many ad-hoc configurations used in different functions, like the structure of a Qt installation, the usage of 'a' on the environment for limited-api, etc. Task-number: PYSIDE-1115 Fixes: PYSIDE-692 Change-Id: Ic12e428b8b9b64bbe2facb1c520595ccd2384497 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--README.pyside6.md7
-rw-r--r--README.pyside6_addons.md62
-rw-r--r--README.pyside6_essentials.md56
-rw-r--r--build_scripts/main.py18
-rw-r--r--build_scripts/wheel_files.py893
-rw-r--r--coin_build_instructions.py10
-rw-r--r--coin_test_instructions.py11
-rw-r--r--create_wheels.py417
-rw-r--r--requirements.txt2
-rw-r--r--testing/wheel_tester.py19
-rw-r--r--wheel_artifacts/pyproject.toml3
-rw-r--r--wheel_artifacts/setup.cfg.base52
-rw-r--r--wheel_artifacts/setup.py.base29
13 files changed, 1568 insertions, 11 deletions
diff --git a/README.pyside6.md b/README.pyside6.md
index 007903291..0ece3ba72 100644
--- a/README.pyside6.md
+++ b/README.pyside6.md
@@ -23,10 +23,15 @@ and [PyPi](https://pypi.org/project/PySide6/):
pip install PySide6
```
+> Please note: this wheel is an alias to other two wheels
+> [PySide6_Essentials](https://pypi.org/project/PySide6_Essentials) and
+> [PySide6_Addons](https://pypi.org/project/PySide6_Addons), which contains
+> a predefined list of Qt Modules.
+
#### Dependencies
PySide6 versions following 6.0 use a C++ parser based on
-[Clang](http://clang.org/). The Clang library (C-bindings), version 10.0 or
+[Clang](http://clang.org/). The Clang library (C-bindings), version 13.0 or
higher is required for building. Prebuilt versions of it can be downloaded from
[download.qt.io](http://download.qt.io/development_releases/prebuilt/libclang/).
diff --git a/README.pyside6_addons.md b/README.pyside6_addons.md
new file mode 100644
index 000000000..f6e2e6605
--- /dev/null
+++ b/README.pyside6_addons.md
@@ -0,0 +1,62 @@
+# PySide6 Addons
+
+PySide6 is the official Python module from the
+[Qt for Python project](http://wiki.qt.io/Qt_for_Python),
+which provides access to the complete Qt 6.0+ framework.
+
+The Qt for Python project is developed in the open, with all facilities you'd expect
+from any modern OSS project such as all code in a git repository and an open
+design process. We welcome any contribution conforming to the
+[Qt Contribution Agreement](https://www.qt.io/contributionagreement/).
+
+This is a complementary wheel for [PySide6](https://pypi.org/project/PySide6),
+it includes the following Qt modules:
+
+* Qt3DAnimation
+* Qt3DCore
+* Qt3DExtras
+* Qt3DInput
+* Qt3DLogic
+* Qt3DRender
+* QtAxContainer
+* QtBluetooth
+* QtCharts
+* QtDataVisualization
+* QtMultimedia
+* QtMultimediaWidgets
+* QtNetworkAuth
+* QtNfc
+* QtPositioning
+* QtQuick3D
+* QtRemoteObjects
+* QtScxml
+* QtSensors
+* QtSerialPort
+* QtStateMachine
+* QtVirtualKeyboard
+* QtWebChannel
+* QtWebEngineCore
+* QtWebEngineQuick
+* QtWebEngineWidgets
+* QtWebSockets
+
+### Documentation and Bugs
+
+You can find more information about the PySide6 module API in the
+[official Qt for Python documentation](https://doc.qt.io/qtforpython/).
+
+If you come across any issue, please file a bug report at our
+[JIRA tracker](https://bugreports.qt.io/projects/PYSIDE) following
+our [guidelines](https://wiki.qt.io/Qt_for_Python/Reporting_Bugs).
+
+### Community
+
+Check *#qt-pyside*, our official IRC channel on FreeNode, or contact us via our
+[mailing list](http://lists.qt-project.org/mailman/listinfo/pyside).
+
+### Licensing
+
+PySide6 is available under both Open Source (LGPLv3/GPLv2) and commercial
+license. Using PyPi is the recommended installation source, because the
+content of the wheels is valid for both cases. For more information, refer to
+the [Qt Licensing page](https://www.qt.io/licensing/).
diff --git a/README.pyside6_essentials.md b/README.pyside6_essentials.md
new file mode 100644
index 000000000..629db92ef
--- /dev/null
+++ b/README.pyside6_essentials.md
@@ -0,0 +1,56 @@
+# PySide6 Essentials
+
+PySide6 is the official Python module from the
+[Qt for Python project](http://wiki.qt.io/Qt_for_Python),
+which provides access to the complete Qt 6.0+ framework.
+
+The Qt for Python project is developed in the open, with all facilities you'd expect
+from any modern OSS project such as all code in a git repository and an open
+design process. We welcome any contribution conforming to the
+[Qt Contribution Agreement](https://www.qt.io/contributionagreement/).
+
+This is a minimal wheel for [PySide6](https://pypi.org/project/PySide6),
+it includes only the essentials Qt modules:
+
+* QtCore
+* QtGui
+* QtWidgets
+* QtHelp
+* QtNetwork
+* QtConcurrent
+* QtDBus
+* QtDesigner
+* QtOpenGL
+* QtOpenGLWidgets
+* QtPrintSupport
+* QtQml
+* QtQuick
+* QtQuickControls2
+* QtQuickWidgets
+* QtXml
+* QtTest
+* QtSql
+* QtSvg
+* QtSvgWidgets
+* QtUiTools
+
+### Documentation and Bugs
+
+You can find more information about the PySide6 module API in the
+[official Qt for Python documentation](https://doc.qt.io/qtforpython/).
+
+If you come across any issue, please file a bug report at our
+[JIRA tracker](https://bugreports.qt.io/projects/PYSIDE) following
+our [guidelines](https://wiki.qt.io/Qt_for_Python/Reporting_Bugs).
+
+### Community
+
+Check *#qt-pyside*, our official IRC channel on FreeNode, or contact us via our
+[mailing list](http://lists.qt-project.org/mailman/listinfo/pyside).
+
+### Licensing
+
+PySide6 is available under both Open Source (LGPLv3/GPLv2) and commercial
+license. Using PyPi is the recommended installation source, because the
+content of the wheels is valid for both cases. For more information, refer to
+the [Qt Licensing page](https://www.qt.io/licensing/).
diff --git a/build_scripts/main.py b/build_scripts/main.py
index e50ca791e..75850691b 100644
--- a/build_scripts/main.py
+++ b/build_scripts/main.py
@@ -44,6 +44,7 @@ import platform
import re
import sys
import importlib
+from pathlib import Path
from textwrap import dedent
import time
from .config import config
@@ -443,6 +444,23 @@ class PysideBuild(_build, DistUtilsCommandMixin, BuildInfoCollectorMixin):
# Build packages
_build.run(self)
+
+ # Keep packaged directories for wheel construction
+ # This is to take advantage of the packaging step
+ # to keep the data in the proper structure to create
+ # a wheel.
+ _path = Path(self.st_build_dir)
+ _wheel_path = _path.parent / "package_for_wheels"
+ if not _wheel_path.exists():
+ _wheel_path.mkdir()
+ _package_name = os.listdir(_path)[0]
+ _src = Path(_path / _package_name)
+ _dst = Path(_wheel_path / _package_name)
+ try:
+ Path(_path / _package_name).rename(_wheel_path / _package_name)
+ except Exception as e:
+ log.warn(f'***** problem renaming "{self.st_build_dir}"')
+ log.warn(f'ignored error: {type(e).__name__}: {e}')
else:
log.info("Skipped preparing and building packages.")
log.info(f"--- Build completed ({elapsed()}s)")
diff --git a/build_scripts/wheel_files.py b/build_scripts/wheel_files.py
new file mode 100644
index 000000000..237a16b38
--- /dev/null
+++ b/build_scripts/wheel_files.py
@@ -0,0 +1,893 @@
+#############################################################################
+##
+## Copyright (C) 2022 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 sys
+from dataclasses import Field, dataclass, field
+from typing import Any, Dict, List
+
+
+# This dataclass is in charge of holding the file information
+# that each Qt module needs to have to be packaged in a wheel
+@dataclass
+class ModuleData:
+ name: str
+ ext: str = ""
+ # Libraries not related to Qt modules
+ lib: List[str] = field(default_factory=list)
+ # Libraries related to Qt modules
+ qtlib: List[str] = field(default_factory=list)
+ # Files from the Qt/qml directory
+ qml: List[str] = field(default_factory=list)
+ pyi: List[str] = field(default_factory=list)
+ translations: List[str] = field(default_factory=list)
+ typesystems: List[str] = field(default_factory=list)
+ include: List[str] = field(default_factory=list)
+ glue: List[str] = field(default_factory=list)
+ metatypes: List[str] = field(default_factory=list)
+ examples: List[str] = field(default_factory=list)
+ plugins: List[str] = field(default_factory=list)
+
+ # For special cases when a file/directory doesn't fall into
+ # the previous categories.
+ extra_dirs: List[str] = field(default_factory=list)
+ extra_files: List[str] = field(default_factory=list)
+
+ # Once the object is created, this method will be executed
+ # and automatically will initialize some of the files that are
+ # common for each module.
+ # Note: The goal of this list is to be used for a MANIFEST.in
+ # meaning that in case a file gets added and it doesn't
+ # exist, the wheel creation process will only throw a
+ # warning, but it will not interrupt the packaging process.
+ def __post_init__(self) -> None:
+ if not self.ext:
+ self.ext = self.get_extension_from_platform(sys.platform)
+ _lo = self.name.lower()
+
+ self.lib.append(f"Qt{self.name}")
+ self.qtlib.append(f"libQt6{self.name}")
+ if not len(self.qml):
+ self.qml.append(f"Qt{self.name}")
+ self.pyi.append(f"Qt{self.name}.pyi")
+ self.typesystems.append(f"typesystem_{_lo}.xml")
+ self.include.append(f"Qt{self.name}/*.h")
+ self.glue.append(f"qt{_lo}.cpp")
+ if not len(self.metatypes):
+ self.metatypes.append(f"qt6{_lo}_relwithdebinfo_metatypes.json")
+ self.examples.append(f"{_lo}")
+
+ # The PySide6 directory that gets packaged by the build_scripts
+ # 'prepare_packages()' has a certain structure that depends on
+ # the platform. Because that directory is the base for the wheel
+ # packaging to work, we use the relative paths that are included
+ # on each file.
+ # Note: The MANIFEST.in file doesn't need to have '\' or other
+ # separator, and respect the '/' even on Windows.
+ def adjusts_paths_and_extensions(self) -> None:
+ if sys.platform == "win32":
+ self.lib = [f"{i}.*{self.ext}".replace("lib", "") for i in self.lib]
+ self.qtlib = [f"{i}.*dll".replace("lib", "") for i in self.qtlib]
+ self.qml = [f"qml/{i}" for i in self.qml]
+ self.translations = [f"translations/{i}" for i in self.translations]
+ self.metatypes = [
+ f"lib/metatypes/{i}".replace("_relwithdebinfo", "") for i in self.metatypes
+ ]
+ self.plugins = [f"plugins/{i}" for i in self.plugins]
+ else:
+ if sys.platform == "darwin":
+ self.qtlib = [f"Qt/lib/{i.replace('libQt6', 'Qt')}.framework" for i in self.qtlib]
+ self.lib = [self.macos_pyside_wrappers_lib(i) for i in self.lib]
+ else:
+ self.lib = [f"{i}.*{self.ext}*" for i in self.lib]
+ self.qtlib = [f"Qt/lib/{i}.*{self.ext}*" for i in self.qtlib]
+ self.qml = [f"Qt/qml/{i}" for i in self.qml]
+ self.translations = [f"Qt/translations/{i}" for i in self.translations]
+ self.metatypes = [f"Qt/lib/metatypes/{i}" for i in self.metatypes]
+ self.plugins = [f"Qt/plugins/{i}" for i in self.plugins]
+
+ self.typesystems = [f"typesystems/{i}" for i in self.typesystems]
+ self.include = [f"include/{i}" for i in self.include]
+ self.glue = [f"glue/{i}" for i in self.glue]
+ self.examples = [f"examples/{i}" for i in self.examples]
+
+ def macos_pyside_wrappers_lib(self, s):
+ if s.startswith("Qt"):
+ return f"{s}.*so*"
+ else:
+ return f"{s}.*{self.ext}*"
+
+ @classmethod
+ def get_fields(cls) -> Dict[str, Field]:
+ return cls.__dataclass_fields__
+
+ @staticmethod
+ def get_extension_from_platform(platform: str) -> str:
+ if platform == "linux":
+ return "so"
+ elif platform == "darwin":
+ return "dylib"
+ elif platform == "win32":
+ return "pyd"
+ else:
+ print(f"Platform '{platform}' not supported. Exiting")
+ sys.exit(-1)
+
+
+# Wheels auxiliary functions to return the ModuleData objects
+# for each module that will be included in the wheel.
+
+# PySide wheel
+def wheel_files_pyside_essentials() -> List[ModuleData]:
+ files = [
+ module_QtCore(),
+ module_QtGui(),
+ module_QtWidgets(),
+ module_QtHelp(),
+ module_QtNetwork(),
+ module_QtConcurent(),
+ module_QtDBus(),
+ module_QtDesigner(),
+ module_QtOpenGL(),
+ module_QtOpenGLWidgets(),
+ module_QtPrintSupport(),
+ module_QtQml(),
+ module_QtQuick(),
+ module_QtQuickControls2(),
+ module_QtQuickWidgets(),
+ module_QtXml(),
+ module_QtTest(),
+ module_QtSql(),
+ module_QtSvg(),
+ module_QtSvgWidgets(),
+ module_QtUiTools(),
+ # Only for plugins
+ module_QtWayland(),
+ ]
+ return files
+
+
+# PySide Addons wheel
+def wheel_files_pyside_addons() -> List[ModuleData]:
+ files = [
+ module_Qt3DAnimation(),
+ module_Qt3DCore(),
+ module_Qt3DExtras(),
+ module_Qt3DInput(),
+ module_Qt3DLogic(),
+ module_Qt3DRender(),
+ module_QtAxContainer(),
+ module_QtBluetooth(),
+ module_QtCharts(),
+ module_QtDataVisualization(),
+ module_QtMultimedia(),
+ module_QtMultimediaWidgets(),
+ module_QtNetworkAuth(),
+ module_QtNfc(),
+ module_QtPositioning(),
+ module_QtQuick3D(),
+ module_QtRemoteObjects(),
+ module_QtScxml(),
+ module_QtSensors(),
+ module_QtSerialPort(),
+ module_QtStateMachine(),
+ # Not available in 6.3
+ #module_QtTextToSpeech(),
+ module_QtVirtualKeyboard(),
+ module_QtWebChannel(),
+ module_QtWebEngineCore(),
+ module_QtWebEngineQuick(),
+ module_QtWebEngineWidgets(),
+ module_QtWebSockets(),
+ ]
+ return files
+
+
+# Functions that hold the information of all the files that needs
+# to be included for the module to work, including Qt libraries,
+# examples, typesystems, glue, etc.
+def module_QtCore() -> ModuleData:
+ # QtCore
+ data = ModuleData("Core", examples=["corelib"])
+ data.typesystems.append("core_common.xml")
+ data.typesystems.append("typesystem_core_common.xml")
+ data.typesystems.append("typesystem_core_win.xml")
+ data.include.append("*.h")
+ if sys.platform == "win32":
+ data.plugins.append("assetimporters")
+ data.plugins.append("styles")
+ data.qtlib.append("pyside6.*")
+ data.extra_files.append("qt.conf")
+ data.extra_files.append("uic.exe")
+ data.extra_files.append("rcc.exe")
+ data.extra_files.append("qtdiag.exe")
+ data.extra_files.append("d3dcompiler*")
+ data.extra_files.append("lconvert*")
+ data.extra_files.append("pyside6.*.lib")
+ data.extra_files.append("resources/icudtl.dat")
+ else:
+ data.lib.append("libpyside6.*")
+ if sys.platform == "darwin":
+ data.plugins.append("styles")
+
+ data.examples.append("samplebinding")
+ data.examples.append("widgetbinding")
+ data.examples.append("scriptableapplication")
+ data.examples.append("utils")
+ data.examples.append("external")
+ data.examples.append("installer_test")
+ data.examples.append("macextras")
+
+ # *.py
+ data.extra_dirs.append("support")
+ data.extra_dirs.append("scripts")
+
+ data.extra_dirs.append("Qt/libexec/")
+ data.extra_dirs.append("typesystems/glue")
+
+ data.extra_files.append("__feature__.pyi")
+ data.extra_files.append("__init__.py")
+ data.extra_files.append("_git_pyside_version.py")
+ data.extra_files.append("_config.py")
+ data.extra_files.append("py.typed")
+
+ # Assistant
+ if sys.platform == "darwin":
+ data.extra_dirs.append("Assistant.app")
+ else:
+ data.extra_files.append("assistant*")
+ data.translations.append("assistant_*")
+
+ # Designer
+ if sys.platform == "darwin":
+ data.extra_dirs.append("Designer.app")
+ else:
+ data.extra_files.append("designer*")
+ data.translations.append("designer_*")
+
+ # Linguist
+ if sys.platform == "darwin":
+ data.extra_dirs.append("Linguist.app")
+ else:
+ data.extra_files.append("linguist*")
+ data.translations.append("linguist_*")
+
+ data.extra_files.append("lrelease*")
+ data.extra_files.append("lupdate*")
+ data.extra_files.append("qmllint*")
+
+ # General translations
+ data.translations.append("qtbase_*")
+ data.translations.append("qt_help_*")
+ data.translations.append("qt_*")
+
+ data.extra_files.append("examples/examples.pyproject")
+
+ # plugins
+ data.plugins.append("platforms")
+ data.plugins.append("platformthemes")
+ data.plugins.append("platforminputcontexts")
+ data.plugins.append("imageformats")
+ data.plugins.append("generic")
+ data.plugins.append("xcbglintegrations")
+
+ # Extra libraries
+ data.qtlib.append("libicudata*")
+ data.qtlib.append("libicui18n*")
+ data.qtlib.append("libicule*")
+ data.qtlib.append("libiculx*")
+ data.qtlib.append("libicutest*")
+ data.qtlib.append("libicutu*")
+ data.qtlib.append("libicuuc*")
+ data.qtlib.append("libicuio*")
+
+ return data
+
+
+def module_QtGui() -> ModuleData:
+ data = ModuleData("Gui")
+ _typesystems = [
+ "gui_common.xml",
+ "typesystem_gui_common.xml",
+ "typesystem_gui_mac.xml",
+ "typesystem_gui_win.xml",
+ "typesystem_gui_x11.xml",
+ ]
+
+ _metatypes = [
+ "qt6eglfsdeviceintegrationprivate_relwithdebinfo_metatypes.json",
+ "qt6eglfskmssupportprivate_relwithdebinfo_metatypes.json",
+ "qt6kmssupportprivate_relwithdebinfo_metatypes.json",
+ "qt6xcbqpaprivate_relwithdebinfo_metatypes.json",
+ ]
+
+ _qtlib = [
+ "libQt6EglFSDeviceIntegration",
+ "libQt6EglFsKmsSupport",
+ "libQt6XcbQpa",
+ ]
+
+ data.typesystems.extend(_typesystems)
+ data.metatypes.extend(_metatypes)
+ data.qtlib.extend(_qtlib)
+
+ data.plugins.append("egldeviceintegrations")
+ data.extra_files.append("Qt/plugins/platforms/libqeglfs*")
+
+ return data
+
+
+def module_QtWidgets() -> ModuleData:
+ data = ModuleData("Widgets")
+ data.typesystems.append("widgets_common.xml")
+ data.typesystems.append("typesystem_widgets_common.xml")
+
+ return data
+
+
+def module_QtHelp() -> ModuleData:
+ data = ModuleData("Help")
+
+ return data
+
+
+def module_QtNetwork() -> ModuleData:
+ data = ModuleData("Network")
+ data.plugins.append("networkinformation")
+ data.plugins.append("tls")
+
+ return data
+
+
+def module_QtBluetooth() -> ModuleData:
+ data = ModuleData("Bluetooth")
+
+ return data
+
+
+def module_QtConcurent() -> ModuleData:
+ data = ModuleData("Concurrent")
+
+ return data
+
+
+def module_QtDBus() -> ModuleData:
+ data = ModuleData("DBus")
+
+ return data
+
+
+def module_QtDesigner() -> ModuleData:
+ data = ModuleData("Designer")
+ data.qtlib.append("libQt6DesignerComponents")
+ data.metatypes.append("qt6designercomponentsprivate_relwithdebinfo_metatypes.json")
+ data.plugins.append("designer")
+ data.extra_files.append("Qt/plugins/assetimporters/libuip*")
+
+ return data
+
+
+def module_QtNfc() -> ModuleData:
+ data = ModuleData("Nfc")
+
+ return data
+
+
+def module_QtPrintSupport() -> ModuleData:
+ data = ModuleData("PrintSupport")
+ data.typesystems.append("typesystem_printsupport_common.xml")
+ data.plugins.append("printsupport")
+
+ return data
+
+
+def module_QtQml() -> ModuleData:
+ data = ModuleData("Qml")
+
+ _qtlib = [
+ "libQt6LabsAnimation",
+ "libQt6LabsFolderListModel",
+ "libQt6LabsQmlModels*",
+ "libQt6LabsSettings",
+ "libQt6LabsSharedImage",
+ "libQt6LabsWavefrontMesh",
+ "libQt6QmlCore",
+ "libQt6QmlLocalStorage",
+ "libQt6QmlModels",
+ "libQt6QmlWorkerScript",
+ "libQt6QmlXmlListModel",
+ ]
+
+ _include = [
+ "pysideqml.h",
+ "pysideqmlmacros.h",
+ "pysideqmlregistertype.h",
+ ]
+
+ _metatypes = [
+ "qt6labsanimation_relwithdebinfo_metatypes.json",
+ "qt6labsfolderlistmodel_relwithdebinfo_metatypes.json",
+ "qt6labsqmlmodels_relwithdebinfo_metatypes.json",
+ "qt6labssettings_relwithdebinfo_metatypes.json",
+ "qt6labssharedimage_relwithdebinfo_metatypes.json",
+ "qt6labswavefrontmesh_relwithdebinfo_metatypes.json",
+ "qt6packetprotocolprivate_relwithdebinfo_metatypes.json",
+ "qt6qmlcompilerprivate_relwithdebinfo_metatypes.json",
+ "qt6qmlcore_relwithdebinfo_metatypes.json",
+ "qt6qmldebugprivate_relwithdebinfo_metatypes.json",
+ "qt6qmldomprivate_relwithdebinfo_metatypes.json",
+ "qt6qmllintprivate_relwithdebinfo_metatypes.json",
+ "qt6qmllocalstorage_relwithdebinfo_metatypes.json",
+ "qt6qmlmodels_relwithdebinfo_metatypes.json",
+ "qt6qmlworkerscript_relwithdebinfo_metatypes.json",
+ "qt6qmlxmllistmodel_relwithdebinfo_metatypes.json",
+ ]
+
+ _qml = [
+ "Qt/labs/animation",
+ "Qt/labs/folderlistmodel",
+ "Qt/labs/sharedimage",
+ "Qt/labs/wavefrontmesh",
+ "Qt/labs/qmlmodels",
+ "Qt/labs/platform",
+ "Qt/labs/settings",
+ ]
+
+ data.lib.append("libpyside6qml")
+ data.examples.append("declarative")
+ data.plugins.append("qmltooling")
+ data.translations.append("qtdeclarative_*")
+ if sys.platform == "win32":
+ data.extra_files.append("pyside6qml.*.lib")
+ data.extra_files.append("pyside6qml.*.dll")
+ data.extra_files.append("qml/builtins.qmltypes")
+ data.extra_files.append("qml/jsroot.qmltypes")
+ else:
+ data.extra_files.append("Qt/qml/builtins.qmltypes")
+ data.extra_files.append("Qt/qml/jsroot.qmltypes")
+
+ data.qtlib.extend(_qtlib)
+ data.include.extend(_include)
+ data.metatypes.extend(_metatypes)
+ data.qml.extend(_qml)
+
+ return data
+
+
+def module_QtQuick() -> ModuleData:
+ data = ModuleData("Quick")
+ _metatypes = [
+ "qt6quickcontrolstestutilsprivate_relwithdebinfo_metatypes.json",
+ "qt6quickdialogs2_relwithdebinfo_metatypes.json",
+ "qt6quickdialogs2quickimpl_relwithdebinfo_metatypes.json",
+ "qt6quickdialogs2utils_relwithdebinfo_metatypes.json",
+ "qt6quicketest_relwithdebinfo_metatypes.json",
+ "qt6quicketestutilsprivate_relwithdebinfo_metatypes.json",
+ "qt6quicklayouts_relwithdebinfo_metatypes.json",
+ "qt6quickparticlesprivate_relwithdebinfo_metatypes.json",
+ "qt6quickshapesprivate_relwithdebinfo_metatypes.json",
+ "qt6quicktemplates2_relwithdebinfo_metatypes.json",
+ "qt6quicktest_relwithdebinfo_metatypes.json",
+ "qt6quicktestutilsprivate_relwithdebinfo_metatypes.json",
+ "qt6quicktimeline_relwithdebinfo_metatypes.json",
+ ]
+ _qtlib = [
+ "libQt6QuickDialogs2",
+ "libQt6QuickDialogs2QuickImpl",
+ "libQt6QuickDialogs2Utils",
+ "libQt6QuickLayouts",
+ "libQt6QuickParticles",
+ "libQt6QuickShapes",
+ "libQt6QuickTemplates2",
+ "libQt6QuickTest",
+ "libQt6QuickTimeline",
+ ]
+
+ data.qtlib.extend(_qtlib)
+ data.metatypes.extend(_metatypes)
+
+ return data
+
+
+def module_QtQuickControls2() -> ModuleData:
+ data = ModuleData("QuickControls2")
+ data.qtlib.append("libQt6QuickControls2Impl")
+ data.metatypes.append("qt6quickcontrols2impl_relwithdebinfo_metatypes.json")
+
+ return data
+
+
+def module_QtQuickWidgets() -> ModuleData:
+ data = ModuleData("QuickWidgets")
+ return data
+
+
+def module_QtXml() -> ModuleData:
+ data = ModuleData("Xml")
+ return data
+
+
+def module_QtTest() -> ModuleData:
+ data = ModuleData("Test")
+ return data
+
+
+def module_QtSql() -> ModuleData:
+ data = ModuleData("Sql")
+ data.plugins.append("sqldrivers")
+
+ return data
+
+
+def module_QtSvg() -> ModuleData:
+ data = ModuleData("Svg")
+ data.plugins.append("iconengines")
+
+ return data
+
+
+def module_QtSvgWidgets() -> ModuleData:
+ data = ModuleData("SvgWidgets")
+
+ return data
+
+
+def module_QtTextToSpeech() -> ModuleData:
+ data = ModuleData("TextToSpeech")
+
+ return data
+
+
+def module_QtUiTools() -> ModuleData:
+ data = ModuleData("UiTools")
+
+ return data
+
+
+def module_QtWayland() -> ModuleData:
+ data = ModuleData("Wayland")
+
+ _qtlib = [
+ "libQt6WaylandClient",
+ "libQt6WaylandCompositor",
+ "libQt6WaylandEglClientHwIntegration",
+ "libQt6WaylandEglCompositorHwIntegration",
+ "libQt6WlShellIntegration",
+ ]
+
+ _metatypes = [
+ "qt6waylandclient_relwithdebinfo_metatypes.json",
+ "qt6waylandeglclienthwintegrationprivate_relwithdebinfo_metatypes.json",
+ "qt6wlshellintegrationprivate_relwithdebinfo_metatypes.json",
+ ]
+
+ # This is added by module_QtCore()
+ # data.plugins.append("platforms")
+ _plugins = [
+ "wayland-decoration",
+ "wayland-decoration-client",
+ "wayland-graphics-integration-client",
+ "wayland-graphics-integration-server",
+ "wayland-shell-integration",
+ ]
+
+ data.qtlib.extend(_qtlib)
+ data.metatypes.extend(_metatypes)
+ data.plugins.extend(_plugins)
+ return data
+
+
+def module_Qt3DCore() -> ModuleData:
+ data = ModuleData("3DCore", qml=["Qt3D/Core"])
+
+ _plugins = [
+ "geometryloaders",
+ "renderers",
+ "renderplugins",
+ "sceneparsers",
+ ]
+
+ data.plugins.extend(_plugins)
+ data.examples.append("3d")
+ return data
+
+
+def module_Qt3DAnimation() -> ModuleData:
+ data = ModuleData("3DAnimation", qml=["Qt3D/Animation"])
+
+ return data
+
+
+def module_Qt3DExtras() -> ModuleData:
+ data = ModuleData("3DExtras", qml=["Qt3D/Extras"])
+
+ return data
+
+
+def module_Qt3DInput() -> ModuleData:
+ data = ModuleData("3DInput", qml=["Qt3D/Input"])
+
+ return data
+
+
+def module_Qt3DLogic() -> ModuleData:
+ data = ModuleData("3DLogic", qml=["Qt3D/Logic"])
+
+ return data
+
+
+def module_Qt3DRender() -> ModuleData:
+ data = ModuleData("3DRender", qml=["Qt3D/Render"])
+
+ return data
+
+
+def module_QtQuick3D() -> ModuleData:
+ data = ModuleData("Quick3D")
+
+ _qtlib = [
+ "libQt6Quick3DAssetImport",
+ "libQt6Quick3DAssetUtils",
+ "libQt6Quick3DEffects",
+ "libQt6Quick3DGlslParser",
+ "libQt6Quick3DHelpers",
+ "libQt6Quick3DIblBaker",
+ "libQt6Quick3DParticleEffects",
+ "libQt6Quick3DParticles",
+ "libQt6Quick3DRuntimeRender",
+ "libQt6Quick3DUtils",
+ "libQt6ShaderTools",
+ "libQt63DQuick",
+ "libQt63DQuickAnimation",
+ "libQt63DQuickExtras",
+ "libQt63DQuickExtras",
+ "libQt63DQuickInput",
+ "libQt63DQuickRender",
+ "libQt63DQuickScene2D",
+ ]
+
+ _metatypes = [
+ "qt63dquick_relwithdebinfo_metatypes.json",
+ "qt63dquickanimation_relwithdebinfo_metatypes.json",
+ "qt63dquickextras_relwithdebinfo_metatypes.json",
+ "qt63dquickinput_relwithdebinfo_metatypes.json",
+ "qt63dquickrender_relwithdebinfo_metatypes.json",
+ "qt63dquickscene2d_relwithdebinfo_metatypes.json",
+ "qt6quick3dassetimport_relwithdebinfo_metatypes.json",
+ "qt6quick3dassetutils_relwithdebinfo_metatypes.json",
+ "qt6quick3deffects_relwithdebinfo_metatypes.json",
+ "qt6quick3dglslparserprivate_relwithdebinfo_metatypes.json",
+ "qt6quick3dhelpers_relwithdebinfo_metatypes.json",
+ "qt6quick3diblbaker_relwithdebinfo_metatypes.json",
+ "qt6quick3dparticleeffects_relwithdebinfo_metatypes.json",
+ "qt6quick3dparticles_relwithdebinfo_metatypes.json",
+ "qt6quick3druntimerender_relwithdebinfo_metatypes.json",
+ "qt6quick3dutils_relwithdebinfo_metatypes.json",
+ "qt6shadertools_relwithdebinfo_metatypes.json",
+ ]
+
+ data.qtlib.extend(_qtlib)
+ data.metatypes.extend(_metatypes)
+ data.extra_files.append("Qt/plugins/assetimporters/libassimp*")
+
+ return data
+
+
+def module_QtAxContainer() -> ModuleData:
+ data = ModuleData("AxContainer")
+ if sys.platform == "win32":
+ data.metatypes.append("qt6axbaseprivate_metatypes.json")
+ data.metatypes.append("qt6axserver_metatypes.json")
+
+ return data
+
+
+def module_QtWebEngineCore() -> ModuleData:
+ data = ModuleData("WebEngineCore", qml=["QtWebEngine"])
+ data.translations.append("qtwebengine_locales/*")
+ data.translations.append("qtwebengine_*")
+ data.extra_dirs.append("Qt/resources")
+ if sys.platform == "win32":
+ data.extra_files.append("resources/qtwebengine*.pak")
+ data.extra_files.append("QtWebEngineProcess.exe")
+
+ return data
+
+
+def module_QtWebEngineWidgets() -> ModuleData:
+ data = ModuleData("WebEngineWidgets")
+
+ return data
+
+
+def module_QtWebEngineQuick() -> ModuleData:
+ data = ModuleData("WebEngineQuick")
+ data.qtlib.append("libQt6WebEngineQuickDelegatesQml")
+ data.metatypes.append("qt6webenginequickdelegatesqml_relwithdebinfo_metatypes.json")
+
+ return data
+
+
+def module_QtCharts() -> ModuleData:
+ data = ModuleData("Charts")
+ data.qtlib.append("libQt6ChartsQml")
+ data.metatypes.append("qt6chartsqml_relwithdebinfo_metatypes.json")
+
+ return data
+
+
+def module_QtDataVisualization() -> ModuleData:
+ data = ModuleData("DataVisualization")
+ data.qtlib.append("libQt6DataVisualizationQml")
+ data.metatypes.append("qt6datavisualizationqml_relwithdebinfo_metatypes.json")
+ data.typesystems.append("datavisualization_common.xml")
+
+ return data
+
+
+def module_QtMultimedia() -> ModuleData:
+ data = ModuleData("Multimedia")
+ data.qtlib.append("libQt6MultimediaQuick")
+ data.metatypes.append("qt6multimediaquickprivate_relwithdebinfo_metatypes.json")
+ data.translations.append("qtmultimedia_*")
+
+ return data
+
+
+def module_QtMultimediaWidgets() -> ModuleData:
+ data = ModuleData("MultimediaWidgets")
+
+ return data
+
+
+def module_QtNetworkAuth() -> ModuleData:
+ data = ModuleData("NetworkAuth")
+
+ return data
+
+
+def module_QtPositioning() -> ModuleData:
+ data = ModuleData("Positioning")
+ data.qtlib.append("libQt6PositioningQuick")
+ data.metatypes.append("qt6positioningquick_relwithdebinfo_metatypes.json")
+ data.plugins.append("position")
+
+ return data
+
+
+def module_QtRemoteObjects() -> ModuleData:
+ data = ModuleData("RemoteObjects")
+ data.qtlib.append("libQt6RemoteObjectsQml")
+ data.metatypes.append("qt6remoteobjectsqml_relwithdebinfo_metatypes.json")
+
+ return data
+
+
+def module_QtSensors() -> ModuleData:
+ data = ModuleData("Sensors")
+ data.qtlib.append("libQt6SensorsQuick")
+ data.metatypes.append("qt6sensorsquick_relwithdebinfo_metatypes.json")
+ data.plugins.append("sensors")
+
+ return data
+
+
+def module_QtSerialPort() -> ModuleData:
+ data = ModuleData("SerialPort")
+ data.translations.append("qtserialport_*")
+
+ return data
+
+
+def module_QtStateMachine() -> ModuleData:
+ data = ModuleData("StateMachine")
+ data.qtlib.append("libQt6StateMachineQml")
+ data.metatypes.append("qt6statemachineqml_relwithdebinfo_metatypes.json")
+
+ return data
+
+
+def module_QtScxml() -> ModuleData:
+ data = ModuleData("Scxml")
+ data.qtlib.append("libQt6ScxmlQml")
+ data.metatypes.append("qt6scxmlqml_relwithdebinfo_metatypes.json")
+ data.plugins.append("scxmldatamodel")
+
+ return data
+
+
+def module_QtWebChannel() -> ModuleData:
+ data = ModuleData("WebChannel")
+
+ return data
+
+
+def module_QtWebSockets() -> ModuleData:
+ data = ModuleData("WebSockets")
+ data.translations.append("qtwebsockets_*")
+
+ return data
+
+
+def module_QtOpenGL() -> ModuleData:
+ data = ModuleData("OpenGL")
+ _typesystems = [
+ "opengl_common.xml",
+ "typesystem_opengl_modifications1_0.xml",
+ "typesystem_opengl_modifications1_0_compat.xml",
+ "typesystem_opengl_modifications1_1.xml",
+ "typesystem_opengl_modifications1_1_compat.xml",
+ "typesystem_opengl_modifications1_2_compat.xml",
+ "typesystem_opengl_modifications1_3_compat.xml",
+ "typesystem_opengl_modifications1_4.xml",
+ "typesystem_opengl_modifications1_4_compat.xml",
+ "typesystem_opengl_modifications2_0.xml",
+ "typesystem_opengl_modifications2_0_compat.xml",
+ "typesystem_opengl_modifications2_1.xml",
+ "typesystem_opengl_modifications3_0.xml",
+ "typesystem_opengl_modifications3_3.xml",
+ "typesystem_opengl_modifications3_3a.xml",
+ "typesystem_opengl_modifications4_0.xml",
+ "typesystem_opengl_modifications4_1.xml",
+ "typesystem_opengl_modifications4_3.xml",
+ "typesystem_opengl_modifications4_4.xml",
+ "typesystem_opengl_modifications4_4_core.xml",
+ "typesystem_opengl_modifications4_5.xml",
+ "typesystem_opengl_modifications4_5_core.xml",
+ "typesystem_opengl_modifications_va.xml",
+ ]
+
+ data.typesystems.extend(_typesystems)
+ if sys.platform == "win32":
+ data.extra_files.append("opengl32*.dll")
+
+ return data
+
+
+def module_QtOpenGLWidgets() -> ModuleData:
+ data = ModuleData("OpenGLWidgets")
+
+ return data
+
+
+def module_QtVirtualKeyboard() -> ModuleData:
+ data = ModuleData("VirtualKeyboard")
+ data.plugins.append("virtualkeyboard")
+
+ return data
diff --git a/coin_build_instructions.py b/coin_build_instructions.py
index 43f789a2e..ba281eb4d 100644
--- a/coin_build_instructions.py
+++ b/coin_build_instructions.py
@@ -140,7 +140,7 @@ def call_setup(python_ver, phase):
cmd = [env_python, "-u", "setup.py"]
if phase in ["BUILD"]:
- cmd += ["build", "--standalone", "--skip-packaging"]
+ cmd += ["build", "--standalone"]
elif phase in ["WHEEL"] or CI_RELEASE_CONF:
cmd += ["bdist_wheel", "--reuse-build", "--standalone", "--skip-cmake", "--skip-make-install", "--only-package"]
@@ -153,8 +153,8 @@ def call_setup(python_ver, phase):
if CI_USE_SCCACHE:
cmd += [f"--compiler-launcher={CI_USE_SCCACHE}"]
- if python_ver == "3":
- cmd += ["--limited-api=yes"]
+ cmd += ["--limited-api=yes"]
+
if is_snapshot_build():
cmd += ["--snapshot-build"]
@@ -173,6 +173,10 @@ def call_setup(python_ver, phase):
env = os.environ
run_instruction(cmd, "Failed to run setup.py for build", initial_env=env)
+ if phase in ["WHEEL"] or CI_RELEASE_CONF:
+ cmd = [env_python, "create_wheels.py"]
+ run_instruction(cmd, "Failed to create new wheels", initial_env=env)
+
if __name__ == "__main__":
# Remove some environment variables that impact cmake
diff --git a/coin_test_instructions.py b/coin_test_instructions.py
index 732a5ba86..dfb2029b2 100644
--- a/coin_test_instructions.py
+++ b/coin_test_instructions.py
@@ -106,8 +106,17 @@ def call_testrunner(python_ver, buildnro):
# Try to install built wheels, and build some buildable examples.
if CI_RELEASE_CONF:
wheel_tester_path = os.path.join("testing", "wheel_tester.py")
+ # Run the test for the old set of wheels
cmd = [env_python, wheel_tester_path, qmake_path]
- run_instruction(cmd, "Error while running wheel_tester.py")
+ run_instruction(cmd, "Error while running wheel_tester.py on old wheels")
+
+ # Uninstalling the other wheels
+ run_instruction([env_pip, "uninstall", "shiboken6", "shiboken6_generator", "pyside6", "-y"],
+ "Failed to uninstall old wheels")
+
+ # Run the test for the new set of wheels
+ cmd = [env_python, wheel_tester_path, qmake_path, "--wheels-dir=dist_new", "--new"]
+ run_instruction(cmd, "Error while running wheel_tester.py on new wheels")
def run_test_instructions():
# Remove some environment variables that impact cmake
diff --git a/create_wheels.py b/create_wheels.py
new file mode 100644
index 000000000..ff350f451
--- /dev/null
+++ b/create_wheels.py
@@ -0,0 +1,417 @@
+#############################################################################
+##
+## Copyright (C) 2022 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
+import platform
+import sys
+from argparse import ArgumentParser, Namespace
+from dataclasses import dataclass
+from pathlib import Path
+from shutil import copy, rmtree
+from sysconfig import get_config_var
+from typing import List, Optional, Tuple
+
+import build # type: ignore
+from build_scripts.wheel_files import (ModuleData, # type: ignore
+ wheel_files_pyside_addons,
+ wheel_files_pyside_essentials)
+
+
+@dataclass
+class SetupData:
+ name: str
+ version: str
+ description: str
+ long_description: str
+ console_scripts: List[str]
+
+
+def get_version_from_package(name: str) -> str:
+ # Get version from the already configured '__init__.py' file
+ version = ""
+ with open(package_path / name / "__init__.py") as f:
+ for line in f:
+ if line.strip().startswith("__version__"):
+ version = line.split("=")[1].strip().replace('"', "")
+ break
+ return version
+
+
+def get_manifest(wheel_name: str, data: List[ModuleData]) -> str:
+ lines = []
+
+ for module in data:
+ # It's crucial to have this adjust method here
+ # because it include all the necessary modifications to make
+ # our soltuion work on the three main platforms.
+ module.adjusts_paths_and_extensions()
+
+ for field in module.get_fields():
+ if field == "name":
+ lines.append(f"# {getattr(module, field)}")
+ continue
+ if field == "ext":
+ continue
+ for line in getattr(module, field):
+ if field in ("examples", "extra_dirs", "qml", "plugins"):
+ lines.append(f"graft PySide6/{line}")
+ elif field == "qtlib" and sys.platform == "darwin":
+ lines.append(f"graft PySide6/{line}")
+ else:
+ lines.append(f"include PySide6/{line}")
+ lines.append("recursive-exclude PySide6 *qt.conf*")
+ lines.append("")
+
+ # Skip certain files if needed
+ lines.append("recursive-exclude PySide6/Qt/qml *.debug")
+
+ return "\n".join(lines)
+
+
+def generate_setup_cfg(artifacts: Path, setup: SetupData) -> str:
+ content = None
+ _os = sys.platform
+ arch = platform.machine()
+
+ # as Qt6 we know it's GLIBC 2.28 on RHEL 8.4
+ _tag = ""
+ if _os == "linux":
+ glibc = platform.libc_ver()[1].replace(".", "_")
+ # Will generate manylinux_2_28_x86_64
+ _tag = f"manylinux_{glibc}_{arch}"
+ elif _os == "darwin":
+ target = get_config_var("MACOSX_DEPLOYMENT_TARGET")
+ if not target:
+ print("Error: couldn't get the value from MACOSX_DEPLOYMENT_TARGET. "
+ "Falling back to local platform version.")
+ mac_ver, _, _ = platform.mac_ver()
+ # We get 10.14.2 for example, and transform into 10_14
+ target = "_".join(mac_ver.split(".")[:2])
+ else:
+ version = target.split(".")
+ if len(version) > 1:
+ target = "_".join(version)
+ else:
+ target = f"{version[0]}_0"
+ # TODO: Make it general
+ # To check if is compatible with 64bit on multi-arch systems
+ # is_64bits = sys.maxsize > 2**32
+ #
+ # We know the CI builds universal2 wheels
+ _tag = f"macosx_{target}_universal2"
+ elif _os == "win32":
+ win_arch = platform.architecture()[0]
+ msvc_arch = "x86" if win_arch.startswith("32") else "amd64"
+ _tag = f"win_{msvc_arch}"
+
+ with open(artifacts / "setup.cfg.base") as f:
+ content = f.read().format(
+ name=setup.name,
+ version=setup.version,
+ description=setup.description,
+ long_description=setup.long_description,
+ tag=_tag,
+ )
+
+ return content
+
+
+def generate_setup_py(artifacts: Path, setup: SetupData):
+ content = None
+ _name = setup.name
+
+ # To get the 'abi3' tag on the wheel name, we need to use
+ # a fake extension to activate the limited-api option.
+ # Because of the order of copying, we will use a name of a real
+ # module for each package, so it gets overwrited.
+ if _name == "PySide6":
+ fext = "PySide6/QtCore"
+ elif _name == "PySide6_Addons":
+ fext = "PySide6/Qt3DCore"
+ else:
+ fext = "Shiboken"
+
+ # Installing dependencies
+ install_requires = []
+ if name == "PySide6":
+ install_requires.append(f"shiboken6=={setup.version}")
+ install_requires.append(f"PySide6_Essentials=={setup.version}")
+ install_requires.append(f"PySide6_Addons=={setup.version}")
+ elif _name == "PySide6_Essentials":
+ install_requires.append(f"shiboken6=={setup.version}")
+ elif _name == "PySide6_Addons":
+ install_requires.append(f"shiboken6=={setup.version}")
+ install_requires.append(f"PySide6_Essentials=={setup.version}")
+
+ # For special wheels based on 'PySide6'
+ # we force the name to be PySide6 for the package_name,
+ # so we can take the files from that packaged-directory
+ if setup.name in ("PySide6_Essentials", "PySide6_Addons"):
+ _name = "PySide6"
+
+ with open(artifacts / "setup.py.base") as f:
+ content = f.read().format(
+ name=_name,
+ fake_ext=fext,
+ install=install_requires,
+ console_scripts={"console_scripts": setup.console_scripts},
+ )
+
+ return content
+
+
+def wheel_shiboken_generator() -> Tuple[SetupData, None]:
+ setup = SetupData(
+ name="shiboken6_generator",
+ version=get_version_from_package("shiboken6_generator"),
+ description="Python/C++ bindings generator",
+ long_description="README.shiboken6-generator.md",
+ console_scripts=[
+ "shiboken6 = shiboken6_generator.scripts.shiboken_tool:main",
+ "shiboken6-genpyi = shiboken6_generator.scripts.shiboken_tool:genpyi",
+ ],
+ )
+
+ return setup, None
+
+
+def wheel_shiboken_module() -> Tuple[SetupData, None]:
+ setup = SetupData(
+ name="shiboken6",
+ version=get_version_from_package("shiboken6"),
+ description="Python/C++ bindings helper module",
+ long_description="README.shiboken6.md",
+ console_scripts=[],
+ )
+
+ return setup, None
+
+
+def wheel_pyside6_essentials() -> Tuple[SetupData, List[ModuleData]]:
+ setup = SetupData(
+ name="PySide6_Essentials",
+ version=get_version_from_package("PySide6"), # we use 'PySide6' here
+ description="Python bindings for the Qt cross-platform application and UI framework (Essentials)",
+ long_description="README.pyside6_essentials.md",
+ console_scripts=[
+ "pyside6-uic = PySide6.scripts.pyside_tool:uic",
+ "pyside6-rcc = PySide6.scripts.pyside_tool:rcc",
+ "pyside6-assistant = PySide6.scripts.pyside_tool:assistant",
+ "pyside6-designer= PySide6.scripts.pyside_tool:designer",
+ "pyside6-linguist = PySide6.scripts.pyside_tool:linguist",
+ "pyside6-lupdate = PySide6.scripts.pyside_tool:lupdate",
+ "pyside6-lrelease = PySide6.scripts.pyside_tool:lrelease",
+ "pyside6-genpyi = PySide6.scripts.pyside_tool:genpyi",
+ "pyside6-metaobjectdump = PySide6.scripts.pyside_tool:metaobjectdump",
+ "pyside6-qmltyperegistrar = PySide6.scripts.pyside_tool:qmltyperegistrar",
+ "pyside6-qmllint = PySide6.scripts.pyside_tool:qmllint",
+ ],
+ )
+
+ data = wheel_files_pyside_essentials()
+
+ return setup, data
+
+
+def wheel_pyside6_addons() -> Tuple[SetupData, List[ModuleData]]:
+ setup = SetupData(
+ name="PySide6_Addons",
+ version=get_version_from_package("PySide6"), # we use 'PySide6' here
+ description="Python bindings for the Qt cross-platform application and UI framework (Addons)",
+ long_description="README.pyside6_addons.md",
+ console_scripts=[],
+ )
+
+ data = wheel_files_pyside_addons()
+
+ return setup, data
+
+
+def wheel_pyside6() -> Tuple[SetupData, Optional[List[ModuleData]]]:
+ setup = SetupData(
+ name="PySide6",
+ version=get_version_from_package("PySide6"),
+ description="Python bindings for the Qt cross-platform application and UI framework",
+ long_description="README.pyside6.md",
+ console_scripts=[],
+ )
+
+ return setup, None
+
+
+def get_build_directory(options: Namespace):
+ _venv = ""
+ _directories = list(Path("build").glob("qfp*"))
+ # Search for a "--env" option first"
+ if options.env is not None:
+ _venv = f"{options.env}a"
+ # Search for a 'qfp' directory second
+ elif _directories and len(_directories) > 0:
+ # Take the first 'qfp' directory
+ _venv = _directories[0].name
+ # Fall back to the virtual environment name
+ else:
+ # Check if we are using a virtual environment
+ try:
+ _venv = os.environ["VIRTUAL_ENV"]
+ if not _venv:
+ raise Exception("No virtual environment found")
+ _venv = f"{_venv}a"
+ except Exception as e:
+ print(f"{type(e).__name__} : {e}")
+ sys.exit(-1)
+
+ return Path(_venv)
+
+
+if __name__ == "__main__":
+
+ # Command line option to find the build/<envname>a/package_for_wheels
+ parser = ArgumentParser()
+ parser.add_argument("--env", type=str, default=None)
+ options = parser.parse_args()
+
+ venv = get_build_directory(options)
+
+ verbose = False
+ # Setup paths
+ current_path = Path(__file__).resolve().parent
+ artifacts_path = Path("wheel_artifacts/")
+ # the extra 'a' is for compatibility with the build_scripts
+ # notation that adds an 'a' when using limited-api
+ package_path = Path("build") / venv.name / "package_for_wheels"
+
+ # Check for 'package_for_wheels' directory
+ if not package_path.is_dir():
+ print(f"Couldn't find the directory: {package_path}")
+ print("Maybe your build used '--skip-packaging'?. Exiting")
+ sys.exit(-1)
+
+ setup_cfg_path = package_path / "setup.cfg"
+ setup_py_path = package_path / "setup.py"
+
+ base_files = [
+ artifacts_path / "pyproject.toml",
+ current_path / "LICENSE.COMMERCIAL",
+ current_path / "LICENSE.FDL",
+ current_path / "LICENSE.GPL2",
+ current_path / "LICENSE.GPLv3",
+ current_path / "LICENSE.GPLv3-EXCEPT",
+ current_path / "LICENSE.LGPLv3",
+ ]
+
+ # Main generation
+ wheels = {
+ "shiboken6": wheel_shiboken_module,
+ "shiboken6_generator": wheel_shiboken_generator,
+ "PySide6_Essentials": wheel_pyside6_essentials,
+ "PySide6_Addons": wheel_pyside6_addons,
+ "PySide6": wheel_pyside6,
+ }
+
+ for name, wheel_info in wheels.items():
+
+ print(f"Starting process for: {name}")
+ setup, data = wheel_info()
+
+ # 1. Generate 'setup.cfg'
+ print("-- Generating setup.cfg")
+ setup_cfg_content = generate_setup_cfg(artifacts_path, setup)
+ with open(setup_cfg_path, "w") as f:
+ f.write(setup_cfg_content)
+
+ # 2. Generate 'setup.py'
+ print("-- Generating setup.py")
+ setup_py_content = generate_setup_py(artifacts_path, setup)
+ with open(setup_py_path, "w") as f:
+ f.write(setup_py_content)
+
+ # 3. Create the 'MANIFEST.in'
+ # Special case for shiboken and shiboken_generator
+ # so we copy the whole directory, only PySide and derivatives
+ # will need to have specific information
+ print("-- Creating MANIFEST.in")
+ if not data:
+ if name == "PySide6":
+ with open(package_path / "MANIFEST.in", "w") as f:
+ f.write(f"purge {name}\n")
+ else:
+ with open(package_path / "MANIFEST.in", "w") as f:
+ f.write(f"graft {name}\n")
+ else:
+ manifest_content = get_manifest(name, data)
+ with open(package_path / "MANIFEST.in", "w") as f:
+ f.write(manifest_content)
+
+ # 4. copy configuration files to create the wheel
+ print("-- Copy configuration files to create the wheel")
+ _files: List[Path] = base_files + [Path(setup.long_description)]
+ for fname in _files:
+ copy(fname, package_path)
+
+ # 5. call the build module to create the wheel
+ # print("-- Creating wheel")
+ # os.chdir(package_path)
+ if not verbose:
+ _runner = build.pep517.wrappers.quiet_subprocess_runner
+ else:
+ _runner = build.pep517.wrappers.default_subprocess_runner
+ builder = build.ProjectBuilder(package_path, runner=_runner)
+ builder.build("wheel", "dist_new")
+ # os.chdir(current_path)
+
+ # 6. Copy wheels back
+ print("-- Copying wheels to dist_new/")
+ dist_path = Path("dist_new")
+ if not dist_path.is_dir():
+ dist_path.mkdir()
+ for wheel in Path(package_path / "dist_new").glob("*.whl"):
+ copy(wheel, dist_path / wheel.name)
+
+ # 7. Remove leftover files
+ print("-- Removing leftover files")
+ all_files = set(package_path.glob("*"))
+ files_to_remove = all_files - {
+ package_path / i for i in ("PySide6", "shiboken6", "shiboken6_generator")
+ }
+ for _f in files_to_remove:
+ if _f.is_dir():
+ rmtree(_f)
+ elif _f.is_file():
+ _f.unlink()
diff --git a/requirements.txt b/requirements.txt
index a2b45fbc5..e1671d0d9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
setuptools>=48.0
+build==0.7
sphinx
sphinx-panels
six
@@ -6,3 +7,4 @@ wheel>=0.35
PyOpenGL
pyinstaller==3.6
nuitka
+dataclasses; python_version < '3.7'
diff --git a/testing/wheel_tester.py b/testing/wheel_tester.py
index db36aa45e..c97647861 100644
--- a/testing/wheel_tester.py
+++ b/testing/wheel_tester.py
@@ -76,6 +76,7 @@ import platform
log.set_verbosity(1)
+NEW_WHEELS = False
def find_executable(executable, command_line_value):
value = command_line_value
@@ -104,8 +105,8 @@ QMAKE_PATH = None
CMAKE_PATH = None
-def get_wheels_dir():
- return os.path.join(setup_script_dir, "dist")
+def get_wheels_dir(dir_name):
+ return os.path.join(setup_script_dir, dir_name)
def get_examples_dir():
@@ -115,7 +116,10 @@ def get_examples_dir():
def package_prefix_names():
# Note: shiboken6_generator is not needed for compile_using_nuitka,
# but building modules with cmake needs it.
- return ["shiboken6", "shiboken6_generator", "PySide6"]
+ if NEW_WHEELS:
+ return ["shiboken6", "shiboken6_generator", "PySide6_Essentials", "PySide6_Addons", "PySide6"]
+ else:
+ return ["shiboken6", "shiboken6_generator", "PySide6"]
def clean_egg_info():
@@ -334,8 +338,8 @@ def try_build_examples():
execute_script(src_path / f"{modname}.pyi")
-def run_wheel_tests(install_wheels):
- wheels_dir = get_wheels_dir()
+def run_wheel_tests(install_wheels, wheels_dir_name):
+ wheels_dir = get_wheels_dir(wheels_dir_name)
py_version = f"{sys.version_info.major}.{sys.version_info.minor}"
if install_wheels:
@@ -358,8 +362,11 @@ if __name__ == "__main__":
)
parser.add_argument("--qmake", type=str, help="Path to qmake")
parser.add_argument("--cmake", type=str, help="Path to cmake")
+ parser.add_argument("--wheels-dir", type=str, help="Path to where the wheels are", default="dist")
+ parser.add_argument("--new", action="store_true", help="Option to test new wheels")
options = parser.parse_args()
QMAKE_PATH = find_executable("qmake", options.qmake)
CMAKE_PATH = find_executable("cmake", options.cmake)
+ NEW_WHEELS = options.new
- run_wheel_tests(not options.no_install_wheels)
+ run_wheel_tests(not options.no_install_wheels, options.wheels_dir)
diff --git a/wheel_artifacts/pyproject.toml b/wheel_artifacts/pyproject.toml
new file mode 100644
index 000000000..9787c3bdf
--- /dev/null
+++ b/wheel_artifacts/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools", "wheel"]
+build-backend = "setuptools.build_meta"
diff --git a/wheel_artifacts/setup.cfg.base b/wheel_artifacts/setup.cfg.base
new file mode 100644
index 000000000..9c8b60940
--- /dev/null
+++ b/wheel_artifacts/setup.cfg.base
@@ -0,0 +1,52 @@
+[metadata]
+name = {name}
+version = {version}
+description = {description}
+url = https://www.pyside.org
+download_url = https://download.qt.io/official_releases/QtForPython
+license = LGPL
+keywords = Qt
+author = Qt for Python Team
+author_email = pyside@qt-project.org
+long_description = file: {long_description}
+long_description_content_type = text/markdown
+ext_modules = None
+projects_urls =
+ Bug Tracker = https://bugreports.qt.io
+classifiers =
+ Development Status :: 5 - Production/Stable
+ Environment :: Console
+ Environment :: MacOS X
+ Environment :: X11 Applications :: Qt
+ Environment :: Win32 (MS Windows)
+ Intended Audience :: Developers
+ License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
+ License :: Other/Proprietary License
+ Operating System :: MacOS :: MacOS X
+ Operating System :: POSIX
+ Operating System :: POSIX :: Linux
+ Operating System :: Microsoft
+ Operating System :: Microsoft :: Windows
+ Programming Language :: C++
+ Programming Language :: Python
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.6
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Programming Language :: Python :: 3.10
+ Topic :: Database
+ Topic :: Software Development
+ Topic :: Software Development :: Code Generators
+ Topic :: Software Development :: Libraries :: Application Frameworks
+ Topic :: Software Development :: User Interfaces
+ Topic :: Software Development :: Widget Sets
+
+[options]
+packages = find:
+python_requires = >=3.6, <3.11
+include_package_data = True
+
+[bdist_wheel]
+py_limited_api = cp36
+plat_name = {tag}
diff --git a/wheel_artifacts/setup.py.base b/wheel_artifacts/setup.py.base
new file mode 100644
index 000000000..18634cbf8
--- /dev/null
+++ b/wheel_artifacts/setup.py.base
@@ -0,0 +1,29 @@
+import setuptools
+from setuptools import setup, Extension
+from setuptools._distutils import cmd
+
+# This class and Extension file is intended only to force setuptools
+# to understand we are using extension modules, but because we don't
+# include the source files in the 'Extension' object, it gets wrongly
+# lost.
+class build_ext(cmd.Command):
+ def initialize_options(self):
+ pass
+ def finalize_options(self):
+ pass
+ def run(self):
+ pass
+ def get_source_files(self):
+ return []
+ def get_requires_for_build_wheel(self):
+ pass
+
+setup_args = dict(
+ include_package_data=True,
+ packages = ["{name}"],
+ entry_points = {console_scripts},
+ ext_modules = [Extension("{fake_ext}", [], py_limited_api=True)],
+ install_requires={install},
+ cmdclass=dict([("build_ext", build_ext)]),
+)
+setup(**setup_args)