From c8e6baea6015cb687fc049a90caa3866476bbe5e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 5 Oct 2020 09:51:17 +0200 Subject: setup.py: Remove constructor parameters depending on options from PysideBuildWheel Constructor parameters depending on option values create a problem for introducing per-command option parsing. To fix this, split utility functions used by the commands in main.py and PysideBuildWheel into a separate wheel_utils.py Task-number: PYSIDE-807 Change-Id: Idabd3ba03726d2284e80234fc8485b70e6eb20ca Reviewed-by: Cristian Maureira-Fredes --- build_scripts/build_scripts.pyproject | 2 +- build_scripts/main.py | 126 ++------------------------ build_scripts/wheel_override.py | 22 ++--- build_scripts/wheel_utils.py | 162 ++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 133 deletions(-) create mode 100644 build_scripts/wheel_utils.py (limited to 'build_scripts') diff --git a/build_scripts/build_scripts.pyproject b/build_scripts/build_scripts.pyproject index 604419c10..80df4d386 100644 --- a/build_scripts/build_scripts.pyproject +++ b/build_scripts/build_scripts.pyproject @@ -1,6 +1,6 @@ { "files": ["main.py", "__init__.py", "config.py", "options.py", "qtinfo.py", - "setup_runner.py", "utils.py", "wheel_override.py", + "setup_runner.py", "utils.py", "wheel_override.py", "wheel_utils.py", "platforms/__init__.py", "platforms/linux.py", "platforms/macos.py", "platforms/unix.py", "platforms/windows_desktop.py", diff --git a/build_scripts/main.py b/build_scripts/main.py index 84f839b78..046f3502d 100644 --- a/build_scripts/main.py +++ b/build_scripts/main.py @@ -43,8 +43,11 @@ from distutils.version import LooseVersion import os import time from .config import config -from .utils import memoize, get_python_dict +from .utils import get_python_dict from .options import OPTION +from .wheel_utils import (get_package_version, get_qt_version, + get_package_timestamp, macos_plat_name, + macos_pyside_min_deployment_target) setup_script_dir = os.getcwd() build_scripts_dir = os.path.join(setup_script_dir, 'build_scripts') @@ -57,37 +60,6 @@ def elapsed(): return int(time.time()) - start_time -@memoize -def get_package_timestamp(): - """ In a Coin CI build the returned timestamp will be the - Coin integration id timestamp. For regular builds it's - just the current timestamp or a user provided one.""" - return OPTION["PACKAGE_TIMESTAMP"] if OPTION["PACKAGE_TIMESTAMP"] else start_time - - -@memoize -def get_package_version(): - """ Returns the version string for the PySide2 package. """ - pyside_version_py = os.path.join( - setup_script_dir, "sources", "pyside2", "pyside_version.py") - d = get_python_dict(pyside_version_py) - - final_version = "{}.{}.{}".format( - d['major_version'], d['minor_version'], d['patch_version']) - release_version_type = d['release_version_type'] - pre_release_version = d['pre_release_version'] - if pre_release_version and release_version_type: - final_version += release_version_type + pre_release_version - if release_version_type.startswith("comm"): - final_version += "." + release_version_type - - # Add the current timestamp to the version number, to suggest it - # is a development snapshot build. - if OPTION["SNAPSHOT_BUILD"]: - final_version += ".dev{}".format(get_package_timestamp()) - return final_version - - def get_setuptools_extension_modules(): # Setting py_limited_api on the extension is the "correct" thing # to do, but it doesn't actually do anything, because we @@ -283,21 +255,6 @@ qtinfo = QtInfo() qtinfo.setup(OPTION["QMAKE"], OPTION["QT_VERSION"]) -def get_qt_version(): - qt_version = qtinfo.version - - if not qt_version: - log.error("Failed to query the Qt version with qmake {0}".format(qtinfo.qmake_command)) - sys.exit(1) - - if LooseVersion(qtinfo.version) < LooseVersion("5.7"): - log.error("Incompatible Qt version detected: {}. A Qt version >= 5.7 is " - "required.".format(qt_version)) - sys.exit(1) - - return qt_version - - def prepare_build(): if (os.path.isdir(".git") and not OPTION["IGNOREGIT"] and not OPTION["ONLYPACKAGE"] and not OPTION["REUSE_BUILD"]): @@ -417,7 +374,7 @@ class PysideBuild(_build): def finalize_options(self): os_name_backup = os.name if sys.platform == 'darwin': - self.plat_name = PysideBuild.macos_plat_name() + self.plat_name = macos_plat_name() # This is a hack to circumvent the dubious check in # distutils.commands.build -> finalize_options, which only # allows setting the plat_name for windows NT. @@ -786,74 +743,12 @@ class PysideBuild(_build): log.info("OpenSSL dll directory: {}".format(OPTION["OPENSSL"])) if sys.platform == 'darwin': pyside_macos_deployment_target = ( - PysideBuild.macos_pyside_min_deployment_target() + macos_pyside_min_deployment_target() ) log.info("MACOSX_DEPLOYMENT_TARGET set to: {}".format( pyside_macos_deployment_target)) log.info("=" * 30) - @staticmethod - def macos_qt_min_deployment_target(): - target = qtinfo.macos_min_deployment_target - - if not target: - raise DistutilsSetupError("Failed to query for Qt's QMAKE_MACOSX_DEPLOYMENT_TARGET.") - return target - - @staticmethod - @memoize - def macos_pyside_min_deployment_target(): - """ - Compute and validate PySide2 MACOSX_DEPLOYMENT_TARGET value. - Candidate sources that are considered: - - setup.py provided value - - maximum value between minimum deployment target of the - Python interpreter and the minimum deployment target of - the Qt libraries. - If setup.py value is provided, that takes precedence. - Otherwise use the maximum of the above mentioned two values. - """ - python_target = get_config_var('MACOSX_DEPLOYMENT_TARGET') or None - qt_target = PysideBuild.macos_qt_min_deployment_target() - setup_target = OPTION["MACOS_DEPLOYMENT_TARGET"] - - qt_target_split = [int(x) for x in qt_target.split('.')] - if python_target: - python_target_split = [int(x) for x in python_target.split('.')] - if setup_target: - setup_target_split = [int(x) for x in setup_target.split('.')] - - message = ("Can't set MACOSX_DEPLOYMENT_TARGET value to {} because " - "{} was built with minimum deployment target set to {}.") - # setup.py provided OPTION["MACOS_DEPLOYMENT_TARGET"] value takes - # precedence. - if setup_target: - if python_target and setup_target_split < python_target_split: - raise DistutilsSetupError(message.format(setup_target, "Python", - python_target)) - if setup_target_split < qt_target_split: - raise DistutilsSetupError(message.format(setup_target, "Qt", - qt_target)) - # All checks clear, use setup.py provided value. - return setup_target - - # Setup.py value not provided, - # use same value as provided by Qt. - if python_target: - maximum_target = '.'.join([str(e) for e in max(python_target_split, qt_target_split)]) - else: - maximum_target = qt_target - return maximum_target - - @staticmethod - @memoize - def macos_plat_name(): - deployment_target = PysideBuild.macos_pyside_min_deployment_target() - # Example triple "macosx-10.12-x86_64". - plat = get_platform().split("-") - plat_name = "{}-{}-{}".format(plat[0], deployment_target, plat[2]) - return plat_name - def build_patchelf(self): if not sys.platform.startswith('linux'): return @@ -1047,7 +942,7 @@ class PysideBuild(_build): # interpreter sysconfig value. # Doing so could break the detected clang include paths # for example. - deployment_target = PysideBuild.macos_pyside_min_deployment_target() + deployment_target = macos_pyside_min_deployment_target() cmake_cmd.append("-DCMAKE_OSX_DEPLOYMENT_TARGET={}".format(deployment_target)) os.environ['MACOSX_DEPLOYMENT_TARGET'] = deployment_target @@ -1400,11 +1295,6 @@ cmd_class_dict = { 'build_rst_docs': PysideRstDocs, } if wheel_module_exists: - params = {} - params['qt_version'] = get_qt_version() - params['package_version'] = get_package_version() - if sys.platform == 'darwin': - params['macos_plat_name'] = PysideBuild.macos_plat_name() - pyside_bdist_wheel = get_bdist_wheel_override(params) + pyside_bdist_wheel = get_bdist_wheel_override() if pyside_bdist_wheel: cmd_class_dict['bdist_wheel'] = pyside_bdist_wheel diff --git a/build_scripts/wheel_override.py b/build_scripts/wheel_override.py index 0a3cb0dbf..e4147a5bc 100644 --- a/build_scripts/wheel_override.py +++ b/build_scripts/wheel_override.py @@ -54,6 +54,7 @@ try: from wheel import __version__ as wheel_version from .options import OPTION + from .wheel_utils import get_package_version, get_qt_version, macos_plat_name wheel_module_exists = True except Exception as e: @@ -62,20 +63,13 @@ except Exception as e: 'Skipping wheel overriding.'.format(e)) -def get_bdist_wheel_override(params): - if wheel_module_exists: - class PysideBuildWheelDecorated(PysideBuildWheel): - def __init__(self, *args, **kwargs): - self.params = params - PysideBuildWheel.__init__(self, *args, **kwargs) - return PysideBuildWheelDecorated - else: - return None +def get_bdist_wheel_override(): + return PysideBuildWheel if wheel_module_exists else None class PysideBuildWheel(_bdist_wheel): def __init__(self, *args, **kwargs): - self.pyside_params = None + self._package_version = None _bdist_wheel.__init__(self, *args, **kwargs) def finalize_options(self): @@ -83,7 +77,7 @@ class PysideBuildWheel(_bdist_wheel): # Override the platform name to contain the correct # minimum deployment target. # This is used in the final wheel name. - self.plat_name = self.params['macos_plat_name'] + self.plat_name = macos_plat_name() # When limited API is requested, notify bdist_wheel to # create a properly named package. @@ -92,6 +86,8 @@ class PysideBuildWheel(_bdist_wheel): if limited_api_enabled: self.py_limited_api = "cp35.cp36.cp37.cp38.cp39" + self._package_version = get_package_version() + _bdist_wheel.finalize_options(self) @property @@ -102,9 +98,7 @@ class PysideBuildWheel(_bdist_wheel): # PySide2-5.6-5.6.4-cp27-cp27m-macosx_10_10_intel.whl # The PySide2 version is "5.6". # The Qt version built against is "5.6.4". - qt_version = self.params['qt_version'] - package_version = self.params['package_version'] - wheel_version = "{}-{}".format(package_version, qt_version) + wheel_version = "{}-{}".format(self._package_version, get_qt_version()) components = (_safer_name(self.distribution.get_name()), wheel_version) if self.build_number: components += (self.build_number,) diff --git a/build_scripts/wheel_utils.py b/build_scripts/wheel_utils.py new file mode 100644 index 000000000..71b4e0acf --- /dev/null +++ b/build_scripts/wheel_utils.py @@ -0,0 +1,162 @@ +############################################################################# +## +## Copyright (C) 2020 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 __future__ import print_function + +import os +import time + +from distutils.errors import DistutilsSetupError +from distutils.sysconfig import get_config_var +from distutils.util import get_platform +from distutils.version import LooseVersion + +from .options import OPTION +from .qtinfo import QtInfo +from .utils import memoize, get_python_dict + + +@memoize +def get_package_timestamp(): + """ In a Coin CI build the returned timestamp will be the + Coin integration id timestamp. For regular builds it's + just the current timestamp or a user provided one.""" + option_value = OPTION["PACKAGE_TIMESTAMP"] + return option_value if option_value else int(time.time()) + + +def get_qt_version(): + qtinfo = QtInfo() + qt_version = qtinfo.version + + if not qt_version: + m = "Failed to query the Qt version with qmake {0}".format(qtinfo.qmake_command) + raise DistutilsSetupError(m) + + if LooseVersion(qtinfo.version) < LooseVersion("5.7"): + m = "Incompatible Qt version detected: {}. A Qt version >= 5.7 is required.".format(qt_version) + raise DistutilsSetupError(m) + + return qt_version + + +@memoize +def get_package_version(): + """ Returns the version string for the PySide2 package. """ + setup_script_dir = os.getcwd() + pyside_version_py = os.path.join( + setup_script_dir, "sources", "pyside2", "pyside_version.py") + d = get_python_dict(pyside_version_py) + + final_version = "{}.{}.{}".format( + d['major_version'], d['minor_version'], d['patch_version']) + release_version_type = d['release_version_type'] + pre_release_version = d['pre_release_version'] + if pre_release_version and release_version_type: + final_version += release_version_type + pre_release_version + if release_version_type.startswith("comm"): + final_version += "." + release_version_type + + # Add the current timestamp to the version number, to suggest it + # is a development snapshot build. + if OPTION["SNAPSHOT_BUILD"]: + final_version += ".dev{}".format(get_package_timestamp()) + return final_version + + +def macos_qt_min_deployment_target(): + target = QtInfo().macos_min_deployment_target + + if not target: + raise DistutilsSetupError("Failed to query for Qt's QMAKE_MACOSX_DEPLOYMENT_TARGET.") + return target + + +@memoize +def macos_pyside_min_deployment_target(): + """ + Compute and validate PySide2 MACOSX_DEPLOYMENT_TARGET value. + Candidate sources that are considered: + - setup.py provided value + - maximum value between minimum deployment target of the + Python interpreter and the minimum deployment target of + the Qt libraries. + If setup.py value is provided, that takes precedence. + Otherwise use the maximum of the above mentioned two values. + """ + python_target = get_config_var('MACOSX_DEPLOYMENT_TARGET') or None + qt_target = macos_qt_min_deployment_target() + setup_target = OPTION["MACOS_DEPLOYMENT_TARGET"] + + qt_target_split = [int(x) for x in qt_target.split('.')] + if python_target: + python_target_split = [int(x) for x in python_target.split('.')] + if setup_target: + setup_target_split = [int(x) for x in setup_target.split('.')] + + message = ("Can't set MACOSX_DEPLOYMENT_TARGET value to {} because " + "{} was built with minimum deployment target set to {}.") + # setup.py provided OPTION["MACOS_DEPLOYMENT_TARGET"] value takes + # precedence. + if setup_target: + if python_target and setup_target_split < python_target_split: + raise DistutilsSetupError(message.format(setup_target, "Python", + python_target)) + if setup_target_split < qt_target_split: + raise DistutilsSetupError(message.format(setup_target, "Qt", + qt_target)) + # All checks clear, use setup.py provided value. + return setup_target + + # Setup.py value not provided, + # use same value as provided by Qt. + if python_target: + maximum_target = '.'.join([str(e) for e in max(python_target_split, qt_target_split)]) + else: + maximum_target = qt_target + return maximum_target + + +@memoize +def macos_plat_name(): + deployment_target = macos_pyside_min_deployment_target() + # Example triple "macosx-10.12-x86_64". + plat = get_platform().split("-") + plat_name = "{}-{}-{}".format(plat[0], deployment_target, plat[2]) + return plat_name -- cgit v1.2.3