diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-10-08 14:21:19 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-10-08 14:21:19 +0200 |
commit | 00fa3966dbed373e341710f1145fd23a88f1bdb0 (patch) | |
tree | 331be762988f22221b40ed93486b9b05b657f0bd | |
parent | e801fdab20ad4f5f47deaf49600af0d5f02ecc51 (diff) | |
parent | 2ed45ce8991408de91d7e02a2b80a09a2d9e5083 (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: I30aaad19852c50b1222222ba66171f9c98ecb7c8
20 files changed, 452 insertions, 371 deletions
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/config.py b/build_scripts/config.py index 0a6c3bbb2..86482a043 100644 --- a/build_scripts/config.py +++ b/build_scripts/config.py @@ -137,7 +137,6 @@ class Config(object): setup_kwargs['version'] = package_version setup_kwargs['python_requires'] = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.10" - if quiet: # Tells distutils / setuptools to be quiet, and only print warnings or errors. # Makes way less noise in the terminal when building. diff --git a/build_scripts/main.py b/build_scripts/main.py index c0fa16a51..8429c1fdb 100644 --- a/build_scripts/main.py +++ b/build_scripts/main.py @@ -41,10 +41,17 @@ from __future__ import print_function from distutils.version import LooseVersion import os +import platform +import re +import sys +from textwrap import dedent 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 +64,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 @@ -101,16 +77,162 @@ def get_setuptools_extension_modules(): return extension_modules +def _get_make(platform_arch, build_type): + """Helper for retrieving the make command and CMake generator name""" + makespec = OPTION["MAKESPEC"] + if makespec == "make": + return ("make", "Unix Makefiles") + if makespec == "msvc": + nmake_path = find_executable("nmake") + if nmake_path is None or not os.path.exists(nmake_path): + log.info("nmake not found. Trying to initialize the MSVC env...") + init_msvc_env(platform_arch, build_type) + nmake_path = find_executable("nmake") + if not nmake_path or not os.path.exists(nmake_path): + raise DistutilsSetupError('"nmake" could not be found.') + if not OPTION["NO_JOM"]: + jom_path = find_executable("jom") + if jom_path: + log.info("jom was found in {}".format(jom_path)) + return (jom_path, "NMake Makefiles JOM") + log.info("nmake was found in {}".format(nmake_path)) + if OPTION["JOBS"]: + msg = "Option --jobs can only be used with 'jom' on Windows." + raise DistutilsSetupError(msg) + return (nmake_path, "NMake Makefiles") + if makespec == "mingw": + return ("mingw32-make", "mingw32-make") + if makespec == "ninja": + return ("ninja", "Ninja") + m = 'Invalid option --make-spec "{}".'.format(makespec) + raise DistutilsSetupError(m) + + +def get_make(platform_arch, build_type): + """Retrieve the make command and CMake generator name""" + (make_path, make_generator) = _get_make(platform_arch, build_type) + if not os.path.isabs(make_path): + make_path = find_executable(make_path) + if not make_path or not os.path.exists(make_path): + raise DistutilsSetupError("You need the program '{}' on your system path to " + "compile PySide2.".format(make_path)) + return (make_path, make_generator) + + +def _get_py_library_win(build_type, py_version, py_prefix, py_libdir, + py_include_dir): + """Helper for finding the Python library on Windows""" + if py_include_dir is None or not os.path.exists(py_include_dir): + py_include_dir = os.path.join(py_prefix, "include") + if py_libdir is None or not os.path.exists(py_libdir): + # For virtual environments on Windows, the py_prefix will contain a + # path pointing to it, instead of the system Python installation path. + # Since INCLUDEPY contains a path to the system location, we use the + # same base directory to define the py_libdir variable. + py_libdir = os.path.join(os.path.dirname(py_include_dir), "libs") + if not os.path.isdir(py_libdir): + raise DistutilsSetupError("Failed to locate the 'libs' directory") + dbg_postfix = "_d" if build_type == "Debug" else "" + if OPTION["MAKESPEC"] == "mingw": + static_lib_name = "libpython{}{}.a".format( + py_version.replace(".", ""), dbg_postfix) + return os.path.join(py_libdir, static_lib_name) + v = py_version.replace(".", "") + python_lib_name = "python{}{}.lib".format(v, dbg_postfix) + return os.path.join(py_libdir, python_lib_name) + + +def _get_py_library_unix(build_type, py_version, py_prefix, py_libdir, + py_include_dir): + """Helper for finding the Python library on UNIX""" + if py_libdir is None or not os.path.exists(py_libdir): + py_libdir = os.path.join(py_prefix, "lib") + if py_include_dir is None or not os.path.exists(py_include_dir): + dir = "include/python{}".format(py_version) + py_include_dir = os.path.join(py_prefix, dir) + dbg_postfix = "_d" if build_type == "Debug" else "" + lib_exts = ['.so'] + if sys.platform == 'darwin': + lib_exts.append('.dylib') + if sys.version_info[0] > 2: + lib_suff = getattr(sys, 'abiflags', None) + else: # Python 2 + lib_suff = '' + lib_exts.append('.so.1') + # Suffix for OpenSuSE 13.01 + lib_exts.append('.so.1.0') + # static library as last gasp + lib_exts.append('.a') + + if sys.version_info[0] == 2 and dbg_postfix: + # For Python2 add a duplicate set of extensions combined with the + # dbg_postfix, so we test for both the debug version of the lib + # and the normal one. This allows a debug PySide2 to be built with a + # non-debug Python. + lib_exts = [dbg_postfix + e for e in lib_exts] + lib_exts + + libs_tried = [] + for lib_ext in lib_exts: + lib_name = "libpython{}{}{}".format(py_version, lib_suff, lib_ext) + py_library = os.path.join(py_libdir, lib_name) + if os.path.exists(py_library): + return py_library + libs_tried.append(py_library) + # At least on macOS 10.11, the system Python 2.6 does not include a + # symlink to the framework file disguised as a .dylib file, thus finding + # the library would fail. Manually check if a framework file "Python" + # exists in the Python framework bundle. + if sys.platform == 'darwin' and sys.version_info[:2] == (2, 6): + # These manipulations essentially transform + # /System/Library/Frameworks/Python.framework/Versions/2.6/lib + # to + # /System/Library/Frameworks/Python.framework/Versions/2.6/Python + possible_framework_path = os.path.realpath(os.path.join(py_libdir, '..')) + possible_framework_version = os.path.basename(possible_framework_path) + possible_framework_library = os.path.join(possible_framework_path, 'Python') + + if (possible_framework_version == '2.6' + and os.path.exists(possible_framework_library)): + return possible_framework_library + libs_tried.append(possible_framework_library) + + # Try to find shared libraries which have a multi arch + # suffix. + py_multiarch = get_config_var("MULTIARCH") + if py_multiarch: + try_py_libdir = os.path.join(py_libdir, py_multiarch) + libs_tried = [] + for lib_ext in lib_exts: + lib_name = "libpython{}{}{}".format(py_version, lib_suff, lib_ext) + py_library = os.path.join(try_py_libdir, lib_name) + if os.path.exists(py_library): + return py_library + libs_tried.append(py_library) + + m = "Failed to locate the Python library with {}".format(", ".join(libs_tried)) + raise DistutilsSetupError(m) + + +def get_py_library(build_type, py_version, py_prefix, py_libdir, py_include_dir): + """Find the Python library""" + if sys.platform == "win32": + py_library = _get_py_library_win(build_type, py_version, py_prefix, + py_libdir, py_include_dir) + else: + py_library = _get_py_library_unix(build_type, py_version, py_prefix, + py_libdir, py_include_dir) + if py_library.endswith('.a'): + # Python was compiled as a static library + log.error("Failed to locate a dynamic Python library, using {}".format(py_library)) + return py_library + + try: import setuptools except ImportError: from ez_setup import use_setuptools use_setuptools() -import sys -import platform -import re - import distutils.log as log from distutils.errors import DistutilsSetupError from distutils.sysconfig import get_config_var @@ -137,8 +259,6 @@ from .platforms.unix import prepare_packages_posix from .platforms.windows_desktop import prepare_packages_win32 from .wheel_override import wheel_module_exists, get_bdist_wheel_override -from textwrap import dedent - def check_allowed_python_version(): """ @@ -243,21 +363,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(): # Clean up temp build folder. for n in ["build"]: @@ -374,7 +479,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. @@ -421,49 +526,7 @@ class PysideBuild(_build): make_path = None make_generator = None if not OPTION["ONLYPACKAGE"]: - if OPTION["MAKESPEC"] == "make": - make_name = "make" - make_generator = "Unix Makefiles" - elif OPTION["MAKESPEC"] == "msvc": - nmake_path = find_executable("nmake") - if nmake_path is None or not os.path.exists(nmake_path): - log.info("nmake not found. Trying to initialize the MSVC env...") - init_msvc_env(platform_arch, build_type) - nmake_path = find_executable("nmake") - assert(nmake_path is not None and os.path.exists(nmake_path)) - jom_path = None if OPTION["NO_JOM"] else find_executable("jom") - if jom_path is not None and os.path.exists(jom_path): - log.info("jom was found in {}".format(jom_path)) - make_name = "jom" - make_generator = "NMake Makefiles JOM" - else: - log.info("nmake was found in {}".format(nmake_path)) - make_name = "nmake" - make_generator = "NMake Makefiles" - if OPTION["JOBS"]: - msg = "Option --jobs can only be used with 'jom' on Windows." - raise DistutilsSetupError(msg) - elif OPTION["MAKESPEC"] == "mingw": - make_name = "mingw32-make" - make_generator = "MinGW Makefiles" - elif OPTION["MAKESPEC"] == "ninja": - make_name = "ninja" - make_generator = "Ninja" - else: - raise DistutilsSetupError("Invalid option --make-spec.") - make_path = find_executable(make_name) - if make_path is None or not os.path.exists(make_path): - raise DistutilsSetupError("You need the program '{}' on your system path to " - "compile PySide2.".format(make_name)) - - if OPTION["CMAKE"] is None or not os.path.exists(OPTION["CMAKE"]): - raise DistutilsSetupError("Failed to find cmake." - " Please specify the path to cmake with " - "--cmake parameter.") - - if OPTION["QMAKE"] is None or not os.path.exists(OPTION["QMAKE"]): - raise DistutilsSetupError("Failed to find qmake. " - "Please specify the path to qmake with --qmake parameter.") + (make_path, make_generator) = get_make(platform_arch, build_type) # Prepare parameters py_executable = sys.executable @@ -479,111 +542,6 @@ class PysideBuild(_build): else: py_scripts_dir = os.path.join(py_prefix, "bin") self.py_scripts_dir = py_scripts_dir - if py_libdir is None or not os.path.exists(py_libdir): - if sys.platform == "win32": - # For virtual environments on Windows, the py_prefix will contain a path pointing - # to it, instead of the system Python installation path. - # Since INCLUDEPY contains a path to the system location, we use the same base - # directory to define the py_libdir variable. - py_libdir = os.path.join(os.path.dirname(py_include_dir), "libs") - if not os.path.isdir(py_libdir): - raise DistutilsSetupError("Failed to locate the 'libs' directory") - else: - py_libdir = os.path.join(py_prefix, "lib") - if py_include_dir is None or not os.path.exists(py_include_dir): - if sys.platform == "win32": - py_include_dir = os.path.join(py_prefix, "include") - else: - py_include_dir = os.path.join(py_prefix, "include/python{}".format(py_version)) - dbg_postfix = "" - if build_type == "Debug": - dbg_postfix = "_d" - if sys.platform == "win32": - if OPTION["MAKESPEC"] == "mingw": - static_lib_name = "libpython{}{}.a".format( - py_version.replace(".", ""), dbg_postfix) - py_library = os.path.join(py_libdir, static_lib_name) - else: - python_lib_name = "python{}{}.lib".format( - py_version.replace(".", ""), dbg_postfix) - py_library = os.path.join(py_libdir, python_lib_name) - else: - lib_exts = ['.so'] - if sys.platform == 'darwin': - lib_exts.append('.dylib') - if sys.version_info[0] > 2: - lib_suff = getattr(sys, 'abiflags', None) - else: # Python 2 - lib_suff = '' - lib_exts.append('.so.1') - # Suffix for OpenSuSE 13.01 - lib_exts.append('.so.1.0') - # static library as last gasp - lib_exts.append('.a') - - if sys.version_info[0] == 2 and dbg_postfix: - # For Python2 add a duplicate set of extensions - # combined with the dbg_postfix, so we test for both the - # debug version of the lib and the normal one. - # This allows a debug PySide2 to be built with a - # non-debug Python. - lib_exts = [dbg_postfix + e for e in lib_exts] + lib_exts - - python_library_found = False - libs_tried = [] - for lib_ext in lib_exts: - lib_name = "libpython{}{}{}".format(py_version, lib_suff, lib_ext) - py_library = os.path.join(py_libdir, lib_name) - if os.path.exists(py_library): - python_library_found = True - break - libs_tried.append(py_library) - else: - # At least on macOS 10.11, the system Python 2.6 does - # not include a symlink to the framework file disguised - # as a .dylib file, thus finding the library would - # fail. - # Manually check if a framework file "Python" exists in - # the Python framework bundle. - if sys.platform == 'darwin' and sys.version_info[:2] == (2, 6): - # These manipulations essentially transform - # /System/Library/Frameworks/Python.framework/Versions/2.6/lib - # to - # /System/Library/Frameworks/Python.framework/Versions/2.6/Python - possible_framework_path = os.path.realpath(os.path.join(py_libdir, '..')) - possible_framework_version = os.path.basename(possible_framework_path) - possible_framework_library = os.path.join(possible_framework_path, 'Python') - - if (possible_framework_version == '2.6' - and os.path.exists(possible_framework_library)): - py_library = possible_framework_library - python_library_found = True - else: - libs_tried.append(possible_framework_library) - - # Try to find shared libraries which have a multi arch - # suffix. - if not python_library_found: - py_multiarch = get_config_var("MULTIARCH") - if py_multiarch and not python_library_found: - try_py_libdir = os.path.join(py_libdir, py_multiarch) - libs_tried = [] - for lib_ext in lib_exts: - lib_name = "libpython{}{}{}".format(py_version, lib_suff, lib_ext) - py_library = os.path.join(try_py_libdir, lib_name) - if os.path.exists(py_library): - py_libdir = try_py_libdir - python_library_found = True - break - libs_tried.append(py_library) - - if not python_library_found: - raise DistutilsSetupError( - "Failed to locate the Python library with {}".format(", ".join(libs_tried))) - - if py_library.endswith('.a'): - # Python was compiled as a static library - log.error("Failed to locate a dynamic Python library, using {}".format(py_library)) self.qtinfo = qtinfo qt_dir = os.path.dirname(OPTION["QMAKE"]) @@ -633,7 +591,8 @@ class PysideBuild(_build): self.install_dir = install_dir self.py_executable = py_executable self.py_include_dir = py_include_dir - self.py_library = py_library + self.py_library = get_py_library(build_type, py_version, py_prefix, + py_libdir, py_include_dir) self.py_version = py_version self.build_type = build_type self.site_packages_dir = get_python_lib(1, 0, prefix=install_dir) @@ -743,74 +702,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 @@ -1004,7 +901,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 @@ -1268,9 +1165,11 @@ class PysideBuild(_build): log.info("Patched rpath to '$ORIGIN/' (Linux) or " "updated rpath (OS/X) in {}.".format(srcpath)) + class PysideRstDocs(Command): description = "Build .rst documentation only" user_options = [] + def initialize_options(self): log.info("-- This build process will not include the API documentation." "API documentation requires a full build of pyside/shiboken.") @@ -1331,12 +1230,8 @@ class PysideRstDocs(Command): elif self.name == "shiboken2": self.sphinx_src = self.out_dir - sphinx_cmd = ["sphinx-build", - "-b", "html", - "-c", self.sphinx_src, - self.doc_dir, - self.out_dir - ] + sphinx_cmd = ["sphinx-build", "-b", "html", "-c", self.sphinx_src, + self.doc_dir, self.out_dir] if run_process(sphinx_cmd) != 0: raise DistutilsSetupError("Error running CMake for {}".format(self.doc_dir)) # Last message @@ -1346,6 +1241,7 @@ class PysideRstDocs(Command): def finalize_options(self): pass + cmd_class_dict = { 'build': PysideBuild, 'build_py': PysideBuildPy, @@ -1357,11 +1253,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/qp5_tool.py b/build_scripts/qp5_tool.py index 1358b21c2..b213948e7 100644 --- a/build_scripts/qp5_tool.py +++ b/build_scripts/qp5_tool.py @@ -390,7 +390,7 @@ if __name__ == '__main__': build_mode = BuildMode.RECONFIGURE if build_mode == BuildMode.NONE and not (options.clean or options.reset - or options.pull or options.test): + or options.pull or options.test): argument_parser.print_help() sys.exit(0) diff --git a/build_scripts/qtinfo.py b/build_scripts/qtinfo.py index fa2d771b2..62bfee812 100644 --- a/build_scripts/qtinfo.py +++ b/build_scripts/qtinfo.py @@ -125,7 +125,7 @@ class QtInfo(object): return self.get_property("QT_INSTALL_PREFIX/src") def get_property(self, prop_name): - if not self._query_dict: + if not self._query_dict: self._get_query_properties() self._get_other_properties() if prop_name not in self._query_dict: diff --git a/build_scripts/setup_runner.py b/build_scripts/setup_runner.py index 15a0bf380..b54c62796 100644 --- a/build_scripts/setup_runner.py +++ b/build_scripts/setup_runner.py @@ -54,6 +54,7 @@ from setuptools import setup if OPTION["VERBOSE_BUILD"]: log.set_verbosity(1) + class SetupRunner(object): def __init__(self, orig_argv): self.invocations_list = [] diff --git a/build_scripts/utils.py b/build_scripts/utils.py index ad17a7ba8..220d32efe 100644 --- a/build_scripts/utils.py +++ b/build_scripts/utils.py @@ -1081,18 +1081,20 @@ def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch): # With windows we are creating building 32-bit target in 64-bit host if hostArch == "X86_64" and targetArch == "X86": if python_ver.startswith("3"): - print("Try to find python from {} env variable".format("PYTHON"+python_ver+"-32_PATH")) - _path = os.getenv("PYTHON"+python_ver+"-32_PATH", "") + var = "PYTHON" + python_ver + "-32_PATH" + print("Try to find python from {} env variable".format(var)) + _path = os.getenv(var, "") _pExe = os.path.join(_path, "python.exe") if not os.path.isfile(_pExe): print("Can't find python.exe from {}, using default python3".format(_pExe)) _pExe = os.path.join(os.getenv("PYTHON3_32_PATH"), "python.exe") else: - _pExe = os.path.join(os.getenv("PYTHON2_32_PATH"), "python.exe") + _pExe = os.path.join(os.getenv("PYTHON2_32_PATH"), "python.exe") else: - if python_ver.startswith("3"): - print("Try to find python from {} env variable".format("PYTHON"+python_ver+"-64_PATH")) - _path = os.getenv("PYTHON"+python_ver+"-64_PATH", "") + if python_ver.startswith("3"): + var = "PYTHON" + python_ver + "-64_PATH" + print("Try to find python from {} env variable".format(var)) + _path = os.getenv(var, "") _pExe = os.path.join(_path, "python.exe") if not os.path.isfile(_pExe): print("Can't find python.exe from {}, using default python3".format(_pExe)) @@ -1137,6 +1139,6 @@ def get_ci_qmake_path(ci_install_dir, ci_host_os): if ci_host_os == "MacOS": return qmake_path + "/bin/qmake" elif ci_host_os == "Windows": - return qmake_path + "\\bin\\qmake.exe" + return qmake_path + "\\bin\\qmake.exe" else: return qmake_path + "/bin/qmake" 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 diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index d06a338a3..70cccebcd 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -175,12 +175,12 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() const TypeEntry *entry = it.value(); if (!entry) continue; - if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing) + if (!entry->isComplex() || !entry->generateCode()) continue; auto centry = static_cast<const ComplexTypeEntry *>(entry); - if (!(centry->codeGeneration() & TypeEntry::GenerateTargetLang)) + if (!centry->generateCode()) continue; FunctionModificationList modifications = centry->functionModifications(); @@ -290,7 +290,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte if (arguments.size() == 1) { unaryOperator = true; } else if (!baseoperandClass - || !(baseoperandClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) { + || !baseoperandClass->typeEntry()->generateCode()) { baseoperandClass = argumentToClass(arguments.at(1), currentClass); firstArgumentIsSelf = false; } else { @@ -551,7 +551,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) && !types->shouldDropTypeEntry(entry->qualifiedCppName()) && !entry->isContainer() && !entry->isCustom() - && (entry->generateCode() & TypeEntry::GenerateTargetLang) + && entry->generateCode() && !AbstractMetaClass::findClass(m_metaClasses, entry)) { qCWarning(lcShiboken, "%s", qPrintable(msgTypeNotDefined(entry))); } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) { @@ -570,7 +570,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) qPrintable(msgGlobalFunctionNotDefined(fte, signature))); } } - } else if (entry->isEnum() && (entry->generateCode() & TypeEntry::GenerateTargetLang)) { + } else if (entry->isEnum() && entry->generateCode()) { auto enumEntry = static_cast<const EnumTypeEntry *>(entry); const QString name = enumEntry->targetLangQualifier(); AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name); @@ -855,8 +855,7 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & return nullptr; } - const bool rejectionWarning = !enclosing - || (enclosing->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang); + const bool rejectionWarning = !enclosing || enclosing->typeEntry()->generateCode(); if (!typeEntry) { if (rejectionWarning) @@ -1185,7 +1184,7 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModel if (!metaType) { const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon()); - if (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang) { + if (cls->typeEntry()->generateCode()) { qCWarning(lcShiboken, "%s", qPrintable(msgSkippingField(field, cls->name(), type))); } @@ -1865,9 +1864,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio // unless the function is virtual (since the override in the // wrapper can then not correctly be generated). if (arg->defaultValue() && !functionItem->isVirtual()) { - if (!currentClass - || (currentClass->typeEntry()->codeGeneration() - & TypeEntry::GenerateTargetLang)) { + if (!currentClass || currentClass->typeEntry()->generateCode()) { qCWarning(lcShiboken, "%s", qPrintable(msgStrippingArgument(functionItem, i, originalQualifiedSignatureWithReturn, arg))); } diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp index 87f5c49df..0d5a8cba7 100644 --- a/sources/shiboken2/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp @@ -432,7 +432,7 @@ ConstantValueTypeEntry * const TypeEntry *parent) { auto result = new ConstantValueTypeEntry(value, parent); - result->setCodeGeneration(0); + result->setCodeGeneration(TypeEntry::GenerateNothing); addType(result); return result; } diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 00f56c51e..d3ef2c629 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -598,13 +598,10 @@ public: Q_ENUM(Type) enum CodeGeneration { - GenerateTargetLang = 0x0001, - GenerateCpp = 0x0002, - GenerateForSubclass = 0x0004, - - GenerateNothing = 0, - GenerateAll = 0xffff, - GenerateCode = GenerateTargetLang | GenerateCpp + GenerateNothing, // Rejection, private type, ConstantValueTypeEntry or similar + GenerationDisabled, // generate='no' in type system + GenerateCode, // Generate code + GenerateForSubclass, // Inherited from a loaded dependent type system. }; Q_ENUM(CodeGeneration) @@ -703,11 +700,11 @@ public: // Name as specified in XML QString entryName() const { return m_entryName; } - uint codeGeneration() const + CodeGeneration codeGeneration() const { return m_codeGeneration; } - void setCodeGeneration(uint cg) + void setCodeGeneration(CodeGeneration cg) { m_codeGeneration = cg; } @@ -719,8 +716,7 @@ public: // on 'load-typesystem' tag inline bool generateCode() const { - return m_codeGeneration != TypeEntry::GenerateForSubclass - && m_codeGeneration != TypeEntry::GenerateNothing; + return m_codeGeneration == GenerateCode; } int revision() const { return m_revision; } @@ -804,7 +800,7 @@ public: return m_docModifications; } - IncludeList extraIncludes() const + const IncludeList &extraIncludes() const { return m_extraIncludes; } @@ -903,7 +899,7 @@ private: QVersionNumber m_version; CustomConversion *m_customConversion = nullptr; SourceLocation m_sourceLocation; // XML file - uint m_codeGeneration = GenerateAll; + CodeGeneration m_codeGeneration = GenerateCode; TypeEntry *m_viewOn = nullptr; int m_revision = 0; int m_sbkIndex = 0; diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp index 7323e01f6..9ad9322b2 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp @@ -505,7 +505,7 @@ QString TypeSystemEntityResolver::resolveUndeclaredEntity(const QString &name) TypeSystemParser::TypeSystemParser(TypeDatabase *database, bool generate) : m_database(database), - m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) + m_generate(generate ? TypeEntry::GenerateCode : TypeEntry::GenerateForSubclass) { } @@ -775,7 +775,7 @@ bool TypeSystemParser::endElement(QStringView localName) switch (m_current->type) { case StackElement::Root: - if (m_generate == TypeEntry::GenerateAll) { + if (m_generate == TypeEntry::GenerateCode) { TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions); TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods); for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) { @@ -790,13 +790,26 @@ bool TypeSystemParser::endElement(QStringView localName) case StackElement::InterfaceTypeEntry: case StackElement::NamespaceTypeEntry: { auto *centry = static_cast<ComplexTypeEntry *>(m_current->entry); - centry->setAddedFunctions(m_contextStack.top()->addedFunctions); - centry->setFunctionModifications(m_contextStack.top()->functionMods); - centry->setFieldModifications(m_contextStack.top()->fieldMods); - centry->setCodeSnips(m_contextStack.top()->codeSnips); - centry->setDocModification(m_contextStack.top()->docModifications); + auto top = m_contextStack.top(); + centry->setAddedFunctions(top->addedFunctions); + centry->setFunctionModifications(top->functionMods); + centry->setFieldModifications(top->fieldMods); + centry->setCodeSnips(top->codeSnips); + centry->setDocModification(top->docModifications); } break; + + case StackElement::TypedefTypeEntry: { + auto *centry = static_cast<TypedefEntry *>(m_current->entry)->target(); + auto top = m_contextStack.top(); + centry->setAddedFunctions(centry->addedFunctions() + top->addedFunctions); + centry->setFunctionModifications(centry->functionModifications() + top->functionMods); + centry->setFieldModifications(centry->fieldModifications() + top->fieldMods); + centry->setCodeSnips(centry->codeSnips() + top->codeSnips); + centry->setDocModification(centry->docModifications() + top->docModifications); + } + break; + case StackElement::AddFunction: { // Leaving add-function: Assign all modifications to the added function StackElementContext *top = m_contextStack.top(); @@ -1576,7 +1589,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const QXmlStreamReader &reader if (generate) ctype->setCodeGeneration(m_generate); else - ctype->setCodeGeneration(TypeEntry::GenerateForSubclass); + ctype->setCodeGeneration(TypeEntry::GenerationDisabled); } bool TypeSystemParser::parseRenameFunction(const QXmlStreamReader &, @@ -1760,7 +1773,7 @@ bool TypeSystemParser::loadTypesystem(const QXmlStreamReader &, } const bool result = m_database->parseFile(typeSystemName, m_currentPath, generateChild - && m_generate == TypeEntry::GenerateAll); + && m_generate == TypeEntry::GenerateCode); if (!result) m_error = QStringLiteral("Failed to parse: '%1'").arg(typeSystemName); return result; @@ -2779,7 +2792,7 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) auto *element = new StackElement(m_current); element->type = elementType; - if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateAll) + if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateCode) customConversionsForReview.clear(); if (element->type == StackElement::CustomMetaConstructor diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp index 487715a3c..445743a74 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -502,8 +502,7 @@ bool Generator::generate() bool Generator::shouldGenerateTypeEntry(const TypeEntry *type) const { - return (type->codeGeneration() & TypeEntry::GenerateTargetLang) - && NamespaceTypeEntry::isVisibleScope(type); + return type->generateCode() && NamespaceTypeEntry::isVisibleScope(type); } bool Generator::shouldGenerate(const AbstractMetaClass *metaClass) const diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 18137a985..a6e9a00b6 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -393,14 +393,18 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums); //Extra includes - s << "\n// Extra includes\n"; - QVector<Include> includes = metaClass->typeEntry()->extraIncludes(); + QVector<Include> includes; + if (!classContext.useWrapper()) + includes += metaClass->typeEntry()->extraIncludes(); for (AbstractMetaEnum *cppEnum : qAsConst(classEnums)) includes.append(cppEnum->typeEntry()->extraIncludes()); - std::sort(includes.begin(), includes.end()); - for (const Include &inc : qAsConst(includes)) - s << inc.toString() << Qt::endl; - s << Qt::endl; + if (!includes.isEmpty()) { + s << "\n// Extra includes\n"; + std::sort(includes.begin(), includes.end()); + for (const Include &inc : qAsConst(includes)) + s << inc.toString() << Qt::endl; + s << '\n'; + } s << "\n#include <cctype>\n#include <cstring>\n"; @@ -5234,9 +5238,16 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "0,\n"; } - // 6:baseType - const auto base = metaClass->isNamespace() + // 6:baseType: Find a type that is not disabled. + auto base = metaClass->isNamespace() ? metaClass->extendedNamespace() : metaClass->baseClass(); + if (!metaClass->isNamespace()) { + for (; base != nullptr; base = base->baseClass()) { + const auto ct = base->typeEntry()->codeGeneration(); + if (ct == TypeEntry::GenerateCode || ct == TypeEntry::GenerateForSubclass) + break; + } + } if (base) { s << INDENT << "reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(base->typeEntry()) << "),\n"; diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp index 1d3a20447..1ba846d87 100644 --- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp @@ -119,7 +119,13 @@ void HeaderGenerator::generateClass(QTextStream &s, const GeneratorContext &clas s << "#define protected public\n\n"; //Includes - s << metaClass->typeEntry()->include() << Qt::endl; + auto typeEntry = metaClass->typeEntry(); + s << typeEntry->include() << '\n'; + if (classContext.useWrapper() && !typeEntry->extraIncludes().isEmpty()) { + s << "\n// Extra includes\n"; + for (const Include &inc : typeEntry->extraIncludes()) + s << inc.toString() << '\n'; + } if (classContext.useWrapper() && usePySideExtensions() && metaClass->isQObject()) s << "namespace PySide { class DynamicQMetaObject; }\n\n"; diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index a6a175999..7b8f2c7e4 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -929,7 +929,7 @@ QString ShibokenGenerator::fixedCppTypeName(const TypeEntry *type, QString typeN { if (typeName.isEmpty()) typeName = type->qualifiedCppName(); - if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang)) { + if (!type->generateCode()) { typeName.prepend(QLatin1Char('_')); typeName.prepend(type->targetLangPackage()); } @@ -1609,8 +1609,7 @@ ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverter // Get only the conversion operators that return a type from another module, // that are value-types and were not removed in the type system. const TypeEntry *convType = convOp->type()->typeEntry(); - if ((convType->codeGeneration() & TypeEntry::GenerateTargetLang) - || !convType->isValue() + if (convType->generateCode() || !convType->isValue() || convOp->isModifiedRemoved()) continue; extConvs[convType].append(convOp->ownerClass()); diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp index fff9d05ec..ca32f5919 100644 --- a/sources/shiboken2/libshiboken/sbkstring.cpp +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -42,6 +42,7 @@ #include "autodecref.h" #include <vector> +#include <unordered_set> namespace Shiboken { @@ -183,7 +184,7 @@ Py_ssize_t len(PyObject *str) // PyObject *attr = PyObject_GetAttr(obj, name()); // -using StaticStrings = std::vector<PyObject *>; +using StaticStrings = std::unordered_set<PyObject *>; static void finalizeStaticStrings(); // forward @@ -195,10 +196,12 @@ static StaticStrings &staticStrings() static void finalizeStaticStrings() { - auto &list = staticStrings(); - for (PyObject *ob : list) + auto &set = staticStrings(); + for (PyObject *ob : set) { + Py_REFCNT(ob) = 1; Py_DECREF(ob); - list.clear(); + } + set.clear(); } PyObject *createStaticString(const char *str) @@ -218,7 +221,16 @@ PyObject *createStaticString(const char *str) PyErr_Print(); Py_FatalError("unexpected error in createStaticString()"); } - staticStrings().push_back(result); + auto it = staticStrings().find(result); + if (it == staticStrings().end()) + staticStrings().insert(result); + /* + * Note: We always add one reference even if we have a new string. + * This makes the strings immortal, and we are safe if someone + * uses AutoDecRef, although the set cannot cope with deletions. + * The exit handler cleans that up, anyway. + */ + Py_INCREF(result); return result; } diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py index 64f654d30..ece3d2edb 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/__feature__.py @@ -104,7 +104,9 @@ Note: This are two imports. # XXX build an improved C version? I guess not. def _import(name, *args, **kwargs): # PYSIDE-1368: The `__name__` attribute does not need to exist in all modules. - importing_module = sys._getframe(1).f_globals.get("__name__", "__main__") + # PYSIDE-1398: sys._getframe(1) may not exist when embedding. + calling_frame = _cf = sys._getframe().f_back + importing_module = _cf.f_globals.get("__name__", "__main__") if _cf else "__main__" existing = pyside_feature_dict.get(importing_module, 0) if name == "__feature__" and args[2]: diff --git a/testing/wheel_tester.py b/testing/wheel_tester.py index 147becdf7..100fd18f7 100644 --- a/testing/wheel_tester.py +++ b/testing/wheel_tester.py @@ -65,8 +65,6 @@ this_dir = os.path.dirname(this_file) setup_script_dir = os.path.abspath(os.path.join(this_dir, '..')) sys.path.append(setup_script_dir) -from build_scripts.options import OPTION - from build_scripts.utils import find_files_using_glob from build_scripts.utils import find_glob_in_path from build_scripts.utils import run_process, run_process_output @@ -77,14 +75,6 @@ import platform log.set_verbosity(1) -def find_executable_qmake(): - return find_executable('qmake', OPTION["QMAKE"]) - - -def find_executable_cmake(): - return find_executable('cmake', OPTION["CMAKE"]) - - def find_executable(executable, command_line_value): value = command_line_value option_str = '--{}'.format(executable) @@ -108,8 +98,8 @@ def find_executable(executable, command_line_value): return value -QMAKE_PATH = find_executable_qmake() -CMAKE_PATH = find_executable_cmake() +QMAKE_PATH = None +CMAKE_PATH = None def get_wheels_dir(): @@ -351,5 +341,12 @@ if __name__ == "__main__": parser.add_argument('--no-install-wheels', '-n', action='store_true', help='Do not install wheels' ' (for developer builds with virtualenv)') + parser.add_argument("--qmake", type=str, + help="Path to qmake") + parser.add_argument("--cmake", type=str, + help="Path to cmake") options = parser.parse_args() + QMAKE_PATH = find_executable('qmake', options.qmake) + CMAKE_PATH = find_executable('cmake', options.cmake) + run_wheel_tests(not options.no_install_wheels) |