aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2018-10-16 13:26:40 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2018-10-16 13:27:27 +0200
commit7aff06b31b4bd8bb28cfedc0dcafbd1f32324cba (patch)
treedbd9d10d8f67243be79fea6d0e32536b79ba83b9
parent0bb173c96a2be3d10a260bb7f001c7557047d392 (diff)
parent6bfbfd6edd0f9701664698768f9ec8d29f96a5bd (diff)
Merge remote-tracking branch 'origin/5.12' into dev
-rw-r--r--.gitignore3
-rw-r--r--MANIFEST.in40
-rw-r--r--README.md52
-rw-r--r--README.pyside2.md53
-rw-r--r--README.shiboken2-generator.md1
-rw-r--r--README.shiboken2.md1
-rw-r--r--build_scripts/build_scripts.pyqtc5
-rw-r--r--build_scripts/config.py393
-rw-r--r--build_scripts/main.py387
-rw-r--r--build_scripts/options.py78
-rw-r--r--build_scripts/platforms/linux.py136
-rw-r--r--build_scripts/platforms/macos.py119
-rw-r--r--build_scripts/platforms/unix.py261
-rw-r--r--build_scripts/platforms/windows_desktop.py468
-rw-r--r--build_scripts/setup_runner.py165
-rw-r--r--build_scripts/utils.py213
-rw-r--r--coin_build_instructions.py40
-rw-r--r--coin_test_instructions.py17
-rw-r--r--examples/samplebinding/CMakeLists.txt26
-rw-r--r--examples/scriptableapplication/CMakeLists.txt34
-rw-r--r--examples/scriptableapplication/pyside2.pri40
-rw-r--r--examples/scriptableapplication/scriptableapplication.pro4
-rw-r--r--examples/utils/pyside2_config.py319
-rw-r--r--keyword-errors.lst43
-rw-r--r--popenasync.py360
-rw-r--r--setup.py115
-rw-r--r--sources/cmake_helpers/helpers.cmake63
-rw-r--r--sources/pyside2/CMakeLists.txt63
-rw-r--r--sources/pyside2/PySide2/CMakeLists.txt6
-rw-r--r--sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml9
-rw-r--r--sources/pyside2/PySide2/QtQuick/typesystem_quick.xml2
-rw-r--r--sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml2
-rw-r--r--sources/pyside2/PySide2/__init__.py.in20
-rw-r--r--sources/pyside2/PySide2/_config.py.in13
-rw-r--r--sources/pyside2/PySide2/support/signature/__init__.py6
-rw-r--r--sources/pyside2/PySide2/support/signature/fix-complaints.py2
-rw-r--r--sources/pyside2/PySide2/support/signature/layout.py237
-rw-r--r--sources/pyside2/PySide2/support/signature/lib/__init__.py40
-rw-r--r--sources/pyside2/PySide2/support/signature/lib/enum_sig.py113
-rw-r--r--sources/pyside2/PySide2/support/signature/loader.py29
-rw-r--r--sources/pyside2/PySide2/support/signature/mapping.py31
-rw-r--r--sources/pyside2/PySide2/support/signature/parser.py47
-rw-r--r--sources/pyside2/tests/registry/init_platform.py90
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp7
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h2
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.cpp1
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp7
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.h4
-rw-r--r--sources/shiboken2/CMakeLists.txt5
-rw-r--r--sources/shiboken2/generator/CMakeLists.txt30
-rw-r--r--sources/shiboken2/generator/__init__.py.in2
-rw-r--r--sources/shiboken2/generator/_config.py.in9
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp14
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp20
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h3
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp42
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h8
-rw-r--r--sources/shiboken2/libshiboken/basewrapper_p.h1
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.cpp15
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.h5
-rw-r--r--sources/shiboken2/libshiboken/helper.cpp26
-rw-r--r--sources/shiboken2/libshiboken/helper.h4
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp27
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.h8
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp291
-rw-r--r--sources/shiboken2/libshiboken/signature.h6
-rw-r--r--sources/shiboken2/libshiboken/typespec.cpp1
-rwxr-xr-xsources/shiboken2/shiboken_tool.py53
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt22
-rw-r--r--sources/shiboken2/shibokenmodule/__init__.py.in4
-rw-r--r--sources/shiboken2/shibokenmodule/_config.py.in11
-rw-r--r--testing/wheel_tester.py295
72 files changed, 3352 insertions, 1717 deletions
diff --git a/.gitignore b/.gitignore
index 6a8b69288..903fc81f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
/build
/dist
/pyside*_build
-/pyside*_package
/pyside*_install
/PySide
/PySide-*.*.*
@@ -13,3 +12,5 @@ distribute-*.egg
distribute-*.tar.gz
explore2
build_history/2*
+*.qdocconf
+*.qdocconf.in
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index dd79b2380..000000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# MANIFEST.in
-#
-# Manifest template for creating the PySide source distribution.
-
-include MANIFEST.in
-include CHANGES.rst
-include README.rst
-include ez_setup.py
-include setup.py
-include popenasync.py
-include qtinfo.py
-include utils.py
-
-# sources
-recursive-include sources/patchelf **
-recursive-include sources/shiboken2 **
-recursive-include sources/pyside2 **
-recursive-include sources/pyside2-tools **
-# ignore .git
-recursive-exclude sources/shiboken2/.git **
-recursive-exclude sources/pyside2/.git **
-recursive-exclude sources/pyside2-tools/.git **
-
-# PySide package
-recursive-include pyside_package/PySide2 **
-recursive-include pyside_package/PySide2/docs **
-recursive-include pyside_package/PySide2/plugins **
-recursive-include pyside_package/PySide2s **
-recursive-include pyside_package/PySide2/translations **
-recursive-include pyside_package/PySide2include **
-recursive-include pyside_package/PySide2/typesystems **
-recursive-include pyside_package/PySide2/examples **
-
-# pysideuic package
-recursive-include pyside_package/pysideuic **
-recursive-include pyside_package/pysideuic/Compiler **
-recursive-include pyside_package/pysideuic/port_v2 **
-recursive-include pyside_package/pysideuic/port_v3 **
-recursive-include pyside_package/pysideuic/widget-plugins **
diff --git a/README.md b/README.md
index cde05940d..fe61136b2 100644
--- a/README.md
+++ b/README.md
@@ -1,53 +1,9 @@
-# PySide2
+# Qt For Python
-### Introduction
-
-PySide is the [Python Qt bindings project](http://wiki.qt.io/PySide2), providing
+Qt For Python is the [Python Qt bindings project](http://wiki.qt.io/PySide2), providing
access to the complete Qt 5.x framework as well as to generator tools for rapidly
generating bindings for any C++ libraries.
-The PySide project is developed in the open, with all facilities you'd expect
-from any modern OSS project such as all code in a git repository and an open
-design process. We welcome any contribution conforming to the
-[Qt Contribution Agreement](https://www.qt.io/contributionagreement/).
-
-
-PySide 2 supports Qt5. For building, please read about
-[getting started](https://wiki.qt.io/PySide2_GettingStarted).
-Then download the sources by running
-
- git clone https://code.qt.io/pyside/pyside-setup
-
-### Building
-
-#### Dependencies
-
-PySide versions following 5.6 use a C++ parser based on
-[Clang](http://clang.org/). The Clang library (C-bindings), version 3.9 or
-higher is required for building. Prebuilt versions of it can be downloaded from
-[download.qt.io](http://download.qt.io/development_releases/prebuilt/libclang/).
-
-After unpacking the archive, set the environment variable *LLVM_INSTALL_DIR* to
-point to the folder containing the *include* and *lib* directories of Clang:
-
- 7z x .../libclang-release_39-linux-Rhel7.2-gcc5.3-x86_64.7z
- export LLVM_INSTALL_DIR=$PWD/libclang
-
-On Windows:
-
- 7z x .../libclang-release_39-windows-vs2015_64.7z
- SET LLVM_INSTALL_DIR=%CD%\libclang
-
-#### Build Instructions
-
-You might consider using a virtual environment as described at
-[getting started](https://wiki.qt.io/PySide2_GettingStarted).
-You should be able to build:
-
- cd pyside-setup
- python setup.py install
+shiboken2 is the generator used to build the bindings.
-The setup script will try to find the location of the qmake tool of the Qt
-version to be used and the cmake build tool in the path. Non-standard
-locations can be specified by the *--qmake=path_to_qmake* or
-*--cmake=path_to_cmake* command line options.
+See README.pyside2.md and README.shiboken2.md for details.
diff --git a/README.pyside2.md b/README.pyside2.md
new file mode 100644
index 000000000..cde05940d
--- /dev/null
+++ b/README.pyside2.md
@@ -0,0 +1,53 @@
+# PySide2
+
+### Introduction
+
+PySide is the [Python Qt bindings project](http://wiki.qt.io/PySide2), providing
+access to the complete Qt 5.x framework as well as to generator tools for rapidly
+generating bindings for any C++ libraries.
+
+The PySide project is developed in the open, with all facilities you'd expect
+from any modern OSS project such as all code in a git repository and an open
+design process. We welcome any contribution conforming to the
+[Qt Contribution Agreement](https://www.qt.io/contributionagreement/).
+
+
+PySide 2 supports Qt5. For building, please read about
+[getting started](https://wiki.qt.io/PySide2_GettingStarted).
+Then download the sources by running
+
+ git clone https://code.qt.io/pyside/pyside-setup
+
+### Building
+
+#### Dependencies
+
+PySide versions following 5.6 use a C++ parser based on
+[Clang](http://clang.org/). The Clang library (C-bindings), version 3.9 or
+higher is required for building. Prebuilt versions of it can be downloaded from
+[download.qt.io](http://download.qt.io/development_releases/prebuilt/libclang/).
+
+After unpacking the archive, set the environment variable *LLVM_INSTALL_DIR* to
+point to the folder containing the *include* and *lib* directories of Clang:
+
+ 7z x .../libclang-release_39-linux-Rhel7.2-gcc5.3-x86_64.7z
+ export LLVM_INSTALL_DIR=$PWD/libclang
+
+On Windows:
+
+ 7z x .../libclang-release_39-windows-vs2015_64.7z
+ SET LLVM_INSTALL_DIR=%CD%\libclang
+
+#### Build Instructions
+
+You might consider using a virtual environment as described at
+[getting started](https://wiki.qt.io/PySide2_GettingStarted).
+You should be able to build:
+
+ cd pyside-setup
+ python setup.py install
+
+The setup script will try to find the location of the qmake tool of the Qt
+version to be used and the cmake build tool in the path. Non-standard
+locations can be specified by the *--qmake=path_to_qmake* or
+*--cmake=path_to_cmake* command line options.
diff --git a/README.shiboken2-generator.md b/README.shiboken2-generator.md
new file mode 100644
index 000000000..c71c6a8de
--- /dev/null
+++ b/README.shiboken2-generator.md
@@ -0,0 +1 @@
+# shiboken2-generator
diff --git a/README.shiboken2.md b/README.shiboken2.md
new file mode 100644
index 000000000..f98f63c57
--- /dev/null
+++ b/README.shiboken2.md
@@ -0,0 +1 @@
+# shiboken2 module
diff --git a/build_scripts/build_scripts.pyqtc b/build_scripts/build_scripts.pyqtc
index eb4b58a63..1fc1c9664 100644
--- a/build_scripts/build_scripts.pyqtc
+++ b/build_scripts/build_scripts.pyqtc
@@ -1,8 +1,10 @@
__init__.py
+config.py
main.py
options.py
platforms
qtinfo.py
+setup_runner.py
utils.py
wheel_override.py
platforms/__init__.py
@@ -11,3 +13,6 @@ platforms/macos.py
platforms/unix.py
platforms/windows_desktop.py
../setup.py
+../coin_build_instructions.py
+../coin_test_instructions.py
+
diff --git a/build_scripts/config.py b/build_scripts/config.py
new file mode 100644
index 000000000..78d7d4040
--- /dev/null
+++ b/build_scripts/config.py
@@ -0,0 +1,393 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import sys, os
+import distutils.log as log
+
+
+class Config(object):
+ def __init__(self):
+ # Constants
+ self._build_type_all = "all"
+ self._invocation_type_top_level = "top-level"
+ self._invocation_type_internal = "internal"
+
+ # The keyword arguments which will be given to setuptools.setup
+ self.setup_kwargs = {}
+
+ # The setup.py invocation type.
+ # top-level
+ # internal
+ self.invocation_type = None
+
+ # The type of the top-level build.
+ # all - build shiboken2 module, shiboken2-generator and PySide2
+ # modules
+ # shiboken2 - build only shiboken2 module
+ # shiboken2-generator - build only the shiboken2-generator
+ # pyside2 - build only PySide2 modules
+ self.build_type = None
+
+ # The internal build type, used for internal invocations of
+ # setup.py to build a specific module only.
+ self.internal_build_type = None
+
+ # Options that can be given to --build-type and
+ # --internal-build-type
+ self.shiboken_module_option_name = "shiboken2"
+ self.shiboken_generator_option_name = "shiboken2-generator"
+ self.pyside_option_name = "pyside2"
+
+ # Names to be passed to setuptools.setup() name key,
+ # so not package name, but rather project name as it appears
+ # in the wheel name and on PyPi.
+ self.shiboken_module_st_name = "shiboken2"
+ self.shiboken_generator_st_name = "shiboken2-generator"
+ self.pyside_st_name = "PySide2"
+
+ # Used by check_allowed_python_version to validate the
+ # interpreter version.
+ self.python_version_classifiers = [
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ ]
+
+ self.setup_script_dir = None
+
+ def init_config(self, build_type=None, internal_build_type=None,
+ cmd_class_dict=None, package_version=None,
+ ext_modules=None, setup_script_dir=None):
+ """
+ Sets up the global singleton config which is used in many parts
+ of the setup process.
+ """
+
+ # if --internal-build-type was passed, it means that this is a
+ # sub-invocation to build a specific package.
+ if internal_build_type:
+ self.set_is_internal_invocation()
+ self.set_internal_build_type(internal_build_type)
+ else:
+ self.set_is_top_level_invocation()
+
+ # --build-type was specified explicitly, so set it. Otherwise
+ # default to all.
+ if build_type:
+ self.build_type = build_type
+ else:
+ self.build_type = self._build_type_all
+
+ self.setup_script_dir = setup_script_dir
+
+ setup_kwargs = {}
+ setup_kwargs['long_description'] = self.get_long_description()
+ setup_kwargs['long_description_content_type'] = 'text/markdown',
+ setup_kwargs['keywords'] = 'Qt'
+ setup_kwargs['author'] = 'Qt for Python Team'
+ setup_kwargs['author_email'] = 'pyside@qt-project.org'
+ setup_kwargs['url'] = 'https://www.pyside.org'
+ setup_kwargs['download_url'] = 'https://download.qt.io/official_releases/QtForPython'
+ setup_kwargs['license'] = 'LGPL'
+ setup_kwargs['zip_safe'] = False
+ setup_kwargs['cmdclass'] = cmd_class_dict
+ setup_kwargs['version'] = package_version
+
+ # Setting these two keys is still a bit of a discussion point.
+ # In general not setting them will allow using "build" and
+ # "bdist_wheel" just fine. What they do, is they specify to the
+ # setuptools.command.build_py command that certain pure python
+ # modules (.py files) exist in the specified package location,
+ # and that they should be copied over to the setuptools build
+ # dir.
+ # But it doesn't really make sense for us, because we copy all
+ # the necessary files to the build dir via prepare_packages()
+ # function anyway.
+ # If we don't set them, the build_py sub-command will be
+ # skipped, but the build command will still be executed, which
+ # is where we run cmake / make.
+ # The only plausible usage of it, is if we will implement a
+ # correctly functioning setup.py develop command (or bdist_egg).
+ # But currently that doesn't seem to work.
+ setup_kwargs['packages'] = self.get_setup_tools_packages_for_current_build()
+ setup_kwargs['package_dir'] = self.get_package_name_to_dir_path_mapping()
+
+ # Add a bogus extension module (will never be built here since
+ # we are overriding the build command to do it using cmake) so
+ # things like bdist_egg will know that there are extension
+ # modules and will name the dist with the full platform info.
+ setup_kwargs['ext_modules'] = ext_modules
+
+ common_classifiers = [
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Console',
+ 'Environment :: MacOS X',
+ 'Environment :: X11 Applications :: Qt',
+ 'Environment :: Win32 (MS Windows)',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
+ 'Operating System :: MacOS :: MacOS X',
+ 'Operating System :: POSIX',
+ 'Operating System :: POSIX :: Linux',
+ 'Operating System :: Microsoft',
+ 'Operating System :: Microsoft :: Windows',
+ 'Programming Language :: C++']
+ common_classifiers.extend(self.python_version_classifiers)
+ common_classifiers.extend([
+ 'Topic :: Database',
+ 'Topic :: Software Development',
+ 'Topic :: Software Development :: Code Generators',
+ 'Topic :: Software Development :: Libraries :: Application Frameworks',
+ 'Topic :: Software Development :: User Interfaces',
+ 'Topic :: Software Development :: Widget Sets'])
+ setup_kwargs['classifiers'] = common_classifiers
+
+ if self.internal_build_type == self.shiboken_module_option_name:
+ setup_kwargs['name'] = self.shiboken_module_st_name
+ setup_kwargs['description'] = "Python / C++ bindings helper module",
+ setup_kwargs['entry_points'] = {}
+
+ elif self.internal_build_type == self.shiboken_generator_option_name:
+ setup_kwargs['name'] = self.shiboken_generator_st_name
+ setup_kwargs['description'] = "Python / C++ bindings generator",
+ setup_kwargs['install_requires'] = [self.shiboken_module_st_name]
+ setup_kwargs['entry_points'] = {
+ 'console_scripts': [
+ 'shiboken2 = {}.scripts.shiboken_tool:main'.format(self.package_name()),
+ ]
+ }
+
+ elif self.internal_build_type == self.pyside_option_name:
+ setup_kwargs['name'] = self.pyside_st_name
+ setup_kwargs['description'] = ("Python bindings for the Qt cross-platform application"
+ " and UI framework"),
+ setup_kwargs['install_requires'] = [self.shiboken_module_st_name]
+ setup_kwargs['entry_points'] = {
+ 'console_scripts': [
+ 'pyside2-uic = {}.scripts.uic:main'.format(self.package_name()),
+ 'pyside2-rcc = {}.scripts.pyside_tool:main'.format(self.package_name()),
+ 'pyside2-lupdate = {}.scripts.pyside_tool:main'.format(self.package_name()),
+ ]
+ }
+ self.setup_kwargs = setup_kwargs
+
+ def get_long_description(self):
+ readme_filename = 'README.md'
+ changes_filename = 'CHANGES.rst'
+
+ if self.is_internal_shiboken_module_build():
+ readme_filename = 'README.shiboken2.md'
+ elif self.is_internal_shiboken_generator_build():
+ readme_filename = 'README.shiboken2-generator.md'
+ elif self.is_internal_pyside_build():
+ readme_filename = 'README.pyside2.md'
+
+ content = ''
+ changes = ''
+ try:
+ with open(os.path.join(self.setup_script_dir, readme_filename)) as f:
+ readme = f.read()
+ except Exception as e:
+ log.error("Couldn't read contents of {}.".format(readme_filename))
+ raise
+
+ # Don't include CHANGES.rst for now, because we have not decided
+ # how to handle change files yet.
+ include_changes = False
+ if include_changes:
+ try:
+ with open(os.path.join(self.setup_script_dir, changes_filename)) as f:
+ changes = f.read()
+ except Exception as e:
+ log.error("Couldn't read contents of {}".format(changes_filename))
+ raise
+ content += readme
+
+ if changes:
+ content += "\n\n" + changes
+
+ return content
+
+ def package_name(self):
+ """
+ Returns package name as it appears in Python's site-packages
+ directory.
+
+ Package names can only be delimited by underscores, and not by
+ dashes.
+ """
+ if self.is_internal_shiboken_module_build():
+ return "shiboken2"
+ elif self.is_internal_shiboken_generator_build():
+ return "shiboken2_generator"
+ elif self.is_internal_pyside_build():
+ return "PySide2"
+ else:
+ return None
+
+ def get_setup_tools_packages_for_current_build(self):
+ """
+ Returns a list of packages for setup tools to consider in the
+ build_py command, so that it can copy the pure python files.
+ Not really necessary because it's done in prepare_packages()
+ anyway.
+
+ This is really just to satisfy some checks in setuptools
+ build_py command, and if we ever properly implement the develop
+ command.
+ """
+ if self.internal_build_type == self.pyside_option_name:
+ return [
+ config.package_name(),
+ 'pyside2uic',
+ 'pyside2uic.Compiler',
+ 'pyside2uic.port_v{}'.format(sys.version_info[0])
+ ]
+ elif self.internal_build_type == self.shiboken_module_option_name:
+ return [self.package_name()]
+ else:
+ return []
+
+ def get_package_name_to_dir_path_mapping(self):
+ """
+ Used in setuptools.setup 'package_dir' argument to specify where
+ the actual module packages are located.
+
+ For example when building the shiboken module, setuptools will
+ expect to find the "shiboken2" module sources under
+ "sources/shiboken2/shibokenmodule".
+
+ This is really just to satisfy some checks in setuptools
+ build_py command, and if we ever properly implement the develop
+ command.
+ """
+ if self.is_internal_shiboken_module_build():
+ return {
+ self.package_name(): "sources/shiboken2/shibokenmodule"
+ }
+ elif self.is_internal_shiboken_generator_build():
+ # This is left empty on purpose, because the shiboken
+ # generator doesn't have a python module for now.
+ return {}
+ elif self.is_internal_pyside_build():
+ return {
+ self.package_name(): "sources/pyside2/PySide2",
+ "pyside2uic": "sources/pyside2-tools/pyside2uic"
+ }
+ else:
+ return {}
+
+ def get_buildable_extensions(self):
+ """
+ Used by PysideBuild.run to build the CMake projects.
+ :return: A list of directory names under the sources directory.
+ """
+ if self.is_internal_shiboken_module_build() or self.is_internal_shiboken_generator_build():
+ return ['shiboken2']
+ elif self.is_internal_pyside_build():
+ return ['pyside2', 'pyside2-tools']
+ return None
+
+ def set_is_top_level_invocation(self):
+ self.invocation_type = self._invocation_type_top_level
+
+ def set_is_internal_invocation(self):
+ self.invocation_type = self._invocation_type_internal
+
+ def is_top_level_invocation(self):
+ return self.invocation_type == self._invocation_type_top_level
+
+ def is_internal_invocation(self):
+ return self.invocation_type == self._invocation_type_internal
+
+ def is_top_level_build_all(self):
+ return self.build_type == self._build_type_all
+
+ def is_top_level_build_shiboken_module(self):
+ return self.build_type == self.shiboken_module_option_name
+
+ def is_top_level_build_shiboken_generator(self):
+ return self.build_type == self.shiboken_generator_option_name
+
+ def is_top_level_build_pyside(self):
+ return self.build_type == self.pyside_option_name
+
+ def set_internal_build_type(self, internal_build_type):
+ self.internal_build_type = internal_build_type
+
+ def is_internal_shiboken_module_build(self):
+ return self.internal_build_type == self.shiboken_module_option_name
+
+ def is_internal_shiboken_generator_build(self):
+ return self.internal_build_type == self.shiboken_generator_option_name
+
+ def is_internal_pyside_build(self):
+ return self.internal_build_type == self.pyside_option_name
+
+ def is_internal_shiboken_generator_build_and_part_of_top_level_all(self):
+ """
+ Used to skip certain build rules and output, when we know that
+ the CMake build of shiboken was already done as part of the
+ top-level "all" build when shiboken2-module was built.
+ """
+ return self.is_internal_shiboken_generator_build() and self.is_top_level_build_all()
+
+ def get_allowed_top_level_build_values(self):
+ return [
+ self._build_type_all,
+ self.shiboken_module_option_name,
+ self.shiboken_generator_option_name,
+ self.pyside_option_name
+ ]
+
+ def get_allowed_internal_build_values(self):
+ return [
+ self.shiboken_module_option_name,
+ self.shiboken_generator_option_name,
+ self.pyside_option_name
+ ]
+
+
+config = Config()
diff --git a/build_scripts/main.py b/build_scripts/main.py
index b64d6f1a9..50f751caa 100644
--- a/build_scripts/main.py
+++ b/build_scripts/main.py
@@ -42,6 +42,7 @@ from distutils.version import LooseVersion
import os
import time
+from .config import config
from .utils import memoize, get_python_dict
from .options import *
@@ -90,15 +91,11 @@ def get_setuptools_extension_modules():
extension_modules = [Extension(*extension_args, **extension_kwargs)]
return extension_modules
-# Buildable extensions.
-contained_modules = ['shiboken2', 'pyside2', 'pyside2-tools']
# Git submodules: ["submodule_name",
# "location_relative_to_sources_folder"]
submodules = [["pyside2-tools"]]
-pyside_package_dir_name = "pyside_package"
-
try:
import setuptools
except ImportError:
@@ -108,13 +105,8 @@ except ImportError:
import sys
import platform
import re
-import fnmatch
-
-import difflib # for a close match of dirname and module
-import functools
-from distutils import log
-from distutils.errors import DistutilsOptionError
+import distutils.log as log
from distutils.errors import DistutilsSetupError
from distutils.sysconfig import get_config_var
from distutils.sysconfig import get_python_lib
@@ -123,7 +115,7 @@ from distutils.command.build import build as _build
from distutils.command.build_ext import build_ext as _build_ext
from distutils.util import get_platform
-from setuptools import setup, Extension
+from setuptools import Extension
from setuptools.command.install import install as _install
from setuptools.command.install_lib import install_lib as _install_lib
from setuptools.command.bdist_egg import bdist_egg as _bdist_egg
@@ -132,39 +124,40 @@ from setuptools.command.build_py import build_py as _build_py
from .qtinfo import QtInfo
from .utils import rmtree, detect_clang, copyfile, copydir, run_process_output, run_process
-from .utils import update_env_path, init_msvc_env, filter_match, macos_fix_rpaths_for_library
+from .utils import update_env_path, init_msvc_env, filter_match
+from .utils import macos_fix_rpaths_for_library
+from .utils import linux_fix_rpaths_for_library
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
-# make sure that setup.py is run with an allowed python version
+
def check_allowed_python_version():
+ """
+ Make sure that setup.py is run with an allowed python version.
+ """
+
import re
- pattern = "'Programming Language :: Python :: (\d+)\.(\d+)'"
+ pattern = "Programming Language :: Python :: (\d+)\.(\d+)"
supported = []
- with open(setup_py_path) as setup:
- for line in setup.readlines():
- found = re.search(pattern, line)
- if found:
- major = int(found.group(1))
- minor = int(found.group(2))
- supported.append( (major, minor) )
+
+ for line in config.python_version_classifiers:
+ found = re.search(pattern, line)
+ if found:
+ major = int(found.group(1))
+ minor = int(found.group(2))
+ supported.append( (major, minor) )
this_py = sys.version_info[:2]
if this_py not in supported:
- print("only these python versions are supported:", supported)
+ print("Unsupported python version detected. Only these python versions are supported: {}"
+ .format(supported))
sys.exit(1)
-check_allowed_python_version()
qt_src_dir = ''
-# This is used automatically by distutils.command.install object, to
-# specify final installation location.
-OPTION_FINAL_INSTALL_PREFIX = option_value("prefix")
-
-
if OPTION_QT_VERSION is None:
OPTION_QT_VERSION = "5"
if OPTION_QMAKE is None:
@@ -293,8 +286,7 @@ def get_qt_version():
qt_version = qtinfo.version
if not qt_version:
- log.error("Failed to query the Qt version with qmake {0}".format(
- self.qtinfo.qmake_command))
+ 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"):
@@ -304,12 +296,13 @@ def get_qt_version():
return qt_version
+
def prepare_build():
if (os.path.isdir(".git") and not OPTION_IGNOREGIT and
not OPTION_ONLYPACKAGE and not OPTION_REUSE_BUILD):
prepare_sub_modules()
- # Clean up temp and package folders
- for n in [pyside_package_dir_name, "build"]:
+ # Clean up temp build folder.
+ for n in ["build"]:
d = os.path.join(setup_script_dir, n)
if os.path.isdir(d):
print("Removing {}".format(d))
@@ -318,13 +311,7 @@ def prepare_build():
except Exception as e:
print('***** problem removing "{}"'.format(d))
print('ignored error: {}'.format(e))
- # Prepare package folders
- ppdn = pyside_package_dir_name
- absolute_paths = [os.path.join(ppdn, "PySide2"),
- os.path.join(ppdn, "pyside2uic")]
- for pkg in absolute_paths:
- pkg_dir = os.path.join(setup_script_dir, pkg)
- os.makedirs(pkg_dir)
+
# locate Qt sources for the documentation
if OPTION_QT_SRC is None:
install_prefix = qtinfo.prefix_dir
@@ -389,26 +376,15 @@ class PysideBuildExt(_build_ext):
pass
-
-# pyside_build_py and pyside_install_lib are reimplemented to preserve
-# symlinks when distutils / setuptools copy files to various
-# directories through the different build stages.
class PysideBuildPy(_build_py):
def __init__(self, *args, **kwargs):
_build_py.__init__(self, *args, **kwargs)
- def build_package_data(self):
- """Copies files from pyside_package into build/xxx directory"""
-
- for package, src_dir, build_dir, filenames in self.data_files:
- for filename in filenames:
- target = os.path.join(build_dir, filename)
- self.mkpath(os.path.dirname(target))
- srcfile = os.path.abspath(os.path.join(src_dir, filename))
- # Using our own copyfile makes sure to preserve symlinks.
- copyfile(srcfile, target)
+# _install_lib is reimplemented to preserve
+# symlinks when distutils / setuptools copy files to various
+# directories from the setup tools build dir to the install dir.
class PysideInstallLib(_install_lib):
def __init__(self, *args, **kwargs):
@@ -539,10 +515,12 @@ class PysideBuild(_build):
py_prefix = get_config_var("prefix")
if not py_prefix or not os.path.exists(py_prefix):
py_prefix = sys.prefix
+ self.py_prefix = py_prefix
if sys.platform == "win32":
py_scripts_dir = os.path.join(py_prefix, "Scripts")
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":
py_libdir = os.path.join(py_prefix, "libs")
@@ -656,7 +634,7 @@ class PysideBuild(_build):
qt_version = get_qt_version()
# Update the PATH environment variable
- additional_paths = [py_scripts_dir, qt_dir]
+ additional_paths = [self.py_scripts_dir, qt_dir]
# Add Clang to path for Windows.
# Revisit once Clang is bundled with Qt.
@@ -685,19 +663,11 @@ class PysideBuild(_build):
install_dir = os.path.join(script_dir, prefix() + "_install",
"{}".format(build_name))
- # Try to ensure that tools built by this script (such as shiboken2)
- # are found before any that may already be installed on the system.
- update_env_path([os.path.join(install_dir, 'bin')])
-
- # Tell cmake to look here for *.cmake files
- os.environ['CMAKE_PREFIX_PATH'] = install_dir
-
self.make_path = make_path
self.make_generator = make_generator
self.debug = OPTION_DEBUG
self.script_dir = script_dir
- self.pyside_package_dir = os.path.join(self.script_dir,
- pyside_package_dir_name)
+ self.st_build_dir = os.path.join(self.script_dir, self.build_lib)
self.sources_dir = sources_dir
self.build_dir = build_dir
self.install_dir = install_dir
@@ -709,14 +679,61 @@ class PysideBuild(_build):
self.site_packages_dir = get_python_lib(1, 0, prefix=install_dir)
self.build_tests = OPTION_BUILDTESTS
- setuptools_install_prefix = get_python_lib(1)
- if OPTION_FINAL_INSTALL_PREFIX:
- setuptools_install_prefix = OPTION_FINAL_INSTALL_PREFIX
-
# Save the shiboken build dir path for clang deployment
# purposes.
self.shiboken_build_dir = os.path.join(self.build_dir, "shiboken2")
+ self.log_pre_build_info()
+
+ # Prepare folders
+ if not os.path.exists(self.sources_dir):
+ log.info("Creating sources folder {}...".format(self.sources_dir))
+ os.makedirs(self.sources_dir)
+ if not os.path.exists(self.build_dir):
+ log.info("Creating build folder {}...".format(self.build_dir))
+ os.makedirs(self.build_dir)
+ if not os.path.exists(self.install_dir):
+ log.info("Creating install folder {}...".format(self.install_dir))
+ os.makedirs(self.install_dir)
+
+ if not (OPTION_ONLYPACKAGE
+ and not config.is_internal_shiboken_generator_build_and_part_of_top_level_all()):
+ # Build extensions
+ for ext in config.get_buildable_extensions():
+ self.build_extension(ext)
+
+ if OPTION_BUILDTESTS:
+ # we record the latest successful build and note the
+ # build directory for supporting the tests.
+ timestamp = time.strftime('%Y-%m-%d_%H%M%S')
+ build_history = os.path.join(setup_script_dir, 'build_history')
+ unique_dir = os.path.join(build_history, timestamp)
+ os.makedirs(unique_dir)
+ fpath = os.path.join(unique_dir, 'build_dir.txt')
+ with open(fpath, 'w') as f:
+ print(build_dir, file=f)
+ log.info("Created {}".format(build_history))
+
+ if not OPTION_SKIP_PACKAGING:
+ # Build patchelf if needed
+ self.build_patchelf()
+
+ # Prepare packages
+ self.prepare_packages()
+
+ # Build packages
+ _build.run(self)
+ else:
+ log.info("Skipped preparing and building packages.")
+ log.info('*** Build completed')
+
+ def log_pre_build_info(self):
+ if config.is_internal_shiboken_generator_build_and_part_of_top_level_all():
+ return
+
+ setuptools_install_prefix = get_python_lib(1)
+ if OPTION_FINAL_INSTALL_PREFIX:
+ setuptools_install_prefix = OPTION_FINAL_INSTALL_PREFIX
log.info("=" * 30)
log.info("Package version: {}".format(get_package_version()))
log.info("Build type: {}".format(self.build_type))
@@ -726,40 +743,34 @@ class PysideBuild(_build):
log.info("Make generator: {}".format(self.make_generator))
log.info("Make jobs: {}".format(OPTION_JOBS))
log.info("-" * 3)
-
log.info("setup.py directory: {}".format(self.script_dir))
log.info("Build scripts directory: {}".format(build_scripts_dir))
log.info("Sources directory: {}".format(self.sources_dir))
-
log.info(dedent("""
- Building PySide2 will create and touch directories
+ Building {st_package_name} will create and touch directories
in the following order:
make build directory (py*_build/*/*) ->
make install directory (py*_install/*/*) ->
- {} directory (pyside_package/*) ->
setuptools build directory (build/*/*) ->
setuptools install directory
(usually path-installed-python/lib/python*/site-packages/*)
- """).format(pyside_package_dir_name))
-
+ """).format(st_package_name=config.package_name()))
log.info("make build directory: {}".format(self.build_dir))
log.info("make install directory: {}".format(self.install_dir))
- log.info("{} directory: {}".format(pyside_package_dir_name,
- self.pyside_package_dir))
- log.info("setuptools build directory: {}".format(
- os.path.join(self.script_dir, "build")))
- log.info("setuptools install directory: {}".format(
- setuptools_install_prefix))
- log.info("make-installed site-packages directory: {} \n"
- " (only relevant for copying files from "
- "'make install directory' to '{} directory'".format(
- self.site_packages_dir, pyside_package_dir_name))
+ log.info("setuptools build directory: {}".format(self.st_build_dir))
+ log.info("setuptools install directory: {}".format(setuptools_install_prefix))
+ log.info(dedent("""
+ make-installed site-packages directory: {}
+ (only relevant for copying files from 'make install directory'
+ to 'setuptools build directory'
+ """).format(
+ self.site_packages_dir))
log.info("-" * 3)
log.info("Python executable: {}".format(self.py_executable))
log.info("Python includes: {}".format(self.py_include_dir))
log.info("Python library: {}".format(self.py_library))
- log.info("Python prefix: {}".format(py_prefix))
- log.info("Python scripts: {}".format(py_scripts_dir))
+ log.info("Python prefix: {}".format(self.py_prefix))
+ log.info("Python scripts: {}".format(self.py_scripts_dir))
log.info("-" * 3)
log.info("Qt qmake: {}".format(self.qtinfo.qmake_command))
log.info("Qt version: {}".format(self.qtinfo.version))
@@ -772,52 +783,11 @@ class PysideBuild(_build):
if sys.platform == 'darwin':
pyside_macos_deployment_target = (
PysideBuild.macos_pyside_min_deployment_target()
- )
+ )
log.info("MACOSX_DEPLOYMENT_TARGET set to: {}".format(
pyside_macos_deployment_target))
log.info("=" * 30)
- # Prepare folders
- if not os.path.exists(self.sources_dir):
- log.info("Creating sources folder {}...".format(self.sources_dir))
- os.makedirs(self.sources_dir)
- if not os.path.exists(self.build_dir):
- log.info("Creating build folder {}...".format(self.build_dir))
- os.makedirs(self.build_dir)
- if not os.path.exists(self.install_dir):
- log.info("Creating install folder {}...".format(self.install_dir))
- os.makedirs(self.install_dir)
-
- if not OPTION_ONLYPACKAGE:
- # Build extensions
- for ext in contained_modules:
- self.build_extension(ext)
-
- if OPTION_BUILDTESTS:
- # we record the latest successful build and note the
- # build directory for supporting the tests.
- timestamp = time.strftime('%Y-%m-%d_%H%M%S')
- build_history = os.path.join(setup_script_dir, 'build_history')
- unique_dir = os.path.join(build_history, timestamp)
- os.makedirs(unique_dir)
- fpath = os.path.join(unique_dir, 'build_dir.txt')
- with open(fpath, 'w') as f:
- print(build_dir, file=f)
- log.info("Created {}".format(build_history))
-
- if not OPTION_SKIP_PACKAGING:
- # Build patchelf if needed
- self.build_patchelf()
-
- # Prepare packages
- self.prepare_packages()
-
- # Build packages
- _build.run(self)
- else:
- log.info("Skipped preparing and building packages.")
- log.info('*** Build completed')
-
@staticmethod
def macos_qt_min_deployment_target():
target = qtinfo.macos_min_deployment_target
@@ -953,6 +923,17 @@ class PysideBuild(_build):
cmake_cmd.append("-DPYTHON_EXECUTABLE={}".format(self.py_executable))
cmake_cmd.append("-DPYTHON_INCLUDE_DIR={}".format(self.py_include_dir))
cmake_cmd.append("-DPYTHON_LIBRARY={}".format(self.py_library))
+
+ # If a custom shiboken cmake config directory path was provided, pass it to CMake.
+ if OPTION_SHIBOKEN_CONFIG_DIR and config.is_internal_pyside_build():
+ if os.path.exists(OPTION_SHIBOKEN_CONFIG_DIR):
+ log.info("Using custom provided shiboken2 installation: {}"
+ .format(OPTION_SHIBOKEN_CONFIG_DIR))
+ cmake_cmd.append("-DShiboken2_DIR={}".format(OPTION_SHIBOKEN_CONFIG_DIR))
+ else:
+ log.info("Custom provided shiboken2 installation not found. Path given: {}"
+ .format(OPTION_SHIBOKEN_CONFIG_DIR))
+
if OPTION_MODULE_SUBSET:
module_sub_set = ''
for m in OPTION_MODULE_SUBSET.split(','):
@@ -1014,20 +995,20 @@ class PysideBuild(_build):
cmake_cmd.append("-DPYSIDE_QT_CONF_PREFIX={}".format(
pyside_qt_conf_prefix))
- # Pass package version to CMake, so this string can be
- # embedded into _config.py file.
- package_version = get_package_version()
- cmake_cmd.append("-DPYSIDE_SETUP_PY_PACKAGE_VERSION={}".format(
- package_version))
-
- # In case if this is a snapshot build, also pass the
- # timestamp as a separate value, because it the only
- # version component that is actually generated by setup.py.
- timestamp = ''
- if OPTION_SNAPSHOT_BUILD:
- timestamp = get_package_timestamp()
- cmake_cmd.append("-DPYSIDE_SETUP_PY_PACKAGE_TIMESTAMP={}".format(
- timestamp))
+ # Pass package version to CMake, so this string can be
+ # embedded into _config.py file.
+ package_version = get_package_version()
+ cmake_cmd.append("-DPACKAGE_SETUP_PY_PACKAGE_VERSION={}".format(
+ package_version))
+
+ # In case if this is a snapshot build, also pass the
+ # timestamp as a separate value, because it is the only
+ # version component that is actually generated by setup.py.
+ timestamp = ''
+ if OPTION_SNAPSHOT_BUILD:
+ timestamp = get_package_timestamp()
+ cmake_cmd.append("-DPACKAGE_SETUP_PY_PACKAGE_TIMESTAMP={}".format(
+ timestamp))
if extension.lower() in ["shiboken2", "pyside2-tools"]:
cmake_cmd.append("-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=yes")
@@ -1129,15 +1110,24 @@ class PysideBuild(_build):
os.chdir(self.script_dir)
def prepare_packages(self):
+ """
+ This will copy all relevant files from the various locations in the "cmake install dir",
+ to the setup tools build dir (which is read from self.build_lib provided by distutils).
+
+ After that setuptools.command.build_py is smart enough to copy everything
+ from the build dir to the install dir (the virtualenv site-packages for example).
+ """
try:
- log.info("Preparing packages...")
+ log.info("\nPreparing setup tools build directory.\n")
vars = {
"site_packages_dir": self.site_packages_dir,
"sources_dir": self.sources_dir,
"install_dir": self.install_dir,
"build_dir": self.build_dir,
"script_dir": self.script_dir,
- "pyside_package_dir": self.pyside_package_dir,
+ "st_build_dir": self.st_build_dir,
+ "cmake_package_name": config.package_name(),
+ "st_package_name": config.package_name(),
"ssl_libs_dir": OPTION_OPENSSL,
"py_version": self.py_version,
"qt_version": self.qtinfo.version,
@@ -1151,6 +1141,12 @@ class PysideBuild(_build):
"qt_qml_dir": self.qtinfo.qml_dir,
"target_arch": self.py_arch,
}
+
+ # Needed for correct file installation in generator build
+ # case.
+ if config.is_internal_shiboken_generator_build():
+ vars['cmake_package_name'] = config.shiboken_module_option_name
+
os.chdir(self.script_dir)
if sys.platform == "win32":
@@ -1170,19 +1166,21 @@ class PysideBuild(_build):
def get_built_pyside_config(self, vars):
# Get config that contains list of built modules, and
# SOVERSIONs of the built libraries.
- pyside_package_dir = vars['pyside_package_dir']
- config_path = os.path.join(pyside_package_dir, "PySide2", "_config.py")
- config = get_python_dict(config_path)
- return config
+ st_build_dir = vars['st_build_dir']
+ config_path = os.path.join(st_build_dir, config.package_name(), "_config.py")
+ temp_config = get_python_dict(config_path)
+ if 'built_modules' not in temp_config:
+ temp_config['built_modules'] = []
+ return temp_config
def is_webengine_built(self, built_modules):
return ('WebEngineWidgets' in built_modules or 'WebEngineCore' in built_modules
or 'WebEngine' in built_modules)
- def prepare_standalone_clang(self, is_win = False):
+ def prepare_standalone_clang(self, is_win=False):
"""
- Copies the libclang library to the pyside package so that
- shiboken executable works.
+ Copies the libclang library to the shiboken2-generator
+ package so that the shiboken executable works.
"""
log.info('Finding path to the libclang shared library.')
cmake_cmd = [
@@ -1205,47 +1203,54 @@ class PysideBuild(_build):
if not clang_lib_path:
raise RuntimeError("Could not find the location of the libclang "
- "library inside the CMake cache file.")
+ "library inside the CMake cache file.")
- target_name = None
if is_win:
# clang_lib_path points to the static import library
# (lib/libclang.lib), whereas we want to copy the shared
# library (bin/libclang.dll).
- clang_lib_path = re.sub(r'lib/libclang.lib$', 'bin/libclang.dll',
- clang_lib_path)
+ clang_lib_path = re.sub(r'lib/libclang.lib$',
+ 'bin/libclang.dll',
+ clang_lib_path)
else:
- if sys.platform != 'darwin' and os.path.islink(clang_lib_path):
- # On Linux, we get "libclang.so" from CMake which is
- # a symlink:
- # libclang.so -> libclang.so.6 -> libclang.so.6.0.
- # shiboken2 links against libclang.so.6. So, we
- # determine the target name by resolving just
- # one symlink (note: os.path.realpath() resolves all).
- target_name = os.readlink(clang_lib_path)
- # We want to resolve any symlink on Linux and macOS, and
- # copy the actual file.
- clang_lib_path = os.path.realpath(clang_lib_path)
-
- if not target_name:
- target_name = os.path.basename(clang_lib_path)
-
- # Path to directory containing libclang.
- clang_lib_dir = os.path.dirname(clang_lib_path)
-
- # The destination will be the package folder near the other
- # extension modules.
- destination_dir = "{}/PySide2".format(os.path.join(self.script_dir,
- 'pyside_package'))
+ # shiboken2 links against libclang.so.6 or a similarly
+ # named library.
+ # If the linked against library is a symlink, resolve
+ # the symlink once (but not all the way to the real
+ # file) on Linux and macOS,
+ # so that we get the path to the "SO version" symlink
+ # (the one used as the install name in the shared library
+ # dependency section).
+ # E.g. On Linux libclang.so -> libclang.so.6 ->
+ # libclang.so.6.0.
+ # "libclang.so.6" is the name we want for the copied file.
+ if os.path.islink(clang_lib_path):
+ link_target = os.readlink(clang_lib_path)
+ if os.path.isabs(link_target):
+ clang_lib_path = link_target
+ else:
+ # link_target is relative, transform to absolute.
+ clang_lib_path = os.path.join(os.path.dirname(clang_lib_path), link_target)
+ clang_lib_path = os.path.abspath(clang_lib_path)
+
+ # The destination will be the shiboken package folder.
+ vars = {}
+ vars['st_build_dir'] = self.st_build_dir
+ vars['st_package_name'] = config.package_name()
+ destination_dir = "{st_build_dir}/{st_package_name}".format(**vars)
+
if os.path.exists(clang_lib_path):
- log.info('Copying libclang shared library {} to the package folder as {}.'.format(
- clang_lib_path, target_name))
basename = os.path.basename(clang_lib_path)
- destination_path = os.path.join(destination_dir, target_name)
+ log.info('Copying libclang shared library {} to the package folder as {}.'.format(
+ clang_lib_path, basename))
+ destination_path = os.path.join(destination_dir, basename)
# Need to modify permissions in case file is not writable
# (a reinstall would cause a permission denied error).
- copyfile(clang_lib_path, destination_path, make_writable_by_owner=True)
+ copyfile(clang_lib_path,
+ destination_path,
+ force_copy_symlink=True,
+ make_writable_by_owner=True)
else:
raise RuntimeError("Error copying libclang library "
"from {} to {}. ".format(
@@ -1265,18 +1270,17 @@ class PysideBuild(_build):
else:
# Add rpath values pointing to $ORIGIN and the
# installed qt lib directory.
- local_rpath = '$ORIGIN/'
- qt_lib_dir = self.qtinfo.libs_dir
+ final_rpath = self.qtinfo.libs_dir
if OPTION_STANDALONE:
- qt_lib_dir = "$ORIGIN/Qt/lib"
- final_rpath = local_rpath + ':' + qt_lib_dir
- cmd = [self._patchelf_path, '--set-rpath', final_rpath, srcpath]
- if run_process(cmd) != 0:
- raise RuntimeError("Error patching rpath in " + srcpath)
+ final_rpath = "$ORIGIN/Qt/lib"
+ override = OPTION_STANDALONE
+ linux_fix_rpaths_for_library(self._patchelf_path, srcpath, final_rpath,
+ override=override)
elif sys.platform == 'darwin':
pyside_libs = [lib for lib in os.listdir(
package_path) if filter_match(lib, ["*.so", "*.dylib"])]
+
def rpath_cmd(srcpath):
final_rpath = ''
# Command line rpath option takes precedence over
@@ -1308,15 +1312,6 @@ class PysideBuild(_build):
"updated rpath (OS/X) in {}.".format(srcpath))
-try:
- with open(os.path.join(setup_script_dir, 'README.rst')) as f:
- README = f.read()
- with open(os.path.join(setup_script_dir, 'CHANGES.rst')) as f:
- CHANGES = f.read()
-except IOError:
- README = CHANGES = ''
-
-
cmd_class_dict = {
'build': PysideBuild,
'build_py': PysideBuildPy,
diff --git a/build_scripts/options.py b/build_scripts/options.py
index fd8b0718e..daf3bb00e 100644
--- a/build_scripts/options.py
+++ b/build_scripts/options.py
@@ -38,16 +38,88 @@
#############################################################################
from __future__ import print_function
+import sys
+import os
+
+
+class Options(object):
+ def __init__(self):
+
+ # Dictionary containing values of all the possible options.
+ self.dict = {}
+
+ def has_option(self, name):
+ """ Returns True if argument '--name' was passed on the command
+ line. """
+ try:
+ sys.argv.remove("--{}".format(name))
+ self.dict[name] = True
+ return True
+ except ValueError:
+ pass
+ return False
+
+ def option_value(self, name, remove=True):
+ """
+ Returns the value of a command line option or environment
+ variable.
+
+ :param name: The name of the command line option or environment
+ variable.
+
+ :param remove: Whether the option and its value should be
+ removed from sys.argv. Useful when there's a need to query for
+ the value and also pass it along to setuptools for example.
+
+ :return: Either the option value or None.
+ """
+ for index, option in enumerate(sys.argv):
+ if option == '--' + name:
+ if index + 1 >= len(sys.argv):
+ raise RuntimeError("The option {} requires a value".format(option))
+ value = sys.argv[index + 1]
+
+ if remove:
+ sys.argv[index:index + 2] = []
+
+ self.dict[name] = value
+ return value
+
+ if option.startswith('--' + name + '='):
+ value = option[len(name) + 3:]
+
+ if remove:
+ sys.argv[index:index + 1] = []
+
+ self.dict[name] = value
+ return value
+
+ env_val = os.getenv(name.upper().replace('-', '_'))
+ self.dict[name] = env_val
+ return env_val
+
+
+options = Options()
+
+
+def has_option(name):
+ return options.has_option(name)
+
+
+def option_value(*args,**kwargs):
+ return options.option_value(*args,**kwargs)
-from .utils import has_option, option_value
# Declare options
+OPTION_BUILD_TYPE = option_value("build-type")
+OPTION_INTERNAL_BUILD_TYPE = option_value("internal-build-type")
OPTION_DEBUG = has_option("debug")
OPTION_RELWITHDEBINFO = has_option('relwithdebinfo')
OPTION_QMAKE = option_value("qmake")
OPTION_QT_VERSION = option_value("qt")
OPTION_CMAKE = option_value("cmake")
OPTION_OPENSSL = option_value("openssl")
+OPTION_SHIBOKEN_CONFIG_DIR = option_value("shiboken-config-dir")
OPTION_ONLYPACKAGE = has_option("only-package")
OPTION_STANDALONE = has_option("standalone")
OPTION_MAKESPEC = option_value("make-spec")
@@ -82,3 +154,7 @@ OPTION_SANITIZE_ADDRESS = has_option("sanitize-address")
OPTION_SNAPSHOT_BUILD = has_option("snapshot-build")
OPTION_LIMITED_API = option_value("limited-api")
OPTION_PACKAGE_TIMESTAMP = option_value("package-timestamp")
+
+# This is used automatically by distutils.command.install object, to
+# specify the final installation location.
+OPTION_FINAL_INSTALL_PREFIX = option_value("prefix", remove=False)
diff --git a/build_scripts/platforms/linux.py b/build_scripts/platforms/linux.py
index 4c38fef6c..067179cdc 100644
--- a/build_scripts/platforms/linux.py
+++ b/build_scripts/platforms/linux.py
@@ -37,76 +37,100 @@
##
#############################################################################
-from ..options import *
from ..utils import copydir, copyfile, copy_icu_libs, find_files_using_glob
+from ..config import config
-def prepare_standalone_package_linux(self, executables, vars):
+
+def prepare_standalone_package_linux(self, vars):
built_modules = vars['built_modules']
- # <qt>/lib/* -> <setup>/PySide2/Qt/lib
- destination_lib_dir = "{pyside_package_dir}/PySide2/Qt/lib"
+ constrain_modules = None
+ copy_plugins = True
+ copy_qml = True
+ copy_translations = True
+ copy_qt_conf = True
+ should_copy_icu_libs = True
+
+ if config.is_internal_shiboken_generator_build():
+ constrain_modules = ["Core", "Network", "Xml", "XmlPatterns"]
+ copy_plugins = False
+ copy_qml = False
+ copy_translations = False
+ copy_qt_conf = False
+ should_copy_icu_libs = False
+
+ # <qt>/lib/* -> <setup>/{st_package_name}/Qt/lib
+ destination_lib_dir = "{st_build_dir}/{st_package_name}/Qt/lib"
+
+ accepted_modules = ['libQt5*.so.?']
+ if constrain_modules:
+ accepted_modules = ["libQt5" + module + "*.so.?" for module in constrain_modules]
+ accepted_modules.append("libicu*.so.??")
+
copydir("{qt_lib_dir}", destination_lib_dir,
- filter=[
- "libQt5*.so.?",
- "libicu*.so.??",
- ],
- recursive=False, vars=vars, force_copy_symlinks=True)
-
- # Check if ICU libraries were copied over to the destination
- # Qt libdir.
- resolved_destination_lib_dir = destination_lib_dir.format(**vars)
- maybe_icu_libs = find_files_using_glob(resolved_destination_lib_dir,
- "libicu*")
-
- # If no ICU libraries are present in the Qt libdir (like when
- # Qt is built against system ICU, or in the Coin CI where ICU
- # libs are in a different directory) try to find out / resolve
- # which ICU libs are used by QtCore (if used at all) using a
- # custom written ldd, and copy the ICU libs to the Pyside Qt
- # dir if necessary. We choose the QtCore lib to inspect, by
- # checking which QtCore library the shiboken2 executable uses.
- if not maybe_icu_libs:
- copy_icu_libs(self._patchelf_path, resolved_destination_lib_dir)
+ filter=accepted_modules,
+ recursive=False, vars=vars, force_copy_symlinks=True)
+
+ if should_copy_icu_libs:
+ # Check if ICU libraries were copied over to the destination
+ # Qt libdir.
+ resolved_destination_lib_dir = destination_lib_dir.format(**vars)
+ maybe_icu_libs = find_files_using_glob(resolved_destination_lib_dir,
+ "libicu*")
+
+ # If no ICU libraries are present in the Qt libdir (like when
+ # Qt is built against system ICU, or in the Coin CI where ICU
+ # libs are in a different directory) try to find out / resolve
+ # which ICU libs are used by QtCore (if used at all) using a
+ # custom written ldd, and copy the ICU libs to the Pyside Qt
+ # dir if necessary. We choose the QtCore lib to inspect, by
+ # checking which QtCore library the shiboken2 executable uses.
+ if not maybe_icu_libs:
+ copy_icu_libs(self._patchelf_path, resolved_destination_lib_dir)
if self.is_webengine_built(built_modules):
copydir("{qt_lib_execs_dir}",
- "{pyside_package_dir}/PySide2/Qt/libexec",
+ "{st_build_dir}/{st_package_name}/Qt/libexec",
filter=None,
recursive=False,
vars=vars)
copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/Qt/resources",
+ "{st_build_dir}/{st_package_name}/Qt/resources",
filter=None,
recursive=False,
vars=vars)
- # <qt>/plugins/* -> <setup>/PySide2/Qt/plugins
- copydir("{qt_plugins_dir}",
- "{pyside_package_dir}/PySide2/Qt/plugins",
- filter=["*.so"],
- recursive=True,
- vars=vars)
-
- # <qt>/qml/* -> <setup>/PySide2/Qt/qml
- copydir("{qt_qml_dir}",
- "{pyside_package_dir}/PySide2/Qt/qml",
- filter=None,
- force=False,
- recursive=True,
- ignore=["*.so.debug"],
- vars=vars)
-
- # <qt>/translations/* -> <setup>/PySide2/Qt/translations
-
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/Qt/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
-
- # Copy the qt.conf file to libexec.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2/Qt/libexec",
- vars=vars)
+ if copy_plugins:
+ # <qt>/plugins/* -> <setup>/{st_package_name}/Qt/plugins
+ copydir("{qt_plugins_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/plugins",
+ filter=["*.so"],
+ recursive=True,
+ vars=vars)
+
+ if copy_qml:
+ # <qt>/qml/* -> <setup>/{st_package_name}/Qt/qml
+ copydir("{qt_qml_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/qml",
+ filter=None,
+ force=False,
+ recursive=True,
+ ignore=["*.so.debug"],
+ vars=vars)
+
+ if copy_translations:
+ # <qt>/translations/* ->
+ # <setup>/{st_package_name}/Qt/translations
+ copydir("{qt_translations_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/translations",
+ filter=["*.qm", "*.pak"],
+ force=False,
+ vars=vars)
+
+ if copy_qt_conf:
+ # Copy the qt.conf file to libexec.
+ copyfile(
+ "{build_dir}/pyside2/{st_package_name}/qt.conf",
+ "{st_build_dir}/{st_package_name}/Qt/libexec",
+ vars=vars)
diff --git a/build_scripts/platforms/macos.py b/build_scripts/platforms/macos.py
index 936f4ca90..49f02754d 100644
--- a/build_scripts/platforms/macos.py
+++ b/build_scripts/platforms/macos.py
@@ -37,12 +37,29 @@
##
#############################################################################
-import fnmatch, os
+import fnmatch
+import os
from ..utils import copydir, copyfile, macos_fix_rpaths_for_library
+from ..config import config
-def prepare_standalone_package_macos(self, executables, vars):
+
+def prepare_standalone_package_macos(self, vars):
built_modules = vars['built_modules']
+ constrain_modules = None
+ copy_plugins = True
+ copy_qml = True
+ copy_translations = True
+ copy_qt_conf = True
+
+ if config.is_internal_shiboken_generator_build():
+ constrain_modules = ["Core", "Network", "Xml", "XmlPatterns"]
+ constrain_frameworks = ['Qt' + name + '.framework' for name in constrain_modules]
+ copy_plugins = False
+ copy_qml = False
+ copy_translations = False
+ copy_qt_conf = False
+
# Directory filter for skipping unnecessary files.
def general_dir_filter(dir_name, parent_full_path, dir_full_path):
if fnmatch.fnmatch(dir_name, "*.dSYM"):
@@ -52,6 +69,7 @@ def prepare_standalone_package_macos(self, executables, vars):
# Filter out debug plugins and qml plugins in the
# debug_and_release config.
no_copy_debug = True
+
def file_variant_filter(file_name, file_full_path):
if self.qtinfo.build_type != 'debug_and_release':
return True
@@ -59,17 +77,16 @@ def prepare_standalone_package_macos(self, executables, vars):
return False
return True
- # <qt>/lib/* -> <setup>/PySide2/Qt/lib
+ # <qt>/lib/* -> <setup>/{st_package_name}/Qt/lib
if self.qt_is_framework_build():
- framework_built_modules = [
- 'Qt' + name + '.framework' for name in built_modules]
-
- def framework_dir_filter(dir_name, parent_full_path,
- dir_full_path):
+ def framework_dir_filter(dir_name, parent_full_path, dir_full_path):
if '.framework' in dir_name:
- if dir_name.startswith('QtWebEngine') and not \
- self.is_webengine_built(built_modules):
+ if (dir_name.startswith('QtWebEngine') and
+ not self.is_webengine_built(built_modules)):
+ return False
+ if constrain_modules and dir_name not in constrain_frameworks:
return False
+
if dir_name in ['Headers', 'fonts']:
return False
if dir_full_path.endswith('Versions/Current'):
@@ -84,6 +101,7 @@ def prepare_standalone_package_macos(self, executables, vars):
# Filter out debug frameworks in the
# debug_and_release config.
no_copy_debug = True
+
def framework_variant_filter(file_name, file_full_path):
if self.qtinfo.build_type != 'debug_and_release':
return True
@@ -93,7 +111,7 @@ def prepare_standalone_package_macos(self, executables, vars):
return False
return True
- copydir("{qt_lib_dir}", "{pyside_package_dir}/PySide2/Qt/lib",
+ copydir("{qt_lib_dir}", "{st_build_dir}/{st_package_name}/Qt/lib",
recursive=True, vars=vars,
ignore=["*.la", "*.a", "*.cmake", "*.pc", "*.prl"],
dir_filter_function=framework_dir_filter,
@@ -104,7 +122,7 @@ def prepare_standalone_package_macos(self, executables, vars):
# from Versions/5/Helpers, thus adding two more levels of
# directory hierarchy.
if self.is_webengine_built(built_modules):
- qt_lib_path = "{pyside_package_dir}/PySide2/Qt/lib".format(
+ qt_lib_path = "{st_build_dir}/{st_package_name}/Qt/lib".format(
**vars)
bundle = "QtWebEngineCore.framework/Helpers/"
bundle += "QtWebEngineProcess.app"
@@ -120,9 +138,11 @@ def prepare_standalone_package_macos(self, executables, vars):
if 'WebKit' not in built_modules:
ignored_modules.extend(['libQt5WebKit*.dylib'])
accepted_modules = ['libQt5*.5.dylib']
+ if constrain_modules:
+ accepted_modules = ["libQt5" + module + "*.5.dylib" for module in constrain_modules]
copydir("{qt_lib_dir}",
- "{pyside_package_dir}/PySide2/Qt/lib",
+ "{st_build_dir}/{st_package_name}/Qt/lib",
filter=accepted_modules,
ignore=ignored_modules,
file_filter_function=file_variant_filter,
@@ -130,53 +150,58 @@ def prepare_standalone_package_macos(self, executables, vars):
if self.is_webengine_built(built_modules):
copydir("{qt_lib_execs_dir}",
- "{pyside_package_dir}/PySide2/Qt/libexec",
+ "{st_build_dir}/{st_package_name}/Qt/libexec",
filter=None,
recursive=False,
vars=vars)
copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/Qt/resources",
+ "{st_build_dir}/{st_package_name}/Qt/resources",
filter=None,
recursive=False,
vars=vars)
# Fix rpath for WebEngine process executable.
- pyside_package_dir = vars['pyside_package_dir']
- qt_libexec_path = "{}/PySide2/Qt/libexec".format(pyside_package_dir)
+ qt_libexec_path = "{st_build_dir}/{st_package_name}/Qt/libexec".format(**vars)
binary = "QtWebEngineProcess"
final_path = os.path.join(qt_libexec_path, binary)
rpath = "@loader_path/../lib"
macos_fix_rpaths_for_library(final_path, rpath)
- # Copy the qt.conf file to libexec.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2/Qt/libexec",
- vars=vars)
+ if copy_qt_conf:
+ # Copy the qt.conf file to libexec.
+ copyfile(
+ "{build_dir}/pyside2/{st_package_name}/qt.conf",
+ "{st_build_dir}/{st_package_name}/Qt/libexec",
+ vars=vars)
+
+ if copy_plugins:
+ # <qt>/plugins/* -> <setup>/{st_package_name}/Qt/plugins
+ copydir("{qt_plugins_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/plugins",
+ filter=["*.dylib"],
+ recursive=True,
+ dir_filter_function=general_dir_filter,
+ file_filter_function=file_variant_filter,
+ vars=vars)
+
- # <qt>/plugins/* -> <setup>/PySide2/Qt/plugins
- copydir("{qt_plugins_dir}",
- "{pyside_package_dir}/PySide2/Qt/plugins",
- filter=["*.dylib"],
- recursive=True,
- dir_filter_function=general_dir_filter,
- file_filter_function=file_variant_filter,
- vars=vars)
-
- # <qt>/qml/* -> <setup>/PySide2/Qt/qml
- copydir("{qt_qml_dir}",
- "{pyside_package_dir}/PySide2/Qt/qml",
- filter=None,
- recursive=True,
- force=False,
- dir_filter_function=general_dir_filter,
- file_filter_function=file_variant_filter,
- vars=vars)
-
- # <qt>/translations/* -> <setup>/PySide2/Qt/translations
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/Qt/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
+ if copy_qml:
+ # <qt>/qml/* -> <setup>/{st_package_name}/Qt/qml
+ copydir("{qt_qml_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/qml",
+ filter=None,
+ recursive=True,
+ force=False,
+ dir_filter_function=general_dir_filter,
+ file_filter_function=file_variant_filter,
+ vars=vars)
+
+ if copy_translations:
+ # <qt>/translations/* ->
+ # <setup>/{st_package_name}/Qt/translations
+ copydir("{qt_translations_dir}",
+ "{st_build_dir}/{st_package_name}/Qt/translations",
+ filter=["*.qm", "*.pak"],
+ force=False,
+ vars=vars)
diff --git a/build_scripts/platforms/unix.py b/build_scripts/platforms/unix.py
index e7fa92390..7dce11612 100644
--- a/build_scripts/platforms/unix.py
+++ b/build_scripts/platforms/unix.py
@@ -37,73 +37,31 @@
##
#############################################################################
-import os, re, sys
+import os
+import sys
from .linux import prepare_standalone_package_linux
from .macos import prepare_standalone_package_macos
+
+from ..config import config
from ..options import *
from ..utils import copydir, copyfile, rmtree, makefile
from ..utils import regenerate_qt_resources
+
def prepare_packages_posix(self, vars):
executables = []
- # <build>/shiboken2/doc/html/* ->
- # <setup>/PySide2/docs/shiboken2
- copydir(
- "{build_dir}/shiboken2/doc/html",
- "{pyside_package_dir}/PySide2/docs/shiboken2",
- force=False, vars=vars)
- # <install>/lib/site-packages/PySide2/* -> <setup>/PySide2
- copydir(
- "{site_packages_dir}/PySide2",
- "{pyside_package_dir}/PySide2",
- vars=vars)
- # <install>/lib/site-packages/shiboken2.so ->
- # <setup>/PySide2/shiboken2.so
- shiboken_module_name = 'shiboken2.so'
- shiboken_src_path = "{site_packages_dir}".format(**vars)
- maybe_shiboken_names = [f for f in os.listdir(shiboken_src_path)
- if re.match(r'shiboken.*\.so', f)]
- if maybe_shiboken_names:
- shiboken_module_name = maybe_shiboken_names[0]
- vars.update({'shiboken_module_name': shiboken_module_name})
- copyfile(
- "{site_packages_dir}/{shiboken_module_name}",
- "{pyside_package_dir}/PySide2/{shiboken_module_name}",
- vars=vars)
- # <install>/lib/site-packages/pyside2uic/* ->
- # <setup>/pyside2uic
+
+ # <install>/lib/site-packages/{st_package_name}/* ->
+ # <setup>/{st_package_name}
+ # This copies the module .so/.dylib files and various .py files
+ # (__init__, config, git version, etc.)
copydir(
- "{site_packages_dir}/pyside2uic",
- "{pyside_package_dir}/pyside2uic",
- force=False, vars=vars)
- if sys.version_info[0] > 2:
- rmtree("{pyside_package_dir}/pyside2uic/port_v2".format(**vars))
- else:
- rmtree("{pyside_package_dir}/pyside2uic/port_v3".format(**vars))
- # <install>/bin/pyside2-uic -> PySide2/scripts/uic.py
- makefile(
- "{pyside_package_dir}/PySide2/scripts/__init__.py",
+ "{site_packages_dir}/{st_package_name}",
+ "{st_build_dir}/{st_package_name}",
vars=vars)
- copyfile(
- "{install_dir}/bin/pyside2-uic",
- "{pyside_package_dir}/PySide2/scripts/uic.py",
- force=False, vars=vars)
- copyfile(
- "{install_dir}/bin/pyside_tool.py",
- "{pyside_package_dir}/PySide2/scripts/pyside_tool.py",
- force=False, vars=vars)
- # <install>/bin/* -> PySide2/
- executables.extend(copydir(
- "{install_dir}/bin/",
- "{pyside_package_dir}/PySide2",
- filter=[
- "pyside2-lupdate",
- "pyside2-rcc",
- "shiboken2",
- ],
- recursive=False, vars=vars))
- # <install>/lib/lib* -> PySide2/
- config = self.get_built_pyside_config(vars)
+
+ generated_config = self.get_built_pyside_config(vars)
+
def adjusted_lib_name(name, version):
postfix = ''
if sys.platform.startswith('linux'):
@@ -111,61 +69,144 @@ def prepare_packages_posix(self, vars):
elif sys.platform == 'darwin':
postfix = '.' + version + '.dylib'
return name + postfix
- copydir(
- "{install_dir}/lib/",
- "{pyside_package_dir}/PySide2",
- filter=[
- adjusted_lib_name("libpyside*",
- config['pyside_library_soversion']),
- adjusted_lib_name("libshiboken*",
- config['shiboken_library_soversion']),
- ],
- recursive=False, vars=vars, force_copy_symlinks=True)
- # <install>/share/PySide2/typesystems/* ->
- # <setup>/PySide2/typesystems
- copydir(
- "{install_dir}/share/PySide2/typesystems",
- "{pyside_package_dir}/PySide2/typesystems",
- vars=vars)
- # <install>/include/* -> <setup>/PySide2/include
- copydir(
- "{install_dir}/include",
- "{pyside_package_dir}/PySide2/include",
- vars=vars)
- # <source>/pyside2/PySide2/support/* ->
- # <setup>/PySide2/support/*
- copydir(
- "{build_dir}/pyside2/PySide2/support",
- "{pyside_package_dir}/PySide2/support",
- vars=vars)
- if not OPTION_NOEXAMPLES:
- # examples/* -> <setup>/PySide2/examples
- copydir(os.path.join(self.script_dir, "examples"),
- "{pyside_package_dir}/PySide2/examples",
- force=False, vars=vars)
- # Re-generate examples Qt resource files for Python 3
- # compatibility
- if sys.version_info[0] == 3:
- examples_path = "{pyside_package_dir}/PySide2/examples".format(
- **vars)
- pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
- **vars)
- pyside_rcc_options = '-py3'
- regenerate_qt_resources(examples_path, pyside_rcc_path,
- pyside_rcc_options)
+
+ if config.is_internal_shiboken_module_build():
+ # <build>/shiboken2/doc/html/* ->
+ # <setup>/{st_package_name}/docs/shiboken2
+ copydir(
+ "{build_dir}/shiboken2/doc/html",
+ "{st_build_dir}/{st_package_name}/docs/shiboken2",
+ force=False, vars=vars)
+
+ # <install>/lib/lib* -> {st_package_name}/
+ copydir(
+ "{install_dir}/lib/",
+ "{st_build_dir}/{st_package_name}",
+ filter=[
+ adjusted_lib_name("libshiboken*",
+ generated_config['shiboken_library_soversion']),
+ ],
+ recursive=False, vars=vars, force_copy_symlinks=True)
+
+ if config.is_internal_shiboken_generator_build():
+ # <install>/bin/* -> {st_package_name}/
+ executables.extend(copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=[
+ "shiboken2",
+ ],
+ recursive=False, vars=vars))
+
+ # Used to create scripts directory.
+ makefile(
+ "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py",
+ vars=vars)
+
+ # For setting up setuptools entry points.
+ copyfile(
+ "{install_dir}/bin/shiboken_tool.py",
+ "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py",
+ force=False, vars=vars)
+
+ if config.is_internal_shiboken_generator_build() or config.is_internal_pyside_build():
+ # <install>/include/* -> <setup>/{st_package_name}/include
+ copydir(
+ "{install_dir}/include/{cmake_package_name}",
+ "{st_build_dir}/{st_package_name}/include",
+ vars=vars)
+
+ if config.is_internal_pyside_build():
+ # <install>/lib/site-packages/pyside2uic/* ->
+ # <setup>/pyside2uic
+ copydir(
+ "{site_packages_dir}/pyside2uic",
+ "{st_build_dir}/pyside2uic",
+ force=False, vars=vars)
+ if sys.version_info[0] > 2:
+ rmtree("{st_build_dir}/pyside2uic/port_v2".format(**vars))
+ else:
+ rmtree("{st_build_dir}/pyside2uic/port_v3".format(**vars))
+
+ # <install>/bin/pyside2-uic -> {st_package_name}/scripts/uic.py
+ makefile(
+ "{st_build_dir}/{st_package_name}/scripts/__init__.py",
+ vars=vars)
+ copyfile(
+ "{install_dir}/bin/pyside2-uic",
+ "{st_build_dir}/{st_package_name}/scripts/uic.py",
+ force=False, vars=vars)
+
+ # For setting up setuptools entry points
+ copyfile(
+ "{install_dir}/bin/pyside_tool.py",
+ "{st_build_dir}/{st_package_name}/scripts/pyside_tool.py",
+ force=False, vars=vars)
+
+ # <install>/bin/* -> {st_package_name}/
+ executables.extend(copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=[
+ "pyside2-lupdate",
+ "pyside2-rcc",
+ ],
+ recursive=False, vars=vars))
+
+ # <install>/lib/lib* -> {st_package_name}/
+ copydir(
+ "{install_dir}/lib/",
+ "{st_build_dir}/{st_package_name}",
+ filter=[
+ adjusted_lib_name("libpyside*",
+ generated_config['pyside_library_soversion']),
+ ],
+ recursive=False, vars=vars, force_copy_symlinks=True)
+
+ # <install>/share/{st_package_name}/typesystems/* ->
+ # <setup>/{st_package_name}/typesystems
+ copydir(
+ "{install_dir}/share/{st_package_name}/typesystems",
+ "{st_build_dir}/{st_package_name}/typesystems",
+ vars=vars)
+
+ # <source>/pyside2/{st_package_name}/support/* ->
+ # <setup>/{st_package_name}/support/*
+ copydir(
+ "{build_dir}/pyside2/{st_package_name}/support",
+ "{st_build_dir}/{st_package_name}/support",
+ vars=vars)
+
+ if not OPTION_NOEXAMPLES:
+ # examples/* -> <setup>/{st_package_name}/examples
+ copydir(os.path.join(self.script_dir, "examples"),
+ "{st_build_dir}/{st_package_name}/examples",
+ force=False, vars=vars)
+ # Re-generate examples Qt resource files for Python 3
+ # compatibility
+ if sys.version_info[0] == 3:
+ examples_path = "{st_build_dir}/{st_package_name}/examples".format(
+ **vars)
+ pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
+ **vars)
+ pyside_rcc_options = '-py3'
+ regenerate_qt_resources(examples_path, pyside_rcc_path,
+ pyside_rcc_options)
+
# Copy Qt libs to package
if OPTION_STANDALONE:
- vars['built_modules'] = config['built_modules']
- if sys.platform == 'darwin':
- prepare_standalone_package_macos(self, executables, vars)
- else:
- prepare_standalone_package_linux(self, executables, vars)
+ if config.is_internal_pyside_build() or config.is_internal_shiboken_generator_build():
+ vars['built_modules'] = generated_config['built_modules']
+ if sys.platform == 'darwin':
+ prepare_standalone_package_macos(self, vars)
+ else:
+ prepare_standalone_package_linux(self, vars)
- # Copy over clang before rpath patching.
- self.prepare_standalone_clang(is_win=False)
+ if config.is_internal_shiboken_generator_build():
+ # Copy over clang before rpath patching.
+ self.prepare_standalone_clang(is_win=False)
# Update rpath to $ORIGIN
- if (sys.platform.startswith('linux') or
- sys.platform.startswith('darwin')):
- self.update_rpath("{pyside_package_dir}/PySide2".format(**vars),
- executables)
+ if sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
+ rpath_path = "{st_build_dir}/{st_package_name}".format(**vars)
+ self.update_rpath(rpath_path, executables)
diff --git a/build_scripts/platforms/windows_desktop.py b/build_scripts/platforms/windows_desktop.py
index aa9487ec6..6307238a1 100644
--- a/build_scripts/platforms/windows_desktop.py
+++ b/build_scripts/platforms/windows_desktop.py
@@ -38,153 +38,225 @@
#############################################################################
import functools
-import os, re, sys
+import os
+import sys
+
+from ..config import config
from ..options import *
from ..utils import copydir, copyfile, rmtree, makefile
from ..utils import regenerate_qt_resources, filter_match
from ..utils import download_and_extract_7z
+
def prepare_packages_win32(self, vars):
# For now, debug symbols will not be shipped into the package.
copy_pdbs = False
pdbs = []
if (self.debug or self.build_type == 'RelWithDebInfo') and copy_pdbs:
pdbs = ['*.pdb']
- # <install>/lib/site-packages/PySide2/* -> <setup>/PySide2
+
+ # <install>/lib/site-packages/{st_package_name}/* ->
+ # <setup>/{st_package_name}
+ # This copies the module .pyd files and various .py files
+ # (__init__, config, git version, etc.)
copydir(
- "{site_packages_dir}/PySide2",
- "{pyside_package_dir}/PySide2",
+ "{site_packages_dir}/{st_package_name}",
+ "{st_build_dir}/{st_package_name}",
vars=vars)
- built_modules = self.get_built_pyside_config(vars)['built_modules']
- # <build>/pyside2/PySide2/*.pdb -> <setup>/PySide2
- copydir(
- "{build_dir}/pyside2/PySide2",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
+ if config.is_internal_shiboken_module_build():
+ # <build>/shiboken2/doc/html/* ->
+ # <setup>/{st_package_name}/docs/shiboken2
+ copydir(
+ "{build_dir}/shiboken2/doc/html",
+ "{st_build_dir}/{st_package_name}/docs/shiboken2",
+ force=False, vars=vars)
+
+ # <install>/bin/*.dll -> {st_package_name}/
+ copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["shiboken*.dll"],
+ recursive=False, vars=vars)
- # <build>/shiboken2/doc/html/* ->
- # <setup>/PySide2/docs/shiboken2
- copydir(
- "{build_dir}/shiboken2/doc/html",
- "{pyside_package_dir}/PySide2/docs/shiboken2",
- force=False, vars=vars)
-
- # <install>/lib/site-packages/shiboken2.pyd ->
- # <setup>/PySide2/shiboken2.pyd
- shiboken_module_name = 'shiboken2.pyd'
- shiboken_src_path = "{site_packages_dir}".format(**vars)
- maybe_shiboken_names = [f for f in os.listdir(shiboken_src_path)
- if re.match(r'shiboken.*\.pyd', f)]
- if maybe_shiboken_names:
- shiboken_module_name = maybe_shiboken_names[0]
- vars.update({'shiboken_module_name': shiboken_module_name})
- copyfile(
- "{site_packages_dir}/{shiboken_module_name}",
- "{pyside_package_dir}/PySide2/{shiboken_module_name}",
- vars=vars)
- # @TODO: Fix this .pdb file not to overwrite release
- # {shibokengenerator}.pdb file.
- # Task-number: PYSIDE-615
- copydir(
- "{build_dir}/shiboken2/shibokenmodule",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
+ # <install>/lib/*.lib -> {st_package_name}/
+ copydir(
+ "{install_dir}/lib/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["shiboken*.lib"],
+ recursive=False, vars=vars)
- # <install>/lib/site-packages/pyside2uic/* ->
- # <setup>/pyside2uic
- copydir(
- "{site_packages_dir}/pyside2uic",
- "{pyside_package_dir}/pyside2uic",
- force=False, vars=vars)
- if sys.version_info[0] > 2:
- rmtree("{pyside_package_dir}/pyside2uic/port_v2".format(**vars))
- else:
- rmtree("{pyside_package_dir}/pyside2uic/port_v3".format(**vars))
+ # @TODO: Fix this .pdb file not to overwrite release
+ # {shibokengenerator}.pdb file.
+ # Task-number: PYSIDE-615
+ copydir(
+ "{build_dir}/shiboken2/shibokenmodule",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
- # <install>/bin/pyside2-uic -> PySide2/scripts/uic.py
- makefile(
- "{pyside_package_dir}/PySide2/scripts/__init__.py",
- vars=vars)
- copyfile(
- "{install_dir}/bin/pyside2-uic",
- "{pyside_package_dir}/PySide2/scripts/uic.py",
- force=False, vars=vars)
-
- # For setting up entry points
- copyfile(
- "{install_dir}/bin/pyside_tool.py",
- "{pyside_package_dir}/PySide2/scripts/pyside_tool.py",
- force=False, vars=vars)
-
- # <install>/bin/*.exe,*.dll,*.pdb -> PySide2/
- copydir(
- "{install_dir}/bin/",
- "{pyside_package_dir}/PySide2",
- filter=["*.exe", "*.dll"],
- recursive=False, vars=vars)
- # @TODO: Fix this .pdb file not to overwrite release
- # {shibokenmodule}.pdb file.
- # Task-number: PYSIDE-615
- copydir(
- "{build_dir}/shiboken2/generator",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
+ # pdb files for libshiboken and libpyside
+ copydir(
+ "{build_dir}/shiboken2/libshiboken",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
- # <install>/lib/*.lib -> PySide2/
- copydir(
- "{install_dir}/lib/",
- "{pyside_package_dir}/PySide2",
- filter=["*.lib"],
- recursive=False, vars=vars)
+ if config.is_internal_shiboken_generator_build():
+ # <install>/bin/*.dll -> {st_package_name}/
+ copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["shiboken*.exe"],
+ recursive=False, vars=vars)
- # <install>/share/PySide2/typesystems/* ->
- # <setup>/PySide2/typesystems
- copydir(
- "{install_dir}/share/PySide2/typesystems",
- "{pyside_package_dir}/PySide2/typesystems",
- vars=vars)
+ # Used to create scripts directory.
+ makefile(
+ "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py",
+ vars=vars)
- # <install>/include/* -> <setup>/PySide2/include
- copydir(
- "{install_dir}/include",
- "{pyside_package_dir}/PySide2/include",
- vars=vars)
+ # For setting up setuptools entry points.
+ copyfile(
+ "{install_dir}/bin/shiboken_tool.py",
+ "{st_build_dir}/{st_package_name}/scripts/shiboken_tool.py",
+ force=False, vars=vars)
+
+ # @TODO: Fix this .pdb file not to overwrite release
+ # {shibokenmodule}.pdb file.
+ # Task-number: PYSIDE-615
+ copydir(
+ "{build_dir}/shiboken2/generator",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
- # <source>/pyside2/PySide2/support/* ->
- # <setup>/PySide2/support/*
- copydir(
- "{build_dir}/pyside2/PySide2/support",
- "{pyside_package_dir}/PySide2/support",
- vars=vars)
+ if config.is_internal_shiboken_generator_build() or config.is_internal_pyside_build():
+ # <install>/include/* -> <setup>/{st_package_name}/include
+ copydir(
+ "{install_dir}/include/{cmake_package_name}",
+ "{st_build_dir}/{st_package_name}/include",
+ vars=vars)
+
+ if config.is_internal_pyside_build():
+ # <build>/pyside2/{st_package_name}/*.pdb ->
+ # <setup>/{st_package_name}
+ copydir(
+ "{build_dir}/pyside2/{st_package_name}",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
+
+ # <install>/lib/site-packages/pyside2uic/* ->
+ # <setup>/pyside2uic
+ copydir(
+ "{site_packages_dir}/pyside2uic",
+ "{st_build_dir}/pyside2uic",
+ force=False, vars=vars)
+ if sys.version_info[0] > 2:
+ rmtree("{st_build_dir}/pyside2uic/port_v2".format(**vars))
+ else:
+ rmtree("{st_build_dir}/pyside2uic/port_v3".format(**vars))
+
+ # <install>/bin/pyside2-uic -> {st_package_name}/scripts/uic.py
+ makefile(
+ "{st_build_dir}/{st_package_name}/scripts/__init__.py",
+ vars=vars)
+ copyfile(
+ "{install_dir}/bin/pyside2-uic",
+ "{st_build_dir}/{st_package_name}/scripts/uic.py",
+ force=False, vars=vars)
+
+ # For setting up setuptools entry points
+ copyfile(
+ "{install_dir}/bin/pyside_tool.py",
+ "{st_build_dir}/{st_package_name}/scripts/pyside_tool.py",
+ force=False, vars=vars)
+
+ # <install>/bin/*.exe,*.dll -> {st_package_name}/
+ copydir(
+ "{install_dir}/bin/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["pyside*.exe", "pyside*.dll"],
+ recursive=False, vars=vars)
+
+ # <install>/lib/*.lib -> {st_package_name}/
+ copydir(
+ "{install_dir}/lib/",
+ "{st_build_dir}/{st_package_name}",
+ filter=["pyside*.lib"],
+ recursive=False, vars=vars)
+
+ # <install>/share/{st_package_name}/typesystems/* ->
+ # <setup>/{st_package_name}/typesystems
+ copydir(
+ "{install_dir}/share/{st_package_name}/typesystems",
+ "{st_build_dir}/{st_package_name}/typesystems",
+ vars=vars)
+
+ # <source>/pyside2/{st_package_name}/support/* ->
+ # <setup>/{st_package_name}/support/*
+ copydir(
+ "{build_dir}/pyside2/{st_package_name}/support",
+ "{st_build_dir}/{st_package_name}/support",
+ vars=vars)
+
+ copydir(
+ "{build_dir}/pyside2/libpyside",
+ "{st_build_dir}/{st_package_name}",
+ filter=pdbs,
+ recursive=False, vars=vars)
- if not OPTION_NOEXAMPLES:
- # examples/* -> <setup>/PySide2/examples
- copydir(os.path.join(self.script_dir, "examples"),
- "{pyside_package_dir}/PySide2/examples",
+ if not OPTION_NOEXAMPLES:
+ # examples/* -> <setup>/{st_package_name}/examples
+ copydir(os.path.join(self.script_dir, "examples"),
+ "{st_build_dir}/{st_package_name}/examples",
+ force=False, vars=vars)
+ # Re-generate examples Qt resource files for Python 3
+ # compatibility
+ if sys.version_info[0] == 3:
+ examples_path = "{st_build_dir}/{st_package_name}/examples".format(
+ **vars)
+ pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
+ **vars)
+ pyside_rcc_options = '-py3'
+ regenerate_qt_resources(examples_path, pyside_rcc_path,
+ pyside_rcc_options)
+
+ if vars['ssl_libs_dir']:
+ # <ssl_libs>/* -> <setup>/{st_package_name}/openssl
+ copydir("{ssl_libs_dir}", "{st_build_dir}/{st_package_name}/openssl",
+ filter=[
+ "libeay32.dll",
+ "ssleay32.dll"],
force=False, vars=vars)
- # Re-generate examples Qt resource files for Python 3
- # compatibility
- if sys.version_info[0] == 3:
- examples_path = "{pyside_package_dir}/PySide2/examples".format(
- **vars)
- pyside_rcc_path = "{install_dir}/bin/pyside2-rcc".format(
- **vars)
- pyside_rcc_options = '-py3'
- regenerate_qt_resources(examples_path, pyside_rcc_path,
- pyside_rcc_options)
-
- # <ssl_libs>/* -> <setup>/PySide2/openssl
- copydir("{ssl_libs_dir}", "{pyside_package_dir}/PySide2/openssl",
- filter=[
- "libeay32.dll",
- "ssleay32.dll"],
- force=False, vars=vars)
-
- # <qt>/bin/*.dll and Qt *.exe -> <setup>/PySide2
+
+ if config.is_internal_pyside_build() or config.is_internal_shiboken_generator_build():
+ copy_qt_artifacts(self, copy_pdbs, vars)
+
+
+def copy_qt_artifacts(self, copy_pdbs, vars):
+ built_modules = self.get_built_pyside_config(vars)['built_modules']
+
+ constrain_modules = None
+ copy_plugins = True
+ copy_qml = True
+ copy_translations = True
+ copy_qt_conf = True
+ copy_qt_permanent_artifacts = True
+ copy_msvc_redist = False
+ copy_clang = False
+
+ if config.is_internal_shiboken_generator_build():
+ constrain_modules = ["Core", "Network", "Xml", "XmlPatterns"]
+ copy_plugins = False
+ copy_qml = False
+ copy_translations = False
+ copy_qt_conf = False
+ copy_qt_permanent_artifacts = False
+ copy_msvc_redist = True
+ copy_clang = True
+
+ # <qt>/bin/*.dll and Qt *.exe -> <setup>/{st_package_name}
qt_artifacts_permanent = [
"opengl*.dll",
"d3d*.dll",
@@ -195,6 +267,7 @@ def prepare_packages_win32(self, vars):
"lconvert.exe",
"qtdiag.exe"
]
+
# MSVC redistributable
msvc_redist = [
"concrt140.dll",
@@ -218,8 +291,14 @@ def prepare_packages_win32(self, vars):
else:
egl_suffix = ''
qt_artifacts_egl = [a.format(egl_suffix) for a in qt_artifacts_egl]
- qt_artifacts_permanent += qt_artifacts_egl
- qt_artifacts_permanent += msvc_redist
+
+ artifacts = []
+ if copy_qt_permanent_artifacts:
+ artifacts += qt_artifacts_permanent
+ artifacts += qt_artifacts_egl
+
+ if copy_msvc_redist:
+ artifacts += msvc_redist
# Extract Qt dependency dll's when building on Qt CI
# There is no proper CI env variable, so using agent launch params
@@ -231,15 +310,22 @@ def prepare_packages_win32(self, vars):
zip_file = "pyside_qt_deps_32.7z"
download_and_extract_7z(redist_url + zip_file, "{qt_bin_dir}".format(**vars))
- copydir("{qt_bin_dir}", "{pyside_package_dir}/PySide2",
- filter=qt_artifacts_permanent,
- recursive=False, vars=vars)
+ if artifacts:
+ copydir("{qt_bin_dir}",
+ "{st_build_dir}/{st_package_name}",
+ filter=artifacts, recursive=False, vars=vars)
- # <qt>/bin/*.dll and Qt *.pdbs -> <setup>/PySide2 part two
+ # <qt>/bin/*.dll and Qt *.pdbs -> <setup>/{st_package_name} part two
# File filter to copy only debug or only release files.
- qt_dll_patterns = ["Qt5*{}.dll", "lib*{}.dll"]
- if copy_pdbs:
- qt_dll_patterns += ["Qt5*{}.pdb", "lib*{}.pdb"]
+ if constrain_modules:
+ qt_dll_patterns = ["Qt5" + x + "{}.dll" for x in constrain_modules]
+ if copy_pdbs:
+ qt_dll_patterns += ["Qt5" + x + "{}.pdb" for x in constrain_modules]
+ else:
+ qt_dll_patterns = ["Qt5*{}.dll", "lib*{}.dll"]
+ if copy_pdbs:
+ qt_dll_patterns += ["Qt5*{}.pdb", "lib*{}.pdb"]
+
def qt_build_config_filter(patterns, file_name, file_full_path):
release = [a.format('') for a in patterns]
debug = [a.format('d') for a in patterns]
@@ -289,56 +375,60 @@ def prepare_packages_win32(self, vars):
return False
qt_dll_filter = functools.partial(qt_build_config_filter,
- qt_dll_patterns)
- copydir("{qt_bin_dir}", "{pyside_package_dir}/PySide2",
- file_filter_function=qt_dll_filter,
- recursive=False, vars=vars)
-
- # <qt>/plugins/* -> <setup>/PySide2/plugins
- plugin_dll_patterns = ["*{}.dll"]
- pdb_pattern = "*{}.pdb"
- if copy_pdbs:
- plugin_dll_patterns += [pdb_pattern]
- plugin_dll_filter = functools.partial(qt_build_config_filter,
- plugin_dll_patterns)
- copydir("{qt_plugins_dir}", "{pyside_package_dir}/PySide2/plugins",
- file_filter_function=plugin_dll_filter,
- vars=vars)
+ qt_dll_patterns)
+ copydir("{qt_bin_dir}",
+ "{st_build_dir}/{st_package_name}",
+ file_filter_function=qt_dll_filter,
+ recursive=False, vars=vars)
- # <qt>/translations/* -> <setup>/PySide2/translations
- copydir("{qt_translations_dir}",
- "{pyside_package_dir}/PySide2/translations",
- filter=["*.qm", "*.pak"],
- force=False,
- vars=vars)
+ if copy_plugins:
+ # <qt>/plugins/* -> <setup>/{st_package_name}/plugins
+ plugin_dll_patterns = ["*{}.dll"]
+ pdb_pattern = "*{}.pdb"
+ if copy_pdbs:
+ plugin_dll_patterns += [pdb_pattern]
+ plugin_dll_filter = functools.partial(qt_build_config_filter,
+ plugin_dll_patterns)
+ copydir("{qt_plugins_dir}", "{st_build_dir}/{st_package_name}/plugins",
+ file_filter_function=plugin_dll_filter,
+ vars=vars)
- # <qt>/qml/* -> <setup>/PySide2/qml
- qml_dll_patterns = ["*{}.dll"]
- qml_ignore_patterns = qml_dll_patterns + [pdb_pattern]
- qml_ignore = [a.format('') for a in qml_ignore_patterns]
+ if copy_translations:
+ # <qt>/translations/* -> <setup>/{st_package_name}/translations
+ copydir("{qt_translations_dir}",
+ "{st_build_dir}/{st_package_name}/translations",
+ filter=["*.qm", "*.pak"],
+ force=False,
+ vars=vars)
- # Copy all files that are not dlls and pdbs (.qml, qmldir).
- copydir("{qt_qml_dir}", "{pyside_package_dir}/PySide2/qml",
- ignore=qml_ignore,
- force=False,
- recursive=True,
- vars=vars)
+ if copy_qml:
+ # <qt>/qml/* -> <setup>/{st_package_name}/qml
+ qml_dll_patterns = ["*{}.dll"]
+ qml_ignore_patterns = qml_dll_patterns + [pdb_pattern]
+ qml_ignore = [a.format('') for a in qml_ignore_patterns]
+
+ # Copy all files that are not dlls and pdbs (.qml, qmldir).
+ copydir("{qt_qml_dir}", "{st_build_dir}/{st_package_name}/qml",
+ ignore=qml_ignore,
+ force=False,
+ recursive=True,
+ vars=vars)
- if copy_pdbs:
- qml_dll_patterns += [pdb_pattern]
- qml_dll_filter = functools.partial(qt_build_config_filter,
- qml_dll_patterns)
+ if copy_pdbs:
+ qml_dll_patterns += [pdb_pattern]
+ qml_dll_filter = functools.partial(qt_build_config_filter,
+ qml_dll_patterns)
- # Copy all dlls (and possibly pdbs).
- copydir("{qt_qml_dir}", "{pyside_package_dir}/PySide2/qml",
- file_filter_function=qml_dll_filter,
- force=False,
- recursive=True,
- vars=vars)
+ # Copy all dlls (and possibly pdbs).
+ copydir("{qt_qml_dir}", "{st_build_dir}/{st_package_name}/qml",
+ file_filter_function=qml_dll_filter,
+ force=False,
+ recursive=True,
+ vars=vars)
if self.is_webengine_built(built_modules):
copydir("{qt_prefix_dir}/resources",
- "{pyside_package_dir}/PySide2/resources",
+ "{st_build_dir}/{st_package_name}/resources",
filter=None,
recursive=False,
vars=vars)
@@ -346,26 +436,16 @@ def prepare_packages_win32(self, vars):
filter = 'QtWebEngineProcess{}.exe'.format(
'd' if self.debug else '')
copydir("{qt_bin_dir}",
- "{pyside_package_dir}/PySide2",
+ "{st_build_dir}/{st_package_name}",
filter=[filter],
recursive=False, vars=vars)
- # Copy the qt.conf file to prefix dir.
- copyfile(
- "{build_dir}/pyside2/PySide2/qt.conf",
- "{pyside_package_dir}/PySide2",
- vars=vars)
-
- self.prepare_standalone_clang(is_win=True)
+ if copy_qt_conf:
+ # Copy the qt.conf file to prefix dir.
+ copyfile(
+ "{build_dir}/pyside2/{st_package_name}/qt.conf",
+ "{st_build_dir}/{st_package_name}",
+ vars=vars)
- # pdb files for libshiboken and libpyside
- copydir(
- "{build_dir}/shiboken2/libshiboken",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
- copydir(
- "{build_dir}/pyside2/libpyside",
- "{pyside_package_dir}/PySide2",
- filter=pdbs,
- recursive=False, vars=vars)
+ if copy_clang:
+ self.prepare_standalone_clang(is_win=True)
diff --git a/build_scripts/setup_runner.py b/build_scripts/setup_runner.py
new file mode 100644
index 000000000..a1526793e
--- /dev/null
+++ b/build_scripts/setup_runner.py
@@ -0,0 +1,165 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import sys, os, textwrap
+
+from build_scripts.config import config
+from build_scripts.main import get_package_version, get_setuptools_extension_modules
+from build_scripts.main import cmd_class_dict
+from build_scripts.options import OPTION_BUILD_TYPE, OPTION_INTERNAL_BUILD_TYPE
+from build_scripts.utils import run_process
+
+from setuptools import setup
+
+
+class SetupRunner(object):
+ def __init__(self, orig_argv):
+ self.invocations_list = []
+
+ # Keep the original args around in case we ever need to pass
+ # modified arguments to the sub invocations.
+ self.orig_argv = orig_argv
+ self.sub_argv = list(orig_argv)
+
+ self.setup_script_dir = os.getcwd()
+
+ @staticmethod
+ def cmd_line_argument_is_in_args(argument, args):
+ """ Check if command line argument was passed in args. """
+ return any(arg for arg in list(args) if "--" + argument in arg)
+
+ @staticmethod
+ def remove_cmd_line_argument_in_args(argument, args):
+ """ Remove command line argument from args. """
+ return [arg for arg in list(args) if "--" + argument not in arg]
+
+ @staticmethod
+ def construct_cmd_line_argument(name, value=None):
+ """ Constructs a command line argument given name and value. """
+ if not value:
+ return "--{}".format(name)
+ return "--{}={}".format(name, value)
+
+ @staticmethod
+ def construct_internal_build_type_cmd_line_argument(internal_build_type):
+ return SetupRunner.construct_cmd_line_argument("internal-build-type", internal_build_type)
+
+ def add_setup_internal_invocation(self, build_type, reuse_build=False):
+ """ Enqueues a script sub-invocation to be executed later. """
+ internal_build_type_arg = self.construct_internal_build_type_cmd_line_argument(build_type)
+ setup_cmd = [sys.executable] + self.sub_argv + [internal_build_type_arg]
+
+ # Add --reuse-build option if requested and not already present.
+ if reuse_build and not self.cmd_line_argument_is_in_args("reuse-build", self.sub_argv):
+ setup_cmd.append(self.construct_cmd_line_argument("reuse-build"))
+ self.invocations_list.append(setup_cmd)
+
+ def run_setup(self):
+ """
+ Decide what kind of build is requested and then execute it.
+ In the top-level invocation case, the script
+ will spawn setup.py again (possibly multiple times).
+ In the internal invocation case, the script
+ will run setuptools.setup().
+ """
+
+ # Prepare initial config.
+ config.init_config(build_type=OPTION_BUILD_TYPE,
+ internal_build_type=OPTION_INTERNAL_BUILD_TYPE,
+ cmd_class_dict=cmd_class_dict,
+ package_version=get_package_version(),
+ ext_modules=get_setuptools_extension_modules(),
+ setup_script_dir=self.setup_script_dir)
+
+ # This is an internal invocation of setup.py, so start actual
+ # build.
+ if config.is_internal_invocation():
+ if config.internal_build_type not in config.get_allowed_internal_build_values():
+ raise RuntimeError("Invalid '{}' option given to --internal-build-type. "
+ .format(config.internal_build_type))
+ self.run_setuptools_setup()
+ return
+
+ # This is a top-level invocation of setup.py, so figure out what
+ # modules we will build and depending on that, call setup.py
+ # multiple times with different arguments.
+ if config.build_type not in config.get_allowed_top_level_build_values():
+ raise RuntimeError("Invalid '{}' option given to --build-type. "
+ .format(config.build_type))
+
+ # Build everything: shiboken2, shiboken2-generator and PySide2.
+ if config.is_top_level_build_all():
+ self.add_setup_internal_invocation(config.shiboken_module_option_name)
+
+ # Reuse the shiboken build for the generator package instead
+ # of rebuilding it again.
+ self.add_setup_internal_invocation(config.shiboken_generator_option_name,
+ reuse_build=True)
+
+ self.add_setup_internal_invocation(config.pyside_option_name)
+
+ elif config.is_top_level_build_shiboken_module():
+ self.add_setup_internal_invocation(config.shiboken_module_option_name)
+
+ elif config.is_top_level_build_shiboken_generator():
+ self.add_setup_internal_invocation(config.shiboken_generator_option_name)
+
+ elif config.is_top_level_build_pyside():
+ self.add_setup_internal_invocation(config.pyside_option_name)
+
+ for cmd in self.invocations_list:
+ cmd_as_string = " ".join(cmd)
+ print("\nRunning process: {}\n".format(cmd_as_string))
+ exit_code = run_process(cmd)
+ if exit_code != 0:
+ msg = textwrap.dedent("""
+ setup.py invocation failed with exit code: {}.\n\n
+ setup.py invocation was: {}
+ """).format(exit_code, cmd_as_string)
+ raise RuntimeError(msg)
+
+ @staticmethod
+ def run_setuptools_setup():
+ """
+ Runs setuptools.setup() once in a single setup.py
+ sub-invocation.
+ """
+
+ kwargs = config.setup_kwargs
+ setup(**kwargs)
diff --git a/build_scripts/utils.py b/build_scripts/utils.py
index 7160630d1..741de73b9 100644
--- a/build_scripts/utils.py
+++ b/build_scripts/utils.py
@@ -39,17 +39,13 @@
import sys
import os
-import stat
import re
import stat
import errno
-import time
import shutil
import subprocess
import fnmatch
-import glob
import itertools
-import popenasync
import glob
# There is no urllib.request in Python2
@@ -58,11 +54,9 @@ try:
except ImportError:
import urllib
-from distutils import log
+import distutils.log as log
from distutils.errors import DistutilsOptionError
from distutils.errors import DistutilsSetupError
-from distutils.spawn import spawn
-from distutils.spawn import DistutilsExecError
try:
WindowsError
@@ -70,32 +64,6 @@ except NameError:
WindowsError = None
-def has_option(name):
- try:
- sys.argv.remove("--{}".format(name))
- return True
- except ValueError:
- pass
- return False
-
-
-def option_value(name):
- for index, option in enumerate(sys.argv):
- if option == '--' + name:
- if index+1 >= len(sys.argv):
- raise DistutilsOptionError("The option {} requires a "
- "value".format(option))
- value = sys.argv[index+1]
- sys.argv[index:index+2] = []
- return value
- if option.startswith('--' + name + '='):
- value = option[len(name)+3:]
- sys.argv[index:index+1] = []
- return value
- env_val = os.getenv(name.upper().replace('-', '_'))
- return env_val
-
-
def filter_match(name, patterns):
for pattern in patterns:
if pattern is None:
@@ -182,7 +150,6 @@ def find_vcdir(version):
"""
from distutils.msvc9compiler import VS_BASE
from distutils.msvc9compiler import Reg
- from distutils import log
vsbase = VS_BASE % version
try:
productdir = Reg.get_value(r"{}\Setup\VC".format(vsbase), "productdir")
@@ -416,13 +383,15 @@ def rmtree(dirname, ignore=False):
os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
func(path)
else:
- raise
+ raise IOError
shutil.rmtree(dirname, ignore_errors=ignore, onerror=handle_remove_readonly)
def run_process_output(args, initial_env=None):
if initial_env is None:
initial_env = os.environ
- std_out = subprocess.Popen(args, env = initial_env, universal_newlines = 1,
+ std_out = subprocess.Popen(args,
+ env = initial_env,
+ universal_newlines = 1,
stdout=subprocess.PIPE).stdout
result = []
for raw_line in std_out.readlines():
@@ -431,53 +400,21 @@ def run_process_output(args, initial_env=None):
return result
def run_process(args, initial_env=None):
- def _log(buffer, check_new_line=False):
- ends_with_new_line = False
- if buffer.endswith('\n'):
- ends_with_new_line = True
- if check_new_line and buffer.find('\n') == -1:
- return buffer
- lines = buffer.splitlines()
- buffer = ''
- if check_new_line and not ends_with_new_line:
- buffer = lines[-1]
- lines = lines[:-1]
- for line in lines:
- log.info(line.rstrip('\r'))
- return buffer
- _log("Running process in {0}: {1}".format(os.getcwd(),
- " ".join([(" " in x and '"{0}"'.format(x) or x) for x in args])))
-
- if sys.platform != "win32":
- try:
- spawn(args)
- return 0
- except DistutilsExecError:
- return -1
-
- shell = False
- if sys.platform == "win32":
- shell = True
+ """
+ Run process until completion and return the process exit code.
+ Prints both stdout and stderr to the console.
+ No output is captured.
+ """
+ log.info("Running process in directory {0}: command {1}".format(
+ os.getcwd(),
+ " ".join([(" " in x and '"{0}"'.format(x) or x) for x in args]))
+ )
if initial_env is None:
initial_env = os.environ
- proc = popenasync.Popen(args,
- stdin = subprocess.PIPE,
- stdout = subprocess.PIPE,
- stderr = subprocess.STDOUT,
- universal_newlines = 1,
- shell = shell,
- env = initial_env)
-
- log_buffer = None;
- while proc.poll() is None:
- log_buffer = _log(proc.read_async(wait=0.1, e=0))
- if log_buffer:
- _log(log_buffer)
-
- proc.wait()
- return proc.returncode
+ exit_code = subprocess.call(args, stderr=subprocess.STDOUT, env=initial_env)
+ return exit_code
def get_environment_from_batch_command(env_cmd, initial=None):
@@ -665,6 +602,9 @@ def macos_get_rpaths(libpath):
ctr += 3
return rpaths
+def macos_add_rpath(rpath, library_path):
+ back_tick('install_name_tool -add_rpath {rpath} {library_path}'.format(
+ rpath=rpath, library_path=library_path))
def macos_fix_rpaths_for_library(library_path, qt_lib_dir):
""" Adds required rpath load commands to given library.
@@ -703,8 +643,7 @@ def macos_fix_rpaths_for_library(library_path, qt_lib_dir):
break
if needs_loader_path and "@loader_path" not in existing_rpath_commands:
- back_tick('install_name_tool -add_rpath {rpath} {library_path}'.format(
- rpath="@loader_path", library_path=library_path))
+ macos_add_rpath("@loader_path", library_path)
# If the library depends on a Qt library, add an rpath load comment
# pointing to the Qt lib directory.
@@ -738,8 +677,7 @@ def macos_add_qt_rpath(library_path, qt_lib_dir,
break
if needs_qt_rpath:
- back_tick('install_name_tool -add_rpath {rpath} {library_path}'.format(
- rpath=qt_lib_dir, library_path=library_path))
+ macos_add_rpath(qt_lib_dir, library_path)
# Find an executable specified by a glob pattern ('foo*') in the OS path
def find_glob_in_path(pattern):
@@ -996,6 +934,17 @@ def copy_icu_libs(patchelf, destination_lib_dir):
new_rpaths_string = ":".join(rpaths)
linux_set_rpaths(patchelf, qt_core_library_path, new_rpaths_string)
+
+def linux_run_read_elf(executable_path):
+ cmd = "readelf -d {}".format(executable_path)
+ (out, err, code) = back_tick(cmd, True)
+ if code != 0:
+ raise RuntimeError("Running `readelf -d {}` failed with error "
+ "output:\n {}. ".format(executable_path, err))
+ lines = split_and_strip(out)
+ return lines
+
+
def linux_set_rpaths(patchelf, executable_path, rpath_string):
""" Patches the `executable_path` with a new rpath string. """
@@ -1005,18 +954,32 @@ def linux_set_rpaths(patchelf, executable_path, rpath_string):
raise RuntimeError("Error patching rpath in {}".format(
executable_path))
+
+def linux_get_dependent_libraries(executable_path):
+ """
+ Returns a list of libraries that executable_path depends on.
+ """
+
+ lines = linux_run_read_elf(executable_path)
+ pattern = re.compile(r"^.+?\(NEEDED\).+?\[(.+?)\]$")
+
+ library_lines = []
+ for line in lines:
+ match = pattern.search(line)
+ if match:
+ library_line = match.group(1)
+ library_lines.append(library_line)
+
+ return library_lines
+
+
def linux_get_rpaths(executable_path):
"""
Returns a list of run path values embedded in the executable or just
an empty list.
"""
- cmd = "readelf -d {}".format(executable_path)
- (out, err, code) = back_tick(cmd, True)
- if code != 0:
- raise RuntimeError("Running `readelf -d {}` failed with error "
- "output:\n {}. ".format(executable_path, err))
- lines = split_and_strip(out)
+ lines = linux_run_read_elf(executable_path)
pattern = re.compile(r"^.+?\(RUNPATH\).+?\[(.+?)\]$")
rpath_line = None
@@ -1033,6 +996,7 @@ def linux_get_rpaths(executable_path):
return rpaths
+
def rpaths_has_origin(rpaths):
"""
Return True if the specified list of rpaths has an "$ORIGIN" value
@@ -1048,6 +1012,39 @@ def rpaths_has_origin(rpaths):
return True
return False
+
+def linux_needs_qt_rpath(executable_path):
+ """
+ Returns true if library_path depends on Qt libraries.
+ """
+
+ dependencies = linux_get_dependent_libraries(executable_path)
+
+ # Check if any library dependencies are Qt libraries (hacky).
+ needs_qt_rpath = False
+ for dep in dependencies:
+ if 'Qt' in dep:
+ needs_qt_rpath = True
+ break
+ return needs_qt_rpath
+
+
+def linux_fix_rpaths_for_library(patchelf, executable_path, qt_rpath, override=False):
+ """
+ Adds or overrides required rpaths in given executable / library.
+ """
+ rpaths = ['$ORIGIN/']
+ existing_rpaths = []
+ if not override:
+ existing_rpaths = linux_get_rpaths(executable_path)
+ rpaths.extend(existing_rpaths)
+
+ if linux_needs_qt_rpath(executable_path) and qt_rpath not in existing_rpaths:
+ rpaths.append(qt_rpath)
+
+ rpaths_string = ':'.join(rpaths)
+ linux_set_rpaths(patchelf, executable_path, rpaths_string)
+
def memoize(function):
"""
Decorator to wrap a function with a memoizing callable.
@@ -1076,9 +1073,27 @@ def get_python_dict(python_script_path):
"file: {}.".format(python_script_path))
raise
-def install_pip_dependencies(env_pip, packages):
+def install_pip_wheel_package(env_pip):
+ # Need to install an unreleased wheel version, due to a bug that
+ # will generate a wheel which will not be installable.
+ # See https://github.com/pypa/wheel/issues/263
+ wheel_url = "git+https://github.com/pypa/wheel.git@fbf3e3ada64d36ca7bb9c1422f5a1ccdba7e4dcf"
+ install_pip_package_from_url_specifier(env_pip, wheel_url)
+
+def install_pip_package_from_url_specifier(env_pip, url, upgrade=True):
+ args = [env_pip, "install", url]
+ if upgrade:
+ args.append("--upgrade")
+ args.append(url)
+ run_instruction(args, "Failed to install {}".format(url))
+
+def install_pip_dependencies(env_pip, packages, upgrade=True):
for p in packages:
- run_instruction([env_pip, "install", p], "Failed to install " + p)
+ args = [env_pip, "install"]
+ if upgrade:
+ args.append("--upgrade")
+ args.append(p)
+ run_instruction(args, "Failed to install " + p)
def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch):
_pExe = "python"
@@ -1105,9 +1120,11 @@ def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch):
_pExe = "python3"
return(_pExe, _env, env_pip, env_python)
-def run_instruction(instruction, error):
+def run_instruction(instruction, error, initial_env=None):
+ if initial_env is None:
+ initial_env = os.environ
print("Running Coin instruction: " + ' '.join(str(e) for e in instruction))
- result = subprocess.call(instruction)
+ result = subprocess.call(instruction, env=initial_env)
if result != 0:
print("ERROR : " + error)
exit(result)
@@ -1124,3 +1141,13 @@ def acceptCITestConfiguration(hostOS, hostOSVer, targetArch, compiler):
print("Disabled " + compiler + " to " + targetArch + " from Coin configuration")
return False
return True
+
+
+def get_ci_qmake_path(ci_install_dir, ci_host_os):
+ qmake_path = "--qmake={}".format(ci_install_dir)
+ if ci_host_os == "MacOS":
+ return qmake_path + "/bin/qmake"
+ elif ci_host_os == "Windows":
+ return qmake_path + "\\bin\\qmake.exe"
+ else:
+ return qmake_path + "/bin/qmake"
diff --git a/coin_build_instructions.py b/coin_build_instructions.py
index 9f9a74bc9..1104e996c 100644
--- a/coin_build_instructions.py
+++ b/coin_build_instructions.py
@@ -36,14 +36,16 @@
## $QT_END_LICENSE$
##
#############################################################################
-from build_scripts.utils import has_option
-from build_scripts.utils import option_value
+from build_scripts.options import has_option
+from build_scripts.options import option_value
from build_scripts.utils import install_pip_dependencies
+from build_scripts.utils import install_pip_wheel_package
from build_scripts.utils import get_qtci_virtualEnv
from build_scripts.utils import run_instruction
from build_scripts.utils import rmtree
from build_scripts.utils import get_python_dict
from build_scripts.utils import acceptCITestConfiguration
+from build_scripts.utils import get_ci_qmake_path
import os
# Values must match COIN thrift
@@ -98,19 +100,17 @@ def call_setup(python_ver):
_pExe, _env, env_pip, env_python = get_qtci_virtualEnv(python_ver, CI_HOST_OS, CI_HOST_ARCH, CI_TARGET_ARCH)
rmtree(_env, True)
run_instruction(["virtualenv", "-p", _pExe, _env], "Failed to create virtualenv")
- install_pip_dependencies(env_pip, ["six", "wheel"])
- cmd = [env_python, "setup.py"]
+
+ install_pip_dependencies(env_pip, ["six", "setuptools"])
+ install_pip_wheel_package(env_pip)
+
+ cmd = [env_python, "-u", "setup.py"]
if CI_RELEASE_CONF:
cmd += ["bdist_wheel", "--standalone"]
else:
cmd += ["build"]
- if CI_HOST_OS == "MacOS":
- cmd += ["--qmake=" + CI_ENV_INSTALL_DIR + "/bin/qmake"]
- elif CI_HOST_OS == "Windows":
-
- cmd += ["--qmake=" + CI_ENV_INSTALL_DIR + "\\bin\\qmake.exe"]
- else:
- cmd += ["--qmake=" + CI_ENV_INSTALL_DIR + "/bin/qmake"]
+ qmake_path = get_ci_qmake_path(CI_ENV_INSTALL_DIR, CI_HOST_OS)
+ cmd.append(qmake_path)
cmd += ["--build-tests",
"--jobs=4",
"--verbose-build"]
@@ -121,7 +121,23 @@ def call_setup(python_ver):
cmd += ["--package-timestamp=" + CI_INTEGRATION_ID]
- run_instruction(cmd, "Failed to run setup.py")
+ env = os.environ
+ if CI_HOST_OS == "MacOS":
+ # On Python 3, setuptools.dist.handle_display_options does some
+ # weird sys.stdout.detach-ing if the stdout encoding is
+ # different from utf-8. This causes issues when running
+ # subprocess.call() because that access the original stdout
+ # object stored in sys.__stdout__ which was detached, and
+ # results in an exception being thrown.
+ # The Coin macOS locale by default is US-ASCII, and that
+ # triggers the above issue. Set the encoding to UTF-8 which
+ # makes sure to skip over the detach-ing code.
+ # Relevant links to the issue:
+ # https://bugs.python.org/issue15216
+ # https://bitbucket.org/tarek/distribute/issues/334/fix-for-311-breaks-packages-that-use
+ # https://github.com/pypa/virtualenv/issues/359
+ env['LC_CTYPE'] = 'UTF-8'
+ run_instruction(cmd, "Failed to run setup.py", initial_env=env)
def run_build_instructions():
if not acceptCITestConfiguration(CI_HOST_OS, CI_HOST_OS_VER, CI_TARGET_ARCH, CI_COMPILER):
diff --git a/coin_test_instructions.py b/coin_test_instructions.py
index c2c5c07ea..a61a1c9fa 100644
--- a/coin_test_instructions.py
+++ b/coin_test_instructions.py
@@ -36,13 +36,15 @@
## $QT_END_LICENSE$
##
#############################################################################
-from build_scripts.utils import has_option
-from build_scripts.utils import option_value
+from build_scripts.options import has_option
+from build_scripts.options import option_value
from build_scripts.utils import install_pip_dependencies
+from build_scripts.utils import install_pip_wheel_package
from build_scripts.utils import get_qtci_virtualEnv
from build_scripts.utils import run_instruction
from build_scripts.utils import rmtree
from build_scripts.utils import acceptCITestConfiguration
+from build_scripts.utils import get_ci_qmake_path
import os
# Values must match COIN thrift
@@ -66,12 +68,21 @@ def call_testrunner(python_ver, buildnro):
_pExe, _env, env_pip, env_python = get_qtci_virtualEnv(python_ver, CI_HOST_OS, CI_HOST_ARCH, CI_TARGET_ARCH)
rmtree(_env, True)
run_instruction(["virtualenv", "-p", _pExe, _env], "Failed to create virtualenv")
- install_pip_dependencies(env_pip, ["six", "wheel"])
+ install_pip_dependencies(env_pip, ["six", "setuptools"])
+ install_pip_wheel_package(env_pip)
cmd = [env_python, "testrunner.py", "test",
"--blacklist", "build_history/blacklist.txt",
"--buildno=" + buildnro]
run_instruction(cmd, "Failed to run testrunner.py")
+ qmake_path = get_ci_qmake_path(CI_ENV_INSTALL_DIR, CI_HOST_OS)
+
+ # Try to install built wheels, and build some buildable examples.
+ if CI_RELEASE_CONF:
+ wheel_tester_path = os.path.join("testing", "wheel_tester.py")
+ cmd = [env_python, wheel_tester_path, qmake_path]
+ run_instruction(cmd, "Error while running wheel_tester.py")
+
def run_test_instructions():
if not acceptCITestConfiguration(CI_HOST_OS, CI_HOST_OS_VER, CI_TARGET_ARCH, CI_COMPILER):
exit()
diff --git a/examples/samplebinding/CMakeLists.txt b/examples/samplebinding/CMakeLists.txt
index 03ab85754..3852ed36f 100644
--- a/examples/samplebinding/CMakeLists.txt
+++ b/examples/samplebinding/CMakeLists.txt
@@ -40,7 +40,11 @@ set(generated_sources
# ================================== Shiboken detection ======================================
-
+# Use provided python interpreter if given.
+if(NOT python_interpreter)
+ find_program(python_interpreter "python")
+endif()
+message(STATUS "Using python interpreter: ${python_interpreter}")
# Macro to get various pyside / python include / link flags and paths.
# Uses the not entirely supported utils/pyside2_config.py file.
@@ -52,7 +56,8 @@ macro(pyside2_config option output_var)
endif()
execute_process(
- COMMAND python "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py" ${option}
+ COMMAND ${python_interpreter} "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py"
+ ${option}
OUTPUT_VARIABLE ${output_var}
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -64,14 +69,15 @@ macro(pyside2_config option output_var)
endif()
endmacro()
-# Query for the shiboken path, Python path, include paths and linker flags.
-pyside2_config(--pyside2 pyside2_path)
-pyside2_config(--python-include python_include_dir)
-pyside2_config(--shiboken-include shiboken_include_dir 1)
-pyside2_config(--shiboken-shared-libraries-cmake shiboken_shared_libraries 0)
-pyside2_config(--python-link-cmake python_linking_data 0)
+# Query for the shiboken generator path, Python path, include paths and linker flags.
+pyside2_config(--shiboken2-module-path shiboken2_module_path)
+pyside2_config(--shiboken2-generator-path shiboken2_generator_path)
+pyside2_config(--python-include-path python_include_dir)
+pyside2_config(--shiboken2-generator-include-path shiboken_include_dir 1)
+pyside2_config(--shiboken2-module-shared-libraries-cmake shiboken_shared_libraries 0)
+pyside2_config(--python-link-flags-cmake python_linking_data 0)
-set(shiboken_path "${pyside2_path}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
+set(shiboken_path "${shiboken2_generator_path}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
if(NOT EXISTS ${shiboken_path})
message(FATAL_ERROR "Shiboken executable not found at path: ${shiboken_path}")
endif()
@@ -87,7 +93,7 @@ endif()
# Enable rpaths so that the built shared libraries find their dependencies.
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
-set(CMAKE_INSTALL_RPATH ${pyside2_path} ${CMAKE_CURRENT_SOURCE_DIR})
+set(CMAKE_INSTALL_RPATH ${shiboken2_module_path} ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# =============================================================================================
# !!! End of dubious section.
diff --git a/examples/scriptableapplication/CMakeLists.txt b/examples/scriptableapplication/CMakeLists.txt
index 4119b6756..215d08961 100644
--- a/examples/scriptableapplication/CMakeLists.txt
+++ b/examples/scriptableapplication/CMakeLists.txt
@@ -14,6 +14,12 @@ set(CMAKE_CXX_STANDARD 11)
# Find required Qt packages.
find_package(Qt5 5.9 REQUIRED COMPONENTS Core Gui Widgets)
+# Use provided python interpreter if given.
+if(NOT python_interpreter)
+ find_program(python_interpreter "python")
+endif()
+message(STATUS "Using python interpreter: ${python_interpreter}")
+
# Macro to get various pyside / python include / link flags.
macro(pyside2_config option output_var)
if(${ARGC} GREATER 2)
@@ -23,7 +29,8 @@ macro(pyside2_config option output_var)
endif()
execute_process(
- COMMAND python "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py" ${option}
+ COMMAND ${python_interpreter} "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py"
+ ${option}
OUTPUT_VARIABLE ${output_var}
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -35,14 +42,20 @@ macro(pyside2_config option output_var)
endif()
endmacro()
-# Query for the PySide2 path, Python path, include paths and linker flags.
-pyside2_config(--pyside2 PYSIDE2_PATH)
-pyside2_config(--python-include PYTHON_INCLUDE_DIR)
-pyside2_config(--pyside2-include PYSIDE2_INCLUDE_DIR 1)
+# Query for the shiboken2-generator path, PySide2 path, Python path, include paths and linker flags.
+pyside2_config(--shiboken2-module-path SHIBOKEN2_MODULE_PATH)
+pyside2_config(--shiboken2-generator-path SHIBOKEN2_GENERATOR_PATH)
+pyside2_config(--pyside2-path PYSIDE2_PATH)
+
+pyside2_config(--python-include-path PYTHON_INCLUDE_DIR)
+pyside2_config(--shiboken2-generator-include-path SHIBOKEN2_GENERATOR_INCLUDE_DIR 1)
+pyside2_config(--pyside2-include-path PYSIDE2_INCLUDE_DIR 1)
+
+pyside2_config(--python-link-flags-cmake PYTHON_LINKING_DATA 0)
+pyside2_config(--shiboken2-module-shared-libraries-cmake SHIBOKEN2_MODULE_SHARED_LIBRARIES 0)
pyside2_config(--pyside2-shared-libraries-cmake PYSIDE2_SHARED_LIBRARIES 0)
-pyside2_config(--python-link-cmake PYTHON_LINKING_DATA 0)
-set(SHIBOKEN_PATH "${PYSIDE2_PATH}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
+set(SHIBOKEN_PATH "${SHIBOKEN2_GENERATOR_PATH}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}")
if(NOT EXISTS ${SHIBOKEN_PATH})
message(FATAL_ERROR "Shiboken executable not found at path: ${SHIBOKEN_PATH}")
@@ -122,7 +135,7 @@ endforeach()
# Enable rpaths so that the example can be executed from the build dir.
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
-set(CMAKE_INSTALL_RPATH ${PYSIDE2_PATH})
+set(CMAKE_INSTALL_RPATH ${PYSIDE2_PATH} ${SHIBOKEN2_MODULE_PATH})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# =============================================================================================
# !!! End of dubious section.
@@ -139,11 +152,13 @@ target_sources(${PROJECT_NAME} PUBLIC ${SOURCES})
# Apply relevant include and link flags.
target_include_directories(${PROJECT_NAME} PRIVATE ${PYTHON_INCLUDE_DIR})
+target_include_directories(${PROJECT_NAME} PRIVATE ${SHIBOKEN2_GENERATOR_INCLUDE_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${PYSIDE2_INCLUDE_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${PYSIDE2_ADDITIONAL_INCLUDES})
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets)
+target_link_libraries(${PROJECT_NAME} PRIVATE ${SHIBOKEN2_MODULE_SHARED_LIBRARIES})
target_link_libraries(${PROJECT_NAME} PRIVATE ${PYSIDE2_SHARED_LIBRARIES})
# Find and link to the python library.
@@ -176,7 +191,8 @@ if(WIN32)
# Add custom target to hard link PySide2 shared libraries (just like in qmake example), so you
# don't have to set PATH manually to point to the PySide2 package.
- foreach(LIBRARY_PATH ${PYSIDE2_SHARED_LIBRARIES})
+ set(shared_libraries ${SHIBOKEN2_MODULE_SHARED_LIBRARIES} ${PYSIDE2_SHARED_LIBRARIES})
+ foreach(LIBRARY_PATH ${shared_libraries})
string(REGEX REPLACE ".lib$" ".dll" LIBRARY_PATH ${LIBRARY_PATH})
get_filename_component(BASE_NAME ${LIBRARY_PATH} NAME)
file(TO_NATIVE_PATH ${LIBRARY_PATH} SOURCE_PATH)
diff --git a/examples/scriptableapplication/pyside2.pri b/examples/scriptableapplication/pyside2.pri
index 17be4392f..2da3bc880 100644
--- a/examples/scriptableapplication/pyside2.pri
+++ b/examples/scriptableapplication/pyside2.pri
@@ -1,30 +1,52 @@
PYSIDE_CONFIG = $$PWD/../utils/pyside2_config.py
-PYSIDE2 = $$system(python $$PYSIDE_CONFIG --pyside2)
+# Use provided python interpreter if given.
+isEmpty(python_interpreter) {
+ python_interpreter = python
+}
+message(Using python interpreter: $$python_interpreter)
+
+SHIBOKEN2_GENERATOR = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-generator-path)
+isEmpty(SHIBOKEN2_GENERATOR): error(Unable to locate the shiboken2-generator package location)
+
+SHIBOKEN2_MODULE = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-module-path)
+isEmpty(SHIBOKEN2_MODULE): error(Unable to locate the shiboken2 package location)
+
+PYSIDE2 = $$system($$python_interpreter $$PYSIDE_CONFIG --pyside2-path)
isEmpty(PYSIDE2): error(Unable to locate the PySide2 package location)
-PYTHON_INCLUDE = $$system(python $$PYSIDE_CONFIG --python-include)
+PYTHON_INCLUDE = $$system($$python_interpreter $$PYSIDE_CONFIG --python-include-path)
isEmpty(PYTHON_INCLUDE): error(Unable to locate the Python include headers directory)
-PYTHON_LFLAGS = $$system(python $$PYSIDE_CONFIG --python-link)
+PYTHON_LFLAGS = $$system($$python_interpreter $$PYSIDE_CONFIG --python-link-flags-qmake)
isEmpty(PYTHON_LFLAGS): error(Unable to locate the Python library for linking)
-PYSIDE2_INCLUDE = $$system(python $$PYSIDE_CONFIG --pyside2-include)
+SHIBOKEN2_INCLUDE = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-generator-include-path)
+isEmpty(SHIBOKEN2_INCLUDE): error(Unable to locate the shiboken include headers directory)
+
+PYSIDE2_INCLUDE = $$system($$python_interpreter $$PYSIDE_CONFIG --pyside2-include-path)
isEmpty(PYSIDE2_INCLUDE): error(Unable to locate the PySide2 include headers directory)
-PYSIDE2_LFLAGS = $$system(python $$PYSIDE_CONFIG --pyside2-link)
+SHIBOKEN2_LFLAGS = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-module-qmake-lflags)
+isEmpty(SHIBOKEN2_LFLAGS): error(Unable to locate the shiboken libraries for linking)
+
+PYSIDE2_LFLAGS = $$system($$python_interpreter $$PYSIDE_CONFIG --pyside2-qmake-lflags)
isEmpty(PYSIDE2_LFLAGS): error(Unable to locate the PySide2 libraries for linking)
-PYSIDE2_SHARED_LIBRARIES = $$system(python $$PYSIDE_CONFIG --pyside2-shared-libraries)
+SHIBOKEN2_SHARED_LIBRARIES = $$system($$python_interpreter $$PYSIDE_CONFIG --shiboken2-module-shared-libraries-qmake)
+isEmpty(SHIBOKEN2_SHARED_LIBRARIES): error(Unable to locate the used shiboken2 module shared libraries)
+
+PYSIDE2_SHARED_LIBRARIES = $$system($$python_interpreter $$PYSIDE_CONFIG --pyside2-shared-libraries-qmake)
isEmpty(PYSIDE2_SHARED_LIBRARIES): error(Unable to locate the used PySide2 shared libraries)
-INCLUDEPATH += "$$PYTHON_INCLUDE" $$PYSIDE2_INCLUDE
-LIBS += $$PYTHON_LFLAGS $$PYSIDE2_LFLAGS
+INCLUDEPATH += "$$PYTHON_INCLUDE" $$PYSIDE2_INCLUDE $$SHIBOKEN2_INCLUDE
+LIBS += $$PYTHON_LFLAGS $$PYSIDE2_LFLAGS $$SHIBOKEN2_LFLAGS
!build_pass:message(INCLUDEPATH is $$INCLUDEPATH)
!build_pass:message(LIBS are $$LIBS)
!build_pass:message(Using $$PYSIDE2)
!win32 {
- QMAKE_RPATHDIR += $$PYSIDE2
+ !build_pass:message(RPATH will include $$PYSIDE2 and $$SHIBOKEN2_MODULE)
+ QMAKE_RPATHDIR += $$PYSIDE2 $$SHIBOKEN2_MODULE
}
diff --git a/examples/scriptableapplication/scriptableapplication.pro b/examples/scriptableapplication/scriptableapplication.pro
index 8a09b0abf..8ebab9476 100644
--- a/examples/scriptableapplication/scriptableapplication.pro
+++ b/examples/scriptableapplication/scriptableapplication.pro
@@ -23,7 +23,7 @@ SHIBOKEN_OPTIONS = --generator-set=shiboken --enable-parent-ctor-heuristic \
win32:SHIBOKEN_OPTIONS += --avoid-protected-hack
# Prepare the shiboken tool
-QT_TOOL.shiboken.binary = $$system_path($$PYSIDE2/shiboken2)
+QT_TOOL.shiboken.binary = $$system_path($$SHIBOKEN2_GENERATOR/shiboken2)
qtPrepareTool(SHIBOKEN, shiboken)
# Shiboken run that adds the module wrapper to GENERATED_SOURCES
@@ -61,7 +61,7 @@ win32 {
hard_link_libraries.CONFIG = no_link target_predeps explicit_dependencies
hard_link_libraries.output = $$out_dir/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT}
hard_link_libraries.commands = mklink /H $$shell_path($$out_dir/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT}) $$shell_path(${QMAKE_FILE_IN})
- hard_link_libraries.input = PYSIDE2_SHARED_LIBRARIES
+ hard_link_libraries.input = PYSIDE2_SHARED_LIBRARIES SHIBOKEN2_SHARED_LIBRARIES
}
QMAKE_EXTRA_COMPILERS += shiboken module_wrapper_dummy_command
diff --git a/examples/utils/pyside2_config.py b/examples/utils/pyside2_config.py
index 21a1238b1..c62b38cad 100644
--- a/examples/utils/pyside2_config.py
+++ b/examples/utils/pyside2_config.py
@@ -41,25 +41,103 @@
import os, glob, re, sys
from distutils import sysconfig
+generic_error = (' Did you forget to activate your virtualenv? Or perhaps'
+ ' you forgot to build / install PySide2 into your currently active Python'
+ ' environment?')
+pyside2_error = 'Unable to locate PySide2.' + generic_error
+shiboken2_module_error = 'Unable to locate shiboken2-module.' + generic_error
+shiboken2_generator_error = 'Unable to locate shiboken2-generator.' + generic_error
+pyside2_libs_error = 'Unable to locate the PySide2 shared libraries.' + generic_error
+python_link_error = 'Unable to locate the Python library for linking.'
+python_include_error = 'Unable to locate the Python include headers directory.'
+
+options = []
+
+# option, function, error, description
+options.append(("--shiboken2-module-path",
+ lambda: find_shiboken2_module(),
+ shiboken2_module_error,
+ "Print shiboken2 module location"))
+options.append(("--shiboken2-generator-path",
+ lambda: find_shiboken2_generator(),
+ shiboken2_generator_error,
+ "Print shiboken2 generator location"))
+options.append(("--pyside2-path", lambda: find_pyside2(), pyside2_error,
+ "Print PySide2 location"))
+
+options.append(("--python-include-path",
+ lambda: get_python_include_path(),
+ python_include_error,
+ "Print Python include path"))
+options.append(("--shiboken2-generator-include-path",
+ lambda: get_package_include_path(Package.shiboken2_generator),
+ pyside2_error,
+ "Print shiboken2 generator include paths"))
+options.append(("--pyside2-include-path",
+ lambda: get_package_include_path(Package.pyside2),
+ pyside2_error,
+ "Print PySide2 include paths"))
+
+options.append(("--python-link-flags-qmake", lambda: python_link_flags_qmake(), python_link_error,
+ "Print python link flags for qmake"))
+options.append(("--python-link-flags-cmake", lambda: python_link_flags_cmake(), python_link_error,
+ "Print python link flags for cmake"))
+
+options.append(("--shiboken2-module-qmake-lflags",
+ lambda: get_package_qmake_lflags(Package.shiboken2_module), pyside2_error,
+ "Print shiboken2 shared library link flags for qmake"))
+options.append(("--pyside2-qmake-lflags",
+ lambda: get_package_qmake_lflags(Package.pyside2), pyside2_error,
+ "Print PySide2 shared library link flags for qmake"))
+
+options.append(("--shiboken2-module-shared-libraries-qmake",
+ lambda: get_shared_libraries_qmake(Package.shiboken2_module), pyside2_libs_error,
+ "Print paths of shiboken2 shared libraries (.so's, .dylib's, .dll's) for qmake"))
+options.append(("--shiboken2-module-shared-libraries-cmake",
+ lambda: get_shared_libraries_cmake(Package.shiboken2_module), pyside2_libs_error,
+ "Print paths of shiboken2 shared libraries (.so's, .dylib's, .dll's) for cmake"))
+
+options.append(("--pyside2-shared-libraries-qmake",
+ lambda: get_shared_libraries_qmake(Package.pyside2), pyside2_libs_error,
+ "Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's) for qmake"))
+options.append(("--pyside2-shared-libraries-cmake",
+ lambda: get_shared_libraries_cmake(Package.pyside2), pyside2_libs_error,
+ "Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's) for cmake"))
+
+options_usage = ''
+for i, (flag, _, _, description) in enumerate(options):
+ options_usage += ' {:<45} {}'.format(flag, description)
+ if i < len(options) - 1:
+ options_usage += '\n'
+
usage = """
-Utility to determine include/link options of PySide2 and Python for qmake
+Utility to determine include/link options of shiboken2/PySide2 and Python for qmake/CMake projects
+that would like to embed or build custom shiboken2/PySide2 bindings.
Usage: pyside2_config.py [option]
Options:
- --python-include Print Python include path
- --python-link Print Python link flags
- --pyside2 Print PySide2 location
- --pyside2-include Print PySide2 include paths
- --pyside2-link Print PySide2 link flags
- --pyside2-shared-libraries Print paths of PySide2 shared libraries (.so's, .dylib's, .dll's)
- -a Print all
- --help/-h Print this help
-"""
-
-def cleanPath(path):
+{}
+ -a Print all options and their values
+ --help/-h Print this help
+""".format(options_usage)
+
+option = sys.argv[1] if len(sys.argv) == 2 else '-a'
+if option == '-h' or option == '--help':
+ print(usage)
+ sys.exit(0)
+
+
+class Package(object):
+ shiboken2_module = 1
+ shiboken2_generator = 2
+ pyside2 = 3
+
+
+def clean_path(path):
return path if sys.platform != 'win32' else path.replace('\\', '/')
-def sharedLibrarySuffix():
+
+def shared_library_suffix():
if sys.platform == 'win32':
return 'lib'
elif sys.platform == 'darwin':
@@ -68,7 +146,8 @@ def sharedLibrarySuffix():
else:
return 'so.*'
-def importSuffixes():
+
+def import_suffixes():
if (sys.version_info >= (3, 4)):
import importlib
return importlib.machinery.EXTENSION_SUFFIXES
@@ -79,25 +158,29 @@ def importSuffixes():
result.append(t[0])
return result
-def isDebug():
- debugSuffix = '_d.pyd' if sys.platform == 'win32' else '_d.so'
- return any([s.endswith(debugSuffix) for s in importSuffixes()])
-def sharedLibraryGlobPattern():
- glob = '*.' + sharedLibrarySuffix()
+def is_debug():
+ debug_suffix = '_d.pyd' if sys.platform == 'win32' else '_d.so'
+ return any([s.endswith(debug_suffix) for s in import_suffixes()])
+
+
+def shared_library_glob_pattern():
+ glob = '*.' + shared_library_suffix()
return glob if sys.platform == 'win32' else 'lib' + glob
-def filterPySide2SharedLibraries(list, only_shiboken=False):
- def predicate(item):
- basename = os.path.basename(item)
- if 'shiboken' in basename or ('pyside2' in basename and not only_shiboken):
+
+def filter_shared_libraries(libs_list):
+ def predicate(lib_name):
+ basename = os.path.basename(lib_name)
+ if 'shiboken' in basename or 'pyside2' in basename:
return True
return False
- result = [item for item in list if predicate(item)]
+ result = [lib for lib in libs_list if predicate(lib)]
return result
+
# Return qmake link option for a library file name
-def linkOption(lib):
+def link_option(lib):
# On Linux:
# Since we cannot include symlinks with wheel packages
# we are using an absolute path for the libpyside and libshiboken
@@ -112,24 +195,50 @@ def linkOption(lib):
link += os.path.splitext(baseName)[0]
return link
-# Locate PySide2 via package path
-def findPySide2():
+
+# Locate PySide2 via sys.path package path.
+def find_pyside2():
+ return find_package_path("PySide2")
+
+
+def find_shiboken2_module():
+ return find_package_path("shiboken2")
+
+
+def find_shiboken2_generator():
+ return find_package_path("shiboken2_generator")
+
+
+def find_package(which_package):
+ if which_package == Package.shiboken2_module:
+ return find_shiboken2_module()
+ if which_package == Package.shiboken2_generator:
+ return find_shiboken2_generator()
+ if which_package == Package.pyside2:
+ return find_pyside2()
+ return None
+
+
+def find_package_path(dir_name):
for p in sys.path:
if 'site-' in p:
- pyside2 = os.path.join(p, 'PySide2')
- if os.path.exists(pyside2):
- return cleanPath(os.path.realpath(pyside2))
+ package = os.path.join(p, dir_name)
+ if os.path.exists(package):
+ return clean_path(os.path.realpath(package))
return None
+
# Return version as "3.5"
-def pythonVersion():
+def python_version():
return str(sys.version_info[0]) + '.' + str(sys.version_info[1])
-def pythonInclude():
+
+def get_python_include_path():
return sysconfig.get_python_inc()
-def pythonLinkQmake():
- flags = pythonLinkData()
+
+def python_link_flags_qmake():
+ flags = python_link_data()
if sys.platform == 'win32':
libdir = flags['libdir']
# This will add the "~1" shortcut for directories that
@@ -146,25 +255,27 @@ def pythonLinkQmake():
# Linux and anything else
return '-L{} -l{}'.format(flags['libdir'], flags['lib'])
-def pythonLinkCmake():
- flags = pythonLinkData()
+
+def python_link_flags_cmake():
+ flags = python_link_data()
libdir = flags['libdir']
lib = re.sub(r'.dll$', '.lib', flags['lib'])
return '{};{}'.format(libdir, lib)
-def pythonLinkData():
+
+def python_link_data():
# @TODO Fix to work with static builds of Python
libdir = sysconfig.get_config_var('LIBDIR')
if libdir is None:
libdir = os.path.abspath(os.path.join(
sysconfig.get_config_var('LIBDEST'), "..", "libs"))
- version = pythonVersion()
+ version = python_version()
version_no_dots = version.replace('.', '')
flags = {}
flags['libdir'] = libdir
if sys.platform == 'win32':
- suffix = '_d' if isDebug() else ''
+ suffix = '_d' if is_debug() else ''
flags['lib'] = 'python{}{}'.format(version_no_dots, suffix)
elif sys.platform == 'darwin':
@@ -173,42 +284,44 @@ def pythonLinkData():
# Linux and anything else
else:
if sys.version_info[0] < 3:
- suffix = '_d' if isDebug() else ''
+ suffix = '_d' if is_debug() else ''
flags['lib'] = 'python{}{}'.format(version, suffix)
else:
flags['lib'] = 'python{}{}'.format(version, sys.abiflags)
return flags
-def pyside2Include(only_shiboken=False):
- pySide2 = findPySide2()
- if pySide2 is None:
+
+def get_package_include_path(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
return None
- includes = "{0}/include/shiboken2".format(pySide2)
- if not only_shiboken:
- includes = includes + " {0}/include/PySide2".format(pySide2)
+ includes = "{0}/include".format(package_path)
return includes
-def pyside2Link():
- pySide2 = findPySide2()
- if pySide2 is None:
+
+def get_package_qmake_lflags(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
return None
- link = "-L{}".format(pySide2)
- glob_result = glob.glob(os.path.join(pySide2, sharedLibraryGlobPattern()))
- for lib in filterPySide2SharedLibraries(glob_result):
+
+ link = "-L{}".format(package_path)
+ glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern()))
+ for lib in filter_shared_libraries(glob_result):
link += ' '
- link += linkOption(lib)
+ link += link_option(lib)
return link
-def pyside2SharedLibrariesData(only_shiboken=False):
- pySide2 = findPySide2()
- if pySide2 is None:
+
+def get_shared_libraries_data(which_package):
+ package_path = find_package(which_package)
+ if package_path is None:
return None
- glob_result = glob.glob(os.path.join(pySide2, sharedLibraryGlobPattern()))
- filtered_libs = filterPySide2SharedLibraries(glob_result, only_shiboken)
+ glob_result = glob.glob(os.path.join(package_path, shared_library_glob_pattern()))
+ filtered_libs = filter_shared_libraries(glob_result)
libs = []
if sys.platform == 'win32':
for lib in filtered_libs:
@@ -218,8 +331,9 @@ def pyside2SharedLibrariesData(only_shiboken=False):
libs.append(lib)
return libs
-def pyside2SharedLibraries():
- libs = pyside2SharedLibrariesData()
+
+def get_shared_libraries_qmake(which_package):
+ libs = get_shared_libraries_data(which_package)
if libs is None:
return None
@@ -238,80 +352,21 @@ def pyside2SharedLibraries():
libs_string += lib + ' '
return libs_string
-def pyside2SharedLibrariesCmake(only_shiboken=False):
- libs = pyside2SharedLibrariesData(only_shiboken)
+
+def get_shared_libraries_cmake(which_package):
+ libs = get_shared_libraries_data(which_package)
result = ';'.join(libs)
return result
-option = sys.argv[1] if len(sys.argv) == 2 else '-a'
-if option == '-h' or option == '--help':
- print(usage)
- sys.exit(0)
-generic_error = (' Did you forget to activate your virtualenv? Or perhaps'
- ' you forgot to build / install PySide2 into your currently active Python'
- ' environment?')
-pyside2_error = 'Unable to locate PySide2.' + generic_error
-pyside2_libs_error = 'Unable to locate the PySide2 shared libraries.' + generic_error
-python_link_error = 'Unable to locate the Python library for linking.'
+print_all = option == "-a"
+for argument, handler, error, _ in options:
+ if option == argument or print_all:
+ handler_result = handler()
+ if handler_result is None:
+ sys.exit(error)
-if option == '--pyside2' or option == '-a':
- pySide2 = findPySide2()
- if pySide2 is None:
- sys.exit(pyside2_error)
- print(pySide2)
-
-if option == '--pyside2-link' or option == '-a':
- l = pyside2Link()
- if l is None:
- sys.exit(pyside2_error)
-
- print(l)
-
-if option == '--shiboken-include' or option == '-a':
- i = pyside2Include(only_shiboken=True)
- if i is None:
- sys.exit(pyside2_error)
- print(i)
-
-if option == '--pyside2-include' or option == '-a':
- i = pyside2Include()
- if i is None:
- sys.exit(pyside2_error)
- print(i)
-
-if option == '--python-include' or option == '-a':
- i = pythonInclude()
- if i is None:
- sys.exit('Unable to locate the Python include headers directory.')
- print(i)
-
-if option == '--python-link' or option == '-a':
- l = pythonLinkQmake()
- if l is None:
- sys.exit(python_link_error)
- print(l)
-
-if option == '--python-link-cmake' or option == '-a':
- l = pythonLinkCmake()
- if l is None:
- sys.exit(python_link_error)
- print(l)
-
-if option == '--pyside2-shared-libraries' or option == '-a':
- l = pyside2SharedLibraries()
- if l is None:
- sys.exit(pyside2_libs_error)
- print(l)
-
-if option == '--pyside2-shared-libraries-cmake' or option == '-a':
- l = pyside2SharedLibrariesCmake()
- if l is None:
- sys.exit(pyside2_libs_error)
- print(l)
-
-if option == '--shiboken-shared-libraries-cmake' or option == '-a':
- l = pyside2SharedLibrariesCmake(only_shiboken=True)
- if l is None:
- sys.exit(pyside2_libs_error)
- print(l)
+ line = handler_result
+ if print_all:
+ line = "{:<40}: ".format(argument) + line
+ print(line)
diff --git a/keyword-errors.lst b/keyword-errors.lst
new file mode 100644
index 000000000..af8c581a5
--- /dev/null
+++ b/keyword-errors.lst
@@ -0,0 +1,43 @@
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QAbstractItemModel.changePersistentIndex', 'arglist': 'from:PySide2.QtCore.QModelIndex,to:PySide2.QtCore.QModelIndex', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QAbstractItemModel.changePersistentIndexList', 'arglist': 'from:QModelIndexList,to:QModelIndexList', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QByteArray.indexOf', 'arglist': 'a:PySide2.QtCore.QByteArray,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QByteArray.lastIndexOf', 'arglist': 'a:PySide2.QtCore.QByteArray,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': '1', 'funcname': 'PySide2.QtCore.QByteArrayMatcher.indexIn', 'arglist': 'ba:PySide2.QtCore.QByteArray,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': '0', 'funcname': 'PySide2.QtCore.QByteArrayMatcher.indexIn', 'arglist': 'str:str,len:int,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QItemSelection.indexOf', 'arglist': 't:PySide2.QtCore.QItemSelectionRange,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QItemSelection.lastIndexOf', 'arglist': 't:PySide2.QtCore.QItemSelectionRange,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QItemSelection.move', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QTextCodec.convertToUnicode', 'arglist': 'in:str,length:int,state:PySide2.QtCore.QTextCodec.ConverterState', 'returntype': 'QString'}
+KEYWORD {'multi': '0', 'funcname': 'PySide2.QtCore.QTextCodec.toUnicode', 'arglist': 'in:str,length:int,state:PySide2.QtCore.QTextCodec.ConverterState=nullptr', 'returntype': 'QString'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QVariantAnimation.interpolated', 'arglist': 'from:QVariant,to:QVariant,progress:double', 'returntype': 'QVariant'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QXmlStreamAttributes.indexOf', 'arglist': 't:PySide2.QtCore.QXmlStreamAttribute,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QXmlStreamAttributes.lastIndexOf', 'arglist': 't:PySide2.QtCore.QXmlStreamAttribute,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtCore.QXmlStreamAttributes.move', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QAbstractTextDocumentLayout.documentChanged', 'arglist': 'from:int,charsRemoved:int,charsAdded:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QIconEngine.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'bool'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QKeySequence.__lshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygon.indexOf', 'arglist': 't:PySide2.QtCore.QPoint,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygon.lastIndexOf', 'arglist': 't:PySide2.QtCore.QPoint,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygon.move', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygonF.indexOf', 'arglist': 't:PySide2.QtCore.QPointF,from:int=0', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygonF.lastIndexOf', 'arglist': 't:PySide2.QtCore.QPointF,from:int=-1', 'returntype': 'int'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QPolygonF.move', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QQuaternion.rotationTo', 'arglist': 'from:PySide2.QtGui.QVector3D,to:PySide2.QtGui.QVector3D', 'returntype': 'PySide2.QtGui.QQuaternion'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QStandardItem.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QStandardItem.__rshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': '4', 'funcname': 'PySide2.QtGui.QTextDocument.find', 'arglist': 'expr:PySide2.QtCore.QRegExp,from:int=0,options:PySide2.QtGui.QTextDocument.FindFlags=QTextDocument.FindFlags()', 'returntype': 'PySide2.QtGui.QTextCursor'}
+KEYWORD {'multi': '2', 'funcname': 'PySide2.QtGui.QTextDocument.find', 'arglist': 'expr:PySide2.QtCore.QRegularExpression,from:int=0,options:PySide2.QtGui.QTextDocument.FindFlags=QTextDocument.FindFlags()', 'returntype': 'PySide2.QtGui.QTextCursor'}
+KEYWORD {'multi': '0', 'funcname': 'PySide2.QtGui.QTextDocument.find', 'arglist': 'subString:QString,from:int=0,options:PySide2.QtGui.QTextDocument.FindFlags=QTextDocument.FindFlags()', 'returntype': 'PySide2.QtGui.QTextCursor'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtGui.QTextDocument.markContentsDirty', 'arglist': 'from:int,length:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QHeaderView.moveSection', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QLayout.replaceWidget', 'arglist': 'from:PySide2.QtWidgets.QWidget,to:PySide2.QtWidgets.QWidget,options:PySide2.QtCore.Qt.FindChildOptions=Qt.FindChildrenRecursively', 'returntype': 'PySide2.QtWidgets.QLayoutItem'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QListWidgetItem.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QListWidgetItem.__rshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QPlainTextDocumentLayout.documentChanged', 'arglist': 'from:int,arg__2:int,charsAdded:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTabBar.moveTab', 'arglist': 'from:int,to:int', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTableWidgetItem.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTableWidgetItem.__rshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTreeWidgetItem.read', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': None}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtWidgets.QTreeWidgetItem.__rshift__', 'arglist': 'in:PySide2.QtCore.QDataStream', 'returntype': 'PySide2.QtCore.QDataStream'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtMultimedia.QAudio.convertVolume', 'arglist': 'volume:double,from:PySide2.QtMultimedia.QAudio.VolumeScale,to:PySide2.QtMultimedia.QAudio.VolumeScale', 'returntype': 'double'}
+KEYWORD {'multi': None, 'funcname': 'PySide2.QtMultimedia.QMediaPlaylist.moveMedia', 'arglist': 'from:int,to:int', 'returntype': 'bool'}
diff --git a/popenasync.py b/popenasync.py
deleted file mode 100644
index 77faf9e0c..000000000
--- a/popenasync.py
+++ /dev/null
@@ -1,360 +0,0 @@
-#############################################################################
-##
-## Copyright (C) 2017 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$
-##
-#############################################################################
-
-################################################################################
-"""
-
-Modification of http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554
-
-"""
-
-#################################### IMPORTS ###################################
-
-import os
-import subprocess
-import errno
-import time
-import sys
-import unittest
-import tempfile
-
-def geterror ():
- return sys.exc_info()[1]
-
-if sys.version_info >= (3,):
- null_byte = '\x00'.encode('ascii')
-else:
- null_byte = '\x00'
-
-mswindows = (sys.platform == "win32")
-
-if mswindows:
- if sys.version_info >= (3,):
- # Test date should be in ascii.
- def encode(s):
- return s.encode('ascii', 'ignore')
-
- def decode(b):
- return b.decode('ascii', 'ignore')
- else:
- # Strings only; do nothing
- def encode(s):
- return s
-
- def decode(b):
- return b
-
- try:
- import ctypes
- from ctypes.wintypes import DWORD
- kernel32 = ctypes.windll.kernel32
- TerminateProcess = ctypes.windll.kernel32.TerminateProcess
- def WriteFile(handle, data, ol = None):
- c_written = DWORD()
- success = ctypes.windll.kernel32.WriteFile(handle,
- ctypes.create_string_buffer(encode(data)), len(data),
- ctypes.byref(c_written), ol)
- return ctypes.windll.kernel32.GetLastError(), c_written.value
- def ReadFile(handle, desired_bytes, ol = None):
- c_read = DWORD()
- buffer = ctypes.create_string_buffer(desired_bytes+1)
- success = ctypes.windll.kernel32.ReadFile(handle, buffer,
- desired_bytes, ctypes.byref(c_read), ol)
- buffer[c_read.value] = null_byte
- return ctypes.windll.kernel32.GetLastError(), decode(buffer.value)
- def PeekNamedPipe(handle, desired_bytes):
- c_avail = DWORD()
- c_message = DWORD()
- if desired_bytes > 0:
- c_read = DWORD()
- buffer = ctypes.create_string_buffer(desired_bytes+1)
- success = ctypes.windll.kernel32.PeekNamedPipe(handle, buffer,
- desired_bytes, ctypes.byref(c_read), ctypes.byref(c_avail),
- ctypes.byref(c_message))
- buffer[c_read.value] = null_byte
- return decode(buffer.value), c_avail.value, c_message.value
- else:
- success = ctypes.windll.kernel32.PeekNamedPipe(handle, None,
- desired_bytes, None, ctypes.byref(c_avail),
- ctypes.byref(c_message))
- return "", c_avail.value, c_message.value
-
- except ImportError:
- from win32file import ReadFile, WriteFile
- from win32pipe import PeekNamedPipe
- from win32api import TerminateProcess
- import msvcrt
-
-else:
- from signal import SIGINT, SIGTERM, SIGKILL
- import select
- import fcntl
-
-################################### CONSTANTS ##################################
-
-PIPE = subprocess.PIPE
-
-################################################################################
-
-class Popen(subprocess.Popen):
- def __init__(self, *args, **kwargs):
- subprocess.Popen.__init__(self, *args, **kwargs)
-
- def recv(self, maxsize=None):
- return self._recv('stdout', maxsize)
-
- def recv_err(self, maxsize=None):
- return self._recv('stderr', maxsize)
-
- def send_recv(self, input='', maxsize=None):
- return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
-
- def read_async(self, wait=.1, e=1, tr=5, stderr=0):
- if tr < 1:
- tr = 1
- x = time.time()+ wait
- y = []
- r = ''
- pr = self.recv
- if stderr:
- pr = self.recv_err
- while time.time() < x or r:
- r = pr()
- if r is None:
- if e:
- raise Exception("Other end disconnected!")
- else:
- break
- elif r:
- y.append(r)
- else:
- time.sleep(max((x-time.time())/tr, 0))
- return ''.join(y)
-
- def send_all(self, data):
- while len(data):
- sent = self.send(data)
- if sent is None:
- raise Exception("Other end disconnected!")
- data = buffer(data, sent)
-
- def get_conn_maxsize(self, which, maxsize):
- if maxsize is None:
- maxsize = 1024
- elif maxsize < 1:
- maxsize = 1
- return getattr(self, which), maxsize
-
- def _close(self, which):
- conn = getattr(self, which)
- flags = fcntl.fcntl(conn, fcntl.F_GETFL)
- if not conn.closed:
- fcntl.fcntl(conn, fcntl.F_SETFL, flags & ~os.O_NONBLOCK)
- assert conn.read() == ''
- getattr(self, which).close()
- setattr(self, which, None)
-
- if mswindows:
- def kill(self):
- # Recipes
- #http://me.in-berlin.de/doc/python/faq/windows.html#how-do-i-emulate-os-kill-in-windows
- #http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/347462
-
- """kill function for Win32"""
- TerminateProcess(int(self._handle), 0) # returns None
-
- def send(self, input):
- if not self.stdin:
- return None
-
- try:
- x = msvcrt.get_osfhandle(self.stdin.fileno())
- (errCode, written) = WriteFile(x, input)
- except ValueError:
- return self._close('stdin')
- except (subprocess.pywintypes.error, Exception):
- if geterror()[0] in (109, errno.ESHUTDOWN):
- return self._close('stdin')
- raise
-
- return written
-
- def _recv(self, which, maxsize):
- conn, maxsize = self.get_conn_maxsize(which, maxsize)
- if conn is None:
- return None
-
- try:
- x = msvcrt.get_osfhandle(conn.fileno())
- (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
- if maxsize < nAvail:
- nAvail = maxsize
- if nAvail > 0:
- (errCode, read) = ReadFile(x, nAvail, None)
- except ValueError:
- return self._close(which)
- except (subprocess.pywintypes.error, Exception):
- if geterror()[0] in (109, errno.ESHUTDOWN):
- return self._close(which)
- raise
-
- if self.universal_newlines:
- # Translate newlines. For Python 3.x assume read is text.
- # If bytes then another solution is needed.
- read = read.replace("\r\n", "\n").replace("\r", "\n")
- return read
-
- else:
- def kill(self):
- for i, sig in enumerate([SIGTERM, SIGKILL] * 2):
- if i % 2 == 0: os.kill(self.pid, sig)
- time.sleep((i * (i % 2) / 5.0) + 0.01)
-
- killed_pid, stat = os.waitpid(self.pid, os.WNOHANG)
- if killed_pid != 0: return
-
- def send(self, input):
- if not self.stdin:
- return None
-
- if not select.select([], [self.stdin], [], 0)[1]:
- return 0
-
- try:
- written = os.write(self.stdin.fileno(), input)
- except OSError:
- if geterror()[0] == errno.EPIPE: #broken pipe
- return self._close('stdin')
- raise
-
- return written
-
- def _recv(self, which, maxsize):
- conn, maxsize = self.get_conn_maxsize(which, maxsize)
- if conn is None:
- return None
-
- flags = fcntl.fcntl(conn, fcntl.F_GETFL)
- if not conn.closed:
- fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
-
- try:
- if not select.select([conn], [], [], 0)[0]:
- return ''
-
- try:
- r = conn.read(maxsize)
- except IOError as e:
- if e.errno == errno.EAGAIN:
- return ''
- raise
- if not r:
- return self._close(which)
-
- if self.universal_newlines:
- r = r.replace("\r\n", "\n").replace("\r", "\n")
- return r
- finally:
- if not conn.closed:
- fcntl.fcntl(conn, fcntl.F_SETFL, flags)
-
-################################################################################
-
-def proc_in_time_or_kill(cmd, time_out, wd = None, env = None):
- proc = Popen (
- cmd, cwd = wd, env = env,
- stdin = subprocess.PIPE, stdout = subprocess.PIPE,
- stderr = subprocess.STDOUT, universal_newlines = 1
- )
-
- ret_code = None
- response = []
-
- t = time.time()
- while ret_code is None and ((time.time() -t) < time_out):
- ret_code = proc.poll()
- response += [proc.read_async(wait=0.1, e=0)]
-
- if ret_code is None:
- ret_code = '"Process timed out (time_out = {} secs) '.format(time_out)
- try:
- proc.kill()
- ret_code += 'and was successfully terminated"'
- except Exception:
- ret_code += ("and termination failed "
- "(exception: {})".format(geterror(),))
-
- return ret_code, ''.join(response)
-
-################################################################################
-
-class AsyncTest(unittest.TestCase):
- def test_proc_in_time_or_kill(self):
- ret_code, response = proc_in_time_or_kill(
- [sys.executable, '-c', 'while 1: pass'], time_out = 1
- )
-
- self.assert_( 'rocess timed out' in ret_code )
- self.assert_( 'successfully terminated' in ret_code )
-
-################################################################################
-
-def _example():
- if sys.platform == 'win32':
- shell, commands, tail = ('cmd', ('echo "hello"', 'echo "HELLO WORLD"'),
- '\r\n')
- else:
- shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n')
-
- a = Popen(shell, stdin=PIPE, stdout=PIPE)
- sys.stdout.write(a.read_async())
- sys.stdout.write(" ")
- for cmd in commands:
- a.send_all(cmd + tail)
- sys.stdout.write(a.read_async())
- sys.stdout.write(" ")
- a.send_all('exit' + tail)
- print (a.read_async(e=0))
- a.wait()
-
-################################################################################
-
-if __name__ == '__main__':
- if 1: unittest.main()
- else: _example()
diff --git a/setup.py b/setup.py
index c7e7e9862..d27ca088f 100644
--- a/setup.py
+++ b/setup.py
@@ -42,12 +42,18 @@ from __future__ import print_function
"""
This is a distutils setup-script for the Qt for Python project
-To build PySide2 simply execute:
+To build both shiboken2 and PySide2 simply execute:
python setup.py build
or
python setup.py install
to build and install into your current Python installation.
+The same setup.py script is used to build all the components of the
+project:
+ - shiboken2 (the supporting Python module)
+ - shiboken2-generator (the bindings generation executable)
+ - PySide2
+ - pyside2-tools
Optionally, one can specify the location of qmake and cmake if it is
not on the current PATH with:
@@ -56,6 +62,23 @@ and
--cmake=/path/to/bin/cmake
respectively.
+By default, all of the above is built when no special options are
+passed to the script. You can use the --build-type parameter to specify
+which things should be built:
+ --build-type=shiboken2 - build / package only the python module
+ --build-type=shiboken2-generator - build / package the generator
+ executable
+ --build-type=pyside2 - build / package the PySide2 bindings and
+ and pyside2-tools
+ --build-type=all - the implicit default to build all of the above
+
+
+When building PySide2, optionally, one can specify the location of the
+shiboken2 cmake config path if it is not on the current PATH with:
+ --shiboken-config-dir=/path/to/shiboken/cmake/config/dir
+This is useful if you did a cmake installation of shiboken2 into
+a custom location.
+
For Windows, if OpenSSL support is required, it's necessary to specify
the directory path that contains the OpenSSL shared libraries
"libeay32.dll" and "ssleay32.dll", for example:
@@ -79,7 +102,7 @@ not specified.
You can use the option `--only-package` if you want to create more
binary packages (bdist_wheel, bdist_egg, ...) without rebuilding the
-entire PySide2 every time:
+entire project every time:
e.g.:
@@ -89,7 +112,7 @@ e.g.:
--cmake=c:\tools\cmake\bin\cmake.exe
--openssl=c:\libs\OpenSSL32bit\bin
-* Then, we create a bdist_egg reusing PySide2 build with option
+* Then, we create a bdist_egg reusing the PySide2 build with option
`--only-package`:
python setup.py bdist_egg --only-package
@@ -110,7 +133,7 @@ new environment variable called PYSIDE_DISABLE_INTERNAL_QT_CONF is
introduced.
You should assign the integer "1" to disable the internal `qt.conf`,
-or "0" (or leave empty) to keep usining the internal `qt.conf` file.
+or "0" (or leave empty) to keep using the internal `qt.conf` file.
DEVELOPMENT OPTIONS:
@@ -230,78 +253,18 @@ this_file = os.path.abspath(this_file)
if os.path.dirname(this_file):
os.chdir(os.path.dirname(this_file))
-from build_scripts.main import get_package_version, get_setuptools_extension_modules
-from build_scripts.main import pyside_package_dir_name
-from build_scripts.main import cmd_class_dict
-from build_scripts.main import README, CHANGES
-from setuptools import setup, Extension
+# Save the original command line arguments to pass them on to the setup
+# mechanism.
+original_argv = list(sys.argv)
-# The __version__ variable is just for PEP compliancy, and shouldn't be
-# used as a value source.
+from build_scripts.main import get_package_version, check_allowed_python_version
+from build_scripts.setup_runner import SetupRunner
+
+# The __version__ variable is just for PEP compliance, and shouldn't be
+# used as a value source. Use get_package_version() instead.
__version__ = get_package_version()
-extension_modules = get_setuptools_extension_modules()
-
-setup(
- name = "PySide2",
- version = get_package_version(),
- description = ("Python bindings for the Qt cross-platform application and "
- "UI framework"),
- long_description = README + "\n\n" + CHANGES,
- long_description_content_type = 'text/markdown',
- classifiers = [
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Console',
- 'Environment :: MacOS X',
- 'Environment :: X11 Applications :: Qt',
- 'Environment :: Win32 (MS Windows)',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
- 'Operating System :: MacOS :: MacOS X',
- 'Operating System :: POSIX',
- 'Operating System :: POSIX :: Linux',
- 'Operating System :: Microsoft',
- 'Operating System :: Microsoft :: Windows',
- 'Programming Language :: C++',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Topic :: Database',
- 'Topic :: Software Development',
- 'Topic :: Software Development :: Code Generators',
- 'Topic :: Software Development :: Libraries :: Application Frameworks',
- 'Topic :: Software Development :: User Interfaces',
- 'Topic :: Software Development :: Widget Sets',
- ],
- keywords = 'Qt',
- author = 'Qt for Python Team',
- author_email = 'pyside@qt-project.org',
- url = 'https://www.pyside.org',
- download_url = 'https://download.qt.io/official_releases/QtForPython/',
- license = 'LGPL',
- packages = ['PySide2', 'pyside2uic',
- 'pyside2uic.Compiler',
- 'pyside2uic.port_v{}'.format(sys.version_info[0]) ],
- package_dir = {'': pyside_package_dir_name},
- include_package_data = True,
- zip_safe = False,
- entry_points = {
- 'console_scripts': [
- 'pyside2-uic = PySide2.scripts.uic:main',
- 'pyside2-rcc = PySide2.scripts.pyside_tool:main',
- 'pyside2-lupdate = PySide2.scripts.pyside_tool:main',
- 'shiboken2 = PySide2.scripts.pyside_tool:main',
- ]
- },
- cmdclass = cmd_class_dict,
- # Add a bogus extension module (will never be built here since we
- # are overriding the build command to do it using cmake) so things
- # like bdist_egg will know that there are extension modules and
- # will name the dist with the full platform info.
- ext_modules = extension_modules,
- ext_package = 'PySide2',
-)
+check_allowed_python_version()
+
+setup_runner = SetupRunner(original_argv)
+setup_runner.run_setup()
diff --git a/sources/cmake_helpers/helpers.cmake b/sources/cmake_helpers/helpers.cmake
new file mode 100644
index 000000000..dd2e98a3a
--- /dev/null
+++ b/sources/cmake_helpers/helpers.cmake
@@ -0,0 +1,63 @@
+macro(compute_config_py_values
+ full_version_var_name
+ )
+ string(TIMESTAMP PACKAGE_BUILD_DATE "%Y-%m-%dT%H:%M:%S+00:00" UTC)
+ if (PACKAGE_BUILD_DATE)
+ set(PACKAGE_BUILD_DATE "__build_date__ = '${PACKAGE_BUILD_DATE}'")
+ endif()
+
+ if (PACKAGE_SETUP_PY_PACKAGE_VERSION)
+ set(PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT "__setup_py_package_version__ = '${PACKAGE_SETUP_PY_PACKAGE_VERSION}'")
+ set(FINAL_PACKAGE_VERSION ${PACKAGE_SETUP_PY_PACKAGE_VERSION})
+ else()
+ set(FINAL_PACKAGE_VERSION ${${full_version_var_name}})
+ endif()
+
+ if (PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP)
+ set(PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT "__setup_py_package_timestamp__ = '${PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP}'")
+ else()
+ set(PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT "")
+ endif()
+
+ find_package(Git)
+ if(GIT_FOUND)
+ # Check if current source folder is inside a git repo, so that commit information can be
+ # queried.
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse --git-dir
+ OUTPUT_VARIABLE PACKAGE_SOURCE_IS_INSIDE_REPO
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(PACKAGE_SOURCE_IS_INSIDE_REPO)
+ # Force git dates to be UTC-based.
+ set(ENV{TZ} UTC)
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} --no-pager show --date=format-local:%Y-%m-%dT%H:%M:%S+00:00 -s --format=%cd HEAD
+ OUTPUT_VARIABLE PACKAGE_BUILD_COMMIT_DATE
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(PACKAGE_BUILD_COMMIT_DATE)
+ set(PACKAGE_BUILD_COMMIT_DATE "__build_commit_date__ = '${PACKAGE_BUILD_COMMIT_DATE}'")
+ endif()
+ unset(ENV{TZ})
+
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
+ OUTPUT_VARIABLE PACKAGE_BUILD_COMMIT_HASH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(PACKAGE_BUILD_COMMIT_HASH)
+ set(PACKAGE_BUILD_COMMIT_HASH "__build_commit_hash__ = '${PACKAGE_BUILD_COMMIT_HASH}'")
+ endif()
+
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} describe HEAD
+ OUTPUT_VARIABLE PACKAGE_BUILD_COMMIT_HASH_DESCRIBED
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(PACKAGE_BUILD_COMMIT_HASH_DESCRIBED)
+ set(PACKAGE_BUILD_COMMIT_HASH_DESCRIBED "__build_commit_hash_described__ = '${PACKAGE_BUILD_COMMIT_HASH_DESCRIBED}'")
+ endif()
+
+ endif()
+ endif()
+
+endmacro()
diff --git a/sources/pyside2/CMakeLists.txt b/sources/pyside2/CMakeLists.txt
index 358c119ae..25598bb5e 100644
--- a/sources/pyside2/CMakeLists.txt
+++ b/sources/pyside2/CMakeLists.txt
@@ -8,8 +8,10 @@ cmake_policy(SET CMP0046 NEW)
project(pysidebindings)
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Macros/
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../cmake_helpers/
+ ${CMAKE_SOURCE_DIR}/cmake/Macros/
${CMAKE_MODULE_PATH})
+include(helpers)
option(USE_PYTHON_VERSION "Use specific python version to build pyside2." "")
@@ -244,64 +246,7 @@ else()
CACHE STRING "PySide2 version [full]" FORCE)
endif()
-string(TIMESTAMP PYSIDE_BUILD_DATE "%Y-%m-%dT%H:%M:%S+00:00" UTC)
-if (PYSIDE_BUILD_DATE)
- set(PYSIDE_BUILD_DATE "__build_date__ = '${PYSIDE_BUILD_DATE}'")
-endif()
-
-if (PYSIDE_SETUP_PY_PACKAGE_VERSION)
- set(PYSIDE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT "__setup_py_package_version__ = '${PYSIDE_SETUP_PY_PACKAGE_VERSION}'")
- set(FINAL_PACKAGE_VERSION ${PYSIDE_SETUP_PY_PACKAGE_VERSION})
-else()
- set(FINAL_PACKAGE_VERSION ${BINDING_API_VERSION_FULL})
-endif()
-
-if (PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP)
- set(PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT "__setup_py_package_timestamp__ = '${PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP}'")
-else()
- set(PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT "__setup_py_package_timestamp__ = ''")
-endif()
-
-find_package(Git)
-if(GIT_FOUND)
- # Check if current source folder is inside a git repo, so that commit information can be
- # queried.
- execute_process(
- COMMAND ${GIT_EXECUTABLE} rev-parse --git-dir
- OUTPUT_VARIABLE PYSIDE_SOURCE_IS_INSIDE_REPO
- ERROR_QUIET
- OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- if(PYSIDE_SOURCE_IS_INSIDE_REPO)
- # Force git dates to be UTC-based.
- set(ENV{TZ} UTC)
- execute_process(
- COMMAND ${GIT_EXECUTABLE} --no-pager show --date=format-local:%Y-%m-%dT%H:%M:%S+00:00 -s --format=%cd HEAD
- OUTPUT_VARIABLE PYSIDE_BUILD_COMMIT_DATE
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if(PYSIDE_BUILD_COMMIT_DATE)
- set(PYSIDE_BUILD_COMMIT_DATE "__build_commit_date__ = '${PYSIDE_BUILD_COMMIT_DATE}'")
- endif()
- unset(ENV{TZ})
-
- execute_process(
- COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
- OUTPUT_VARIABLE PYSIDE_BUILD_COMMIT_HASH
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if(PYSIDE_BUILD_COMMIT_HASH)
- set(PYSIDE_BUILD_COMMIT_HASH "__build_commit_hash__ = '${PYSIDE_BUILD_COMMIT_HASH}'")
- endif()
-
- execute_process(
- COMMAND ${GIT_EXECUTABLE} describe HEAD
- OUTPUT_VARIABLE PYSIDE_BUILD_COMMIT_HASH_DESCRIBED
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- if(PYSIDE_BUILD_COMMIT_HASH_DESCRIBED)
- set(PYSIDE_BUILD_COMMIT_HASH_DESCRIBED "__build_commit_hash_described__ = '${PYSIDE_BUILD_COMMIT_HASH_DESCRIBED}'")
- endif()
-
- endif()
-endif()
+compute_config_py_values(BINDING_API_VERSION)
include(PySideModules)
diff --git a/sources/pyside2/PySide2/CMakeLists.txt b/sources/pyside2/PySide2/CMakeLists.txt
index 0263f7441..4709dd073 100644
--- a/sources/pyside2/PySide2/CMakeLists.txt
+++ b/sources/pyside2/PySide2/CMakeLists.txt
@@ -40,12 +40,18 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/__init__.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/__init__.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/__init__.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/__init__.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/layout.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/layout.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/loader.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/loader.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/mapping.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/mapping.py" COPYONLY)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/parser.py"
"${CMAKE_CURRENT_BINARY_DIR}/support/signature/parser.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/__init__.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/__init__.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/enum_sig.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/enum_sig.py" COPYONLY)
if (PYTHON_VERSION_MAJOR EQUAL 3)
else()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/backport_inspect.py"
diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
index f67b5a306..32d586631 100644
--- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
+++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
@@ -2694,10 +2694,10 @@
The signature "QList<qreal>" is needed by the __reduce__ methods,
but created by some other object used elsewhere.
- After the matrix type was changed, "QList<float>" was nowhere created.
+ After the matrix type was changed, "QList<float>" was created nowhere.
I don't know an explicit way to produce the right conversion function, so what I did
- was to create a dummy function and immediately dele it again.
+ was to create a dummy function and immediately delete it again.
This has the desired effect of creating the implicitly needed "QList<float>"
conversion, although the dummy function goes away.
@@ -2983,10 +2983,12 @@
</extra-includes>
</primitive-type>
- <object-type name="QWindow">
+ <object-type name="QWindow" delete-in-main-thread="true">
<enum-type name="AncestorMode"/>
<enum-type name="Visibility"/>
+ <modify-function signature="raise()" rename="raise_" />
</object-type>
+
<!-- Qt5: not sure if this needs support, skipped for now -->
<rejection class="QWindow" function-name="nativeEvent"/>"
@@ -3013,7 +3015,6 @@
}
</inject-code>
</add-function>
- <modify-function signature="exec()" rename="exec_" allow-thread="yes"/>
<inject-code class="native" file="glue/qguiapplication_init.cpp" position="beginning" />
</object-type>
diff --git a/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml b/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml
index 7e6b450c9..dde90166f 100644
--- a/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml
+++ b/sources/pyside2/PySide2/QtQuick/typesystem_quick.xml
@@ -65,7 +65,7 @@
<object-type name="QQuickImageResponse" since="5.6" />
<object-type name="QQuickTransform" />
- <object-type name="QQuickItem">
+ <object-type name="QQuickItem" delete-in-main-thread="true">
<value-type name="UpdatePaintNodeData" />
<enum-type name="Flag" flags="Flags" />
<enum-type name="ItemChange" />
diff --git a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
index 9c21493da..1f2cd446b 100644
--- a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
+++ b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
@@ -2196,7 +2196,7 @@
</modify-function>
</object-type>
- <object-type name="QWidget">
+ <object-type name="QWidget" delete-in-main-thread="true">
<!-- Qt5: remove native event for now -->
<modify-function signature="nativeEvent(const QByteArray &amp;,void*,long*)" remove="all" />
diff --git a/sources/pyside2/PySide2/__init__.py.in b/sources/pyside2/PySide2/__init__.py.in
index ab50ef776..631f5f13a 100644
--- a/sources/pyside2/PySide2/__init__.py.in
+++ b/sources/pyside2/PySide2/__init__.py.in
@@ -4,18 +4,22 @@ __all__ = list("Qt" + body for body in
__version__ = "@FINAL_PACKAGE_VERSION@"
__version_info__ = (@BINDING_API_MAJOR_VERSION@, @BINDING_API_MINOR_VERSION@, @BINDING_API_MICRO_VERSION@, "@BINDING_API_PRE_RELEASE_VERSION_TYPE@", "@BINDING_API_PRE_RELEASE_VERSION@")
-@PYSIDE_BUILD_DATE@
-@PYSIDE_BUILD_COMMIT_DATE@
-@PYSIDE_BUILD_COMMIT_HASH@
-@PYSIDE_BUILD_COMMIT_HASH_DESCRIBED@
-
-# Timestamp used for snapshot build, which is part of snapshot package version.
-@PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
-
def _setupQtDirectories():
import sys
import os
+ # On Windows we need to explicitly import the shiboken2 module so
+ # that the libshiboken.dll dependency is loaded by the time a
+ # Qt module is imported. Otherwise due to PATH not containing
+ # the shiboken2 module path, the Qt module import would fail
+ # due to the missing libshiboken dll.
+ # We need to do the same on Linux and macOS, because we do not
+ # embed rpaths into the PySide2 libraries that would point to
+ # the libshiboken library location. Importing the module
+ # loads the libraries into the process memory beforehand, and
+ # thus takes care of it for us.
+ import shiboken2
+
pyside_package_dir = os.path.abspath(os.path.dirname(__file__))
# Used by signature module.
os.environ["PYSIDE_PACKAGE_DIR"] = pyside_package_dir
diff --git a/sources/pyside2/PySide2/_config.py.in b/sources/pyside2/PySide2/_config.py.in
index 31a2f7a50..740e9a001 100644
--- a/sources/pyside2/PySide2/_config.py.in
+++ b/sources/pyside2/PySide2/_config.py.in
@@ -8,10 +8,9 @@ pyside_library_soversion = str(@PYSIDE_SO_VERSION@)
version = "@FINAL_PACKAGE_VERSION@"
version_info = (@BINDING_API_MAJOR_VERSION@, @BINDING_API_MINOR_VERSION@, @BINDING_API_MICRO_VERSION@, "@BINDING_API_PRE_RELEASE_VERSION_TYPE@", "@BINDING_API_PRE_RELEASE_VERSION@")
-@PYSIDE_BUILD_DATE@
-@PYSIDE_BUILD_COMMIT_DATE@
-@PYSIDE_BUILD_COMMIT_HASH@
-@PYSIDE_BUILD_COMMIT_HASH_DESCRIBED@
-
-# Timestamp used for snapshot build, which is part of snapshot package version.
-@PYSIDE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@PACKAGE_BUILD_DATE@
+@PACKAGE_BUILD_COMMIT_DATE@
+@PACKAGE_BUILD_COMMIT_HASH@
+@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
+@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
diff --git a/sources/pyside2/PySide2/support/signature/__init__.py b/sources/pyside2/PySide2/support/signature/__init__.py
index 0ff9ec7e9..14e63a5fb 100644
--- a/sources/pyside2/PySide2/support/signature/__init__.py
+++ b/sources/pyside2/PySide2/support/signature/__init__.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -40,3 +40,7 @@
from __future__ import print_function, absolute_import
from .loader import inspect
+from PySide2 import QtCore
+if QtCore.QProcess.__signature__:
+ pass # trigger initialization
+from signature_loader import get_signature
diff --git a/sources/pyside2/PySide2/support/signature/fix-complaints.py b/sources/pyside2/PySide2/support/signature/fix-complaints.py
index fa2b44420..e078ef1ab 100644
--- a/sources/pyside2/PySide2/support/signature/fix-complaints.py
+++ b/sources/pyside2/PySide2/support/signature/fix-complaints.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
diff --git a/sources/pyside2/PySide2/support/signature/layout.py b/sources/pyside2/PySide2/support/signature/layout.py
new file mode 100644
index 000000000..ac7833f03
--- /dev/null
+++ b/sources/pyside2/PySide2/support/signature/layout.py
@@ -0,0 +1,237 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+layout.py
+
+The signature module now has the capability to configure
+differently formatted versions of signatures. The default
+layout is known from the "__signature__" attribute.
+
+The function "get_signature(ob, modifier=None)" produces the same
+signatures by default. By passing different modifiers, you
+can select different layouts.
+
+This module configures the different layouts which can be used.
+It also implements them in this file. The configurations are
+used literally as strings like "signature", "existence", etc.
+"""
+
+from textwrap import dedent
+from .loader import inspect
+
+class SimpleNamespace(object):
+ # From types.rst, because the builtin is implemented in Python 3, only.
+ def __init__(self, **kwargs):
+ self.__dict__.update(kwargs)
+
+ def __repr__(self):
+ keys = sorted(self.__dict__)
+ items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
+ return "{}({})".format(type(self).__name__, ", ".join(items))
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+class SignatureLayout(SimpleNamespace):
+ """
+ Configure a signature.
+
+ The layout of signatures can have different layouts which are
+ controlled by keyword arguments:
+
+ definition=True Determines if self will generated.
+ defaults=True
+ ellipsis=False Replaces defaults by "...".
+ return_annotation=True
+ parameter_names=True False removes names before ":".
+ """
+ allowed_keys = SimpleNamespace(definition=True,
+ defaults=True,
+ ellipsis=False,
+ return_annotation=True,
+ parameter_names=True)
+ allowed_values = True, False
+
+ def __init__(self, **kwds):
+ args = SimpleNamespace(**self.allowed_keys.__dict__)
+ args.__dict__.update(kwds)
+ self.__dict__.update(args.__dict__)
+ err_keys = list(set(self.__dict__) - set(self.allowed_keys.__dict__))
+ if err_keys:
+ self._attributeerror(err_keys)
+ err_values = list(set(self.__dict__.values()) - set(self.allowed_values))
+ if err_values:
+ self._valueerror(err_values)
+
+ def __setattr__(self, key, value):
+ if key not in self.allowed_keys.__dict__:
+ self._attributeerror([key])
+ if value not in self.allowed_values:
+ self._valueerror([value])
+ self.__dict__[key] = value
+
+ def _attributeerror(self, err_keys):
+ err_keys = ", ".join(err_keys)
+ allowed_keys = ", ".join(self.allowed_keys.__dict__.keys())
+ raise AttributeError(dedent("""\
+ Not allowed: '{err_keys}'.
+ The only allowed keywords are '{allowed_keys}'.
+ """.format(**locals())))
+
+ def _valueerror(self, err_values):
+ err_values = ", ".join(map(str, err_values))
+ allowed_values = ", ".join(map(str, self.allowed_values))
+ raise ValueError(dedent("""\
+ Not allowed: '{err_values}'.
+ The only allowed values are '{allowed_values}'.
+ """.format(**locals())))
+
+# The following names are used literally in this module.
+# This way, we avoid the dict hashing problem.
+signature = SignatureLayout()
+
+existence = SignatureLayout(definition=False,
+ defaults=False,
+ return_annotation=False,
+ parameter_names=False)
+
+hintingstub = SignatureLayout(ellipsis=True)
+
+typeerror = SignatureLayout(definition=False,
+ return_annotation=False,
+ parameter_names=False)
+
+def define_nameless_parameter():
+ """
+ Create Nameless Parameters
+
+ A nameless parameter has a reduced string representation.
+ This is done by cloning the parameter type and overwriting its
+ __str__ method. The inner structure is still a valid parameter.
+ """
+ def __str__(self):
+ # for Python 2, we must change self to be an instance of P
+ klass = self.__class__
+ self.__class__ = P
+ txt = P.__str__(self)
+ self.__class__ = klass
+ txt = txt[txt.index(":") + 1:].strip() if ":" in txt else txt
+ return txt
+
+ P = inspect.Parameter
+ newname = "NamelessParameter"
+ bases = P.__bases__
+ body = dict(P.__dict__) # get rid of mappingproxy
+ if "__slots__" in body:
+ # __slots__ would create duplicates
+ for name in body["__slots__"]:
+ del body[name]
+ body["__str__"] = __str__
+ return type(newname, bases, body)
+
+NamelessParameter = define_nameless_parameter()
+
+def make_signature_nameless(signature):
+ """
+ Make a Signature Nameless
+
+ We use an existing signature and change the type of its parameters.
+ The signature looks different, but is totally intact.
+ """
+ for key in signature.parameters.keys():
+ Signature.parameters[key].__class__ = NamelessParameter
+
+def create_signature(props, key):
+ if not props:
+ # empty signatures string
+ return
+ if isinstance(props["multi"], list):
+ # multi sig: call recursively
+ return list(create_signature(elem, key)
+ for elem in props["multi"])
+ if type(key) is tuple:
+ sig_kind, modifier = key
+ else:
+ sig_kind, modifier = key, "signature"
+
+ layout = globals()[modifier] # lookup of the modifier, here
+ if not isinstance(layout, SignatureLayout):
+ raise SystemError("Modifiers must be names of a SignatureLayout "
+ "instance")
+
+ # this is the basic layout of a signature
+ varnames = props["varnames"]
+ if layout.definition:
+ if sig_kind == "method":
+ varnames = ("self",) + varnames
+ elif sig_kind == "staticmethod":
+ pass
+ elif sig_kind == "classmethod":
+ varnames = ("klass",) + varnames
+ else:
+ raise SystemError("Methods must be normal, staticmethod or "
+ "classmethod")
+ # calculate the modifications
+ defaults = props["defaults"][:]
+ if not layout.defaults:
+ defaults = ()
+ if layout.ellipsis:
+ defaults = ("...",) * len(defaults)
+ annotations = props["annotations"].copy()
+ if not layout.return_annotation and "return" in annotations:
+ del annotations["return"]
+
+ # attach parameters to a fake function and build a signature
+ argstr = ", ".join(varnames)
+ fakefunc = eval("lambda {}: None".format(argstr))
+ fakefunc.__name__ = props["name"]
+ fakefunc.__defaults__ = defaults
+ fakefunc.__kwdefaults__ = props["kwdefaults"]
+ fakefunc.__annotations__ = annotations
+ sig = inspect._signature_from_function(inspect.Signature, fakefunc)
+
+ # the special case of nameless parameters
+ if not layout.parameter_names:
+ make_signature_nameless(sig)
+ return sig
+
+# end of file
diff --git a/sources/pyside2/PySide2/support/signature/lib/__init__.py b/sources/pyside2/PySide2/support/signature/lib/__init__.py
new file mode 100644
index 000000000..2d640cb89
--- /dev/null
+++ b/sources/pyside2/PySide2/support/signature/lib/__init__.py
@@ -0,0 +1,40 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+# this file intentionally left blank
diff --git a/sources/pyside2/PySide2/support/signature/lib/enum_sig.py b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
new file mode 100644
index 000000000..702ee7ebd
--- /dev/null
+++ b/sources/pyside2/PySide2/support/signature/lib/enum_sig.py
@@ -0,0 +1,113 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import sys
+from PySide2.support.signature import inspect, get_signature
+
+
+class ExactEnumerator(object):
+ """
+ ExactEnumerator enumerates all signatures in a module as they are.
+
+ This class is used for generating complete listings of all signatures.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+ def __init__(self, formatter, result_type=dict):
+ self.fmt = formatter
+ self.result_type = result_type
+
+ def module(self, mod_name):
+ __import__(mod_name)
+ with self.fmt.module(mod_name):
+ module = sys.modules[mod_name]
+ members = inspect.getmembers(module, inspect.isclass)
+ ret = self.result_type()
+ for class_name, klass in members:
+ ret.update(self.klass(class_name, klass))
+ return ret
+
+ def klass(self, class_name, klass):
+ bases_list = []
+ for base in klass.__bases__:
+ name = base.__name__
+ if name == "object":
+ pass
+ else:
+ modname = base.__module__
+ name = modname + "." + base.__name__
+ bases_list.append(name)
+ class_str = "{}({})".format(class_name, ", ".join(bases_list))
+ with self.fmt.klass(class_name, class_str):
+ ret = self.function("__init__", klass)
+ # class_members = inspect.getmembers(klass)
+ # gives us also the inherited things.
+ class_members = sorted(list(klass.__dict__.items()))
+ for func_name, func in class_members:
+ ret.update(self.function(func_name, func))
+ return ret
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = getattr(func, '__signature__', None)
+ if signature is not None:
+ with self.fmt.function(func_name, signature) as key:
+ ret[key] = signature
+ return ret
+
+
+class SimplifyingEnumerator(ExactEnumerator):
+ """
+ SimplifyingEnumerator enumerates all signatures in a module filtered.
+
+ There are no default values, no variable
+ names and no self parameter. Only types are present after simplification.
+ The functions 'next' resp. '__next__' are removed
+ to make the output identical for Python 2 and 3.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = get_signature(func, 'existence')
+ if signature is not None and func_name not in ("next", "__next__"):
+ with self.fmt.function(func_name, signature) as key:
+ ret[key] = signature
+ return ret
diff --git a/sources/pyside2/PySide2/support/signature/loader.py b/sources/pyside2/PySide2/support/signature/loader.py
index f51bafe79..21ecebcc8 100644
--- a/sources/pyside2/PySide2/support/signature/loader.py
+++ b/sources/pyside2/PySide2/support/signature/loader.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -80,31 +80,10 @@ from PySide2.support.signature.parser import pyside_type_init
sys.path.pop(0)
# Note also that during the tests we have a different encoding that would
# break the Python license decorated files without an encoding line.
+from PySide2.support.signature import layout
# name used in signature.cpp
-def create_signature(props, sig_kind):
- if not props:
- # empty signatures string
- return
- if isinstance(props["multi"], list):
- return list(create_signature(elem, sig_kind)
- for elem in props["multi"])
- varnames = props["varnames"]
- if sig_kind == "method":
- varnames = ("self",) + varnames
- elif sig_kind == "staticmethod":
- pass
- elif sig_kind == "classmethod":
- varnames = ("klass",) + varnames
- else:
- raise SystemError("Methods must be normal, staticmethod or "
- "classmethod")
- argstr = ", ".join(varnames)
- fakefunc = eval("lambda {}: None".format(argstr))
- fakefunc.__name__ = props["name"]
- fakefunc.__defaults__ = props["defaults"]
- fakefunc.__kwdefaults__ = props["kwdefaults"]
- fakefunc.__annotations__ = props["annotations"]
- return inspect._signature_from_function(inspect.Signature, fakefunc)
+def create_signature(props, key):
+ return layout.create_signature(props, key)
# end of file
diff --git a/sources/pyside2/PySide2/support/signature/mapping.py b/sources/pyside2/PySide2/support/signature/mapping.py
index dd3df0988..6b7d1ad01 100644
--- a/sources/pyside2/PySide2/support/signature/mapping.py
+++ b/sources/pyside2/PySide2/support/signature/mapping.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -46,7 +46,7 @@ This module has the mapping from the pyside C-modules view of signatures
to the Python representation.
The PySide modules are not loaded in advance, but only after they appear
-in sys.modules. This minimises the loading overhead.
+in sys.modules. This minimizes the loading overhead.
In principle, we need to re-load the module, when the imports change.
But it is much easier to do it on demand, when we get an exception.
See _resolve_value() in singature.py
@@ -71,7 +71,6 @@ FloatMatrix = typing.List[typing.List[float]]
# Pair could be more specific, but we loose the info in the generator.
Pair = typing.Tuple[typing.Any, typing.Any]
MultiMap = typing.DefaultDict[str, typing.List[str]]
-Text = typing.Text
# ulong_max is only 32 bit on windows.
ulong_max = 2*sys.maxsize+1 if len(struct.pack("L", 1)) != 4 else 0xffffffff
@@ -153,7 +152,7 @@ type_map = {}
def init_QtCore():
import PySide2.QtCore
- from PySide2.QtCore import Qt, QUrl, QDir, QGenericArgument
+ from PySide2.QtCore import Qt, QUrl, QDir
from PySide2.QtCore import QRect, QSize, QPoint, QLocale, QByteArray
from PySide2.QtCore import QMarginsF # 5.9
try:
@@ -201,9 +200,8 @@ def init_QtCore():
"ULONG_MAX": ulong_max,
"quintptr": int,
"PyCallable": typing.Callable,
- "...": ellipsis, # no idea how this should be translated... maybe so?
"PyTypeObject": type,
- "PySequence": typing.Sequence,
+ "PySequence": typing.Iterable, # important for numpy
"qptrdiff": int,
"true": True,
"Qt.HANDLE": int, # be more explicit with some consts?
@@ -242,7 +240,7 @@ def init_QtCore():
"QDir.SortFlags(QDir.Name | QDir.IgnoreCase)"),
"PyBytes": bytes,
"PyByteArray": bytearray,
- "PyUnicode": Text,
+ "PyUnicode": typing.Text,
"signed long": int,
"PySide2.QtCore.int": int,
"PySide2.QtCore.char": StringList, # A 'char **' is a list of strings.
@@ -259,13 +257,13 @@ def init_QtCore():
"float[][]": FloatMatrix, # 5.9
"PySide2.QtCore.unsigned int": int, # 5.9 Ubuntu
"PySide2.QtCore.long long": int, # 5.9, MSVC 15
- "QGenericArgument(nullptr)": QGenericArgument(None), # 5.10
+ "QGenericArgument(nullptr)": ellipsis, # 5.10
"QModelIndex()": Invalid("PySide2.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?!
- "QGenericArgument((0))": None, # 5.6, RHEL 6.6. Is that ok?
- "QGenericArgument()": None,
- "QGenericArgument(0)": None,
- "QGenericArgument(NULL)": None, # 5.6, MSVC
- "QGenericArgument(Q_NULLPTR)": None,
+ "QGenericArgument((0))": ellipsis, # 5.6, RHEL 6.6. Is that ok?
+ "QGenericArgument()": ellipsis,
+ "QGenericArgument(0)": ellipsis,
+ "QGenericArgument(NULL)": ellipsis, # 5.6, MSVC
+ "QGenericArgument(Q_NULLPTR)": ellipsis,
"zero(PySide2.QtCore.QObject)": None,
"zero(PySide2.QtCore.QThread)": None,
"zero(quintptr)": 0,
@@ -289,6 +287,8 @@ def init_QtCore():
"zero(PySide2.QtCore.QEvent.Type)": None,
"CheckIndexOption.NoOption": Instance(
"PySide2.QtCore.QAbstractItemModel.CheckIndexOptions.NoOption"), # 5.11
+ "QVariantMap": dict,
+ "PySide2.QtCore.QCborStreamReader.StringResult": typing.AnyStr,
})
try:
type_map.update({
@@ -301,7 +301,6 @@ def init_QtCore():
def init_QtGui():
import PySide2.QtGui
- from PySide2.QtGui import QPageLayout, QPageSize # 5.9
type_map.update({
"QVector< QTextLayout.FormatRange >()": [], # do we need more structure?
"USHRT_MAX": ushort_max,
@@ -313,7 +312,7 @@ def init_QtGui():
"GL_COLOR_BUFFER_BIT": GL_COLOR_BUFFER_BIT,
"GL_NEAREST": GL_NEAREST,
"WId": WId,
- "PySide2.QtGui.QPlatformSurface": Virtual("PySide2.QtGui.QPlatformSurface"), # hmm...
+ "PySide2.QtGui.QPlatformSurface": int, # a handle
"QList< QTouchEvent.TouchPoint >()": [], # XXX improve?
"QPixmap()": Default("PySide2.QtGui.QPixmap"), # can't create without qApp
"PySide2.QtCore.uint8_t": int, # macOS 5.9
@@ -325,6 +324,7 @@ def init_QtGui():
"zero(PySide2.QtGui.QTextLayout.FormatRange)": None,
"zero(PySide2.QtGui.QTouchDevice)": None,
"zero(PySide2.QtGui.QScreen)": None,
+ "PySide2.QtGui.QGenericMatrix": Missing("PySide2.QtGui.QGenericMatrix"),
})
return locals()
@@ -396,7 +396,6 @@ def init_QtMultimedia():
import PySide2.QtMultimedia
import PySide2.QtMultimediaWidgets
type_map.update({
- "QVariantMap": dict,
"QGraphicsVideoItem": PySide2.QtMultimediaWidgets.QGraphicsVideoItem,
"QVideoWidget": PySide2.QtMultimediaWidgets.QVideoWidget,
})
diff --git a/sources/pyside2/PySide2/support/signature/parser.py b/sources/pyside2/PySide2/support/signature/parser.py
index 9313fb540..dd6640fde 100644
--- a/sources/pyside2/PySide2/support/signature/parser.py
+++ b/sources/pyside2/PySide2/support/signature/parser.py
@@ -1,6 +1,6 @@
#############################################################################
##
-## Copyright (C) 2017 The Qt Company Ltd.
+## Copyright (C) 2018 The Qt Company Ltd.
## Contact: https://www.qt.io/licensing/
##
## This file is part of Qt for Python.
@@ -48,6 +48,7 @@ import functools
from .mapping import type_map, update_mapping, __dict__ as namespace
_DEBUG = False
+LIST_KEYWORDS = False
"""
parser.py
@@ -119,6 +120,8 @@ def _parse_line(line):
for arg in arglist:
name, ann = arg.split(":")
if name in keyword.kwlist:
+ if LIST_KEYWORDS:
+ print("KEYWORD", ret)
name = name + "_"
if "=" in ann:
ann, default = ann.split("=")
@@ -130,6 +133,10 @@ def _parse_line(line):
multi = ret["multi"]
if multi is not None:
ret["multi"] = int(multi)
+ funcname = ret["funcname"]
+ parts = funcname.split(".")
+ if parts[-1] in keyword.kwlist:
+ ret["funcname"] = funcname + "_"
return ret
def make_good_value(thing, valtype):
@@ -192,8 +199,14 @@ def calculate_props(line):
arglist = res["arglist"]
annotations = {}
_defaults = []
- for tup in arglist:
+ for idx, tup in enumerate(arglist):
name, ann = tup[:2]
+ if ann == "...":
+ name = "*args"
+ # copy the fields back :()
+ ann = 'NULL' # maps to None
+ tup = name, ann
+ arglist[idx] = tup
annotations[name] = _resolve_type(ann, line)
if len(tup) == 3:
default = _resolve_value(tup[2], ann, line)
@@ -214,6 +227,31 @@ def calculate_props(line):
props["multi"] = res["multi"]
return props
+def fixup_multilines(sig_str):
+ lines = list(line.strip() for line in sig_str.strip().splitlines())
+ res = []
+ multi_lines = []
+ for line in lines:
+ multi = re.match(r"([0-9]+):", line)
+ if multi:
+ idx, rest = int(multi.group(1)), line[multi.end():]
+ multi_lines.append(rest)
+ if idx > 0:
+ continue
+ # remove duplicates
+ multi_lines = list(set(multi_lines))
+ # renumber or return a single line
+ nmulti = len(multi_lines)
+ if nmulti > 1:
+ for idx, line in enumerate(multi_lines):
+ res.append("{}:{}".format(nmulti-idx-1, line))
+ else:
+ res.append(multi_lines[0])
+ multi_lines = []
+ else:
+ res.append(line)
+ return res
+
def pyside_type_init(typemod, sig_str):
dprint()
if type(typemod) is types.ModuleType:
@@ -222,9 +260,10 @@ def pyside_type_init(typemod, sig_str):
dprint("Initialization of type '{}.{}'".format(typemod.__module__,
typemod.__name__))
update_mapping()
+ lines = fixup_multilines(sig_str)
ret = {}
multi_props = []
- for line in sig_str.strip().splitlines():
+ for line in lines:
props = calculate_props(line)
shortname = props["name"]
multi = props["multi"]
@@ -232,10 +271,10 @@ def pyside_type_init(typemod, sig_str):
ret[shortname] = props
dprint(props)
else:
- fullname = props.pop("fullname")
multi_props.append(props)
if multi > 0:
continue
+ fullname = props.pop("fullname")
multi_props = {"multi": multi_props, "fullname": fullname}
ret[shortname] = multi_props
dprint(multi_props)
diff --git a/sources/pyside2/tests/registry/init_platform.py b/sources/pyside2/tests/registry/init_platform.py
index 03d0ed133..22875a63e 100644
--- a/sources/pyside2/tests/registry/init_platform.py
+++ b/sources/pyside2/tests/registry/init_platform.py
@@ -55,9 +55,10 @@ from textwrap import dedent
all_modules = list("PySide2." + x for x in PySide2.__all__)
-from PySide2.support.signature import inspect
from PySide2.QtCore import __version__
+from PySide2.support.signature.lib.enum_sig import SimplifyingEnumerator
+
is_py3 = sys.version_info[0] == 3
is_ci = os.environ.get("QTEST_ENVIRONMENT", "") == "ci"
# Python2 legacy: Correct 'linux2' to 'linux', recommended way.
@@ -114,7 +115,7 @@ class Formatter(object):
Formatter is formatting the signature listing of an enumerator.
It is written as context managers in order to avoid many callbacks.
- The division in formatter and enumerator is done to keep the
+ The separation in formatter and enumerator is done to keep the
unrelated tasks of enumeration and formatting apart.
"""
def __init__(self, outfile):
@@ -134,7 +135,7 @@ class Formatter(object):
self.print(" })")
@contextmanager
- def klass(self, class_name):
+ def klass(self, class_name, class_str):
self.class_name = class_name
self.print()
self.print(" # class {}.{}:".format(self.mod_name, class_name))
@@ -152,89 +153,6 @@ class Formatter(object):
yield key
-class ExactEnumerator(object):
- """
- ExactEnumerator enumerates all signatures in a module as they are.
-
- This class is used for generating complete listings of all signatures.
- An appropriate formatter should be supplied, if printable output
- is desired.
- """
- def __init__(self, formatter, result_type=dict):
- self.fmt = formatter
- self.result_type = result_type
-
- def module(self, mod_name):
- __import__(mod_name)
- with self.fmt.module(mod_name):
- module = sys.modules[mod_name]
- members = inspect.getmembers(module, inspect.isclass)
- ret = self.result_type()
- for class_name, klass in members:
- ret.update(self.klass(class_name, klass))
- return ret
-
- def klass(self, class_name, klass):
- with self.fmt.klass(class_name):
- ret = self.function("__init__", klass)
- # class_members = inspect.getmembers(klass)
- # gives us also the inherited things.
- class_members = sorted(list(klass.__dict__.items()))
- for func_name, func in class_members:
- ret.update(self.function(func_name, func))
- return ret
-
- def function(self, func_name, func):
- ret = self.result_type()
- signature = getattr(func, '__signature__', None)
- if signature is not None:
- with self.fmt.function(func_name, signature) as key:
- ret[key] = signature
- return ret
-
-
-def simplify(signature):
- if isinstance(signature, list):
- # remove duplicates which still sometimes occour:
- ret = set(simplify(sig) for sig in signature)
- return sorted(ret) if len(ret) > 1 else list(ret)[0]
- ret = []
- for pv in signature.parameters.values():
- txt = str(pv)
- if txt == "self":
- continue
- txt = txt[txt.index(":") + 1:]
- if "=" in txt:
- txt = txt[:txt.index("=")]
- quote = txt[0]
- if quote in ("'", '"') and txt[-1] == quote:
- txt = txt[1:-1]
- ret.append(txt)
- return tuple(ret)
-
-
-class SimplifyingEnumerator(ExactEnumerator):
- """
- SimplifyingEnumerator enumerates all signatures in a module filtered.
-
- There are no default values, no variable
- names and no self parameter. Only types are present after simplification.
- The functions 'next' resp. '__next__' are removed
- to make the output identical for Python 2 and 3.
- An appropriate formatter should be supplied, if printable output
- is desired.
- """
-
- def function(self, func_name, func):
- ret = self.result_type()
- signature = getattr(func, '__signature__', None)
- sig = simplify(signature) if signature is not None else None
- if sig is not None and func_name not in ("next", "__next__"):
- with self.fmt.function(func_name, sig) as key:
- ret[key] = sig
- return ret
-
-
def enum_all():
fmt = Formatter(None)
enu = SimplifyingEnumerator(fmt)
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index 35e12f780..c65d7e0bd 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -1613,6 +1613,13 @@ void AbstractMetaClass::setTemplateBaseClassInstantiations(AbstractMetaTypeList&
metaClassBaseTemplateInstantiations()->insert(this, instantiations);
}
+// Does any of the base classes require deletion in the main thread?
+bool AbstractMetaClass::deleteInMainThread() const
+{
+ return typeEntry()->deleteInMainThread()
+ || (m_baseClass && m_baseClass->deleteInMainThread());
+}
+
static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func)
{
for (const AbstractMetaFunction *f : l) {
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index 42129e9b7..aaefa32d5 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -1699,6 +1699,8 @@ public:
return m_hasToStringCapability;
}
+ bool deleteInMainThread() const;
+
static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
const QString &name);
static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp
index 69cddca4c..dcfd9f740 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase.cpp
+++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp
@@ -782,6 +782,7 @@ void ComplexTypeEntry::formatDebug(QDebug &d) const
FORMAT_BOOL("QObject", m_qobject)
FORMAT_BOOL("polymorphicBase", m_polymorphicBase)
FORMAT_BOOL("genericClass", m_genericClass)
+ FORMAT_BOOL("deleteInMainThread", m_deleteInMainThread)
if (m_typeFlags != 0)
d << ", typeFlags=" << m_typeFlags;
d << ", copyableFlag=" << m_copyableFlag
diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp
index ba219cf5f..21c35bda6 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystem.cpp
@@ -1301,8 +1301,8 @@ void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader,
if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false))
ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
} else if (name == deleteInMainThreadAttribute()) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false))
+ ctype->setDeleteInMainThread(true);
} else if (name == QLatin1String("target-type")) {
ctype->setTargetType(attributes->takeAt(i).value().toString());
}
@@ -3221,7 +3221,8 @@ ComplexTypeEntry::ComplexTypeEntry(const QString &name, TypeEntry::Type t,
m_qualifiedCppName(name),
m_qobject(false),
m_polymorphicBase(false),
- m_genericClass(false)
+ m_genericClass(false),
+ m_deleteInMainThread(false)
{
}
diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h
index 028f016f3..721d19f29 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.h
+++ b/sources/shiboken2/ApiExtractor/typesystem.h
@@ -1346,6 +1346,9 @@ public:
m_genericClass = isGeneric;
}
+ bool deleteInMainThread() const { return m_deleteInMainThread; }
+ void setDeleteInMainThread(bool d) { m_deleteInMainThread = d; }
+
CopyableFlag copyable() const
{
return m_copyableFlag;
@@ -1403,6 +1406,7 @@ private:
uint m_qobject : 1;
uint m_polymorphicBase : 1;
uint m_genericClass : 1;
+ uint m_deleteInMainThread : 1;
QString m_polymorphicIdValue;
QString m_lookupName;
diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt
index 1af84fca1..12a9b8773 100644
--- a/sources/shiboken2/CMakeLists.txt
+++ b/sources/shiboken2/CMakeLists.txt
@@ -5,8 +5,9 @@ include(CheckIncludeFileCXX)
cmake_minimum_required(VERSION 3.1)
cmake_policy(VERSION 3.1)
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules/
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../cmake_helpers/
${CMAKE_MODULE_PATH})
+include(helpers)
find_package(Qt5 5.7 REQUIRED COMPONENTS Core Xml XmlPatterns)
@@ -158,6 +159,8 @@ list(GET SHIBOKEN_VERSION_OUTPUT 4 shiboken_PRE_RELEASE_VERSION)
set(shiboken2_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}")
set(shiboken2_library_so_version "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}")
+compute_config_py_values(shiboken2_VERSION)
+
## For debugging the PYTHON* variables
message("PYTHONLIBS_FOUND: " ${PYTHONLIBS_FOUND})
message("PYTHON_LIBRARIES: " ${PYTHON_LIBRARIES})
diff --git a/sources/shiboken2/generator/CMakeLists.txt b/sources/shiboken2/generator/CMakeLists.txt
index 032118666..fb8058b2d 100644
--- a/sources/shiboken2/generator/CMakeLists.txt
+++ b/sources/shiboken2/generator/CMakeLists.txt
@@ -38,3 +38,33 @@ target_link_libraries(shiboken2
configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
install(TARGETS shiboken2 DESTINATION bin)
+
+set(shiboken_generator_package_name "shiboken2_generator")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/_config.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/_config.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
+
+# shiboken2 setuptools entry point
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_tool.py
+ DESTINATION bin
+ PERMISSIONS
+ OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ GROUP_EXECUTE GROUP_READ
+ WORLD_EXECUTE WORLD_READ)
+
+# Use absolute path instead of relative path, to avoid ninja build errors due to
+# duplicate file dependency inconsistency.
+set(shiboken_version_relative_path "${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_version.py")
+get_filename_component(shiboken_version_path ${shiboken_version_relative_path} ABSOLUTE)
+configure_file("${shiboken_version_path}"
+ "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py" @ONLY)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
diff --git a/sources/shiboken2/generator/__init__.py.in b/sources/shiboken2/generator/__init__.py.in
new file mode 100644
index 000000000..4be6a833b
--- /dev/null
+++ b/sources/shiboken2/generator/__init__.py.in
@@ -0,0 +1,2 @@
+__version__ = "@FINAL_PACKAGE_VERSION@"
+__version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
diff --git a/sources/shiboken2/generator/_config.py.in b/sources/shiboken2/generator/_config.py.in
new file mode 100644
index 000000000..985735fa4
--- /dev/null
+++ b/sources/shiboken2/generator/_config.py.in
@@ -0,0 +1,9 @@
+version = "@FINAL_PACKAGE_VERSION@"
+version_info = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+@PACKAGE_BUILD_DATE@
+@PACKAGE_BUILD_COMMIT_DATE@
+@PACKAGE_BUILD_COMMIT_HASH@
+@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
+@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 0f94793e9..f0d6c9082 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -502,7 +502,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
writeCopyFunction(s, classContext);
- signatureStream << metaClass->fullName() << ".__copy__()" << endl;
+ signatureStream << fullPythonClassName(metaClass) << ".__copy__()" << endl;
}
// Write single method definitions
@@ -4947,8 +4947,16 @@ void CppGenerator::writeClassRegister(QTextStream &s,
else
s << INDENT << "0," << endl;
- // 9:isInnerClass
- s << INDENT << (hasEnclosingClass ? "true" : "false") << endl;
+ // 9:wrapperflags
+ QByteArrayList wrapperFlags;
+ if (hasEnclosingClass)
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass"));
+ if (metaClass->deleteInMainThread())
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread"));
+ if (wrapperFlags.isEmpty())
+ s << INDENT << '0';
+ else
+ s << INDENT << wrapperFlags.join(" | ");
}
s << INDENT << ");" << endl;
s << INDENT << endl;
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 6d263dd01..b9eea7529 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -361,7 +361,19 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
return metaType->cppSignature();
}
-QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func)
+QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClass)
+{
+ QString fullClassName = metaClass->name();
+ const AbstractMetaClass *enclosing = metaClass->enclosingClass();
+ while (enclosing) {
+ fullClassName.prepend(enclosing->name() + QLatin1Char('.'));
+ enclosing = enclosing->enclosingClass();
+ }
+ fullClassName.prepend(packageName() + QLatin1Char('.'));
+ return fullClassName;
+}
+
+QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction *func) //WS
{
QString funcName;
if (func->isOperatorOverload())
@@ -369,11 +381,11 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* fu
else
funcName = func->name();
if (func->ownerClass()) {
- QString fullName = func->ownerClass()->fullName();
+ QString fullClassName = fullPythonClassName(func->ownerClass());
if (func->isConstructor())
- funcName = fullName;
+ funcName = fullClassName;
else
- funcName.prepend(fullName + QLatin1Char('.'));
+ funcName.prepend(fullClassName + QLatin1Char('.'));
}
else {
funcName = packageName() + QLatin1Char('.') + func->name();
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
index 76f71827a..60e31a99b 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -214,7 +214,8 @@ protected:
QString wrapperName(const AbstractMetaClass* metaClass) const;
QString wrapperName(const AbstractMetaType *metaType) const;
- QString fullPythonFunctionName(const AbstractMetaFunction* func);
+ QString fullPythonClassName(const AbstractMetaClass *metaClass);
+ QString fullPythonFunctionName(const AbstractMetaFunction *func); //WS
static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum);
static QString protectedFieldGetterName(const AbstractMetaField* field);
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 2b27f2881..2f5f27989 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -40,6 +40,7 @@
#include "basewrapper.h"
#include "basewrapper_p.h"
#include "bindingmanager.h"
+#include "helper.h"
#include "sbkconverter.h"
#include "sbkenum.h"
#include "sbkstring.h"
@@ -190,6 +191,12 @@ SbkObjectType *SbkObject_TypeF(void)
return reinterpret_cast<SbkObjectType *>(type);
}
+static int mainThreadDeletionHandler(void *)
+{
+ if (Py_IsInitialized())
+ Shiboken::BindingManager::instance().runDeletionInMainThread();
+ return 0;
+}
static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete)
{
@@ -218,8 +225,27 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete)
PyObject_ClearWeakRefs(pyObj);
// If I have ownership and is valid delete C++ pointer
- if (canDelete && sbkObj->d->hasOwnership && sbkObj->d->validCppObject) {
- SbkObjectTypePrivate *sotp = PepType_SOTP(pyType);
+ SbkObjectTypePrivate *sotp{nullptr};
+ canDelete &= sbkObj->d->hasOwnership && sbkObj->d->validCppObject;
+ if (canDelete) {
+ sotp = PepType_SOTP(pyType);
+ if (sotp->delete_in_main_thread && Shiboken::currentThreadId() != Shiboken::mainThreadId()) {
+ auto &bindingManager = Shiboken::BindingManager::instance();
+ if (sotp->is_multicpp) {
+ Shiboken::DtorAccumulatorVisitor visitor(sbkObj);
+ Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor);
+ for (const auto &e : visitor.entries())
+ bindingManager.addToDeletionInMainThread(e);
+ } else {
+ Shiboken::DestructorEntry e{sotp->cpp_dtor, sbkObj->d->cptr[0]};
+ bindingManager.addToDeletionInMainThread(e);
+ }
+ Py_AddPendingCall(mainThreadDeletionHandler, nullptr);
+ canDelete = false;
+ }
+ }
+
+ if (canDelete) {
if (sotp->is_multicpp) {
Shiboken::DtorAccumulatorVisitor visitor(sbkObj);
Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor);
@@ -533,6 +559,8 @@ bool DtorAccumulatorVisitor::visit(SbkObjectType *node)
return false;
}
+void _initMainThreadId(); // helper.cpp
+
namespace Conversions { void init(); }
void init()
@@ -541,6 +569,8 @@ void init()
if (shibokenAlreadInitialised)
return;
+ _initMainThreadId();
+
Conversions::init();
PyEval_InitThreads();
@@ -735,7 +765,7 @@ introduceWrapperType(PyObject *enclosingObject,
ObjectDestructor cppObjDtor,
SbkObjectType *baseType,
PyObject *baseTypes,
- bool isInnerClass)
+ unsigned wrapperFlags)
{
if (baseType) {
typeSpec->slots[0].pfunc = reinterpret_cast<void *>(baseType);
@@ -760,10 +790,14 @@ introduceWrapperType(PyObject *enclosingObject,
return nullptr;
initPrivateData(type);
+ auto sotp = PepType_SOTP(type);
+ if (wrapperFlags & DeleteInMainThread)
+ sotp->delete_in_main_thread = 1;
+
setOriginalName(type, originalName);
setDestructorFunction(type, cppObjDtor);
- if (isInnerClass) {
+ if (wrapperFlags & InnerClass) {
if (PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0)
return type;
else
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index 06b17a151..f8940b842 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -192,6 +192,12 @@ LIBSHIBOKEN_API void setDestructorFunction(SbkObjectType* self, ObjectDes
LIBSHIBOKEN_API void initPrivateData(SbkObjectType* self);
+enum WrapperFlags
+{
+ InnerClass = 0x1,
+ DeleteInMainThread = 0x2
+};
+
/**
* Initializes a Shiboken wrapper type and adds it to the module,
* or to the enclosing class if the type is an inner class.
@@ -217,7 +223,7 @@ LIBSHIBOKEN_API SbkObjectType *introduceWrapperType(PyObject *enclosingObject,
ObjectDestructor cppObjDtor,
SbkObjectType *baseType,
PyObject *baseTypes,
- bool isInnerClass);
+ unsigned wrapperFlags = 0);
/**
* Set the subtype init hook for a type.
diff --git a/sources/shiboken2/libshiboken/basewrapper_p.h b/sources/shiboken2/libshiboken/basewrapper_p.h
index d99ca19ea..f8a381078 100644
--- a/sources/shiboken2/libshiboken/basewrapper_p.h
+++ b/sources/shiboken2/libshiboken/basewrapper_p.h
@@ -137,6 +137,7 @@ struct SbkObjectTypePrivate
/// Tells is the type is a value type or an object-type, see BEHAVIOUR_* constants.
// TODO-CONVERTERS: to be deprecated/removed
int type_behaviour : 2;
+ int delete_in_main_thread : 1;
/// C++ name
char* original_name;
/// Type user data
diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp
index 82c5bd65f..8a9e912fd 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken2/libshiboken/bindingmanager.cpp
@@ -136,8 +136,11 @@ static void showWrapperMap(const WrapperMap& wrapperMap)
#endif
struct BindingManager::BindingManagerPrivate {
+ using DestructorEntries = std::vector<DestructorEntry>;
+
WrapperMap wrapperMapper;
Graph classHierarchy;
+ DestructorEntries deleteInMainThread;
bool destroying;
BindingManagerPrivate() : destroying(false) {}
@@ -249,6 +252,18 @@ void BindingManager::releaseWrapper(SbkObject* sbkObj)
sbkObj->d->validCppObject = false;
}
+void BindingManager::runDeletionInMainThread()
+{
+ for (const DestructorEntry &e : m_d->deleteInMainThread)
+ e.destructor(e.cppInstance);
+ m_d->deleteInMainThread.clear();
+}
+
+void BindingManager::addToDeletionInMainThread(const DestructorEntry &e)
+{
+ m_d->deleteInMainThread.push_back(e);
+}
+
SbkObject* BindingManager::retrieveWrapper(const void* cptr)
{
WrapperMap::iterator iter = m_d->wrapperMapper.find(cptr);
diff --git a/sources/shiboken2/libshiboken/bindingmanager.h b/sources/shiboken2/libshiboken/bindingmanager.h
index c09b985dc..d03aa999a 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.h
+++ b/sources/shiboken2/libshiboken/bindingmanager.h
@@ -50,6 +50,8 @@ struct SbkObjectType;
namespace Shiboken
{
+struct DestructorEntry;
+
typedef void (*ObjectVisitor)(SbkObject*, void*);
class LIBSHIBOKEN_API BindingManager
@@ -67,6 +69,9 @@ public:
void registerWrapper(SbkObject* pyObj, void* cptr);
void releaseWrapper(SbkObject* wrapper);
+ void runDeletionInMainThread();
+ void addToDeletionInMainThread(const DestructorEntry &);
+
SbkObject* retrieveWrapper(const void* cptr);
PyObject* getOverride(const void* cptr, const char* methodName);
diff --git a/sources/shiboken2/libshiboken/helper.cpp b/sources/shiboken2/libshiboken/helper.cpp
index 472924723..e42daff07 100644
--- a/sources/shiboken2/libshiboken/helper.cpp
+++ b/sources/shiboken2/libshiboken/helper.cpp
@@ -41,6 +41,12 @@
#include "sbkstring.h"
#include <stdarg.h>
+#ifdef _WIN32
+# include <windows.h>
+#else
+# include <pthread.h>
+#endif
+
namespace Shiboken
{
@@ -141,4 +147,24 @@ int warning(PyObject* category, int stacklevel, const char* format, ...)
return result;
}
+ThreadId currentThreadId()
+{
+#if defined(_WIN32)
+ return GetCurrentThreadId();
+#elif defined(__APPLE_CC__)
+ return reinterpret_cast<ThreadId>(pthread_self());
+#else
+ return pthread_self();
+#endif
+}
+
+// Internal, used by init() from main thread
+static ThreadId _mainThreadId{0};
+void _initMainThreadId() { _mainThreadId = currentThreadId(); }
+
+ThreadId mainThreadId()
+{
+ return _mainThreadId;
+}
+
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/helper.h b/sources/shiboken2/libshiboken/helper.h
index 79a30871a..9b6d8903f 100644
--- a/sources/shiboken2/libshiboken/helper.h
+++ b/sources/shiboken2/libshiboken/helper.h
@@ -90,6 +90,10 @@ class AutoArrayPointer
T* data;
};
+typedef unsigned long long ThreadId;
+LIBSHIBOKEN_API ThreadId currentThreadId();
+LIBSHIBOKEN_API ThreadId mainThreadId();
+
/**
* An utility function used to call PyErr_WarnEx with a formatted message.
*/
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index 4481f1cdd..18094c5c0 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -398,7 +398,10 @@ PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
return ret;
}
+#endif // Py_LIMITED_API
+
// This is only a simple local helper that returns a computed variable.
+// Used also in Python 2.
static PyObject *
PepRun_GetResult(const char *command, const char *resvar)
{
@@ -415,6 +418,8 @@ PepRun_GetResult(const char *command, const char *resvar)
return res;
}
+#ifdef Py_LIMITED_API
+
/*****************************************************************************
*
* Support for classobject.h
@@ -499,13 +504,26 @@ PyTypeObject *PepStaticMethod_TypePtr = NULL;
static PyTypeObject *getStaticMethodType(void)
{
+ // this works for Python 3, only
+ // "StaticMethodType = type(str.__dict__['maketrans'])\n";
static const char prog[] =
- "StaticMethodType = type(str.__dict__['maketrans'])\n";
- return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethodType");
+ "from xxsubtype import spamlist\n"
+ "StaticMethod_Type = type(spamlist.__dict__['staticmeth'])\n";
+ return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethod_Type");
}
-
#endif // Py_LIMITED_API
+#if PY_VERSION_HEX < 0x03000000
+PyTypeObject *PepMethodDescr_TypePtr = NULL;
+
+static PyTypeObject *getMethodDescrType(void)
+{
+ static const char prog[] =
+ "MethodDescr_Type = type(str.split)\n";
+ return (PyTypeObject *) PepRun_GetResult(prog, "MethodDescr_Type");
+}
+#endif
+
/*****************************************************************************
*
* Common newly needed functions
@@ -630,6 +648,9 @@ Pep384_Init()
PepFunction_TypePtr = getFunctionType();
PepStaticMethod_TypePtr = getStaticMethodType();
#endif
+#if PY_VERSION_HEX < 0x03000000
+ PepMethodDescr_TypePtr = getMethodDescrType();
+#endif
}
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
index b566a6218..6649fa95e 100644
--- a/sources/shiboken2/libshiboken/pep384impl.h
+++ b/sources/shiboken2/libshiboken/pep384impl.h
@@ -286,7 +286,7 @@ LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject *
// But this is no problem as we check it's validity for every version.
#define PYTHON_BUFFER_VERSION_COMPATIBLE (PY_VERSION_HEX >= 0x03030000 && \
- PY_VERSION_HEX < 0X0307FFFF)
+ PY_VERSION_HEX < 0x0307FFFF)
#if !PYTHON_BUFFER_VERSION_COMPATIBLE
# error Please check the buffer compatibility for this python version!
#endif
@@ -470,6 +470,12 @@ extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr;
#else
#define PepStaticMethod_TypePtr &PyStaticMethod_Type
#endif
+// Although not PEP specific, we resolve this similar issue, here:
+#if PY_VERSION_HEX < 0x03000000
+extern LIBSHIBOKEN_API PyTypeObject *PepMethodDescr_TypePtr;
+#else
+#define PepMethodDescr_TypePtr &PyMethodDescr_Type
+#endif
/*****************************************************************************
*
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index f0bb8e609..24d60acc4 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -77,18 +77,23 @@ typedef struct safe_globals_struc {
static safe_globals pyside_globals = 0;
-static PyObject *GetSignature_Function(PyCFunctionObject *);
-static PyObject *GetSignature_TypeMod(PyObject *);
+static PyObject *GetSignature_Function(PyCFunctionObject *, const char *);
+static PyObject *GetSignature_TypeMod(PyObject *, const char *);
+static PyObject *GetSignature_Wrapper(PyObject *, const char *);
+static PyObject *get_signature(PyObject *self, PyObject *args);
static PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
+static void init_module_1(void);
+static void init_module_2(void);
+
const char helper_module_name[] = "signature_loader";
const char bootstrap_name[] = "bootstrap";
const char arg_name[] = "pyside_arg_dict";
const char func_name[] = "pyside_type_init";
static PyObject *
-CreateSignature(PyObject *props, const char *sig_kind)
+CreateSignature(PyObject *props, PyObject *key)
{
/*
* Here is the new function to create all signatures. It simply calls
@@ -97,22 +102,22 @@ CreateSignature(PyObject *props, const char *sig_kind)
* to support '_signature_is_functionlike()'.
*/
return PyObject_CallFunction(pyside_globals->createsig_func,
- (char *)"(Os)", props, sig_kind);
+ (char *)"(OO)", props, key);
}
static PyObject *
-pyside_cf_get___signature__(PyObject *func)
+pyside_cf_get___signature__(PyObject *func, const char *modifier)
{
- return GetSignature_Function((PyCFunctionObject *)func);
+ return GetSignature_Function((PyCFunctionObject *)func, modifier);
}
static PyObject *
-pyside_sm_get___signature__(PyObject *sm)
+pyside_sm_get___signature__(PyObject *sm, const char *modifier)
{
PyObject *func, *ret;
func = PyObject_GetAttrString(sm, "__func__");
- ret = GetSignature_Function((PyCFunctionObject *)func);
+ ret = GetSignature_Function((PyCFunctionObject *)func, modifier);
Py_XDECREF(func);
return ret;
}
@@ -192,7 +197,7 @@ qualname_to_func(PyObject *ob)
#endif
static PyObject *
-pyside_md_get___signature__(PyObject *ob)
+pyside_md_get___signature__(PyObject *ob, const char *modifier)
{
PyObject *func;
PyObject *result;
@@ -218,21 +223,31 @@ pyside_md_get___signature__(PyObject *ob)
return Py_None;
if (func == NULL)
Py_FatalError("missing mapping in MethodDescriptor");
- result = pyside_cf_get___signature__(func);
+ result = pyside_cf_get___signature__(func, modifier);
Py_DECREF(func);
return result;
}
static PyObject *
-pyside_tp_get___signature__(PyObject *typemod)
+pyside_wd_get___signature__(PyObject *ob, const char *modifier)
+{
+ return GetSignature_Wrapper(ob, modifier);
+}
+
+static PyObject *
+pyside_tp_get___signature__(PyObject *typemod, const char *modifier)
{
- return GetSignature_TypeMod(typemod);
+ return GetSignature_TypeMod(typemod, modifier);
}
+// forward
+static PyObject *
+GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier);
+
static PyObject *
-GetSignature_Function(PyCFunctionObject *func)
+GetSignature_Function(PyCFunctionObject *func, const char *modifier)
{
- PyObject *typemod, *type_name, *dict, *props, *value, *selftype;
+ PyObject *typemod, *type_name, *dict, *props, *selftype;
PyObject *func_name = PyObject_GetAttrString((PyObject *)func, "__name__");
const char *sig_kind;
int flags;
@@ -241,12 +256,8 @@ GetSignature_Function(PyCFunctionObject *func)
if (selftype == NULL)
selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)func);
if (selftype == NULL) {
- if (!PyErr_Occurred()) {
- PyErr_Format(PyExc_SystemError,
- "the signature for \"%s\" should exist",
- PepCFunction_GET_NAMESTR(func)
- );
- }
+ if (!PyErr_Occurred())
+ Py_RETURN_NONE;
return NULL;
}
if ((PyType_Check(selftype) || PyModule_Check(selftype)))
@@ -279,24 +290,46 @@ GetSignature_Function(PyCFunctionObject *func)
sig_kind = "staticmethod";
else
sig_kind = "method";
- value = PyDict_GetItemString(props, sig_kind);
- if (value == NULL) {
- // we need to compute a signature object
- value = CreateSignature(props, sig_kind);
- if (value != NULL) {
- if (PyDict_SetItemString(props, sig_kind, value) < 0)
- return NULL;
- }
- else
+ return GetSignature_Cached(props, sig_kind, modifier);
+}
+
+static PyObject *
+GetSignature_Wrapper(PyObject *ob, const char *modifier)
+{
+ PyObject *dict, *props;
+ PyObject *func_name = PyObject_GetAttrString(ob, "__name__");
+ PyObject *objclass = PyObject_GetAttrString(ob, "__objclass__");
+ PyObject *class_name = PyObject_GetAttrString(objclass, "__name__");
+ const char *sig_kind;
+
+ if (func_name == nullptr || objclass == nullptr || class_name == nullptr)
+ return nullptr;
+ dict = PyDict_GetItem(pyside_globals->arg_dict, class_name);
+ if (dict == NULL)
+ Py_RETURN_NONE;
+ if (PyTuple_Check(dict)) {
+ /*
+ * We do the initialization lazily.
+ * This has also the advantage that we can freely import PySide.
+ */
+ dict = PySide_BuildSignatureProps(objclass);
+ if (dict == NULL)
Py_RETURN_NONE;
}
- return Py_INCREF(value), value;
+ props = PyDict_GetItem(dict, func_name);
+ Py_DECREF(func_name);
+ Py_DECREF(objclass);
+ Py_DECREF(class_name);
+ if (props == NULL)
+ Py_RETURN_NONE;
+ sig_kind = "method";
+ return GetSignature_Cached(props, sig_kind, modifier);
}
static PyObject *
-GetSignature_TypeMod(PyObject *ob)
+GetSignature_TypeMod(PyObject *ob, const char *modifier)
{
- PyObject *ob_name, *dict, *props, *value;
+ PyObject *ob_name, *dict, *props;
const char *sig_kind;
ob_name = PyObject_GetAttrString(ob, "__name__");
@@ -314,37 +347,62 @@ GetSignature_TypeMod(PyObject *ob)
if (props == NULL)
Py_RETURN_NONE;
sig_kind = "method";
- value = PyDict_GetItemString(props, sig_kind);
- if (value == NULL) {
+ return GetSignature_Cached(props, sig_kind, modifier);
+}
+
+static PyObject *
+GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier)
+{
+ PyObject *key, *value;
+
+ if (modifier == nullptr)
+ key = Py_BuildValue("s", sig_kind);
+ else
+ key = Py_BuildValue("(ss)", sig_kind, modifier);
+ if (key == nullptr)
+ return nullptr;
+ value = PyDict_GetItem(props, key);
+ if (value == nullptr) {
// we need to compute a signature object
- value = CreateSignature(props, sig_kind);
- if (value != NULL) {
- if (PyDict_SetItemString(props, sig_kind, value) < 0)
- return NULL;
+ value = CreateSignature(props, key);
+ if (value != nullptr) {
+ if (PyDict_SetItem(props, key, value) < 0) {
+ // this is an error
+ Py_DECREF(key);
+ return nullptr;
+ }
}
- else
+ else {
+ // key not found
+ Py_DECREF(key);
Py_RETURN_NONE;
+ }
}
return Py_INCREF(value), value;
}
-
static const char PySide_PythonCode[] =
- "from __future__ import print_function, absolute_import\n"
- "import sys, os, traceback\n"
-
- "pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR', '.')\n"
- "__file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')\n"
-
- "def bootstrap():\n"
- " try:\n"
- " with open(__file__) as _f:\n"
- " exec(compile(_f.read(), __file__, 'exec'))\n"
- " except Exception as e:\n"
- " print('Exception:', e)\n"
- " traceback.print_exc(file=sys.stdout)\n"
- " globals().update(locals())\n"
- ;
+ "from __future__ import print_function, absolute_import\n" R"~(if True:
+
+ import sys, os, traceback
+
+ pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR')
+ if pyside_package_dir is None:
+ # This happens in shiboken running ctest.
+ from distutils.sysconfig import get_python_lib
+ pyside_package_dir = os.path.join(get_python_lib(), 'PySide2')
+ __file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')
+
+ def bootstrap():
+ try:
+ with open(__file__) as _f:
+ exec(compile(_f.read(), __file__, 'exec'))
+ except Exception as e:
+ print('Exception:', e)
+ traceback.print_exc(file=sys.stdout)
+ globals().update(locals())
+
+ )~";
static safe_globals_struc *
init_phase_1(void)
@@ -387,9 +445,10 @@ error:
}
static int
-init_phase_2(safe_globals_struc *p)
+init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
{
- PyObject *bootstrap_func;
+ PyObject *bootstrap_func, *v = nullptr;
+ PyMethodDef *ml;
bootstrap_func = PyObject_GetAttrString(p->helper_module, bootstrap_name);
if (bootstrap_func == NULL)
@@ -403,9 +462,22 @@ init_phase_2(safe_globals_struc *p)
p->createsig_func = PyObject_GetAttrString(p->helper_module, "create_signature");
if (p->createsig_func == NULL)
goto error;
+
+ // The single function to be called, but maybe more to come.
+ for (ml = methods; ml->ml_name != NULL; ml++) {
+ v = PyCFunction_NewEx(ml, nullptr, nullptr);
+ if (v == nullptr) {
+ goto error;
+ }
+ if (PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0) {
+ goto error;
+ }
+ Py_DECREF(v);
+ }
return 0;
error:
+ Py_XDECREF(v);
PyErr_SetString(PyExc_SystemError, "could not initialize part 2");
return -1;
}
@@ -413,8 +485,11 @@ error:
static int
add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp)
{
- PyObject *dict = type->tp_dict;
+ PyObject *dict;
+ assert(PyType_Check(type));
+ PyType_Ready(type);
+ dict = type->tp_dict;
for (; gsp->name != NULL; gsp++) {
PyObject *descr;
if (PyDict_GetItemString(dict, gsp->name))
@@ -463,6 +538,45 @@ static PyGetSetDef new_PyType_getsets[] = {
{0}
};
+static PyGetSetDef new_PyWrapperDescr_getsets[] = {
+ {(char *) "__signature__", (getter)pyside_wd_get___signature__},
+ {0}
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// get_signature -- providing a superior interface
+//
+// Additionally to the interface via __signature__, we also provide
+// a general function, which allows for different signature layouts.
+// The "modifier" argument is a string that is passed in from loader.py .
+// Configuration what the modifiers mean is completely in Python.
+//
+
+static PyObject *
+get_signature(PyObject *self, PyObject *args)
+{
+ PyObject *ob;
+ const char *modifier = nullptr;
+
+ init_module_1();
+ init_module_2();
+
+ if (!PyArg_ParseTuple(args, "O|s", &ob, &modifier))
+ return NULL;
+ if (Py_TYPE(ob) == &PyCFunction_Type)
+ return pyside_cf_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return pyside_sm_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return pyside_md_get___signature__(ob, modifier);
+ if (PyType_Check(ob))
+ return pyside_tp_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return pyside_wd_get___signature__(ob, modifier);
+ Py_RETURN_NONE;
+}
+
////////////////////////////////////////////////////////////////////////////
//
// This special Type_Ready does certain initializations earlier with
@@ -497,23 +611,23 @@ void handler(int sig) {
static int
PySideType_Ready(PyTypeObject *type)
{
- PyObject *md;
+ PyObject *md, *wd;
static int init_done = 0;
if (!init_done) {
- // Python2 does not expose certain types. We look them up:
- // PyMethodDescr_Type 'type(str.__dict__["split"])'
- // PyClassMethodDescr_Type. 'type(dict.__dict__["fromkeys"])'
- // The latter is not needed until we use class methods in PySide.
- md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split");
- if (md == NULL
+ md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split"); // method-descriptor
+ wd = PyObject_GetAttrString((PyObject *)Py_TYPE(Py_True), "__add__"); // wrapper-descriptor
+ if (md == nullptr || wd == nullptr
|| PyType_Ready(Py_TYPE(md)) < 0
- || add_more_getsets(Py_TYPE(md), new_PyMethodDescr_getsets) < 0
+ || add_more_getsets(PepMethodDescr_TypePtr, new_PyMethodDescr_getsets) < 0
|| add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0
|| add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets) < 0
- || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0)
+ || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0
+ || add_more_getsets(Py_TYPE(wd), new_PyWrapperDescr_getsets) < 0
+ )
return -1;
Py_DECREF(md);
+ Py_DECREF(wd);
#ifndef _WIN32
// We enable the stack trace in CI, only.
const char *testEnv = getenv("QTEST_ENVIRONMENT");
@@ -550,20 +664,26 @@ build_func_to_type(PyObject *obtype)
return 0;
}
+static void
+init_module_1(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ pyside_globals = init_phase_1();
+ if (pyside_globals != nullptr)
+ init_done = 1;
+ }
+}
+
static int
PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
const char *signatures)
{
PyObject *type_name, *arg_tup;
const char *name = NULL;
- static int init_done = 0;
- if (!init_done) {
- pyside_globals = init_phase_1();
- if (pyside_globals == NULL)
- return -1;
- init_done = 1;
- }
+ init_module_1();;
arg_tup = Py_BuildValue("(Os)", type, signatures);
if (arg_tup == NULL)
return -1;
@@ -599,23 +719,34 @@ PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
return 0;
}
-static PyObject *
-PySide_BuildSignatureProps(PyObject *classmod)
+static PyMethodDef signature_methods[] = {
+ {"get_signature", (PyCFunction)get_signature, METH_VARARGS,
+ "get the __signature__, but pass an optional string parameter"},
+ {NULL, NULL}
+};
+
+static void
+init_module_2(void)
{
- PyObject *arg_tup, *dict, *type_name;
static int init_done = 0;
if (!init_done) {
- if (init_phase_2(pyside_globals) < 0)
- return NULL;
+ init_phase_2(pyside_globals, signature_methods);
init_done = 1;
}
+}
+
+static PyObject *
+PySide_BuildSignatureProps(PyObject *classmod)
+{
+ PyObject *arg_tup, *dict, *type_name;
/*
* Here is the second part of the function.
* This part will be called on-demand when needed by some attribute.
* We simply pick up the arguments that we stored here and replace
* them by the function result.
*/
+ init_module_2();
type_name = PyObject_GetAttrString(classmod, "__name__");
if (type_name == NULL)
return NULL;
diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h
index 3a229cb5c..b65317662 100644
--- a/sources/shiboken2/libshiboken/signature.h
+++ b/sources/shiboken2/libshiboken/signature.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -45,8 +45,8 @@
extern "C"
{
-LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char*);
-LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char*);
+LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char *); //WS
+LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *);
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp
index 9123a09e0..a67daf12d 100644
--- a/sources/shiboken2/libshiboken/typespec.cpp
+++ b/sources/shiboken2/libshiboken/typespec.cpp
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include "sbkpython.h"
#include "typespec.h"
#include <structmember.h>
diff --git a/sources/shiboken2/shiboken_tool.py b/sources/shiboken2/shiboken_tool.py
new file mode 100755
index 000000000..8494c5d57
--- /dev/null
+++ b/sources/shiboken2/shiboken_tool.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+import sys
+import os
+import subprocess
+
+def main():
+ # The tools listed as entrypoints in setup.py are copied to 'scripts/..'
+ cmd = os.path.join("..", os.path.basename(sys.argv[0]))
+ command = [os.path.join(os.path.dirname(os.path.realpath(__file__)), cmd)]
+ command.extend(sys.argv[1:])
+ sys.exit(subprocess.call(command))
+
+if __name__ == "__main__":
+ main()
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index f2d7b30f2..517aecba8 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -40,4 +40,24 @@ target_link_libraries(shibokenmodule
add_dependencies(shibokenmodule shiboken2)
-install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES})
+install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}/shiboken2)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/_config.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/_config.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
+
+# Use absolute path instead of relative path, to avoid ninja build errors due to
+# duplicate file dependency inconsistency.
+set(shiboken_version_relative_path "${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_version.py")
+get_filename_component(shiboken_version_path ${shiboken_version_relative_path} ABSOLUTE)
+configure_file("${shiboken_version_path}"
+ "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_module_version.py" @ONLY)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_module_version.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
diff --git a/sources/shiboken2/shibokenmodule/__init__.py.in b/sources/shiboken2/shibokenmodule/__init__.py.in
new file mode 100644
index 000000000..81ab0063a
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/__init__.py.in
@@ -0,0 +1,4 @@
+__version__ = "@FINAL_PACKAGE_VERSION@"
+__version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+from .shiboken2 import *
diff --git a/sources/shiboken2/shibokenmodule/_config.py.in b/sources/shiboken2/shibokenmodule/_config.py.in
new file mode 100644
index 000000000..9607e5ca7
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/_config.py.in
@@ -0,0 +1,11 @@
+shiboken_library_soversion = str(@shiboken2_library_so_version@)
+
+version = "@FINAL_PACKAGE_VERSION@"
+version_info = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+@PACKAGE_BUILD_DATE@
+@PACKAGE_BUILD_COMMIT_DATE@
+@PACKAGE_BUILD_COMMIT_HASH@
+@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
+@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
diff --git a/testing/wheel_tester.py b/testing/wheel_tester.py
new file mode 100644
index 000000000..60fd7a38a
--- /dev/null
+++ b/testing/wheel_tester.py
@@ -0,0 +1,295 @@
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+"""
+This script is used by Coin (coin_test_instructions.py specifically) to
+test installation of generated wheels, and test building of the
+"buildable" examples samplebinding and scriptableapplication.
+
+It can also be invoked regularly from the command line via
+python testing/wheel_tester.py --qmake=some-value --cmake=some-value
+
+The qmake and cmake arguments can also be omitted, and they will be
+looked up in your PATH.
+
+Make sure that some generated wheels already exist in the dist/
+directory (e.g. setup.py bdist_wheel was already executed).
+"""
+
+import os, sys
+
+try:
+ this_file = __file__
+except NameError:
+ this_file = sys.argv[0]
+this_file = os.path.abspath(this_file)
+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_QMAKE
+from build_scripts.options import OPTION_CMAKE
+
+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
+from build_scripts.utils import rmtree
+import distutils.log as log
+
+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)
+
+ if value:
+ log.info("{} option given: {}".format(option_str, value))
+ if not os.path.exists(value):
+ raise RuntimeError("No executable exists at: {}".format(value))
+ else:
+ log.info("No {} option given, trying to find {} in PATH.".format(option_str, executable))
+ paths = find_glob_in_path(executable)
+ log.info("{} executables found in PATH: {}".format(executable, paths))
+ if not paths:
+ raise RuntimeError(
+ "No {} option was specified and no {} was found "
+ "in PATH.".format(option_str, executable))
+ else:
+ value = paths[0]
+ log.info("Using {} found in PATH: {}".format(executable, value))
+ log.info("")
+ return value
+
+
+QMAKE_PATH = find_executable_qmake()
+CMAKE_PATH = find_executable_cmake()
+
+
+def get_wheels_dir():
+ return os.path.join(setup_script_dir, "dist")
+
+
+def get_examples_dir():
+ return os.path.join(setup_script_dir, "examples")
+
+
+def package_prefix_names():
+ return ["shiboken2", "shiboken2_generator", "PySide2"]
+
+
+def clean_egg_info():
+ # After a successful bdist_wheel build, some .egg-info directories
+ # are left over, which confuse pip when invoking it via
+ # python -m pip, making pip think that the packages are already
+ # installed in the root source directory.
+ # Clean up the .egg-info directories to fix this, it should be
+ # safe to do so.
+ paths = find_files_using_glob(setup_script_dir, "*.egg-info")
+ for p in paths:
+ log.info("Removing {}".format(p))
+ rmtree(p)
+
+
+def install_wheel(wheel_path):
+ log.info("Installing wheel: {}".format(wheel_path))
+ exit_code = run_process([sys.executable, "-m", "pip", "install", wheel_path])
+ log.info("")
+ if exit_code:
+ raise RuntimeError("Error while installing wheel {}".format(wheel_path))
+
+
+def try_install_wheels(wheels_dir, py_version):
+ clean_egg_info()
+ all_wheels_pattern = "*.whl"
+ all_wheels = find_files_using_glob(wheels_dir, all_wheels_pattern)
+
+ if len(all_wheels) > 1:
+ log.info("Found the following wheels in {}: ".format(wheels_dir))
+ for wheel in all_wheels:
+ log.info(wheel)
+ else:
+ log.info("No wheels found in {}".format(wheels_dir))
+ log.info("")
+
+ for p in package_prefix_names():
+ pattern = "{}-*cp{}*.whl".format(p, py_version)
+ files = find_files_using_glob(wheels_dir, pattern)
+ if files and len(files) == 1:
+ wheel_path = files[0]
+ install_wheel(wheel_path)
+ elif len(files) > 1:
+ raise RuntimeError("More than one wheel found for specific package and version.")
+ else:
+ raise RuntimeError("No wheels compatible with Python {} found "
+ "for testing.".format(py_version))
+
+
+def is_unix():
+ if sys.platform.startswith("linux") or sys.platform == "darwin":
+ return True
+ return False
+
+
+def generate_build_cmake():
+ args = [CMAKE_PATH]
+ if is_unix():
+ args.extend(["-G", "Unix Makefiles"])
+ else:
+ args.extend(["-G", "NMake Makefiles"])
+ args.append("-DCMAKE_BUILD_TYPE=Release")
+ args.append("-Dpython_interpreter={}".format(sys.executable))
+
+ # Specify prefix path so find_package(Qt5) works.
+ qmake_dir = os.path.abspath(os.path.join(os.path.dirname(QMAKE_PATH), ".."))
+ args.append("-DCMAKE_PREFIX_PATH={}".format(qmake_dir))
+
+ args.append("..")
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while running cmake.")
+ log.info("")
+
+
+def generate_build_qmake():
+ exit_code = run_process([QMAKE_PATH, "..", "python_interpreter={}".format(sys.executable)])
+ if exit_code:
+ raise RuntimeError("Failure while running qmake.")
+ log.info("")
+
+
+def run_make():
+ args = []
+ if is_unix():
+ executable = "make"
+ else:
+ executable = "nmake"
+ args.append(executable)
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while running {}.".format(executable))
+ log.info("")
+
+
+def run_make_install():
+ args = []
+ if is_unix():
+ executable = "make"
+ else:
+ executable = "nmake"
+ args.append(executable)
+ args.append("install")
+
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failed while running {} install.".format(executable))
+ log.info("")
+
+
+def execute_script(script_path):
+ args = [sys.executable, script_path]
+ exit_code = run_process(args)
+ if exit_code:
+ raise RuntimeError("Failure while executing script: {}".format(script_path))
+ log.info("")
+
+
+def prepare_build_folder(src_path, build_folder_name):
+ build_path = os.path.join(src_path, build_folder_name)
+
+ # The script can be called for both Python 2 and Python 3 wheels, so
+ # preparing a build folder should clean any previous existing build.
+ if os.path.exists(build_path):
+ log.info("Removing {}".format(build_path))
+ rmtree(build_path)
+
+ log.info("Creating {}".format(build_path))
+ os.makedirs(build_path)
+ os.chdir(build_path)
+
+
+def try_build_examples():
+ examples_dir = get_examples_dir()
+
+ log.info("Attempting to build and run samplebinding using cmake.")
+ src_path = os.path.join(examples_dir, "samplebinding")
+ prepare_build_folder(src_path, "cmake")
+ generate_build_cmake()
+ run_make()
+ run_make_install()
+ execute_script(os.path.join(src_path, "main.py"))
+
+ log.info("Attempting to build scriptableapplication using cmake.")
+ src_path = os.path.join(examples_dir, "scriptableapplication")
+ prepare_build_folder(src_path, "cmake")
+ generate_build_cmake()
+ run_make()
+
+ log.info("Attempting to build scriptableapplication using qmake.")
+ src_path = os.path.join(examples_dir, "scriptableapplication")
+ prepare_build_folder(src_path, "qmake")
+ generate_build_qmake()
+ run_make()
+
+
+def run_wheel_tests():
+ wheels_dir = get_wheels_dir()
+ py_version = sys.version_info[0]
+
+ log.info("Attempting to install wheels.\n")
+ try_install_wheels(wheels_dir, py_version)
+
+ log.info("Attempting to build examples.\n")
+ try_build_examples()
+
+ log.info("All tests passed!")
+
+
+if __name__ == "__main__":
+ run_wheel_tests()