[neon/forks/pyqt-builder/Neon/release] /: New upstream version 1.12.1+dfsg
Dmitry Shachnev
null at kde.org
Mon Oct 18 17:21:13 BST 2021
Git commit 58a5063a5b3c1a58cfc4a389a43d2c62924c193d by Dmitry Shachnev.
Committed on 15/10/2021 at 16:37.
Pushed by jriddell into branch 'Neon/release'.
New upstream version 1.12.1+dfsg
M +32 -0 ChangeLog
M +9 -0 NEWS
M +1 -1 PKG-INFO
M +1 -1 PyQt_builder.egg-info/PKG-INFO
M +1 -1 PyQt_builder.egg-info/SOURCES.txt
M +1 -1 PyQt_builder.egg-info/requires.txt
M +5 -0 doc/pyqtbundle.rst
M +9 -1 pyqtbuild/builder.py
M +25 -27 pyqtbuild/bundle/abstract_package.py
M +16 -6 pyqtbuild/bundle/bundle.py
M +12 -2 pyqtbuild/bundle/bundle_main.py
M +5 -5 pyqtbuild/bundle/packages/pyqt.py
M +119 -64 pyqtbuild/bundle/qt_metadata.py
M +22 -11 pyqtbuild/bundle/qt_wheel.py
M +11 -1 pyqtbuild/bundle/qt_wheel_main.py
M +13 -0 pyqtbuild/project.py
M +2 -2 pyqtbuild/version.py
M +1 -1 setup.py
https://invent.kde.org/neon/forks/pyqt-builder/commit/58a5063a5b3c1a58cfc4a389a43d2c62924c193d
diff --git a/ChangeLog b/ChangeLog
index 828e07f..384e8f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2021-10-12 Phil Thompson <phil at riverbankcomputing.com>
+
+ * NEWS, pyqtbuild/bundle/bundle.py:
+ Fixed a syntax error in pyqt-bundle.
+ [1b94d1df9598] [1.12.1] <1.12-maint>
+
+ * .hgtags:
+ Added tag 1.12.0 for changeset a8e714b1af6a
+ [fdaf18dae011]
+
+2021-10-11 Phil Thompson <phil at riverbankcomputing.com>
+
+ * NEWS, doc/pyqtbundle.rst, pyqtbuild/bundle/abstract_package.py,
+ pyqtbuild/bundle/bundle.py, pyqtbuild/bundle/bundle_main.py,
+ pyqtbuild/bundle/packages/pyqt.py, pyqtbuild/bundle/qt_metadata.py,
+ pyqtbuild/bundle/qt_wheel.py, pyqtbuild/bundle/qt_wheel_main.py:
+ Added support for the --arch option to pyqt-bundle and pyqt-qt-
+ wheel.
+ [a8e714b1af6a] [1.12.0]
+
+2021-10-05 Phil Thompson <phil at riverbankcomputing.com>
+
+ * NEWS, pyqtbuild/builder.py, pyqtbuild/project.py, setup.py:
+ Build universal2 binaries when using Python 3.10 and Qt v6.2.
+ [2cbfd9cfac73]
+
+2021-09-30 Phil Thompson <phil at riverbankcomputing.com>
+
+ * .hgtags:
+ Added tag 1.11.0 for changeset 128fd244a822
+ [543a47e6bc23]
+
2021-09-25 Phil Thompson <phil at riverbankcomputing.com>
* NEWS, pyqtbuild/bundle/packages/pyqt6_webengine.py:
diff --git a/NEWS b/NEWS
index 880f0b5..a5f43f1 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,12 @@
+v1.12.1 11th October 2021
+ - A bug fix release.
+
+v1.12.0 11th October 2021
+ - Build universal2 wheels for Qt v6.2 and later when using Python v3.10 and
+ later.
+ - Added the '--arch' command line option to pyqt-bundle to specify a
+ particular architecture (x86_64 or arm64) to bundle on macOS.
+
v1.11.0 25th September 2021
- Added support for bundling Qt v6.2.
- Added support for PyQt6-WebEngine to pyqt-bundle.
diff --git a/PKG-INFO b/PKG-INFO
index 6cfc961..e278aa6 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: PyQt-builder
-Version: 1.11.0
+Version: 1.12.1
Summary: The PEP 517 compliant PyQt build system
Home-page: https://www.riverbankcomputing.com/software/pyqt-builder/
Author: Riverbank Computing Limited
diff --git a/PyQt_builder.egg-info/PKG-INFO b/PyQt_builder.egg-info/PKG-INFO
index 6cfc961..e278aa6 100644
--- a/PyQt_builder.egg-info/PKG-INFO
+++ b/PyQt_builder.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: PyQt-builder
-Version: 1.11.0
+Version: 1.12.1
Summary: The PEP 517 compliant PyQt build system
Home-page: https://www.riverbankcomputing.com/software/pyqt-builder/
Author: Riverbank Computing Limited
diff --git a/PyQt_builder.egg-info/SOURCES.txt b/PyQt_builder.egg-info/SOURCES.txt
index d816489..fb41b97 100644
--- a/PyQt_builder.egg-info/SOURCES.txt
+++ b/PyQt_builder.egg-info/SOURCES.txt
@@ -59,7 +59,7 @@ doc/html/_static/pygments.css
doc/html/_static/riverbank.css
doc/html/_static/searchtools.js
doc/html/_static/sidebar.js
-doc/html/_static/underscore-1.3.1.js
+doc/html/_static/underscore-1.13.1.js
doc/html/_static/underscore.js
doc/riverbank/layout.html
doc/riverbank/theme.conf
diff --git a/PyQt_builder.egg-info/requires.txt b/PyQt_builder.egg-info/requires.txt
index a2c1e15..9b2bbb0 100644
--- a/PyQt_builder.egg-info/requires.txt
+++ b/PyQt_builder.egg-info/requires.txt
@@ -1,2 +1,2 @@
packaging
-sip<7,>=5.5
+sip<7,>=6.3
diff --git a/doc/pyqtbundle.rst b/doc/pyqtbundle.rst
index 4f42de2..154e0e0 100644
--- a/doc/pyqtbundle.rst
+++ b/doc/pyqtbundle.rst
@@ -66,6 +66,11 @@ The full set of command line options is:
``SUFFIX`` is appended to the build tag in the name of the updated wheel.
The build tag is the version number of the copy of Qt being bundled.
+.. option:: --arch ARCH
+
+ On macOS, when bundling Qt v6.2 or later, support for the ``ARCH``
+ architecture (either ``x86_64`` or ``arm64``) only is included.
+
.. option:: --exclude NAME
The ``NAME`` bindings are excluded from the wheel. This option may be
diff --git a/pyqtbuild/builder.py b/pyqtbuild/builder.py
index ad9275e..c3934e0 100644
--- a/pyqtbuild/builder.py
+++ b/pyqtbuild/builder.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2020, Riverbank Computing Limited
+# Copyright (c) 2021, Riverbank Computing Limited
# All rights reserved.
#
# This copy of PyQt-builder is licensed for use under the terms of the SIP
@@ -24,6 +24,7 @@
import os
import sys
+import sysconfig
from sipbuild import (Buildable, BuildableModule, Builder, Option, Project,
PyProjectOptionException, UserException)
@@ -679,6 +680,13 @@ macx {
buildable.make_names_relative()
+ # Handle the target architecture(s). The way that Python handles
+ # 'universal2' seems broken as it is determined by what versions of
+ # macOS and the SDK the interpreter was built against rather than the
+ # versions that are being used now.
+ if self.project.get_platform_tag().endswith('_universal2'):
+ pro_lines.append('QMAKE_APPLE_DEVICE_ARCHS = x86_64 arm64')
+
# Handle debugging.
pro_lines.append(
'CONFIG += {}'.format(
diff --git a/pyqtbuild/bundle/abstract_package.py b/pyqtbuild/bundle/abstract_package.py
index 9f0c1b3..c539064 100644
--- a/pyqtbuild/bundle/abstract_package.py
+++ b/pyqtbuild/bundle/abstract_package.py
@@ -62,34 +62,32 @@ class AbstractPackage(ABC):
else:
self._version = None
- def bundle_msvc_runtime(self, target_qt_dir, arch):
+ def bundle_msvc_runtime(self, target_qt_dir, platform_tag):
""" Bundle the MSVC runtime. """
# This default implementation does nothing.
- def bundle_openssl(self, target_qt_dir, openssl_dir, arch):
+ def bundle_openssl(self, target_qt_dir, openssl_dir, platform_tag):
""" Bundle the OpenSSL DLLs. """
# This default implementation does nothing.
- def bundle_qt(self, target_qt_dir, arch, exclude, ignore_missing,
+ def bundle_qt(self, target_qt_dir, platform_tag, exclude, ignore_missing,
bindings=True):
""" Bundle the relevant parts of the Qt installation. Returns True if
the LGPL applies to all bundled parts.
"""
# Architecture-specific values.
- if arch.startswith('manylinux'):
- metadata_arch = 'linux'
+ if platform_tag.startswith('manylinux'):
module_extensions = ['.abi3.so', '.so']
- elif arch.startswith('macosx'):
- metadata_arch = 'macos'
+ elif platform_tag.startswith('macosx'):
module_extensions = ['.abi3.so', '.so']
- elif arch.startswith('win'):
- metadata_arch = 'win'
+ elif platform_tag.startswith('win'):
module_extensions = ['.pyd']
else:
- raise UserException("Unsupported platform tag '{0}'".format(arch))
+ raise UserException(
+ "Unsupported platform tag '{0}'".format(platform_tag))
package_dir = os.path.dirname(target_qt_dir)
lgpl = True
@@ -123,9 +121,9 @@ class AbstractPackage(ABC):
# '--target-qt-dir' but we still have to handle
# older wheels (ie. using versions of Qt released
# before '--target-qt-dir' was added.
- if metadata_arch == 'linux':
+ if platform_tag.startswith('manylinux'):
self._fix_linux_rpath(bindings)
- elif metadata_arch == 'macos':
+ elif platform_tag.startswith('macosx'):
self._fix_macos_rpath(bindings)
break
@@ -140,7 +138,7 @@ class AbstractPackage(ABC):
lgpl = lgpl and metadata.lgpl
- metadata.bundle(name, target_qt_dir, self._qt_dir, metadata_arch,
+ metadata.bundle(name, target_qt_dir, self._qt_dir, platform_tag,
self.qt_version, ignore_missing)
return lgpl
@@ -169,6 +167,18 @@ class AbstractPackage(ABC):
return os.path.join('PyQt{}'.format(qt_major_version),
'Qt{}'.format(qt_major_version))
+ @staticmethod
+ def missing_executable(exe):
+ """ Return True if an executable cannot be found on PATH. """
+
+ for p in os.environ.get('PATH', '').split(os.pathsep):
+ exe_path = os.path.join(p, exe)
+
+ if os.access(exe_path, os.X_OK):
+ return False
+
+ return True
+
@property
def qt_version_str(self):
""" The version number of the Qt installation as a string. """
@@ -179,7 +189,7 @@ class AbstractPackage(ABC):
def _fix_linux_rpath(cls, bindings):
""" Fix the rpath for Linux bindings. """
- if cls._missing_executable('chrpath'):
+ if cls.missing_executable('chrpath'):
raise UserException("'chrpath' must be installed on your system")
subprocess.run(['chrpath', '--replace', '$ORIGIN/Qt/lib', bindings])
@@ -188,7 +198,7 @@ class AbstractPackage(ABC):
def _fix_macos_rpath(cls, bindings):
""" Fix the rpath for macOS bindings. """
- if cls._missing_executable('otool') or cls._missing_executable('install_name_tool'):
+ if cls.missing_executable('otool') or cls.missing_executable('install_name_tool'):
raise UserException(
"'otool' and 'install_name_tool' from Xcode must be "
"installed on your system")
@@ -229,18 +239,6 @@ class AbstractPackage(ABC):
args.append(bindings)
subprocess.run(args)
- @staticmethod
- def _missing_executable(exe):
- """ Return True if an executable cannot be found on PATH. """
-
- for p in os.environ.get('PATH', '').split(os.pathsep):
- exe_path = os.path.join(p, exe)
-
- if os.access(exe_path, os.X_OK):
- return False
-
- return True
-
@staticmethod
def _parse_version(version_str):
""" Parse a version string as a 3-tuple of major, minor and maintenance
diff --git a/pyqtbuild/bundle/bundle.py b/pyqtbuild/bundle/bundle.py
index 394e0f9..fe13216 100644
--- a/pyqtbuild/bundle/bundle.py
+++ b/pyqtbuild/bundle/bundle.py
@@ -34,7 +34,7 @@ from .wheel import create_wheel, unpack_wheel, write_record_file
def bundle(wheel_path, qt_dir, build_tag_suffix, msvc_runtime, openssl,
- openssl_dir, exclude, ignore_missing):
+ openssl_dir, exclude, ignore_missing, arch):
""" Bundle a Qt installation with a PyQt wheel. """
wheel_path = os.path.abspath(wheel_path)
@@ -58,6 +58,16 @@ def bundle(wheel_path, qt_dir, build_tag_suffix, msvc_runtime, openssl,
raise UserException(
"Unable to recognise '{0}' as a wheel name".format(wheel_name))
+ # If an architecture is specified then it must be supported by the wheel.
+ if arch:
+ if arch in parts[-1]:
+ pass
+ elif 'universal2' in parts[-1]:
+ parts[-1] = parts[-1].replace('universal2', arch)
+ else:
+ raise UserException(
+ "'{0}' is not supported by {1}".format(arch, wheel_name))
+
# Get the package object.
sub_parts = parts[0].split('_')
if sub_parts[-1] == 'commercial':
@@ -89,7 +99,7 @@ def bundle(wheel_path, qt_dir, build_tag_suffix, msvc_runtime, openssl,
if bundled_wheel_dir.endswith(tail):
bundled_wheel_dir = bundled_wheel_dir[:-len(tail)]
- arch = bundled_wheel_dir.split('-')[-1]
+ platform_tag = bundled_wheel_dir.split('-')[-1]
# Create the directory to contain the existing wheel contents.
shutil.rmtree(bundled_wheel_dir, ignore_errors=True)
@@ -114,16 +124,16 @@ def bundle(wheel_path, qt_dir, build_tag_suffix, msvc_runtime, openssl,
ignore_errors=True)
# Bundle the relevant parts of the Qt installation.
- package.bundle_qt(target_qt_dir, arch, exclude, ignore_missing)
+ package.bundle_qt(target_qt_dir, platform_tag, exclude, ignore_missing)
- if arch in ('win32', 'win_amd64'):
+ if platform_tag in ('win32', 'win_amd64'):
# Bundle the MSVC runtime if required.
if msvc_runtime:
- package.bundle_msvc_runtime(target_qt_dir, arch)
+ package.bundle_msvc_runtime(target_qt_dir, platform_tag)
# Bundle OpenSSL if required.
if openssl:
- package.bundle_openssl(target_qt_dir, openssl_dir, arch)
+ package.bundle_openssl(target_qt_dir, openssl_dir, platform_tag)
# Find the .dist-info directory.
for distinfo_dir in os.listdir('.'):
diff --git a/pyqtbuild/bundle/bundle_main.py b/pyqtbuild/bundle/bundle_main.py
index ce76646..a3f7739 100644
--- a/pyqtbuild/bundle/bundle_main.py
+++ b/pyqtbuild/bundle/bundle_main.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2020, Riverbank Computing Limited
+# Copyright (c) 2021, Riverbank Computing Limited
# All rights reserved.
#
# This copy of PyQt-builder is licensed for use under the terms of the SIP
@@ -23,6 +23,7 @@
from argparse import ArgumentParser
+import sys
from sipbuild import handle_exception
@@ -45,6 +46,10 @@ def main():
parser.add_argument('--verbose', default=False, action='store_true',
help="enable verbose progress messages")
+ if sys.platform == 'darwin':
+ parser.add_argument('--arch', choices=('x86_64', 'arm64'),
+ help="the architecture to bundle")
+
parser.add_argument('--build-tag-suffix', metavar='SUFFIX',
help="append SUFFIX to the build tag in the wheel name")
@@ -77,11 +82,16 @@ def main():
try:
set_verbose(args.verbose)
+ try:
+ arch = args.arch
+ except AttributeError:
+ arch = None
+
bundle(wheel_path=args.wheels[0], qt_dir=args.qt_dir,
build_tag_suffix=args.build_tag_suffix,
msvc_runtime=args.msvc_runtime, openssl=args.openssl,
openssl_dir=args.openssl_dir, exclude=args.exclude,
- ignore_missing=args.ignore_missing)
+ ignore_missing=args.ignore_missing, arch=arch)
except Exception as e:
handle_exception(e)
diff --git a/pyqtbuild/bundle/packages/pyqt.py b/pyqtbuild/bundle/packages/pyqt.py
index d5dddcd..7176eaf 100644
--- a/pyqtbuild/bundle/packages/pyqt.py
+++ b/pyqtbuild/bundle/packages/pyqt.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2020, Riverbank Computing Limited
+# Copyright (c) 2021, Riverbank Computing Limited
# All rights reserved.
#
# This copy of PyQt-builder is licensed for use under the terms of the SIP
@@ -36,16 +36,16 @@ _DLLS_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'dlls')
class PyQt(AbstractPackage):
""" The base PyQt package. """
- def bundle_msvc_runtime(self, target_qt_dir, arch):
+ def bundle_msvc_runtime(self, target_qt_dir, platform_tag):
""" Bundle the MSVC runtime. """
verbose("Bundling the MSVC runtime")
self._bundle_dlls(target_qt_dir,
os.path.join(_DLLS_DIR,
- 'msvc-64' if arch == 'win_amd64' else 'msvc-32'))
+ 'msvc-64' if platform_tag == 'win_amd64' else 'msvc-32'))
- def bundle_openssl(self, target_qt_dir, openssl_dir, arch):
+ def bundle_openssl(self, target_qt_dir, openssl_dir, platform_tag):
""" Bundle the OpenSSL DLLs. """
# Qt v6.2.0 and later include appropriate backends.
@@ -62,7 +62,7 @@ class PyQt(AbstractPackage):
verbose("Bundling the default OpenSSL libraries")
openssl_dir = os.path.join(_DLLS_DIR,
- 'openssl-64' if arch == 'win_amd64' else 'openssl-32')
+ 'openssl-64' if platform_tag == 'win_amd64' else 'openssl-32')
self._bundle_dlls(target_qt_dir, openssl_dir)
diff --git a/pyqtbuild/bundle/qt_metadata.py b/pyqtbuild/bundle/qt_metadata.py
index 13cf3b3..fe242ce 100644
--- a/pyqtbuild/bundle/qt_metadata.py
+++ b/pyqtbuild/bundle/qt_metadata.py
@@ -59,7 +59,7 @@ class VersionedMetadata:
self.lgpl = lgpl
self.legacy = legacy
- def bundle(self, name, target_qt_dir, qt_dir, arch, qt_version,
+ def bundle(self, name, target_qt_dir, qt_dir, platform_tag, qt_version,
ignore_missing):
""" Bundle part of Qt as defined by the meta-data. """
@@ -68,53 +68,68 @@ class VersionedMetadata:
if self._name is None:
self._name = name
+ # See if a particular macOS architecture has been specified but only
+ # for versions of Qt that support universal libraries.
+ macos_thin_arch = self._get_macos_thin_arch(platform_tag)
+ if qt_version < (6, 2, 0):
+ macos_thin_arch = None
+
+ if macos_thin_arch is not None:
+ from .abstract_package import AbstractPackage
+
+ if AbstractPackage.missing_executable('lipo'):
+ raise UserException(
+ "'lipo' from Xcode must be installed on your system")
+
# Bundle the Qt library that has been wrapped (if there is one).
if self._dll:
- self._bundle_qt_library(self._name, target_qt_dir, qt_dir, arch,
- qt_version, ignore_missing)
+ self._bundle_qt_library(self._name, target_qt_dir, qt_dir,
+ qt_version, platform_tag, macos_thin_arch, ignore_missing)
# Bundle any other dependent Qt libraries.
- for lib_arch, libs in self._lib_deps.items():
- if lib_arch == '' or lib_arch == arch:
+ for metadata_arch, libs in self._lib_deps.items():
+ if self._is_platform(metadata_arch, platform_tag):
for lib in libs:
- self._bundle_qt_library(lib, target_qt_dir, qt_dir, arch,
- qt_version, ignore_missing)
+ self._bundle_qt_library(lib, target_qt_dir, qt_dir,
+ qt_version, platform_tag, macos_thin_arch,
+ ignore_missing)
# Bundle any other libraries.
lib_contents = None
- for lib_arch, libs in self._other_lib_deps.items():
- if lib_arch == '' or lib_arch == arch:
+ for metadata_arch, libs in self._other_lib_deps.items():
+ if self._is_platform(metadata_arch, platform_tag):
for lib in libs:
if '*' in lib:
# A wildcard implies the dependency is optional. This
# is mainly to (historically) deal with ICU on Windows.
if lib_contents is None:
lib_contents = os.listdir(
- self._get_qt_library_dir(qt_dir, arch))
+ self._get_qt_library_dir(qt_dir,
+ platform_tag))
for qt_lib in lib_contents:
if fnmatch.fnmatch(qt_lib, lib):
self._bundle_library(qt_lib, target_qt_dir,
- qt_dir, arch, qt_version,
+ qt_dir, platform_tag, macos_thin_arch,
ignore_missing)
else:
- self._bundle_library(lib, target_qt_dir, qt_dir, arch,
- qt_version, ignore_missing)
+ self._bundle_library(lib, target_qt_dir, qt_dir,
+ platform_tag, macos_thin_arch, ignore_missing)
# Bundle any executables.
- for exe_arch, exes in self._exes.items():
- if exe_arch == '' or exe_arch == arch:
+ for metadata_arch, exes in self._exes.items():
+ if self._is_platform(metadata_arch, platform_tag):
for exe in exes:
bundled_exe = self._bundle_file(exe, target_qt_dir, qt_dir,
- arch, qt_version, ignore_missing)
+ platform_tag, macos_thin_arch, ignore_missing)
if bundled_exe is not None:
- if arch == 'linux':
+ if self._is_platform('linux', platform_tag):
self._fix_linux_executable(bundled_exe, qt_version)
- elif arch == 'macos':
+ elif self._is_platform('macos', platform_tag):
self._fix_macos_executable(bundled_exe, qt_version)
- elif arch == 'win':
+ elif self._is_platform('win', platform_tag):
self._fix_win_executable(bundled_exe)
# Bundle any QML files.
@@ -125,15 +140,16 @@ class VersionedMetadata:
for qml_subdir in qml_names:
self._bundle_nondebug(os.path.join('qml', qml_subdir),
- target_qt_dir, qt_dir, arch, qt_version,
+ target_qt_dir, qt_dir, platform_tag, macos_thin_arch,
ignore_missing)
# Bundle any plugins. We haven't done the analysis of which plugins
# belong to which package so we assume that only the QtCore package
# will specify any to exclude and we bundle all of them with that.
if self._excluded_plugins is not None:
- self._bundle_nondebug('plugins', target_qt_dir, qt_dir, arch,
- qt_version, ignore_missing, exclude=self._excluded_plugins)
+ self._bundle_nondebug('plugins', target_qt_dir, qt_dir,
+ platform_tag, macos_thin_arch, ignore_missing,
+ exclude=self._excluded_plugins)
# Bundle any translations:
if self._translations:
@@ -144,13 +160,14 @@ class VersionedMetadata:
if qm.endswith('.qm'):
for prefix in self._translations:
if qm.startswith(prefix):
- self._bundle_file(qm, target_tr_dir, tr_dir, arch,
- qt_version, ignore_missing,
+ self._bundle_file(qm, target_tr_dir, tr_dir,
+ platform_tag, macos_thin_arch,
+ ignore_missing,
might_be_code=False)
# Bundle any dynamically created files.
- for files_arch, files in self._files.items():
- if files_arch == '' or files_arch == arch:
+ for metadata_arch, files in self._files.items():
+ if self._is_platform(metadata_arch, platform_tag):
for fn, content in files:
fn = os.path.join(target_qt_dir, fn)
os.makedirs(os.path.dirname(fn), exist_ok=True)
@@ -159,11 +176,11 @@ class VersionedMetadata:
f.write(content)
# Bundle anything else.
- for oth_arch, others in self._others.items():
- if oth_arch == '' or oth_arch == arch:
+ for metadata_arch, others in self._others.items():
+ if self._is_platform(metadata_arch, platform_tag):
for oth in others:
self._bundle_file(oth, target_qt_dir, qt_dir,
- arch, qt_version, ignore_missing,
+ platform_tag, macos_thin_arch, ignore_missing,
might_be_code=False)
def is_applicable(self, qt_version):
@@ -174,8 +191,8 @@ class VersionedMetadata:
return self._version is None or qt_version >= self._version
@classmethod
- def _bundle_nondebug(cls, src_dir, target_qt_dir, qt_dir, arch, qt_version,
- ignore_missing, exclude=None):
+ def _bundle_nondebug(cls, src_dir, target_qt_dir, qt_dir, platform_tag,
+ macos_thin_arch, ignore_missing, exclude=None):
""" Bundle the non-debug contents of a directory. """
if exclude is None:
@@ -189,20 +206,20 @@ class VersionedMetadata:
pass
for name in list(dirnames):
- if cls._is_debug(name, arch):
+ if cls._is_debug(name, platform_tag):
dirnames.remove(name)
for name in filenames:
- if cls._is_debug(name, arch):
+ if cls._is_debug(name, platform_tag):
continue
cls._bundle_file(
os.path.relpath(os.path.join(dirpath, name), qt_dir),
- target_qt_dir, qt_dir, arch, qt_version,
+ target_qt_dir, qt_dir, platform_tag, macos_thin_arch,
ignore_missing)
@staticmethod
- def _bundle_file(name, target_dir, src_dir, arch, qt_version,
+ def _bundle_file(name, target_dir, src_dir, platform_tag, macos_thin_arch,
ignore_missing, ignore=None, might_be_code=True):
""" Bundle a file (or directory) and return the name of the installed
file (or directory) or None if it was missing.
@@ -216,13 +233,13 @@ class VersionedMetadata:
if os.path.isdir(src):
shutil.copytree(src, dst, ignore=ignore)
elif os.path.isfile(src):
- # See if it worth trying to remove the arm64 code.
- if arch == 'macos' and might_be_code and qt_version >= (6, 2, 0):
+ if macos_thin_arch is not None and might_be_code:
stderr = None if is_verbose() else subprocess.DEVNULL
try:
subprocess.run(
- ['lipo', '-thin', 'x86_64', '-output', dst, src],
+ ['lipo', '-thin', macos_thin_arch, '-output', dst,
+ src],
stderr=stderr, check=True)
except:
# If there is any sort of error then just copy it.
@@ -239,27 +256,31 @@ class VersionedMetadata:
return dst
@classmethod
- def _bundle_library(cls, name, target_qt_dir, qt_dir, arch, qt_version,
- ignore_missing, ignore=None):
+ def _bundle_library(cls, name, target_qt_dir, qt_dir, platform_tag,
+ macos_thin_arch, ignore_missing, ignore=None):
""" Bundle a library. """
cls._bundle_file(name,
- os.path.join(target_qt_dir, cls._get_qt_library_subdir(arch)),
- cls._get_qt_library_dir(qt_dir, arch), arch, qt_version,
- ignore_missing, ignore=ignore)
+ os.path.join(target_qt_dir,
+ cls._get_qt_library_subdir(platform_tag)),
+ cls._get_qt_library_dir(qt_dir, platform_tag), platform_tag,
+ macos_thin_arch, ignore_missing, ignore=ignore)
@classmethod
- def _bundle_qt_library(cls, name, target_qt_dir, qt_dir, arch, qt_version,
- ignore_missing):
+ def _bundle_qt_library(cls, name, target_qt_dir, qt_dir, qt_version,
+ platform_tag, macos_thin_arch, ignore_missing):
""" Bundle a Qt library. """
- cls._bundle_library(cls._impl_from_library(name, arch, qt_version),
- target_qt_dir, qt_dir, arch, qt_version, ignore_missing)
+ cls._bundle_library(
+ cls._impl_from_library(name, platform_tag, qt_version),
+ target_qt_dir, qt_dir, platform_tag, macos_thin_arch,
+ ignore_missing)
- if arch == 'macos':
+ if cls._is_platform('macos', platform_tag):
# Copy the Resources directory without the unnecessary .prl files.
cls._bundle_library('{}.framework/Resources'.format(name),
- target_qt_dir, qt_dir, arch, qt_version, ignore_missing,
+ target_qt_dir, qt_dir, platform_tag, macos_thin_arch,
+ ignore_missing,
ignore=lambda d, c: [f for f in c if f.endswith('.prl')])
@staticmethod
@@ -323,51 +344,85 @@ class VersionedMetadata:
cls._create_qt_conf(exe)
@classmethod
- def _get_qt_library_dir(cls, qt_dir, arch):
+ def _get_macos_thin_arch(cls, platform_tag):
+ """ Return the single macOS architecture, or None if the platform is
+ not macOS or is universal.
+ """
+
+ if cls._is_platform('macos', platform_tag):
+ if platform_tag.endswith('_intel') or platform_tag.endswith('_x86_64'):
+ return 'x86_64'
+
+ if platform_tag.endswith('_arm64'):
+ return 'arm64'
+
+ return None
+
+ @classmethod
+ def _get_qt_library_dir(cls, qt_dir, platform_tag):
""" Return the name of the directory in the Qt installation containing
the libraries.
"""
- return os.path.join(qt_dir, cls._get_qt_library_subdir(arch))
+ return os.path.join(qt_dir, cls._get_qt_library_subdir(platform_tag))
- @staticmethod
- def _get_qt_library_subdir(arch):
+ @classmethod
+ def _get_qt_library_subdir(cls, platform_tag):
""" Return the name of the sub-directory in the Qt installation
containing the libraries.
"""
- return 'bin' if arch == 'win' else 'lib'
+ return 'bin' if cls._is_platform('win', platform_tag) else 'lib'
- @staticmethod
- def _impl_from_library(name, arch, qt_version):
+ @classmethod
+ def _impl_from_library(cls, name, platform_tag, qt_version):
""" Return the architecture-specific name of a Qt library. """
qt_major = qt_version[0]
- if arch == 'linux':
+ if cls._is_platform('linux', platform_tag):
return 'libQt{}{}.so.{}'.format(qt_major, name[2:], qt_major)
- if arch == 'macos':
+ if cls._is_platform('macos', platform_tag):
framework = '5' if qt_major == 5 else 'A'
return '{}.framework/Versions/{}/{}'.format(name, framework, name)
- if arch == 'win':
+ if cls._is_platform('win', platform_tag):
return 'Qt{}{}.dll'.format(qt_major, name[2:])
- @staticmethod
- def _is_debug(name, arch):
+ @classmethod
+ def _is_debug(cls, name, platform_tag):
""" Return True if a name implies a debug version. """
- if arch == 'linux':
+ if cls._is_platform('linux', platform_tag):
return name.endswith('.debug')
- if arch == 'macos':
+ if cls._is_platform('macos', platform_tag):
return name.endswith('_debug.dylib') or name.endswith('.dSYM')
- if arch == 'win':
+ if cls._is_platform('win', platform_tag):
# Special case known non-debug DLLs that end with a 'd'.
if name.endswith('backend.dll'):
return False
return name.endswith('.pdb') or name.endswith('d.dll')
+
+ @staticmethod
+ def _is_platform(metadata_arch, platform_tag):
+ """ Return True if a metadata archtitecture matches a platform tag. """
+
+ # See if it applies to all architectures.
+ if metadata_arch == '':
+ return True
+
+ if metadata_arch == 'linux' and platform_tag.startswith('manylinux'):
+ return True
+
+ if metadata_arch == 'macos' and platform_tag.startswith('macosx'):
+ return True
+
+ if metadata_arch == 'win' and platform_tag.startswith('win'):
+ return True
+
+ return False
diff --git a/pyqtbuild/bundle/qt_wheel.py b/pyqtbuild/bundle/qt_wheel.py
index 8cfbfcb..e93f9ab 100644
--- a/pyqtbuild/bundle/qt_wheel.py
+++ b/pyqtbuild/bundle/qt_wheel.py
@@ -33,7 +33,7 @@ from .wheel import create_wheel, write_record_file
def qt_wheel(package, qt_dir, build_tag, suffix, msvc_runtime, openssl,
- openssl_dir, exclude):
+ openssl_dir, exclude, arch):
""" Create a wheel containing the subset of a Qt installation required for
a particular PyQt package.
"""
@@ -61,18 +61,29 @@ def qt_wheel(package, qt_dir, build_tag, suffix, msvc_runtime, openssl,
# Construct the tag.
qt_arch = os.path.basename(qt_dir)
if qt_arch == 'gcc_64':
- arch = 'manylinux{}_x86_64'.format(
+ platform_tag = 'manylinux{}_x86_64'.format(
'_2_28' if package.qt_version[0] == 6 else '2014')
elif qt_arch in ('macos', 'clang_64'):
- arch = 'macosx_{}_intel'.format(
- '10_14' if package.qt_version[0] == 6 else '10_13')
+ if package.qt_version < (6, 2, 0):
+ if arch is not None:
+ raise UserException(
+ "'--arch' may only be specified for Qt v6.2 and later")
+
+ subarch = 'x86_64'
+ elif arch is None:
+ subarch = 'universal2'
+ else:
+ subarch = arch
+
+ platform_tag = 'macosx_{}_{}'.format(
+ '10_14' if package.qt_version[0] == 6 else '10_13', subarch)
elif qt_arch.startswith('msvc'):
- arch = 'win_amd64' if qt_arch.endswith('_64') else 'win32'
+ platform_tag = 'win_amd64' if qt_arch.endswith('_64') else 'win32'
else:
raise UserException(
"Qt architecture '{0}' is unsupported".format(qt_arch))
- tag_parts = ['py3', 'none', arch]
+ tag_parts = ['py3', 'none', platform_tag]
tag = '-'.join(tag_parts)
# Construct the name of the wheel.
@@ -98,17 +109,17 @@ def qt_wheel(package, qt_dir, build_tag, suffix, msvc_runtime, openssl,
# Bundle the relevant parts of the Qt installation.
target_qt_dir = package.get_target_qt_dir()
- lgpl = package.bundle_qt(target_qt_dir, arch, exclude, ignore_missing=True,
- bindings=False)
+ lgpl = package.bundle_qt(target_qt_dir, platform_tag, exclude,
+ ignore_missing=True, bindings=False)
- if arch in ('win32', 'win_amd64'):
+ if platform_tag in ('win32', 'win_amd64'):
# Bundle the MSVC runtime if required.
if msvc_runtime:
- package.bundle_msvc_runtime(target_qt_dir, arch)
+ package.bundle_msvc_runtime(target_qt_dir, platform_tag)
# Bundle OpenSSL if required.
if openssl:
- package.bundle_openssl(target_qt_dir, openssl_dir, arch)
+ package.bundle_openssl(target_qt_dir, openssl_dir, platform_tag)
# Create the .dist-info directory and populate it from the prototypes.
os.mkdir(distinfo_dir)
diff --git a/pyqtbuild/bundle/qt_wheel_main.py b/pyqtbuild/bundle/qt_wheel_main.py
index 7e025ee..ae7153b 100644
--- a/pyqtbuild/bundle/qt_wheel_main.py
+++ b/pyqtbuild/bundle/qt_wheel_main.py
@@ -23,6 +23,7 @@
from argparse import ArgumentParser
+import sys
from sipbuild import handle_exception
@@ -45,6 +46,10 @@ def main():
parser.add_argument('--verbose', default=False, action='store_true',
help="enable verbose progress messages")
+ if sys.platform == 'darwin':
+ parser.add_argument('--arch', choices=('x86_64', 'arm64'),
+ help="the architecture to create the wheel for")
+
parser.add_argument('--build-tag', metavar='TAG',
help="use TAG as the build tag in the wheel name")
@@ -77,10 +82,15 @@ def main():
try:
set_verbose(args.verbose)
+ try:
+ arch = args.arch
+ except AttributeError:
+ arch = None
+
qt_wheel(package=args.packages[0], qt_dir=args.qt_dir,
build_tag=args.build_tag, suffix=args.suffix,
msvc_runtime=args.msvc_runtime, openssl=args.openssl,
- openssl_dir=args.openssl_dir, exclude=args.exclude)
+ openssl_dir=args.openssl_dir, exclude=args.exclude, arch=arch)
except Exception as e:
handle_exception(e)
diff --git a/pyqtbuild/project.py b/pyqtbuild/project.py
index 6d6cb3a..8a816ad 100644
--- a/pyqtbuild/project.py
+++ b/pyqtbuild/project.py
@@ -129,6 +129,19 @@ class PyQtProject(Project):
if self.py_pylib_shlib == '':
self.py_pylib_shlib = pylib_shlib
+ def get_platform_tag(self):
+ """ Return the platform tag to use in a wheel name. This calls the
+ default implementation and replaces 'universal2' with 'x86_64' for
+ versions of Qt that don't support Apple silicon.
+ """
+
+ platform_tag = super().get_platform_tag().split('_')
+
+ if platform_tag[-1] == 'universal2' and self.builder.qt_version < 0x060200:
+ platform_tag[-1] = 'x86_64'
+
+ return '_'.join(platform_tag)
+
def get_options(self):
""" Return the list of configurable options. """
diff --git a/pyqtbuild/version.py b/pyqtbuild/version.py
index 52f0fa6..af1763e 100644
--- a/pyqtbuild/version.py
+++ b/pyqtbuild/version.py
@@ -1,2 +1,2 @@
-PYQTBUILD_VERSION = 0x010b00
-PYQTBUILD_VERSION_STR = '1.11.0'
+PYQTBUILD_VERSION = 0x010c01
+PYQTBUILD_VERSION_STR = '1.12.1'
diff --git a/setup.py b/setup.py
index 66dcfd9..0e835d9 100644
--- a/setup.py
+++ b/setup.py
@@ -49,7 +49,7 @@ setup(
version=version,
license='SIP',
python_requires='>=3.5',
- install_requires=['packaging', 'sip >=5.5, <7'],
+ install_requires=['packaging', 'sip >=6.3, <7'],
packages=find_packages(),
package_data={
'pyqtbuild.bundle': ['dlls/*/*', 'qt_wheel_distinfo/*'],
More information about the Neon-commits
mailing list